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

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