home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / fs / sysv / namei.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-29  |  19.2 KB  |  837 lines

  1. /*
  2.  *  linux/fs/sysv/namei.c
  3.  *
  4.  *  minix/namei.c
  5.  *  Copyright (C) 1991, 1992  Linus Torvalds
  6.  *
  7.  *  coh/namei.c
  8.  *  Copyright (C) 1993  Pascal Haible, Bruno Haible
  9.  *
  10.  *  sysv/namei.c
  11.  *  Copyright (C) 1993  Bruno Haible
  12.  */
  13.  
  14. #include <linux/sched.h>
  15. #include <linux/kernel.h>
  16. #include <linux/fs.h>
  17. #include <linux/sysv_fs.h>
  18. #include <linux/string.h>
  19. #include <linux/stat.h>
  20. #include <linux/errno.h>
  21.  
  22. /* compare strings: name[0..len-1] (not zero-terminated) and
  23.  * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1])
  24.  */
  25. static inline int namecompare(int len, int maxlen,
  26.     const char * name, const char * buffer)
  27. {
  28.     if (len >= maxlen || !buffer[len]) {
  29.         unsigned char same;
  30.         __asm__("repe ; cmpsb ; setz %0"
  31.             :"=q" (same)
  32.             :"S" ((long) name),"D" ((long) buffer),"c" (len)
  33.             :"cx","di","si");
  34.         return same;
  35.     }
  36.     /* if (len<maxlen && buffer[len]) then buffer is longer than name */
  37.     return 0;
  38. }
  39.  
  40. /*
  41.  * ok, we cannot use strncmp, as the name is not in our data space. [Now it is!]
  42.  * Thus we'll have to use sysv_match. No big problem. Match also makes
  43.  * some sanity tests.
  44.  *
  45.  * NOTE! unlike strncmp, sysv_match returns 1 for success, 0 for failure.
  46.  */
  47. static int sysv_match(int len, const char * name, struct sysv_dir_entry * de)
  48. {
  49.     if (!de->inode || len > SYSV_NAMELEN)
  50.         return 0;
  51.     /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
  52.     if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
  53.         return 1;
  54.     return namecompare(len,SYSV_NAMELEN,name,de->name);
  55. }
  56.  
  57. /*
  58.  *    sysv_find_entry()
  59.  *
  60.  * finds an entry in the specified directory with the wanted name. It
  61.  * returns the cache buffer in which the entry was found, and the entry
  62.  * itself (as a parameter - res_dir). It does NOT read the inode of the
  63.  * entry - you'll have to do that yourself if you want to.
  64.  */
  65. static struct buffer_head * sysv_find_entry(struct inode * dir,
  66.     const char * name, int namelen, struct sysv_dir_entry ** res_dir)
  67. {
  68.     struct super_block * sb;
  69.     unsigned long pos, block, offset; /* pos = block * block_size + offset */
  70.     struct buffer_head * bh;
  71.     char * bh_data;
  72.  
  73.     *res_dir = NULL;
  74.     if (!dir)
  75.         return NULL;
  76.     sb = dir->i_sb;
  77.     if (namelen > SYSV_NAMELEN)
  78.         if (sb->sv_truncate)
  79.             namelen = SYSV_NAMELEN;
  80.         else
  81.             return NULL;
  82.     bh = NULL;
  83.     pos = block = offset = 0;
  84.     while (pos < dir->i_size) {
  85.         if (!bh) {
  86.             bh = sysv_file_bread(dir,block,0,&bh_data);
  87.             if (!bh) {
  88.                 /* offset = 0; */ block++;
  89.                 pos += sb->sv_block_size;
  90.                 continue;
  91.             }
  92.         }
  93.         if (sysv_match(namelen, name,
  94.                    *res_dir = (struct sysv_dir_entry *) (bh_data + offset) ))
  95.             return bh;
  96.         pos += SYSV_DIRSIZE;
  97.         offset += SYSV_DIRSIZE;
  98.         if (offset < sb->sv_block_size)
  99.             continue;
  100.         brelse(bh);
  101.         bh = NULL;
  102.         offset = 0; block++;
  103.     }
  104.     brelse(bh);
  105.     *res_dir = NULL;
  106.     return NULL;
  107. }
  108.  
  109. int sysv_lookup(struct inode * dir,const char * name, int len,
  110.     struct inode ** result)
  111. {
  112.     int ino;
  113.     struct sysv_dir_entry * de;
  114.     struct buffer_head * bh;
  115.  
  116.     *result = NULL;
  117.     if (!dir)
  118.         return -ENOENT;
  119.     if (!S_ISDIR(dir->i_mode)) {
  120.         iput(dir);
  121.         return -ENOENT;
  122.     }
  123.     if (!(bh = sysv_find_entry(dir,name,len,&de))) {
  124.         iput(dir);
  125.         return -ENOENT;
  126.     }
  127.     ino = de->inode;
  128.     brelse(bh);
  129.     if (!(*result = iget(dir->i_sb,ino))) {
  130.         iput(dir);
  131.         return -EACCES;
  132.     }
  133.     iput(dir);
  134.     return 0;
  135. }
  136.  
  137. /*
  138.  *    sysv_add_entry()
  139.  *
  140.  * adds a file entry to the specified directory, returning a possible
  141.  * error value if it fails.
  142.  *
  143.  * NOTE!! The inode part of 'de' is left at 0 - which means you
  144.  * may not sleep between calling this and putting something into
  145.  * the entry, as someone else might have used it while you slept.
  146.  */
  147. static int sysv_add_entry(struct inode * dir,
  148.     const char * name, int namelen,
  149.     struct buffer_head ** res_buf,
  150.     struct sysv_dir_entry ** res_dir)
  151. {
  152.     struct super_block * sb;
  153.     int i;
  154.     unsigned long pos, block, offset; /* pos = block * block_size + offset */
  155.     struct buffer_head * bh;
  156.     char * bh_data;
  157.     struct sysv_dir_entry * de;
  158.  
  159.     *res_buf = NULL;
  160.     *res_dir = NULL;
  161.     if (!dir)
  162.         return -ENOENT;
  163.     sb = dir->i_sb;
  164.     if (namelen > SYSV_NAMELEN)
  165.         if (sb->sv_truncate)
  166.             namelen = SYSV_NAMELEN;
  167.         else
  168.             return -ENAMETOOLONG;
  169.     if (!namelen)
  170.         return -ENOENT;
  171.     bh = NULL;
  172.     pos = block = offset = 0;
  173.     while (1) {
  174.         if (!bh) {
  175.             bh = sysv_file_bread(dir,block,1,&bh_data);
  176.             if (!bh)
  177.                 return -ENOSPC;
  178.         }
  179.         de = (struct sysv_dir_entry *) (bh_data + offset);
  180.         pos += SYSV_DIRSIZE;
  181.         offset += SYSV_DIRSIZE;
  182.         if (pos > dir->i_size) {
  183.             de->inode = 0;
  184.             dir->i_size = pos;
  185.             dir->i_dirt = 1;
  186.         }
  187.         if (de->inode) {
  188.             if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) {
  189.                 brelse(bh);
  190.                 return -EEXIST;
  191.             }
  192.         } else {
  193.             dir->i_mtime = dir->i_ctime = CURRENT_TIME;
  194.             for (i = 0; i < SYSV_NAMELEN ; i++)
  195.                 de->name[i] = (i < namelen) ? name[i] : 0;
  196.             bh->b_dirt = 1;
  197.             *res_dir = de;
  198.             break;
  199.         }
  200.         if (offset < sb->sv_block_size)
  201.             continue;
  202.         brelse(bh);
  203.         bh = NULL;
  204.         offset = 0; block++;
  205.     }
  206.     *res_buf = bh;
  207.     return 0;
  208. }
  209.  
  210. int sysv_create(struct inode * dir,const char * name, int len, int mode,
  211.     struct inode ** result)
  212. {
  213.     int error;
  214.     struct inode * inode;
  215.     struct buffer_head * bh;
  216.     struct sysv_dir_entry * de;
  217.  
  218.     *result = NULL;
  219.     if (!dir)
  220.         return -ENOENT;
  221.     inode = sysv_new_inode(dir);
  222.     if (!inode) {
  223.         iput(dir);
  224.         return -ENOSPC;
  225.     }
  226.     if (inode->i_sb->sv_block_size_ratio_bits == 0) /* block_size == BLOCK_SIZE ? */
  227.         inode->i_op = &sysv_file_inode_operations_with_bmap;
  228.     else
  229.         inode->i_op = &sysv_file_inode_operations;
  230.     inode->i_mode = mode;
  231.     inode->i_dirt = 1;
  232.     error = sysv_add_entry(dir,name,len, &bh ,&de);
  233.     if (error) {
  234.         inode->i_nlink--;
  235.         inode->i_dirt = 1;
  236.         iput(inode);
  237.         iput(dir);
  238.         return error;
  239.     }
  240.     de->inode = inode->i_ino;
  241.     bh->b_dirt = 1;
  242.     brelse(bh);
  243.     iput(dir);
  244.     *result = inode;
  245.     return 0;
  246. }
  247.  
  248. int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
  249. {
  250.     int error;
  251.     struct inode * inode;
  252.     struct buffer_head * bh;
  253.     struct sysv_dir_entry * de;
  254.  
  255.     if (!dir)
  256.         return -ENOENT;
  257.     bh = sysv_find_entry(dir,name,len,&de);
  258.     if (bh) {
  259.         brelse(bh);
  260.         iput(dir);
  261.         return -EEXIST;
  262.     }
  263.     inode = sysv_new_inode(dir);
  264.     if (!inode) {
  265.         iput(dir);
  266.         return -ENOSPC;
  267.     }
  268.     inode->i_uid = current->euid;
  269.     inode->i_mode = mode;
  270.     inode->i_op = NULL;
  271.     if (S_ISREG(inode->i_mode))
  272.         if (inode->i_sb->sv_block_size_ratio_bits == 0) /* block_size == BLOCK_SIZE ? */
  273.             inode->i_op = &sysv_file_inode_operations_with_bmap;
  274.         else
  275.             inode->i_op = &sysv_file_inode_operations;
  276.     else if (S_ISDIR(inode->i_mode)) {
  277.         inode->i_op = &sysv_dir_inode_operations;
  278.         if (dir->i_mode & S_ISGID)
  279.             inode->i_mode |= S_ISGID;
  280.     }
  281.     else if (S_ISLNK(inode->i_mode))
  282.         inode->i_op = &sysv_symlink_inode_operations;
  283.     else if (S_ISCHR(inode->i_mode))
  284.         inode->i_op = &chrdev_inode_operations;
  285.     else if (S_ISBLK(inode->i_mode))
  286.         inode->i_op = &blkdev_inode_operations;
  287.     else if (S_ISFIFO(inode->i_mode))
  288.         init_fifo(inode);
  289.     if (S_ISBLK(mode) || S_ISCHR(mode))
  290.         inode->i_rdev = rdev;
  291.     inode->i_dirt = 1;
  292.     error = sysv_add_entry(dir, name, len, &bh, &de);
  293.     if (error) {
  294.         inode->i_nlink--;
  295.         inode->i_dirt = 1;
  296.         iput(inode);
  297.         iput(dir);
  298.         return error;
  299.     }
  300.     de->inode = inode->i_ino;
  301.     bh->b_dirt = 1;
  302.     brelse(bh);
  303.     iput(dir);
  304.     iput(inode);
  305.     return 0;
  306. }
  307.  
  308. int sysv_mkdir(struct inode * dir, const char * name, int len, int mode)
  309. {
  310.     int error;
  311.     struct inode * inode;
  312.     struct buffer_head * bh, *dir_block;
  313.     char * bh_data;
  314.     struct sysv_dir_entry * de;
  315.  
  316.     if (!dir) {
  317.         iput(dir);
  318.         return -EINVAL;
  319.     }
  320.     bh = sysv_find_entry(dir,name,len,&de);
  321.     if (bh) {
  322.         brelse(bh);
  323.         iput(dir);
  324.         return -EEXIST;
  325.     }
  326.     if (dir->i_nlink >= dir->i_sb->sv_link_max) {
  327.         iput(dir);
  328.         return -EMLINK;
  329.     }
  330.     inode = sysv_new_inode(dir);
  331.     if (!inode) {
  332.         iput(dir);
  333.         return -ENOSPC;
  334.     }
  335.     inode->i_op = &sysv_dir_inode_operations;
  336.     inode->i_size = 2 * SYSV_DIRSIZE;
  337.     dir_block = sysv_file_bread(inode,0,1,&bh_data);
  338.     if (!dir_block) {
  339.         iput(dir);
  340.         inode->i_nlink--;
  341.         inode->i_dirt = 1;
  342.         iput(inode);
  343.         return -ENOSPC;
  344.     }
  345.     de = (struct sysv_dir_entry *) (bh_data + 0*SYSV_DIRSIZE);
  346.     de->inode = inode->i_ino;
  347.     strcpy(de->name,"."); /* rest of de->name is zero, see sysv_new_block */
  348.     de = (struct sysv_dir_entry *) (bh_data + 1*SYSV_DIRSIZE);
  349.     de->inode = dir->i_ino;
  350.     strcpy(de->name,".."); /* rest of de->name is zero, see sysv_new_block */
  351.     inode->i_nlink = 2;
  352.     dir_block->b_dirt = 1;
  353.     brelse(dir_block);
  354.     inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask);
  355.     if (dir->i_mode & S_ISGID)
  356.         inode->i_mode |= S_ISGID;
  357.     inode->i_dirt = 1;
  358.     error = sysv_add_entry(dir, name, len, &bh, &de);
  359.     if (error) {
  360.         iput(dir);
  361.         inode->i_nlink=0;
  362.         iput(inode);
  363.         return error;
  364.     }
  365.     de->inode = inode->i_ino;
  366.     bh->b_dirt = 1;
  367.     dir->i_nlink++;
  368.     dir->i_dirt = 1;
  369.     iput(dir);
  370.     iput(inode);
  371.     brelse(bh);
  372.     return 0;
  373. }
  374.  
  375. /*
  376.  * routine to check that the specified directory is empty (for rmdir)
  377.  */
  378. static int empty_dir(struct inode * inode)
  379. {
  380.     struct super_block * sb;
  381.     unsigned long pos, block, offset; /* pos = block * block_size + offset */
  382.     struct buffer_head * bh;
  383.     char * bh_data;
  384.     struct sysv_dir_entry * de;
  385.  
  386.     if (!inode)
  387.         return 1;
  388.     block = 0;
  389.     bh = NULL;
  390.     pos = offset = 2*SYSV_DIRSIZE;
  391.     if (inode->i_size % SYSV_DIRSIZE)
  392.         goto bad_dir;
  393.     if (inode->i_size < pos)
  394.         goto bad_dir;
  395.     bh = sysv_file_bread(inode,0,0,&bh_data);
  396.     if (!bh)
  397.         goto bad_dir;
  398.     de = (struct sysv_dir_entry *) (bh_data + 0*SYSV_DIRSIZE);
  399.     if (!de->inode || strcmp(de->name,"."))
  400.         goto bad_dir;
  401.     de = (struct sysv_dir_entry *) (bh_data + 1*SYSV_DIRSIZE);
  402.     if (!de->inode || strcmp(de->name,".."))
  403.         goto bad_dir;
  404.     sb = inode->i_sb;
  405.     while (pos < inode->i_size) {
  406.         if (!bh) {
  407.             bh = sysv_file_bread(inode,block,0,&bh_data);
  408.             if (!bh) {
  409.                 /* offset = 0; */ block++;
  410.                 pos += sb->sv_block_size;
  411.                 continue;
  412.             }
  413.         }
  414.         de = (struct sysv_dir_entry *) (bh_data + offset);
  415.         pos += SYSV_DIRSIZE;
  416.         offset += SYSV_DIRSIZE;
  417.         if (de->inode) {
  418.             brelse(bh);
  419.             return 0;
  420.         }
  421.         if (offset < sb->sv_block_size)
  422.             continue;
  423.         brelse(bh);
  424.         bh = NULL;
  425.         offset = 0; block++;
  426.     }
  427.     brelse(bh);
  428.     return 1;
  429. bad_dir:
  430.     brelse(bh);
  431.     printk("Bad directory on device %04x\n",inode->i_dev);
  432.     return 1;
  433. }
  434.  
  435. int sysv_rmdir(struct inode * dir, const char * name, int len)
  436. {
  437.     int retval;
  438.     struct inode * inode;
  439.     struct buffer_head * bh;
  440.     struct sysv_dir_entry * de;
  441.  
  442.     inode = NULL;
  443.     bh = sysv_find_entry(dir,name,len,&de);
  444.     retval = -ENOENT;
  445.     if (!bh)
  446.         goto end_rmdir;
  447.     retval = -EPERM;
  448.     if (!(inode = iget(dir->i_sb, de->inode)))
  449.         goto end_rmdir;
  450.     if ((dir->i_mode & S_ISVTX) && current->euid &&
  451.         inode->i_uid != current->euid)
  452.         goto end_rmdir;
  453.     if (inode->i_dev != dir->i_dev)
  454.         goto end_rmdir;
  455.     if (inode == dir)    /* we may not delete ".", but "../dir" is ok */
  456.         goto end_rmdir;
  457.     if (!S_ISDIR(inode->i_mode)) {
  458.         retval = -ENOTDIR;
  459.         goto end_rmdir;
  460.     }
  461.     if (!empty_dir(inode)) {
  462.         retval = -ENOTEMPTY;
  463.         goto end_rmdir;
  464.     }
  465.     if (de->inode != inode->i_ino) {
  466.         retval = -ENOENT;
  467.         goto end_rmdir;
  468.     }
  469.     if (inode->i_count > 1) {
  470.         retval = -EBUSY;
  471.         goto end_rmdir;
  472.     }
  473.     if (inode->i_nlink != 2)
  474.         printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
  475.     de->inode = 0;
  476.     bh->b_dirt = 1;
  477.     inode->i_nlink=0;
  478.     inode->i_dirt=1;
  479.     dir->i_nlink--;
  480.     inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  481.     dir->i_dirt=1;
  482.     retval = 0;
  483. end_rmdir:
  484.     iput(dir);
  485.     iput(inode);
  486.     brelse(bh);
  487.     return retval;
  488. }
  489.  
  490. int sysv_unlink(struct inode * dir, const char * name, int len)
  491. {
  492.     int retval;
  493.     struct inode * inode;
  494.     struct buffer_head * bh;
  495.     struct sysv_dir_entry * de;
  496.  
  497. repeat:
  498.     retval = -ENOENT;
  499.     inode = NULL;
  500.     bh = sysv_find_entry(dir,name,len,&de);
  501.     if (!bh)
  502.         goto end_unlink;
  503.     if (!(inode = iget(dir->i_sb, de->inode)))
  504.         goto end_unlink;
  505.     retval = -EPERM;
  506.     if (S_ISDIR(inode->i_mode))
  507.         goto end_unlink;
  508.     if (de->inode != inode->i_ino) {
  509.         iput(inode);
  510.         brelse(bh);
  511.         current->counter = 0;
  512.         schedule();
  513.         goto repeat;
  514.     }
  515.     if ((dir->i_mode & S_ISVTX) && !suser() &&
  516.         current->euid != inode->i_uid &&
  517.         current->euid != dir->i_uid)
  518.         goto end_unlink;
  519.     if (de->inode != inode->i_ino) {
  520.         retval = -ENOENT;
  521.         goto end_unlink;
  522.     }
  523.     if (!inode->i_nlink) {
  524.         printk("Deleting nonexistent file (%04x:%lu), %d\n",
  525.             inode->i_dev,inode->i_ino,inode->i_nlink);
  526.         inode->i_nlink=1;
  527.     }
  528.     de->inode = 0;
  529.     bh->b_dirt = 1;
  530.     dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  531.     dir->i_dirt = 1;
  532.     inode->i_nlink--;
  533.     inode->i_ctime = dir->i_ctime;
  534.     inode->i_dirt = 1;
  535.     retval = 0;
  536. end_unlink:
  537.     brelse(bh);
  538.     iput(inode);
  539.     iput(dir);
  540.     return retval;
  541. }
  542.  
  543. int sysv_symlink(struct inode * dir, const char * name, int len, const char * symname)
  544. {
  545.     struct sysv_dir_entry * de;
  546.     struct inode * inode;
  547.     struct buffer_head * name_block;
  548.     char * name_block_data;
  549.     struct super_block * sb;
  550.     int i;
  551.     char c;
  552.     struct buffer_head * bh;
  553.  
  554.     if (!(inode = sysv_new_inode(dir))) {
  555.         iput(dir);
  556.         return -ENOSPC;
  557.     }
  558.     inode->i_mode = S_IFLNK | 0777;
  559.     inode->i_op = &sysv_symlink_inode_operations;
  560.     name_block = sysv_file_bread(inode,0,1,&name_block_data);
  561.     if (!name_block) {
  562.         iput(dir);
  563.         inode->i_nlink--;
  564.         inode->i_dirt = 1;
  565.         iput(inode);
  566.         return -ENOSPC;
  567.     }
  568.     sb = inode->i_sb;
  569.     i = 0;
  570.     while (i < sb->sv_block_size_1 && (c = *(symname++)))
  571.         name_block_data[i++] = c;
  572.     name_block_data[i] = 0;
  573.     name_block->b_dirt = 1;
  574.     brelse(name_block);
  575.     inode->i_size = i;
  576.     inode->i_dirt = 1;
  577.     bh = sysv_find_entry(dir,name,len,&de);
  578.     if (bh) {
  579.         inode->i_nlink--;
  580.         inode->i_dirt = 1;
  581.         iput(inode);
  582.         brelse(bh);
  583.         iput(dir);
  584.         return -EEXIST;
  585.     }
  586.     i = sysv_add_entry(dir, name, len, &bh, &de);
  587.     if (i) {
  588.         inode->i_nlink--;
  589.         inode->i_dirt = 1;
  590.         iput(inode);
  591.         iput(dir);
  592.         return i;
  593.     }
  594.     de->inode = inode->i_ino;
  595.     bh->b_dirt = 1;
  596.     brelse(bh);
  597.     iput(dir);
  598.     iput(inode);
  599.     return 0;
  600. }
  601.  
  602. int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
  603. {
  604.     int error;
  605.     struct sysv_dir_entry * de;
  606.     struct buffer_head * bh;
  607.  
  608.     if (S_ISDIR(oldinode->i_mode)) {
  609.         iput(oldinode);
  610.         iput(dir);
  611.         return -EPERM;
  612.     }
  613.     if (oldinode->i_nlink >= oldinode->i_sb->sv_link_max) {
  614.         iput(oldinode);
  615.         iput(dir);
  616.         return -EMLINK;
  617.     }
  618.     bh = sysv_find_entry(dir,name,len,&de);
  619.     if (bh) {
  620.         brelse(bh);
  621.         iput(dir);
  622.         iput(oldinode);
  623.         return -EEXIST;
  624.     }
  625.     error = sysv_add_entry(dir, name, len, &bh, &de);
  626.     if (error) {
  627.         iput(dir);
  628.         iput(oldinode);
  629.         return error;
  630.     }
  631.     de->inode = oldinode->i_ino;
  632.     bh->b_dirt = 1;
  633.     brelse(bh);
  634.     iput(dir);
  635.     oldinode->i_nlink++;
  636.     oldinode->i_ctime = CURRENT_TIME;
  637.     oldinode->i_dirt = 1;
  638.     iput(oldinode);
  639.     return 0;
  640. }
  641.  
  642. /* return 1 if `new' is a subdir of `old' on the same device */
  643. static int subdir(struct inode * new_inode, struct inode * old_inode)
  644. {
  645.     int ino;
  646.     int result;
  647.  
  648.     new_inode->i_count++;
  649.     result = 0;
  650.     for (;;) {
  651.         if (new_inode == old_inode) {
  652.             result = 1;
  653.             break;
  654.         }
  655.         if (new_inode->i_dev != old_inode->i_dev)
  656.             break;
  657.         ino = new_inode->i_ino;
  658.         if (sysv_lookup(new_inode,"..",2,&new_inode))
  659.             break;
  660.         if (new_inode->i_ino == ino) /* root dir reached ? */
  661.             break;
  662.     }
  663.     iput(new_inode);
  664.     return result;
  665. }
  666.  
  667. #define PARENT_INO(buffer) \
  668. (((struct sysv_dir_entry *) ((buffer) + 1*SYSV_DIRSIZE))->inode)
  669.  
  670. /*
  671.  * rename uses retrying to avoid race-conditions: at least they should be minimal.
  672.  * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
  673.  * checks fail, it tries to restart itself again. Very practical - no changes
  674.  * are done until we know everything works ok.. and then all the changes can be
  675.  * done in one fell swoop when we have claimed all the buffers needed.
  676.  *
  677.  * Anybody can rename anything with this: the permission checks are left to the
  678.  * higher-level routines.
  679.  */
  680. static int do_sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
  681.     struct inode * new_dir, const char * new_name, int new_len)
  682. {
  683.     struct inode * old_inode, * new_inode;
  684.     struct buffer_head * old_bh, * new_bh, * dir_bh;
  685.     char * dir_bh_data;
  686.     struct sysv_dir_entry * old_de, * new_de;
  687.     int retval;
  688.  
  689.     goto start_up;
  690. try_again:
  691.     brelse(old_bh);
  692.     brelse(new_bh);
  693.     brelse(dir_bh);
  694.     iput(old_inode);
  695.     iput(new_inode);
  696.     current->counter = 0;
  697.     schedule();
  698. start_up:
  699.     old_inode = new_inode = NULL;
  700.     old_bh = new_bh = dir_bh = NULL;
  701.     old_bh = sysv_find_entry(old_dir,old_name,old_len,&old_de);
  702.     retval = -ENOENT;
  703.     if (!old_bh)
  704.         goto end_rename;
  705.     old_inode = __iget(old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */
  706.     if (!old_inode)
  707.         goto end_rename;
  708.     retval = -EPERM;
  709.     if ((old_dir->i_mode & S_ISVTX) && 
  710.         current->euid != old_inode->i_uid &&
  711.         current->euid != old_dir->i_uid && !suser())
  712.         goto end_rename;
  713.     new_bh = sysv_find_entry(new_dir,new_name,new_len,&new_de);
  714.     if (new_bh) {
  715.         new_inode = __iget(new_dir->i_sb, new_de->inode, 0);
  716.         if (!new_inode) {
  717.             brelse(new_bh);
  718.             new_bh = NULL;
  719.         }
  720.     }
  721.     if (new_inode == old_inode) {
  722.         retval = 0;
  723.         goto end_rename;
  724.     }
  725.     if (new_inode && S_ISDIR(new_inode->i_mode)) {
  726.         retval = -EISDIR;
  727.         if (!S_ISDIR(old_inode->i_mode))
  728.             goto end_rename;
  729.         retval = -EINVAL;
  730.         if (subdir(new_dir, old_inode))
  731.             goto end_rename;
  732.         retval = -ENOTEMPTY;
  733.         if (!empty_dir(new_inode))
  734.             goto end_rename;
  735.         retval = -EBUSY;
  736.         if (new_inode->i_count > 1)
  737.             goto end_rename;
  738.     }
  739.     retval = -EPERM;
  740.     if (new_inode && (new_dir->i_mode & S_ISVTX) && 
  741.         current->euid != new_inode->i_uid &&
  742.         current->euid != new_dir->i_uid && !suser())
  743.         goto end_rename;
  744.     if (S_ISDIR(old_inode->i_mode)) {
  745.         retval = -ENOTDIR;
  746.         if (new_inode && !S_ISDIR(new_inode->i_mode))
  747.             goto end_rename;
  748.         retval = -EINVAL;
  749.         if (subdir(new_dir, old_inode))
  750.             goto end_rename;
  751.         retval = -EIO;
  752.         dir_bh = sysv_file_bread(old_inode,0,0,&dir_bh_data);
  753.         if (!dir_bh)
  754.             goto end_rename;
  755.         if (PARENT_INO(dir_bh_data) != old_dir->i_ino)
  756.             goto end_rename;
  757.         retval = -EMLINK;
  758.         if (!new_inode && new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
  759.             goto end_rename;
  760.     }
  761.     if (!new_bh) {
  762.         retval = sysv_add_entry(new_dir,new_name,new_len,&new_bh,&new_de);
  763.         if (retval)
  764.             goto end_rename;
  765.     }
  766. /* sanity checking before doing the rename - avoid races */
  767.     if (new_inode && (new_de->inode != new_inode->i_ino))
  768.         goto try_again;
  769.     if (new_de->inode && !new_inode)
  770.         goto try_again;
  771.     if (old_de->inode != old_inode->i_ino)
  772.         goto try_again;
  773. /* ok, that's it */
  774.     old_de->inode = 0;
  775.     new_de->inode = old_inode->i_ino;
  776.     old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
  777.     old_dir->i_dirt = 1;
  778.     new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
  779.     new_dir->i_dirt = 1;
  780.     if (new_inode) {
  781.         new_inode->i_nlink--;
  782.         new_inode->i_ctime = CURRENT_TIME;
  783.         new_inode->i_dirt = 1;
  784.     }
  785.     old_bh->b_dirt = 1;
  786.     new_bh->b_dirt = 1;
  787.     if (dir_bh) {
  788.         PARENT_INO(dir_bh_data) = new_dir->i_ino;
  789.         dir_bh->b_dirt = 1;
  790.         old_dir->i_nlink--;
  791.         old_dir->i_dirt = 1;
  792.         if (new_inode) {
  793.             new_inode->i_nlink--;
  794.             new_inode->i_dirt = 1;
  795.         } else {
  796.             new_dir->i_nlink++;
  797.             new_dir->i_dirt = 1;
  798.         }
  799.     }
  800.     retval = 0;
  801. end_rename:
  802.     brelse(dir_bh);
  803.     brelse(old_bh);
  804.     brelse(new_bh);
  805.     iput(old_inode);
  806.     iput(new_inode);
  807.     iput(old_dir);
  808.     iput(new_dir);
  809.     return retval;
  810. }
  811.  
  812. /*
  813.  * Ok, rename also locks out other renames, as they can change the parent of
  814.  * a directory, and we don't want any races. Other races are checked for by
  815.  * "do_rename()", which restarts if there are inconsistencies.
  816.  *
  817.  * Note that there is no race between different filesystems: it's only within
  818.  * the same device that races occur: many renames can happen at once, as long
  819.  * as they are on different partitions.
  820.  */
  821. int sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
  822.     struct inode * new_dir, const char * new_name, int new_len)
  823. {
  824.     static struct wait_queue * wait = NULL;
  825.     static int lock = 0;
  826.     int result;
  827.  
  828.     while (lock)
  829.         sleep_on(&wait);
  830.     lock = 1;
  831.     result = do_sysv_rename(old_dir, old_name, old_len,
  832.         new_dir, new_name, new_len);
  833.     lock = 0;
  834.     wake_up(&wait);
  835.     return result;
  836. }
  837.