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 / minix / namei.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-23  |  18.8 KB  |  836 lines

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