|
|
1.1 ! root 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) ! 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, ! 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, ! 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, ! 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, ! 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) ! 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) ! 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) ! 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, ! 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, ! 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, ! 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.