root/fs/msdos/namei.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. msdos_format_name
  2. msdos_find
  3. msdos_lookup
  4. msdos_create_entry
  5. msdos_create
  6. dump_fat
  7. msdos_mkdir
  8. msdos_empty
  9. msdos_rmdir
  10. msdos_unlinkx
  11. msdos_unlink
  12. msdos_unlink_umsdos
  13. rename_same_dir
  14. rename_diff_dir
  15. msdos_rename

   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,
     /* [previous][next][first][last][top][bottom][index][help] */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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(
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 433 {
 434         return msdos_unlinkx (dir,name,len,0);
 435 }
 436 
 437 static int rename_same_dir(struct inode *old_dir,char *old_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */