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