Import 1.3.85
[davej-history.git] / fs / open.c
blob2f6d38af277b0eb2d37276ae76914c4b90f850a2
1 /*
2 * linux/fs/open.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
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 #include <linux/mm.h>
21 #include <asm/segment.h>
23 asmlinkage intsys_statfs(const char* path,struct statfs * buf)
25 struct inode * inode;
26 int error;
28 error =verify_area(VERIFY_WRITE, buf,sizeof(struct statfs));
29 if(error)
30 return error;
31 error =namei(path,&inode);
32 if(error)
33 return error;
34 if(!inode->i_sb->s_op->statfs) {
35 iput(inode);
36 return-ENOSYS;
38 inode->i_sb->s_op->statfs(inode->i_sb, buf,sizeof(struct statfs));
39 iput(inode);
40 return0;
43 asmlinkage intsys_fstatfs(unsigned int fd,struct statfs * buf)
45 struct inode * inode;
46 struct file * file;
47 int error;
49 error =verify_area(VERIFY_WRITE, buf,sizeof(struct statfs));
50 if(error)
51 return error;
52 if(fd >= NR_OPEN || !(file = current->files->fd[fd]))
53 return-EBADF;
54 if(!(inode = file->f_inode))
55 return-ENOENT;
56 if(!inode->i_sb->s_op->statfs)
57 return-ENOSYS;
58 inode->i_sb->s_op->statfs(inode->i_sb, buf,sizeof(struct statfs));
59 return0;
62 intdo_truncate(struct inode *inode,unsigned long length)
64 int error;
65 struct iattr newattrs;
67 down(&inode->i_sem);
68 newattrs.ia_size = length;
69 newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
70 error =notify_change(inode, &newattrs);
71 if(!error) {
72 /* truncate virtual mappings of this file */
73 vmtruncate(inode, length);
74 if(inode->i_op && inode->i_op->truncate)
75 inode->i_op->truncate(inode);
77 up(&inode->i_sem);
78 return error;
81 asmlinkage intsys_truncate(const char* path,unsigned long length)
83 struct inode * inode;
84 int error;
86 error =namei(path,&inode);
87 if(error)
88 return error;
89 if(S_ISDIR(inode->i_mode)) {
90 iput(inode);
91 return-EACCES;
93 if((error =permission(inode,MAY_WRITE)) !=0) {
94 iput(inode);
95 return error;
97 if(IS_RDONLY(inode)) {
98 iput(inode);
99 return-EROFS;
101 if(IS_IMMUTABLE(inode) ||IS_APPEND(inode)) {
102 iput(inode);
103 return-EPERM;
105 error =get_write_access(inode);
106 if(error) {
107 iput(inode);
108 return error;
110 error =locks_verify(FLOCK_VERIFY_WRITE, inode, NULL,
111 length < inode->i_size ? length : inode->i_size,
112 abs(inode->i_size - length));
113 if(error)
114 return error;
115 error =do_truncate(inode, length);
116 put_write_access(inode);
117 iput(inode);
118 return error;
121 asmlinkage intsys_ftruncate(unsigned int fd,unsigned long length)
123 struct inode * inode;
124 struct file * file;
125 int error;
127 if(fd >= NR_OPEN || !(file = current->files->fd[fd]))
128 return-EBADF;
129 if(!(inode = file->f_inode))
130 return-ENOENT;
131 if(S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
132 return-EACCES;
133 if(IS_IMMUTABLE(inode) ||IS_APPEND(inode))
134 return-EPERM;
135 error =locks_verify(FLOCK_VERIFY_WRITE, inode, file,
136 length < inode->i_size ? length : inode->i_size,
137 abs(inode->i_size - length));
138 if(error)
139 return error;
140 returndo_truncate(inode, length);
143 #ifndef __alpha__
146 * sys_utime() can be implemented in user-level using sys_utimes().
147 * Is this for backwards compatibility? If so, why not move it
148 * into the appropriate arch directory (for those architectures that
149 * need it).
152 /* If times==NULL, set access and modification to current time,
153 * must be owner or have write permission.
154 * Else, update from *times, must be owner or super user.
156 asmlinkage intsys_utime(char* filename,struct utimbuf * times)
158 int error;
159 struct inode * inode;
160 struct iattr newattrs;
162 error =namei(filename,&inode);
163 if(error)
164 return error;
165 if(IS_RDONLY(inode)) {
166 iput(inode);
167 return-EROFS;
169 /* Don't worry, the checks are done in inode_change_ok() */
170 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
171 if(times) {
172 error =verify_area(VERIFY_READ, times,sizeof(*times));
173 if(error) {
174 iput(inode);
175 return error;
177 newattrs.ia_atime =get_user(&times->actime);
178 newattrs.ia_mtime =get_user(&times->modtime);
179 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
180 }else{
181 if((error =permission(inode,MAY_WRITE)) !=0) {
182 iput(inode);
183 return error;
186 error =notify_change(inode, &newattrs);
187 iput(inode);
188 return error;
191 #endif
193 /* If times==NULL, set access and modification to current time,
194 * must be owner or have write permission.
195 * Else, update from *times, must be owner or super user.
197 asmlinkage intsys_utimes(char* filename,struct timeval * utimes)
199 int error;
200 struct inode * inode;
201 struct iattr newattrs;
203 error =namei(filename,&inode);
204 if(error)
205 return error;
206 if(IS_RDONLY(inode)) {
207 iput(inode);
208 return-EROFS;
210 /* Don't worry, the checks are done in inode_change_ok() */
211 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
212 if(utimes) {
213 struct timeval times[2];
214 error =verify_area(VERIFY_READ, utimes,sizeof(times));
215 if(error) {
216 iput(inode);
217 return error;
219 memcpy_fromfs(&times, utimes,sizeof(times));
220 newattrs.ia_atime = times[0].tv_sec;
221 newattrs.ia_mtime = times[1].tv_sec;
222 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
223 }else{
224 if((error =permission(inode,MAY_WRITE)) !=0) {
225 iput(inode);
226 return error;
229 error =notify_change(inode, &newattrs);
230 iput(inode);
231 return error;
235 * access() needs to use the real uid/gid, not the effective uid/gid.
236 * We do this by temporarily setting fsuid/fsgid to the wanted values
238 asmlinkage intsys_access(const char* filename,int mode)
240 struct inode * inode;
241 int old_fsuid, old_fsgid;
242 int res;
244 if(mode != (mode & S_IRWXO))/* where's F_OK, X_OK, W_OK, R_OK? */
245 return-EINVAL;
246 old_fsuid = current->fsuid;
247 old_fsgid = current->fsgid;
248 current->fsuid = current->uid;
249 current->fsgid = current->gid;
250 res =namei(filename,&inode);
251 if(!res) {
252 res =permission(inode, mode);
253 iput(inode);
255 current->fsuid = old_fsuid;
256 current->fsgid = old_fsgid;
257 return res;
260 asmlinkage intsys_chdir(const char* filename)
262 struct inode * inode;
263 int error;
265 error =namei(filename,&inode);
266 if(error)
267 return error;
268 if(!S_ISDIR(inode->i_mode)) {
269 iput(inode);
270 return-ENOTDIR;
272 if((error =permission(inode,MAY_EXEC)) !=0) {
273 iput(inode);
274 return error;
276 iput(current->fs->pwd);
277 current->fs->pwd = inode;
278 return(0);
281 asmlinkage intsys_fchdir(unsigned int fd)
283 struct inode * inode;
284 struct file * file;
285 int error;
287 if(fd >= NR_OPEN || !(file = current->files->fd[fd]))
288 return-EBADF;
289 if(!(inode = file->f_inode))
290 return-ENOENT;
291 if(!S_ISDIR(inode->i_mode))
292 return-ENOTDIR;
293 if((error =permission(inode,MAY_EXEC)) !=0)
294 return error;
295 iput(current->fs->pwd);
296 current->fs->pwd = inode;
297 inode->i_count++;
298 return(0);
301 asmlinkage intsys_chroot(const char* filename)
303 struct inode * inode;
304 int error;
306 error =namei(filename,&inode);
307 if(error)
308 return error;
309 if(!S_ISDIR(inode->i_mode)) {
310 iput(inode);
311 return-ENOTDIR;
313 if(!fsuser()) {
314 iput(inode);
315 return-EPERM;
317 iput(current->fs->root);
318 current->fs->root = inode;
319 return(0);
322 asmlinkage intsys_fchmod(unsigned int fd, mode_t mode)
324 struct inode * inode;
325 struct file * file;
326 struct iattr newattrs;
328 if(fd >= NR_OPEN || !(file = current->files->fd[fd]))
329 return-EBADF;
330 if(!(inode = file->f_inode))
331 return-ENOENT;
332 if(IS_RDONLY(inode))
333 return-EROFS;
334 if(IS_IMMUTABLE(inode) ||IS_APPEND(inode))
335 return-EPERM;
336 if(mode == (mode_t) -1)
337 mode = inode->i_mode;
338 newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
339 newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
340 inode->i_dirt =1;
341 returnnotify_change(inode, &newattrs);
344 asmlinkage intsys_chmod(const char* filename, mode_t mode)
346 struct inode * inode;
347 int error;
348 struct iattr newattrs;
350 error =namei(filename,&inode);
351 if(error)
352 return error;
353 if(IS_RDONLY(inode)) {
354 iput(inode);
355 return-EROFS;
357 if(IS_IMMUTABLE(inode) ||IS_APPEND(inode)) {
358 iput(inode);
359 return-EPERM;
361 if(mode == (mode_t) -1)
362 mode = inode->i_mode;
363 newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
364 newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
365 inode->i_dirt =1;
366 error =notify_change(inode, &newattrs);
367 iput(inode);
368 return error;
371 asmlinkage intsys_fchown(unsigned int fd, uid_t user, gid_t group)
373 struct inode * inode;
374 struct file * file;
375 struct iattr newattrs;
376 int error;
378 if(fd >= NR_OPEN || !(file = current->files->fd[fd]))
379 return-EBADF;
380 if(!(inode = file->f_inode))
381 return-ENOENT;
382 if(IS_RDONLY(inode))
383 return-EROFS;
384 if(IS_IMMUTABLE(inode) ||IS_APPEND(inode))
385 return-EPERM;
386 if(user == (uid_t) -1)
387 user = inode->i_uid;
388 if(group == (gid_t) -1)
389 group = inode->i_gid;
390 newattrs.ia_mode = inode->i_mode;
391 newattrs.ia_uid = user;
392 newattrs.ia_gid = group;
393 newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
395 * If the owner has been changed, remove the setuid bit
397 if(user != inode->i_uid && (inode->i_mode & S_ISUID)) {
398 newattrs.ia_mode &= ~S_ISUID;
399 newattrs.ia_valid |= ATTR_MODE;
402 * If the group has been changed, remove the setgid bit
404 * Don't remove the setgid bit if no group execute bit.
405 * This is a file marked for mandatory locking.
407 if(group != inode->i_gid &&
408 ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
409 newattrs.ia_mode &= ~S_ISGID;
410 newattrs.ia_valid |= ATTR_MODE;
412 inode->i_dirt =1;
413 if(inode->i_sb && inode->i_sb->dq_op) {
414 inode->i_sb->dq_op->initialize(inode, -1);
415 if(inode->i_sb->dq_op->transfer(inode, &newattrs,0))
416 return-EDQUOT;
417 error =notify_change(inode, &newattrs);
418 if(error)
419 inode->i_sb->dq_op->transfer(inode, &newattrs,1);
420 }else
421 error =notify_change(inode, &newattrs);
422 return error;
425 asmlinkage intsys_chown(const char* filename, uid_t user, gid_t group)
427 struct inode * inode;
428 int error;
429 struct iattr newattrs;
431 error =lnamei(filename,&inode);
432 if(error)
433 return error;
434 if(IS_RDONLY(inode)) {
435 iput(inode);
436 return-EROFS;
438 if(IS_IMMUTABLE(inode) ||IS_APPEND(inode)) {
439 iput(inode);
440 return-EPERM;
442 if(user == (uid_t) -1)
443 user = inode->i_uid;
444 if(group == (gid_t) -1)
445 group = inode->i_gid;
446 newattrs.ia_mode = inode->i_mode;
447 newattrs.ia_uid = user;
448 newattrs.ia_gid = group;
449 newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
451 * If the owner has been changed, remove the setuid bit
453 if(user != inode->i_uid && (inode->i_mode & S_ISUID)) {
454 newattrs.ia_mode &= ~S_ISUID;
455 newattrs.ia_valid |= ATTR_MODE;
458 * If the group has been changed, remove the setgid bit
460 * Don't remove the setgid bit if no group execute bit.
461 * This is a file marked for mandatory locking.
463 if(group != inode->i_gid &&
464 ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
465 newattrs.ia_mode &= ~S_ISGID;
466 newattrs.ia_valid |= ATTR_MODE;
468 inode->i_dirt =1;
469 if(inode->i_sb->dq_op) {
470 inode->i_sb->dq_op->initialize(inode, -1);
471 if(inode->i_sb->dq_op->transfer(inode, &newattrs,0))
472 return-EDQUOT;
473 error =notify_change(inode, &newattrs);
474 if(error)
475 inode->i_sb->dq_op->transfer(inode, &newattrs,1);
476 }else
477 error =notify_change(inode, &newattrs);
478 iput(inode);
479 return(error);
483 * Note that while the flag value (low two bits) for sys_open means:
484 * 00 - read-only
485 * 01 - write-only
486 * 10 - read-write
487 * 11 - special
488 * it is changed into
489 * 00 - no permissions needed
490 * 01 - read-permission
491 * 10 - write-permission
492 * 11 - read-write
493 * for the internal routines (ie open_namei()/follow_link() etc). 00 is
494 * used by symlinks.
496 intdo_open(const char* filename,int flags,int mode)
498 struct inode * inode;
499 struct file * f;
500 int flag,error,fd;
502 f =get_empty_filp();
503 if(!f)
504 return-ENFILE;
505 f->f_flags = flag = flags;
506 f->f_mode = (flag+1) & O_ACCMODE;
507 if(f->f_mode)
508 flag++;
509 if(flag & (O_TRUNC | O_CREAT))
510 flag |=2;
511 error =open_namei(filename,flag,mode,&inode,NULL);
512 if(error)
513 goto cleanup_file;
514 if(f->f_mode & FMODE_WRITE) {
515 error =get_write_access(inode);
516 if(error)
517 goto cleanup_inode;
520 f->f_inode = inode;
521 f->f_pos =0;
522 f->f_reada =0;
523 f->f_op = NULL;
524 if(inode->i_op)
525 f->f_op = inode->i_op->default_file_ops;
526 if(f->f_op && f->f_op->open) {
527 error = f->f_op->open(inode,f);
528 if(error)
529 goto cleanup_all;
531 f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
534 * We have to do this last, because we mustn't export
535 * an incomplete fd to other processes which may share
536 * the same file table with us.
538 for(fd =0; fd < NR_OPEN && fd < current->rlim[RLIMIT_NOFILE].rlim_cur; fd++) {
539 if(!current->files->fd[fd]) {
540 current->files->fd[fd] = f;
541 FD_CLR(fd,&current->files->close_on_exec);
542 return fd;
545 error = -EMFILE;
546 if(f->f_op && f->f_op->release)
547 f->f_op->release(inode,f);
548 cleanup_all:
549 if(f->f_mode & FMODE_WRITE)
550 put_write_access(inode);
551 cleanup_inode:
552 iput(inode);
553 cleanup_file:
554 f->f_count--;
555 return error;
558 asmlinkage intsys_open(const char* filename,int flags,int mode)
560 char* tmp;
561 int error;
563 error =getname(filename, &tmp);
564 if(error)
565 return error;
566 error =do_open(tmp,flags,mode);
567 putname(tmp);
568 return error;
571 #ifndef __alpha__
574 * For backward compatibility? Maybe this should be moved
575 * into arch/i386 instead?
577 asmlinkage intsys_creat(const char* pathname,int mode)
579 returnsys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
582 #endif
584 intclose_fp(struct file *filp)
586 struct inode *inode;
588 if(filp->f_count ==0) {
589 printk("VFS: Close: file count is 0\n");
590 return0;
592 inode = filp->f_inode;
593 if(inode)
594 locks_remove_locks(current, filp);
595 if(filp->f_count >1) {
596 filp->f_count--;
597 return0;
599 if(filp->f_op && filp->f_op->release)
600 filp->f_op->release(inode,filp);
601 filp->f_count--;
602 filp->f_inode = NULL;
603 if(filp->f_mode & FMODE_WRITE)
604 put_write_access(inode);
605 iput(inode);
606 return0;
609 asmlinkage intsys_close(unsigned int fd)
611 struct file * filp;
613 if(fd >= NR_OPEN)
614 return-EBADF;
615 FD_CLR(fd, &current->files->close_on_exec);
616 if(!(filp = current->files->fd[fd]))
617 return-EBADF;
618 current->files->fd[fd] = NULL;
619 return(close_fp(filp));
623 * This routine simulates a hangup on the tty, to arrange that users
624 * are given clean terminals at login time.
626 asmlinkage intsys_vhangup(void)
628 if(!suser())
629 return-EPERM;
630 /* If there is a controlling tty, hang it up */
631 if(current->tty)
632 tty_vhangup(current->tty);
633 return0;
close