root/fs/namei.c

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

DEFINITIONS

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

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