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 / msdos / namei.c < prev   
Encoding:
C/C++ Source or Header  |  1993-12-01  |  14.8 KB  |  593 lines

  1. /*
  2.  *  linux/fs/msdos/namei.c
  3.  *
  4.  *  Written 1992,1993 by Werner Almesberger
  5.  */
  6.  
  7. #include <asm/segment.h>
  8.  
  9. #include <linux/sched.h>
  10. #include <linux/msdos_fs.h>
  11. #include <linux/kernel.h>
  12. #include <linux/errno.h>
  13. #include <linux/string.h>
  14. #include <linux/stat.h>
  15.  
  16. /* MS-DOS "device special files" */
  17.  
  18. static char *reserved_names[] = {
  19.     "CON     ","PRN     ","NUL     ","AUX     ",
  20.     "LPT1    ","LPT2    ","LPT3    ","LPT4    ",
  21.     "COM1    ","COM2    ","COM3    ","COM4    ",
  22.     NULL };
  23.  
  24.  
  25. /* Characters that are undesirable in an MS-DOS file name */
  26.   
  27. static char bad_chars[] = "*?<>|\"";
  28. static char bad_if_strict[] = "+=,; ";
  29.  
  30.  
  31. /* Formats an MS-DOS file name. Rejects invalid names. */
  32.  
  33. static int msdos_format_name(char conv,const char *name,int len,char *res,
  34.   int dot_dirs)
  35. {
  36.     char *walk,**reserved;
  37.     unsigned char c;
  38.     int space;
  39.  
  40.     if (IS_FREE(name)) return -EINVAL;
  41.     if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
  42.         if (!dot_dirs) return -EEXIST;
  43.         memset(res+1,' ',10);
  44.         while (len--) *res++ = '.';
  45.         return 0;
  46.     }
  47.     space = 1; /* disallow names starting with a dot */
  48.     c = 0;
  49.     for (walk = res; len && walk-res < 8; walk++) {
  50.             c = *name++;
  51.         len--;
  52.         if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
  53.         if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
  54.           if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
  55.         if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
  56.         if (c == '.') break;
  57.         space = c == ' ';
  58.         *walk = c >= 'a' && c <= 'z' ? c-32 : c;
  59.     }
  60.     if (space) return -EINVAL;
  61.     if (conv == 's' && len && c != '.') {
  62.         c = *name++;
  63.         len--;
  64.         if (c != '.') return -EINVAL;
  65.     }
  66.     while (c != '.' && len--) c = *name++;
  67.     if (c == '.') {
  68.         while (walk-res < 8) *walk++ = ' ';
  69.         while (len > 0 && walk-res < MSDOS_NAME) {
  70.             c = *name++;
  71.             len--;
  72.             if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
  73.             if (conv == 's' && strchr(bad_if_strict,c))
  74.                 return -EINVAL;
  75.             if (c < ' ' || c == ':' || c == '\\' || c == '.')
  76.                 return -EINVAL;
  77.             if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
  78.             space = c == ' ';
  79.             *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
  80.         }
  81.         if (space) return -EINVAL;
  82.         if (conv == 's' && len) return -EINVAL;
  83.     }
  84.     while (walk-res < MSDOS_NAME) *walk++ = ' ';
  85.     for (reserved = reserved_names; *reserved; reserved++)
  86.         if (!strncmp(res,*reserved,8)) return -EINVAL;
  87.     return 0;
  88. }
  89.  
  90.  
  91. /* Locates a directory entry. */
  92.  
  93. static int msdos_find(struct inode *dir,const char *name,int len,
  94.     struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
  95. {
  96.     char msdos_name[MSDOS_NAME];
  97.     int res;
  98.  
  99.     if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
  100.         msdos_name,1)) < 0) return res;
  101.     return msdos_scan(dir,msdos_name,bh,de,ino);
  102. }
  103.  
  104.  
  105. int msdos_lookup(struct inode *dir,const char *name,int len,
  106.     struct inode **result)
  107. {
  108.     int ino,res;
  109.     struct msdos_dir_entry *de;
  110.     struct buffer_head *bh;
  111.     struct inode *next;
  112.  
  113.     *result = NULL;
  114.     if (!dir) return -ENOENT;
  115.     if (!S_ISDIR(dir->i_mode)) {
  116.         iput(dir);
  117.         return -ENOENT;
  118.     }
  119.     if (len == 1 && name[0] == '.') {
  120.         *result = dir;
  121.         return 0;
  122.     }
  123.     if (len == 2 && name[0] == '.' && name[1] == '.') {
  124.         ino = msdos_parent_ino(dir,0);
  125.         iput(dir);
  126.         if (ino < 0) return ino;
  127.         if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
  128.         return 0;
  129.     }
  130.     if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
  131.         iput(dir);
  132.         return res;
  133.     }
  134.     if (bh) brelse(bh);
  135. /* printk("lookup: ino=%d\n",ino); */
  136.     if (!(*result = iget(dir->i_sb,ino))) {
  137.         iput(dir);
  138.         return -EACCES;
  139.     }
  140.     if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */
  141.         iput(*result);
  142.         iput(dir);
  143.         return -ENOENT;
  144.     }
  145.     while (MSDOS_I(*result)->i_old) {
  146.         next = MSDOS_I(*result)->i_old;
  147.         iput(*result);
  148.         if (!(*result = iget(next->i_sb,next->i_ino))) {
  149.             fs_panic(dir->i_sb,"msdos_lookup: Can't happen");
  150.             iput(dir);
  151.             return -ENOENT;
  152.         }
  153.     }
  154.     iput(dir);
  155.     return 0;
  156. }
  157.  
  158.  
  159. /* Creates a directory entry (name is already formatted). */
  160.  
  161. static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
  162.     struct inode **result)
  163. {
  164.     struct buffer_head *bh;
  165.     struct msdos_dir_entry *de;
  166.     int res,ino;
  167.  
  168.     if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) {
  169.         if (res != -ENOENT) return res;
  170.         if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
  171.         if ((res = msdos_add_cluster(dir)) < 0) return res;
  172.         if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res;
  173.     }
  174.     /*
  175.      * XXX all times should be set by caller upon successful completion.
  176.      */
  177.     dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  178.     dir->i_dirt = 1;
  179.     memcpy(de->name,name,MSDOS_NAME);
  180.     de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
  181.     de->start = 0;
  182.     date_unix2dos(dir->i_mtime,&de->time,&de->date);
  183.     de->size = 0;
  184.     bh->b_dirt = 1;
  185.     if ((*result = iget(dir->i_sb,ino)) != NULL)
  186.         msdos_read_inode(*result);
  187.     brelse(bh);
  188.     if (!*result) return -EIO;
  189.     (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
  190.         CURRENT_TIME;
  191.     (*result)->i_dirt = 1;
  192.     return 0;
  193. }
  194.  
  195.  
  196. int msdos_create(struct inode *dir,const char *name,int len,int mode,
  197.     struct inode **result)
  198. {
  199.     struct buffer_head *bh;
  200.     struct msdos_dir_entry *de;
  201.     char msdos_name[MSDOS_NAME];
  202.     int ino,res;
  203.  
  204.     if (!dir) return -ENOENT;
  205.     if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
  206.         msdos_name,0)) < 0) {
  207.         iput(dir);
  208.         return res;
  209.     }
  210.     lock_creation();
  211.     if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
  212.         unlock_creation();
  213.         brelse(bh);
  214.         iput(dir);
  215.         return -EEXIST;
  216.      }
  217.     res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),result);
  218.     unlock_creation();
  219.     iput(dir);
  220.     return res;
  221. }
  222.  
  223.  
  224. #ifdef DEBUG
  225.  
  226. static void dump_fat(struct super_block *sb,int start)
  227. {
  228.     printk("[");
  229.     while (start) {
  230.         printk("%d ",start);
  231.             start = fat_access(sb,start,-1);
  232.         if (!start) {
  233.             printk("ERROR");
  234.             break;
  235.         }
  236.         if (start == -1) break;
  237.     }
  238.     printk("]\n");
  239. }
  240.  
  241. #endif
  242.  
  243.  
  244. int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
  245. {
  246.     struct buffer_head *bh;
  247.     struct msdos_dir_entry *de;
  248.     struct inode *inode,*dot;
  249.     char msdos_name[MSDOS_NAME];
  250.     int ino,res;
  251.  
  252.     if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
  253.         msdos_name,0)) < 0) {
  254.         iput(dir);
  255.         return res;
  256.     }
  257.     lock_creation();
  258.     if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
  259.         unlock_creation();
  260.         brelse(bh);
  261.         iput(dir);
  262.         return -EEXIST;
  263.      }
  264.     if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) {
  265.         unlock_creation();
  266.         iput(dir);
  267.         return res;
  268.     }
  269.     dir->i_nlink++;
  270.     inode->i_nlink = 2; /* no need to mark them dirty */
  271.     MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
  272.     if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
  273.     if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
  274.         goto mkdir_error;
  275.     dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
  276.     MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
  277.     dot->i_nlink = inode->i_nlink;
  278.     dot->i_dirt = 1;
  279.     iput(dot);
  280.     if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
  281.         goto mkdir_error;
  282.     unlock_creation();
  283.     dot->i_size = dir->i_size;
  284.     MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
  285.     dot->i_nlink = dir->i_nlink;
  286.     dot->i_dirt = 1;
  287.     MSDOS_I(inode)->i_busy = 0;
  288.     iput(dot);
  289.     iput(inode);
  290.     iput(dir);
  291.     return 0;
  292. mkdir_error:
  293.     iput(inode);
  294.     if (msdos_rmdir(dir,name,len) < 0)
  295.         fs_panic(dir->i_sb,"rmdir in mkdir failed");
  296.     unlock_creation();
  297.     return res;
  298. }
  299.  
  300.  
  301. static int msdos_empty(struct inode *dir)
  302. {
  303.     off_t pos;
  304.     struct buffer_head *bh;
  305.     struct msdos_dir_entry *de;
  306.  
  307.     if (dir->i_count > 1)
  308.         return -EBUSY;
  309.     if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
  310.         pos = 0;
  311.         bh = NULL;
  312.         while (msdos_get_entry(dir,&pos,&bh,&de) > -1)
  313.             if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
  314.                 MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
  315.                 MSDOS_NAME)) {
  316.                 brelse(bh);
  317.                 return -ENOTEMPTY;
  318.             }
  319.         if (bh)
  320.             brelse(bh);
  321.     }
  322.     return 0;
  323. }
  324.  
  325.  
  326. int msdos_rmdir(struct inode *dir,const char *name,int len)
  327. {
  328.     int res,ino;
  329.     struct buffer_head *bh;
  330.     struct msdos_dir_entry *de;
  331.     struct inode *inode;
  332.  
  333.     bh = NULL;
  334.     inode = NULL;
  335.     res = -EPERM;
  336.     if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
  337.         goto rmdir_done;
  338.     if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
  339.     res = -ENOENT;
  340.     if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
  341.     res = -ENOTDIR;
  342.     if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
  343.     res = -EBUSY;
  344.     if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
  345.     res = msdos_empty(inode);
  346.     if (res)
  347.         goto rmdir_done;
  348.     inode->i_nlink = 0;
  349.     inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  350.     dir->i_nlink--;
  351.     inode->i_dirt = dir->i_dirt = 1;
  352.     de->name[0] = DELETED_FLAG;
  353.     bh->b_dirt = 1;
  354.     res = 0;
  355. rmdir_done:
  356.     brelse(bh);
  357.     iput(dir);
  358.     iput(inode);
  359.     return res;
  360. }
  361.  
  362.  
  363. int msdos_unlink(struct inode *dir,const char *name,int len)
  364. {
  365.     int res,ino;
  366.     struct buffer_head *bh;
  367.     struct msdos_dir_entry *de;
  368.     struct inode *inode;
  369.  
  370.     bh = NULL;
  371.     inode = NULL;
  372.     if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
  373.         goto unlink_done;
  374.     if (!(inode = iget(dir->i_sb,ino))) {
  375.         res = -ENOENT;
  376.         goto unlink_done;
  377.     }
  378.     if (!S_ISREG(inode->i_mode)) {
  379.         res = -EPERM;
  380.         goto unlink_done;
  381.     }
  382.     inode->i_nlink = 0;
  383.     inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  384.     MSDOS_I(inode)->i_busy = 1;
  385.     inode->i_dirt = dir->i_dirt = 1;
  386.     de->name[0] = DELETED_FLAG;
  387.     bh->b_dirt = 1;
  388. unlink_done:
  389.     brelse(bh);
  390.     iput(inode);
  391.     iput(dir);
  392.     return res;
  393. }
  394.  
  395.  
  396. static int rename_same_dir(struct inode *old_dir,char *old_name,
  397.     struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
  398.     struct msdos_dir_entry *old_de,int old_ino)
  399. {
  400.     struct buffer_head *new_bh;
  401.     struct msdos_dir_entry *new_de;
  402.     struct inode *new_inode,*old_inode;
  403.     int new_ino,exists,error;
  404.  
  405.     if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
  406.     exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
  407.     if (*(unsigned char *) old_de->name == DELETED_FLAG) {
  408.         if (exists) brelse(new_bh);
  409.         return -ENOENT;
  410.     }
  411.     if (exists) {
  412.         if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
  413.             brelse(new_bh);
  414.             return -EIO;
  415.         }
  416.         error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ?
  417.             msdos_empty(new_inode) : -EPERM : (old_de->attr & ATTR_DIR)
  418.             ? -EPERM : 0;
  419.         if (error) {
  420.             iput(new_inode);
  421.             brelse(new_bh);
  422.             return error;
  423.         }
  424.         if (S_ISDIR(new_inode->i_mode)) {
  425.             new_dir->i_nlink--;
  426.             new_dir->i_dirt = 1;
  427.         }
  428.         new_inode->i_nlink = 0;
  429.         MSDOS_I(new_inode)->i_busy = 1;
  430.         new_inode->i_dirt = 1;
  431.         new_de->name[0] = DELETED_FLAG;
  432.         new_bh->b_dirt = 1;
  433.         iput(new_inode);
  434.         brelse(new_bh);
  435.     }
  436.     memcpy(old_de->name,new_name,MSDOS_NAME);
  437.     old_bh->b_dirt = 1;
  438.     if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */
  439.         if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) {
  440.             msdos_read_inode(old_inode);
  441.             iput(old_inode);
  442.         }
  443.     return 0;
  444. }
  445.  
  446.  
  447. static int rename_diff_dir(struct inode *old_dir,char *old_name,
  448.     struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
  449.     struct msdos_dir_entry *old_de,int old_ino)
  450. {
  451.     struct buffer_head *new_bh,*free_bh,*dotdot_bh;
  452.     struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
  453.     struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
  454.     int new_ino,free_ino,dotdot_ino;
  455.     int error,exists,ino;
  456.  
  457.     if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
  458.     if (old_ino == new_dir->i_ino) return -EINVAL;
  459.     if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
  460.     while (walk->i_ino != MSDOS_ROOT_INO) {
  461.         ino = msdos_parent_ino(walk,1);
  462.         iput(walk);
  463.         if (ino < 0) return ino;
  464.         if (ino == old_ino) return -EINVAL;
  465.         if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
  466.     }
  467.     iput(walk);
  468.     while ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) <
  469.          0) {
  470.         if (error != -ENOENT) return error;
  471.         error = msdos_add_cluster(new_dir);
  472.         if (error) return error;
  473.     }
  474.     exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
  475.     if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
  476.         brelse(free_bh);
  477.         if (exists) brelse(new_bh);
  478.         return -EIO;
  479.     }
  480.     if (*(unsigned char *) old_de->name == DELETED_FLAG) {
  481.         iput(old_inode);
  482.         brelse(free_bh);
  483.         if (exists) brelse(new_bh);
  484.         return -ENOENT;
  485.     }
  486.     new_inode = NULL; /* to make GCC happy */
  487.     if (exists) {
  488.         if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
  489.             iput(old_inode);
  490.             brelse(new_bh);
  491.             return -EIO;
  492.         }
  493.         error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ?
  494.             msdos_empty(new_inode) : -EPERM : (old_de->attr & ATTR_DIR)
  495.             ? -EPERM : 0;
  496.         if (error) {
  497.             iput(new_inode);
  498.             iput(old_inode);
  499.             brelse(new_bh);
  500.             return error;
  501.         }
  502.         new_inode->i_nlink = 0;
  503.         MSDOS_I(new_inode)->i_busy = 1;
  504.         new_inode->i_dirt = 1;
  505.         new_de->name[0] = DELETED_FLAG;
  506.         new_bh->b_dirt = 1;
  507.     }
  508.     memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
  509.     memcpy(free_de->name,new_name,MSDOS_NAME);
  510.     if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
  511.         free_de->name[0] = DELETED_FLAG;
  512. /*  Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
  513.         brelse(free_bh);
  514.         if (exists) {
  515.             iput(new_inode);
  516.             brelse(new_bh);
  517.         }
  518.         return -EIO;
  519.     }
  520.     if (exists && S_ISDIR(new_inode->i_mode)) {
  521.         new_dir->i_nlink--;
  522.         new_dir->i_dirt = 1;
  523.     }
  524.     msdos_read_inode(free_inode);
  525.     MSDOS_I(old_inode)->i_busy = 1;
  526.     cache_inval_inode(old_inode);
  527.     old_inode->i_dirt = 1;
  528.     old_de->name[0] = DELETED_FLAG;
  529.     old_bh->b_dirt = 1;
  530.     free_bh->b_dirt = 1;
  531.     if (!exists) iput(free_inode);
  532.     else {
  533.         MSDOS_I(new_inode)->i_depend = free_inode;
  534.         MSDOS_I(free_inode)->i_old = new_inode;
  535.         /* free_inode is put when putting new_inode */
  536.         iput(new_inode);
  537.         brelse(new_bh);
  538.     }
  539.     if (S_ISDIR(old_inode->i_mode)) {
  540.         if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
  541.             &dotdot_de,&dotdot_ino)) < 0) goto rename_done;
  542.         if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
  543.             brelse(dotdot_bh);
  544.             error = -EIO;
  545.             goto rename_done;
  546.         }
  547.         dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
  548.             MSDOS_I(new_dir)->i_start;
  549.         dotdot_inode->i_dirt = 1;
  550.         dotdot_bh->b_dirt = 1;
  551.         old_dir->i_nlink--;
  552.         new_dir->i_nlink++;
  553.         /* no need to mark them dirty */
  554.         dotdot_inode->i_nlink = new_dir->i_nlink;
  555.         iput(dotdot_inode);
  556.         brelse(dotdot_bh);
  557.     }
  558.     error = 0;
  559. rename_done:
  560.     brelse(free_bh);
  561.     iput(old_inode);
  562.     return error;
  563. }
  564.  
  565.  
  566. int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
  567.     struct inode *new_dir,const char *new_name,int new_len)
  568. {
  569.     char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
  570.     struct buffer_head *old_bh;
  571.     struct msdos_dir_entry *old_de;
  572.     int old_ino,error;
  573.  
  574.     if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
  575.         old_name,old_len,old_msdos_name,1)) < 0) goto rename_done;
  576.     if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
  577.         new_name,new_len,new_msdos_name,0)) < 0) goto rename_done;
  578.     if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de,
  579.         &old_ino)) < 0) goto rename_done;
  580.     lock_creation();
  581.     if (old_dir == new_dir)
  582.         error = rename_same_dir(old_dir,old_msdos_name,new_dir,
  583.             new_msdos_name,old_bh,old_de,old_ino);
  584.     else error = rename_diff_dir(old_dir,old_msdos_name,new_dir,
  585.             new_msdos_name,old_bh,old_de,old_ino);
  586.     unlock_creation();
  587.     brelse(old_bh);
  588. rename_done:
  589.     iput(old_dir);
  590.     iput(new_dir);
  591.     return error;
  592. }
  593.