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

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