|
|
1.1.1.2 ! root 1: /* ! 2: * linux/fs/namei.c ! 3: * ! 4: * (C) 1991 Linus Torvalds ! 5: */ ! 6: 1.1 root 7: #include <linux/sched.h> 8: #include <linux/kernel.h> 9: #include <asm/segment.h> 10: 11: #include <string.h> 12: #include <fcntl.h> 13: #include <errno.h> 14: #include <const.h> 15: #include <sys/stat.h> 16: 17: #define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE]) 18: 19: /* 20: * comment out this line if you want names > NAME_LEN chars to be 21: * truncated. Else they will be disallowed. 22: */ 23: /* #define NO_TRUNCATE */ 24: 25: #define MAY_EXEC 1 26: #define MAY_WRITE 2 27: #define MAY_READ 4 28: 29: /* 30: * permission() 31: * 32: * is used to check for read/write/execute permissions on a file. 33: * I don't know if we should look at just the euid or both euid and 34: * uid, but that should be easily changed. 35: */ 36: static int permission(struct m_inode * inode,int mask) 37: { 38: int mode = inode->i_mode; 39: 40: /* special case: not even root can read/write a deleted file */ 41: if (inode->i_dev && !inode->i_nlinks) 42: return 0; 1.1.1.2 ! root 43: else if (current->euid==inode->i_uid) 1.1 root 44: mode >>= 6; 1.1.1.2 ! root 45: else if (current->egid==inode->i_gid) 1.1 root 46: mode >>= 3; 1.1.1.2 ! root 47: if (((mode & mask & 0007) == mask) || suser()) ! 48: return 1; ! 49: return 0; 1.1 root 50: } 51: 52: /* 53: * ok, we cannot use strncmp, as the name is not in our data space. 54: * Thus we'll have to use match. No big problem. Match also makes 55: * some sanity tests. 56: * 57: * NOTE! unlike strncmp, match returns 1 for success, 0 for failure. 58: */ 59: static int match(int len,const char * name,struct dir_entry * de) 60: { 61: register int same __asm__("ax"); 62: 63: if (!de || !de->inode || len > NAME_LEN) 64: return 0; 65: if (len < NAME_LEN && de->name[len]) 66: return 0; 67: __asm__("cld\n\t" 68: "fs ; repe ; cmpsb\n\t" 69: "setz %%al" 70: :"=a" (same) 71: :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len) 72: :"cx","di","si"); 73: return same; 74: } 75: 76: /* 77: * find_entry() 78: * 79: * finds and entry in the specified directory with the wanted name. It 80: * returns the cache buffer in which the entry was found, and the entry 81: * itself (as a parameter - res_dir). It does NOT read the inode of the 82: * entry - you'll have to do that yourself if you want to. 1.1.1.2 ! root 83: * ! 84: * This also takes care of the few special cases due to '..'-traversal ! 85: * over a pseudo-root and a mount point. 1.1 root 86: */ 1.1.1.2 ! root 87: static struct buffer_head * find_entry(struct m_inode ** dir, 1.1 root 88: const char * name, int namelen, struct dir_entry ** res_dir) 89: { 90: int entries; 91: int block,i; 92: struct buffer_head * bh; 93: struct dir_entry * de; 1.1.1.2 ! root 94: struct super_block * sb; 1.1 root 95: 96: #ifdef NO_TRUNCATE 97: if (namelen > NAME_LEN) 98: return NULL; 99: #else 100: if (namelen > NAME_LEN) 101: namelen = NAME_LEN; 102: #endif 1.1.1.2 ! root 103: entries = (*dir)->i_size / (sizeof (struct dir_entry)); 1.1 root 104: *res_dir = NULL; 105: if (!namelen) 106: return NULL; 1.1.1.2 ! root 107: /* check for '..', as we might have to do some "magic" for it */ ! 108: if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') { ! 109: /* '..' in a pseudo-root results in a faked '.' (just change namelen) */ ! 110: if ((*dir) == current->root) ! 111: namelen=1; ! 112: else if ((*dir)->i_num == ROOT_INO) { ! 113: /* '..' over a mount-point results in 'dir' being exchanged for the mounted ! 114: directory-inode. NOTE! We set mounted, so that we can iput the new dir */ ! 115: sb=get_super((*dir)->i_dev); ! 116: if (sb->s_imount) { ! 117: iput(*dir); ! 118: (*dir)=sb->s_imount; ! 119: (*dir)->i_count++; ! 120: } ! 121: } ! 122: } ! 123: if (!(block = (*dir)->i_zone[0])) 1.1 root 124: return NULL; 1.1.1.2 ! root 125: if (!(bh = bread((*dir)->i_dev,block))) 1.1 root 126: return NULL; 127: i = 0; 128: de = (struct dir_entry *) bh->b_data; 129: while (i < entries) { 130: if ((char *)de >= BLOCK_SIZE+bh->b_data) { 131: brelse(bh); 132: bh = NULL; 1.1.1.2 ! root 133: if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) || ! 134: !(bh = bread((*dir)->i_dev,block))) { 1.1 root 135: i += DIR_ENTRIES_PER_BLOCK; 136: continue; 137: } 138: de = (struct dir_entry *) bh->b_data; 139: } 140: if (match(namelen,name,de)) { 141: *res_dir = de; 142: return bh; 143: } 144: de++; 145: i++; 146: } 147: brelse(bh); 148: return NULL; 149: } 150: 151: /* 152: * add_entry() 153: * 154: * adds a file entry to the specified directory, using the same 155: * semantics as find_entry(). It returns NULL if it failed. 156: * 157: * NOTE!! The inode part of 'de' is left at 0 - which means you 158: * may not sleep between calling this and putting something into 159: * the entry, as someone else might have used it while you slept. 160: */ 161: static struct buffer_head * add_entry(struct m_inode * dir, 162: const char * name, int namelen, struct dir_entry ** res_dir) 163: { 164: int block,i; 165: struct buffer_head * bh; 166: struct dir_entry * de; 167: 168: *res_dir = NULL; 169: #ifdef NO_TRUNCATE 170: if (namelen > NAME_LEN) 171: return NULL; 172: #else 173: if (namelen > NAME_LEN) 174: namelen = NAME_LEN; 175: #endif 176: if (!namelen) 177: return NULL; 178: if (!(block = dir->i_zone[0])) 179: return NULL; 180: if (!(bh = bread(dir->i_dev,block))) 181: return NULL; 182: i = 0; 183: de = (struct dir_entry *) bh->b_data; 184: while (1) { 185: if ((char *)de >= BLOCK_SIZE+bh->b_data) { 186: brelse(bh); 187: bh = NULL; 188: block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK); 189: if (!block) 190: return NULL; 191: if (!(bh = bread(dir->i_dev,block))) { 192: i += DIR_ENTRIES_PER_BLOCK; 193: continue; 194: } 195: de = (struct dir_entry *) bh->b_data; 196: } 197: if (i*sizeof(struct dir_entry) >= dir->i_size) { 198: de->inode=0; 199: dir->i_size = (i+1)*sizeof(struct dir_entry); 200: dir->i_dirt = 1; 201: dir->i_ctime = CURRENT_TIME; 202: } 203: if (!de->inode) { 204: dir->i_mtime = CURRENT_TIME; 205: for (i=0; i < NAME_LEN ; i++) 206: de->name[i]=(i<namelen)?get_fs_byte(name+i):0; 207: bh->b_dirt = 1; 208: *res_dir = de; 209: return bh; 210: } 211: de++; 212: i++; 213: } 214: brelse(bh); 215: return NULL; 216: } 217: 218: /* 219: * get_dir() 220: * 221: * Getdir traverses the pathname until it hits the topmost directory. 222: * It returns NULL on failure. 223: */ 224: static struct m_inode * get_dir(const char * pathname) 225: { 226: char c; 227: const char * thisname; 228: struct m_inode * inode; 229: struct buffer_head * bh; 230: int namelen,inr,idev; 231: struct dir_entry * de; 232: 233: if (!current->root || !current->root->i_count) 234: panic("No root inode"); 235: if (!current->pwd || !current->pwd->i_count) 236: panic("No cwd inode"); 237: if ((c=get_fs_byte(pathname))=='/') { 238: inode = current->root; 239: pathname++; 240: } else if (c) 241: inode = current->pwd; 242: else 243: return NULL; /* empty name is bad */ 244: inode->i_count++; 245: while (1) { 246: thisname = pathname; 247: if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) { 248: iput(inode); 249: return NULL; 250: } 251: for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++) 252: /* nothing */ ; 253: if (!c) 254: return inode; 1.1.1.2 ! root 255: if (!(bh = find_entry(&inode,thisname,namelen,&de))) { 1.1 root 256: iput(inode); 257: return NULL; 258: } 259: inr = de->inode; 260: idev = inode->i_dev; 261: brelse(bh); 262: iput(inode); 263: if (!(inode = iget(idev,inr))) 264: return NULL; 265: } 266: } 267: 268: /* 269: * dir_namei() 270: * 271: * dir_namei() returns the inode of the directory of the 272: * specified name, and the name within that directory. 273: */ 274: static struct m_inode * dir_namei(const char * pathname, 275: int * namelen, const char ** name) 276: { 277: char c; 278: const char * basename; 279: struct m_inode * dir; 280: 281: if (!(dir = get_dir(pathname))) 282: return NULL; 283: basename = pathname; 284: while (c=get_fs_byte(pathname++)) 285: if (c=='/') 286: basename=pathname; 287: *namelen = pathname-basename-1; 288: *name = basename; 289: return dir; 290: } 291: 292: /* 293: * namei() 294: * 295: * is used by most simple commands to get the inode of a specified name. 296: * Open, link etc use their own routines, but this is enough for things 297: * like 'chmod' etc. 298: */ 299: struct m_inode * namei(const char * pathname) 300: { 301: const char * basename; 302: int inr,dev,namelen; 303: struct m_inode * dir; 304: struct buffer_head * bh; 305: struct dir_entry * de; 306: 307: if (!(dir = dir_namei(pathname,&namelen,&basename))) 308: return NULL; 309: if (!namelen) /* special case: '/usr/' etc */ 310: return dir; 1.1.1.2 ! root 311: bh = find_entry(&dir,basename,namelen,&de); 1.1 root 312: if (!bh) { 313: iput(dir); 314: return NULL; 315: } 316: inr = de->inode; 317: dev = dir->i_dev; 318: brelse(bh); 319: iput(dir); 320: dir=iget(dev,inr); 321: if (dir) { 322: dir->i_atime=CURRENT_TIME; 323: dir->i_dirt=1; 324: } 325: return dir; 326: } 327: 328: /* 329: * open_namei() 330: * 331: * namei for open - this is in fact almost the whole open-routine. 332: */ 333: int open_namei(const char * pathname, int flag, int mode, 334: struct m_inode ** res_inode) 335: { 336: const char * basename; 337: int inr,dev,namelen; 338: struct m_inode * dir, *inode; 339: struct buffer_head * bh; 340: struct dir_entry * de; 341: 342: if ((flag & O_TRUNC) && !(flag & O_ACCMODE)) 343: flag |= O_WRONLY; 344: mode &= 0777 & ~current->umask; 345: mode |= I_REGULAR; 346: if (!(dir = dir_namei(pathname,&namelen,&basename))) 347: return -ENOENT; 348: if (!namelen) { /* special case: '/usr/' etc */ 349: if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) { 350: *res_inode=dir; 351: return 0; 352: } 353: iput(dir); 354: return -EISDIR; 355: } 1.1.1.2 ! root 356: bh = find_entry(&dir,basename,namelen,&de); 1.1 root 357: if (!bh) { 358: if (!(flag & O_CREAT)) { 359: iput(dir); 360: return -ENOENT; 361: } 362: if (!permission(dir,MAY_WRITE)) { 363: iput(dir); 364: return -EACCES; 365: } 366: inode = new_inode(dir->i_dev); 367: if (!inode) { 368: iput(dir); 369: return -ENOSPC; 370: } 1.1.1.2 ! root 371: inode->i_uid = current->euid; 1.1 root 372: inode->i_mode = mode; 373: inode->i_dirt = 1; 374: bh = add_entry(dir,basename,namelen,&de); 375: if (!bh) { 376: inode->i_nlinks--; 377: iput(inode); 378: iput(dir); 379: return -ENOSPC; 380: } 381: de->inode = inode->i_num; 382: bh->b_dirt = 1; 383: brelse(bh); 384: iput(dir); 385: *res_inode = inode; 386: return 0; 387: } 388: inr = de->inode; 389: dev = dir->i_dev; 390: brelse(bh); 391: iput(dir); 392: if (flag & O_EXCL) 393: return -EEXIST; 394: if (!(inode=iget(dev,inr))) 395: return -EACCES; 396: if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) || 1.1.1.2 ! root 397: !permission(inode,ACC_MODE(flag))) { 1.1 root 398: iput(inode); 399: return -EPERM; 400: } 401: inode->i_atime = CURRENT_TIME; 402: if (flag & O_TRUNC) 403: truncate(inode); 404: *res_inode = inode; 405: return 0; 406: } 407: 1.1.1.2 ! root 408: int sys_mknod(const char * filename, int mode, int dev) ! 409: { ! 410: const char * basename; ! 411: int namelen; ! 412: struct m_inode * dir, * inode; ! 413: struct buffer_head * bh; ! 414: struct dir_entry * de; ! 415: ! 416: if (!suser()) ! 417: return -EPERM; ! 418: if (!(dir = dir_namei(filename,&namelen,&basename))) ! 419: return -ENOENT; ! 420: if (!namelen) { ! 421: iput(dir); ! 422: return -ENOENT; ! 423: } ! 424: if (!permission(dir,MAY_WRITE)) { ! 425: iput(dir); ! 426: return -EPERM; ! 427: } ! 428: bh = find_entry(&dir,basename,namelen,&de); ! 429: if (bh) { ! 430: brelse(bh); ! 431: iput(dir); ! 432: return -EEXIST; ! 433: } ! 434: inode = new_inode(dir->i_dev); ! 435: if (!inode) { ! 436: iput(dir); ! 437: return -ENOSPC; ! 438: } ! 439: inode->i_mode = mode; ! 440: if (S_ISBLK(mode) || S_ISCHR(mode)) ! 441: inode->i_zone[0] = dev; ! 442: inode->i_mtime = inode->i_atime = CURRENT_TIME; ! 443: inode->i_dirt = 1; ! 444: bh = add_entry(dir,basename,namelen,&de); ! 445: if (!bh) { ! 446: iput(dir); ! 447: inode->i_nlinks=0; ! 448: iput(inode); ! 449: return -ENOSPC; ! 450: } ! 451: de->inode = inode->i_num; ! 452: bh->b_dirt = 1; ! 453: iput(dir); ! 454: iput(inode); ! 455: brelse(bh); ! 456: return 0; ! 457: } ! 458: 1.1 root 459: int sys_mkdir(const char * pathname, int mode) 460: { 461: const char * basename; 462: int namelen; 463: struct m_inode * dir, * inode; 464: struct buffer_head * bh, *dir_block; 465: struct dir_entry * de; 466: 1.1.1.2 ! root 467: if (!suser()) 1.1 root 468: return -EPERM; 469: if (!(dir = dir_namei(pathname,&namelen,&basename))) 470: return -ENOENT; 471: if (!namelen) { 472: iput(dir); 473: return -ENOENT; 474: } 475: if (!permission(dir,MAY_WRITE)) { 476: iput(dir); 477: return -EPERM; 478: } 1.1.1.2 ! root 479: bh = find_entry(&dir,basename,namelen,&de); 1.1 root 480: if (bh) { 481: brelse(bh); 482: iput(dir); 483: return -EEXIST; 484: } 485: inode = new_inode(dir->i_dev); 486: if (!inode) { 487: iput(dir); 488: return -ENOSPC; 489: } 490: inode->i_size = 32; 491: inode->i_dirt = 1; 492: inode->i_mtime = inode->i_atime = CURRENT_TIME; 493: if (!(inode->i_zone[0]=new_block(inode->i_dev))) { 494: iput(dir); 495: inode->i_nlinks--; 496: iput(inode); 497: return -ENOSPC; 498: } 499: inode->i_dirt = 1; 500: if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) { 501: iput(dir); 502: free_block(inode->i_dev,inode->i_zone[0]); 503: inode->i_nlinks--; 504: iput(inode); 505: return -ERROR; 506: } 507: de = (struct dir_entry *) dir_block->b_data; 508: de->inode=inode->i_num; 509: strcpy(de->name,"."); 510: de++; 511: de->inode = dir->i_num; 512: strcpy(de->name,".."); 513: inode->i_nlinks = 2; 514: dir_block->b_dirt = 1; 515: brelse(dir_block); 516: inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask); 517: inode->i_dirt = 1; 518: bh = add_entry(dir,basename,namelen,&de); 519: if (!bh) { 520: iput(dir); 521: free_block(inode->i_dev,inode->i_zone[0]); 522: inode->i_nlinks=0; 523: iput(inode); 524: return -ENOSPC; 525: } 526: de->inode = inode->i_num; 527: bh->b_dirt = 1; 528: dir->i_nlinks++; 529: dir->i_dirt = 1; 530: iput(dir); 531: iput(inode); 532: brelse(bh); 533: return 0; 534: } 535: 536: /* 537: * routine to check that the specified directory is empty (for rmdir) 538: */ 539: static int empty_dir(struct m_inode * inode) 540: { 541: int nr,block; 542: int len; 543: struct buffer_head * bh; 544: struct dir_entry * de; 545: 546: len = inode->i_size / sizeof (struct dir_entry); 547: if (len<2 || !inode->i_zone[0] || 548: !(bh=bread(inode->i_dev,inode->i_zone[0]))) { 549: printk("warning - bad directory on dev %04x\n",inode->i_dev); 550: return 0; 551: } 552: de = (struct dir_entry *) bh->b_data; 553: if (de[0].inode != inode->i_num || !de[1].inode || 554: strcmp(".",de[0].name) || strcmp("..",de[1].name)) { 555: printk("warning - bad directory on dev %04x\n",inode->i_dev); 556: return 0; 557: } 558: nr = 2; 559: de += 2; 560: while (nr<len) { 561: if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) { 562: brelse(bh); 563: block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK); 564: if (!block) { 565: nr += DIR_ENTRIES_PER_BLOCK; 566: continue; 567: } 568: if (!(bh=bread(inode->i_dev,block))) 569: return 0; 570: de = (struct dir_entry *) bh->b_data; 571: } 572: if (de->inode) { 573: brelse(bh); 574: return 0; 575: } 576: de++; 577: nr++; 578: } 579: brelse(bh); 580: return 1; 581: } 582: 583: int sys_rmdir(const char * name) 584: { 585: const char * basename; 586: int namelen; 587: struct m_inode * dir, * inode; 588: struct buffer_head * bh; 589: struct dir_entry * de; 590: 1.1.1.2 ! root 591: if (!suser()) 1.1 root 592: return -EPERM; 593: if (!(dir = dir_namei(name,&namelen,&basename))) 594: return -ENOENT; 595: if (!namelen) { 596: iput(dir); 597: return -ENOENT; 598: } 1.1.1.2 ! root 599: bh = find_entry(&dir,basename,namelen,&de); 1.1 root 600: if (!bh) { 601: iput(dir); 602: return -ENOENT; 603: } 604: if (!permission(dir,MAY_WRITE)) { 605: iput(dir); 606: brelse(bh); 607: return -EPERM; 608: } 609: if (!(inode = iget(dir->i_dev, de->inode))) { 610: iput(dir); 611: brelse(bh); 612: return -EPERM; 613: } 614: if (inode == dir) { /* we may not delete ".", but "../dir" is ok */ 615: iput(inode); 616: iput(dir); 617: brelse(bh); 618: return -EPERM; 619: } 620: if (!S_ISDIR(inode->i_mode)) { 621: iput(inode); 622: iput(dir); 623: brelse(bh); 624: return -ENOTDIR; 625: } 626: if (!empty_dir(inode)) { 627: iput(inode); 628: iput(dir); 629: brelse(bh); 630: return -ENOTEMPTY; 631: } 632: if (inode->i_nlinks != 2) 633: printk("empty directory has nlink!=2 (%d)",inode->i_nlinks); 634: de->inode = 0; 635: bh->b_dirt = 1; 636: brelse(bh); 637: inode->i_nlinks=0; 638: inode->i_dirt=1; 639: dir->i_nlinks--; 640: dir->i_ctime = dir->i_mtime = CURRENT_TIME; 641: dir->i_dirt=1; 642: iput(dir); 643: iput(inode); 644: return 0; 645: } 646: 647: int sys_unlink(const char * name) 648: { 649: const char * basename; 650: int namelen; 651: struct m_inode * dir, * inode; 652: struct buffer_head * bh; 653: struct dir_entry * de; 654: 655: if (!(dir = dir_namei(name,&namelen,&basename))) 656: return -ENOENT; 657: if (!namelen) { 658: iput(dir); 659: return -ENOENT; 660: } 661: if (!permission(dir,MAY_WRITE)) { 662: iput(dir); 663: return -EPERM; 664: } 1.1.1.2 ! root 665: bh = find_entry(&dir,basename,namelen,&de); 1.1 root 666: if (!bh) { 667: iput(dir); 668: return -ENOENT; 669: } 670: inode = iget(dir->i_dev, de->inode); 671: if (!inode) { 672: printk("iget failed in delete (%04x:%d)",dir->i_dev,de->inode); 673: iput(dir); 674: brelse(bh); 675: return -ENOENT; 676: } 1.1.1.2 ! root 677: if (S_ISDIR(inode->i_mode)) { 1.1 root 678: iput(inode); 679: iput(dir); 680: brelse(bh); 681: return -EPERM; 682: } 1.1.1.2 ! root 683: /* ! 684: * If the directory has the sticky bit, the user must either ! 685: * own the file or own the directory or be the superuser to ! 686: * delete a file in that directory. This is typically used ! 687: * for /tmp and /usr/tmp. ! 688: */ ! 689: if ((dir->i_mode & S_ISVTX) && (current->euid != inode->i_uid) && ! 690: (current->euid != dir->i_uid) && !suser()) { ! 691: iput(inode); ! 692: iput(dir); ! 693: brelse(bh); ! 694: return -EPERM; ! 695: } 1.1 root 696: if (!inode->i_nlinks) { 697: printk("Deleting nonexistent file (%04x:%d), %d\n", 698: inode->i_dev,inode->i_num,inode->i_nlinks); 699: inode->i_nlinks=1; 700: } 701: de->inode = 0; 702: bh->b_dirt = 1; 703: brelse(bh); 704: inode->i_nlinks--; 705: inode->i_dirt = 1; 706: inode->i_ctime = CURRENT_TIME; 707: iput(inode); 708: iput(dir); 709: return 0; 710: } 711: 712: int sys_link(const char * oldname, const char * newname) 713: { 714: struct dir_entry * de; 715: struct m_inode * oldinode, * dir; 716: struct buffer_head * bh; 717: const char * basename; 718: int namelen; 719: 720: oldinode=namei(oldname); 721: if (!oldinode) 722: return -ENOENT; 1.1.1.2 ! root 723: if (S_ISDIR(oldinode->i_mode)) { 1.1 root 724: iput(oldinode); 725: return -EPERM; 726: } 727: dir = dir_namei(newname,&namelen,&basename); 728: if (!dir) { 729: iput(oldinode); 730: return -EACCES; 731: } 732: if (!namelen) { 733: iput(oldinode); 734: iput(dir); 735: return -EPERM; 736: } 737: if (dir->i_dev != oldinode->i_dev) { 738: iput(dir); 739: iput(oldinode); 740: return -EXDEV; 741: } 742: if (!permission(dir,MAY_WRITE)) { 743: iput(dir); 744: iput(oldinode); 745: return -EACCES; 746: } 1.1.1.2 ! root 747: bh = find_entry(&dir,basename,namelen,&de); 1.1 root 748: if (bh) { 749: brelse(bh); 750: iput(dir); 751: iput(oldinode); 752: return -EEXIST; 753: } 754: bh = add_entry(dir,basename,namelen,&de); 755: if (!bh) { 756: iput(dir); 757: iput(oldinode); 758: return -ENOSPC; 759: } 760: de->inode = oldinode->i_num; 761: bh->b_dirt = 1; 762: brelse(bh); 763: iput(dir); 764: oldinode->i_nlinks++; 765: oldinode->i_ctime = CURRENT_TIME; 766: oldinode->i_dirt = 1; 767: iput(oldinode); 768: return 0; 769: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.