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

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