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 / msdos / namei.c < prev   
Encoding:
C/C++ Source or Header  |  1995-01-23  |  16.0 KB  |  637 lines

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