~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/open.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/fs/open.c
  3  *
  4  *  Copyright (C) 1991, 1992  Linus Torvalds
  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 
 17 #include <asm/uaccess.h>
 18 
 19 #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
 20 
 21 int vfs_statfs(struct super_block *sb, struct statfs *buf)
 22 {
 23         int retval = -ENODEV;
 24 
 25         if (sb) {
 26                 retval = -ENOSYS;
 27                 if (sb->s_op && sb->s_op->statfs) {
 28                         memset(buf, 0, sizeof(struct statfs));
 29                         lock_kernel();
 30                         retval = sb->s_op->statfs(sb, buf);
 31                         unlock_kernel();
 32                 }
 33         }
 34         return retval;
 35 }
 36 
 37 
 38 asmlinkage long sys_statfs(const char * path, struct statfs * buf)
 39 {
 40         struct nameidata nd;
 41         int error;
 42 
 43         error = user_path_walk(path, &nd);
 44         if (!error) {
 45                 struct statfs tmp;
 46                 error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
 47                 if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs)))
 48                         error = -EFAULT;
 49                 path_release(&nd);
 50         }
 51         return error;
 52 }
 53 
 54 asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf)
 55 {
 56         struct file * file;
 57         struct statfs tmp;
 58         int error;
 59 
 60         error = -EBADF;
 61         file = fget(fd);
 62         if (!file)
 63                 goto out;
 64         error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
 65         if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs)))
 66                 error = -EFAULT;
 67         fput(file);
 68 out:
 69         return error;
 70 }
 71 
 72 int do_truncate(struct dentry *dentry, loff_t length)
 73 {
 74         struct inode *inode = dentry->d_inode;
 75         int error;
 76         struct iattr newattrs;
 77 
 78         /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
 79         if (length < 0)
 80                 return -EINVAL;
 81 
 82         down(&inode->i_sem);
 83         newattrs.ia_size = length;
 84         newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
 85         error = notify_change(dentry, &newattrs);
 86         up(&inode->i_sem);
 87         return error;
 88 }
 89 
 90 static inline long do_sys_truncate(const char * path, loff_t length)
 91 {
 92         struct nameidata nd;
 93         struct inode * inode;
 94         int error;
 95 
 96         error = -EINVAL;
 97         if (length < 0) /* sorry, but loff_t says... */
 98                 goto out;
 99 
100         error = user_path_walk(path, &nd);
101         if (error)
102                 goto out;
103         inode = nd.dentry->d_inode;
104 
105         error = -EACCES;
106         if (!S_ISREG(inode->i_mode))
107                 goto dput_and_out;
108 
109         error = permission(inode,MAY_WRITE);
110         if (error)
111                 goto dput_and_out;
112 
113         error = -EROFS;
114         if (IS_RDONLY(inode))
115                 goto dput_and_out;
116 
117         error = -EPERM;
118         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
119                 goto dput_and_out;
120 
121         /*
122          * Make sure that there are no leases.
123          */
124         error = get_lease(inode, FMODE_WRITE);
125         if (error)
126                 goto dput_and_out;
127 
128         error = get_write_access(inode);
129         if (error)
130                 goto dput_and_out;
131 
132         error = locks_verify_truncate(inode, NULL, length);
133         if (!error) {
134                 DQUOT_INIT(inode);
135                 error = do_truncate(nd.dentry, length);
136         }
137         put_write_access(inode);
138 
139 dput_and_out:
140         path_release(&nd);
141 out:
142         return error;
143 }
144 
145 asmlinkage long sys_truncate(const char * path, unsigned long length)
146 {
147         return do_sys_truncate(path, length);
148 }
149 
150 static inline long do_sys_ftruncate(unsigned int fd, loff_t length)
151 {
152         struct inode * inode;
153         struct dentry *dentry;
154         struct file * file;
155         int error;
156 
157         error = -EINVAL;
158         if (length < 0)
159                 goto out;
160         error = -EBADF;
161         file = fget(fd);
162         if (!file)
163                 goto out;
164         dentry = file->f_dentry;
165         inode = dentry->d_inode;
166         error = -EACCES;
167         if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
168                 goto out_putf;
169         error = -EPERM;
170         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
171                 goto out_putf;
172 
173         error = locks_verify_truncate(inode, file, length);
174         if (!error)
175                 error = do_truncate(dentry, length);
176 out_putf:
177         fput(file);
178 out:
179         return error;
180 }
181 
182 asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length)
183 {
184         return do_sys_ftruncate(fd, length);
185 }
186 
187 /* LFS versions of truncate are only needed on 32 bit machines */
188 #if BITS_PER_LONG == 32
189 asmlinkage long sys_truncate64(const char * path, loff_t length)
190 {
191         return do_sys_truncate(path, length);
192 }
193 
194 asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
195 {
196         return do_sys_ftruncate(fd, length);
197 }
198 #endif
199 
200 #if !(defined(__alpha__) || defined(__ia64__))
201 
202 /*
203  * sys_utime() can be implemented in user-level using sys_utimes().
204  * Is this for backwards compatibility?  If so, why not move it
205  * into the appropriate arch directory (for those architectures that
206  * need it).
207  */
208 
209 /* If times==NULL, set access and modification to current time,
210  * must be owner or have write permission.
211  * Else, update from *times, must be owner or super user.
212  */
213 asmlinkage long sys_utime(char * filename, struct utimbuf * times)
214 {
215         int error;
216         struct nameidata nd;
217         struct inode * inode;
218         struct iattr newattrs;
219 
220         error = user_path_walk(filename, &nd);
221         if (error)
222                 goto out;
223         inode = nd.dentry->d_inode;
224 
225         error = -EROFS;
226         if (IS_RDONLY(inode))
227                 goto dput_and_out;
228 
229         /* Don't worry, the checks are done in inode_change_ok() */
230         newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
231         if (times) {
232                 error = get_user(newattrs.ia_atime, &times->actime);
233                 if (!error) 
234                         error = get_user(newattrs.ia_mtime, &times->modtime);
235                 if (error)
236                         goto dput_and_out;
237 
238                 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
239         } else {
240                 if (current->fsuid != inode->i_uid &&
241                     (error = permission(inode,MAY_WRITE)) != 0)
242                         goto dput_and_out;
243         }
244         error = notify_change(nd.dentry, &newattrs);
245 dput_and_out:
246         path_release(&nd);
247 out:
248         return error;
249 }
250 
251 #endif
252 
253 /* If times==NULL, set access and modification to current time,
254  * must be owner or have write permission.
255  * Else, update from *times, must be owner or super user.
256  */
257 asmlinkage long sys_utimes(char * filename, struct timeval * utimes)
258 {
259         int error;
260         struct nameidata nd;
261         struct inode * inode;
262         struct iattr newattrs;
263 
264         error = user_path_walk(filename, &nd);
265 
266         if (error)
267                 goto out;
268         inode = nd.dentry->d_inode;
269 
270         error = -EROFS;
271         if (IS_RDONLY(inode))
272                 goto dput_and_out;
273 
274         /* Don't worry, the checks are done in inode_change_ok() */
275         newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
276         if (utimes) {
277                 struct timeval times[2];
278                 error = -EFAULT;
279                 if (copy_from_user(&times, utimes, sizeof(times)))
280                         goto dput_and_out;
281                 newattrs.ia_atime = times[0].tv_sec;
282                 newattrs.ia_mtime = times[1].tv_sec;
283                 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
284         } else {
285                 if ((error = permission(inode,MAY_WRITE)) != 0)
286                         goto dput_and_out;
287         }
288         error = notify_change(nd.dentry, &newattrs);
289 dput_and_out:
290         path_release(&nd);
291 out:
292         return error;
293 }
294 
295 /*
296  * access() needs to use the real uid/gid, not the effective uid/gid.
297  * We do this by temporarily clearing all FS-related capabilities and
298  * switching the fsuid/fsgid around to the real ones.
299  */
300 asmlinkage long sys_access(const char * filename, int mode)
301 {
302         struct nameidata nd;
303         int old_fsuid, old_fsgid;
304         kernel_cap_t old_cap;
305         int res;
306 
307         if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
308                 return -EINVAL;
309 
310         old_fsuid = current->fsuid;
311         old_fsgid = current->fsgid;
312         old_cap = current->cap_effective;
313 
314         current->fsuid = current->uid;
315         current->fsgid = current->gid;
316 
317         /* Clear the capabilities if we switch to a non-root user */
318         if (current->uid)
319                 cap_clear(current->cap_effective);
320         else
321                 current->cap_effective = current->cap_permitted;
322 
323         res = user_path_walk(filename, &nd);
324         if (!res) {
325                 res = permission(nd.dentry->d_inode, mode);
326                 /* SuS v2 requires we report a read only fs too */
327                 if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
328                    && !special_file(nd.dentry->d_inode->i_mode))
329                         res = -EROFS;
330                 path_release(&nd);
331         }
332 
333         current->fsuid = old_fsuid;
334         current->fsgid = old_fsgid;
335         current->cap_effective = old_cap;
336 
337         return res;
338 }
339 
340 asmlinkage long sys_chdir(const char * filename)
341 {
342         int error;
343         struct nameidata nd;
344         char *name;
345 
346         name = getname(filename);
347         error = PTR_ERR(name);
348         if (IS_ERR(name))
349                 goto out;
350 
351         error = 0;
352         if (path_init(name,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd))
353                 error = path_walk(name, &nd);
354         putname(name);
355         if (error)
356                 goto out;
357 
358         error = permission(nd.dentry->d_inode,MAY_EXEC);
359         if (error)
360                 goto dput_and_out;
361 
362         set_fs_pwd(current->fs, nd.mnt, nd.dentry);
363 
364 dput_and_out:
365         path_release(&nd);
366 out:
367         return error;
368 }
369 
370 asmlinkage long sys_fchdir(unsigned int fd)
371 {
372         struct file *file;
373         struct dentry *dentry;
374         struct inode *inode;
375         struct vfsmount *mnt;
376         int error;
377 
378         error = -EBADF;
379         file = fget(fd);
380         if (!file)
381                 goto out;
382 
383         dentry = file->f_dentry;
384         mnt = file->f_vfsmnt;
385         inode = dentry->d_inode;
386 
387         error = -ENOTDIR;
388         if (!S_ISDIR(inode->i_mode))
389                 goto out_putf;
390 
391         error = permission(inode, MAY_EXEC);
392         if (!error)
393                 set_fs_pwd(current->fs, mnt, dentry);
394 out_putf:
395         fput(file);
396 out:
397         return error;
398 }
399 
400 asmlinkage long sys_chroot(const char * filename)
401 {
402         int error;
403         struct nameidata nd;
404         char *name;
405 
406         name = getname(filename);
407         error = PTR_ERR(name);
408         if (IS_ERR(name))
409                 goto out;
410 
411         path_init(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
412                       LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
413         error = path_walk(name, &nd);   
414         putname(name);
415         if (error)
416                 goto out;
417 
418         error = permission(nd.dentry->d_inode,MAY_EXEC);
419         if (error)
420                 goto dput_and_out;
421 
422         error = -EPERM;
423         if (!capable(CAP_SYS_CHROOT))
424                 goto dput_and_out;
425 
426         set_fs_root(current->fs, nd.mnt, nd.dentry);
427         set_fs_altroot();
428         error = 0;
429 dput_and_out:
430         path_release(&nd);
431 out:
432         return error;
433 }
434 
435 asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
436 {
437         struct inode * inode;
438         struct dentry * dentry;
439         struct file * file;
440         int err = -EBADF;
441         struct iattr newattrs;
442 
443         file = fget(fd);
444         if (!file)
445                 goto out;
446 
447         dentry = file->f_dentry;
448         inode = dentry->d_inode;
449 
450         err = -EROFS;
451         if (IS_RDONLY(inode))
452                 goto out_putf;
453         err = -EPERM;
454         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
455                 goto out_putf;
456         if (mode == (mode_t) -1)
457                 mode = inode->i_mode;
458         newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
459         newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
460         err = notify_change(dentry, &newattrs);
461 
462 out_putf:
463         fput(file);
464 out:
465         return err;
466 }
467 
468 asmlinkage long sys_chmod(const char * filename, mode_t mode)
469 {
470         struct nameidata nd;
471         struct inode * inode;
472         int error;
473         struct iattr newattrs;
474 
475         error = user_path_walk(filename, &nd);
476         if (error)
477                 goto out;
478         inode = nd.dentry->d_inode;
479 
480         error = -EROFS;
481         if (IS_RDONLY(inode))
482                 goto dput_and_out;
483 
484         error = -EPERM;
485         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
486                 goto dput_and_out;
487 
488         if (mode == (mode_t) -1)
489                 mode = inode->i_mode;
490         newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
491         newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
492         error = notify_change(nd.dentry, &newattrs);
493 
494 dput_and_out:
495         path_release(&nd);
496 out:
497         return error;
498 }
499 
500 static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
501 {
502         struct inode * inode;
503         int error;
504         struct iattr newattrs;
505 
506         error = -ENOENT;
507         if (!(inode = dentry->d_inode)) {
508                 printk("chown_common: NULL inode\n");
509                 goto out;
510         }
511         error = -EROFS;
512         if (IS_RDONLY(inode))
513                 goto out;
514         error = -EPERM;
515         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
516                 goto out;
517         if (user == (uid_t) -1)
518                 user = inode->i_uid;
519         if (group == (gid_t) -1)
520                 group = inode->i_gid;
521         newattrs.ia_mode = inode->i_mode;
522         newattrs.ia_uid = user;
523         newattrs.ia_gid = group;
524         newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
525         /*
526          * If the user or group of a non-directory has been changed by a
527          * non-root user, remove the setuid bit.
528          * 19981026     David C Niemi <niemi@tux.org>
529          *
530          * Changed this to apply to all users, including root, to avoid
531          * some races. This is the behavior we had in 2.0. The check for
532          * non-root was definitely wrong for 2.2 anyway, as it should
533          * have been using CAP_FSETID rather than fsuid -- 19990830 SD.
534          */
535         if ((inode->i_mode & S_ISUID) == S_ISUID &&
536                 !S_ISDIR(inode->i_mode))
537         {
538                 newattrs.ia_mode &= ~S_ISUID;
539                 newattrs.ia_valid |= ATTR_MODE;
540         }
541         /*
542          * Likewise, if the user or group of a non-directory has been changed
543          * by a non-root user, remove the setgid bit UNLESS there is no group
544          * execute bit (this would be a file marked for mandatory locking).
545          * 19981026     David C Niemi <niemi@tux.org>
546          *
547          * Removed the fsuid check (see the comment above) -- 19990830 SD.
548          */
549         if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) 
550                 && !S_ISDIR(inode->i_mode))
551         {
552                 newattrs.ia_mode &= ~S_ISGID;
553                 newattrs.ia_valid |= ATTR_MODE;
554         }
555         error = DQUOT_TRANSFER(dentry, &newattrs);
556 out:
557         return error;
558 }
559 
560 asmlinkage long sys_chown(const char * filename, uid_t user, gid_t group)
561 {
562         struct nameidata nd;
563         int error;
564 
565         error = user_path_walk(filename, &nd);
566         if (!error) {
567                 error = chown_common(nd.dentry, user, group);
568                 path_release(&nd);
569         }
570         return error;
571 }
572 
573 asmlinkage long sys_lchown(const char * filename, uid_t user, gid_t group)
574 {
575         struct nameidata nd;
576         int error;
577 
578         error = user_path_walk_link(filename, &nd);
579         if (!error) {
580                 error = chown_common(nd.dentry, user, group);
581                 path_release(&nd);
582         }
583         return error;
584 }
585 
586 
587 asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
588 {
589         struct file * file;
590         int error = -EBADF;
591 
592         file = fget(fd);
593         if (file) {
594                 error = chown_common(file->f_dentry, user, group);
595                 fput(file);
596         }
597         return error;
598 }
599 
600 /*
601  * Note that while the flag value (low two bits) for sys_open means:
602  *      00 - read-only
603  *      01 - write-only
604  *      10 - read-write
605  *      11 - special
606  * it is changed into
607  *      00 - no permissions needed
608  *      01 - read-permission
609  *      10 - write-permission
610  *      11 - read-write
611  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
612  * used by symlinks.
613  */
614 struct file *filp_open(const char * filename, int flags, int mode)
615 {
616         int namei_flags, error;
617         struct nameidata nd;
618 
619         namei_flags = flags;
620         if ((namei_flags+1) & O_ACCMODE)
621                 namei_flags++;
622         if (namei_flags & O_TRUNC)
623                 namei_flags |= 2;
624 
625         error = open_namei(filename, namei_flags, mode, &nd);
626         if (!error)
627                 return dentry_open(nd.dentry, nd.mnt, flags);
628 
629         return ERR_PTR(error);
630 }
631 
632 struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
633 {
634         struct file * f;
635         struct inode *inode;
636         int error;
637 
638         error = -ENFILE;
639         f = get_empty_filp();
640         if (!f)
641                 goto cleanup_dentry;
642         f->f_flags = flags;
643         f->f_mode = (flags+1) & O_ACCMODE;
644         inode = dentry->d_inode;
645         if (f->f_mode & FMODE_WRITE) {
646                 error = get_write_access(inode);
647                 if (error)
648                         goto cleanup_file;
649         }
650 
651         f->f_dentry = dentry;
652         f->f_vfsmnt = mnt;
653         f->f_pos = 0;
654         f->f_reada = 0;
655         f->f_op = fops_get(inode->i_fop);
656         if (inode->i_sb)
657                 file_move(f, &inode->i_sb->s_files);
658         if (f->f_op && f->f_op->open) {
659                 error = f->f_op->open(inode,f);
660                 if (error)
661                         goto cleanup_all;
662         }
663         f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
664 
665         return f;
666 
667 cleanup_all:
668         fops_put(f->f_op);
669         if (f->f_mode & FMODE_WRITE)
670                 put_write_access(inode);
671         f->f_dentry = NULL;
672         f->f_vfsmnt = NULL;
673 cleanup_file:
674         put_filp(f);
675 cleanup_dentry:
676         dput(dentry);
677         mntput(mnt);
678         return ERR_PTR(error);
679 }
680 
681 /*
682  * Find an empty file descriptor entry, and mark it busy.
683  */
684 int get_unused_fd(void)
685 {
686         struct files_struct * files = current->files;
687         int fd, error;
688 
689         error = -EMFILE;
690         write_lock(&files->file_lock);
691 
692 repeat:
693         fd = find_next_zero_bit(files->open_fds, 
694                                 files->max_fdset, 
695                                 files->next_fd);
696 
697         /*
698          * N.B. For clone tasks sharing a files structure, this test
699          * will limit the total number of files that can be opened.
700          */
701         if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
702                 goto out;
703 
704         /* Do we need to expand the fdset array? */
705         if (fd >= files->max_fdset) {
706                 error = expand_fdset(files, fd);
707                 if (!error) {
708                         error = -EMFILE;
709                         goto repeat;
710                 }
711                 goto out;
712         }
713         
714         /* 
715          * Check whether we need to expand the fd array.
716          */
717         if (fd >= files->max_fds) {
718                 error = expand_fd_array(files, fd);
719                 if (!error) {
720                         error = -EMFILE;
721                         goto repeat;
722                 }
723                 goto out;
724         }
725 
726         FD_SET(fd, files->open_fds);
727         FD_CLR(fd, files->close_on_exec);
728         files->next_fd = fd + 1;
729 #if 1
730         /* Sanity check */
731         if (files->fd[fd] != NULL) {
732                 printk("get_unused_fd: slot %d not NULL!\n", fd);
733                 files->fd[fd] = NULL;
734         }
735 #endif
736         error = fd;
737 
738 out:
739         write_unlock(&files->file_lock);
740         return error;
741 }
742 
743 asmlinkage long sys_open(const char * filename, int flags, int mode)
744 {
745         char * tmp;
746         int fd, error;
747 
748 #if BITS_PER_LONG != 32
749         flags |= O_LARGEFILE;
750 #endif
751         tmp = getname(filename);
752         fd = PTR_ERR(tmp);
753         if (!IS_ERR(tmp)) {
754                 fd = get_unused_fd();
755                 if (fd >= 0) {
756                         struct file *f = filp_open(tmp, flags, mode);
757                         error = PTR_ERR(f);
758                         if (IS_ERR(f))
759                                 goto out_error;
760                         fd_install(fd, f);
761                 }
762 out:
763                 putname(tmp);
764         }
765         return fd;
766 
767 out_error:
768         put_unused_fd(fd);
769         fd = error;
770         goto out;
771 }
772 
773 #ifndef __alpha__
774 
775 /*
776  * For backward compatibility?  Maybe this should be moved
777  * into arch/i386 instead?
778  */
779 asmlinkage long sys_creat(const char * pathname, int mode)
780 {
781         return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
782 }
783 
784 #endif
785 
786 /*
787  * "id" is the POSIX thread ID. We use the
788  * files pointer for this..
789  */
790 int filp_close(struct file *filp, fl_owner_t id)
791 {
792         int retval;
793 
794         if (!file_count(filp)) {
795                 printk("VFS: Close: file count is 0\n");
796                 return 0;
797         }
798         retval = 0;
799         if (filp->f_op && filp->f_op->flush) {
800                 lock_kernel();
801                 retval = filp->f_op->flush(filp);
802                 unlock_kernel();
803         }
804         fcntl_dirnotify(0, filp, 0);
805         locks_remove_posix(filp, id);
806         fput(filp);
807         return retval;
808 }
809 
810 /*
811  * Careful here! We test whether the file pointer is NULL before
812  * releasing the fd. This ensures that one clone task can't release
813  * an fd while another clone is opening it.
814  */
815 asmlinkage long sys_close(unsigned int fd)
816 {
817         struct file * filp;
818         struct files_struct *files = current->files;
819 
820         write_lock(&files->file_lock);
821         if (fd >= files->max_fds)
822                 goto out_unlock;
823         filp = files->fd[fd];
824         if (!filp)
825                 goto out_unlock;
826         files->fd[fd] = NULL;
827         FD_CLR(fd, files->close_on_exec);
828         __put_unused_fd(files, fd);
829         write_unlock(&files->file_lock);
830         return filp_close(filp, files);
831 
832 out_unlock:
833         write_unlock(&files->file_lock);
834         return -EBADF;
835 }
836 
837 /*
838  * This routine simulates a hangup on the tty, to arrange that users
839  * are given clean terminals at login time.
840  */
841 asmlinkage long sys_vhangup(void)
842 {
843         if (capable(CAP_SYS_TTY_CONFIG)) {
844                 tty_vhangup(current->tty);
845                 return 0;
846         }
847         return -EPERM;
848 }
849 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.