|
|
1.1 ! root 1: /* ! 2: * linux/fs/minix/namei.c ! 3: * ! 4: * (C) 1991 Linus Torvalds ! 5: */ ! 6: ! 7: #include <linux/sched.h> ! 8: #include <linux/minix_fs.h> ! 9: #include <linux/kernel.h> ! 10: #include <asm/segment.h> ! 11: ! 12: #include <string.h> ! 13: #include <fcntl.h> ! 14: #include <errno.h> ! 15: #include <const.h> ! 16: #include <sys/stat.h> ! 17: ! 18: extern int permission(struct inode * inode,int mask); ! 19: extern struct inode * _namei(const char * filename, struct inode * base, ! 20: int follow_links); ! 21: ! 22: /* ! 23: * comment out this line if you want names > MINIX_NAME_LEN chars to be ! 24: * truncated. Else they will be disallowed. ! 25: */ ! 26: /* #define NO_TRUNCATE */ ! 27: ! 28: /* ! 29: * ok, we cannot use strncmp, as the name is not in our data space. ! 30: * Thus we'll have to use minix_match. No big problem. Match also makes ! 31: * some sanity tests. ! 32: * ! 33: * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure. ! 34: */ ! 35: static int minix_match(int len,const char * name,struct minix_dir_entry * de) ! 36: { ! 37: register int same __asm__("ax"); ! 38: ! 39: if (!de || !de->inode || len > MINIX_NAME_LEN) ! 40: return 0; ! 41: /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ ! 42: if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) ! 43: return 1; ! 44: if (len < MINIX_NAME_LEN && de->name[len]) ! 45: return 0; ! 46: __asm__("cld\n\t" ! 47: "fs ; repe ; cmpsb\n\t" ! 48: "setz %%al" ! 49: :"=a" (same) ! 50: :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len) ! 51: :"cx","di","si"); ! 52: return same; ! 53: } ! 54: ! 55: /* ! 56: * minix_find_entry() ! 57: * ! 58: * finds an entry in the specified directory with the wanted name. It ! 59: * returns the cache buffer in which the entry was found, and the entry ! 60: * itself (as a parameter - res_dir). It does NOT read the inode of the ! 61: * entry - you'll have to do that yourself if you want to. ! 62: */ ! 63: static struct buffer_head * minix_find_entry(struct inode * dir, ! 64: const char * name, int namelen, struct minix_dir_entry ** res_dir) ! 65: { ! 66: int entries; ! 67: int block,i; ! 68: struct buffer_head * bh; ! 69: struct minix_dir_entry * de; ! 70: ! 71: *res_dir = NULL; ! 72: if (!dir) ! 73: return NULL; ! 74: #ifdef NO_TRUNCATE ! 75: if (namelen > MINIX_NAME_LEN) ! 76: return NULL; ! 77: #else ! 78: if (namelen > MINIX_NAME_LEN) ! 79: namelen = MINIX_NAME_LEN; ! 80: #endif ! 81: entries = dir->i_size / (sizeof (struct minix_dir_entry)); ! 82: if (!(block = dir->i_data[0])) ! 83: return NULL; ! 84: if (!(bh = bread(dir->i_dev,block))) ! 85: return NULL; ! 86: i = 0; ! 87: de = (struct minix_dir_entry *) bh->b_data; ! 88: while (i < entries) { ! 89: if ((char *)de >= BLOCK_SIZE+bh->b_data) { ! 90: brelse(bh); ! 91: bh = NULL; ! 92: if (!(block = bmap(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK)) || ! 93: !(bh = bread(dir->i_dev,block))) { ! 94: i += MINIX_DIR_ENTRIES_PER_BLOCK; ! 95: continue; ! 96: } ! 97: de = (struct minix_dir_entry *) bh->b_data; ! 98: } ! 99: if (minix_match(namelen,name,de)) { ! 100: *res_dir = de; ! 101: return bh; ! 102: } ! 103: de++; ! 104: i++; ! 105: } ! 106: brelse(bh); ! 107: return NULL; ! 108: } ! 109: ! 110: struct inode * minix_follow_link(struct inode * dir, struct inode * inode) ! 111: { ! 112: unsigned short fs; ! 113: struct buffer_head * bh; ! 114: ! 115: if (!dir) { ! 116: dir = current->root; ! 117: dir->i_count++; ! 118: } ! 119: if (!inode) { ! 120: iput(dir); ! 121: return NULL; ! 122: } ! 123: if (!S_ISLNK(inode->i_mode)) { ! 124: iput(dir); ! 125: return inode; ! 126: } ! 127: __asm__("mov %%fs,%0":"=r" (fs)); ! 128: if ((current->link_count > 5) || !inode->i_data[0] || ! 129: !(bh = bread(inode->i_dev, inode->i_data[0]))) { ! 130: iput(dir); ! 131: iput(inode); ! 132: return NULL; ! 133: } ! 134: iput(inode); ! 135: __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); ! 136: current->link_count++; ! 137: inode = _namei(bh->b_data,dir,1); ! 138: current->link_count--; ! 139: __asm__("mov %0,%%fs"::"r" (fs)); ! 140: brelse(bh); ! 141: return inode; ! 142: } ! 143: ! 144: int minix_lookup(struct inode * dir,const char * name, int len, ! 145: struct inode ** result) ! 146: { ! 147: int ino; ! 148: struct minix_dir_entry * de; ! 149: struct buffer_head * bh; ! 150: ! 151: *result = NULL; ! 152: if (!dir) ! 153: return -ENOENT; ! 154: if (!S_ISDIR(dir->i_mode)) { ! 155: iput(dir); ! 156: return -ENOENT; ! 157: } ! 158: if (!(bh = minix_find_entry(dir,name,len,&de))) { ! 159: iput(dir); ! 160: return -ENOENT; ! 161: } ! 162: ino = de->inode; ! 163: brelse(bh); ! 164: if (!(*result = iget(dir->i_dev,ino))) { ! 165: iput(dir); ! 166: return -EACCES; ! 167: } ! 168: iput(dir); ! 169: return 0; ! 170: } ! 171: ! 172: /* ! 173: * minix_add_entry() ! 174: * ! 175: * adds a file entry to the specified directory, using the same ! 176: * semantics as minix_find_entry(). It returns NULL if it failed. ! 177: * ! 178: * NOTE!! The inode part of 'de' is left at 0 - which means you ! 179: * may not sleep between calling this and putting something into ! 180: * the entry, as someone else might have used it while you slept. ! 181: */ ! 182: static struct buffer_head * minix_add_entry(struct inode * dir, ! 183: const char * name, int namelen, struct minix_dir_entry ** res_dir) ! 184: { ! 185: int block,i; ! 186: struct buffer_head * bh; ! 187: struct minix_dir_entry * de; ! 188: ! 189: *res_dir = NULL; ! 190: if (!dir) ! 191: return NULL; ! 192: #ifdef NO_TRUNCATE ! 193: if (namelen > MINIX_NAME_LEN) ! 194: return NULL; ! 195: #else ! 196: if (namelen > MINIX_NAME_LEN) ! 197: namelen = MINIX_NAME_LEN; ! 198: #endif ! 199: if (!namelen) ! 200: return NULL; ! 201: if (!(block = dir->i_data[0])) ! 202: return NULL; ! 203: if (!(bh = bread(dir->i_dev,block))) ! 204: return NULL; ! 205: i = 0; ! 206: de = (struct minix_dir_entry *) bh->b_data; ! 207: while (1) { ! 208: if ((char *)de >= BLOCK_SIZE+bh->b_data) { ! 209: brelse(bh); ! 210: bh = NULL; ! 211: block = minix_create_block(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK); ! 212: if (!block) ! 213: return NULL; ! 214: if (!(bh = bread(dir->i_dev,block))) { ! 215: i += MINIX_DIR_ENTRIES_PER_BLOCK; ! 216: continue; ! 217: } ! 218: de = (struct minix_dir_entry *) bh->b_data; ! 219: } ! 220: if (i*sizeof(struct minix_dir_entry) >= dir->i_size) { ! 221: de->inode=0; ! 222: dir->i_size = (i+1)*sizeof(struct minix_dir_entry); ! 223: dir->i_dirt = 1; ! 224: dir->i_ctime = CURRENT_TIME; ! 225: } ! 226: if (!de->inode) { ! 227: dir->i_mtime = CURRENT_TIME; ! 228: for (i=0; i < MINIX_NAME_LEN ; i++) ! 229: de->name[i]=(i<namelen)?get_fs_byte(name+i):0; ! 230: bh->b_dirt = 1; ! 231: *res_dir = de; ! 232: return bh; ! 233: } ! 234: de++; ! 235: i++; ! 236: } ! 237: brelse(bh); ! 238: return NULL; ! 239: } ! 240: ! 241: int minix_create(struct inode * dir,const char * name, int len, int mode, ! 242: struct inode ** result) ! 243: { ! 244: struct inode * inode; ! 245: struct buffer_head * bh; ! 246: struct minix_dir_entry * de; ! 247: ! 248: *result = NULL; ! 249: if (!dir) ! 250: return -ENOENT; ! 251: inode = minix_new_inode(dir->i_dev); ! 252: if (!inode) { ! 253: iput(dir); ! 254: return -ENOSPC; ! 255: } ! 256: inode->i_mode = mode; ! 257: inode->i_dirt = 1; ! 258: bh = minix_add_entry(dir,name,len,&de); ! 259: if (!bh) { ! 260: inode->i_nlink--; ! 261: iput(inode); ! 262: iput(dir); ! 263: return -ENOSPC; ! 264: } ! 265: de->inode = inode->i_ino; ! 266: bh->b_dirt = 1; ! 267: brelse(bh); ! 268: iput(dir); ! 269: *result = inode; ! 270: return 0; ! 271: } ! 272: ! 273: int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev) ! 274: { ! 275: struct inode * inode; ! 276: struct buffer_head * bh; ! 277: struct minix_dir_entry * de; ! 278: ! 279: if (!dir) ! 280: return -ENOENT; ! 281: bh = minix_find_entry(dir,name,len,&de); ! 282: if (bh) { ! 283: brelse(bh); ! 284: iput(dir); ! 285: return -EEXIST; ! 286: } ! 287: inode = minix_new_inode(dir->i_dev); ! 288: if (!inode) { ! 289: iput(dir); ! 290: return -ENOSPC; ! 291: } ! 292: inode->i_uid = current->euid; ! 293: inode->i_mode = mode; ! 294: if (S_ISBLK(mode) || S_ISCHR(mode)) ! 295: inode->i_rdev = rdev; ! 296: inode->i_mtime = inode->i_atime = CURRENT_TIME; ! 297: inode->i_dirt = 1; ! 298: bh = minix_add_entry(dir,name,len,&de); ! 299: if (!bh) { ! 300: inode->i_nlink--; ! 301: iput(inode); ! 302: iput(dir); ! 303: return -ENOSPC; ! 304: } ! 305: de->inode = inode->i_ino; ! 306: bh->b_dirt = 1; ! 307: brelse(bh); ! 308: iput(dir); ! 309: iput(inode); ! 310: return 0; ! 311: } ! 312: ! 313: int minix_mkdir(struct inode * dir, const char * name, int len, int mode) ! 314: { ! 315: struct inode * inode; ! 316: struct buffer_head * bh, *dir_block; ! 317: struct minix_dir_entry * de; ! 318: ! 319: bh = minix_find_entry(dir,name,len,&de); ! 320: if (bh) { ! 321: brelse(bh); ! 322: iput(dir); ! 323: return -EEXIST; ! 324: } ! 325: inode = minix_new_inode(dir->i_dev); ! 326: if (!inode) { ! 327: iput(dir); ! 328: return -ENOSPC; ! 329: } ! 330: inode->i_size = 32; ! 331: inode->i_dirt = 1; ! 332: inode->i_mtime = inode->i_atime = CURRENT_TIME; ! 333: if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) { ! 334: iput(dir); ! 335: inode->i_nlink--; ! 336: iput(inode); ! 337: return -ENOSPC; ! 338: } ! 339: inode->i_dirt = 1; ! 340: if (!(dir_block = bread(inode->i_dev,inode->i_data[0]))) { ! 341: iput(dir); ! 342: inode->i_nlink--; ! 343: iput(inode); ! 344: return -ERROR; ! 345: } ! 346: de = (struct minix_dir_entry *) dir_block->b_data; ! 347: de->inode=inode->i_ino; ! 348: strcpy(de->name,"."); ! 349: de++; ! 350: de->inode = dir->i_ino; ! 351: strcpy(de->name,".."); ! 352: inode->i_nlink = 2; ! 353: dir_block->b_dirt = 1; ! 354: brelse(dir_block); ! 355: inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask); ! 356: inode->i_dirt = 1; ! 357: bh = minix_add_entry(dir,name,len,&de); ! 358: if (!bh) { ! 359: iput(dir); ! 360: inode->i_nlink=0; ! 361: iput(inode); ! 362: return -ENOSPC; ! 363: } ! 364: de->inode = inode->i_ino; ! 365: bh->b_dirt = 1; ! 366: dir->i_nlink++; ! 367: dir->i_dirt = 1; ! 368: iput(dir); ! 369: iput(inode); ! 370: brelse(bh); ! 371: return 0; ! 372: } ! 373: ! 374: /* ! 375: * routine to check that the specified directory is empty (for rmdir) ! 376: */ ! 377: static int empty_dir(struct inode * inode) ! 378: { ! 379: int nr,block; ! 380: int len; ! 381: struct buffer_head * bh; ! 382: struct minix_dir_entry * de; ! 383: ! 384: len = inode->i_size / sizeof (struct minix_dir_entry); ! 385: if (len<2 || !inode->i_data[0] || ! 386: !(bh=bread(inode->i_dev,inode->i_data[0]))) { ! 387: printk("warning - bad directory on dev %04x\n",inode->i_dev); ! 388: return 0; ! 389: } ! 390: de = (struct minix_dir_entry *) bh->b_data; ! 391: if (de[0].inode != inode->i_ino || !de[1].inode || ! 392: strcmp(".",de[0].name) || strcmp("..",de[1].name)) { ! 393: printk("warning - bad directory on dev %04x\n",inode->i_dev); ! 394: return 0; ! 395: } ! 396: nr = 2; ! 397: de += 2; ! 398: while (nr<len) { ! 399: if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) { ! 400: brelse(bh); ! 401: block=bmap(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK); ! 402: if (!block) { ! 403: nr += MINIX_DIR_ENTRIES_PER_BLOCK; ! 404: continue; ! 405: } ! 406: if (!(bh=bread(inode->i_dev,block))) ! 407: return 0; ! 408: de = (struct minix_dir_entry *) bh->b_data; ! 409: } ! 410: if (de->inode) { ! 411: brelse(bh); ! 412: return 0; ! 413: } ! 414: de++; ! 415: nr++; ! 416: } ! 417: brelse(bh); ! 418: return 1; ! 419: } ! 420: ! 421: int minix_rmdir(struct inode * dir, const char * name, int len) ! 422: { ! 423: int retval; ! 424: struct inode * inode; ! 425: struct buffer_head * bh; ! 426: struct minix_dir_entry * de; ! 427: ! 428: inode = NULL; ! 429: bh = minix_find_entry(dir,name,len,&de); ! 430: retval = -ENOENT; ! 431: if (!bh) ! 432: goto end_rmdir; ! 433: retval = -EPERM; ! 434: if (!(inode = iget(dir->i_dev, de->inode))) ! 435: goto end_rmdir; ! 436: if ((dir->i_mode & S_ISVTX) && current->euid && ! 437: inode->i_uid != current->euid) ! 438: goto end_rmdir; ! 439: if (inode->i_dev != dir->i_dev) ! 440: goto end_rmdir; ! 441: if (inode == dir) /* we may not delete ".", but "../dir" is ok */ ! 442: goto end_rmdir; ! 443: if (!S_ISDIR(inode->i_mode)) { ! 444: retval = -ENOTDIR; ! 445: goto end_rmdir; ! 446: } ! 447: if (!empty_dir(inode)) { ! 448: retval = -ENOTEMPTY; ! 449: goto end_rmdir; ! 450: } ! 451: if (inode->i_count > 1) { ! 452: retval = -EBUSY; ! 453: goto end_rmdir; ! 454: } ! 455: if (inode->i_nlink != 2) ! 456: printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink); ! 457: de->inode = 0; ! 458: bh->b_dirt = 1; ! 459: inode->i_nlink=0; ! 460: inode->i_dirt=1; ! 461: dir->i_nlink--; ! 462: dir->i_ctime = dir->i_mtime = CURRENT_TIME; ! 463: dir->i_dirt=1; ! 464: retval = 0; ! 465: end_rmdir: ! 466: iput(dir); ! 467: iput(inode); ! 468: brelse(bh); ! 469: return retval; ! 470: } ! 471: ! 472: int minix_unlink(struct inode * dir, const char * name, int len) ! 473: { ! 474: int retval; ! 475: struct inode * inode; ! 476: struct buffer_head * bh; ! 477: struct minix_dir_entry * de; ! 478: ! 479: retval = -ENOENT; ! 480: inode = NULL; ! 481: bh = minix_find_entry(dir,name,len,&de); ! 482: if (!bh) ! 483: goto end_unlink; ! 484: if (!(inode = iget(dir->i_dev, de->inode))) ! 485: goto end_unlink; ! 486: retval = -EPERM; ! 487: if ((dir->i_mode & S_ISVTX) && !suser() && ! 488: current->euid != inode->i_uid && ! 489: current->euid != dir->i_uid) ! 490: goto end_unlink; ! 491: if (S_ISDIR(inode->i_mode)) ! 492: goto end_unlink; ! 493: if (!inode->i_nlink) { ! 494: printk("Deleting nonexistent file (%04x:%d), %d\n", ! 495: inode->i_dev,inode->i_ino,inode->i_nlink); ! 496: inode->i_nlink=1; ! 497: } ! 498: de->inode = 0; ! 499: bh->b_dirt = 1; ! 500: inode->i_nlink--; ! 501: inode->i_dirt = 1; ! 502: inode->i_ctime = CURRENT_TIME; ! 503: retval = 0; ! 504: end_unlink: ! 505: brelse(bh); ! 506: iput(inode); ! 507: iput(dir); ! 508: return retval; ! 509: } ! 510: ! 511: int minix_symlink(struct inode * dir, const char * name, int len, const char * symname) ! 512: { ! 513: struct minix_dir_entry * de; ! 514: struct inode * inode = NULL; ! 515: struct buffer_head * bh = NULL, * name_block = NULL; ! 516: int i; ! 517: char c; ! 518: ! 519: if (!(inode = minix_new_inode(dir->i_dev))) { ! 520: iput(dir); ! 521: return -ENOSPC; ! 522: } ! 523: inode->i_mode = S_IFLNK | 0777; ! 524: inode->i_dirt = 1; ! 525: if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) { ! 526: iput(dir); ! 527: inode->i_nlink--; ! 528: iput(inode); ! 529: return -ENOSPC; ! 530: } ! 531: inode->i_dirt = 1; ! 532: if (!(name_block = bread(inode->i_dev,inode->i_data[0]))) { ! 533: iput(dir); ! 534: inode->i_nlink--; ! 535: iput(inode); ! 536: return -ERROR; ! 537: } ! 538: i = 0; ! 539: while (i < 1023 && (c=get_fs_byte(symname++))) ! 540: name_block->b_data[i++] = c; ! 541: name_block->b_data[i] = 0; ! 542: name_block->b_dirt = 1; ! 543: brelse(name_block); ! 544: inode->i_size = i; ! 545: inode->i_dirt = 1; ! 546: bh = minix_find_entry(dir,name,len,&de); ! 547: if (bh) { ! 548: inode->i_nlink--; ! 549: iput(inode); ! 550: brelse(bh); ! 551: iput(dir); ! 552: return -EEXIST; ! 553: } ! 554: bh = minix_add_entry(dir,name,len,&de); ! 555: if (!bh) { ! 556: inode->i_nlink--; ! 557: iput(inode); ! 558: iput(dir); ! 559: return -ENOSPC; ! 560: } ! 561: de->inode = inode->i_ino; ! 562: bh->b_dirt = 1; ! 563: brelse(bh); ! 564: iput(dir); ! 565: iput(inode); ! 566: return 0; ! 567: } ! 568: ! 569: int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len) ! 570: { ! 571: struct minix_dir_entry * de; ! 572: struct buffer_head * bh; ! 573: ! 574: if (S_ISDIR(oldinode->i_mode)) { ! 575: iput(oldinode); ! 576: iput(dir); ! 577: return -EPERM; ! 578: } ! 579: bh = minix_find_entry(dir,name,len,&de); ! 580: if (bh) { ! 581: brelse(bh); ! 582: iput(dir); ! 583: iput(oldinode); ! 584: return -EEXIST; ! 585: } ! 586: bh = minix_add_entry(dir,name,len,&de); ! 587: if (!bh) { ! 588: iput(dir); ! 589: iput(oldinode); ! 590: return -ENOSPC; ! 591: } ! 592: de->inode = oldinode->i_ino; ! 593: bh->b_dirt = 1; ! 594: brelse(bh); ! 595: iput(dir); ! 596: oldinode->i_nlink++; ! 597: oldinode->i_ctime = CURRENT_TIME; ! 598: oldinode->i_dirt = 1; ! 599: iput(oldinode); ! 600: return 0; ! 601: } ! 602: ! 603: static int subdir(struct inode * new, struct inode * old) ! 604: { ! 605: unsigned short fs; ! 606: int ino; ! 607: int result; ! 608: ! 609: __asm__("mov %%fs,%0":"=r" (fs)); ! 610: __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); ! 611: new->i_count++; ! 612: result = 0; ! 613: for (;;) { ! 614: if (new == old) { ! 615: result = 1; ! 616: break; ! 617: } ! 618: if (new->i_dev != old->i_dev) ! 619: break; ! 620: ino = new->i_ino; ! 621: if (minix_lookup(new,"..",2,&new)) ! 622: break; ! 623: if (new->i_ino == ino) ! 624: break; ! 625: } ! 626: iput(new); ! 627: __asm__("mov %0,%%fs"::"r" (fs)); ! 628: return result; ! 629: } ! 630: ! 631: #define PARENT_INO(buffer) \ ! 632: (((struct minix_dir_entry *) (buffer))[1].inode) ! 633: ! 634: #define PARENT_NAME(buffer) \ ! 635: (((struct minix_dir_entry *) (buffer))[1].name) ! 636: ! 637: /* ! 638: * rename uses retrying to avoid race-conditions: at least they should be minimal. ! 639: * it tries to allocate all the blocks, then sanity-checks, and if the sanity- ! 640: * checks fail, it tries to restart itself again. Very practical - no changes ! 641: * are done until we know everything works ok.. and then all the changes can be ! 642: * done in one fell swoop when we have claimed all the buffers needed. ! 643: * ! 644: * Anybody can rename anything with this: the permission checks are left to the ! 645: * higher-level routines. ! 646: */ ! 647: static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len, ! 648: struct inode * new_dir, const char * new_name, int new_len) ! 649: { ! 650: struct inode * old_inode, * new_inode; ! 651: struct buffer_head * old_bh, * new_bh, * dir_bh; ! 652: struct minix_dir_entry * old_de, * new_de; ! 653: int retval; ! 654: ! 655: goto start_up; ! 656: try_again: ! 657: brelse(old_bh); ! 658: brelse(new_bh); ! 659: brelse(dir_bh); ! 660: iput(old_inode); ! 661: iput(new_inode); ! 662: current->counter = 0; ! 663: schedule(); ! 664: start_up: ! 665: old_inode = new_inode = NULL; ! 666: old_bh = new_bh = dir_bh = NULL; ! 667: old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de); ! 668: retval = -ENOENT; ! 669: if (!old_bh) ! 670: goto end_rename; ! 671: old_inode = iget(old_dir->i_dev, old_de->inode); ! 672: if (!old_inode) ! 673: goto end_rename; ! 674: new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de); ! 675: if (new_bh) { ! 676: new_inode = iget(new_dir->i_dev, new_de->inode); ! 677: if (!new_inode) { ! 678: brelse(new_bh); ! 679: new_bh = NULL; ! 680: } ! 681: } ! 682: if (new_inode == old_inode) { ! 683: retval = 0; ! 684: goto end_rename; ! 685: } ! 686: if (S_ISDIR(old_inode->i_mode)) { ! 687: retval = -EEXIST; ! 688: if (new_bh) ! 689: goto end_rename; ! 690: retval = -EACCES; ! 691: if (!permission(old_inode, MAY_WRITE)) ! 692: goto end_rename; ! 693: retval = -EINVAL; ! 694: if (subdir(new_dir, old_inode)) ! 695: goto end_rename; ! 696: retval = -EIO; ! 697: if (!old_inode->i_data[0]) ! 698: goto end_rename; ! 699: if (!(dir_bh = bread(old_inode->i_dev, old_inode->i_data[0]))) ! 700: goto end_rename; ! 701: if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) ! 702: goto end_rename; ! 703: } ! 704: if (!new_bh) ! 705: new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de); ! 706: retval = -ENOSPC; ! 707: if (!new_bh) ! 708: goto end_rename; ! 709: /* sanity checking before doing the rename - avoid races */ ! 710: if (new_inode && (new_de->inode != new_inode->i_ino)) ! 711: goto try_again; ! 712: if (new_de->inode && !new_inode) ! 713: goto try_again; ! 714: if (old_de->inode != old_inode->i_ino) ! 715: goto try_again; ! 716: /* ok, that's it */ ! 717: old_de->inode = 0; ! 718: new_de->inode = old_inode->i_ino; ! 719: if (new_inode) ! 720: new_inode->i_nlink--; ! 721: old_bh->b_dirt = 1; ! 722: new_bh->b_dirt = 1; ! 723: if (dir_bh) { ! 724: PARENT_INO(dir_bh->b_data) = new_dir->i_ino; ! 725: dir_bh->b_dirt = 1; ! 726: old_dir->i_nlink--; ! 727: new_dir->i_nlink++; ! 728: old_dir->i_dirt = 1; ! 729: new_dir->i_dirt = 1; ! 730: } ! 731: retval = 0; ! 732: end_rename: ! 733: brelse(dir_bh); ! 734: brelse(old_bh); ! 735: brelse(new_bh); ! 736: iput(old_inode); ! 737: iput(new_inode); ! 738: iput(old_dir); ! 739: iput(new_dir); ! 740: return retval; ! 741: } ! 742: ! 743: /* ! 744: * Ok, rename also locks out other renames, as they can change the parent of ! 745: * a directory, and we don't want any races. Other races are checked for by ! 746: * "do_rename()", which restarts if there are inconsistencies. ! 747: * ! 748: * Note that there is no race between different filesystems: it's only within ! 749: * the same device that races occur: many renames can happen at once, as long ! 750: * as they are on different partitions. ! 751: */ ! 752: int minix_rename(struct inode * old_dir, const char * old_name, int old_len, ! 753: struct inode * new_dir, const char * new_name, int new_len) ! 754: { ! 755: static struct task_struct * wait = NULL; ! 756: static int lock = 0; ! 757: int result; ! 758: ! 759: while (lock) ! 760: sleep_on(&wait); ! 761: lock = 1; ! 762: result = do_minix_rename(old_dir, old_name, old_len, ! 763: new_dir, new_name, new_len); ! 764: lock = 0; ! 765: wake_up(&wait); ! 766: return result; ! 767: } ! 768: ! 769: int minix_readlink(struct inode * inode, char * buffer, int buflen) ! 770: { ! 771: struct buffer_head * bh; ! 772: int i; ! 773: char c; ! 774: ! 775: if (!S_ISLNK(inode->i_mode)) { ! 776: iput(inode); ! 777: return -EINVAL; ! 778: } ! 779: if (buflen > 1023) ! 780: buflen = 1023; ! 781: if (inode->i_data[0]) ! 782: bh = bread(inode->i_dev, inode->i_data[0]); ! 783: else ! 784: bh = NULL; ! 785: iput(inode); ! 786: if (!bh) ! 787: return 0; ! 788: i = 0; ! 789: while (i<buflen && (c = bh->b_data[i])) { ! 790: i++; ! 791: put_fs_byte(c,buffer++); ! 792: } ! 793: brelse(bh); ! 794: return i; ! 795: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.