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                 flag &= ~O_TRUNC;
 377         } else {
 378                 if (IS_RDONLY(inode) && (flag & 2)) {
 379                         iput(inode);
 380                         return -EROFS;
 381                 }
 382         }
 383         if ((inode->i_count > 1) && (flag & 2)) {
 384                 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
 385                         struct vm_area_struct * mpnt;
 386                         if (!*p)
 387                                 continue;
 388                         for(mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
 389                                 if (inode != mpnt->vm_inode)
 390                                         continue;
 391                                 if (mpnt->vm_page_prot & PAGE_RW)
 392                                         continue;
 393                                 if (mpnt->vm_flags & VM_DENYWRITE) {
 394                                         iput(inode);
 395                                         return -ETXTBSY;
 396                                 }
 397                         }
 398                 }
 399         }
 400         /*
 401          * An append-only file must be opened in append mode for writing
 402          */
 403         if (IS_APPEND(inode) && ((flag & 2) && !(flag & O_APPEND))) {
 404                 iput(inode);
 405                 return -EPERM;
 406         }
 407         if (flag & O_TRUNC) {
 408                 struct iattr newattrs;
 409 
 410                 newattrs.ia_size = 0;
 411                 newattrs.ia_valid = ATTR_SIZE;
 412                 if ((error = notify_change(inode, &newattrs))) {
 413                         iput(inode);
 414                         return error;
 415                 }
 416                 inode->i_size = 0;
 417                 if (inode->i_op && inode->i_op->truncate)
 418                         inode->i_op->truncate(inode);
 419                 inode->i_dirt = 1;
 420         }
 421         *res_inode = inode;
 422         return 0;
 423 }
 424 
 425 int do_mknod(const char * filename, int mode, dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 426 {
 427         const char * basename;
 428         int namelen, error;
 429         struct inode * dir;
 430 
 431         mode &= ~current->fs->umask;
 432         error = dir_namei(filename,&namelen,&basename, NULL, &dir);
 433         if (error)
 434                 return error;
 435         if (!namelen) {
 436                 iput(dir);
 437                 return -ENOENT;
 438         }
 439         if (IS_RDONLY(dir)) {
 440                 iput(dir);
 441                 return -EROFS;
 442         }
 443         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 444                 iput(dir);
 445                 return -EACCES;
 446         }
 447         if (!dir->i_op || !dir->i_op->mknod) {
 448                 iput(dir);
 449                 return -EPERM;
 450         }
 451         dir->i_count++;
 452         down(&dir->i_sem);
 453         error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
 454         up(&dir->i_sem);
 455         iput(dir);
 456         return error;
 457 }
 458 
 459 asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 460 {
 461         int error;
 462         char * tmp;
 463 
 464         if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !fsuser()))
 465                 return -EPERM;
 466         switch (mode & S_IFMT) {
 467         case 0:
 468                 mode |= S_IFREG;
 469                 break;
 470         case S_IFREG: case S_IFCHR: case S_IFBLK: case S_IFIFO:
 471                 break;
 472         default:
 473                 return -EINVAL;
 474         }
 475         error = getname(filename,&tmp);
 476         if (!error) {
 477                 error = do_mknod(tmp,mode,dev);
 478                 putname(tmp);
 479         }
 480         return error;
 481 }
 482 
 483 static int do_mkdir(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 484 {
 485         const char * basename;
 486         int namelen, error;
 487         struct inode * dir;
 488 
 489         error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
 490         if (error)
 491                 return error;
 492         if (!namelen) {
 493                 iput(dir);
 494                 return -ENOENT;
 495         }
 496         if (IS_RDONLY(dir)) {
 497                 iput(dir);
 498                 return -EROFS;
 499         }
 500         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 501                 iput(dir);
 502                 return -EACCES;
 503         }
 504         if (!dir->i_op || !dir->i_op->mkdir) {
 505                 iput(dir);
 506                 return -EPERM;
 507         }
 508         dir->i_count++;
 509         down(&dir->i_sem);
 510         error = dir->i_op->mkdir(dir,basename,namelen,mode);
 511         up(&dir->i_sem);
 512         iput(dir);
 513         return error;
 514 }
 515 
 516 asmlinkage int sys_mkdir(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 517 {
 518         int error;
 519         char * tmp;
 520 
 521         error = getname(pathname,&tmp);
 522         if (!error) {
 523                 error = do_mkdir(tmp,mode);
 524                 putname(tmp);
 525         }
 526         return error;
 527 }
 528 
 529 static int do_rmdir(const char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 530 {
 531         const char * basename;
 532         int namelen, error;
 533         struct inode * dir;
 534 
 535         error = dir_namei(name,&namelen,&basename,NULL,&dir);
 536         if (error)
 537                 return error;
 538         if (!namelen) {
 539                 iput(dir);
 540                 return -ENOENT;
 541         }
 542         if (IS_RDONLY(dir)) {
 543                 iput(dir);
 544                 return -EROFS;
 545         }
 546         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 547                 iput(dir);
 548                 return -EACCES;
 549         }
 550         /*
 551          * A subdirectory cannot be removed from an append-only directory
 552          */
 553         if (IS_APPEND(dir)) {
 554                 iput(dir);
 555                 return -EPERM;
 556         }
 557         if (!dir->i_op || !dir->i_op->rmdir) {
 558                 iput(dir);
 559                 return -EPERM;
 560         }
 561         return dir->i_op->rmdir(dir,basename,namelen);
 562 }
 563 
 564 asmlinkage int sys_rmdir(const char * pathname)
     /* [previous][next][first][last][top][bottom][index][help] */
 565 {
 566         int error;
 567         char * tmp;
 568 
 569         error = getname(pathname,&tmp);
 570         if (!error) {
 571                 error = do_rmdir(tmp);
 572                 putname(tmp);
 573         }
 574         return error;
 575 }
 576 
 577 static int do_unlink(const char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 578 {
 579         const char * basename;
 580         int namelen, error;
 581         struct inode * dir;
 582 
 583         error = dir_namei(name,&namelen,&basename,NULL,&dir);
 584         if (error)
 585                 return error;
 586         if (!namelen) {
 587                 iput(dir);
 588                 return -EPERM;
 589         }
 590         if (IS_RDONLY(dir)) {
 591                 iput(dir);
 592                 return -EROFS;
 593         }
 594         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 595                 iput(dir);
 596                 return -EACCES;
 597         }
 598         /*
 599          * A file cannot be removed from an append-only directory
 600          */
 601         if (IS_APPEND(dir)) {
 602                 iput(dir);
 603                 return -EPERM;
 604         }
 605         if (!dir->i_op || !dir->i_op->unlink) {
 606                 iput(dir);
 607                 return -EPERM;
 608         }
 609         return dir->i_op->unlink(dir,basename,namelen);
 610 }
 611 
 612 asmlinkage int sys_unlink(const char * pathname)
     /* [previous][next][first][last][top][bottom][index][help] */
 613 {
 614         int error;
 615         char * tmp;
 616 
 617         error = getname(pathname,&tmp);
 618         if (!error) {
 619                 error = do_unlink(tmp);
 620                 putname(tmp);
 621         }
 622         return error;
 623 }
 624 
 625 static int do_symlink(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 626 {
 627         struct inode * dir;
 628         const char * basename;
 629         int namelen, error;
 630 
 631         error = dir_namei(newname,&namelen,&basename,NULL,&dir);
 632         if (error)
 633                 return error;
 634         if (!namelen) {
 635                 iput(dir);
 636                 return -ENOENT;
 637         }
 638         if (IS_RDONLY(dir)) {
 639                 iput(dir);
 640                 return -EROFS;
 641         }
 642         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 643                 iput(dir);
 644                 return -EACCES;
 645         }
 646         if (!dir->i_op || !dir->i_op->symlink) {
 647                 iput(dir);
 648                 return -EPERM;
 649         }
 650         dir->i_count++;
 651         down(&dir->i_sem);
 652         error = dir->i_op->symlink(dir,basename,namelen,oldname);
 653         up(&dir->i_sem);
 654         iput(dir);
 655         return error;
 656 }
 657 
 658 asmlinkage int sys_symlink(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 659 {
 660         int error;
 661         char * from, * to;
 662 
 663         error = getname(oldname,&from);
 664         if (!error) {
 665                 error = getname(newname,&to);
 666                 if (!error) {
 667                         error = do_symlink(from,to);
 668                         putname(to);
 669                 }
 670                 putname(from);
 671         }
 672         return error;
 673 }
 674 
 675 static int do_link(struct inode * oldinode, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 676 {
 677         struct inode * dir;
 678         const char * basename;
 679         int namelen, error;
 680 
 681         error = dir_namei(newname,&namelen,&basename,NULL,&dir);
 682         if (error) {
 683                 iput(oldinode);
 684                 return error;
 685         }
 686         if (!namelen) {
 687                 iput(oldinode);
 688                 iput(dir);
 689                 return -EPERM;
 690         }
 691         if (IS_RDONLY(dir)) {
 692                 iput(oldinode);
 693                 iput(dir);
 694                 return -EROFS;
 695         }
 696         if (dir->i_dev != oldinode->i_dev) {
 697                 iput(dir);
 698                 iput(oldinode);
 699                 return -EXDEV;
 700         }
 701         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 702                 iput(dir);
 703                 iput(oldinode);
 704                 return -EACCES;
 705         }
 706         /*
 707          * A link to an append-only or immutable file cannot be created
 708          */
 709         if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) {
 710                 iput(dir);
 711                 iput(oldinode);
 712                 return -EPERM;
 713         }
 714         if (!dir->i_op || !dir->i_op->link) {
 715                 iput(dir);
 716                 iput(oldinode);
 717                 return -EPERM;
 718         }
 719         dir->i_count++;
 720         down(&dir->i_sem);
 721         error = dir->i_op->link(oldinode, dir, basename, namelen);
 722         up(&dir->i_sem);
 723         iput(dir);
 724         return error;
 725 }
 726 
 727 asmlinkage int sys_link(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 728 {
 729         int error;
 730         char * to;
 731         struct inode * oldinode;
 732 
 733         error = namei(oldname, &oldinode);
 734         if (error)
 735                 return error;
 736         error = getname(newname,&to);
 737         if (error) {
 738                 iput(oldinode);
 739                 return error;
 740         }
 741         error = do_link(oldinode,to);
 742         putname(to);
 743         return error;
 744 }
 745 
 746 static int do_rename(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 747 {
 748         struct inode * old_dir, * new_dir;
 749         const char * old_base, * new_base;
 750         int old_len, new_len, error;
 751 
 752         error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
 753         if (error)
 754                 return error;
 755         if (!permission(old_dir,MAY_WRITE | MAY_EXEC)) {
 756                 iput(old_dir);
 757                 return -EACCES;
 758         }
 759         if (!old_len || (old_base[0] == '.' &&
 760             (old_len == 1 || (old_base[1] == '.' &&
 761              old_len == 2)))) {
 762                 iput(old_dir);
 763                 return -EPERM;
 764         }
 765         error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
 766         if (error) {
 767                 iput(old_dir);
 768                 return error;
 769         }
 770         if (!permission(new_dir,MAY_WRITE | MAY_EXEC)) {
 771                 iput(old_dir);
 772                 iput(new_dir);
 773                 return -EACCES;
 774         }
 775         if (!new_len || (new_base[0] == '.' &&
 776             (new_len == 1 || (new_base[1] == '.' &&
 777              new_len == 2)))) {
 778                 iput(old_dir);
 779                 iput(new_dir);
 780                 return -EPERM;
 781         }
 782         if (new_dir->i_dev != old_dir->i_dev) {
 783                 iput(old_dir);
 784                 iput(new_dir);
 785                 return -EXDEV;
 786         }
 787         if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
 788                 iput(old_dir);
 789                 iput(new_dir);
 790                 return -EROFS;
 791         }
 792         /*
 793          * A file cannot be removed from an append-only directory
 794          */
 795         if (IS_APPEND(old_dir)) {
 796                 iput(old_dir);
 797                 iput(new_dir);
 798                 return -EPERM;
 799         }
 800         if (!old_dir->i_op || !old_dir->i_op->rename) {
 801                 iput(old_dir);
 802                 iput(new_dir);
 803                 return -EPERM;
 804         }
 805         new_dir->i_count++;
 806         down(&new_dir->i_sem);
 807         error = old_dir->i_op->rename(old_dir, old_base, old_len, 
 808                 new_dir, new_base, new_len);
 809         up(&new_dir->i_sem);
 810         iput(new_dir);
 811         return error;
 812 }
 813 
 814 asmlinkage int sys_rename(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 815 {
 816         int error;
 817         char * from, * to;
 818 
 819         error = getname(oldname,&from);
 820         if (!error) {
 821                 error = getname(newname,&to);
 822                 if (!error) {
 823                         error = do_rename(from,to);
 824                         putname(to);
 825                 }
 826                 putname(from);
 827         }
 828         return error;
 829 }

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