home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / fs / open.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  10.5 KB  |  476 lines

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