root/fs/namei.c

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

DEFINITIONS

This source file includes following definitions.
  1. permission
  2. lookup
  3. follow_link
  4. dir_namei
  5. _namei
  6. lnamei
  7. namei
  8. open_namei
  9. do_mknod
  10. sys_mknod
  11. sys_mkdir
  12. sys_rmdir
  13. sys_unlink
  14. sys_symlink
  15. sys_link
  16. 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  *      permission()
  30  *
  31  * is used to check for read/write/execute permissions on a file.
  32  * I don't know if we should look at just the euid or both euid and
  33  * uid, but that should be easily changed.
  34  */
  35 int permission(struct inode * inode,int mask)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37         int mode = inode->i_mode;
  38 
  39 /* special case: not even root can read/write a deleted file */
  40         if (inode->i_dev && !inode->i_nlink)
  41                 return 0;
  42         else if (current->euid == inode->i_uid)
  43                 mode >>= 6;
  44         else if (in_group_p(inode->i_gid))
  45                 mode >>= 3;
  46         if (((mode & mask & 0007) == mask) || suser())
  47                 return 1;
  48         return 0;
  49 }
  50 
  51 /*
  52  * lookup() looks up one part of a pathname, using the fs-dependent
  53  * routines (currently minix_lookup) for it. It also checks for
  54  * fathers (pseudo-roots, mount-points)
  55  */
  56 int lookup(struct inode * dir,const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
  57         struct inode ** result)
  58 {
  59         struct super_block * sb;
  60 
  61         *result = NULL;
  62         if (len==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
  63                 if (dir == current->root)
  64                         len = 1;
  65                 else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
  66                         sb = dir->i_sb;
  67                         iput(dir);
  68                         dir = sb->s_covered;
  69                         if (dir)
  70                                 dir->i_count++;
  71                 }
  72         }
  73         if (!dir)
  74                 return -ENOENT;
  75         if (!dir->i_op || !dir->i_op->lookup) {
  76                 iput(dir);
  77                 return -ENOTDIR;
  78         }
  79         if (!permission(dir,MAY_EXEC)) {
  80                 iput(dir);
  81                 return -EACCES;
  82         }
  83         if (!len) {
  84                 *result = dir;
  85                 return 0;
  86         }
  87         return dir->i_op->lookup(dir,name,len,result);
  88 }
  89 
  90 int follow_link(struct inode * dir, struct inode * inode,
     /* [previous][next][first][last][top][bottom][index][help] */
  91         int flag, int mode, struct inode ** res_inode)
  92 {
  93         if (!dir || !inode) {
  94                 iput(dir);
  95                 iput(inode);
  96                 *res_inode = NULL;
  97                 return -ENOENT;
  98         }
  99         if (!inode->i_op || !inode->i_op->follow_link) {
 100                 iput(dir);
 101                 *res_inode = inode;
 102                 return 0;
 103         }
 104         return inode->i_op->follow_link(dir,inode,flag,mode,res_inode);
 105 }
 106 
 107 /*
 108  *      dir_namei()
 109  *
 110  * dir_namei() returns the inode of the directory of the
 111  * specified name, and the name within that directory.
 112  */
 113 static int dir_namei(const char * pathname, int * namelen, const char ** name,
     /* [previous][next][first][last][top][bottom][index][help] */
 114         struct inode * base, struct inode ** res_inode)
 115 {
 116         char c;
 117         const char * thisname;
 118         int len,error;
 119         struct inode * inode;
 120 
 121         *res_inode = NULL;
 122         if (!base) {
 123                 base = current->pwd;
 124                 base->i_count++;
 125         }
 126         if ((c=get_fs_byte(pathname))=='/') {
 127                 iput(base);
 128                 base = current->root;
 129                 pathname++;
 130                 base->i_count++;
 131         }
 132         while (1) {
 133                 thisname = pathname;
 134                 for(len=0;(c=get_fs_byte(pathname++))&&(c!='/');len++)
 135                         /* nothing */ ;
 136                 if (!c)
 137                         break;
 138                 base->i_count++;
 139                 error = lookup(base,thisname,len,&inode);
 140                 if (error) {
 141                         iput(base);
 142                         return error;
 143                 }
 144                 error = follow_link(base,inode,0,0,&base);
 145                 if (error)
 146                         return error;
 147         }
 148         if (!base->i_op || !base->i_op->lookup) {
 149                 iput(base);
 150                 return -ENOTDIR;
 151         }
 152         *name = thisname;
 153         *namelen = len;
 154         *res_inode = base;
 155         return 0;
 156 }
 157 
 158 static int _namei(const char * pathname, struct inode * base,
     /* [previous][next][first][last][top][bottom][index][help] */
 159         int follow_links, struct inode ** res_inode)
 160 {
 161         const char * basename;
 162         int namelen,error;
 163         struct inode * inode;
 164 
 165         *res_inode = NULL;
 166         error = dir_namei(pathname,&namelen,&basename,base,&base);
 167         if (error)
 168                 return error;
 169         base->i_count++;        /* lookup uses up base */
 170         error = lookup(base,basename,namelen,&inode);
 171         if (error) {
 172                 iput(base);
 173                 return error;
 174         }
 175         if (follow_links) {
 176                 error = follow_link(base,inode,0,0,&inode);
 177                 if (error)
 178                         return error;
 179         } else
 180                 iput(base);
 181         *res_inode = inode;
 182         return 0;
 183 }
 184 
 185 int lnamei(const char * pathname, struct inode ** res_inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 186 {
 187         return _namei(pathname,NULL,0,res_inode);
 188 }
 189 
 190 /*
 191  *      namei()
 192  *
 193  * is used by most simple commands to get the inode of a specified name.
 194  * Open, link etc use their own routines, but this is enough for things
 195  * like 'chmod' etc.
 196  */
 197 int namei(const char * pathname, struct inode ** res_inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 198 {
 199         return _namei(pathname,NULL,1,res_inode);
 200 }
 201 
 202 /*
 203  *      open_namei()
 204  *
 205  * namei for open - this is in fact almost the whole open-routine.
 206  *
 207  * Note that the low bits of "flag" aren't the same asin the open
 208  * system call - they are 00 - no permissions needed
 209  *                        01 - read permission needed
 210  *                        10 - write permission needed
 211  *                        11 - read/write permissions needed
 212  * which is a lot more logical, and also allows the "no perm" needed
 213  * for symlinks (where the permissions are checked later).
 214  */
 215 int open_namei(const char * pathname, int flag, int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
 216         struct inode ** res_inode, struct inode * base)
 217 {
 218         const char * basename;
 219         int namelen,error,i;
 220         struct inode * dir, *inode;
 221         struct task_struct ** p;
 222 
 223         mode &= 07777 & ~current->umask;
 224         mode |= S_IFREG;
 225         error = dir_namei(pathname,&namelen,&basename,base,&dir);
 226         if (error)
 227                 return error;
 228         if (!namelen) {                 /* special case: '/usr/' etc */
 229                 if (flag & 2) {
 230                         iput(dir);
 231                         return -EISDIR;
 232                 }
 233                 /* thanks to Paul Pluzhnikov for noticing this was missing.. */
 234                 if (!permission(dir,ACC_MODE(flag))) {
 235                         iput(dir);
 236                         return -EACCES;
 237                 }
 238                 *res_inode=dir;
 239                 return 0;
 240         }
 241         dir->i_count++;         /* lookup eats the dir */
 242         error = lookup(dir,basename,namelen,&inode);
 243         if (error) {
 244                 if (!(flag & O_CREAT)) {
 245                         iput(dir);
 246                         return error;
 247                 }
 248                 if (!permission(dir,MAY_WRITE)) {
 249                         iput(dir);
 250                         return -EACCES;
 251                 }
 252                 if (!dir->i_op || !dir->i_op->create) {
 253                         iput(dir);
 254                         return -EACCES;
 255                 }
 256                 if (IS_RDONLY(dir)) {
 257                         iput(dir);
 258                         return -EROFS;
 259                 }
 260                 return dir->i_op->create(dir,basename,namelen,mode,res_inode);
 261         }
 262         if (flag & O_EXCL) {
 263                 iput(dir);
 264                 iput(inode);
 265                 return -EEXIST;
 266         }
 267         error = follow_link(dir,inode,flag,mode,&inode);
 268         if (error)
 269                 return error;
 270         if (S_ISDIR(inode->i_mode) && (flag & 2)) {
 271                 iput(inode);
 272                 return -EISDIR;
 273         }
 274         if (!permission(inode,ACC_MODE(flag))) {
 275                 iput(inode);
 276                 return -EACCES;
 277         }
 278         if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
 279                 if (IS_NODEV(inode)) {
 280                         iput(inode);
 281                         return -EACCES;
 282                 }
 283         } else {
 284                 if (IS_RDONLY(inode) && (flag & 2)) {
 285                         iput(inode);
 286                         return -EROFS;
 287                 }
 288         }
 289         if ((inode->i_count > 1) && (flag & 2))
 290                 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
 291                         if (!*p)
 292                                 continue;
 293                         if (inode == (*p)->executable) {
 294                                 iput(inode);
 295                                 return -ETXTBSY;
 296                         }
 297                         for (i=0; i < (*p)->numlibraries; i++)
 298                                 if (inode == (*p)->libraries[i].library) {
 299                                         iput(inode);
 300                                         return -ETXTBSY;
 301                                 }
 302                 }
 303         *res_inode = inode;
 304         return 0;
 305 }
 306 
 307 int do_mknod(const char * filename, int mode, dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 308 {
 309         const char * basename;
 310         int namelen, error;
 311         struct inode * dir;
 312 
 313         error = dir_namei(filename,&namelen,&basename, NULL, &dir);
 314         if (error)
 315                 return error;
 316         if (!namelen) {
 317                 iput(dir);
 318                 return -ENOENT;
 319         }
 320         if (IS_RDONLY(dir)) {
 321                 iput(dir);
 322                 return -EROFS;
 323         }
 324         if (!permission(dir,MAY_WRITE)) {
 325                 iput(dir);
 326                 return -EACCES;
 327         }
 328         if (!dir->i_op || !dir->i_op->mknod) {
 329                 iput(dir);
 330                 return -EPERM;
 331         }
 332         return dir->i_op->mknod(dir,basename,namelen,mode,dev);
 333 }
 334 
 335 int sys_mknod(const char * filename, int mode, dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 336 {
 337         if (S_ISFIFO(mode) || suser())
 338                 return do_mknod(filename,mode,dev);
 339         return -EPERM;
 340 }
 341 
 342 int sys_mkdir(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 343 {
 344         const char * basename;
 345         int namelen, error;
 346         struct inode * dir;
 347 
 348         error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
 349         if (error)
 350                 return error;
 351         if (!namelen) {
 352                 iput(dir);
 353                 return -ENOENT;
 354         }
 355         if (IS_RDONLY(dir)) {
 356                 iput(dir);
 357                 return -EROFS;
 358         }
 359         if (!permission(dir,MAY_WRITE)) {
 360                 iput(dir);
 361                 return -EACCES;
 362         }
 363         if (!dir->i_op || !dir->i_op->mkdir) {
 364                 iput(dir);
 365                 return -EPERM;
 366         }
 367         return dir->i_op->mkdir(dir,basename,namelen,mode);
 368 }
 369 
 370 int sys_rmdir(const char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 371 {
 372         const char * basename;
 373         int namelen, error;
 374         struct inode * dir;
 375 
 376         error = dir_namei(name,&namelen,&basename,NULL,&dir);
 377         if (error)
 378                 return error;
 379         if (!namelen) {
 380                 iput(dir);
 381                 return -ENOENT;
 382         }
 383         if (IS_RDONLY(dir)) {
 384                 iput(dir);
 385                 return -EROFS;
 386         }
 387         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 388                 iput(dir);
 389                 return -EACCES;
 390         }
 391         if (!dir->i_op || !dir->i_op->rmdir) {
 392                 iput(dir);
 393                 return -EPERM;
 394         }
 395         return dir->i_op->rmdir(dir,basename,namelen);
 396 }
 397 
 398 int sys_unlink(const char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 399 {
 400         const char * basename;
 401         int namelen, error;
 402         struct inode * dir;
 403 
 404         error = dir_namei(name,&namelen,&basename,NULL,&dir);
 405         if (error)
 406                 return error;
 407         if (!namelen) {
 408                 iput(dir);
 409                 return -EPERM;
 410         }
 411         if (IS_RDONLY(dir)) {
 412                 iput(dir);
 413                 return -EROFS;
 414         }
 415         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 416                 iput(dir);
 417                 return -EACCES;
 418         }
 419         if (!dir->i_op || !dir->i_op->unlink) {
 420                 iput(dir);
 421                 return -EPERM;
 422         }
 423         return dir->i_op->unlink(dir,basename,namelen);
 424 }
 425 
 426 int sys_symlink(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 427 {
 428         struct inode * dir;
 429         const char * basename;
 430         int namelen, error;
 431 
 432         error = dir_namei(newname,&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)) {
 444                 iput(dir);
 445                 return -EACCES;
 446         }
 447         if (!dir->i_op || !dir->i_op->symlink) {
 448                 iput(dir);
 449                 return -EPERM;
 450         }
 451         return dir->i_op->symlink(dir,basename,namelen,oldname);
 452 }
 453 
 454 int sys_link(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 455 {
 456         struct inode * oldinode, * dir;
 457         const char * basename;
 458         int namelen, error;
 459 
 460         error = namei(oldname, &oldinode);
 461         if (error)
 462                 return error;
 463         error = dir_namei(newname,&namelen,&basename,NULL,&dir);
 464         if (error) {
 465                 iput(oldinode);
 466                 return error;
 467         }
 468         if (!namelen) {
 469                 iput(oldinode);
 470                 iput(dir);
 471                 return -EPERM;
 472         }
 473         if (IS_RDONLY(dir)) {
 474                 iput(oldinode);
 475                 iput(dir);
 476                 return -EROFS;
 477         }
 478         if (dir->i_dev != oldinode->i_dev) {
 479                 iput(dir);
 480                 iput(oldinode);
 481                 return -EXDEV;
 482         }
 483         if (!permission(dir,MAY_WRITE)) {
 484                 iput(dir);
 485                 iput(oldinode);
 486                 return -EACCES;
 487         }
 488         if (!dir->i_op || !dir->i_op->link) {
 489                 iput(dir);
 490                 iput(oldinode);
 491                 return -EPERM;
 492         }
 493         return dir->i_op->link(oldinode, dir, basename, namelen);
 494 }
 495 
 496 int sys_rename(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 497 {
 498         struct inode * old_dir, * new_dir;
 499         const char * old_base, * new_base;
 500         int old_len, new_len, error;
 501 
 502         error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
 503         if (error)
 504                 return error;
 505         if (!permission(old_dir,MAY_WRITE)) {
 506                 iput(old_dir);
 507                 return -EACCES;
 508         }
 509         if (!old_len || (get_fs_byte(old_base) == '.' &&
 510             (old_len == 1 || (get_fs_byte(old_base+1) == '.' &&
 511              old_len == 2)))) {
 512                 iput(old_dir);
 513                 return -EPERM;
 514         }
 515         error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
 516         if (error) {
 517                 iput(old_dir);
 518                 return error;
 519         }
 520         if (!permission(new_dir,MAY_WRITE)) {
 521                 iput(old_dir);
 522                 iput(new_dir);
 523                 return -EACCES;
 524         }
 525         if (!new_len || (get_fs_byte(new_base) == '.' &&
 526             (new_len == 1 || (get_fs_byte(new_base+1) == '.' &&
 527              new_len == 2)))) {
 528                 iput(old_dir);
 529                 iput(new_dir);
 530                 return -EPERM;
 531         }
 532         if (new_dir->i_dev != old_dir->i_dev) {
 533                 iput(old_dir);
 534                 iput(new_dir);
 535                 return -EXDEV;
 536         }
 537         if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
 538                 iput(old_dir);
 539                 iput(new_dir);
 540                 return -EROFS;
 541         }
 542         if (!old_dir->i_op || !old_dir->i_op->rename) {
 543                 iput(old_dir);
 544                 iput(new_dir);
 545                 return -EPERM;
 546         }
 547         return old_dir->i_op->rename(old_dir, old_base, old_len, 
 548                 new_dir, new_base, new_len);
 549 }

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