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                         *res_inode=dir;
 231                         return 0;
 232                 }
 233                 iput(dir);
 234                 return -EISDIR;
 235         }
 236         dir->i_count++;         /* lookup eats the dir */
 237         error = lookup(dir,basename,namelen,&inode);
 238         if (error) {
 239                 if (!(flag & O_CREAT)) {
 240                         iput(dir);
 241                         return error;
 242                 }
 243                 if (!permission(dir,MAY_WRITE)) {
 244                         iput(dir);
 245                         return -EACCES;
 246                 }
 247                 if (!dir->i_op || !dir->i_op->create) {
 248                         iput(dir);
 249                         return -EACCES;
 250                 }
 251                 if (IS_RDONLY(dir)) {
 252                         iput(dir);
 253                         return -EROFS;
 254                 }
 255                 return dir->i_op->create(dir,basename,namelen,mode,res_inode);
 256         }
 257         if (flag & O_EXCL) {
 258                 iput(dir);
 259                 iput(inode);
 260                 return -EEXIST;
 261         }
 262         error = follow_link(dir,inode,flag,mode,&inode);
 263         if (error)
 264                 return error;
 265         if (S_ISDIR(inode->i_mode) && (flag & 2)) {
 266                 iput(inode);
 267                 return -EPERM;
 268         }
 269         if (!permission(inode,ACC_MODE(flag))) {
 270                 iput(inode);
 271                 return -EACCES;
 272         }
 273         if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
 274                 if (IS_NODEV(inode)) {
 275                         iput(inode);
 276                         return -EACCES;
 277                 }
 278         } else {
 279                 if (IS_RDONLY(inode) && (flag & 2)) {
 280                         iput(inode);
 281                         return -EROFS;
 282                 }
 283         }
 284         if ((inode->i_count > 1) && (flag & 2))
 285                 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
 286                         if (!*p)
 287                                 continue;
 288                         if (inode == (*p)->executable) {
 289                                 iput(inode);
 290                                 return -ETXTBSY;
 291                         }
 292                         for (i=0; i < (*p)->numlibraries; i++)
 293                                 if (inode == (*p)->libraries[i].library) {
 294                                         iput(inode);
 295                                         return -ETXTBSY;
 296                                 }
 297                 }
 298         *res_inode = inode;
 299         return 0;
 300 }
 301 
 302 int do_mknod(const char * filename, int mode, dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 303 {
 304         const char * basename;
 305         int namelen, error;
 306         struct inode * dir;
 307 
 308         error = dir_namei(filename,&namelen,&basename, NULL, &dir);
 309         if (error)
 310                 return error;
 311         if (!namelen) {
 312                 iput(dir);
 313                 return -ENOENT;
 314         }
 315         if (IS_RDONLY(dir)) {
 316                 iput(dir);
 317                 return -EROFS;
 318         }
 319         if (!permission(dir,MAY_WRITE)) {
 320                 iput(dir);
 321                 return -EACCES;
 322         }
 323         if (!dir->i_op || !dir->i_op->mknod) {
 324                 iput(dir);
 325                 return -EPERM;
 326         }
 327         return dir->i_op->mknod(dir,basename,namelen,mode,dev);
 328 }
 329 
 330 int sys_mknod(const char * filename, int mode, dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 331 {
 332         if (S_ISFIFO(mode) || suser())
 333                 return do_mknod(filename,mode,dev);
 334         return -EPERM;
 335 }
 336 
 337 int sys_mkdir(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 338 {
 339         const char * basename;
 340         int namelen, error;
 341         struct inode * dir;
 342 
 343         error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
 344         if (error)
 345                 return error;
 346         if (!namelen) {
 347                 iput(dir);
 348                 return -ENOENT;
 349         }
 350         if (IS_RDONLY(dir)) {
 351                 iput(dir);
 352                 return -EROFS;
 353         }
 354         if (!permission(dir,MAY_WRITE)) {
 355                 iput(dir);
 356                 return -EACCES;
 357         }
 358         if (!dir->i_op || !dir->i_op->mkdir) {
 359                 iput(dir);
 360                 return -EPERM;
 361         }
 362         return dir->i_op->mkdir(dir,basename,namelen,mode);
 363 }
 364 
 365 int sys_rmdir(const char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 366 {
 367         const char * basename;
 368         int namelen, error;
 369         struct inode * dir;
 370 
 371         error = dir_namei(name,&namelen,&basename,NULL,&dir);
 372         if (error)
 373                 return error;
 374         if (!namelen) {
 375                 iput(dir);
 376                 return -ENOENT;
 377         }
 378         if (IS_RDONLY(dir)) {
 379                 iput(dir);
 380                 return -EROFS;
 381         }
 382         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 383                 iput(dir);
 384                 return -EACCES;
 385         }
 386         if (!dir->i_op || !dir->i_op->rmdir) {
 387                 iput(dir);
 388                 return -EPERM;
 389         }
 390         return dir->i_op->rmdir(dir,basename,namelen);
 391 }
 392 
 393 int sys_unlink(const char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 394 {
 395         const char * basename;
 396         int namelen, error;
 397         struct inode * dir;
 398 
 399         error = dir_namei(name,&namelen,&basename,NULL,&dir);
 400         if (error)
 401                 return error;
 402         if (!namelen) {
 403                 iput(dir);
 404                 return -EPERM;
 405         }
 406         if (IS_RDONLY(dir)) {
 407                 iput(dir);
 408                 return -EROFS;
 409         }
 410         if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
 411                 iput(dir);
 412                 return -EACCES;
 413         }
 414         if (!dir->i_op || !dir->i_op->unlink) {
 415                 iput(dir);
 416                 return -EPERM;
 417         }
 418         return dir->i_op->unlink(dir,basename,namelen);
 419 }
 420 
 421 int sys_symlink(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 422 {
 423         struct inode * dir;
 424         const char * basename;
 425         int namelen, error;
 426 
 427         error = dir_namei(newname,&namelen,&basename,NULL,&dir);
 428         if (error)
 429                 return error;
 430         if (!namelen) {
 431                 iput(dir);
 432                 return -ENOENT;
 433         }
 434         if (IS_RDONLY(dir)) {
 435                 iput(dir);
 436                 return -EROFS;
 437         }
 438         if (!permission(dir,MAY_WRITE)) {
 439                 iput(dir);
 440                 return -EACCES;
 441         }
 442         if (!dir->i_op || !dir->i_op->symlink) {
 443                 iput(dir);
 444                 return -EPERM;
 445         }
 446         return dir->i_op->symlink(dir,basename,namelen,oldname);
 447 }
 448 
 449 int sys_link(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 450 {
 451         struct inode * oldinode, * dir;
 452         const char * basename;
 453         int namelen, error;
 454 
 455         error = namei(oldname, &oldinode);
 456         if (error)
 457                 return error;
 458         error = dir_namei(newname,&namelen,&basename,NULL,&dir);
 459         if (error) {
 460                 iput(oldinode);
 461                 return error;
 462         }
 463         if (!namelen) {
 464                 iput(oldinode);
 465                 iput(dir);
 466                 return -EPERM;
 467         }
 468         if (IS_RDONLY(dir)) {
 469                 iput(oldinode);
 470                 iput(dir);
 471                 return -EROFS;
 472         }
 473         if (dir->i_dev != oldinode->i_dev) {
 474                 iput(dir);
 475                 iput(oldinode);
 476                 return -EXDEV;
 477         }
 478         if (!permission(dir,MAY_WRITE)) {
 479                 iput(dir);
 480                 iput(oldinode);
 481                 return -EACCES;
 482         }
 483         if (!dir->i_op || !dir->i_op->link) {
 484                 iput(dir);
 485                 iput(oldinode);
 486                 return -EPERM;
 487         }
 488         return dir->i_op->link(oldinode, dir, basename, namelen);
 489 }
 490 
 491 int sys_rename(const char * oldname, const char * newname)
     /* [previous][next][first][last][top][bottom][index][help] */
 492 {
 493         struct inode * old_dir, * new_dir;
 494         const char * old_base, * new_base;
 495         int old_len, new_len, error;
 496 
 497         error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
 498         if (error)
 499                 return error;
 500         if (!permission(old_dir,MAY_WRITE)) {
 501                 iput(old_dir);
 502                 return -EACCES;
 503         }
 504         if (!old_len || (get_fs_byte(old_base) == '.' &&
 505             (old_len == 1 || (get_fs_byte(old_base+1) == '.' &&
 506              old_len == 2)))) {
 507                 iput(old_dir);
 508                 return -EPERM;
 509         }
 510         error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
 511         if (error) {
 512                 iput(old_dir);
 513                 return error;
 514         }
 515         if (!permission(new_dir,MAY_WRITE)) {
 516                 iput(old_dir);
 517                 iput(new_dir);
 518                 return -EACCES;
 519         }
 520         if (!new_len || (get_fs_byte(new_base) == '.' &&
 521             (new_len == 1 || (get_fs_byte(new_base+1) == '.' &&
 522              new_len == 2)))) {
 523                 iput(old_dir);
 524                 iput(new_dir);
 525                 return -EPERM;
 526         }
 527         if (new_dir->i_dev != old_dir->i_dev) {
 528                 iput(old_dir);
 529                 iput(new_dir);
 530                 return -EXDEV;
 531         }
 532         if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
 533                 iput(old_dir);
 534                 iput(new_dir);
 535                 return -EROFS;
 536         }
 537         if (!old_dir->i_op || !old_dir->i_op->rename) {
 538                 iput(old_dir);
 539                 iput(new_dir);
 540                 return -EPERM;
 541         }
 542         return old_dir->i_op->rename(old_dir, old_base, old_len, 
 543                 new_dir, new_base, new_len);
 544 }

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