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