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