root/fs/namei.c

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

DEFINITIONS

This source file includes following definitions.
  1. getname
  2. putname
  3. permission
  4. lookup
  5. follow_link
  6. dir_namei
  7. _namei
  8. lnamei
  9. namei
  10. open_namei
  11. do_mknod
  12. sys_mknod
  13. do_mkdir
  14. sys_mkdir
  15. do_rmdir
  16. sys_rmdir
  17. do_unlink
  18. sys_unlink
  19. do_symlink
  20. sys_symlink
  21. do_link
  22. sys_link
  23. do_rename
  24. sys_rename

   1 /*
   2  *  linux/fs/namei.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 /*
   8  * Some corrections by tytso.
   9  */
  10 
  11 #include <asm/segment.h>
  12 
  13 #include <linux/errno.h>
  14 #include <linux/sched.h>
  15 #include <linux/kernel.h>
  16 #include <linux/string.h>
  17 #include <linux/fcntl.h>
  18 #include <linux/stat.h>
  19 
  20 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
  21 
  22 /*
  23  * In order to reduce some races, while at the same time doing additional
  24  * checking and hopefully speeding things up, we copy filenames to the
  25  * kernel data space before using them..
  26  *
  27  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
  28  */
  29 int getname(const char * filename, char **result)
     /* [previous][next][first][last][top][bottom][index][help] */
  30 {
  31         int error;
  32         unsigned long i, page;
  33         char * tmp, c;
  34 
  35         i = (unsigned long) filename;
  36         if (!i || i >= TASK_SIZE)
  37                 return -EFAULT;
  38         i = TASK_SIZE - i;
  39         error = -EFAULT;
  40         if (i > PAGE_SIZE) {
  41                 i = PAGE_SIZE;
  42                 error = -ENAMETOOLONG;
  43         }
  44         c = get_fs_byte(filename++);
  45         if (!c)
  46                 return -ENOENT;
  47         if(!(page = __get_free_page(GFP_KERNEL)))
  48                 return -ENOMEM;
  49         *result = tmp = (char *) page;
  50         while (--i) {
  51                 *(tmp++) = c;
  52                 c = get_fs_byte(filename++);
  53                 if (!c) {
  54                         *tmp = '\0';
  55                         return 0;
  56                 }
  57         }
  58         free_page(page);
  59         return error;
  60 }
  61 
  62 void putname(char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64         free_page((unsigned long) name);
  65 }
  66 
  67 /*
  68  *      permission()
  69  *
  70  * is used to check for read/write/execute permissions on a file.
  71  * We use "fsuid" for this, letting us set arbitrary permissions
  72  * permissions for filesystem access without changing the "normal"
  73  * uids which are used for other things..
  74  */
  75 int permission(struct inode * inode,int mask)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77         int mode = inode->i_mode;
  78 
  79         if (inode->i_op && inode->i_op->permission)
  80                 return inode->i_op->permission(inode, mask);
  81         else if (current->fsuid == inode->i_uid)
  82                 mode >>= 6;
  83         else if (in_group_p(inode->i_gid))
  84                 mode >>= 3;
  85         if (((mode & mask & 0007) == mask) || fsuser())
  86                 return 1;
  87         return 0;
  88 }
  89 
  90 /*
  91  * lookup() looks up one part of a pathname, using the fs-dependent
  92  * routines (currently minix_lookup) for it. It also checks for
  93  * fathers (pseudo-roots, mount-points)
  94  */
  95 int lookup(struct inode * dir,const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
  96         struct inode ** result)
  97 {
  98         struct super_block * sb;
  99         int perm;
 100 
 101         *result = NULL;
 102         if (!dir)
 103                 return -ENOENT;
 104 /* check permissions before traversing mount-points */
 105         perm = permission(dir,MAY_EXEC);
 106         if (len==2 && name[0] == '.' && name[1] == '.') {
 107                 if (dir == current->fs->root) {
 108                         *result = dir;
 109                         return 0;
 110                 } else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
 111                         sb = dir->i_sb;
 112                         iput(dir);
 113                         dir = sb->s_covered;
 114                         if (!dir)
 115                                 return -ENOENT;
 116                         dir->i_count++;
 117                 }
 118         }
 119         if (!dir->i_op || !dir->i_op->lookup) {
 120                 iput(dir);
 121                 return -ENOTDIR;
 122         }
 123         if (!perm) {
 124                 iput(dir);
 125                 return -EACCES;
 126         }
 127         if (!len) {
 128                 *result = dir;
 129                 return 0;
 130         }
 131         return dir->i_op->lookup(dir,name,len,result);
 132 }
 133 
 134 int follow_link(struct inode * dir, struct inode * inode,
     /* [previous][next][first][last][top][bottom][index][help] */
 135         int flag, int mode, struct inode ** res_inode)
 136 {
 137         if (!dir || !inode) {
 138                 iput(dir);
 139                 iput(inode);
 140                 *res_inode = NULL;
 141                 return -ENOENT;
 142         }
 143         if (!inode->i_op || !inode->i_op->follow_link) {
 144                 iput(dir);
 145                 *res_inode = inode;
 146                 return 0;
 147         }
 148         return inode->i_op->follow_link(dir,inode,flag,mode,res_inode);
 149 }
 150 
 151 /*
 152  *      dir_namei()
 153  *
 154  * dir_namei() returns the inode of the directory of the
 155  * specified name, and the name within that directory.
 156  */
 157 static int dir_namei(const char * pathname, int * namelen, const char ** name,
     /* [previous][next][first][last][top][bottom][index][help] */
 158         struct inode * base, struct inode ** res_inode)
 159 {
 160         char c;
 161         const char * thisname;
 162         int len,error;
 163         struct inode * inode;
 164 
 165         *res_inode = NULL;
 166         if (!base) {
 167                 base = current->fs->pwd;
 168                 base->i_count++;
 169         }
 170         if ((c = *pathname) == '/') {
 171                 iput(base);
 172                 base = current->fs->root;
 173                 pathname++;
 174                 base->i_count++;
 175         }
 176         while (1) {
 177                 thisname = pathname;
 178                 for(len=0;(c = *(pathname++))&&(c != '/');len++)
 179                         /* nothing */ ;
 180                 if (!c)
 181                         break;
 182                 base->i_count++;
 183                 error = lookup(base,thisname,len,&inode);
 184                 if (error) {
 185                         iput(base);
 186                         return error;
 187                 }
 188                 error = follow_link(base,inode,0,0,&base);
 189                 if (error)
 190                         return error;
 191         }
 192         if (!base->i_op || !base->i_op->lookup) {
 193                 iput(base);
 194                 return -ENOTDIR;
 195         }
 196         *name = thisname;
 197         *namelen = len;
 198         *res_inode = base;
 199         return 0;
 200 }
 201 
 202 static int _namei(const char * pathname, struct inode * base,
     /* [previous][next][first][last][top][bottom][index][help] */
 203         int follow_links, struct inode ** res_inode)
 204 {
 205         const char * basename;
 206         int namelen,error;
 207         struct inode * inode;
 208 
 209         *res_inode = NULL;
 210         error = dir_namei(pathname,&namelen,&basename,base,&base);
 211         if (error)
 212                 return error;
 213         base->i_count++;        /* lookup uses up base */
 214         error = lookup(base,basename,namelen,&inode);
 215         if (error) {
 216                 iput(base);
 217                 return error;
 218         }
 219         if (follow_links) {
 220                 error = follow_link(base,inode,0,0,&inode);
 221                 if (error)
 222                         return error;
 223         } else
 224                 iput(base);
 225         *res_inode = inode;
 226         return 0;
 227 }
 228 
 229 int lnamei(const char * pathname, struct inode ** res_inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 230 {
 231         int error;
 232         char * tmp;
 233 
 234         error = getname(pathname,&tmp);
 235         if (!error) {
 236                 error = _namei(tmp,NULL,0,res_inode);
 237                 putname(tmp);
 238         }
 239         return error;
 240 }
 241 
 242 /*
 243  *      namei()
 244  *
 245  * is used by most simple commands to get the inode of a specified name.
 246  * Open, link etc use their own routines, but this is enough for things
 247  * like 'chmod' etc.
 248  */
 249 int namei(const char * pathname, struct inode ** res_inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 250 {
 251         int error;
 252         char * tmp;
 253 
 254         error = getname(pathname,&tmp);
 255         if (!error) {
 256                 error = _namei(tmp,NULL,1,res_inode);
 257                 putname(tmp);
 258         }
 259         return error;
 260 }
 261 
 262 /*
 263  *      open_namei()
 264  *
 265  * namei for open - this is in fact almost the whole open-routine.
 266  *
 267  * Note that the low bits of "flag" aren't the same as in the open
 268  * system call - they are 00 - no permissions needed
 269  *                        01 - read permission needed
 270  *                        10 - write permission needed
 271  *                        11 - read/write permissions needed
 272  * which is a lot more logical, and also allows the "no perm" needed
 273  * for symlinks (where the permissions are checked later).
 274  */
 275 int open_namei(const char * pathname, int flag, int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
 276         struct inode ** res_inode, struct inode * base)
 277 {
 278         const char * basename;
 279         int namelen,error;
 280         struct inode * dir, *inode;
 281         struct task_struct ** p;
 282 
 283         mode &= S_IALLUGO & ~current->fs->umask;
 284         mode |= S_IFREG;
 285         error = dir_namei(pathname,&namelen,&basename,base,&dir);
 286         if (error)
 287                 return error;
 288         if (!namelen) {                 /* special case: '/usr/' etc */
 289                 if (flag & 2) {
 290                         iput(dir);
 291                         return -EISDIR;
 292                 }
 293                 /* thanks to Paul Pluzhnikov for noticing this was missing.. */
 294                 if (!permission(dir,ACC_MODE(flag))) {
 295                         iput(dir);
 296                         return -EACCES;
 297                 }
 298                 *res_inode=dir;
 299                 return 0;
 300         }
 301         dir->i_count++;         /* lookup eats the dir */
 302         if (flag & O_CREAT) {
 303                 down(&dir->i_sem);
 304                 error = lookup(dir,basename,namelen,&inode);
 305                 if (!error) {
 306                         if (flag & O_EXCL) {
 307                                 iput(inode);
 308                                 error = -EEXIST;
 309                         }
 310                 } else if (!permission(dir,MAY_WRITE | MAY_EXEC))
 311                         error = -EACCES;
 312                 else if (!dir->i_op || !dir->i_op->create)
 313                         error = -EACCES;
 314                 else if (IS_RDONLY(dir))
 315                         error = -EROFS;
 316                 else {
 317                         dir->i_count++;         /* create eats the dir */
 318                         error = dir->i_op->create(dir,basename,namelen,mode,res_inode);
 319                         up(&dir->i_sem);
 320                         iput(dir);
 321                         return error;
 322                 }
 323                 up(&dir->i_sem);
 324         } else
 325                 error = lookup(dir,basename,namelen,&inode);
 326         if (error) {
 327                 iput(dir);
 328                 return error;
 329         }
 330         error = follow_link(dir,inode,flag,mode,&inode);
 331         if (error)
 332                 return error;
 333         if (S_ISDIR(inode->i_mode) && (flag & 2)) {
 334                 iput(inode);
 335                 return -EISDIR;
 336         }
 337         if (!permission(inode,ACC_MODE(flag))) {
 338                 iput(inode);
 339                 return -EACCES;
 340         }
 341         if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
 342                 if (IS_NODEV(inode)) {
 343                         iput(inode);
 344                         return -EACCES;
 345                 }
 346         } else {
 347                 if (IS_RDONLY(inode) && (flag & 2)) {
 348                         iput(inode);
 349                         return -EROFS;
 350                 }
 351         }
 352         if ((inode->i_count > 1) && (flag & 2)) {
 353                 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
 354                         struct vm_area_struct * mpnt;
 355                         if (!*p)
 356                                 continue;
 357                         for(mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
 358                                 if (inode != mpnt->vm_inode)
 359                                         continue;
 360                                 if (mpnt->vm_page_prot & PAGE_RW)
 361                                         continue;
 362                                 if (mpnt->vm_flags & VM_DENYWRITE) {
 363                                         iput(inode);
 364                                         return -ETXTBSY;
 365                                 }
 366                         }
 367                 }
 368         }
 369         if (flag & O_TRUNC) {
 370               inode->i_size = 0;
 371               if (inode->i_op && inode->i_op->truncate)
 372                    inode->i_op->truncate(inode);
 373               if ((error = notify_change(NOTIFY_SIZE, inode))) {
 374                    iput(inode);
 375                    return error;
 376               }
 377               inode->i_dirt = 1;
 378         }
 379         *res_inode = inode;
 380         return 0;
 381 }
 382 
 383 int do_mknod(const char * filename, int mode, dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 384 {
 385         const char * basename;
 386         int namelen, error;
 387         struct inode * dir;
 388 
 389         mode &= ~current->fs->umask;
 390         error = dir_namei(filename,&namelen,&basename, NULL, &dir);
 391         if (error)
 392                 return error;
 393         if (!namelen) {
 394                 iput(dir);
 395                 return -ENOENT;
 396         }
 397         if (IS_RDONLY(dir)) {
 398                 iput(dir);
 399                 return -EROFS;
 400         }
 401         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 402                 iput(dir);
 403                 return -EACCES;
 404         }
 405         if (!dir->i_op || !dir->i_op->mknod) {
 406                 iput(dir);
 407                 return -EPERM;
 408         }
 409         dir->i_count++;
 410         down(&dir->i_sem);
 411         error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
 412         up(&dir->i_sem);
 413         iput(dir);
 414         return error;
 415 }
 416 
 417 asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 418 {
 419         int error;
 420         char * tmp;
 421 
 422         if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !fsuser()))
 423                 return -EPERM;
 424         switch (mode & S_IFMT) {
 425         case 0:
 426                 mode |= S_IFREG;
 427                 break;
 428         case S_IFREG: case S_IFCHR: case S_IFBLK: case S_IFIFO:
 429                 break;
 430         default:
 431                 return -EINVAL;
 432         }
 433         error = getname(filename,&tmp);
 434         if (!error) {
 435                 error = do_mknod(tmp,mode,dev);
 436                 putname(tmp);
 437         }
 438         return error;
 439 }
 440 
 441 static int do_mkdir(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 442 {
 443         const char * basename;
 444         int namelen, error;
 445         struct inode * dir;
 446 
 447         error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
 448         if (error)
 449                 return error;
 450         if (!namelen) {
 451                 iput(dir);
 452                 return -ENOENT;
 453         }
 454         if (IS_RDONLY(dir)) {
 455                 iput(dir);
 456                 return -EROFS;
 457         }
 458         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 459                 iput(dir);
 460                 return -EACCES;
 461         }
 462         if (!dir->i_op || !dir->i_op->mkdir) {
 463                 iput(dir);
 464                 return -EPERM;
 465         }
 466         dir->i_count++;
 467         down(&dir->i_sem);
 468         error = dir->i_op->mkdir(dir,basename,namelen,mode);
 469         up(&dir->i_sem);
 470         iput(dir);
 471         return error;
 472 }
 473 
 474 asmlinkage int sys_mkdir(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 475 {
 476         int error;
 477         char * tmp;
 478 
 479         error = getname(pathname,&tmp);
 480         if (!error) {
 481                 error = do_mkdir(tmp,mode);
 482                 putname(tmp);
 483         }
 484         return error;
 485 }
 486 
 487 static int do_rmdir(const char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 488 {
 489         const char * basename;
 490         int namelen, error;
 491         struct inode * dir;
 492 
 493         error = dir_namei(name,&namelen,&basename,NULL,&dir);
 494         if (error)
 495                 return error;
 496         if (!namelen) {
 497                 iput(dir);
 498                 return -ENOENT;
 499         }
 500         if (IS_RDONLY(dir)) {
 501                 iput(dir);
 502                 return -EROFS;
 503         }
 504         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 505                 iput(dir);
 506                 return -EACCES;
 507         }
 508         if (!dir->i_op || !dir->i_op->rmdir) {
 509                 iput(dir);
 510                 return -EPERM;
 511         }
 512         return dir->i_op->rmdir(dir,basename,namelen);
 513 }
 514 
 515 asmlinkage int sys_rmdir(const char * pathname)
     /* [previous][next][first][last][top][bottom][index][help] */
 516 {
 517         int error;
 518         char * tmp;
 519 
 520         error = getname(pathname,&tmp);
 521         if (!error) {
 522                 error = do_rmdir(tmp);
 523                 putname(tmp);
 524         }
 525         return error;
 526 }
 527 
 528 static int do_unlink(const char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 529 {
 530         const char * basename;
 531         int namelen, error;
 532         struct inode * dir;
 533 
 534         error = dir_namei(name,&namelen,&basename,NULL,&dir);
 535         if (error)
 536                 return error;
 537         if (!namelen) {
 538                 iput(dir);
 539                 return -EPERM;
 540         }
 541         if (IS_RDONLY(dir)) {
 542                 iput(dir);
 543                 return -EROFS;
 544         }
 545         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 546                 iput(dir);
 547                 return -EACCES;
 548         }
 549         if (!dir->i_op || !dir->i_op->unlink) {
 550                 iput(dir);
 551                 return -EPERM;
 552         }
 553         return dir->i_op->unlink(dir,basename,namelen);
 554 }
 555 
 556 asmlinkage int sys_unlink(const char * pathname)
     /* [previous][next][first][last][top][bottom][index][help] */
 557 {
 558         int error;
 559         char * tmp;
 560 
 561         error = getname(pathname,&tmp);
 562         if (!error) {
 563                 error = do_unlink(tmp);
 564                 putname(tmp);
 565         }
 566         return error;
 567 }
 568 
 569 static int do_symlink(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 570 {
 571         struct inode * dir;
 572         const char * basename;
 573         int namelen, error;
 574 
 575         error = dir_namei(newname,&namelen,&basename,NULL,&dir);
 576         if (error)
 577                 return error;
 578         if (!namelen) {
 579                 iput(dir);
 580                 return -ENOENT;
 581         }
 582         if (IS_RDONLY(dir)) {
 583                 iput(dir);
 584                 return -EROFS;
 585         }
 586         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 587                 iput(dir);
 588                 return -EACCES;
 589         }
 590         if (!dir->i_op || !dir->i_op->symlink) {
 591                 iput(dir);
 592                 return -EPERM;
 593         }
 594         dir->i_count++;
 595         down(&dir->i_sem);
 596         error = dir->i_op->symlink(dir,basename,namelen,oldname);
 597         up(&dir->i_sem);
 598         iput(dir);
 599         return error;
 600 }
 601 
 602 asmlinkage int sys_symlink(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 603 {
 604         int error;
 605         char * from, * to;
 606 
 607         error = getname(oldname,&from);
 608         if (!error) {
 609                 error = getname(newname,&to);
 610                 if (!error) {
 611                         error = do_symlink(from,to);
 612                         putname(to);
 613                 }
 614                 putname(from);
 615         }
 616         return error;
 617 }
 618 
 619 static int do_link(struct inode * oldinode, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 620 {
 621         struct inode * dir;
 622         const char * basename;
 623         int namelen, error;
 624 
 625         error = dir_namei(newname,&namelen,&basename,NULL,&dir);
 626         if (error) {
 627                 iput(oldinode);
 628                 return error;
 629         }
 630         if (!namelen) {
 631                 iput(oldinode);
 632                 iput(dir);
 633                 return -EPERM;
 634         }
 635         if (IS_RDONLY(dir)) {
 636                 iput(oldinode);
 637                 iput(dir);
 638                 return -EROFS;
 639         }
 640         if (dir->i_dev != oldinode->i_dev) {
 641                 iput(dir);
 642                 iput(oldinode);
 643                 return -EXDEV;
 644         }
 645         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 646                 iput(dir);
 647                 iput(oldinode);
 648                 return -EACCES;
 649         }
 650         if (!dir->i_op || !dir->i_op->link) {
 651                 iput(dir);
 652                 iput(oldinode);
 653                 return -EPERM;
 654         }
 655         dir->i_count++;
 656         down(&dir->i_sem);
 657         error = dir->i_op->link(oldinode, dir, basename, namelen);
 658         up(&dir->i_sem);
 659         iput(dir);
 660         return error;
 661 }
 662 
 663 asmlinkage int sys_link(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 664 {
 665         int error;
 666         char * to;
 667         struct inode * oldinode;
 668 
 669         error = namei(oldname, &oldinode);
 670         if (error)
 671                 return error;
 672         error = getname(newname,&to);
 673         if (error) {
 674                 iput(oldinode);
 675                 return error;
 676         }
 677         error = do_link(oldinode,to);
 678         putname(to);
 679         return error;
 680 }
 681 
 682 static int do_rename(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 683 {
 684         struct inode * old_dir, * new_dir;
 685         const char * old_base, * new_base;
 686         int old_len, new_len, error;
 687 
 688         error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
 689         if (error)
 690                 return error;
 691         if (!permission(old_dir,MAY_WRITE | MAY_EXEC)) {
 692                 iput(old_dir);
 693                 return -EACCES;
 694         }
 695         if (!old_len || (old_base[0] == '.' &&
 696             (old_len == 1 || (old_base[1] == '.' &&
 697              old_len == 2)))) {
 698                 iput(old_dir);
 699                 return -EPERM;
 700         }
 701         error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
 702         if (error) {
 703                 iput(old_dir);
 704                 return error;
 705         }
 706         if (!permission(new_dir,MAY_WRITE | MAY_EXEC)) {
 707                 iput(old_dir);
 708                 iput(new_dir);
 709                 return -EACCES;
 710         }
 711         if (!new_len || (new_base[0] == '.' &&
 712             (new_len == 1 || (new_base[1] == '.' &&
 713              new_len == 2)))) {
 714                 iput(old_dir);
 715                 iput(new_dir);
 716                 return -EPERM;
 717         }
 718         if (new_dir->i_dev != old_dir->i_dev) {
 719                 iput(old_dir);
 720                 iput(new_dir);
 721                 return -EXDEV;
 722         }
 723         if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
 724                 iput(old_dir);
 725                 iput(new_dir);
 726                 return -EROFS;
 727         }
 728         if (!old_dir->i_op || !old_dir->i_op->rename) {
 729                 iput(old_dir);
 730                 iput(new_dir);
 731                 return -EPERM;
 732         }
 733         new_dir->i_count++;
 734         down(&new_dir->i_sem);
 735         error = old_dir->i_op->rename(old_dir, old_base, old_len, 
 736                 new_dir, new_base, new_len);
 737         up(&new_dir->i_sem);
 738         iput(new_dir);
 739         return error;
 740 }
 741 
 742 asmlinkage int sys_rename(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 743 {
 744         int error;
 745         char * from, * to;
 746 
 747         error = getname(oldname,&from);
 748         if (!error) {
 749                 error = getname(newname,&to);
 750                 if (!error) {
 751                         error = do_rename(from,to);
 752                         putname(to);
 753                 }
 754                 putname(from);
 755         }
 756         return error;
 757 }

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