1
2
3
4
5
6
7#include <linux/string.h>
8#include <linux/mm.h>
9#include <linux/utime.h>
10#include <linux/file.h>
11#include <linux/smp_lock.h>
12#include <linux/quotaops.h>
13#include <linux/dnotify.h>
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/tty.h>
17#include <linux/iobuf.h>
18
19#include <asm/uaccess.h>
20
21#define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
22
23int vfs_statfs(struct super_block *sb, struct statfs *buf)
24{
25 int retval = -ENODEV;
26
27 if (sb) {
28 retval = -ENOSYS;
29 if (sb->s_op && sb->s_op->statfs) {
30 memset(buf, 0, sizeof(struct statfs));
31 lock_kernel();
32 retval = sb->s_op->statfs(sb, buf);
33 unlock_kernel();
34 }
35 }
36 return retval;
37}
38
39
40asmlinkage long sys_statfs(const char * path, struct statfs * buf)
41{
42 struct nameidata nd;
43 int error;
44
45 error = user_path_walk(path, &nd);
46 if (!error) {
47 struct statfs tmp;
48 error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
49 if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs)))
50 error = -EFAULT;
51 path_release(&nd);
52 }
53 return error;
54}
55
56asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf)
57{
58 struct file * file;
59 struct statfs tmp;
60 int error;
61
62 error = -EBADF;
63 file = fget(fd);
64 if (!file)
65 goto out;
66 error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
67 if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs)))
68 error = -EFAULT;
69 fput(file);
70out:
71 return error;
72}
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87void fd_install(unsigned int fd, struct file * file)
88{
89 struct files_struct *files = current->files;
90
91 write_lock(&files->file_lock);
92 if (files->fd[fd])
93 BUG();
94 files->fd[fd] = file;
95 write_unlock(&files->file_lock);
96}
97
98int do_truncate(struct dentry *dentry, loff_t length)
99{
100 struct inode *inode = dentry->d_inode;
101 int error;
102 struct iattr newattrs;
103
104
105 if (length < 0)
106 return -EINVAL;
107
108 down(&inode->i_sem);
109 newattrs.ia_size = length;
110 newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
111 error = notify_change(dentry, &newattrs);
112 up(&inode->i_sem);
113 return error;
114}
115
116static inline long do_sys_truncate(const char * path, loff_t length)
117{
118 struct nameidata nd;
119 struct inode * inode;
120 int error;
121
122 error = -EINVAL;
123 if (length < 0)
124 goto out;
125
126 error = user_path_walk(path, &nd);
127 if (error)
128 goto out;
129 inode = nd.dentry->d_inode;
130
131
132 error = -EISDIR;
133 if (S_ISDIR(inode->i_mode))
134 goto dput_and_out;
135
136 error = -EINVAL;
137 if (!S_ISREG(inode->i_mode))
138 goto dput_and_out;
139
140 error = permission(inode,MAY_WRITE);
141 if (error)
142 goto dput_and_out;
143
144 error = -EROFS;
145 if (IS_RDONLY(inode))
146 goto dput_and_out;
147
148 error = -EPERM;
149 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
150 goto dput_and_out;
151
152
153
154
155 error = get_lease(inode, FMODE_WRITE);
156 if (error)
157 goto dput_and_out;
158
159 error = get_write_access(inode);
160 if (error)
161 goto dput_and_out;
162
163 error = locks_verify_truncate(inode, NULL, length);
164 if (!error) {
165 DQUOT_INIT(inode);
166 error = do_truncate(nd.dentry, length);
167 }
168 put_write_access(inode);
169
170dput_and_out:
171 path_release(&nd);
172out:
173 return error;
174}
175
176asmlinkage long sys_truncate(const char * path, unsigned long length)
177{
178
179 return do_sys_truncate(path, (long)length);
180}
181
182static inline long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
183{
184 struct inode * inode;
185 struct dentry *dentry;
186 struct file * file;
187 int error;
188
189 error = -EINVAL;
190 if (length < 0)
191 goto out;
192 error = -EBADF;
193 file = fget(fd);
194 if (!file)
195 goto out;
196
197
198 if (file->f_flags & O_LARGEFILE)
199 small = 0;
200
201 dentry = file->f_dentry;
202 inode = dentry->d_inode;
203 error = -EINVAL;
204 if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
205 goto out_putf;
206
207 error = -EINVAL;
208
209 if (small && length > MAX_NON_LFS)
210 goto out_putf;
211
212 error = -EPERM;
213 if (IS_APPEND(inode))
214 goto out_putf;
215
216 error = locks_verify_truncate(inode, file, length);
217 if (!error)
218 error = do_truncate(dentry, length);
219out_putf:
220 fput(file);
221out:
222 return error;
223}
224
225asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length)
226{
227 return do_sys_ftruncate(fd, length, 1);
228}
229
230
231#if BITS_PER_LONG == 32
232asmlinkage long sys_truncate64(const char * path, loff_t length)
233{
234 return do_sys_truncate(path, length);
235}
236
237asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
238{
239 return do_sys_ftruncate(fd, length, 0);
240}
241#endif
242
243#if !(defined(__alpha__) || defined(__ia64__))
244
245
246
247
248
249
250
251
252
253
254
255
256asmlinkage long sys_utime(char * filename, struct utimbuf * times)
257{
258 int error;
259 struct nameidata nd;
260 struct inode * inode;
261 struct iattr newattrs;
262
263 error = user_path_walk(filename, &nd);
264 if (error)
265 goto out;
266 inode = nd.dentry->d_inode;
267
268 error = -EROFS;
269 if (IS_RDONLY(inode))
270 goto dput_and_out;
271
272
273 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
274 if (times) {
275 error = get_user(newattrs.ia_atime, ×->actime);
276 if (!error)
277 error = get_user(newattrs.ia_mtime, ×->modtime);
278 if (error)
279 goto dput_and_out;
280
281 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
282 } else {
283 if (current->fsuid != inode->i_uid &&
284 (error = permission(inode,MAY_WRITE)) != 0)
285 goto dput_and_out;
286 }
287 error = notify_change(nd.dentry, &newattrs);
288dput_and_out:
289 path_release(&nd);
290out:
291 return error;
292}
293
294#endif
295
296
297
298
299
300asmlinkage long sys_utimes(char * filename, struct timeval * utimes)
301{
302 int error;
303 struct nameidata nd;
304 struct inode * inode;
305 struct iattr newattrs;
306
307 error = user_path_walk(filename, &nd);
308
309 if (error)
310 goto out;
311 inode = nd.dentry->d_inode;
312
313 error = -EROFS;
314 if (IS_RDONLY(inode))
315 goto dput_and_out;
316
317
318 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
319 if (utimes) {
320 struct timeval times[2];
321 error = -EFAULT;
322 if (copy_from_user(×, utimes, sizeof(times)))
323 goto dput_and_out;
324 newattrs.ia_atime = times[0].tv_sec;
325 newattrs.ia_mtime = times[1].tv_sec;
326 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
327 } else {
328 if (current->fsuid != inode->i_uid &&
329 (error = permission(inode,MAY_WRITE)) != 0)
330 goto dput_and_out;
331 }
332 error = notify_change(nd.dentry, &newattrs);
333dput_and_out:
334 path_release(&nd);
335out:
336 return error;
337}
338
339
340
341
342
343
344asmlinkage long sys_access(const char * filename, int mode)
345{
346 struct nameidata nd;
347 int old_fsuid, old_fsgid;
348 kernel_cap_t old_cap;
349 int res;
350
351 if (mode & ~S_IRWXO)
352 return -EINVAL;
353
354 old_fsuid = current->fsuid;
355 old_fsgid = current->fsgid;
356 old_cap = current->cap_effective;
357
358 current->fsuid = current->uid;
359 current->fsgid = current->gid;
360
361
362 if (current->uid)
363 cap_clear(current->cap_effective);
364 else
365 current->cap_effective = current->cap_permitted;
366
367 res = user_path_walk(filename, &nd);
368 if (!res) {
369 res = permission(nd.dentry->d_inode, mode);
370
371 if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
372 && !special_file(nd.dentry->d_inode->i_mode))
373 res = -EROFS;
374 path_release(&nd);
375 }
376
377 current->fsuid = old_fsuid;
378 current->fsgid = old_fsgid;
379 current->cap_effective = old_cap;
380
381 return res;
382}
383
384asmlinkage long sys_chdir(const char * filename)
385{
386 int error;
387 struct nameidata nd;
388
389 error = __user_walk(filename,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd);
390 if (error)
391 goto out;
392
393 error = permission(nd.dentry->d_inode,MAY_EXEC);
394 if (error)
395 goto dput_and_out;
396
397 set_fs_pwd(current->fs, nd.mnt, nd.dentry);
398
399dput_and_out:
400 path_release(&nd);
401out:
402 return error;
403}
404
405asmlinkage long sys_fchdir(unsigned int fd)
406{
407 struct file *file;
408 struct dentry *dentry;
409 struct inode *inode;
410 struct vfsmount *mnt;
411 int error;
412
413 error = -EBADF;
414 file = fget(fd);
415 if (!file)
416 goto out;
417
418 dentry = file->f_dentry;
419 mnt = file->f_vfsmnt;
420 inode = dentry->d_inode;
421
422 error = -ENOTDIR;
423 if (!S_ISDIR(inode->i_mode))
424 goto out_putf;
425
426 error = permission(inode, MAY_EXEC);
427 if (!error)
428 set_fs_pwd(current->fs, mnt, dentry);
429out_putf:
430 fput(file);
431out:
432 return error;
433}
434
435asmlinkage long sys_chroot(const char * filename)
436{
437 int error;
438 struct nameidata nd;
439
440 error = __user_walk(filename, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
441 LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
442 if (error)
443 goto out;
444
445 error = permission(nd.dentry->d_inode,MAY_EXEC);
446 if (error)
447 goto dput_and_out;
448
449 error = -EPERM;
450 if (!capable(CAP_SYS_CHROOT))
451 goto dput_and_out;
452
453 set_fs_root(current->fs, nd.mnt, nd.dentry);
454 set_fs_altroot();
455 error = 0;
456dput_and_out:
457 path_release(&nd);
458out:
459 return error;
460}
461
462asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
463{
464 struct inode * inode;
465 struct dentry * dentry;
466 struct file * file;
467 int err = -EBADF;
468 struct iattr newattrs;
469
470 file = fget(fd);
471 if (!file)
472 goto out;
473
474 dentry = file->f_dentry;
475 inode = dentry->d_inode;
476
477 err = -EROFS;
478 if (IS_RDONLY(inode))
479 goto out_putf;
480 err = -EPERM;
481 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
482 goto out_putf;
483 if (mode == (mode_t) -1)
484 mode = inode->i_mode;
485 newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
486 newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
487 err = notify_change(dentry, &newattrs);
488
489out_putf:
490 fput(file);
491out:
492 return err;
493}
494
495asmlinkage long sys_chmod(const char * filename, mode_t mode)
496{
497 struct nameidata nd;
498 struct inode * inode;
499 int error;
500 struct iattr newattrs;
501
502 error = user_path_walk(filename, &nd);
503 if (error)
504 goto out;
505 inode = nd.dentry->d_inode;
506
507 error = -EROFS;
508 if (IS_RDONLY(inode))
509 goto dput_and_out;
510
511 error = -EPERM;
512 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
513 goto dput_and_out;
514
515 if (mode == (mode_t) -1)
516 mode = inode->i_mode;
517 newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
518 newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
519 error = notify_change(nd.dentry, &newattrs);
520
521dput_and_out:
522 path_release(&nd);
523out:
524 return error;
525}
526
527static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
528{
529 struct inode * inode;
530 int error;
531 struct iattr newattrs;
532
533 error = -ENOENT;
534 if (!(inode = dentry->d_inode)) {
535 printk(KERN_ERR "chown_common: NULL inode\n");
536 goto out;
537 }
538 error = -EROFS;
539 if (IS_RDONLY(inode))
540 goto out;
541 error = -EPERM;
542 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
543 goto out;
544 if (user == (uid_t) -1)
545 user = inode->i_uid;
546 if (group == (gid_t) -1)
547 group = inode->i_gid;
548 newattrs.ia_mode = inode->i_mode;
549 newattrs.ia_uid = user;
550 newattrs.ia_gid = group;
551 newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
552
553
554
555
556
557
558
559
560
561
562 if ((inode->i_mode & S_ISUID) == S_ISUID &&
563 !S_ISDIR(inode->i_mode))
564 {
565 newattrs.ia_mode &= ~S_ISUID;
566 newattrs.ia_valid |= ATTR_MODE;
567 }
568
569
570
571
572
573
574
575
576 if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
577 && !S_ISDIR(inode->i_mode))
578 {
579 newattrs.ia_mode &= ~S_ISGID;
580 newattrs.ia_valid |= ATTR_MODE;
581 }
582 error = notify_change(dentry, &newattrs);
583out:
584 return error;
585}
586
587asmlinkage long sys_chown(const char * filename, uid_t user, gid_t group)
588{
589 struct nameidata nd;
590 int error;
591
592 error = user_path_walk(filename, &nd);
593 if (!error) {
594 error = chown_common(nd.dentry, user, group);
595 path_release(&nd);
596 }
597 return error;
598}
599
600asmlinkage long sys_lchown(const char * filename, uid_t user, gid_t group)
601{
602 struct nameidata nd;
603 int error;
604
605 error = user_path_walk_link(filename, &nd);
606 if (!error) {
607 error = chown_common(nd.dentry, user, group);
608 path_release(&nd);
609 }
610 return error;
611}
612
613
614asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
615{
616 struct file * file;
617 int error = -EBADF;
618
619 file = fget(fd);
620 if (file) {
621 error = chown_common(file->f_dentry, user, group);
622 fput(file);
623 }
624 return error;
625}
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641struct file *filp_open(const char * filename, int flags, int mode)
642{
643 int namei_flags, error;
644 struct nameidata nd;
645
646 namei_flags = flags;
647 if ((namei_flags+1) & O_ACCMODE)
648 namei_flags++;
649 if (namei_flags & O_TRUNC)
650 namei_flags |= 2;
651
652 error = open_namei(filename, namei_flags, mode, &nd);
653 if (!error)
654 return dentry_open(nd.dentry, nd.mnt, flags);
655
656 return ERR_PTR(error);
657}
658
659struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
660{
661 struct file * f;
662 struct inode *inode;
663 static LIST_HEAD(kill_list);
664 int error;
665
666 error = -ENFILE;
667 f = get_empty_filp();
668 if (!f)
669 goto cleanup_dentry;
670 f->f_flags = flags;
671 f->f_mode = (flags+1) & O_ACCMODE;
672 inode = dentry->d_inode;
673 if (f->f_mode & FMODE_WRITE) {
674 error = get_write_access(inode);
675 if (error)
676 goto cleanup_file;
677 }
678
679 f->f_dentry = dentry;
680 f->f_vfsmnt = mnt;
681 f->f_pos = 0;
682 f->f_reada = 0;
683 f->f_op = fops_get(inode->i_fop);
684 file_move(f, &inode->i_sb->s_files);
685
686
687 f->f_iobuf = NULL;
688 f->f_iobuf_lock = 0;
689 if (f->f_flags & O_DIRECT) {
690 error = alloc_kiovec(1, &f->f_iobuf);
691 if (error)
692 goto cleanup_all;
693 }
694
695 if (f->f_op && f->f_op->open) {
696 error = f->f_op->open(inode,f);
697 if (error)
698 goto cleanup_all;
699 }
700 f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
701
702 return f;
703
704cleanup_all:
705 if (f->f_iobuf)
706 free_kiovec(1, &f->f_iobuf);
707 fops_put(f->f_op);
708 if (f->f_mode & FMODE_WRITE)
709 put_write_access(inode);
710 file_move(f, &kill_list);
711 f->f_dentry = NULL;
712 f->f_vfsmnt = NULL;
713cleanup_file:
714 put_filp(f);
715cleanup_dentry:
716 dput(dentry);
717 mntput(mnt);
718 return ERR_PTR(error);
719}
720
721
722
723
724int get_unused_fd(void)
725{
726 struct files_struct * files = current->files;
727 int fd, error;
728
729 error = -EMFILE;
730 write_lock(&files->file_lock);
731
732repeat:
733 fd = find_next_zero_bit(files->open_fds,
734 files->max_fdset,
735 files->next_fd);
736
737
738
739
740
741 if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
742 goto out;
743
744
745 if (fd >= files->max_fdset) {
746 error = expand_fdset(files, fd);
747 if (!error) {
748 error = -EMFILE;
749 goto repeat;
750 }
751 goto out;
752 }
753
754
755
756
757 if (fd >= files->max_fds) {
758 error = expand_fd_array(files, fd);
759 if (!error) {
760 error = -EMFILE;
761 goto repeat;
762 }
763 goto out;
764 }
765
766 FD_SET(fd, files->open_fds);
767 FD_CLR(fd, files->close_on_exec);
768 files->next_fd = fd + 1;
769#if 1
770
771 if (files->fd[fd] != NULL) {
772 printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd);
773 files->fd[fd] = NULL;
774 }
775#endif
776 error = fd;
777
778out:
779 write_unlock(&files->file_lock);
780 return error;
781}
782
783asmlinkage long sys_open(const char * filename, int flags, int mode)
784{
785 char * tmp;
786 int fd, error;
787
788#if BITS_PER_LONG != 32
789 flags |= O_LARGEFILE;
790#endif
791 tmp = getname(filename);
792 fd = PTR_ERR(tmp);
793 if (!IS_ERR(tmp)) {
794 fd = get_unused_fd();
795 if (fd >= 0) {
796 struct file *f = filp_open(tmp, flags, mode);
797 error = PTR_ERR(f);
798 if (IS_ERR(f))
799 goto out_error;
800 fd_install(fd, f);
801 }
802out:
803 putname(tmp);
804 }
805 return fd;
806
807out_error:
808 put_unused_fd(fd);
809 fd = error;
810 goto out;
811}
812
813#ifndef __alpha__
814
815
816
817
818
819asmlinkage long sys_creat(const char * pathname, int mode)
820{
821 return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
822}
823
824#endif
825
826
827
828
829
830int filp_close(struct file *filp, fl_owner_t id)
831{
832 int retval;
833
834 if (!file_count(filp)) {
835 printk(KERN_ERR "VFS: Close: file count is 0\n");
836 return 0;
837 }
838 retval = 0;
839 if (filp->f_op && filp->f_op->flush) {
840 lock_kernel();
841 retval = filp->f_op->flush(filp);
842 unlock_kernel();
843 }
844 dnotify_flush(filp, id);
845 locks_remove_posix(filp, id);
846 fput(filp);
847 return retval;
848}
849
850
851
852
853
854
855asmlinkage long sys_close(unsigned int fd)
856{
857 struct file * filp;
858 struct files_struct *files = current->files;
859
860 write_lock(&files->file_lock);
861 if (fd >= files->max_fds)
862 goto out_unlock;
863 filp = files->fd[fd];
864 if (!filp)
865 goto out_unlock;
866 files->fd[fd] = NULL;
867 FD_CLR(fd, files->close_on_exec);
868 __put_unused_fd(files, fd);
869 write_unlock(&files->file_lock);
870 return filp_close(filp, files);
871
872out_unlock:
873 write_unlock(&files->file_lock);
874 return -EBADF;
875}
876
877
878
879
880
881asmlinkage long sys_vhangup(void)
882{
883 if (capable(CAP_SYS_TTY_CONFIG)) {
884 tty_vhangup(current->tty);
885 return 0;
886 }
887 return -EPERM;
888}
889
890
891
892
893
894
895
896int generic_file_open(struct inode * inode, struct file * filp)
897{
898 if (!(filp->f_flags & O_LARGEFILE) && inode->i_size > MAX_NON_LFS)
899 return -EFBIG;
900 return 0;
901}
902
903EXPORT_SYMBOL(generic_file_open);
904