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 / open.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-15  |  11.8 KB  |  530 lines

  1. /*
  2.  *  linux/fs/open.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6.  
  7. #include <linux/vfs.h>
  8. #include <linux/types.h>
  9. #include <linux/utime.h>
  10. #include <linux/errno.h>
  11. #include <linux/fcntl.h>
  12. #include <linux/stat.h>
  13. #include <linux/string.h>
  14. #include <linux/sched.h>
  15. #include <linux/kernel.h>
  16. #include <linux/signal.h>
  17. #include <linux/tty.h>
  18. #include <linux/time.h>
  19. #include <linux/mm.h>
  20.  
  21. #include <asm/segment.h>
  22.  
  23. extern void fcntl_remove_locks(struct task_struct *, struct file *);
  24.  
  25. asmlinkage int sys_ustat(int dev, struct ustat * ubuf)
  26. {
  27.     return -ENOSYS;
  28. }
  29.  
  30. asmlinkage int sys_statfs(const char * path, struct statfs * buf)
  31. {
  32.     struct inode * inode;
  33.     int error;
  34.  
  35.     error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
  36.     if (error)
  37.         return error;
  38.     error = namei(path,&inode);
  39.     if (error)
  40.         return error;
  41.     if (!inode->i_sb->s_op->statfs) {
  42.         iput(inode);
  43.         return -ENOSYS;
  44.     }
  45.     inode->i_sb->s_op->statfs(inode->i_sb, buf);
  46.     iput(inode);
  47.     return 0;
  48. }
  49.  
  50. asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
  51. {
  52.     struct inode * inode;
  53.     struct file * file;
  54.     int error;
  55.  
  56.     error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
  57.     if (error)
  58.         return error;
  59.     if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
  60.         return -EBADF;
  61.     if (!(inode = file->f_inode))
  62.         return -ENOENT;
  63.     if (!inode->i_sb->s_op->statfs)
  64.         return -ENOSYS;
  65.     inode->i_sb->s_op->statfs(inode->i_sb, buf);
  66.     return 0;
  67. }
  68.  
  69. asmlinkage int sys_truncate(const char * path, unsigned int length)
  70. {
  71.     struct inode * inode;
  72.     int error;
  73.     struct iattr newattrs;
  74.  
  75.     error = namei(path,&inode);
  76.     if (error)
  77.         return error;
  78.     if (S_ISDIR(inode->i_mode)) {
  79.         iput(inode);
  80.         return -EACCES;
  81.     }
  82.     if ((error = permission(inode,MAY_WRITE)) != 0) {
  83.         iput(inode);
  84.         return error;
  85.     }
  86.     if (IS_RDONLY(inode)) {
  87.         iput(inode);
  88.         return -EROFS;
  89.     }
  90.     if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
  91.         iput(inode);
  92.         return -EPERM;
  93.     }
  94.     error = get_write_access(inode);
  95.     if (error) {
  96.         iput(inode);
  97.         return error;
  98.     }
  99.     inode->i_size = newattrs.ia_size = length;
  100.     if (inode->i_op && inode->i_op->truncate)
  101.         inode->i_op->truncate(inode);
  102.     newattrs.ia_ctime = newattrs.ia_mtime = CURRENT_TIME;
  103.     newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME | ATTR_MTIME;
  104.     inode->i_dirt = 1;
  105.     error = notify_change(inode, &newattrs);
  106.     put_write_access(inode);
  107.     iput(inode);
  108.     return error;
  109. }
  110.  
  111. asmlinkage int sys_ftruncate(unsigned int fd, unsigned int length)
  112. {
  113.     struct inode * inode;
  114.     struct file * file;
  115.     struct iattr newattrs;
  116.  
  117.     if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
  118.         return -EBADF;
  119.     if (!(inode = file->f_inode))
  120.         return -ENOENT;
  121.     if (S_ISDIR(inode->i_mode) || !(file->f_mode & 2))
  122.         return -EACCES;
  123.     if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
  124.         return -EPERM;
  125.     inode->i_size = newattrs.ia_size = length;
  126.     if (inode->i_op && inode->i_op->truncate)
  127.         inode->i_op->truncate(inode);
  128.     newattrs.ia_ctime = newattrs.ia_mtime = CURRENT_TIME;
  129.     newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME | ATTR_MTIME;
  130.     inode->i_dirt = 1;
  131.     return notify_change(inode, &newattrs);
  132. }
  133.  
  134. /* If times==NULL, set access and modification to current time,
  135.  * must be owner or have write permission.
  136.  * Else, update from *times, must be owner or super user.
  137.  */
  138. asmlinkage int sys_utime(char * filename, struct utimbuf * times)
  139. {
  140.     struct inode * inode;
  141.     long actime,modtime;
  142.     int error;
  143.     unsigned int flags = 0;
  144.     struct iattr newattrs;
  145.  
  146.     error = namei(filename,&inode);
  147.     if (error)
  148.         return error;
  149.     if (IS_RDONLY(inode)) {
  150.         iput(inode);
  151.         return -EROFS;
  152.     }
  153.     /* Don't worry, the checks are done in inode_change_ok() */
  154.     if (times) {
  155.         error = verify_area(VERIFY_READ, times, sizeof(*times));
  156.         if (error) {
  157.             iput(inode);
  158.             return error;
  159.         }
  160.         actime = get_fs_long((unsigned long *) ×->actime);
  161.         modtime = get_fs_long((unsigned long *) ×->modtime);
  162.         newattrs.ia_ctime = CURRENT_TIME;
  163.         flags = ATTR_ATIME_SET | ATTR_MTIME_SET;
  164.     } else {
  165.         if ((error = permission(inode,MAY_WRITE)) != 0) {
  166.             iput(inode);
  167.             return error;
  168.         }
  169.         actime = modtime = newattrs.ia_ctime = CURRENT_TIME;
  170.     }
  171.     newattrs.ia_atime = actime;
  172.     newattrs.ia_mtime = modtime;
  173.     newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME | flags;
  174.     inode->i_dirt = 1;
  175.     error = notify_change(inode, &newattrs);
  176.     iput(inode);
  177.     return error;
  178. }
  179.  
  180. /*
  181.  * access() needs to use the real uid/gid, not the effective uid/gid.
  182.  * We do this by temporarily setting fsuid/fsgid to the wanted values
  183.  */
  184. asmlinkage int sys_access(const char * filename, int mode)
  185. {
  186.     struct inode * inode;
  187.     int old_fsuid, old_fsgid;
  188.     int res;
  189.  
  190.     if (mode != (mode & S_IRWXO))    /* where's F_OK, X_OK, W_OK, R_OK? */
  191.         return -EINVAL;
  192.     old_fsuid = current->fsuid;
  193.     old_fsgid = current->fsgid;
  194.     current->fsuid = current->uid;
  195.     current->fsgid = current->gid;
  196.     res = namei(filename,&inode);
  197.     if (!res) {
  198.         res = permission(inode, mode);
  199.         iput(inode);
  200.     }
  201.     current->fsuid = old_fsuid;
  202.     current->fsgid = old_fsgid;
  203.     return res;
  204. }
  205.  
  206. asmlinkage int sys_chdir(const char * filename)
  207. {
  208.     struct inode * inode;
  209.     int error;
  210.  
  211.     error = namei(filename,&inode);
  212.     if (error)
  213.         return error;
  214.     if (!S_ISDIR(inode->i_mode)) {
  215.         iput(inode);
  216.         return -ENOTDIR;
  217.     }
  218.     if ((error = permission(inode,MAY_EXEC)) != 0) {
  219.         iput(inode);
  220.         return error;
  221.     }
  222.     iput(current->fs->pwd);
  223.     current->fs->pwd = inode;
  224.     return (0);
  225. }
  226.  
  227. asmlinkage int sys_fchdir(unsigned int fd)
  228. {
  229.     struct inode * inode;
  230.     struct file * file;
  231.     int error;
  232.  
  233.     if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
  234.         return -EBADF;
  235.     if (!(inode = file->f_inode))
  236.         return -ENOENT;
  237.     if (!S_ISDIR(inode->i_mode))
  238.         return -ENOTDIR;
  239.     if ((error = permission(inode,MAY_EXEC)) != 0)
  240.         return error;
  241.     iput(current->fs->pwd);
  242.     current->fs->pwd = inode;
  243.     inode->i_count++;
  244.     return (0);
  245. }
  246.  
  247. asmlinkage int sys_chroot(const char * filename)
  248. {
  249.     struct inode * inode;
  250.     int error;
  251.  
  252.     error = namei(filename,&inode);
  253.     if (error)
  254.         return error;
  255.     if (!S_ISDIR(inode->i_mode)) {
  256.         iput(inode);
  257.         return -ENOTDIR;
  258.     }
  259.     if (!fsuser()) {
  260.         iput(inode);
  261.         return -EPERM;
  262.     }
  263.     iput(current->fs->root);
  264.     current->fs->root = inode;
  265.     return (0);
  266. }
  267.  
  268. asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
  269. {
  270.     struct inode * inode;
  271.     struct file * file;
  272.     struct iattr newattrs;
  273.  
  274.     if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
  275.         return -EBADF;
  276.     if (!(inode = file->f_inode))
  277.         return -ENOENT;
  278.     if (IS_RDONLY(inode))
  279.         return -EROFS;
  280.     if (mode == (mode_t) -1)
  281.         mode = inode->i_mode;
  282.     newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
  283.     newattrs.ia_ctime = CURRENT_TIME;
  284.     newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
  285.     inode->i_dirt = 1;
  286.     return notify_change(inode, &newattrs);
  287. }
  288.  
  289. asmlinkage int sys_chmod(const char * filename, mode_t mode)
  290. {
  291.     struct inode * inode;
  292.     int error;
  293.     struct iattr newattrs;
  294.  
  295.     error = namei(filename,&inode);
  296.     if (error)
  297.         return error;
  298.     if (IS_RDONLY(inode)) {
  299.         iput(inode);
  300.         return -EROFS;
  301.     }
  302.     if (mode == (mode_t) -1)
  303.         mode = inode->i_mode;
  304.     newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
  305.     newattrs.ia_ctime = CURRENT_TIME;
  306.     newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
  307.     inode->i_dirt = 1;
  308.     error = notify_change(inode, &newattrs);
  309.     iput(inode);
  310.     return error;
  311. }
  312.  
  313. asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
  314. {
  315.     struct inode * inode;
  316.     struct file * file;
  317.     struct iattr newattrs;
  318.  
  319.     if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
  320.         return -EBADF;
  321.     if (!(inode = file->f_inode))
  322.         return -ENOENT;
  323.     if (IS_RDONLY(inode))
  324.         return -EROFS;
  325.     if (user == (uid_t) -1)
  326.         user = inode->i_uid;
  327.     if (group == (gid_t) -1)
  328.         group = inode->i_gid;
  329.     newattrs.ia_mode = inode->i_mode;
  330.     newattrs.ia_uid = user;
  331.     newattrs.ia_gid = group;
  332.     newattrs.ia_ctime = CURRENT_TIME;
  333.     newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
  334.     /*
  335.      * If the owner has been changed, remove the setuid bit
  336.      */
  337.     if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
  338.         newattrs.ia_mode &= ~S_ISUID;
  339.         newattrs.ia_valid |= ATTR_MODE;
  340.     }
  341.     /*
  342.      * If the group has been changed, remove the setgid bit
  343.      */
  344.     if (group != inode->i_gid && (inode->i_mode & S_ISGID)) {
  345.         newattrs.ia_mode &= ~S_ISGID;
  346.         newattrs.ia_valid |= ATTR_MODE;
  347.     }
  348.     inode->i_dirt = 1;
  349.     return notify_change(inode, &newattrs);
  350. }
  351.  
  352. asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
  353. {
  354.     struct inode * inode;
  355.     int error;
  356.     struct iattr newattrs;
  357.  
  358.     error = lnamei(filename,&inode);
  359.     if (error)
  360.         return error;
  361.     if (IS_RDONLY(inode)) {
  362.         iput(inode);
  363.         return -EROFS;
  364.     }
  365.     if (user == (uid_t) -1)
  366.         user = inode->i_uid;
  367.     if (group == (gid_t) -1)
  368.         group = inode->i_gid;
  369.     newattrs.ia_mode = inode->i_mode;
  370.     newattrs.ia_uid = user;
  371.     newattrs.ia_gid = group;
  372.     newattrs.ia_ctime = CURRENT_TIME;
  373.     newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
  374.     /*
  375.      * If the owner has been changed, remove the setuid bit
  376.      */
  377.     if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
  378.         newattrs.ia_mode &= ~S_ISUID;
  379.         newattrs.ia_valid |= ATTR_MODE;
  380.     }
  381.     /*
  382.      * If the group has been changed, remove the setgid bit
  383.      */
  384.     if (group != inode->i_gid && (inode->i_mode & S_ISGID)) {
  385.         newattrs.ia_mode &= ~S_ISGID;
  386.         newattrs.ia_valid |= ATTR_MODE;
  387.     }
  388.     inode->i_dirt = 1;
  389.     error = notify_change(inode, &newattrs);
  390.     iput(inode);
  391.     return(error);
  392. }
  393.  
  394. /*
  395.  * Note that while the flag value (low two bits) for sys_open means:
  396.  *    00 - read-only
  397.  *    01 - write-only
  398.  *    10 - read-write
  399.  *    11 - special
  400.  * it is changed into
  401.  *    00 - no permissions needed
  402.  *    01 - read-permission
  403.  *    10 - write-permission
  404.  *    11 - read-write
  405.  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
  406.  * used by symlinks.
  407.  */
  408. int do_open(const char * filename,int flags,int mode)
  409. {
  410.     struct inode * inode;
  411.     struct file * f;
  412.     int flag,error,fd;
  413.  
  414.     for(fd=0; fd<NR_OPEN && fd<current->rlim[RLIMIT_NOFILE].rlim_cur; fd++)
  415.         if (!current->files->fd[fd])
  416.             break;
  417.     if (fd>=NR_OPEN || fd>=current->rlim[RLIMIT_NOFILE].rlim_cur)
  418.         return -EMFILE;
  419.     FD_CLR(fd,¤t->files->close_on_exec);
  420.     f = get_empty_filp();
  421.     if (!f)
  422.         return -ENFILE;
  423.     current->files->fd[fd] = f;
  424.     f->f_flags = flag = flags;
  425.     f->f_mode = (flag+1) & O_ACCMODE;
  426.     if (f->f_mode)
  427.         flag++;
  428.     if (flag & (O_TRUNC | O_CREAT))
  429.         flag |= 2;
  430.     error = open_namei(filename,flag,mode,&inode,NULL);
  431.     if (!error && (f->f_mode & 2)) {
  432.         error = get_write_access(inode);
  433.         if (error)
  434.             iput(inode);
  435.     }
  436.     if (error) {
  437.         current->files->fd[fd]=NULL;
  438.         f->f_count--;
  439.         return error;
  440.     }
  441.  
  442.     f->f_inode = inode;
  443.     f->f_pos = 0;
  444.     f->f_reada = 0;
  445.     f->f_op = NULL;
  446.     if (inode->i_op)
  447.         f->f_op = inode->i_op->default_file_ops;
  448.     if (f->f_op && f->f_op->open) {
  449.         error = f->f_op->open(inode,f);
  450.         if (error) {
  451.             if (f->f_mode & 2) put_write_access(inode);
  452.             iput(inode);
  453.             f->f_count--;
  454.             current->files->fd[fd]=NULL;
  455.             return error;
  456.         }
  457.     }
  458.     f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
  459.     return (fd);
  460. }
  461.  
  462. asmlinkage int sys_open(const char * filename,int flags,int mode)
  463. {
  464.     char * tmp;
  465.     int error;
  466.  
  467.     error = getname(filename, &tmp);
  468.     if (error)
  469.         return error;
  470.     error = do_open(tmp,flags,mode);
  471.     putname(tmp);
  472.     return error;
  473. }
  474.  
  475. asmlinkage int sys_creat(const char * pathname, int mode)
  476. {
  477.     return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
  478. }
  479.  
  480. int close_fp(struct file *filp)
  481. {
  482.     struct inode *inode;
  483.  
  484.     if (filp->f_count == 0) {
  485.         printk("VFS: Close: file count is 0\n");
  486.         return 0;
  487.     }
  488.     inode = filp->f_inode;
  489.     if (inode)
  490.         fcntl_remove_locks(current, filp);
  491.     if (filp->f_count > 1) {
  492.         filp->f_count--;
  493.         return 0;
  494.     }
  495.     if (filp->f_op && filp->f_op->release)
  496.         filp->f_op->release(inode,filp);
  497.     filp->f_count--;
  498.     filp->f_inode = NULL;
  499.     if (filp->f_mode & 2) put_write_access(inode);
  500.     iput(inode);
  501.     return 0;
  502. }
  503.  
  504. asmlinkage int sys_close(unsigned int fd)
  505. {    
  506.     struct file * filp;
  507.  
  508.     if (fd >= NR_OPEN)
  509.         return -EBADF;
  510.     FD_CLR(fd, ¤t->files->close_on_exec);
  511.     if (!(filp = current->files->fd[fd]))
  512.         return -EBADF;
  513.     current->files->fd[fd] = NULL;
  514.     return (close_fp (filp));
  515. }
  516.  
  517. /*
  518.  * This routine simulates a hangup on the tty, to arrange that users
  519.  * are given clean terminals at login time.
  520.  */
  521. asmlinkage int sys_vhangup(void)
  522. {
  523.     if (!suser())
  524.         return -EPERM;
  525.     /* If there is a controlling tty, hang it up */
  526.     if (current->tty)
  527.         tty_vhangup(current->tty);
  528.     return 0;
  529. }
  530.