home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / fs / namei.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-13  |  14.8 KB  |  749 lines

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