home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / alt_os / mint / mfs6011 / source / minixfs / minixfs.c < prev    next >
C/C++ Source or Header  |  1994-12-30  |  37KB  |  1,535 lines

  1. /* This file is part of 'minixfs' Copyright 1991,1992,1993,1994 S.N.Henson */
  2.  
  3. #include "minixfs.h"
  4. #include "proto.h"
  5. #include "global.h"
  6.  
  7. FILESYS minix_filesys = {
  8.     (FILESYS *) 0,
  9. #ifdef SYSUPDATE
  10.     FS_CASESENSITIVE | FS_LONGPATH | FS_DO_SYNC,
  11. #else
  12.     FS_CASESENSITIVE | FS_LONGPATH,
  13. #endif
  14.     m_root, m_lookup, m_creat, m_getdev,
  15.     m_getxattr, m_chattr, m_chown,
  16.     m_chmode, m_mkdir,
  17.     m_rmdir, m_remove, m_getname,
  18.     m_rename, m_opendir, m_readdir,
  19.     m_rewinddir, m_closedir,
  20.     m_pathconf, m_dfree,
  21.     m_wlabel, m_rlabel,
  22.     m_symlink, m_readlink,
  23.     m_hardlink, m_fscntl, m_dskchng,
  24.     m_release,m_dupcookie,
  25. #ifdef SYSUPDATE
  26.     l_sync
  27. #endif
  28. };
  29.  
  30. extern DEVDRV minix_dev;
  31.  
  32. static restore_dev=-1;
  33.  
  34. /*
  35.  * the kernel calls this when it detects a disk change. Note the mnt_flags
  36.  * flag MNT_CHANGE signals that the drive is being changed to force relogging
  37.  * of it's root directory and it should not be completely changed.
  38.  */
  39.  
  40. /*
  41.  * Hack alert: disk changes on mounted filesystems are ungracefully handled.
  42.  * Basically, if it isn't the first forced change then they are ignored. See
  43.  * comment (3) in #if does_not_work_yet for reason. This isn't any great loss
  44.  * because changing mounted filesystems is very naughty (causing various Unix
  45.  * variants to panic, in more senses than one. If Unix doesn't handle it why
  46.  * should I? ). Actually since changes, by necessity force the mounted 
  47.  * structure to be destroyed, there isn't much we can gracefully do.
  48.  */
  49.  
  50. long m_dskchng(d)
  51. int d;
  52. {
  53.     FILEPTR *f, **last;
  54.     super_info *psblk;
  55.     char ignore;
  56.     psblk=super_ptr[d];
  57.  
  58.     TRACE("Disk Change drive %c",d+'A');
  59.  
  60.     if(psblk && psblk!=DFS)
  61.     {
  62.         ignore = psblk->mnt_flags & MNT_CHANGE;
  63.         /* If mounted then (for now) ignore changes */
  64.         if(!ignore && psblk->mnt_inode) return 0;
  65.     }
  66.     else ignore=0;
  67.  
  68.     if(psblk && psblk!=DFS && !ignore)
  69.     {
  70.         Kfree(psblk->ibitmap);
  71.  
  72. #if does_not_work_yet
  73.  
  74.         /* Need to do three things:
  75.          * 1. Make sure all children are no longer mounted.
  76.          * 2. Make sure filesystem is no longer searched in lookups
  77.          *    of parent device.
  78.          * 3. (sigh) Force media change of all descendents without
  79.          *    disturbing mounted structure, so MiNT will reread the
  80.          *    root dirs properly.
  81.          */
  82.  
  83.         if(psblk->mnt_inode)
  84.         /* Umount this filesystem */
  85.         {
  86.           super_info **ublk,*tsblk;
  87.           /* Unlink from list on parent device */
  88.           for(ublk=&super_ptr[psblk->mnt_dev]->mnt_first;*ublk;
  89.                               ublk=&(*ublk)->mnt_next)
  90.             if(*ublk==psblk)
  91.             {
  92.             *ublk=psblk->mnt_next;
  93.             break;
  94.             }
  95.             /* Umount all children */
  96.             for(tsblk=psblk->mnt_first;tsblk;tsblk=tsblk->mnt_next)
  97.                                  tsblk->mnt_inode=0;
  98.         }
  99. #endif
  100.         Kfree(psblk);
  101.     }
  102.     if(!ignore) super_ptr[d]=0;
  103.  
  104.     /* this may affect the m_getname cache, too */
  105.     if (lpath && (d == lroot.dev || d == ldir.dev)) {
  106.         Kfree(lpath);
  107.         lpath = 0;
  108.     }
  109.  
  110.     /* Since the disk has changed always invalidate cache */
  111.     m_invalidate(d);
  112.  
  113.     /* Free any memory associated to file pointers of this drive. */
  114.     last = &firstptr;
  115.     for (f = *last; f != 0; f = *last)
  116.       {
  117.         if (f->fc.dev == d)
  118.           {
  119.         f_cache *fch = (f_cache *) f->devinfo;
  120.         /* The lock structure is shared between the fileptr's.
  121.            Make sure that it is freed only once. */
  122.         if (!f->next || f->next->fc.dev != d
  123.             || f->next->fc.index != f->fc.index)
  124.           {
  125.             LOCK *lck, *nextlck;
  126.             nextlck = *fch->lfirst;
  127.             while ((lck = nextlck) != 0)
  128.               {
  129.             nextlck = lck->next;
  130.             Kfree (lck);
  131.               }
  132.             Kfree (fch->lfirst);
  133.           }
  134.         Kfree (fch);
  135.         /* Remove this fileptr from the list. */
  136.         *last = f->next;
  137.         f->next = 0;
  138.           }
  139.         else
  140.           last = &f->next;
  141.       }
  142.         
  143.     if(!ignore) minix_sanity(d);
  144.  
  145.     return 1;
  146. }
  147.  
  148. /*
  149.  * Note: in the first round of initialisations, we assume that floppy
  150.  * drives (A and B) don't belong to us; but in a later disk change,
  151.  * they may very well be ours, so we remember that. This is means that a
  152.  * minix disk inserted into a drive will be unrecognisable at boot up and
  153.  * a forced disk change is needed. However for MiNT 1.05 (and presumably
  154.  * later) drives are initialised on first access so this isn't needed.
  155.  */
  156.  
  157. long m_root(dev,dir)
  158. int dev;
  159. fcookie *dir;
  160. {
  161.     int ret;
  162.     static first_init = 2;
  163.     extern FILESYS dummy_filesys;
  164.     super_info **psblk;
  165.  
  166.     psblk = super_ptr+dev;
  167.  
  168.     ret=0;
  169.  
  170.     if( (kernel->maj_version==0 ) || 
  171.         (kernel->maj_version==1 && kernel->min_version < 5 ) ) {
  172.         /* the first 2 checks (on A: and B:) we fail automatically */
  173.         if (first_init ) {
  174.             --first_init;
  175.             return -1;
  176.         }
  177.     }
  178.  
  179.     /* If not present, see if it's valid */
  180.     if( *psblk || ( dev >= 0 && (ret=minix_sanity(dev)) ) ) {
  181.         if(ret ==-1 || *psblk==DFS ) dir->fs = &dummy_filesys;
  182.         else
  183.         {
  184.             dir->fs=&minix_filesys;
  185.             /* Aux field tells original device */
  186.             dir->aux= dev | AUX_DRV ;
  187.             dir->index=ROOT_INODE;
  188.             /* If mounted trace back to root filesystem */
  189.             while((*psblk)->mnt_inode)
  190.             {
  191.                 dev=(*psblk)->mnt_dev;
  192.                 psblk=super_ptr+dev;
  193.             }
  194.         }
  195.         dir->dev=dev;
  196.         return 0;
  197.  
  198.     }
  199.     return -1;
  200. }
  201.  
  202. long m_lookup(dir,name,entry)
  203. fcookie *dir; 
  204. char *name;
  205. fcookie *entry;
  206. {
  207.  
  208.     if(!*name)
  209.     {
  210.         *entry=*dir;
  211.         entry->aux=0;
  212.         return 0;
  213.     }
  214.  
  215.     if(dir->index==ROOT_INODE && !strcmp(name,".."))
  216.     {
  217.         *entry=*dir;
  218.         /* If mounted treat as a lookup from mount point */
  219.         if( cross_mount(entry) ) return EMOUNT;
  220.         DEBUG("m_lookup: crossing mount point");
  221.         entry->index = search_dir(name,entry->index,entry->dev,FIND);
  222.         if(entry->index < 0 )  return entry->index;
  223.         entry->aux=0;
  224.         return 0;
  225.     }
  226.  
  227.     entry->index=search_dir(name,dir->index,dir->dev,FIND);
  228.     entry->dev=dir->dev;
  229.     if(entry->index < 0 ) return entry->index ;
  230.     entry->aux=0;
  231.     entry->fs=&minix_filesys;
  232.     if( check_mount(entry) ) DEBUG("Crossed mount point");
  233.     return 0;
  234. }
  235.  
  236. long m_creat(dir,name,mode,attr,entry)
  237. fcookie *dir;
  238. char *name;
  239. unsigned mode;
  240. int attr;
  241. fcookie *entry;
  242. {
  243.     long pos;
  244.     d_inode ripnew;
  245.     unshort newfile;
  246.     char *ext;
  247.     
  248.     /* Create dir entry */    
  249.     if((pos=search_dir(name,dir->index,dir->dev,ADD))<0)
  250.     {    
  251.         return pos;
  252.     }
  253.  
  254.     /* Get new inode */
  255.     if(!(newfile=alloc_inode(dir->dev)))
  256.     {
  257.         DEBUG("m_getdev: no free inodes");
  258.         return EWRITF;
  259.     }
  260.     /* Set up inode */
  261.     bzero(&ripnew,sizeof(d_inode));
  262.  
  263. /* If  creating a file with approriate extensions 
  264.  * automatically give it execute permissions.
  265.  */
  266.     if(do_trans(AEXEC_TOS,dir->dev) && ( ext=strrchr(name,'.') ) )
  267.     {
  268.         ext++;
  269.         if( 
  270.         /* Insert your favourite extensions here */
  271.           !(  Stricmp(ext,"TTP") && Stricmp(ext,"PRG") 
  272.            && Stricmp(ext,"APP") && Stricmp(ext,"TOS") 
  273.            && Stricmp(ext,"ACC") && Stricmp(ext, "GTP")))
  274.                 mode |= 0111;
  275.     }
  276.     ripnew.i_mode= I_REGULAR | mode;
  277.     ripnew.i_uid=Geteuid();
  278.     ripnew.i_gid=Getegid();
  279.     ripnew.i_nlinks=1;
  280.  
  281.     ripnew.i_mtime=Unixtime(Timestamp(), Datestamp());
  282.     ripnew.i_atime=ripnew.i_mtime;
  283.     ripnew.i_ctime=ripnew.i_mtime;
  284.  
  285.     write_inode(newfile,&ripnew,dir->dev);
  286.     l_write(dir->index,pos,2L,&newfile,dir->dev);
  287.  
  288.     if(cache_mode) l_sync();
  289.  
  290.     entry->fs = dir->fs;
  291.     entry->dev = dir->dev;
  292.     entry->index=newfile;
  293.     entry->aux=0;
  294.     return 0;
  295. }
  296.  
  297. DEVDRV * m_getdev(file,special)
  298. fcookie *file;
  299. long *special;
  300. {
  301.     return(&minix_dev);
  302. }
  303.  
  304. long m_getxattr(file,xattr)
  305. fcookie *file;
  306. XATTR *xattr;
  307. {
  308.         d_inode rip;
  309.     long time_tmp;
  310.     long extra;
  311.     super_info *psblk;
  312.     psblk=super_ptr[file->dev];
  313.     read_inode(file->index,&rip,file->dev);
  314.     /* Minix and gcc use different values for FIFO's */
  315.     if((rip.i_mode & I_TYPE) == I_NAMED_PIPE)
  316.         xattr->mode = S_IFIFO | (rip.i_mode & ALL_MODES);
  317.     else xattr->mode=rip.i_mode;
  318.  
  319.     /* We could potentially have trouble with symlinks too */
  320. #if I_SYMLINK != S_IFLNK
  321.     if( (rip.i_mode & I_TYPE) == I_SYMLINK)
  322.         xattr->mode = S_IFLNK | (rip.i_mode & ALL_MODES);
  323. #endif
  324.  
  325.     /* Fake attr field a bit , to keep TOS happy */
  326.     if(IS_DIR(rip))xattr->attr=FA_DIR;
  327.     else xattr->attr=(rip.i_mode & 0222) ? 0 : FA_RDONLY;
  328.  
  329.         xattr->index=file->index;
  330.         xattr->dev=file->dev;
  331.  
  332.     /* Char and block special files need major/minor device nos filled in */
  333.     if(IM_SPEC(rip.i_mode)) xattr->rdev=rip.i_zone[0];
  334.         else xattr->rdev=0;
  335.  
  336.         xattr->nlink=rip.i_nlinks;
  337.         xattr->uid=rip.i_uid;
  338.         xattr->gid=rip.i_gid;
  339.         xattr->size=rip.i_size;
  340.     xattr->blksize = BLOCK_SIZE;
  341. /* Note: the nblocks calculation is accurate only if the file is
  342.  * contiguous. It usually will be, and if it's not, it shouldn't
  343.  * matter ('du' will return values that are slightly too high)
  344.  */
  345.     xattr->nblocks = (xattr->size + (BLOCK_SIZE-1)) / BLOCK_SIZE;
  346.     extra = 0;
  347.     if (xattr->nblocks > psblk->dzpi)
  348.         extra++;    /* correct for the indirection block */
  349.     if (xattr->nblocks > psblk->ndbl) {
  350.         extra++;    /* correct for double indirection block */
  351.         extra += (xattr->nblocks - psblk->ndbl) / psblk->zpind;
  352.                 /* and single indirection blocks */
  353.     }
  354.     if (xattr->nblocks > psblk->ndbl + (long) psblk->zpind * psblk->zpind)
  355.       {
  356.         extra++;    /* correct for triple indir block */
  357.         /* and double indirection blocks */
  358.         extra += ((xattr->nblocks - psblk->ndbl
  359.                - (long) psblk->zpind * psblk->zpind)
  360.               / ((long) psblk->zpind * psblk->zpind));
  361.       }
  362.     xattr->nblocks += extra;
  363.  
  364.     time_tmp=Dostime(_corr(rip.i_mtime));
  365.     xattr->mtime=time_tmp >> 16;
  366.     xattr->mdate=time_tmp & (0xffff);
  367.     time_tmp=Dostime(_corr(rip.i_atime));
  368.     xattr->atime=time_tmp >> 16;
  369.     xattr->adate=time_tmp & (0xffff);
  370.     time_tmp=Dostime(_corr(rip.i_ctime));
  371.     xattr->ctime=time_tmp >> 16;
  372.     xattr->cdate=time_tmp & (0xffff);
  373.  
  374.     xattr->reserved2=0;
  375.     xattr->reserved3[0]=0;
  376.     xattr->reserved3[1]=0;
  377.  
  378.     return 0;
  379. }
  380.  
  381. long m_chown(file, uid , gid)
  382. fcookie *file;
  383. int uid,gid;
  384. {
  385.  
  386.     d_inode rip;
  387.     read_inode(file->index,&rip,file->dev);
  388.      if(uid!=-1)rip.i_uid=uid;
  389.     if(gid!=-1)rip.i_gid=gid;
  390.     rip.i_ctime=Unixtime(Timestamp(),Datestamp());
  391.     write_inode(file->index,&rip,file->dev);
  392.     if(cache_mode) l_sync();
  393.     return 0;
  394. }
  395.  
  396. long m_chmode(file, mode)
  397. fcookie *file;
  398. unsigned mode;
  399. {
  400.         d_inode rip;
  401.     super_info *psblk=super_ptr[file->dev];
  402.  
  403.         read_inode(file->index,&rip,file->dev);
  404.  
  405.         rip.i_mode=(rip.i_mode & I_TYPE)|(mode & ALL_MODES);                
  406.     if(psblk->version)rip.i_ctime=Unixtime(Timestamp(),Datestamp());
  407.     write_inode(file->index,&rip,file->dev);
  408.     if(cache_mode) l_sync();
  409.         return 0;
  410. }
  411.  
  412.  
  413. long m_mkdir(dir,name,mode)
  414. fcookie *dir;
  415. char *name;
  416. unsigned mode;
  417. {
  418.     unshort newdir;
  419.     d_inode rip,ripnew;
  420.     long pos;
  421.     int incr;
  422.     dir_struct blank[MAX_INCREMENT*2];
  423.     incr=super_ptr[dir->dev]->increment;
  424.     if((pos=search_dir(name,dir->index,dir->dev,ADD))<0)return pos;
  425.     read_inode(dir->index,&rip,dir->dev);
  426.     if(rip.i_nlinks>=MINIX_MAX_LINK)return EACCDN;
  427.     /* Get new inode */
  428.     if(!(newdir=alloc_inode(dir->dev)))return EACCDN;
  429.  
  430.     /* Set up inode */
  431.     bzero(&ripnew,sizeof(d_inode));
  432.     ripnew.i_mode=I_DIRECTORY | (mode & 0777);
  433.     ripnew.i_uid=Geteuid();
  434.     ripnew.i_gid=Getegid();
  435.     ripnew.i_nlinks=2;
  436.     ripnew.i_mtime=Unixtime(Timestamp(), Datestamp());
  437.     ripnew.i_ctime=ripnew.i_mtime;
  438.     ripnew.i_atime=ripnew.i_mtime;
  439.     write_inode(newdir,&ripnew,dir->dev);
  440.  
  441.     /* Set up new directory */
  442.     strcpy(blank[0].d_name,".");
  443.     blank[0].d_inum=newdir;
  444.     strcpy(blank[incr].d_name,"..");
  445.     blank[incr].d_inum=dir->index;
  446.     if(l_write((unsigned)newdir,-1L,(long)(DIR_ENTRY_SIZE*2*incr),
  447.         blank,dir->dev)!=(incr*DIR_ENTRY_SIZE*2) )
  448.     {
  449.         ripnew.i_mode=0;
  450.         ripnew.i_nlinks=0;
  451.         write_inode(newdir,&ripnew,dir->dev);
  452.         free_inode(newdir,dir->dev);
  453.         if(cache_mode) l_sync();
  454.         return EACCDN;
  455.     }
  456.     rip.i_nlinks++;
  457.     write_inode(dir->index,&rip,dir->dev);
  458.     l_write(dir->index,pos,2L,&newdir,dir->dev);
  459.  
  460.     if(cache_mode) l_sync();
  461.  
  462.     return(0);
  463. }
  464.  
  465. long m_rmdir(dir,name)
  466. fcookie *dir;
  467. char *name;
  468. {
  469.     long chunk,left;
  470.     long inum;
  471.     int i,incr;
  472.     super_info *psblk;
  473.     d_inode rip,rip2;
  474.     if((inum=search_dir(name,dir->index,dir->dev,FIND))<0)return inum;
  475.  
  476.     /* Is anything mounted on this dir ? */
  477.     for(psblk=super_ptr[dir->dev]->mnt_first;psblk;psblk=psblk->mnt_next)
  478.         if(psblk->mnt_inode==inum)
  479.         {
  480.             DEBUG("m_rmdir: can't delete mount point");
  481.             return EACCDN;
  482.         }
  483.  
  484.     read_inode(inum,&rip,dir->dev);
  485.     read_inode(dir->index,&rip2,dir->dev);
  486.     if(!IS_DIR(rip))return EFILNF;
  487.     incr=super_ptr[dir->dev]->increment;
  488.     /* Check if dir is actually empty */
  489.     for(chunk=0;(left=next_zone(&rip,chunk,&temp,dir->dev)/DIR_ENTRY_SIZE);
  490.         chunk++)
  491.     {
  492.         for(i=0;i<left;i+=incr)
  493.            if (temp.bdir[i].d_inum
  494.                && (temp.bdir[i].d_name[0] != '.'
  495.                || temp.bdir[i].d_name[1] != 0)
  496.                && (temp.bdir[i].d_name[0] != '.'
  497.                || temp.bdir[i].d_name[1] != '.'
  498.                || temp.bdir[i].d_name[2] != 0))
  499.             return EACCDN ;
  500.     }
  501.     if(!inode_busy(inum,dir->dev,1))
  502.     {
  503.         trunc_inode(&rip,dir->dev,0L,0);
  504.         rip.i_mode=0;
  505.         free_inode(inum,dir->dev);
  506.     }
  507.     rip.i_nlinks=0;
  508.     write_inode(inum,&rip,dir->dev);
  509.     read_inode(dir->index,&rip,dir->dev);
  510.     rip.i_mtime=Unixtime(Timestamp(), Datestamp());
  511.     rip.i_nlinks--;
  512.     write_inode(dir->index,&rip,dir->dev);
  513.     search_dir(name,dir->index,dir->dev,KILL);
  514.  
  515.     if( lpath && (ldir.dev==dir->dev) && (ldir.index==inum) )
  516.     {
  517.         Kfree(lpath);
  518.         lpath=0;
  519.     }
  520.  
  521.     if(cache_mode) l_sync();
  522.  
  523.     return(0);
  524. }
  525.  
  526. /* Unix-like unlink ... handle regulars, symlinks and specials.
  527.  * 
  528.  */
  529.  
  530. long m_remove(dir,name)
  531. fcookie *dir;
  532. char *name;
  533. {
  534.     long inum,ret;
  535.     char spec;    /* Special file */
  536.     d_inode rip;
  537.     inum=search_dir(name,dir->index,dir->dev,FIND);
  538.     if(inum<0) return inum;
  539.     read_inode(inum,&rip,dir->dev);
  540.     if(!IS_REG(rip) && !IS_SYM(rip) ) 
  541.     {
  542.         if(!IM_SPEC(rip.i_mode)) return EACCDN;
  543.         spec=1;
  544.     }
  545.     else spec=0;
  546.     if((ret=search_dir(name,dir->index,dir->dev,KILL))<0) return ret;    
  547.     if(--rip.i_nlinks==0)
  548.     {
  549.         if(spec || !inode_busy(inum,dir->dev,1)) /* Is inode busy ? */
  550.         {
  551.             if(!spec) trunc_inode(&rip,dir->dev,0L,0);
  552.             rip.i_mode=0;
  553.             free_inode(inum,dir->dev);
  554.         }
  555.     }
  556.     write_inode(inum,&rip,dir->dev);
  557.  
  558.     if(cache_mode) l_sync();
  559.  
  560.     return(0);
  561. }
  562.  
  563. /* This function is inefficient, it uses the standard sys V method of 
  564.  * finding out the pathname of the cwd : for each part of the path, search
  565.  * the parent for a link with the same inode number as '..' , append this to the
  566.  * path until we get to root dir, then reverse order of dirs. This way no 
  567.  * temporary buffers are allocated which could overflow or kmalloc to fail ...
  568.  */
  569.  
  570. /* In fact its so inefficient a mini-cache remembers the last call info */
  571.  
  572. long m_getname(root,dir,pathname,length)
  573. fcookie *root,*dir;
  574. char *pathname;
  575. short length;
  576. {
  577.     long inum,pinum;
  578.     unsigned dev;
  579.     int chunk;
  580.     long left;
  581.     int incr;
  582.     short plength;
  583.     super_info *psblk;
  584.     psblk=super_ptr[dir->dev];
  585.  
  586.     if(no_length) length=PATH_MAX;
  587.  
  588.     if(lpath && lroot.dev==root->dev && 
  589.         lroot.index==root->index && ldir.dev==dir->dev && 
  590.         ldir.index==dir->index)
  591.     {
  592.         TRACE("m_getname: cache hit");
  593.         if(length <= llength) return ENAMETOOLONG;
  594.         strcpy(pathname,lpath);
  595.         return 0;
  596.     }
  597.  
  598.     *pathname=0;
  599.  
  600.     if( dir->dev==root->dev && dir->index==root->index) return 0;
  601.  
  602.     incr=psblk->increment;
  603.     inum=dir->index;
  604.     dev=dir->dev;
  605.     plength=0;
  606.     if(inum==ROOT_INODE && psblk->mnt_inode)
  607.     {
  608.         dev=psblk->mnt_dev;
  609.         inum=psblk->mnt_inode;
  610.         psblk=super_ptr[dev];
  611.     }
  612.  
  613.     while( inum!=root->index && inum!= ROOT_INODE )
  614.     {
  615.         d_inode rip;
  616.         cache *tmp;
  617.         pinum=search_dir("..",inum,dev,FIND); 
  618.         /* Parent inum */
  619.  
  620.         if(pinum < 0) /* If this happens we're in trouble */
  621.         {
  622.             ALERT("No .. in inode %d , drive %c",inum,dir->dev+'A');
  623.             return pinum;
  624.         }
  625.         read_inode(pinum,&rip,dev);
  626.         for(chunk=0;
  627.         (left=cnext_zone(&rip,chunk,&tmp,dev)/DIR_ENTRY_SIZE) &&
  628.         inum!=pinum ;chunk++)
  629.         {
  630.             char tname[MNAME_MAX+1];
  631.             int i;
  632.             for(i=0;i<left && inum!=pinum ;i+=incr)
  633.             if(tmp->buffer->bdir[i].d_inum==inum)
  634.             {
  635.                 strncpy(tname,tmp->buffer->bdir[i].d_name,MMAX_FNAME(incr));
  636.                 tname[MMAX_FNAME(incr)]=0;
  637.                 strrev(tname);
  638.                 plength+=strlen(tname)+1;
  639.                 if(length <= plength) return ENAMETOOLONG;
  640.                 strcat(pathname,tname);
  641.                 strcat(pathname,"\\");
  642.                 inum=pinum;
  643.             }
  644.         }
  645.         if(left==0 && inum!=pinum) {
  646.             ALERT("m_getname inode %d orphaned or bad ..",inum);
  647.             return EINTRN;
  648.         }
  649.         /* Cross mount point if possible */
  650.         if(inum==ROOT_INODE && psblk->mnt_inode)
  651.         {
  652.             dev=psblk->mnt_dev;
  653.             inum=psblk->mnt_inode;
  654.             psblk=super_ptr[dev];
  655.         }
  656.     }
  657.     if(inum==ROOT_INODE && root->index!=ROOT_INODE)
  658.     {
  659.         DEBUG("m_getname: Hmmmm root is not a parent of dir");
  660.         return EINTRN;
  661.     }
  662.     strrev(pathname);
  663.     if(lpath)Kfree(lpath);
  664.     if( (lpath=Kmalloc(strlen(pathname)+1)) )
  665.     {
  666.         strcpy(lpath,pathname);
  667.         llength=plength;
  668.     }
  669.  
  670.     lroot=*root;
  671.     ldir=*dir;
  672.     return 0;
  673. }
  674.  
  675.  
  676. long m_opendir(dirh,flag)
  677. DIR *dirh;
  678. int flag;
  679. {
  680.     dirh->index=0;
  681.     return 0;
  682. }
  683.  
  684. long m_readdir(dirh,name,namelen,fc)
  685. DIR *dirh;
  686. char *name;
  687. int namelen;
  688. fcookie *fc;
  689. {
  690.         d_inode rip;
  691.     cache *tmp;
  692.     unsigned entry,chunk;
  693.     super_info *psblk;
  694.     long limit;
  695.     int flag,incr;
  696.     psblk=super_ptr[dirh->fc.dev];
  697.     if(dirh->flags) flag=do_trans(DIR_TOS,dirh->fc.dev);
  698.     else flag=0;
  699.     if(!dirh->fc.index)return EACCDN;
  700.     entry=dirh->index % NR_DIR_ENTRIES;
  701.     chunk=dirh->index / NR_DIR_ENTRIES;    
  702.     read_inode(dirh->fc.index,&rip,dirh->fc.dev);
  703.     incr=psblk->increment;
  704.  
  705.     while( (limit=cnext_zone(&rip,chunk,&tmp,dirh->fc.dev)/DIR_ENTRY_SIZE) )
  706.     {
  707.         while( entry < limit)
  708.           {
  709.             dir_struct *try=&tmp->buffer->bdir[entry];
  710.             entry+=incr;
  711.             if(try->d_inum)
  712.             {
  713.                 char *tmpnam;
  714.                 tmpnam=tosify(try->d_name,flag,MMAX_FNAME(incr));
  715.  
  716.                 if (dirh->flags==0)
  717.                 {
  718.                     namelen -= sizeof(long);
  719.                     if (namelen <= 0) return ERANGE;
  720.                     *((long *)name) = (long)try->d_inum;
  721.                     name += sizeof(long);
  722.                        }
  723.  
  724.                 strncpy(name,tmpnam,namelen);
  725.                 dirh->index=entry+chunk*NR_DIR_ENTRIES;
  726.             /* set up a file cookie for this entry */
  727.                 fc->dev = dirh->fc.dev;
  728.                 fc->aux = 0;
  729.                 fc->index = (long)try->d_inum;
  730.                 fc->fs = &minix_filesys;
  731.                 if(strlen(tmpnam) >= namelen) 
  732.                     return ENAMETOOLONG;
  733.                 /* If turbo mode set atime here: we'll only
  734.                  * change the cache here so it wont cause
  735.                  * lots of I/O
  736.                  */
  737.                 if( cache_mode==TURBO
  738.                     && super_ptr[dirh->fc.dev]->version
  739.                     && dirh->fc.dev > 1 )
  740.                                set_atime(&dirh->fc);
  741.                 return 0;
  742.             }
  743.         }
  744.         if(entry!=NR_DIR_ENTRIES)return ENMFIL;
  745.         else entry=0;
  746.         chunk++;
  747.     }
  748.     return ENMFIL;
  749. }
  750.  
  751. long m_rewinddir(dirh)
  752. DIR *dirh;
  753. {
  754.     dirh->index=0;
  755.     return 0;
  756. }
  757.  
  758. long m_closedir(dirh)
  759. DIR *dirh;
  760. {
  761.  
  762. /* Access time is set here if we aren't in TURBO cache mode. Otherwise we
  763.  * would be sync'ing on every dir read which would be far too slow. See note
  764.  * in set_atime().
  765.  */
  766.  
  767.     if( cache_mode!=TURBO && super_ptr[dirh->fc.dev]->version && 
  768.             dirh->fc.dev > 1 )
  769.     {
  770.         set_atime(&dirh->fc);
  771.         l_sync();
  772.     }
  773.  
  774.     dirh->fc.index=0;
  775.     return 0;
  776. }
  777.  
  778. /* Set the atime of a V2 inode for filesystems. There is a snag here: if the
  779.  * disk is changed then this is likely not to be written out before the whole
  780.  * cache is invalidated. So we set the status to '3' which means that it is
  781.  * not alerted if this is dirty when invalidated (hardly the end of the world
  782.  * if the atime is slightly wrong!)
  783.  */
  784. void set_atime(fc)
  785. fcookie *fc;
  786. {
  787.     d_inode *rip;
  788.     int *status;
  789.     rip=get_inode2(fc->index,fc->dev,&status,NOGUESS);
  790.     rip->i_atime=Unixtime(Timestamp(),Datestamp());
  791.     if(*status!=2) *status=3;
  792. }
  793.  
  794.  
  795. long m_rlabel(dir,name,namelen)
  796. fcookie *dir;
  797. char *name;
  798. int namelen;
  799. {
  800.     return EFILNF;
  801. }
  802.  
  803. long m_wlabel(dir,name)
  804. fcookie *dir;
  805. char *name;
  806. {
  807.     return EACCDN;
  808. }
  809.  
  810. long m_dfree(dir,buffer)
  811. fcookie *dir;
  812. long *buffer;
  813. {
  814.     super_info *psblk ;
  815.     psblk = super_ptr[dir->dev];
  816.     buffer[1] = psblk->sblk.s_zones-psblk->sblk.s_firstdatazn;
  817.     buffer[0] = buffer[1] - count_bits(psblk->zbitmap,buffer[1]+1)+1;
  818.     buffer[2]=512L;
  819.     buffer[3]=2L;
  820.     return(0);
  821. }
  822.  
  823. long m_fscntl(dir,name,cmd,arg)
  824. fcookie *dir;
  825. char *name;
  826. int cmd;
  827. long arg;
  828. {
  829.     FILEPTR *f;
  830.     mfs_info *inf;
  831.     super_info *psblk;
  832.     long inum;
  833.     int uid,gid,id;
  834.     d_inode rip;
  835.     extern long init_addr;
  836.  
  837.     uid = Geteuid();
  838.     gid = Getegid();
  839.  
  840.     switch(cmd)
  841.     {
  842.         case MFS_VERIFY:
  843.         *((long *)arg)=MFS_MAGIC;
  844.         return 0;
  845.  
  846.         /* Sync the filesystem */
  847.         case MFS_SYNC:
  848.         TRACE("Done l_sync()");
  849.         l_sync();
  850.         return 0;
  851.  
  852.         /* Invalidate all cache entries for a given drive */
  853.         case MFS_CINVALID:
  854.         if(uid) return EACCDN;
  855.         m_invalidate(dir->dev);
  856.         return 0;
  857.  
  858.         /* Invalidate all fileptrs for a given drive */
  859.         case MFS_FINVALID:
  860.         if(uid) return EACCDN;
  861.         id=Getpid();
  862.         for(f=firstptr;f;f=f->next)if(f->fc.dev==dir->dev)m_close(f,id);
  863.         return 0;
  864.  
  865.         case MFS_INFO:
  866.         psblk=super_ptr[dir->dev];
  867.         inf=(mfs_info *)arg;
  868.         inf->total_zones=psblk->sblk.s_zones-psblk->sblk.s_firstdatazn;
  869.         inf->total_inodes=psblk->sblk.s_ninodes;
  870.         inf->version=psblk->version+1;
  871.         inf->increment=psblk->increment;        
  872.         inf->free_inodes=inf->total_inodes-
  873.             count_bits(psblk->ibitmap,inf->total_inodes+1)+1;
  874.         inf->free_zones=inf->total_zones-count_bits(psblk->zbitmap,inf->total_zones+1)+1;
  875.         return 0;
  876.  
  877.         case MFS_IMODE:
  878.         if(uid) return EACCDN;
  879.         inum=search_dir(name,dir->index,dir->dev,FIND);
  880.         if(inum < 0 ) return inum;
  881.         read_inode(inum,&rip,dir->dev);
  882.         rip.i_mode=arg;
  883.         write_inode(inum,&rip,dir->dev);
  884.         return 0;
  885.  
  886.         case MFS_GTRANS:
  887.         *((long *) arg)=fs_mode[dir->dev];
  888.         return 0;
  889.  
  890.         case MFS_STRANS:
  891.         if(uid) return EACCDN;
  892.         fs_mode[dir->dev]=*((long *)arg);
  893.         return 0;
  894.  
  895.         case MFS_PHYS:
  896.         *((struct phys_part *)arg)=ppart[dir->dev];
  897.         return 0;
  898.  
  899.         case MFS_IADDR:
  900.         *((long *)arg)=(long)&init_addr;
  901.         return 0;
  902.  
  903.         case MFS_UPDATE:
  904.         if(cache_mode!=TURBO ) return -1;
  905.         switch(arg)
  906.         {
  907.             case 0:
  908.             return update_suspend;
  909.  
  910.             case 1:
  911.             TRACE("Minixfs: update suspended");
  912.             update_suspend=1;
  913.             return 0;
  914.  
  915.             case 2:
  916.             TRACE("Minixfs: update restarted");
  917.             update_suspend=0;
  918.             return 0;
  919.  
  920.             case 3:
  921.             if(Addroottimeout) return -1;
  922.             return update_pid;
  923.  
  924.             default:
  925.             return EINVFN;
  926.         }
  927.  
  928. /* Mounting and umounting.
  929.  * This basically involves cookie translation when crossing the mount point.
  930.  * However this presents an interesting problem. Suppose E:\usr has D: mounted
  931.  * on it. If we are in directory E:\usr\ we are in the root directory of D:.
  932.  * If we do a cd \ then we get sent back to the root cookie directory of D:,
  933.  * which we want to be E:. The only way to change the root cookie at present is
  934.  * to force a disk change, this is no problem.
  935.  * The fun starts when we want to umount D:. Changing D: will have no effect
  936.  * because the root cookie of D: is now on E: and since E: hasn't changed the
  937.  * root cookie on D: wont change either. If we change E: then we will get the
  938.  * root cookie of D: changed but we also change E: as well.
  939.  * The only way out is to fiddle the aux field of the root cookie so it shows
  940.  * the original device. The cookie from m_root is copied with the dup_cookie
  941.  * function, if we kludge this at umount time to read the aux field and copy
  942.  * the original device the root cookies should be set back. This relies very
  943.  * heavily on the structure of filesys.c in MiNT, but it's better than nothing.
  944.  * Repeat after me: KLUDGE, KLUDGE, KLUDGE, KLUDGE, KLUDGE!!!
  945.  */
  946.  
  947.         case MFS_MOUNT:
  948.         {
  949.             char tpath[]="A:";
  950.             fcookie fc;
  951.             unsigned dev;
  952.             super_info *mptr;
  953.             if(uid) return EACCDN;
  954.             /* Lookup the entry */
  955.             if( (inum=m_lookup(dir,name,&fc)) ) return inum;
  956.             read_inode(fc.index,&rip,fc.dev);
  957.             /* Must be a directory */
  958.             if(!IS_DIR(rip))
  959.             {
  960.                 DEBUG("MFS_MOUNT: not a directory!");
  961.                 return EACCDN;
  962.             }
  963.  
  964.             if(fc.index==ROOT_INODE)
  965.             {
  966.                 DEBUG("MFS_MOUNT: can't mount on root!");
  967.                 return EACCDN;
  968.             }
  969.             if(!arg) return EINVFN;
  970.             dev = ( ( mfs_mount *) arg)->dev ;
  971.  
  972.             if(fc.dev==dev)
  973.             {
  974.                 DEBUG("MFS_MOUNT: can't mount on self!");
  975.                 return EACCDN;
  976.             }
  977.  
  978.             tpath[0]='A'+dev;
  979.  
  980.             /* Sync filesystem (and force access if unrecognised) */
  981.  
  982.             d_cntl(MFS_SYNC,tpath,0l);
  983.  
  984.             psblk=super_ptr[dev];
  985.  
  986.             if(!psblk || psblk==DFS)
  987.             {
  988.                 DEBUG("MFS_MOUNT: not a Minixfs filesystem!");
  989.                 return EACCDN;
  990.             }
  991.  
  992.             if(psblk->mnt_inode)
  993.             {
  994.               DEBUG("MFS_MOUNT: filesystem already mounted!");
  995.               return EACCDN;
  996.             }
  997.  
  998.             if(psblk->mnt_first)
  999.             {
  1000.               DEBUG("MFS_MOUNT: filesystem has others mounted!");
  1001.               return EACCDN;
  1002.             }
  1003.  
  1004.             for(mptr=super_ptr[fc.dev]->mnt_first;
  1005.                           mptr;mptr=mptr->mnt_next)
  1006.             {
  1007.               if( mptr->mnt_inode==fc.index )
  1008.               {
  1009.                 DEBUG("MFS_MOUNT: inode already mounted on!");
  1010.                 return EACCDN;
  1011.               }
  1012.             }
  1013.  
  1014.             mptr=super_ptr[fc.dev];
  1015.  
  1016.             psblk->mnt_next=mptr->mnt_first;
  1017.             mptr->mnt_first=psblk;
  1018.  
  1019.             psblk->mnt_dev=fc.dev;
  1020.             psblk->mnt_inode=fc.index;
  1021.  
  1022.             psblk->mnt_flags |= MNT_CHANGE;
  1023.  
  1024.             /* Force change */
  1025.             d_lock(1,dev);
  1026.             d_lock(0,dev);
  1027.  
  1028.             d_cntl(MFS_SYNC,tpath,0l);
  1029.  
  1030.             psblk->mnt_flags &= ~MNT_CHANGE;
  1031.  
  1032.             return 0;
  1033.         }
  1034.  
  1035.         case MFS_UMOUNT:
  1036.         {
  1037.             fcookie fc;
  1038.             super_info **pptr,*pdev;
  1039.             char tpath[]="A:";
  1040.  
  1041.             if(uid) return EACCDN;
  1042.             /* Lookup path */
  1043.             if( ( inum=m_lookup(dir,name,&fc) ) ) return inum;
  1044.  
  1045.             psblk=super_ptr[fc.dev];
  1046.  
  1047.             /* Can't have other devices mounted */
  1048.             if(psblk->mnt_first)
  1049.             {
  1050.                 DEBUG("MFS_UMOUNT: device busy");
  1051.                 return EACCDN;
  1052.             }
  1053.  
  1054.             if(!psblk->mnt_inode)
  1055.             {
  1056.                 DEBUG("MFS_UMOUNT: not mounted");
  1057.                 return EACCDN;
  1058.             }
  1059.  
  1060.             /* Unlink from parent filesystem list */
  1061.             for(pptr=&super_ptr[psblk->mnt_dev]->mnt_first;*pptr;
  1062.                               pptr=&(*pptr)->mnt_next )
  1063.             {
  1064.                 if(*pptr==psblk)
  1065.                 {
  1066.                     *pptr = psblk->mnt_next;
  1067.                     break;
  1068.                 }
  1069.             }
  1070.  
  1071.             pdev=psblk;
  1072.  
  1073.             /* Find root device */
  1074.             while(pdev->mnt_inode) pdev = super_ptr[pdev->mnt_dev];
  1075.  
  1076.             psblk->mnt_inode=0;
  1077.  
  1078.             pdev->mnt_flags |= MNT_CHANGE;
  1079.  
  1080.             /* Make dupcookie restore dev fields */
  1081.             restore_dev = psblk->dev;
  1082.  
  1083.             /* Change root device */
  1084.             d_lock(1,pdev->dev);
  1085.             d_lock(0,pdev->dev);
  1086.  
  1087.             tpath[0] = 'A'+pdev->dev;
  1088.             d_cntl(MFS_SYNC,tpath,0l);
  1089.  
  1090.             restore_dev = -1;
  1091.  
  1092.             pdev->mnt_flags &= ~MNT_CHANGE;
  1093.  
  1094.             return 0;
  1095.  
  1096.         }
  1097.  
  1098.         case FUTIME:
  1099.         case FTRUNCATE:
  1100.         {
  1101.             fcookie fc;
  1102.             read_inode(dir->index,&rip,dir->dev);
  1103.         /* Have we got 'x' access for current dir ? */
  1104.          if (check_mode(uid,gid,&rip,S_IXUSR)) 
  1105.           return EACCDN;
  1106.         /* Lookup the entry */
  1107.             if( (inum=m_lookup(dir,name,&fc)) ) return inum;
  1108.             read_inode(fc.index,&rip,fc.dev);
  1109.             if(cmd==FUTIME)
  1110.             {
  1111.                 short *timeptr = (short *) arg;
  1112.               /* The owner or super-user can always touch,
  1113.                  others only if timeptr == 0 and write
  1114.                  permission. */
  1115.               if (uid && uid != rip.i_uid
  1116.                   && (timeptr
  1117.                   || check_mode (uid, gid, &rip, S_IWUSR)))
  1118.                 return EACCDN;
  1119.                 
  1120.               rip.i_ctime = Unixtime(Timestamp (), Datestamp ());
  1121.               if(timeptr)
  1122.               {    
  1123.                 rip.i_atime = Unixtime(timeptr[0], timeptr[1]);
  1124.                 rip.i_mtime = Unixtime(timeptr[2], timeptr[3]);
  1125.               }
  1126.               else rip.i_atime = rip.i_mtime = rip.i_ctime;
  1127.                 write_inode (fc.index, &rip, fc.dev);
  1128.                 if (cache_mode != TURBO) l_sync();
  1129.                 return 0;
  1130.             }
  1131.  
  1132.             if(!IS_REG(rip)) return EACCDN;
  1133.             /* Need write access as well */
  1134.             if (check_mode(uid, gid, &rip, S_IWUSR))
  1135.               return EACCDN;
  1136.             itruncate(fc.index,fc.dev,*((long *)arg));
  1137.               if (cache_mode != TURBO) l_sync ();
  1138.             return 0;
  1139.         }
  1140.  
  1141.         case MFS_LOPEN:
  1142.         {
  1143.           long fcount;
  1144.           openf_list *flist = (openf_list *) arg;
  1145.           fcount=0;
  1146.           inum=0;
  1147.           for(f=firstptr;f;f=f->next)
  1148.           {
  1149.             /* If same file or wrong device, skip */
  1150.             if( f->fc.dev!=dir->dev || f->fc.index==inum) continue;
  1151.             inum=f->fc.index;
  1152.             flist->flist[fcount++]=inum;
  1153.             if(fcount==flist->limit) return ERANGE;
  1154.           }
  1155.           flist->flist[fcount]=0;
  1156.         }
  1157.         return 0;
  1158.  
  1159.         case MFS_MKNOD:
  1160.         {
  1161.              long pos;
  1162.             unsigned inm,mode;
  1163.  
  1164.              if(uid) return EACCDN;
  1165.              mode = arg & 0xffff;
  1166.  
  1167.              /* Char and block specials only at present */
  1168.              if(!IM_SPEC(mode))return ERANGE;
  1169.  
  1170.              /* Create new name */
  1171.              pos=search_dir(name,dir->index,dir->dev,ADD);
  1172.              if(pos < 0) return pos;         
  1173.              inm=alloc_inode(dir->dev);
  1174.              if(!inm) return EWRITF;
  1175.  
  1176.              bzero(&rip,sizeof(d_inode));
  1177.  
  1178.             rip.i_mode = mode;
  1179.             rip.i_uid = uid;
  1180.             rip.i_gid = gid;
  1181.             rip.i_nlinks = 1;
  1182.  
  1183.             rip.i_mtime=Unixtime(Timestamp(), Datestamp());
  1184.             rip.i_atime=rip.i_mtime;
  1185.             rip.i_ctime=rip.i_mtime;
  1186.             rip.i_zone[0]= arg >> 16;
  1187.  
  1188.             write_inode(inm,&rip,dir->dev);
  1189.             l_write(dir->index,pos,2L,&inm,dir->dev);
  1190.             if(cache_mode) l_sync();
  1191.  
  1192.         }
  1193.         return 0;
  1194.  
  1195.         default:
  1196.         return EINVFN;
  1197.     }
  1198. }
  1199.  
  1200. /* m_rename, move a file or directory. Directories need special attention 
  1201.  * because if /usr/foo is moved to /usr/foo/bar then the filesystem will be
  1202.  * damaged by making the /usr/foo directory inaccessible. The sanity checking
  1203.  * performed is very simple but should cover all cases: Start at the parent
  1204.  * of the destination , check if this is the source inode , if not then 
  1205.  * move back to '..' and check again , repeatedly check until the root inode
  1206.  * is reached , if the source is ever seen on the way back to the root then
  1207.  * the rename is invalid , otherwise it should be OK.
  1208.  */
  1209.  
  1210. long m_rename(olddir,oldname,newdir,newname)
  1211. fcookie *olddir;
  1212. char *oldname;
  1213. fcookie *newdir;
  1214. char *newname;
  1215. {
  1216.     long finode,ret;
  1217.     d_inode rip;
  1218.     long pos;
  1219.     char dirmove,dirren;
  1220.     dirmove=0;
  1221.     dirren=0;
  1222. /* Check cross drives */
  1223.     if(olddir->dev!=newdir->dev)return EXDEV;
  1224.  
  1225. /* Check new doesn't exist and path is otherwise valid */
  1226.     finode=search_dir(newname,newdir->index,newdir->dev,FIND);
  1227.     if(finode>0) return EACCDN;
  1228.     if(finode!=EFILNF) return finode;
  1229.  
  1230. /* Check old path OK */
  1231.     if((finode=search_dir(oldname,olddir->index,olddir->dev,FIND))<0)
  1232.         return finode;
  1233.  
  1234.     read_inode(finode,&rip,olddir->dev);
  1235.  
  1236. /* Sanity check movement of directories */
  1237.     if(IS_DIR(rip))
  1238.     {
  1239.         dirren=1;
  1240.          if(olddir->index!=newdir->index)
  1241.         {
  1242. #ifdef MFS_NMOVE_DIR
  1243.             return EACCDN;
  1244. #else
  1245.             d_inode riptemp;
  1246.             ret=is_parent(newdir->index,finode,olddir->dev);
  1247.             if(ret < 0) return ret;
  1248.             if(ret) return EACCDN;
  1249.             read_inode(newdir->index,&riptemp,newdir->dev);
  1250.             if(riptemp.i_nlinks==MINIX_MAX_LINK) return EACCDN;
  1251.             TRACE("minixfs: valid directory move");
  1252.             dirmove=1;
  1253. #endif
  1254.         }
  1255.     }
  1256.  
  1257.     /* Check the m_getname cache is not invalidated by this move ....
  1258.     if no dir move, invalidate if the ldir is the name being changed ,
  1259.     if we move dir's then if the olddir is a parent of ldir, invalidate */
  1260.  
  1261.     if (lpath && ldir.dev == olddir->dev
  1262.         && (ldir.index == finode
  1263.         || (dirmove && is_parent (ldir.index, finode, olddir->dev) > 0)))
  1264.     {
  1265.         Kfree (lpath);
  1266.         lpath=0;
  1267.     }
  1268.         
  1269. /* Create new entry */
  1270.       if((pos=search_dir(newname,newdir->index,newdir->dev,ADD))<0) return pos;
  1271. /* Delete old path */
  1272.     if((finode=search_dir(oldname,olddir->index,olddir->dev,KILL))<0)
  1273.             return finode;
  1274.     {
  1275.       unshort ino = finode;
  1276.       l_write (newdir->index, pos, 2L, &ino, newdir->dev);
  1277.     }
  1278.  
  1279. /* When moving directories, fixup things like '..' and nlinks of old and
  1280.  * new dirs
  1281.  */
  1282.  
  1283.     if(dirmove)
  1284.     {
  1285.         pos=search_dir("..",finode,newdir->dev,POS);
  1286.         if(pos<0) 
  1287.         {
  1288.             ALERT("m_rename: no .. in inode %ld",finode);
  1289.             return EACCDN;
  1290.         }
  1291.         if(pos!=DIR_ENTRY_SIZE*super_ptr[newdir->dev]->increment)
  1292.           ALERT("m_rename: Unexpected .. position in inode %ld",finode);
  1293.         {
  1294.           unshort ino = newdir->index;
  1295.           l_write (finode, pos, 2L, &ino, newdir->dev);
  1296.         }
  1297.         read_inode(olddir->index,&rip,olddir->dev);
  1298.         rip.i_nlinks--;
  1299.         write_inode(olddir->index,&rip,olddir->dev);
  1300.         read_inode(newdir->index,&rip,newdir->dev);
  1301.         rip.i_nlinks++;
  1302.         write_inode(newdir->index,&rip,newdir->dev);
  1303.     }
  1304.  
  1305.     if(cache_mode) l_sync();
  1306.  
  1307. /* Check the m_getname cache is not invalidated by this move ....
  1308.  * if no dir alter, invalidate if the ldir is the name being changed ,
  1309.  * if we alter dir's then if the moved dir is a parent of ldir, invalidate.
  1310.  */
  1311.  
  1312.     if (lpath && ldir.dev == olddir->dev
  1313.         && (ldir.index == finode
  1314.         || (dirren && is_parent (ldir.index, finode, olddir->dev) > 0)))
  1315.     {
  1316.         Kfree (lpath);
  1317.         lpath=0;
  1318.     }
  1319.  
  1320.     return 0;
  1321. }
  1322.  
  1323. /* Minix hard-link, you can't make a hardlink to a directory ... it causes
  1324.  * too much trouble, use symbolic links instead.
  1325.  */
  1326.  
  1327. long m_hardlink(fromdir,fromname,todir,toname)
  1328. fcookie *fromdir;
  1329. char *fromname;
  1330. fcookie *todir;
  1331. char *toname;
  1332. {
  1333.     long finode;
  1334.     d_inode rip;
  1335.     long pos;
  1336.  
  1337. /* Check cross drives */
  1338.     if(fromdir->dev!=todir->dev)return EXDEV;
  1339.  
  1340. /* Check new doesn't exist and path is otherwise valid */
  1341.     finode=search_dir(toname,todir->index,todir->dev,FIND);
  1342.     if(finode>0) return EACCDN;
  1343.     if(finode!=EFILNF) return finode;
  1344.  
  1345. /* Check old path OK */
  1346.     if((finode=search_dir(fromname,fromdir->index,fromdir->dev,FIND))<0)
  1347.         return finode;
  1348.  
  1349.     read_inode(finode,&rip,fromdir->dev);
  1350.     if( (!IS_REG(rip) && !IM_SPEC(rip.i_mode))
  1351.         || (rip.i_nlinks >=MINIX_MAX_LINK) ) return EACCDN;
  1352.  
  1353. /* Create new entry */
  1354.     if((pos=search_dir(toname,todir->index,todir->dev,ADD))<0) return pos;
  1355.     {
  1356.       unshort ino = finode;
  1357.       l_write (todir->index, pos, 2L, &ino, todir->dev);
  1358.     }
  1359.     rip.i_nlinks++;
  1360.     rip.i_ctime=Unixtime(Timestamp(),Datestamp());
  1361.     write_inode(finode,&rip,fromdir->dev);
  1362.  
  1363.     if(cache_mode) l_sync();
  1364.  
  1365.     return 0;
  1366. }
  1367.  
  1368. /* Symbolic links ... basically similar to a regular file with one zone */
  1369.  
  1370. long m_symlink(dir,name,to)
  1371. fcookie *dir;
  1372. char *name;
  1373. char *to;
  1374. {
  1375.     d_inode rip;
  1376.     long pos;
  1377.     unshort newinode;
  1378.  
  1379.     if(!*to)
  1380.     {
  1381.         DEBUG("m_symlink: invalid null filename");
  1382.         return EACCDN;
  1383.     }
  1384.  
  1385.     /* Strip U: prefix */
  1386.     if ((to[0] == 'u' || to[0] == 'U') && to[1] == ':' && to[2] == '\\')
  1387.       to += 2;
  1388.  
  1389.     if(strlen(to)>=SYMLINK_NAME_MAX)
  1390.     {
  1391.         DEBUG("minixfs: Symbolic link name too long");        
  1392.         return ERANGE;
  1393.     }
  1394.  
  1395.     if((pos=search_dir(name,dir->index,dir->dev,ADD))<0) return pos;
  1396.  
  1397.     if(!(newinode=alloc_inode(dir->dev)))
  1398.     {
  1399.         DEBUG("minixfs: symlink drive %c,no free inodes",dir->dev+'A');
  1400.         return EACCDN;
  1401.     }
  1402.     
  1403.  
  1404.     bzero(&rip,sizeof(d_inode));
  1405.     rip.i_mode=I_SYMLINK | 0777;
  1406.     rip.i_size=strlen(to);
  1407.     rip.i_uid=Geteuid();
  1408.     rip.i_gid=Getegid();
  1409.     rip.i_mtime=Unixtime(Timestamp(),Datestamp());
  1410.     rip.i_ctime=rip.i_mtime;
  1411.     rip.i_atime=rip.i_mtime;
  1412.     rip.i_nlinks=1;
  1413.  
  1414.     if(!(rip.i_zone[0]=alloc_zone(dir->dev)))
  1415.     {
  1416.         free_inode(newinode,dir->dev);
  1417.         DEBUG("minixfs: symlink drive %c no free zones",dir->dev+'A');
  1418.         return EACCDN;
  1419.     }
  1420.     btos_cpy((char *)&temp,to);
  1421.      write_zone(rip.i_zone[0],&temp,dir->dev,&syscache);
  1422.     write_inode(newinode,&rip,dir->dev);
  1423.     l_write(dir->index,pos,2L,&newinode,dir->dev);
  1424.  
  1425.     if(cache_mode) l_sync();
  1426.  
  1427.     return 0;
  1428. }
  1429.  
  1430. long m_readlink(file,buf,len)
  1431. fcookie *file;
  1432. char *buf;
  1433. int len;
  1434. {
  1435.     long inum = file->index;
  1436.     d_inode rip;
  1437.  
  1438.     read_inode(inum,&rip,file->dev);
  1439.     if( (rip.i_mode & I_TYPE)!=I_SYMLINK)
  1440.     {
  1441.         DEBUG("minixfs: attempted readlink on non-symlink");
  1442.         return EACCDN;
  1443.     }
  1444.     read_zone(rip.i_zone[0],&temp,file->dev,&syscache);
  1445.     if (temp.bdata[0] == '/' && len > 2)
  1446.       {
  1447.         *buf++ = 'u';
  1448.         *buf++ = ':';
  1449.         len -= 2;
  1450.       }
  1451.     if(stob_ncpy(buf, (char *) &temp,len))
  1452.     {
  1453.         DEBUG("m_readlink: name too long");
  1454.         return ERANGE;
  1455.     }
  1456.     TRACE("m_readlink returned %s",buf);
  1457.  
  1458.     return 0;
  1459. }
  1460.  
  1461. /* the only settable attribute is FA_RDONLY; if the bit is set,
  1462.  * the mode is changed so that no write permission exists
  1463.  */
  1464. long m_chattr(file,attr)
  1465. fcookie *file;
  1466. int attr;
  1467. {
  1468.         long inum = file->index;
  1469.     int drive = file->dev;
  1470.     d_inode rip;
  1471.  
  1472.     if ( (attr & FA_RDONLY) ) {
  1473.         read_inode(inum,&rip,drive);
  1474.         rip.i_mode &= ~(0222);    /* turn off write permission */
  1475.         rip.i_ctime=Unixtime(Timestamp(),Datestamp());
  1476.         write_inode(inum,&rip,drive);
  1477.         if(cache_mode) l_sync();
  1478.     } else if (attr == 0) {
  1479.         read_inode(inum,&rip,drive);
  1480.         if ( (rip.i_mode & 0222) == 0 ) {
  1481.             rip.i_mode |= ( (rip.i_mode&0444) >> 1 );
  1482.                 /* turn write permission back on */
  1483.             rip.i_ctime=Unixtime(Timestamp(),Datestamp());
  1484.             write_inode(inum,&rip,drive);
  1485.             if(cache_mode) l_sync();
  1486.         }
  1487.     }
  1488.     return 0;
  1489. }
  1490.  
  1491. long m_pathconf(dir,which)
  1492. fcookie *dir;
  1493. int which;
  1494. {
  1495.     switch(which) {
  1496.     case -1:
  1497.         return DP_MAXREQ;
  1498.     case DP_IOPEN:
  1499.         return UNLIMITED;
  1500.     case DP_MAXLINKS:
  1501.          return MINIX_MAX_LINK;
  1502.     case DP_PATHMAX:
  1503.         return UNLIMITED; /* At last ! */
  1504.     case DP_NAMEMAX:
  1505.         return MMAX_FNAME(super_ptr[dir->dev]->increment);
  1506.     case DP_ATOMIC:
  1507.         return BLOCK_SIZE;    /* we can write at least a block atomically */
  1508.     case DP_TRUNC:
  1509.         return DP_AUTOTRUNC;
  1510.     case DP_CASE:
  1511.         return DP_CASESENS;    /* Well sort of ... */
  1512.     default:
  1513.         return EINVFN;
  1514.     }
  1515. }
  1516.  
  1517. long m_release(fc)
  1518. fcookie *fc;
  1519. {
  1520.     return 0;
  1521. }
  1522.  
  1523. long m_dupcookie(dest,src)
  1524. fcookie *dest,*src;
  1525. {
  1526.     unsigned tmpaux;
  1527.     tmpaux=dest->aux;
  1528.     *dest=*src;
  1529.     if(restore_dev!=-1 && 
  1530.     (tmpaux & (AUX_DEV|AUX_DRV))== restore_dev|AUX_DRV )
  1531.                         dest->dev = tmpaux & AUX_DEV;
  1532.  
  1533.     return 0;
  1534. }
  1535.