home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / ENTERPRS / CPM / UTILS / S / UZIUTILS.ARK / XFS.C < prev    next >
Text File  |  1988-12-24  |  43KB  |  2,292 lines

  1.  
  2. /**************************************************
  3. UZI (Unix Z80 Implementation) Utilities:  xfs.c
  4. ***************************************************/
  5.  
  6.  
  7. /*LINTLIBRARY*/
  8. #include "unix.h"
  9. #include "extern.h"
  10.  
  11. char *bread();
  12.  
  13.  
  14.  
  15. xfs_init(bootdev)
  16. int bootdev;
  17. {
  18.     register char *j;
  19.     inoptr i_open();
  20.  
  21.     fs_init();
  22.     bufinit();
  23.  
  24.     /* User's file table */
  25.     for (j=udata.u_files; j < (udata.u_files+UFTSIZE); ++j)
  26.     *j = -1;
  27.  
  28.     /* Open the console tty device */
  29.     if (d_open(TTYDEV) != 0)
  30.     panic("no tty");
  31.  
  32.     ROOTDEV = bootdev;
  33.  
  34.     /* Mount the root device */
  35.     if (fmount(ROOTDEV,NULLINODE))
  36.     panic("no filesys");
  37.  
  38.     ifnot (root = i_open(ROOTDEV,ROOTINODE))
  39.     panic("no root");
  40.     i_ref(udata.u_cwd = root);
  41.     rdtime(&udata.u_time);
  42. }
  43.  
  44.  
  45. xfs_end()
  46. {
  47.     register int16 j;
  48.  
  49.     for (j=0; j < UFTSIZE; ++j)
  50.     {
  51.     ifnot (udata.u_files[j] & 0x80)  /* Portable equivalent of == -1 */
  52.         doclose(j);
  53.     }
  54.  
  55.     _sync();  /* Not necessary, but a good idea. */
  56.  
  57. }
  58.  
  59.  
  60.  
  61. _open(name, flag)
  62. char *name;
  63. register int16 flag;
  64. {
  65.     int16 uindex;
  66.     register int16 oftindex;
  67.     register inoptr ino;
  68.     register int16 perm;
  69.     inoptr n_open();
  70.  
  71.     udata.u_error = 0;
  72.  
  73.     if (flag < 0 || flag > 2)
  74.     {
  75.     udata.u_error = EINVAL;
  76.     return (-1);
  77.     }
  78.     if ((uindex = uf_alloc()) == -1)
  79.     return (-1);
  80.  
  81.     if ((oftindex = oft_alloc()) == -1)
  82.     goto nooft;
  83.  
  84.     ifnot (ino = n_open(name,NULLINOPTR))
  85.     goto cantopen;
  86.  
  87.     of_tab[oftindex].o_inode = ino;
  88.  
  89.     perm = getperm(ino);
  90.     if (((flag == O_RDONLY || flag == O_RDWR) && !(perm & OTH_RD)) ||
  91.         ((flag == O_WRONLY || flag == O_RDWR) && !(perm & OTH_WR)))
  92.     {
  93.     udata.u_error = EPERM;
  94.     goto cantopen;
  95.     }
  96.  
  97.     if (getmode(ino) == F_DIR &&
  98.     (flag == O_WRONLY || flag == O_RDWR))
  99.     {
  100.     udata.u_error = EISDIR;
  101.     goto cantopen;
  102.     }
  103.  
  104.     if (isdevice(ino) && d_open((int)ino->c_node.i_addr[0]) != 0)
  105.     {
  106.     udata.u_error = ENXIO;
  107.     goto cantopen;
  108.     }
  109.  
  110.     udata.u_files[uindex] = oftindex;
  111.  
  112.     of_tab[oftindex].o_ptr.o_offset = 0;
  113.     of_tab[oftindex].o_ptr.o_blkno = 0;
  114.     of_tab[oftindex].o_access = flag;
  115.  
  116.     return (uindex);
  117.  
  118. cantopen:
  119.     oft_deref(oftindex);  /* This will call i_deref() */
  120. nooft:
  121.     udata.u_files[uindex] = -1;
  122.     return (-1);
  123. }
  124.  
  125.  
  126.  
  127.  
  128. _close(uindex)
  129. int16 uindex;
  130. {
  131.     udata.u_error = 0;
  132.     return(doclose(uindex));
  133. }
  134.  
  135.  
  136.  
  137. doclose(uindex)
  138. int16 uindex;
  139. {
  140.     register int16 oftindex;
  141.     inoptr ino;
  142.     inoptr getinode();
  143.  
  144.     udata.u_error = 0;
  145.     ifnot(ino = getinode(uindex))
  146.     return(-1);
  147.     oftindex = udata.u_files[uindex];
  148.  
  149.     if (isdevice(ino)
  150.     /* && ino->c_refs == 1 && of_tab[oftindex].o_refs == 1 */ )
  151.     d_close((int)(ino->c_node.i_addr[0]));
  152.  
  153.     udata.u_files[uindex] = -1;
  154.     oft_deref(oftindex);
  155.  
  156.     return(0);
  157. }
  158.  
  159.  
  160.  
  161. _creat(name, mode)
  162. char *name;
  163. int16 mode;
  164. {
  165.     register inoptr ino;
  166.     register int16 uindex;
  167.     register int16 oftindex;
  168.     inoptr parent;
  169.     register int16 j;
  170.     inoptr n_open();
  171.     inoptr newfile();
  172.  
  173.     udata.u_error = 0;
  174.     parent = NULLINODE;
  175.  
  176.     if ((uindex = uf_alloc()) == -1)
  177.     return (-1);
  178.     if ((oftindex = oft_alloc()) == -1)
  179.     return (-1);
  180.  
  181.     if (ino = n_open(name,&parent))  /* The file exists */
  182.     {
  183.     i_deref(parent);
  184.     if (getmode(ino) == F_DIR)
  185.     {
  186.         i_deref(ino);
  187.         udata.u_error = EISDIR;
  188.         goto nogood;
  189.     }
  190.       ifnot (getperm(ino) & OTH_WR)
  191.       {
  192.           i_deref(ino);
  193.           udata.u_error = EACCES;
  194.           goto nogood;
  195.       }
  196.       if (getmode(ino) == F_REG)
  197.     {
  198.         /* Truncate the file to zero length */
  199.         f_trunc(ino);
  200.         /* Reset any oft pointers */
  201.         for (j=0; j < OFTSIZE; ++j)
  202.         if (of_tab[j].o_inode == ino)
  203.             of_tab[j].o_ptr.o_blkno = of_tab[j].o_ptr.o_offset = 0;
  204.     }
  205.  
  206.     }
  207.     else
  208.     {
  209.     if (parent && (ino = newfile(parent,name)))
  210.          /* Parent was derefed in newfile */
  211.     {
  212.         ino->c_node.i_mode = (F_REG | (mode & MODE_MASK & ~udata.u_mask));
  213.         setftime(ino, A_TIME|M_TIME|C_TIME);
  214.         /* The rest of the inode is initialized in newfile() */
  215.         wr_inode(ino);
  216.     }
  217.     else
  218.     {
  219.         /* Doesn't exist and can't make it */
  220.         if (parent)
  221.         i_deref(parent);
  222.         goto nogood;
  223.     }
  224.     }
  225.  
  226.     udata.u_files[uindex] = oftindex;
  227.  
  228.     of_tab[oftindex].o_ptr.o_offset = 0;
  229.     of_tab[oftindex].o_ptr.o_blkno = 0;
  230.     of_tab[oftindex].o_inode = ino;
  231.     of_tab[oftindex].o_access = O_WRONLY;
  232.  
  233.     return (uindex);
  234.  
  235. nogood:
  236.     oft_deref(oftindex);
  237.     return (-1);
  238.  
  239. }
  240.  
  241.  
  242.  
  243.  
  244. _link(name1, name2)
  245. char *name1;
  246. char *name2;
  247. {
  248.     register inoptr ino;
  249.     register inoptr ino2;
  250.     inoptr parent2;
  251.     char *filename();
  252.     inoptr n_open();
  253.  
  254.     udata.u_error = 0;
  255.     ifnot (ino = n_open(name1,NULLINOPTR))
  256.     return(-1);
  257.  
  258.     if (getmode(ino) == F_DIR && !super())
  259.     {
  260.     udata.u_error = EPERM;
  261.     goto nogood;
  262.     }
  263.  
  264.     /* Make sure file2 doesn't exist, and get its parent */
  265.     if (ino2 = n_open(name2,&parent2))
  266.     {
  267.     i_deref(ino2);
  268.     i_deref(parent2);
  269.     udata.u_error = EEXIST;
  270.     goto nogood;
  271.     }
  272.     
  273.     ifnot (parent2)
  274.     goto nogood;
  275.  
  276.     if (ino->c_dev != parent2->c_dev)
  277.     {
  278.     i_deref(parent2);
  279.     udata.u_error = EXDEV;
  280.     goto nogood;
  281.     }
  282.  
  283.     if (ch_link(parent2,"",filename(name2),ino) == 0)
  284.     goto nogood;
  285.  
  286.  
  287.     /* Update the link count. */
  288.     ++ino->c_node.i_nlink;
  289.     wr_inode(ino);
  290.     setftime(ino, C_TIME);
  291.  
  292.     i_deref(parent2);
  293.     i_deref(ino);
  294.     return(0);
  295.  
  296. nogood:
  297.     i_deref(ino);
  298.     return(-1);
  299.  
  300. }
  301.  
  302.  
  303.  
  304. _unlink(path)
  305. char *path;
  306. {
  307.     register inoptr ino;
  308.     inoptr pino;
  309.     char *filename();
  310.     inoptr i_open();
  311.     inoptr n_open();
  312.  
  313.     udata.u_error = 0;
  314.     ino = n_open(path,&pino);
  315.  
  316.     ifnot (pino && ino)
  317.     {
  318.     udata.u_error = ENOENT;
  319.     return (-1);
  320.     }
  321.  
  322.     if (getmode(ino) == F_DIR && !super())
  323.     {
  324.     udata.u_error = EPERM;
  325.     goto nogood;
  326.     }
  327.  
  328.     /* Remove the directory entry */
  329.  
  330.     if (ch_link(pino,filename(path),"",NULLINODE) == 0)
  331.         goto nogood;
  332.  
  333.     /* Decrease the link count of the inode */
  334.  
  335.     ifnot (ino->c_node.i_nlink--)
  336.     {
  337.         ino->c_node.i_nlink += 2;
  338.     warning("_unlink: bad nlink");
  339.     }
  340.     setftime(ino, C_TIME);
  341.     i_deref(pino);
  342.     i_deref(ino);
  343.     return(0);
  344.  
  345. nogood:
  346.     i_deref(pino);
  347.     i_deref(ino);
  348.     return(-1);
  349. }
  350.  
  351.  
  352.  
  353.  
  354. _read(d, buf, nbytes)
  355. int16 d;
  356. char *buf;
  357. uint16 nbytes;
  358. {
  359.     register inoptr ino;
  360.     inoptr rwsetup();
  361.  
  362.     udata.u_error = 0;
  363.     /* Set up u_base, u_offset, ino; check permissions, file num. */
  364.     if ((ino = rwsetup(1, d, buf, nbytes)) == NULLINODE)
  365.     return (-1);   /* bomb out if error */
  366.  
  367.     readi(ino);
  368.     updoff(d);
  369.  
  370.     return (udata.u_count);
  371. }
  372.  
  373.  
  374.  
  375. _write(d, buf, nbytes)
  376. int16 d;
  377. char *buf;
  378. uint16 nbytes;
  379. {
  380.     register inoptr ino;
  381.     off_t *offp;
  382.     inoptr rwsetup();
  383.  
  384.     udata.u_error = 0;
  385.     /* Set up u_base, u_offset, ino; check permissions, file num. */
  386.     if ((ino = rwsetup(0, d, buf, nbytes)) == NULLINODE)
  387.     return (-1);   /* bomb out if error */
  388.  
  389.     writei(ino);
  390.     updoff(d);
  391.  
  392.     return (udata.u_count);
  393. }
  394.  
  395.  
  396.  
  397. inoptr
  398. rwsetup(rwflag, d, buf, nbytes)
  399. int rwflag;
  400. int d;
  401. char *buf;
  402. int nbytes;
  403. {
  404.     register inoptr ino;
  405.     register struct oft *oftp;
  406.     inoptr getinode();
  407.  
  408.     udata.u_base = buf;
  409.     udata.u_count = nbytes;
  410.  
  411.     if ((ino = getinode(d)) == NULLINODE)
  412.     return (NULLINODE);
  413.  
  414.     oftp = of_tab + udata.u_files[d];
  415.     if (oftp->o_access == (rwflag ? O_WRONLY : O_RDONLY))
  416.     {
  417.     udata.u_error = EBADF;
  418.     return (NULLINODE);
  419.     }
  420.  
  421.     setftime(ino, rwflag ? A_TIME : (A_TIME | M_TIME | C_TIME));
  422.  
  423.     /* Initialize u_offset from file pointer */
  424.     udata.u_offset.o_blkno = oftp->o_ptr.o_blkno;
  425.     udata.u_offset.o_offset = oftp->o_ptr.o_offset;
  426.  
  427.     return (ino);
  428. }
  429.  
  430.  
  431.  
  432. readi(ino)
  433. register inoptr ino;
  434. {
  435.     register uint16 amount;
  436.     register uint16 toread;
  437.     register blkno_t pblk;
  438.     register char *bp;
  439.     int dev;
  440.     int ispipe;
  441.     char *bread();
  442.     char *zerobuf();
  443.     blkno_t bmap();
  444.  
  445.     dev = ino->c_dev;
  446.     ispipe = 0;
  447.     switch (getmode(ino))
  448.     {
  449.  
  450.     case F_DIR:
  451.     case F_REG:
  452.  
  453.     /* See of end of file will limit read */
  454.     toread = udata.u_count =
  455.         ino->c_node.i_size.o_blkno-udata.u_offset.o_blkno >= 64 ?
  456.         udata.u_count :
  457.         min(udata.u_count,
  458.          512*(ino->c_node.i_size.o_blkno-udata.u_offset.o_blkno) +
  459.          (ino->c_node.i_size.o_offset-udata.u_offset.o_offset));
  460.     goto loop;
  461.  
  462.     case F_BDEV:
  463.     toread = udata.u_count;
  464.         dev = *(ino->c_node.i_addr);
  465.  
  466.     loop:
  467.     while (toread)
  468.     {
  469.         if ((pblk = bmap(ino, udata.u_offset.o_blkno, 1)) != NULLBLK)
  470.         bp = bread(dev, pblk, 0);
  471.         else
  472.         bp = zerobuf();
  473.  
  474.         bcopy(bp+udata.u_offset.o_offset, udata.u_base,
  475.             (amount = min(toread, 512 - udata.u_offset.o_offset)));
  476.         brelse(bp);
  477.  
  478.         udata.u_base += amount;
  479.         addoff(&udata.u_offset, amount);
  480.         if (ispipe && udata.u_offset.o_blkno >= 18)
  481.         udata.u_offset.o_blkno = 0;
  482.         toread -= amount;
  483.     }
  484.  
  485.     break;
  486.  
  487.     case F_CDEV:
  488.     udata.u_count = cdread(ino->c_node.i_addr[0]);
  489.  
  490.     if (udata.u_count != -1)
  491.         addoff(&udata.u_offset, udata.u_count);
  492.         break;
  493.  
  494.     default:
  495.     udata.u_error = ENODEV;
  496.     }
  497. }
  498.  
  499.  
  500.  
  501. /* Writei (and readi) need more i/o error handling */
  502.  
  503. writei(ino)
  504. register inoptr ino;
  505. {
  506.     register uint16 amount;
  507.     register uint16 towrite;
  508.     register char *bp;
  509.     int ispipe;
  510.     blkno_t pblk;
  511.     int created;    /* Set by bmap if newly allocated block used */
  512.     int dev;
  513.     char *zerobuf();
  514.     char *bread();
  515.     blkno_t bmap();
  516.  
  517.     dev = ino->c_dev;
  518.  
  519.     switch (getmode(ino))
  520.     {
  521.  
  522.     case F_BDEV:
  523.         dev = *(ino->c_node.i_addr);
  524.     case F_DIR:
  525.     case F_REG:
  526.       ispipe = 0;
  527.     towrite = udata.u_count;
  528.     goto loop;
  529.  
  530.     loop:
  531.  
  532.     while (towrite)
  533.     {
  534.         amount = min(towrite, 512 - udata.u_offset.o_offset);
  535.  
  536.  
  537.         if ((pblk = bmap(ino, udata.u_offset.o_blkno, 0)) == NULLBLK)
  538.         break;    /* No space to make more blocks */
  539.  
  540.         /* If we are writing an entire block, we don't care
  541.         about its previous contents */
  542.         bp = bread(dev, pblk, (amount == 512));
  543.  
  544.         bcopy(udata.u_base, bp+udata.u_offset.o_offset, amount);
  545.         bawrite(bp);
  546.  
  547.         udata.u_base += amount;
  548.         addoff(&udata.u_offset, amount);
  549.         towrite -= amount;
  550.     }
  551.  
  552.     /* Update size if file grew */
  553.     ifnot (ispipe)
  554.     {
  555.         if ( udata.u_offset.o_blkno > ino->c_node.i_size.o_blkno ||
  556.             (udata.u_offset.o_blkno == ino->c_node.i_size.o_blkno &&
  557.             udata.u_offset.o_offset > ino->c_node.i_size.o_offset))
  558.         {
  559.             ino->c_node.i_size.o_blkno = udata.u_offset.o_blkno;
  560.             ino->c_node.i_size.o_offset = udata.u_offset.o_offset;
  561.             ino->c_dirty = 1;
  562.         }    
  563.     }
  564.  
  565.     break;
  566.  
  567.     case F_CDEV:
  568.     udata.u_count = cdwrite(ino->c_node.i_addr[0]);
  569.  
  570.     if (udata.u_count != -1)
  571.         addoff(&udata.u_offset, udata.u_count);
  572.     break;
  573.  
  574.     default:
  575.     udata.u_error = ENODEV;
  576.     }
  577.  
  578. }
  579.  
  580.  
  581. min(a, b)
  582. int a, b;
  583. {
  584.     return ( a < b ? a : b);
  585. }
  586.  
  587.  
  588. psize(ino)
  589. inoptr ino;
  590. {
  591.     return (512*ino->c_node.i_size.o_blkno+ino->c_node.i_size.o_offset);
  592. }
  593.  
  594.  
  595.  
  596. addoff(ofptr, amount)
  597. off_t *ofptr;
  598. int amount;
  599. {
  600.     if (amount >= 0)
  601.     {
  602.     ofptr->o_offset += amount % 512;
  603.     if (ofptr->o_offset >= 512)
  604.     {
  605.     ofptr->o_offset -= 512;
  606.     ++ofptr->o_blkno;
  607.     }
  608.     ofptr->o_blkno += amount/512;
  609.     }
  610.     else
  611.     {
  612.         ofptr->o_offset -= (-amount) % 512;
  613.         if (ofptr->o_offset < 0)
  614.         {
  615.         ofptr->o_offset += 512;
  616.         --ofptr->o_blkno;
  617.         }
  618.         ofptr->o_blkno -= (-amount)/512;
  619.     }
  620. }
  621.  
  622.  
  623. updoff(d)
  624. int d;
  625. {
  626.     register off_t *offp;
  627.  
  628.     /* Update current file pointer */
  629.     offp = &of_tab[udata.u_files[d]].o_ptr;
  630.     offp->o_blkno = udata.u_offset.o_blkno;
  631.     offp->o_offset = udata.u_offset.o_offset;
  632. }
  633.  
  634.  
  635.  
  636. _seek(file,offset,flag)
  637. int16 file;
  638. uint16 offset;
  639. int16 flag;
  640. {
  641.     register inoptr ino;
  642.     register int16 oftno;
  643.     register uint16 retval;
  644.     inoptr getinode();
  645.  
  646.     udata.u_error = 0;
  647.     if ((ino = getinode(file)) == NULLINODE)
  648.     return(-1);
  649.  
  650.     oftno = udata.u_files[file];
  651.  
  652.  
  653.     if (flag <= 2)
  654.     retval = of_tab[oftno].o_ptr.o_offset;
  655.     else
  656.     retval = of_tab[oftno].o_ptr.o_blkno;
  657.  
  658.     switch(flag)
  659.     {
  660.     case 0:
  661.     of_tab[oftno].o_ptr.o_blkno = 0;
  662.     of_tab[oftno].o_ptr.o_offset = offset;
  663.     break;
  664.     case 1:
  665.     of_tab[oftno].o_ptr.o_offset += offset;
  666.     break;
  667.     case 2:
  668.     of_tab[oftno].o_ptr.o_blkno = ino->c_node.i_size.o_blkno;
  669.     of_tab[oftno].o_ptr.o_offset = ino->c_node.i_size.o_offset + offset;
  670.     break;
  671.     case 3:
  672.     of_tab[oftno].o_ptr.o_blkno = offset;
  673.     break;
  674.     case 4:
  675.     of_tab[oftno].o_ptr.o_blkno += offset;
  676.     break;
  677.     case 5:
  678.     of_tab[oftno].o_ptr.o_blkno = ino->c_node.i_size.o_blkno + offset;
  679.     break;
  680.     default:
  681.     udata.u_error = EINVAL;
  682.     return(-1);
  683.     }
  684.  
  685.     while ((unsigned)of_tab[oftno].o_ptr.o_offset >= 512)
  686.     {
  687.     of_tab[oftno].o_ptr.o_offset -= 512;
  688.     ++of_tab[oftno].o_ptr.o_blkno;
  689.     }
  690.  
  691.     return((int16)retval);
  692. }
  693.  
  694.  
  695.  
  696.  
  697. _chdir(dir)
  698. char *dir;
  699. {
  700.     register inoptr newcwd;
  701.     inoptr n_open();
  702.  
  703.     udata.u_error = 0;
  704.     ifnot (newcwd = n_open(dir,NULLINOPTR))
  705.     return(-1);
  706.  
  707.     if (getmode(newcwd) != F_DIR)
  708.     {
  709.     udata.u_error = ENOTDIR;
  710.     i_deref(newcwd);
  711.     return(-1);
  712.     }
  713.     i_deref(udata.u_cwd);
  714.     udata.u_cwd = newcwd;
  715.     return(0);
  716. }
  717.  
  718.  
  719.  
  720.  
  721. _mknod(name,mode,dev)
  722. char *name;
  723. int16 mode;
  724. int16 dev;
  725. {
  726.     register inoptr ino;
  727.     inoptr parent;
  728.     inoptr n_open();
  729.     inoptr newfile();
  730.  
  731.     udata.u_error = 0;
  732.     ifnot (super())
  733.     {
  734.     udata.u_error = EPERM;
  735.     return(-1);
  736.     }
  737.  
  738.     if (ino = n_open(name,&parent))
  739.     {
  740.     udata.u_error = EEXIST;
  741.     goto nogood;
  742.     }
  743.     
  744.     ifnot (parent)
  745.     {
  746.     udata.u_error = ENOENT;
  747.     return(-1);
  748.     }
  749.  
  750.     ifnot (ino = newfile(parent,name))
  751.     goto nogood2;
  752.  
  753.     /* Initialize mode and dev */
  754.     ino->c_node.i_mode = mode & ~udata.u_mask;
  755.     ino->c_node.i_addr[0] = isdevice(ino) ? dev : 0;
  756.     setftime(ino, A_TIME|M_TIME|C_TIME);
  757.     wr_inode(ino);
  758.  
  759.     i_deref(ino);
  760.     return (0);
  761.  
  762. nogood:
  763.     i_deref(ino);
  764. nogood2:
  765.     i_deref(parent);
  766.     return (-1);
  767. }
  768.  
  769.  
  770.  
  771.  
  772. _sync()
  773. {
  774.     register j;
  775.     register inoptr ino;
  776.     register char *buf;
  777.     char *bread();
  778.  
  779.     /* Write out modified inodes */
  780.  
  781.     udata.u_error = 0;
  782.     for (ino=i_tab; ino < i_tab+ITABSIZE; ++ino)
  783.     if ((ino->c_refs) > 0 && ino->c_dirty != 0)
  784.     {
  785.         wr_inode(ino);
  786.         ino->c_dirty = 0;
  787.     }
  788.  
  789.     /* Write out modified super blocks */
  790.     /* This fills the rest of the super block with garbage. */
  791.  
  792.     for (j=0; j < NDEVS; ++j)
  793.     {
  794.     if (fs_tab[j].s_mounted == SMOUNTED && fs_tab[j].s_fmod)
  795.     {
  796.         fs_tab[j].s_fmod = 0;
  797.         buf = bread(j, 1, 1);
  798.         bcopy((char *)&fs_tab[j], buf, 512);
  799.         bfree(buf, 2);
  800.     }
  801.     }
  802.  
  803.     bufsync();   /* Clear buffer pool */
  804. }
  805.  
  806.  
  807. _access(path,mode)
  808. char *path;
  809. int16 mode;
  810. {
  811.     register inoptr ino;
  812.     register int16 euid;
  813.     register int16 egid;
  814.     register int16 retval;
  815.     inoptr n_open();
  816.  
  817.     udata.u_error = 0;
  818.     if ((mode & 07) && !*(path))
  819.     {
  820.     udata.u_error = ENOENT;
  821.     return (-1);
  822.     }
  823.  
  824.     /* Temporarily make eff. id real id. */
  825.     euid = udata.u_euid;
  826.     egid = udata.u_egid;
  827.     udata.u_euid = udata.u_ptab->p_uid;
  828.     udata.u_egid = udata.u_gid;
  829.  
  830.     ifnot (ino = n_open(path,NULLINOPTR))
  831.     {
  832.     retval = -1;
  833.     goto nogood;
  834.     }
  835.     
  836.     retval = 0;
  837.     if (~getperm(ino) & (mode&07))
  838.     {
  839.     udata.u_error = EPERM;
  840.     retval = -1;
  841.     }
  842.  
  843.     i_deref(ino);
  844. nogood:
  845.     udata.u_euid = euid;
  846.     udata.u_egid = egid;
  847.  
  848.     return(retval);
  849. }
  850.  
  851.  
  852. _chmod(path,mode)
  853. char *path;
  854. int16 mode;
  855. {
  856.  
  857.     inoptr ino;
  858.     inoptr n_open();
  859.  
  860.     udata.u_error = 0;
  861.     ifnot (ino = n_open(path,NULLINOPTR))
  862.     return (-1);
  863.  
  864.     if (ino->c_node.i_uid != udata.u_euid && !super())
  865.     {
  866.     i_deref(ino);
  867.     udata.u_error = EPERM;
  868.     return(-1);
  869.     }
  870.  
  871.     ino->c_node.i_mode = (mode & MODE_MASK) | (ino->c_node.i_mode & F_MASK);
  872.     setftime(ino, C_TIME);
  873.     i_deref(ino);
  874.     return(0);
  875. }
  876.  
  877.  
  878.  
  879.  
  880. _chown(path, owner, group)
  881. char *path;
  882. int owner;
  883. int group;
  884. {
  885.     register inoptr ino;
  886.     inoptr n_open();
  887.  
  888.     udata.u_error = 0;
  889.     ifnot (ino = n_open(path,NULLINOPTR))
  890.     return (-1);
  891.  
  892.     if (ino->c_node.i_uid != udata.u_euid && !super())
  893.     {
  894.     i_deref(ino);
  895.     udata.u_error = EPERM;
  896.     return(-1);
  897.     }
  898.  
  899.     ino->c_node.i_uid = owner;
  900.     ino->c_node.i_gid = group;
  901.     setftime(ino, C_TIME);
  902.     i_deref(ino);
  903.     return(0);
  904. }
  905.  
  906.  
  907.  
  908.  
  909. _stat(path,buf)
  910. char *path;
  911. char *buf;
  912. {
  913.  
  914.     register inoptr ino;
  915.     inoptr n_open();
  916.  
  917.     udata.u_error = 0;
  918.     ifnot (valadr(buf,sizeof(struct stat)) && (ino = n_open(path,NULLINOPTR)))
  919.     {
  920.     return (-1);
  921.     }
  922.  
  923.     stcpy(ino,buf);
  924.     i_deref(ino);
  925.     return(0);
  926. }
  927.  
  928.  
  929.  
  930.  
  931. _fstat(fd, buf)
  932. int16 fd;
  933. char *buf;
  934. {
  935.     register inoptr ino;
  936.     inoptr getinode();
  937.  
  938.     udata.u_error = 0;
  939.     ifnot (valadr(buf,sizeof(struct stat)))
  940.     return(-1);
  941.  
  942.     if ((ino = getinode(fd)) == NULLINODE)
  943.     return(-1);
  944.  
  945.     stcpy(ino,buf);
  946.     return(0);
  947. }
  948.  
  949.  
  950.  
  951. /* Utility for stat and fstat */
  952. stcpy(ino, buf)
  953. inoptr ino;
  954. char *buf;
  955. {
  956.     /* violently system-dependent */
  957.     bcopy((char *)&(ino->c_dev), buf, 12);
  958.     bcopy((char *)&(ino->c_node.i_addr[0]), buf+12, 2);
  959.     bcopy((char *)&(ino->c_node.i_size), buf+14, 16);
  960. }
  961.  
  962.  
  963.  
  964. _dup(oldd)
  965. int16 oldd;
  966. {
  967.     register int newd;
  968.     inoptr getinode();
  969.  
  970.     udata.u_error = 0;
  971.     if (getinode(oldd) == NULLINODE)
  972.     return(-1);
  973.  
  974.     if ((newd = uf_alloc()) == -1)
  975.     return (-1);
  976.     
  977.     udata.u_files[newd] = udata.u_files[oldd];
  978.     ++of_tab[udata.u_files[oldd]].o_refs;
  979.  
  980.     return(newd);
  981. }
  982.  
  983.  
  984.  
  985.  
  986. _dup2(oldd, newd)
  987. int16 oldd;
  988. int16 newd;
  989. {
  990.     inoptr getinode();
  991.  
  992.     udata.u_error = 0;
  993.     if (getinode(oldd) == NULLINODE)
  994.     return(-1);
  995.  
  996.     if (newd < 0 || newd >= UFTSIZE)
  997.     {
  998.     udata.u_error = EBADF;
  999.     return (-1);
  1000.     }
  1001.     
  1002.     ifnot (udata.u_files[newd] & 0x80)
  1003.     doclose(newd);
  1004.     
  1005.     udata.u_files[newd] = udata.u_files[oldd];
  1006.     ++of_tab[udata.u_files[oldd]].o_refs;
  1007.  
  1008.     return(0);
  1009. }
  1010.  
  1011.  
  1012.  
  1013.  
  1014. _umask(mask)
  1015. int mask;
  1016. {
  1017.     register int omask;
  1018.  
  1019.     udata.u_error = 0;
  1020.     omask = udata.u_mask;
  1021.     udata.u_mask = mask & 0777;
  1022.     return(omask);
  1023. }
  1024.  
  1025.  
  1026.  
  1027.  
  1028. /* Special system call returns super-block of given
  1029. filesystem for users to determine free space, etc.
  1030. Should be replaced with a sync() followed by a read
  1031. of block 1 of the device.  */
  1032.  
  1033. _getfsys(dev,buf)
  1034. {
  1035.     udata.u_error = 0;
  1036.    if (dev < 0 || dev >= NDEVS || fs_tab[dev].s_mounted != SMOUNTED)
  1037.    {
  1038.        udata.u_error = ENXIO;
  1039.        return(-1);
  1040.     }
  1041.  
  1042.     bcopy((char *)&fs_tab[dev],(char *)buf,sizeof(struct filesys));
  1043.     return(0);
  1044. }
  1045.  
  1046.  
  1047.  
  1048. _ioctl(fd, request, data)
  1049. int fd;
  1050. int request;
  1051. char *data;
  1052. {
  1053.  
  1054.     register inoptr ino;
  1055.     register int dev;
  1056.     inoptr getinode();
  1057.  
  1058.     udata.u_error = 0;
  1059.     if ((ino = getinode(fd)) == NULLINODE)
  1060.     return(-1);
  1061.  
  1062.     ifnot (isdevice(ino))
  1063.     {
  1064.     udata.u_error = ENOTTY;
  1065.     return(-1);
  1066.     }
  1067.  
  1068.     ifnot (getperm(ino) & OTH_WR)
  1069.     {
  1070.     udata.u_error = EPERM;
  1071.     return(-1);
  1072.     }
  1073.  
  1074.     dev = ino->c_node.i_addr[0];
  1075.  
  1076.     if (d_ioctl(dev, request,data))
  1077.     return(-1);
  1078.     return(0);
  1079. }
  1080.  
  1081.  
  1082.  
  1083.  
  1084. _mount(spec, dir, rwflag)
  1085. char *spec;
  1086. char *dir;
  1087. int rwflag;
  1088. {
  1089.     register inoptr sino, dino;
  1090.     register int dev;
  1091.     inoptr n_open();
  1092.  
  1093.     udata.u_error = 0;
  1094.     ifnot(super())
  1095.     {
  1096.     udata.u_error = EPERM;
  1097.     return (-1);
  1098.     }
  1099.  
  1100.     ifnot (sino = n_open(spec,NULLINOPTR))
  1101.     return (-1);
  1102.  
  1103.     ifnot (dino = n_open(dir,NULLINOPTR))
  1104.     {
  1105.     i_deref(sino);
  1106.     return (-1);
  1107.     }
  1108.  
  1109.     if (getmode(sino) != F_BDEV)
  1110.     {
  1111.     udata.u_error = ENOTBLK;
  1112.     goto nogood;
  1113.     }
  1114.  
  1115.     if (getmode(dino) != F_DIR)
  1116.     {
  1117.     udata.u_error = ENOTDIR;
  1118.     goto nogood;
  1119.     }
  1120.  
  1121.     dev = (int)sino->c_node.i_addr[0];
  1122.  
  1123.     if ( dev >= NDEVS || d_open(dev))
  1124.     {
  1125.     udata.u_error = ENXIO;
  1126.     goto nogood;
  1127.     }
  1128.  
  1129.     if (fs_tab[dev].s_mounted || dino->c_refs != 1 || dino->c_num == ROOTINODE)
  1130.     {
  1131.        udata.u_error = EBUSY;
  1132.        goto nogood;
  1133.     }
  1134.  
  1135.     _sync();
  1136.  
  1137.     if (fmount(dev,dino))
  1138.     {
  1139.        udata.u_error = EBUSY;
  1140.        goto nogood;
  1141.     }
  1142.  
  1143.     i_deref(dino);
  1144.     i_deref(sino);
  1145.     return(0);
  1146.  
  1147. nogood:
  1148.     i_deref(dino);
  1149.     i_deref(sino);
  1150.     return (-1);
  1151. }
  1152.  
  1153.  
  1154.  
  1155.  
  1156. _umount(spec)
  1157. char *spec;
  1158. {
  1159.     register inoptr sino;
  1160.     register int dev;
  1161.     register inoptr ptr;
  1162.     inoptr n_open();
  1163.  
  1164.     udata.u_error = 0;
  1165.     ifnot(super())
  1166.     {
  1167.     udata.u_error = EPERM;
  1168.     return (-1);
  1169.     }
  1170.  
  1171.     ifnot (sino = n_open(spec,NULLINOPTR))
  1172.     return (-1);
  1173.  
  1174.     if (getmode(sino) != F_BDEV)
  1175.     {
  1176.     udata.u_error = ENOTBLK;
  1177.     goto nogood;
  1178.     }
  1179.  
  1180.     dev = (int)sino->c_node.i_addr[0];
  1181.     ifnot (validdev(dev))
  1182.     {
  1183.     udata.u_error = ENXIO;
  1184.     goto nogood;
  1185.     }
  1186.  
  1187.     if (!fs_tab[dev].s_mounted)
  1188.     {
  1189.     udata.u_error = EINVAL;
  1190.     goto nogood;
  1191.     }
  1192.  
  1193.     for (ptr = i_tab; ptr < i_tab+ITABSIZE; ++ptr)
  1194.     if (ptr->c_refs > 0 && ptr->c_dev == dev)
  1195.     {
  1196.         udata.u_error = EBUSY;
  1197.         goto nogood;
  1198.     }
  1199.  
  1200.     _sync();
  1201.     fs_tab[dev].s_mounted = 0;
  1202.     i_deref(fs_tab[dev].s_mntpt);
  1203.  
  1204.     i_deref(sino);
  1205.     return(0);
  1206.  
  1207. nogood:
  1208.     i_deref(sino);
  1209.     return (-1);
  1210. }
  1211.  
  1212.  
  1213.  
  1214.  
  1215.  
  1216. _time(tvec)
  1217. int tvec[];
  1218. {
  1219.     udata.u_error = 0;
  1220.     rdtime(tvec);  /* In machdep.c */
  1221.     return(0);
  1222. }
  1223.  
  1224.  
  1225.  
  1226.  
  1227.  
  1228.  
  1229.  
  1230.  
  1231.  
  1232.  
  1233.  
  1234.  
  1235. /* N_open is given a string containing a path name,
  1236.   and returns a inode table pointer.  If it returns NULL,
  1237.   the file did not exist.  If the parent existed,
  1238.   and parent is not null, parent will be filled in with
  1239.   the parents inoptr. Otherwise, parent will be set to NULL. */
  1240.  
  1241. inoptr
  1242. n_open(name,parent)
  1243. register char *name;
  1244. register inoptr *parent;
  1245. {
  1246.  
  1247.     register inoptr wd;  /* the directory we are currently searching. */
  1248.     register inoptr ninode;
  1249.     register inoptr temp;
  1250.     inoptr srch_dir();
  1251.     inoptr srch_mt();
  1252.  
  1253.     if (*name == '/')
  1254.     wd = root;
  1255.     else
  1256.     wd = udata.u_cwd;
  1257.  
  1258.     i_ref(ninode = wd);
  1259.     i_ref(ninode);
  1260.  
  1261.     for(;;)
  1262.     {
  1263.     if (ninode)
  1264.         magic(ninode);
  1265.  
  1266.     /* See if we are at a mount point */
  1267.     if (ninode)
  1268.         ninode = srch_mt(ninode);
  1269.  
  1270.     while (*name == '/')    /* Skip (possibly repeated) slashes */
  1271.         ++name;
  1272.     ifnot (*name)        /* No more components of path? */
  1273.         break;
  1274.     ifnot (ninode)
  1275.     {
  1276.         udata.u_error = ENOENT;
  1277.         goto nodir;
  1278.     }
  1279.     i_deref(wd);
  1280.     wd = ninode;
  1281.     if (getmode(wd) != F_DIR)
  1282.     {
  1283.         udata.u_error = ENOTDIR;
  1284.         goto nodir;
  1285.     }
  1286.     ifnot (getperm(wd) & OTH_EX)
  1287.     {
  1288.         udata.u_error = EPERM;
  1289.         goto nodir;
  1290.     }
  1291.  
  1292.     /* See if we are going up through a mount point */
  1293.     if ( wd->c_num == ROOTINODE && wd->c_dev != ROOTDEV && name[1] == '.')
  1294.     {
  1295.        temp = fs_tab[wd->c_dev].s_mntpt;
  1296.        ++temp->c_refs;
  1297.        i_deref(wd);
  1298.        wd = temp;
  1299.     }
  1300.  
  1301.     ninode = srch_dir(wd,name);
  1302.  
  1303.     while (*name != '/' && *name )
  1304.         ++name;
  1305.     }
  1306.  
  1307.     if (parent)
  1308.     *parent = wd;
  1309.     else
  1310.     i_deref(wd);
  1311.     ifnot (parent || ninode)
  1312.     udata.u_error = ENOENT;
  1313.     return (ninode);
  1314.  
  1315. nodir:
  1316.     if (parent)
  1317.     *parent = NULLINODE;
  1318.     i_deref(wd);
  1319.     return(NULLINODE);
  1320.  
  1321. }
  1322.  
  1323.  
  1324.  
  1325. /* Srch_dir is given a inode pointer of an open directory
  1326. and a string containing a filename, and searches the directory
  1327. for the file.  If it exists, it opens it and returns the inode pointer,
  1328. otherwise NULL. This depends on the fact that ba_read will return unallocated
  1329. blocks as zero-filled, and a partially allocated block will be padded with
  1330. zeroes.  */
  1331.  
  1332. inoptr
  1333. srch_dir(wd,compname)
  1334. register inoptr wd;
  1335. register char *compname;
  1336. {
  1337.     register int curentry;
  1338.     register blkno_t curblock;
  1339.     register struct direct *buf;
  1340.     register int nblocks;
  1341.     unsigned inum;
  1342.     inoptr i_open();
  1343.     blkno_t bmap();
  1344.  
  1345.     nblocks = wd->c_node.i_size.o_blkno;
  1346.     if (wd->c_node.i_size.o_offset)
  1347.     ++nblocks;
  1348.  
  1349.     for (curblock=0; curblock < nblocks; ++curblock)
  1350.     {
  1351.     buf = (struct direct *)bread( wd->c_dev, bmap(wd, curblock, 1), 0);
  1352.     for (curentry = 0; curentry < 32; ++curentry)
  1353.     {
  1354.         if (namecomp(compname,buf[curentry].d_name))
  1355.         {
  1356.         inum = buf[curentry&0x1f].d_ino;
  1357.         brelse(buf);
  1358.         return(i_open(wd->c_dev, inum));
  1359.         }
  1360.     }
  1361.     brelse(buf);
  1362.     }
  1363.     return(NULLINODE);
  1364. }
  1365.  
  1366.  
  1367.  
  1368. /* Srch_mt sees if the given inode is a mount point. If
  1369. so it dereferences it, and references and returns a pointer
  1370. to the root of the mounted filesystem. */
  1371.  
  1372. inoptr
  1373. srch_mt(ino)
  1374. register inoptr ino;
  1375. {
  1376.     register int j;
  1377.     inoptr i_open();
  1378.  
  1379.     for (j=0; j < NDEVS; ++j)
  1380.     if (fs_tab[j].s_mounted == SMOUNTED && fs_tab[j].s_mntpt == ino)
  1381.     {
  1382.         i_deref(ino);
  1383.         return(i_open(j,ROOTINODE));
  1384.     }
  1385.     
  1386.     return(ino);
  1387. }
  1388.  
  1389.  
  1390. /* I_open is given an inode number and a device number,
  1391. and makes an entry in the inode table for them, or
  1392. increases it reference count if it is already there.
  1393. An inode # of zero means a newly allocated inode */
  1394.  
  1395. inoptr
  1396. i_open(dev,ino)
  1397. register int dev;
  1398. register unsigned ino;
  1399. {
  1400.  
  1401.     struct dinode *buf;
  1402.     register inoptr nindex;
  1403.     int i;
  1404.     register inoptr j;
  1405.     int new;
  1406.     static nexti = i_tab;
  1407.     unsigned i_alloc();
  1408.  
  1409.     if (dev<0 || dev>=NDEVS)
  1410.     panic("i_open: Bad dev");
  1411.  
  1412.     new = 0;
  1413.     ifnot (ino)  /* Want a new one */
  1414.     {
  1415.     new = 1;
  1416.         ifnot (ino = i_alloc(dev))
  1417.         {
  1418.         udata.u_error = ENOSPC;
  1419.         return (NULLINODE);
  1420.         }
  1421.     }
  1422.  
  1423.     if (ino < ROOTINODE || ino >= (fs_tab[dev].s_isize-2)*8)
  1424.     {
  1425.     warning("i_open: bad inode number");
  1426.     return (NULLINODE);
  1427.     }
  1428.  
  1429.  
  1430.     nindex = NULLINODE;
  1431.     j = nexti;
  1432.     for (i=0; i < ITABSIZE; ++i)
  1433.     {
  1434.         nexti =j;
  1435.         if (++j >= i_tab+ITABSIZE)
  1436.         j = i_tab;
  1437.  
  1438.         ifnot (j->c_refs)
  1439.        nindex = j;
  1440.  
  1441.     if (j->c_dev == dev && j->c_num == ino)
  1442.     {
  1443.         nindex = j;
  1444.         goto found;
  1445.     }
  1446.     }
  1447.  
  1448.     /* Not already in table. */
  1449.  
  1450.     ifnot (nindex)  /* No unrefed slots in inode table */
  1451.     {
  1452.     udata.u_error = ENFILE;
  1453.     return(NULLINODE);
  1454.     }
  1455.  
  1456.     buf = (struct dinode *)bread(dev, (ino>>3)+2, 0);
  1457.     bcopy((char *)&(buf[ino & 0x07]), (char *)&(nindex->c_node), 64);
  1458.     brelse(buf);
  1459.  
  1460.     nindex->c_dev = dev;
  1461.     nindex->c_num = ino;
  1462.     nindex->c_magic = CMAGIC;
  1463.  
  1464. found:
  1465.     if (new)
  1466.     {
  1467.         if (nindex->c_node.i_nlink || nindex->c_node.i_mode & F_MASK)
  1468.         goto badino;
  1469.     }
  1470.     else
  1471.     {
  1472.         ifnot (nindex->c_node.i_nlink && nindex->c_node.i_mode & F_MASK)
  1473.         goto badino;
  1474.     }
  1475.  
  1476.     ++nindex->c_refs;
  1477.     return(nindex);
  1478.  
  1479. badino:
  1480.     warning("i_open: bad disk inode");
  1481.     return (NULLINODE);
  1482. }
  1483.  
  1484.  
  1485.  
  1486. /* Ch_link modifies or makes a new entry in the directory for the name
  1487. and inode pointer given. The directory is searched for oldname.
  1488. When found, it is changed to newname, and it inode # is that of
  1489. *nindex.  A oldname of "" matches a unused slot, and a nindex
  1490. of NULLINODE means an inode # of 0.  A return status of 0 means there
  1491. was no space left in the filesystem, or a non-empty oldname was not found,
  1492. or the user did not have write permission. */
  1493.  
  1494. ch_link(wd,oldname,newname,nindex)
  1495. register inoptr wd;
  1496. char *oldname;
  1497. char *newname;
  1498. inoptr nindex;
  1499. {
  1500.     struct direct curentry;
  1501.  
  1502.     ifnot (getperm(wd) & OTH_WR)
  1503.     {
  1504.     udata.u_error = EPERM;
  1505.     return (0);
  1506.     }
  1507.  
  1508.     /* Search the directory for the desired slot. */
  1509.  
  1510.     udata.u_offset.o_blkno = 0;
  1511.     udata.u_offset.o_offset = 0;
  1512.  
  1513.     for (;;)
  1514.     {
  1515.     udata.u_count = 16;
  1516.     udata.u_base = (char *)&curentry;
  1517.     readi(wd);
  1518.  
  1519.     /* Read until EOF or name is found */
  1520.     /* readi() advances udata.u_offset */
  1521.     if (udata.u_count == 0 || namecomp(oldname, curentry.d_name))
  1522.         break;
  1523.     }
  1524.  
  1525.     if (udata.u_count == 0 && *oldname)
  1526.     return (0);   /* Entry not found */
  1527.  
  1528.     bcopy(newname, curentry.d_name, 14);
  1529.     if (nindex)
  1530.     curentry.d_ino = nindex->c_num;
  1531.     else
  1532.     curentry.d_ino = 0;
  1533.  
  1534.     /* If an existing slot is being used, we must back up the file offset */
  1535.     if (udata.u_count)
  1536.     {
  1537.     ifnot (udata.u_offset.o_offset)
  1538.     {
  1539.         --udata.u_offset.o_blkno;
  1540.         udata.u_offset.o_offset = 512;
  1541.     }
  1542.     udata.u_offset.o_offset -= 16;
  1543.     }
  1544.  
  1545.     udata.u_count = 16;
  1546.     udata.u_base = (char *)&curentry;
  1547.     writei(wd);
  1548.  
  1549.     if (udata.u_error)
  1550.     return (0);
  1551.  
  1552.     setftime(wd, A_TIME|M_TIME|C_TIME);  /* Sets c_dirty */
  1553.  
  1554.     /* Update file length to next block */
  1555.     if (wd->c_node.i_size.o_offset)
  1556.     {
  1557.     wd->c_node.i_size.o_offset = 0;
  1558.     ++wd->c_node.i_size.o_blkno;
  1559.     }
  1560.  
  1561.     return (1);
  1562. }
  1563.  
  1564.  
  1565.  
  1566. /* Filename is given a path name, and returns a pointer
  1567. to the final component of it. */
  1568.  
  1569. char *
  1570. filename(path)
  1571. char *path;
  1572. {
  1573.     register char *ptr;
  1574.  
  1575.     ptr = path;
  1576.     while (*ptr)
  1577.     ++ptr;
  1578.     while (*ptr != '/' && ptr-- > path)
  1579.     ;
  1580.     return (ptr+1);
  1581. }
  1582.  
  1583.  
  1584. /* Namecomp compares two strings to see if they are the same file name.
  1585. It stops at 14 chars or a null or a slash. It returns 0 for difference. */
  1586.  
  1587. namecomp(n1,n2)
  1588. register char *n1;
  1589. register char *n2;
  1590. {
  1591.     register int n;
  1592.  
  1593.     n = 14;
  1594.     while (*n1 && *n1 != '/')
  1595.     {
  1596.     if (*n1++ != *n2++)
  1597.         return(0);
  1598.     ifnot (--n)
  1599.         return(-1);
  1600.     }
  1601.     return(*n2 == '\0' || *n2 == '/');
  1602. }
  1603.  
  1604.  
  1605.  
  1606. /* Newfile is given a pointer to a directory and a name, and
  1607.    creates an entry in the directory for the name, dereferences
  1608.    the parent, and returns a pointer to the new inode.
  1609.    It allocates an inode number,
  1610.    and creates a new entry in the inode table for the new file,
  1611.    and initializes the inode table entry for the new file.  The new file
  1612.    will have one reference, and 0 links to it. 
  1613.    Better make sure there isn't already an entry with the same name. */
  1614.  
  1615. inoptr
  1616. newfile(pino, name)
  1617. register inoptr pino;
  1618. register char *name;
  1619. {
  1620.  
  1621.     register inoptr nindex;
  1622.     register int j;
  1623.     inoptr i_open();
  1624.  
  1625.     ifnot (nindex = i_open(pino->c_dev, 0))
  1626.     goto nogood;
  1627.  
  1628.     nindex->c_node.i_mode = F_REG;   /* For the time being */
  1629.     nindex->c_node.i_nlink = 1;
  1630.     nindex->c_node.i_size.o_offset = 0;
  1631.     nindex->c_node.i_size.o_blkno = 0;
  1632.     for (j=0; j <20; j++)
  1633.         nindex->c_node.i_addr[j] = 0;
  1634.     wr_inode(nindex);
  1635.  
  1636.     ifnot (ch_link(pino,"",filename(name),nindex))
  1637.     {
  1638.     i_deref(nindex);
  1639.     goto nogood;
  1640.     }
  1641.  
  1642.     i_deref (pino);
  1643.     return(nindex);
  1644.  
  1645. nogood:
  1646.     i_deref (pino);
  1647.     return (NULLINODE);
  1648. }
  1649.  
  1650.  
  1651.  
  1652. /* Check the given device number, and return its address in the mount table.
  1653. Also time-stamp the superblock of dev, and mark it modified.
  1654. Used when freeing and allocating blocks and inodes. */
  1655.  
  1656. fsptr
  1657. getdev(devno)
  1658. register int devno;
  1659. {
  1660.     register fsptr dev;
  1661.  
  1662.     dev = fs_tab + devno;
  1663.     if (devno < 0 || devno >= NDEVS || !dev->s_mounted)
  1664.     panic("getdev: bad dev");
  1665.     rdtime(&(dev->s_time));
  1666.     dev->s_fmod = 1;
  1667.     return (dev);
  1668. }
  1669.  
  1670.  
  1671. /* Returns true if the magic number of a superblock is corrupt */
  1672.  
  1673. baddev(dev)
  1674. fsptr dev;
  1675. {
  1676.     return (dev->s_mounted != SMOUNTED);
  1677. }
  1678.  
  1679.  
  1680. /* I_alloc finds an unused inode number, and returns it,
  1681. or 0 if there are no more inodes available. */
  1682.  
  1683. unsigned 
  1684. i_alloc(devno)
  1685. int devno;
  1686. {
  1687.     fsptr dev;
  1688.     blkno_t blk;
  1689.     struct dinode *buf;
  1690.     register int j;
  1691.     register int k;
  1692.     unsigned ino;
  1693.  
  1694.     if (baddev(dev = getdev(devno)))
  1695.     goto corrupt;
  1696.  
  1697. tryagain:
  1698.     if (dev->s_ninode)
  1699.     {
  1700.     ifnot (dev->s_tinode)
  1701.         goto corrupt;
  1702.     ino = dev->s_inode[--dev->s_ninode];
  1703.     if (ino < 2 || ino >= (dev->s_isize-2)*8)
  1704.         goto corrupt;
  1705.     --dev->s_tinode;
  1706.     return(ino);
  1707.     }
  1708.  
  1709.     /* We must scan the inodes, and fill up the table */
  1710.  
  1711.     _sync();  /* Make on-disk inodes consistent */
  1712.     k = 0;
  1713.     for (blk = 2; blk < dev->s_isize; blk++)
  1714.     {
  1715.         buf = (struct dinode *)bread(devno, blk, 0);
  1716.     for (j=0; j < 8; j++)
  1717.     {
  1718.         ifnot (buf[j].i_mode || buf[j].i_nlink)
  1719.         dev->s_inode[k++] = 8*(blk-2) + j;
  1720.         if (k==50)
  1721.         {
  1722.             brelse(buf);
  1723.         goto done;
  1724.         }
  1725.     }
  1726.         brelse(buf);
  1727.     }
  1728.  
  1729. done:
  1730.     ifnot (k)
  1731.     {
  1732.     if (dev->s_tinode)
  1733.         goto corrupt;
  1734.     udata.u_error = ENOSPC;
  1735.     return(0);
  1736.     }
  1737.  
  1738.     dev->s_ninode = k;
  1739.     goto tryagain;
  1740.  
  1741. corrupt:
  1742.     warning("i_alloc: corrupt superblock");
  1743.     dev->s_mounted = 1;
  1744.     udata.u_error = ENOSPC;
  1745.     return(0);
  1746. }
  1747.  
  1748.  
  1749. /* I_free is given a device and inode number,
  1750. and frees the inode.  It is assumed that there
  1751. are no references to the inode in the inode table or
  1752. in the filesystem. */
  1753.  
  1754. i_free(devno, ino)
  1755. register int devno;
  1756. register unsigned ino;
  1757. {
  1758.     register fsptr dev;
  1759.  
  1760.     if (baddev(dev = getdev(devno)))
  1761.     return;
  1762.  
  1763.     if (ino < 2 || ino >= (dev->s_isize-2)*8)
  1764.     panic("i_free: bad ino");
  1765.  
  1766.     ++dev->s_tinode;
  1767.     if (dev->s_ninode < 50)
  1768.     dev->s_inode[dev->s_ninode++] = ino;
  1769. }
  1770.  
  1771.  
  1772. /* Blk_alloc is given a device number, and allocates an unused block
  1773. from it. A returned block number of zero means no more blocks. */
  1774.  
  1775. blkno_t
  1776. blk_alloc(devno)
  1777. register int devno;
  1778. {
  1779.  
  1780.     register fsptr dev;
  1781.     register blkno_t newno;
  1782.     blkno_t *buf;
  1783.     register int j;
  1784.  
  1785.     if (baddev(dev = getdev(devno)))
  1786.     goto corrupt2;
  1787.  
  1788.     if (dev->s_nfree <= 0 || dev->s_nfree > 50)
  1789.     goto corrupt;
  1790.  
  1791.     newno = dev->s_free[--dev->s_nfree];
  1792.     ifnot (newno)
  1793.     {
  1794.     if (dev->s_tfree != 0)
  1795.         goto corrupt;
  1796.     udata.u_error = ENOSPC;
  1797.     ++dev->s_nfree;
  1798.     return(0);
  1799.     }
  1800.  
  1801.     /* See if we must refill the s_free array */
  1802.  
  1803.     ifnot (dev->s_nfree)
  1804.     {
  1805.     buf = (blkno_t *)bread(devno,newno, 0);
  1806.     dev->s_nfree = buf[0];
  1807.     for (j=0; j < 50; j++)
  1808.     {
  1809.         dev->s_free[j] = buf[j+1];
  1810.     }
  1811.     brelse((char *)buf);
  1812.     }
  1813.  
  1814.     validblk(devno, newno);
  1815.  
  1816.     ifnot (dev->s_tfree)
  1817.     goto corrupt;
  1818.     --dev->s_tfree;
  1819.  
  1820.     /* Zero out the new block */
  1821.     buf = bread(devno, newno, 2);
  1822.     bzero(buf, 512);
  1823.     bawrite(buf);
  1824.     return(newno);
  1825.  
  1826. corrupt:
  1827.     warning("blk_alloc: corrupt");
  1828.     dev->s_mounted = 1;
  1829. corrupt2:
  1830.     udata.u_error = ENOSPC;
  1831.     return(0);
  1832. }
  1833.  
  1834.  
  1835. /* Blk_free is given a device number and a block number,
  1836. and frees the block. */
  1837.  
  1838. blk_free(devno,blk)
  1839. register int devno;
  1840. register blkno_t blk;
  1841. {
  1842.     register fsptr dev;
  1843.     register char *buf;
  1844.  
  1845.     ifnot (blk)
  1846.     return;
  1847.  
  1848.     if (baddev(dev = getdev(devno)))
  1849.         return;
  1850.  
  1851.     validblk(devno, blk);
  1852.  
  1853.     if (dev->s_nfree == 50)
  1854.     {
  1855.     buf = bread(devno, blk, 1);
  1856.     bcopy((char *)&(dev->s_nfree), buf, 512);
  1857.     bawrite(buf);
  1858.     dev->s_nfree = 0;
  1859.     }
  1860.  
  1861.     ++dev->s_tfree;
  1862.     dev->s_free[(dev->s_nfree)++] = blk;
  1863.  
  1864. }
  1865.  
  1866.  
  1867.  
  1868.  
  1869. /* Oft_alloc and oft_deref allocate and dereference (and possibly free)
  1870. entries in the open file table. */
  1871.  
  1872. oft_alloc()
  1873. {
  1874.     register int j;
  1875.  
  1876.     for (j=0; j < OFTSIZE ; ++j)
  1877.     {
  1878.     ifnot (of_tab[j].o_refs)
  1879.     {
  1880.         of_tab[j].o_refs = 1;
  1881.         of_tab[j].o_inode = NULLINODE;
  1882.         return (j);
  1883.     }
  1884.     }
  1885.     udata.u_error = ENFILE;
  1886.     return(-1);
  1887. }
  1888.  
  1889. oft_deref(of)
  1890. register int of;
  1891. {
  1892.     register struct oft *ofptr;
  1893.  
  1894.     ofptr = of_tab + of;
  1895.  
  1896.     if (!(--ofptr->o_refs) && ofptr->o_inode)
  1897.     {
  1898.         i_deref(ofptr->o_inode);
  1899.     ofptr->o_inode = NULLINODE;
  1900.     }
  1901. }
  1902.  
  1903.  
  1904.  
  1905. /* Uf_alloc finds an unused slot in the user file table. */
  1906.  
  1907. uf_alloc()
  1908. {
  1909.     register int j;
  1910.  
  1911.     for (j=0; j < UFTSIZE ; ++j)
  1912.     {
  1913.     if (udata.u_files[j] & 0x80)  /* Portable, unlike  == -1 */
  1914.     {
  1915.         return (j);
  1916.     }
  1917.     }
  1918.     udata.u_error = ENFILE;
  1919.     return(-1);
  1920. }
  1921.  
  1922.  
  1923.  
  1924. /* I_ref increases the reference count of the given inode table entry. */
  1925.  
  1926. i_ref(ino)
  1927. inoptr ino;
  1928. {
  1929.     if (++(ino->c_refs) == 2*ITABSIZE)  /* Arbitrary limit. */
  1930.     panic("too many i-refs");
  1931. }
  1932.  
  1933.  
  1934. /* I_deref decreases the reference count of an inode, and frees it
  1935. from the table if there are no more references to it.  If it also
  1936. has no links, the inode itself and its blocks (if not a device) is freed. */
  1937.  
  1938. i_deref(ino)
  1939. register inoptr ino;
  1940. {
  1941.     magic(ino);
  1942.  
  1943.     ifnot (ino->c_refs)
  1944.     panic("inode freed.");
  1945.  
  1946.     /* If the inode has no links and no refs, it must have
  1947.     its blocks freed. */
  1948.  
  1949.     ifnot (--ino->c_refs || ino->c_node.i_nlink)
  1950.         f_trunc(ino);
  1951.  
  1952.     /* If the inode was modified, we must write it to disk. */
  1953.     if (!(ino->c_refs) && ino->c_dirty)
  1954.     {
  1955.     ifnot (ino->c_node.i_nlink)
  1956.     {
  1957.         ino->c_node.i_mode = 0;
  1958.         i_free(ino->c_dev, ino->c_num);
  1959.     }
  1960.     wr_inode(ino);
  1961.     }
  1962. }
  1963.  
  1964.  
  1965. /* Wr_inode writes out the given inode in the inode table out to disk,
  1966. and resets its dirty bit. */
  1967.  
  1968. wr_inode(ino)
  1969. register inoptr ino;
  1970. {
  1971.     struct dinode *buf;
  1972.     register blkno_t blkno;
  1973.  
  1974.     magic(ino);
  1975.  
  1976.     blkno = (ino->c_num >> 3) + 2;
  1977.     buf = (struct dinode *)bread(ino->c_dev, blkno,0);
  1978.     bcopy((char *)(&ino->c_node),
  1979.     (char *)((char **)&buf[ino->c_num & 0x07]), 64);
  1980.     bfree(buf, 2);
  1981.     ino->c_dirty = 0;
  1982. }
  1983.  
  1984.  
  1985. /* isdevice(ino) returns true if ino points to a device */
  1986. isdevice(ino)
  1987. inoptr ino;
  1988. {
  1989.     return (ino->c_node.i_mode & 020000);
  1990. }
  1991.  
  1992.  
  1993. /* This returns the device number of an inode representing a device */
  1994. devnum(ino)
  1995. inoptr ino;
  1996. {
  1997.     return (*(ino->c_node.i_addr));
  1998. }
  1999.  
  2000.  
  2001. /* F_trunc frees all the blocks associated with the file,
  2002. if it is a disk file. */
  2003.  
  2004. f_trunc(ino)
  2005. register inoptr ino;
  2006. {
  2007.     int dev;
  2008.     int j;
  2009.  
  2010.     dev = ino->c_dev;
  2011.  
  2012.     /* First deallocate the double indirect blocks */
  2013.     freeblk(dev, ino->c_node.i_addr[19], 2);
  2014.  
  2015.     /* Also deallocate the indirect blocks */
  2016.     freeblk(dev, ino->c_node.i_addr[18], 1);
  2017.  
  2018.     /* Finally, free the direct blocks */
  2019.     for (j=17; j >= 0; --j)
  2020.     freeblk(dev, ino->c_node.i_addr[j], 0);
  2021.  
  2022.     bzero((char *)ino->c_node.i_addr, sizeof(ino->c_node.i_addr));
  2023.  
  2024.     ino->c_dirty = 1;
  2025.     ino->c_node.i_size.o_blkno = 0;
  2026.     ino->c_node.i_size.o_offset = 0;
  2027. }
  2028.  
  2029.  
  2030. /* Companion function to f_trunc(). */
  2031. freeblk(dev, blk, level)
  2032. int dev;
  2033. blkno_t blk;
  2034. int level;
  2035. {
  2036.     blkno_t *buf;
  2037.     int j;
  2038.  
  2039.     ifnot (blk)
  2040.     return;
  2041.  
  2042.     if (level)
  2043.     {
  2044.     buf = (blkno_t *)bread(dev, blk, 0);
  2045.     for (j=255; j >= 0; --j)
  2046.         freeblk(dev, buf[j], level-1);
  2047.     brelse((char *)buf);
  2048.     }
  2049.  
  2050.     blk_free(dev,blk);
  2051. }
  2052.  
  2053.  
  2054.  
  2055. /* Changes: blk_alloc zeroes block it allocates */
  2056.  
  2057. /*
  2058.  * Bmap defines the structure of file system storage
  2059.  * by returning the physical block number on a device given the
  2060.  * inode and the logical block number in a file.
  2061.  * The block is zeroed if created.
  2062.  */
  2063. blkno_t
  2064. bmap(ip, bn, rwflg)
  2065. inoptr ip;
  2066. register blkno_t bn;
  2067. int rwflg;
  2068. {
  2069.     register int i;
  2070.     register bufptr bp;
  2071.     register int j;
  2072.     register blkno_t nb;
  2073.     int sh;
  2074.     int dev;
  2075.  
  2076.     blkno_t blk_alloc();
  2077.  
  2078.     if (getmode(ip) == F_BDEV)
  2079.         return (bn);
  2080.  
  2081.     dev = ip->c_dev;
  2082.  
  2083.     /*
  2084.      * blocks 0..17 are direct blocks
  2085.      */
  2086.     if(bn < 18) {
  2087.         nb = ip->c_node.i_addr[bn];
  2088.         if(nb == 0) {
  2089.             if(rwflg || (nb = blk_alloc(dev))==0)
  2090.                 return(NULLBLK);
  2091.             ip->c_node.i_addr[bn] = nb;
  2092.             ip->c_dirty = 1;
  2093.         }
  2094.         return(nb);
  2095.     }
  2096.  
  2097.     /*
  2098.      * addresses 18 and 19
  2099.      * have single and double indirect blocks.
  2100.      * the first step is to determine
  2101.      * how many levels of indirection.
  2102.      */
  2103.     bn -= 18;
  2104.     sh = 0;
  2105.     j = 2;
  2106.     if (bn & 0xff00)   /* bn > 255  so double indirect */
  2107.     {
  2108.         sh = 8;
  2109.         bn -= 256;
  2110.         j = 1;
  2111.     }
  2112.  
  2113.     /*
  2114.      * fetch the address from the inode
  2115.      * Create the first indirect block if needed.
  2116.      */
  2117.     ifnot (nb = ip->c_node.i_addr[20-j])
  2118.     {
  2119.         if(rwflg || !(nb = blk_alloc(dev)))
  2120.             return(NULLBLK);
  2121.         ip->c_node.i_addr[20-j] = nb;
  2122.         ip->c_dirty = 1;
  2123.     }
  2124.  
  2125.     /*
  2126.      * fetch through the indirect blocks
  2127.      */
  2128.     for(; j<=2; j++) {
  2129.         bp = (bufptr)bread(dev, nb, 0);
  2130.         /******
  2131.         if(bp->bf_error) {
  2132.             brelse(bp);
  2133.             return((blkno_t)0);
  2134.         }
  2135.         ******/
  2136.         i = (bn>>sh) & 0xff;
  2137.         if (nb = ((blkno_t *)bp)[i])
  2138.             brelse(bp);
  2139.         else
  2140.         {
  2141.             if(rwflg || !(nb = blk_alloc(dev))) {
  2142.                 brelse(bp);
  2143.                 return(NULLBLK);
  2144.             }
  2145.             ((blkno_t *)bp)[i] = nb;
  2146.             bawrite(bp);
  2147.         }
  2148.         sh -= 8;
  2149.     }
  2150.  
  2151.     return(nb);
  2152. }
  2153.  
  2154.  
  2155.  
  2156. /* Validblk panics if the given block number is not a valid data block
  2157. for the given device. */
  2158.  
  2159. validblk(dev, num)
  2160. int dev;
  2161. blkno_t num;
  2162. {
  2163.     register fsptr devptr;
  2164.  
  2165.     devptr = fs_tab + dev;
  2166.  
  2167.     if (devptr->s_mounted == 0)
  2168.     panic("validblk: not mounted");
  2169.     
  2170.     if (num < devptr->s_isize || num >= devptr->s_fsize)
  2171.     panic("validblk: invalid blk");
  2172. }
  2173.  
  2174.  
  2175.  
  2176. /* This returns the inode pointer associated with a user's
  2177. file descriptor, checking for valid data structures */
  2178.  
  2179. inoptr
  2180. getinode(uindex)
  2181. register int uindex;
  2182. {
  2183.     register int oftindex;
  2184.     register inoptr inoindex;
  2185.  
  2186.     if (uindex < 0 || uindex >= UFTSIZE || udata.u_files[uindex] & 0x80 )
  2187.     {
  2188.     udata.u_error = EBADF;
  2189.     return (NULLINODE);
  2190.     }
  2191.  
  2192.     if ((oftindex = udata.u_files[uindex]) < 0 || oftindex >= OFTSIZE)
  2193.     panic("Getinode: bad desc table");
  2194.  
  2195.     if ((inoindex = of_tab[oftindex].o_inode) < i_tab ||
  2196.             inoindex >= i_tab+ITABSIZE)
  2197.     panic("Getinode: bad OFT");
  2198.  
  2199.     magic(inoindex);
  2200.  
  2201.     return(inoindex);
  2202. }
  2203.  
  2204. /* Super returns true if we are the superuser */
  2205. super()
  2206. {
  2207.     return(udata.u_euid == 0);
  2208. }
  2209.  
  2210. /* Getperm looks at the given inode and the effective user/group ids, and
  2211. returns the effective permissions in the low-order 3 bits. */
  2212.  
  2213. getperm(ino)
  2214. inoptr ino;
  2215. {
  2216.     int mode;
  2217.  
  2218.     if (super())
  2219.     return(07);
  2220.  
  2221.     mode = ino->c_node.i_mode;
  2222.     if (ino->c_node.i_uid == udata.u_euid)
  2223.     mode >>= 6;
  2224.     else if (ino->c_node.i_gid == udata.u_egid)
  2225.     mode >>= 3;
  2226.  
  2227.     return(mode & 07);
  2228. }
  2229.  
  2230.  
  2231. /* This sets the times of the given inode, according to the flags */
  2232.  
  2233. setftime(ino, flag)
  2234. register inoptr ino;
  2235. register int flag;
  2236. {
  2237.     ino->c_dirty = 1;
  2238.  
  2239.     if (flag & A_TIME)
  2240.     rdtime(&(ino->c_node.i_atime));
  2241.     if (flag & M_TIME)
  2242.     rdtime(&(ino->c_node.i_mtime));
  2243.     if (flag & C_TIME)
  2244.     rdtime(&(ino->c_node.i_ctime));
  2245. }
  2246.  
  2247.  
  2248. getmode(ino)
  2249. inoptr ino;
  2250. {
  2251.     return( ino->c_node.i_mode & F_MASK);
  2252. }
  2253.  
  2254.  
  2255. /* Fmount places the given device in the mount table with
  2256. mount point ino */
  2257.  
  2258. fmount(dev,ino)
  2259. register int dev;
  2260. register inoptr ino;
  2261. {
  2262.     char *buf;
  2263.     register struct filesys *fp;
  2264.  
  2265.     if (d_open(dev) != 0)
  2266.     panic("fmount: Cant open filesystem");
  2267.     /* Dev 0 blk 1 */
  2268.     fp = fs_tab + dev;
  2269.     buf = bread(dev, 1, 0);
  2270.     bcopy(buf, (char *)fp, sizeof(struct filesys));
  2271.     brelse(buf);
  2272.  
  2273.     /* See if there really is a filesystem on the device */
  2274.     if (fp->s_mounted != SMOUNTED ||
  2275.          fp->s_isize >= fp->s_fsize)
  2276.     return (-1);
  2277.  
  2278.     fp->s_mntpt = ino;
  2279.     if (ino)
  2280.     ++ino->c_refs;
  2281.  
  2282.     return (0);
  2283. }
  2284.  
  2285.  
  2286. magic(ino)
  2287. inoptr ino;
  2288. {
  2289.     if (ino->c_magic != CMAGIC)
  2290.     panic("Corrupt inode");
  2291. }
  2292.