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