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. msdos_mkdir
  7. msdos_rmdir
  8. msdos_unlink
  9. rename_same_dir
  10. rename_diff_dir
  11. msdos_rename

   1 /*
   2  *  linux/fs/msdos/namei.c
   3  *
   4  *  Written 1992 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 /* Formats an MS-DOS file name. Rejects invalid names. */
  26 
  27 static int msdos_format_name(char conv,const char *name,int len,char *res)
     /* [previous][next][first][last][top][bottom][index][help] */
  28 {
  29         char *walk,**reserved;
  30         char c;
  31         int space;
  32 
  33         if (get_fs_byte(name) == DELETED_FLAG) return -EINVAL;
  34         if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 &&
  35             get_fs_byte(name+1) == '.'))) {
  36                 memset(res+1,' ',10);
  37                 while (len--) *res++ = '.';
  38                 return 0;
  39         }
  40         space = 0; /* to make GCC happy */
  41         c = 0;
  42         for (walk = res; len && walk-res < 8; walk++) {
  43                 c = get_fs_byte(name++);
  44                 len--;
  45                 if (c == ' ' && conv != 'r') return -EINVAL;
  46                 if (c >= 'A' && c <= 'Z') {
  47                         if (conv != 'r') return -EINVAL;
  48                         c += 32;
  49                 }
  50                 if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
  51                 if (c == '.') break;
  52                 space = c == ' ';
  53                 *walk = c >= 'a' && c <= 'z' ? c-32 : c;
  54         }
  55         if (space) return -EINVAL;
  56         if (conv == 's' && len && c != '.') {
  57                 c = get_fs_byte(name++);
  58                 len--;
  59                 if (c != '.') return -EINVAL;
  60         }
  61         while (c != '.' && len--) c = get_fs_byte(name++);
  62         if (walk == res) return -EINVAL;
  63         if (c == '.') {
  64                 while (walk-res < 8) *walk++ = ' ';
  65                 while (len > 0 && walk-res < MSDOS_NAME) {
  66                         c = get_fs_byte(name++);
  67                         len--;
  68                         if (c == ' ' && conv != 'r') return -EINVAL;
  69                         if (c < ' ' || c == ':' || c == '\\' || c == '.')
  70                                 return -EINVAL;
  71                         if (c >= 'A' && c <= 'Z') {
  72                                 if (conv != 'r') return -EINVAL;
  73                                 c += 32;
  74                         }
  75                         space = c == ' ';
  76                         *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
  77                 }
  78                 if (space) return -EINVAL;
  79                 if (conv == 's' && len) return -EINVAL;
  80         }
  81         while (walk-res < MSDOS_NAME) *walk++ = ' ';
  82         for (reserved = reserved_names; *reserved; reserved++)
  83                 if (!strncmp(res,*reserved,8)) return -EINVAL;
  84         return 0;
  85 }
  86 
  87 
  88 /* Locates a directory entry. */
  89 
  90 static int msdos_find(struct inode *dir,const char *name,int len,
     /* [previous][next][first][last][top][bottom][index][help] */
  91     struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
  92 {
  93         char msdos_name[MSDOS_NAME];
  94         int res;
  95 
  96         if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
  97             msdos_name)) < 0) return res;
  98         return msdos_scan(dir,msdos_name,bh,de,ino);
  99 }
 100 
 101 
 102 int msdos_lookup(struct inode *dir,const char *name,int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 103     struct inode **result)
 104 {
 105         int ino,res;
 106         struct msdos_dir_entry *de;
 107         struct buffer_head *bh;
 108         struct inode *next;
 109 
 110         *result = NULL;
 111         if (!dir) return -ENOENT;
 112         if (!S_ISDIR(dir->i_mode)) {
 113                 iput(dir);
 114                 return -ENOENT;
 115         }
 116         if (len == 1 && get_fs_byte(name) == '.') {
 117                 *result = dir;
 118                 return 0;
 119         }
 120         if (len == 2 && get_fs_byte(name) == '.' && get_fs_byte(name+1) == '.')
 121             {
 122                 ino = msdos_parent_ino(dir,0);
 123                 iput(dir);
 124                 if (ino < 0) return ino;
 125                 if (!(*result = iget(dir->i_dev,ino))) return -EACCES;
 126                 return 0;
 127         }
 128         if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
 129                 iput(dir);
 130                 return res;
 131         }
 132         if (bh) brelse(bh);
 133 /* printk("lookup: ino=%d\r\n",ino); */
 134         if (!(*result = iget(dir->i_dev,ino))) {
 135                 iput(dir);
 136                 return -EACCES;
 137         }
 138         if ((*result)->i_data[D_BUSY]) { /* mkdir in progress */
 139                 iput(*result);
 140                 iput(dir);
 141                 return -ENOENT;
 142         }
 143         while ((*result)->i_data[D_OLD]) {
 144                 next = (struct inode *) ((*result)->i_data[D_OLD]);
 145                 iput(*result);
 146                 if (!(*result = iget(next->i_dev,next->i_ino)))
 147                         panic("msdos_lookup: Can't happen");
 148         }
 149         iput(dir);
 150         return 0;
 151 }
 152 
 153 
 154 /* Creates a directory entry (name is already formatted). */
 155 
 156 static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
     /* [previous][next][first][last][top][bottom][index][help] */
 157     struct inode **result)
 158 {
 159         struct buffer_head *bh;
 160         struct msdos_dir_entry *de;
 161         int res,ino;
 162 
 163         if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) {
 164                 if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
 165                 if ((res = msdos_add_cluster(dir)) < 0) return res;
 166                 if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res;
 167         }
 168         memcpy(de->name,name,MSDOS_NAME);
 169         de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
 170         de->start = 0;
 171         date_unix2dos(CURRENT_TIME,&de->time,&de->date);
 172         de->size = 0;
 173         bh->b_dirt = 1;
 174         if (*result = iget(dir->i_dev,ino)) msdos_read_inode(*result);
 175         brelse(bh);
 176         if (!*result) return -EIO;
 177         (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
 178             CURRENT_TIME;
 179         (*result)->i_dirt = 1;
 180         return 0;
 181 }
 182 
 183 
 184 int msdos_create(struct inode *dir,const char *name,int len,int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
 185         struct inode **result)
 186 {
 187         struct buffer_head *bh;
 188         struct msdos_dir_entry *de;
 189         char msdos_name[MSDOS_NAME];
 190         int ino,res;
 191 
 192         if (!dir) return -ENOENT;
 193         if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
 194             msdos_name)) < 0) {
 195                 iput(dir);
 196                 return res;
 197         }
 198         lock_creation();
 199         if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
 200                 unlock_creation();
 201                 brelse(bh);
 202                 iput(dir);
 203                 return -EEXIST;
 204         }
 205         res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),result);
 206         unlock_creation();
 207         iput(dir);
 208         return res;
 209 }
 210 
 211 
 212 int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 213 {
 214         struct buffer_head *bh;
 215         struct msdos_dir_entry *de;
 216         struct inode *inode,*dot;
 217         char msdos_name[MSDOS_NAME];
 218         int ino,res;
 219 
 220         if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
 221             msdos_name)) < 0) {
 222                 iput(dir);
 223                 return res;
 224         }
 225         lock_creation();
 226         if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
 227                 unlock_creation();
 228                 brelse(bh);
 229                 iput(dir);
 230                 return -EEXIST;
 231         }
 232         if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) {
 233                 unlock_creation();
 234                 iput(dir);
 235                 return res;
 236         }
 237         inode->i_data[D_BUSY] = 1; /* prevent lookups */
 238         if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
 239         if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
 240                 goto mkdir_error;
 241         dot->i_size = inode->i_size;
 242         dot->i_data[D_START] = inode->i_data[D_START];
 243         dot->i_dirt = 1;
 244         iput(dot);
 245         if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
 246                 goto mkdir_error;
 247         unlock_creation();
 248         dot->i_size = dir->i_size;
 249         dot->i_data[D_START] = dir->i_data[D_START];
 250         dot->i_dirt = 1;
 251         inode->i_data[D_BUSY] = 0;
 252         iput(dot);
 253         iput(inode);
 254         iput(dir);
 255         return 0;
 256 mkdir_error:
 257         iput(inode);
 258         if (msdos_rmdir(dir,name,len) < 0) panic("rmdir in mkdir failed");
 259         unlock_creation();
 260         return res;
 261 }
 262 
 263 
 264 int msdos_rmdir(struct inode *dir,const char *name,int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 265 {
 266         int res,ino,pos;
 267         struct buffer_head *bh,*dbh;
 268         struct msdos_dir_entry *de,*dde;
 269         struct inode *inode;
 270 
 271         bh = NULL;
 272         inode = NULL;
 273         res = -EINVAL;
 274         if (len == 1 && get_fs_byte(name) == '.') goto rmdir_done;
 275         if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
 276         res = -ENOENT;
 277         if (!(inode = iget(dir->i_dev,ino))) goto rmdir_done;
 278         res = -ENOTDIR;
 279         if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
 280         res = -EBUSY;
 281         if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
 282         if (inode->i_count > 1) goto rmdir_done;
 283         if (inode->i_data[D_START]) { /* may be zero in mkdir */
 284                 res = -ENOTEMPTY;
 285                 pos = 0;
 286                 dbh = NULL;
 287                 while (msdos_get_entry(inode,&pos,&dbh,&dde) > -1)
 288                         if (dde->name[0] && ((unsigned char *) dde->name)[0] !=
 289                             DELETED_FLAG && strncmp(dde->name,MSDOS_DOT,
 290                             MSDOS_NAME) && strncmp(dde->name,MSDOS_DOTDOT,
 291                             MSDOS_NAME)) goto rmdir_done;
 292                 if (dbh) brelse(dbh);
 293         }
 294         inode->i_nlink = 0;
 295         dir->i_mtime = CURRENT_TIME;
 296         inode->i_dirt = dir->i_dirt = 1;
 297         de->name[0] = DELETED_FLAG;
 298         bh->b_dirt = 1;
 299         res = 0;
 300 rmdir_done:
 301         brelse(bh);
 302         iput(dir);
 303         iput(inode);
 304         return res;
 305 }
 306 
 307 
 308 int msdos_unlink(struct inode *dir,const char *name,int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 309 {
 310         int res,ino;
 311         struct buffer_head *bh;
 312         struct msdos_dir_entry *de;
 313         struct inode *inode;
 314 
 315         bh = NULL;
 316         inode = NULL;
 317         if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
 318                 goto unlink_done;
 319         if (!(inode = iget(dir->i_dev,ino))) {
 320                 res = -ENOENT;
 321                 goto unlink_done;
 322         }
 323         if (!S_ISREG(inode->i_mode)) {
 324                 res = -EPERM;
 325                 goto unlink_done;
 326         }
 327         inode->i_nlink = 0;
 328         inode->i_data[D_BUSY] = 1;
 329         inode->i_dirt = 1;
 330         de->name[0] = DELETED_FLAG;
 331         bh->b_dirt = 1;
 332 unlink_done:
 333         brelse(bh);
 334         iput(inode);
 335         iput(dir);
 336         return res;
 337 }
 338 
 339 
 340 static int rename_same_dir(struct inode *old_dir,char *old_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 341     struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
 342     struct msdos_dir_entry *old_de,int old_ino)
 343 {
 344         struct buffer_head *new_bh;
 345         struct msdos_dir_entry *new_de;
 346         struct inode *new_inode,*old_inode;
 347         int new_ino;
 348         int exists;
 349 
 350         if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
 351         exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
 352         if (*(unsigned char *) old_de->name == DELETED_FLAG) {
 353                 if (exists) brelse(new_bh);
 354                 return -ENOENT;
 355         }
 356         if (exists) {
 357                 if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
 358                         brelse(new_bh);
 359                         return -EIO;
 360                 }
 361                 if (S_ISDIR(new_inode->i_mode)) {
 362                         iput(new_inode);
 363                         brelse(new_bh);
 364                         return -EPERM;
 365                 }
 366                 new_inode->i_nlink = 0;
 367                 new_inode->i_data[D_BUSY] = 1;
 368                 new_inode->i_dirt = 1;
 369                 new_de->name[0] = DELETED_FLAG;
 370                 new_bh->b_dirt = 1;
 371                 iput(new_inode);
 372                 brelse(new_bh);
 373         }
 374         memcpy(old_de->name,new_name,MSDOS_NAME);
 375         old_bh->b_dirt = 1;
 376         if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */
 377                 if (old_inode = iget(old_dir->i_dev,old_ino)) {
 378                         msdos_read_inode(old_inode);
 379                         iput(old_inode);
 380                 }
 381         return 0;
 382 }
 383 
 384 
 385 static int rename_diff_dir(struct inode *old_dir,char *old_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 386     struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
 387     struct msdos_dir_entry *old_de,int old_ino)
 388 {
 389         struct buffer_head *new_bh,*free_bh,*dotdot_bh;
 390         struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
 391         struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
 392         int new_ino,free_ino,dotdot_ino;
 393         int error,exists,ino;
 394 
 395         if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
 396         if (old_ino == new_dir->i_ino) return -EINVAL;
 397         if (!(walk = iget(new_dir->i_dev,new_dir->i_ino))) return -EIO;
 398         while (walk->i_ino != MSDOS_ROOT_INO) {
 399                 ino = msdos_parent_ino(walk,1);
 400                 iput(walk);
 401                 if (ino < 0) return ino;
 402                 if (ino == old_ino) return -EINVAL;
 403                 if (!(walk = iget(new_dir->i_dev,ino))) return -EIO;
 404         }
 405         iput(walk);
 406         if ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < 0)
 407             return error;
 408         exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)
 409             >= 0;
 410         if (!(old_inode = iget(old_dir->i_dev,old_ino))) {
 411                 brelse(free_bh);
 412                 if (exists) brelse(new_bh);
 413                 return -EIO;
 414         }
 415         if (*(unsigned char *) old_de->name == DELETED_FLAG) {
 416                 iput(old_inode);
 417                 brelse(free_bh);
 418                 if (exists) brelse(new_bh);
 419                 return -ENOENT;
 420         }
 421         new_inode = NULL; /* to make GCC happy */
 422         if (exists) {
 423                 if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
 424                         iput(old_inode);
 425                         brelse(new_bh);
 426                         return -EIO;
 427                 }
 428                 if (S_ISDIR(new_inode->i_mode)) {
 429                         iput(new_inode);
 430                         iput(old_inode);
 431                         brelse(new_bh);
 432                         return -EPERM;
 433                 }
 434                 new_inode->i_nlink = 0;
 435                 new_inode->i_data[D_BUSY] = 1;
 436                 new_inode->i_dirt = 1;
 437                 new_de->name[0] = DELETED_FLAG;
 438                 new_bh->b_dirt = 1;
 439         }
 440         memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
 441         memcpy(free_de->name,new_name,MSDOS_NAME);
 442         if (!(free_inode = iget(new_dir->i_dev,free_ino))) {
 443                 free_de->name[0] = DELETED_FLAG;
 444 /*  Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
 445                 brelse(free_bh);
 446                 if (exists) {
 447                         iput(new_inode);
 448                         brelse(new_bh);
 449                 }
 450                 return -EIO;
 451         }
 452         msdos_read_inode(free_inode);
 453         old_inode->i_data[D_BUSY] = 1;
 454         old_inode->i_dirt = 1;
 455         old_de->name[0] = DELETED_FLAG;
 456         old_bh->b_dirt = 1;
 457         free_bh->b_dirt = 1;
 458         if (!exists) iput(free_inode);
 459         else {
 460                 new_inode->i_data[D_DEPEND] = (int) free_inode;
 461                 free_inode->i_data[D_OLD] = (int) new_inode;
 462                 /* free_inode is put when putting new_inode */
 463                 iput(new_inode);
 464                 brelse(new_bh);
 465         }
 466         if (S_ISDIR(old_inode->i_mode)) {
 467                 if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
 468                     &dotdot_de,&dotdot_ino)) < 0) goto rename_done;
 469                 if (!(dotdot_inode = iget(old_inode->i_dev,dotdot_ino))) {
 470                         brelse(dotdot_bh);
 471                         error = -EIO;
 472                         goto rename_done;
 473                 }
 474                 dotdot_de->start = dotdot_inode->i_data[D_START] =
 475                     new_dir->i_data[D_START];
 476                 dotdot_inode->i_dirt = 1;
 477                 dotdot_bh->b_dirt = 1;
 478                 iput(dotdot_inode);
 479                 brelse(dotdot_bh);
 480         }
 481         error = 0;
 482 rename_done:
 483         brelse(free_bh);
 484         iput(old_inode);
 485         return error;
 486 }
 487 
 488 
 489 int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
 490         struct inode *new_dir,const char *new_name,int new_len)
 491 {
 492         char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
 493         struct buffer_head *old_bh;
 494         struct msdos_dir_entry *old_de;
 495         int old_ino,error;
 496 
 497         if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
 498             old_name,old_len,old_msdos_name)) < 0) goto rename_done;
 499         if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
 500             new_name,new_len,new_msdos_name)) < 0) goto rename_done;
 501         if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de,
 502             &old_ino)) < 0) goto rename_done;
 503         lock_creation();
 504         if (old_dir == new_dir)
 505                 error = rename_same_dir(old_dir,old_msdos_name,new_dir,
 506                     new_msdos_name,old_bh,old_de,old_ino);
 507         else error = rename_diff_dir(old_dir,old_msdos_name,new_dir,
 508                     new_msdos_name,old_bh,old_de,old_ino);
 509         unlock_creation();
 510         brelse(old_bh);
 511 rename_done:
 512         iput(old_dir);
 513         iput(new_dir);
 514         return error;
 515 }

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