Linux 2.3.0
[davej-history.git] / fs / open.c
blob629008d4d9ea4a588e5dac631be9c4dae9cff6a6
1 /*
2 * linux/fs/open.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 #include <linux/mm.h>
8 #include <linux/utime.h>
9 #include <linux/file.h>
10 #include <linux/smp_lock.h>
11 #include <linux/quotaops.h>
13 #include <asm/uaccess.h>
15 asmlinkage int sys_statfs(const char * path, struct statfs * buf)
17 struct dentry * dentry;
18 int error;
20 lock_kernel();
21 dentry = namei(path);
22 error = PTR_ERR(dentry);
23 if (!IS_ERR(dentry)) {
24 struct inode * inode = dentry->d_inode;
25 struct super_block * sb = inode->i_sb;
27 error = -ENODEV;
28 if (sb && sb->s_op && sb->s_op->statfs)
29 error = sb->s_op->statfs(sb, buf, sizeof(struct statfs));
31 dput(dentry);
33 unlock_kernel();
34 return error;
37 asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
39 struct file * file;
40 struct inode * inode;
41 struct dentry * dentry;
42 struct super_block * sb;
43 int error;
45 lock_kernel();
46 error = -EBADF;
47 file = fget(fd);
48 if (!file)
49 goto out;
50 error = -ENOENT;
51 if (!(dentry = file->f_dentry))
52 goto out_putf;
53 if (!(inode = dentry->d_inode))
54 goto out_putf;
55 error = -ENODEV;
56 sb = inode->i_sb;
57 if (sb && sb->s_op && sb->s_op->statfs)
58 error = sb->s_op->statfs(sb, buf, sizeof(struct statfs));
59 out_putf:
60 fput(file);
61 out:
62 unlock_kernel();
63 return error;
66 int do_truncate(struct dentry *dentry, unsigned long length)
68 struct inode *inode = dentry->d_inode;
69 int error;
70 struct iattr newattrs;
72 /* Not pretty: "inode->i_size" shouldn't really be "off_t". But it is. */
73 if ((off_t) length < 0)
74 return -EINVAL;
76 down(&inode->i_sem);
77 newattrs.ia_size = length;
78 newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
79 error = notify_change(dentry, &newattrs);
80 if (!error) {
81 /* truncate virtual mappings of this file */
82 vmtruncate(inode, length);
83 if (inode->i_op && inode->i_op->truncate)
84 inode->i_op->truncate(inode);
86 up(&inode->i_sem);
87 return error;
90 asmlinkage int sys_truncate(const char * path, unsigned long length)
92 struct dentry * dentry;
93 struct inode * inode;
94 int error;
96 lock_kernel();
97 dentry = namei(path);
99 error = PTR_ERR(dentry);
100 if (IS_ERR(dentry))
101 goto out;
102 inode = dentry->d_inode;
104 error = -EACCES;
105 if (S_ISDIR(inode->i_mode))
106 goto dput_and_out;
108 error = permission(inode,MAY_WRITE);
109 if (error)
110 goto dput_and_out;
112 error = -EROFS;
113 if (IS_RDONLY(inode))
114 goto dput_and_out;
116 error = -EPERM;
117 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
118 goto dput_and_out;
120 error = get_write_access(inode);
121 if (error)
122 goto dput_and_out;
124 error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, NULL,
125 length < inode->i_size ? length : inode->i_size,
126 abs(inode->i_size - length));
127 if (!error) {
128 DQUOT_INIT(inode);
129 error = do_truncate(dentry, length);
131 put_write_access(inode);
132 dput_and_out:
133 dput(dentry);
134 out:
135 unlock_kernel();
136 return error;
139 asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length)
141 struct inode * inode;
142 struct dentry *dentry;
143 struct file * file;
144 int error;
146 lock_kernel();
147 error = -EBADF;
148 file = fget(fd);
149 if (!file)
150 goto out;
151 error = -ENOENT;
152 if (!(dentry = file->f_dentry))
153 goto out_putf;
154 if (!(inode = dentry->d_inode))
155 goto out_putf;
156 error = -EACCES;
157 if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
158 goto out_putf;
159 error = -EPERM;
160 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
161 goto out_putf;
162 error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
163 length<inode->i_size ? length : inode->i_size,
164 abs(inode->i_size - length));
165 if (!error)
166 error = do_truncate(dentry, length);
167 out_putf:
168 fput(file);
169 out:
170 unlock_kernel();
171 return error;
174 #ifndef __alpha__
177 * sys_utime() can be implemented in user-level using sys_utimes().
178 * Is this for backwards compatibility? If so, why not move it
179 * into the appropriate arch directory (for those architectures that
180 * need it).
183 /* If times==NULL, set access and modification to current time,
184 * must be owner or have write permission.
185 * Else, update from *times, must be owner or super user.
187 asmlinkage int sys_utime(char * filename, struct utimbuf * times)
189 int error;
190 struct dentry * dentry;
191 struct inode * inode;
192 struct iattr newattrs;
194 lock_kernel();
195 dentry = namei(filename);
197 error = PTR_ERR(dentry);
198 if (IS_ERR(dentry))
199 goto out;
200 inode = dentry->d_inode;
202 error = -EROFS;
203 if (IS_RDONLY(inode))
204 goto dput_and_out;
206 /* Don't worry, the checks are done in inode_change_ok() */
207 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
208 if (times) {
209 error = get_user(newattrs.ia_atime, &times->actime);
210 if (!error)
211 error = get_user(newattrs.ia_mtime, &times->modtime);
212 if (error)
213 goto dput_and_out;
215 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
216 } else {
217 if (current->fsuid != inode->i_uid &&
218 (error = permission(inode,MAY_WRITE)) != 0)
219 goto dput_and_out;
221 error = notify_change(dentry, &newattrs);
222 dput_and_out:
223 dput(dentry);
224 out:
225 unlock_kernel();
226 return error;
229 #endif
231 /* If times==NULL, set access and modification to current time,
232 * must be owner or have write permission.
233 * Else, update from *times, must be owner or super user.
235 asmlinkage int sys_utimes(char * filename, struct timeval * utimes)
237 int error;
238 struct dentry * dentry;
239 struct inode * inode;
240 struct iattr newattrs;
242 lock_kernel();
243 dentry = namei(filename);
245 error = PTR_ERR(dentry);
246 if (IS_ERR(dentry))
247 goto out;
248 inode = dentry->d_inode;
250 error = -EROFS;
251 if (IS_RDONLY(inode))
252 goto dput_and_out;
254 /* Don't worry, the checks are done in inode_change_ok() */
255 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
256 if (utimes) {
257 struct timeval times[2];
258 error = -EFAULT;
259 if (copy_from_user(&times, utimes, sizeof(times)))
260 goto dput_and_out;
261 newattrs.ia_atime = times[0].tv_sec;
262 newattrs.ia_mtime = times[1].tv_sec;
263 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
264 } else {
265 if ((error = permission(inode,MAY_WRITE)) != 0)
266 goto dput_and_out;
268 error = notify_change(dentry, &newattrs);
269 dput_and_out:
270 dput(dentry);
271 out:
272 unlock_kernel();
273 return error;
277 * access() needs to use the real uid/gid, not the effective uid/gid.
278 * We do this by temporarily clearing all FS-related capabilities and
279 * switching the fsuid/fsgid around to the real ones.
281 asmlinkage int sys_access(const char * filename, int mode)
283 struct dentry * dentry;
284 int old_fsuid, old_fsgid;
285 kernel_cap_t old_cap;
286 int res = -EINVAL;
288 lock_kernel();
289 if (mode != (mode & S_IRWXO)) /* where's F_OK, X_OK, W_OK, R_OK? */
290 goto out;
291 old_fsuid = current->fsuid;
292 old_fsgid = current->fsgid;
293 old_cap = current->cap_effective;
295 current->fsuid = current->uid;
296 current->fsgid = current->gid;
298 /* Clear the capabilities if we switch to a non-root user */
299 if (current->uid)
300 cap_clear(current->cap_effective);
301 else
302 current->cap_effective = current->cap_permitted;
304 dentry = namei(filename);
305 res = PTR_ERR(dentry);
306 if (!IS_ERR(dentry)) {
307 res = permission(dentry->d_inode, mode);
308 /* SuS v2 requires we report a read only fs too */
309 if(!res && (mode & S_IWOTH) && IS_RDONLY(dentry->d_inode))
310 res = -EROFS;
311 dput(dentry);
314 current->fsuid = old_fsuid;
315 current->fsgid = old_fsgid;
316 current->cap_effective = old_cap;
317 out:
318 unlock_kernel();
319 return res;
322 asmlinkage int sys_chdir(const char * filename)
324 int error;
325 struct inode *inode;
326 struct dentry *dentry, *tmp;
328 lock_kernel();
330 dentry = namei(filename);
331 error = PTR_ERR(dentry);
332 if (IS_ERR(dentry))
333 goto out;
335 inode = dentry->d_inode;
337 error = -ENOTDIR;
338 if (!S_ISDIR(inode->i_mode))
339 goto dput_and_out;
341 error = permission(inode,MAY_EXEC);
342 if (error)
343 goto dput_and_out;
345 /* exchange dentries */
346 tmp = current->fs->pwd;
347 current->fs->pwd = dentry;
348 dentry = tmp;
350 dput_and_out:
351 dput(dentry);
352 out:
353 unlock_kernel();
354 return error;
357 asmlinkage int sys_fchdir(unsigned int fd)
359 struct file *file;
360 struct dentry *dentry;
361 struct inode *inode;
362 int error;
364 lock_kernel();
366 error = -EBADF;
367 file = fget(fd);
368 if (!file)
369 goto out;
371 error = -ENOENT;
372 if (!(dentry = file->f_dentry))
373 goto out_putf;
374 if (!(inode = dentry->d_inode))
375 goto out_putf;
377 error = -ENOTDIR;
378 if (!S_ISDIR(inode->i_mode))
379 goto out_putf;
381 error = permission(inode, MAY_EXEC);
382 if (!error) {
383 struct dentry *tmp = current->fs->pwd;
384 current->fs->pwd = dget(dentry);
385 dput(tmp);
387 out_putf:
388 fput(file);
389 out:
390 unlock_kernel();
391 return error;
394 asmlinkage int sys_chroot(const char * filename)
396 int error;
397 struct inode *inode;
398 struct dentry *dentry, *tmp;
400 lock_kernel();
402 dentry = namei(filename);
403 error = PTR_ERR(dentry);
404 if (IS_ERR(dentry))
405 goto out;
407 inode = dentry->d_inode;
409 error = -ENOTDIR;
410 if (!S_ISDIR(inode->i_mode))
411 goto dput_and_out;
413 error = permission(inode,MAY_EXEC);
414 if (error)
415 goto dput_and_out;
417 error = -EPERM;
418 if (!capable(CAP_SYS_CHROOT))
419 goto dput_and_out;
421 /* exchange dentries */
422 tmp = current->fs->root;
423 current->fs->root = dentry;
424 dentry = tmp;
425 error = 0;
427 dput_and_out:
428 dput(dentry);
429 out:
430 unlock_kernel();
431 return error;
434 asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
436 struct inode * inode;
437 struct dentry * dentry;
438 struct file * file;
439 int err = -EBADF;
440 struct iattr newattrs;
442 lock_kernel();
443 file = fget(fd);
444 if (!file)
445 goto out;
447 err = -ENOENT;
448 if (!(dentry = file->f_dentry))
449 goto out_putf;
450 if (!(inode = dentry->d_inode))
451 goto out_putf;
453 err = -EROFS;
454 if (IS_RDONLY(inode))
455 goto out_putf;
456 err = -EPERM;
457 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
458 goto out_putf;
459 if (mode == (mode_t) -1)
460 mode = inode->i_mode;
461 newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
462 newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
463 err = notify_change(dentry, &newattrs);
465 out_putf:
466 fput(file);
467 out:
468 unlock_kernel();
469 return err;
472 asmlinkage int sys_chmod(const char * filename, mode_t mode)
474 struct dentry * dentry;
475 struct inode * inode;
476 int error;
477 struct iattr newattrs;
479 lock_kernel();
480 dentry = namei(filename);
482 error = PTR_ERR(dentry);
483 if (IS_ERR(dentry))
484 goto out;
485 inode = dentry->d_inode;
487 error = -EROFS;
488 if (IS_RDONLY(inode))
489 goto dput_and_out;
491 error = -EPERM;
492 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
493 goto dput_and_out;
495 if (mode == (mode_t) -1)
496 mode = inode->i_mode;
497 newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
498 newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
499 error = notify_change(dentry, &newattrs);
501 dput_and_out:
502 dput(dentry);
503 out:
504 unlock_kernel();
505 return error;
508 static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
510 struct inode * inode;
511 int error;
512 struct iattr newattrs;
514 error = -ENOENT;
515 if (!(inode = dentry->d_inode)) {
516 printk("chown_common: NULL inode\n");
517 goto out;
519 error = -EROFS;
520 if (IS_RDONLY(inode))
521 goto out;
522 error = -EPERM;
523 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
524 goto out;
525 if (user == (uid_t) -1)
526 user = inode->i_uid;
527 if (group == (gid_t) -1)
528 group = inode->i_gid;
529 newattrs.ia_mode = inode->i_mode;
530 newattrs.ia_uid = user;
531 newattrs.ia_gid = group;
532 newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
534 * If the user or group of a non-directory has been changed by a
535 * non-root user, remove the setuid bit.
536 * 19981026 David C Niemi <niemi@tux.org>
539 if ((inode->i_mode & S_ISUID) == S_ISUID &&
540 !S_ISDIR(inode->i_mode)
541 && current->fsuid)
543 newattrs.ia_mode &= ~S_ISUID;
544 newattrs.ia_valid |= ATTR_MODE;
547 * Likewise, if the user or group of a non-directory has been changed
548 * by a non-root user, remove the setgid bit UNLESS there is no group
549 * execute bit (this would be a file marked for mandatory locking).
550 * 19981026 David C Niemi <niemi@tux.org>
552 if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
553 && !S_ISDIR(inode->i_mode) && current->fsuid)
555 newattrs.ia_mode &= ~S_ISGID;
556 newattrs.ia_valid |= ATTR_MODE;
558 error = DQUOT_TRANSFER(dentry, &newattrs);
559 out:
560 return error;
563 asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
565 struct dentry * dentry;
566 int error;
568 lock_kernel();
569 dentry = namei(filename);
571 error = PTR_ERR(dentry);
572 if (!IS_ERR(dentry)) {
573 error = chown_common(dentry, user, group);
574 dput(dentry);
576 unlock_kernel();
577 return error;
580 asmlinkage int sys_lchown(const char * filename, uid_t user, gid_t group)
582 struct dentry * dentry;
583 int error;
585 lock_kernel();
586 dentry = lnamei(filename);
588 error = PTR_ERR(dentry);
589 if (!IS_ERR(dentry)) {
590 error = chown_common(dentry, user, group);
591 dput(dentry);
593 unlock_kernel();
594 return error;
598 asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
600 struct dentry * dentry;
601 struct file * file;
602 int error = -EBADF;
604 lock_kernel();
605 file = fget(fd);
606 if (!file)
607 goto out;
608 error = -ENOENT;
609 if ((dentry = file->f_dentry) != NULL)
610 error = chown_common(dentry, user, group);
611 fput(file);
613 out:
614 unlock_kernel();
615 return error;
619 * Note that while the flag value (low two bits) for sys_open means:
620 * 00 - read-only
621 * 01 - write-only
622 * 10 - read-write
623 * 11 - special
624 * it is changed into
625 * 00 - no permissions needed
626 * 01 - read-permission
627 * 10 - write-permission
628 * 11 - read-write
629 * for the internal routines (ie open_namei()/follow_link() etc). 00 is
630 * used by symlinks.
632 struct file *filp_open(const char * filename, int flags, int mode)
634 struct inode * inode;
635 struct dentry * dentry;
636 struct file * f;
637 int flag,error;
639 error = -ENFILE;
640 f = get_empty_filp();
641 if (!f)
642 goto out;
643 f->f_flags = flag = flags;
644 f->f_mode = (flag+1) & O_ACCMODE;
645 if (f->f_mode)
646 flag++;
647 if (flag & O_TRUNC)
648 flag |= 2;
649 dentry = open_namei(filename,flag,mode);
650 error = PTR_ERR(dentry);
651 if (IS_ERR(dentry))
652 goto cleanup_file;
653 inode = dentry->d_inode;
654 if (f->f_mode & FMODE_WRITE) {
655 error = get_write_access(inode);
656 if (error)
657 goto cleanup_dentry;
660 f->f_dentry = dentry;
661 f->f_pos = 0;
662 f->f_reada = 0;
663 f->f_op = NULL;
664 if (inode->i_op)
665 f->f_op = inode->i_op->default_file_ops;
666 if (f->f_op && f->f_op->open) {
667 error = f->f_op->open(inode,f);
668 if (error)
669 goto cleanup_all;
671 f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
673 return f;
675 cleanup_all:
676 if (f->f_mode & FMODE_WRITE)
677 put_write_access(inode);
678 cleanup_dentry:
679 f->f_dentry = NULL;
680 dput(dentry);
681 cleanup_file:
682 put_filp(f);
683 out:
684 return ERR_PTR(error);
688 * Find an empty file descriptor entry, and mark it busy.
690 int get_unused_fd(void)
692 struct files_struct * files = current->files;
693 int fd, error;
695 error = -EMFILE;
696 fd = find_first_zero_bit(&files->open_fds, NR_OPEN);
698 * N.B. For clone tasks sharing a files structure, this test
699 * will limit the total number of files that can be opened.
701 if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
702 goto out;
704 /* Check here for fd > files->max_fds to do dynamic expansion */
706 FD_SET(fd, &files->open_fds);
707 FD_CLR(fd, &files->close_on_exec);
708 #if 1
709 /* Sanity check */
710 if (files->fd[fd] != NULL) {
711 printk("get_unused_fd: slot %d not NULL!\n", fd);
712 files->fd[fd] = NULL;
714 #endif
715 error = fd;
717 out:
718 return error;
721 inline void put_unused_fd(unsigned int fd)
723 FD_CLR(fd, &current->files->open_fds);
726 asmlinkage int sys_open(const char * filename, int flags, int mode)
728 char * tmp;
729 int fd, error;
731 tmp = getname(filename);
732 fd = PTR_ERR(tmp);
733 if (!IS_ERR(tmp)) {
734 lock_kernel();
735 fd = get_unused_fd();
736 if (fd >= 0) {
737 struct file * f = filp_open(tmp, flags, mode);
738 error = PTR_ERR(f);
739 if (IS_ERR(f))
740 goto out_error;
741 fd_install(fd, f);
743 out:
744 unlock_kernel();
745 putname(tmp);
747 return fd;
749 out_error:
750 put_unused_fd(fd);
751 fd = error;
752 goto out;
755 #ifndef __alpha__
758 * For backward compatibility? Maybe this should be moved
759 * into arch/i386 instead?
761 asmlinkage int sys_creat(const char * pathname, int mode)
763 return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
766 #endif
769 * Called when retiring the last use of a file pointer.
771 void __fput(struct file *filp)
773 struct dentry * dentry = filp->f_dentry;
774 struct inode * inode = dentry->d_inode;
776 if (filp->f_op && filp->f_op->release)
777 filp->f_op->release(inode, filp);
778 filp->f_dentry = NULL;
779 if (filp->f_mode & FMODE_WRITE)
780 put_write_access(inode);
781 dput(dentry);
785 * "id" is the POSIX thread ID. We use the
786 * files pointer for this..
788 int filp_close(struct file *filp, fl_owner_t id)
790 int retval;
791 struct dentry *dentry = filp->f_dentry;
793 if (filp->f_count == 0) {
794 printk("VFS: Close: file count is 0\n");
795 return 0;
797 retval = 0;
798 if (filp->f_op && filp->f_op->flush)
799 retval = filp->f_op->flush(filp);
800 if (dentry->d_inode)
801 locks_remove_posix(filp, id);
802 fput(filp);
803 return retval;
807 * Careful here! We test whether the file pointer is NULL before
808 * releasing the fd. This ensures that one clone task can't release
809 * an fd while another clone is opening it.
811 asmlinkage int sys_close(unsigned int fd)
813 int error;
814 struct file * filp;
816 lock_kernel();
817 error = -EBADF;
818 filp = fcheck(fd);
819 if (filp) {
820 struct files_struct * files = current->files;
821 files->fd[fd] = NULL;
822 put_unused_fd(fd);
823 FD_CLR(fd, &files->close_on_exec);
824 error = filp_close(filp, files);
826 unlock_kernel();
827 return error;
831 * This routine simulates a hangup on the tty, to arrange that users
832 * are given clean terminals at login time.
834 asmlinkage int sys_vhangup(void)
836 int ret = -EPERM;
838 lock_kernel();
839 if (!capable(CAP_SYS_TTY_CONFIG))
840 goto out;
841 /* If there is a controlling tty, hang it up */
842 if (current->tty)
843 tty_vhangup(current->tty);
844 ret = 0;
845 out:
846 unlock_kernel();
847 return ret;