1 /* This file contains the procedures for creating, opening, closing, and
4 * The entry points into this file are
5 * do_open: perform the OPEN system call
6 * do_mknod: perform the MKNOD system call
7 * do_mkdir: perform the MKDIR system call
8 * do_close: perform the CLOSE system call
9 * do_lseek: perform the LSEEK system call
17 #include <minix/callnr.h>
18 #include <minix/com.h>
19 #include <minix/u64.h>
22 #include <sys/dirent.h>
24 #include <minix/vfsif.h>
29 static char mode_map
[] = {R_BIT
, W_BIT
, R_BIT
|W_BIT
, 0};
31 static struct vnode
*new_node(struct lookup
*resolve
, int oflags
,
33 static int pipe_open(int fd
, struct vnode
*vp
, mode_t bits
, int oflags
);
35 /*===========================================================================*
37 *===========================================================================*/
40 /* Perform the open(name, flags) system call with O_CREAT *not* set. */
42 char fullpath
[PATH_MAX
];
44 open_flags
= job_m_in
.m_lc_vfs_path
.flags
;
46 if (open_flags
& O_CREAT
)
49 if (copy_path(fullpath
, sizeof(fullpath
)) != OK
)
52 return common_open(fullpath
, open_flags
, 0 /*omode*/, FALSE
/*for_exec*/);
55 /*===========================================================================*
57 *===========================================================================*/
60 /* Perform the open(name, flags, mode) system call with O_CREAT set. */
61 int open_flags
, create_mode
;
62 char fullpath
[PATH_MAX
];
66 vname
= job_m_in
.m_lc_vfs_creat
.name
;
67 vname_length
= job_m_in
.m_lc_vfs_creat
.len
;
68 open_flags
= job_m_in
.m_lc_vfs_creat
.flags
;
69 create_mode
= job_m_in
.m_lc_vfs_creat
.mode
;
71 if (!(open_flags
& O_CREAT
))
74 if (fetch_name(vname
, vname_length
, fullpath
) != OK
)
77 return common_open(fullpath
, open_flags
, create_mode
, FALSE
/*for_exec*/);
80 /*===========================================================================*
82 *===========================================================================*/
83 int common_open(char path
[PATH_MAX
], int oflags
, mode_t omode
, int for_exec
)
85 /* Common code from do_creat and do_open. */
86 int b
, r
, exist
= TRUE
;
90 struct filp
*filp
, *filp2
;
94 struct lookup resolve
;
97 /* Remap the bottom two bits of oflags. */
98 bits
= (mode_t
) mode_map
[oflags
& O_ACCMODE
];
99 if (!bits
) return(EINVAL
);
101 /* See if file descriptor and filp slots are available. */
102 if ((r
= get_fd(fp
, start
, bits
, &fd
, &filp
)) != OK
)
105 lookup_init(&resolve
, path
, PATH_NOFLAGS
, &vmp
, &vp
);
107 /* If O_CREATE is set, try to make the file. */
108 if (oflags
& O_CREAT
) {
109 omode
= I_REGULAR
| (omode
& ALLPERMS
& fp
->fp_umask
);
110 vp
= new_node(&resolve
, oflags
, omode
);
112 if (r
== OK
) exist
= FALSE
; /* We just created the file */
113 else if (r
!= EEXIST
) { /* other error */
114 if (vp
) unlock_vnode(vp
);
118 else exist
= !(oflags
& O_EXCL
);/* file exists, if the O_EXCL
119 flag is set this is an error */
122 resolve
.l_vmnt_lock
= VMNT_READ
;
123 resolve
.l_vnode_lock
= VNODE_OPCL
;
124 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) {
129 if (vmp
!= NULL
) unlock_vmnt(vmp
);
132 /* Claim the file descriptor and filp slot and fill them in. */
133 fp
->fp_filp
[fd
] = filp
;
134 filp
->filp_count
= 1;
136 filp
->filp_flags
= oflags
;
137 if (oflags
& O_CLOEXEC
)
138 FD_SET(fd
, &fp
->fp_cloexec_set
);
140 /* Only do the normal open code if we didn't just create the file. */
142 /* Check permissions based on the given open flags, except when we are
143 * opening an executable for the purpose of passing a file descriptor
144 * to its interpreter for execution, in which case we check the X bit.
146 if ((r
= forbidden(fp
, vp
, for_exec
? X_BIT
: bits
)) == OK
) {
147 /* Opening reg. files, directories, and special files differ */
148 switch (vp
->v_mode
& S_IFMT
) {
150 /* Truncate regular file if O_TRUNC. */
151 if (oflags
& O_TRUNC
) {
152 if ((r
= forbidden(fp
, vp
, W_BIT
)) != OK
)
154 upgrade_vnode_lock(vp
);
155 truncate_vnode(vp
, 0);
159 /* Directories may be read but not written. */
160 r
= (bits
& W_BIT
? EISDIR
: OK
);
163 /* Invoke the driver for special processing. */
165 /* TTY needs to know about the O_NOCTTY flag. */
166 r
= cdev_open(fd
, dev
, bits
| (oflags
& O_NOCTTY
));
167 vp
= filp
->filp_vno
; /* Might be updated by
168 * cdev_open after cloning */
174 /* Invoke the driver for special processing. */
176 r
= bdev_open(dev
, bits
);
182 major_dev
= major(vp
->v_sdev
);
183 dp
= &dmap
[major_dev
];
184 if (dp
->dmap_driver
== NONE
) {
185 printf("VFS: block driver disappeared!\n");
191 /* Check whether the device is mounted or not. If so,
192 * then that FS is responsible for this device.
193 * Otherwise we default to ROOT_FS.
195 vp
->v_bfs_e
= ROOT_FS_E
; /* By default */
196 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
)
197 if (vmp
->m_dev
== vp
->v_sdev
&&
198 !(vmp
->m_flags
& VMNT_FORCEROOTBSF
)) {
199 vp
->v_bfs_e
= vmp
->m_fs_e
;
202 /* Send the driver label to the file system that will
203 * handle the block I/O requests (even when its label
204 * and endpoint are known already), but only when it is
205 * the root file system. Other file systems will
206 * already have it anyway.
208 if (vp
->v_bfs_e
!= ROOT_FS_E
) {
213 if (req_newdriver(vp
->v_bfs_e
, vp
->v_sdev
,
214 dp
->dmap_label
) != OK
) {
215 printf("VFS: error sending driver label\n");
223 /* Create a mapped inode on PFS which handles reads
224 and writes to this named pipe. */
225 upgrade_vnode_lock(vp
);
226 r
= map_vnode(vp
, PFS_PROC_NR
);
228 if (vp
->v_ref_count
== 1) {
230 r
= truncate_vnode(vp
, 0);
232 oflags
|= O_APPEND
; /* force append mode */
233 filp
->filp_flags
= oflags
;
236 r
= pipe_open(fd
, vp
, bits
, oflags
);
239 /* See if someone else is doing a rd or wt on
240 * the FIFO. If so, use its filp entry so the
241 * file position will be automatically shared.
243 b
= (bits
& R_BIT
? R_BIT
: W_BIT
);
244 filp
->filp_count
= 0; /* don't find self */
245 if ((filp2
= find_filp(vp
, b
)) != NULL
) {
246 /* Co-reader or writer found. Use it.*/
247 fp
->fp_filp
[fd
] = filp2
;
249 filp2
->filp_vno
= vp
;
250 filp2
->filp_flags
= oflags
;
252 /* v_count was incremented after the vnode
253 * has been found. i_count was incremented
254 * incorrectly in FS, not knowing that we
255 * were going to use an existing filp
256 * entry. Correct this error.
261 /* Nobody else found. Restore filp. */
262 filp
->filp_count
= 1;
270 printf("VFS: attempt to open file <%llu,%llu> of "
271 "type 0%o\n", vp
->v_dev
, vp
->v_inode_nr
,
272 vp
->v_mode
& S_IFMT
);
280 /* If error, release inode. */
283 fp
->fp_filp
[fd
] = NULL
;
284 filp
->filp_count
= 0;
285 filp
->filp_vno
= NULL
;
296 /*===========================================================================*
298 *===========================================================================*/
299 static struct vnode
*new_node(struct lookup
*resolve
, int oflags
, mode_t bits
)
301 /* Try to create a new inode and return a pointer to it. If the inode already
302 exists, return a pointer to it as well, but set err_code accordingly.
303 NULL is returned if the path cannot be resolved up to the last
304 directory, or when the inode cannot be created due to permissions or
306 struct vnode
*dirp
, *vp
;
307 struct vmnt
*dir_vmp
, *vp_vmp
;
309 struct node_details res
;
310 struct lookup findnode
;
313 path
= resolve
->l_path
; /* For easy access */
315 lookup_init(&findnode
, path
, resolve
->l_flags
, &dir_vmp
, &dirp
);
316 findnode
.l_vmnt_lock
= VMNT_WRITE
;
317 findnode
.l_vnode_lock
= VNODE_WRITE
; /* dir node */
319 /* When O_CREAT and O_EXCL flags are set, the path may not be named by a
321 if (oflags
& O_EXCL
) findnode
.l_flags
|= PATH_RET_SYMLINK
;
323 /* See if the path can be opened down to the last directory. */
324 if ((dirp
= last_dir(&findnode
, fp
)) == NULL
) return(NULL
);
326 /* The final directory is accessible. Get final component of the path. */
327 lookup_init(&findnode
, findnode
.l_path
, findnode
.l_flags
, &vp_vmp
, &vp
);
328 findnode
.l_vmnt_lock
= VMNT_WRITE
;
329 findnode
.l_vnode_lock
= (oflags
& O_TRUNC
) ? VNODE_WRITE
: VNODE_OPCL
;
330 vp
= advance(dirp
, &findnode
, fp
);
331 assert(vp_vmp
== NULL
); /* Lookup to last dir should have yielded lock
332 * on vmp or final component does not exist.
333 * Either way, vp_vmp ought to be not set.
336 /* The combination of a symlink with absolute path followed by a danglink
337 * symlink results in a new path that needs to be re-resolved entirely. */
338 if (path
[0] == '/') {
340 unlock_vmnt(dir_vmp
);
346 return new_node(resolve
, oflags
, bits
);
349 if (vp
== NULL
&& err_code
== ENOENT
) {
350 /* Last path component does not exist. Make a new directory entry. */
351 if ((vp
= get_free_vnode()) == NULL
) {
352 /* Can't create new entry: out of vnodes. */
354 unlock_vmnt(dir_vmp
);
359 lock_vnode(vp
, VNODE_OPCL
);
360 upgrade_vmnt_lock(dir_vmp
); /* Creating file, need exclusive access */
362 if ((r
= forbidden(fp
, dirp
, W_BIT
|X_BIT
)) != OK
||
363 (r
= req_create(dirp
->v_fs_e
, dirp
->v_inode_nr
,bits
, fp
->fp_effuid
,
364 fp
->fp_effgid
, path
, &res
)) != OK
) {
365 /* Can't create inode either due to permissions or some other
366 * problem. In case r is EEXIST, we might be dealing with a
367 * dangling symlink.*/
369 /* Downgrade lock to prevent deadlock during symlink resolving*/
370 downgrade_vmnt_lock(dir_vmp
);
373 struct vnode
*slp
, *old_wd
;
376 /* Resolve path up to symlink */
377 findnode
.l_flags
= PATH_RET_SYMLINK
;
378 findnode
.l_vnode_lock
= VNODE_READ
;
379 findnode
.l_vnode
= &slp
;
380 slp
= advance(dirp
, &findnode
, fp
);
382 if (S_ISLNK(slp
->v_mode
)) {
383 /* Get contents of link */
385 r
= req_rdlink(slp
->v_fs_e
,
391 /* Failed to read link */
394 unlock_vmnt(dir_vmp
);
400 path
[r
] = '\0'; /* Terminate path */
406 /* Try to create the inode the dangling symlink was
407 * pointing to. We have to use dirp as starting point
408 * as there might be multiple successive symlinks
409 * crossing multiple mountpoints.
410 * Unlock vnodes and vmnts as we're going to recurse.
414 unlock_vmnt(dir_vmp
);
416 old_wd
= fp
->fp_wd
; /* Save orig. working dirp */
418 vp
= new_node(resolve
, oflags
, bits
);
419 fp
->fp_wd
= old_wd
; /* Restore */
423 *(resolve
->l_vnode
) = vp
;
430 err_code
= EIO
; /* Impossible, we have verified that
431 * the last component doesn't exist and
432 * is not a dangling symlink. */
436 unlock_vmnt(dir_vmp
);
443 /* Store results and mark vnode in use */
445 vp
->v_fs_e
= res
.fs_e
;
446 vp
->v_inode_nr
= res
.inode_nr
;
447 vp
->v_mode
= res
.fmode
;
448 vp
->v_size
= res
.fsize
;
451 vp
->v_sdev
= res
.dev
;
452 vp
->v_vmnt
= dirp
->v_vmnt
;
453 vp
->v_dev
= vp
->v_vmnt
->m_dev
;
457 /* Either last component exists, or there is some other problem. */
459 r
= EEXIST
; /* File exists or a symlink names a file while
462 r
= err_code
; /* Other problem. */
466 /* When dirp equals vp, we shouldn't release the lock as a vp is locked only
467 * once. Releasing the lock would cause the resulting vp not be locked and
468 * cause mayhem later on. */
472 unlock_vmnt(dir_vmp
);
475 *(resolve
->l_vnode
) = vp
;
480 /*===========================================================================*
482 *===========================================================================*/
483 static int pipe_open(int fd
, struct vnode
*vp
, mode_t bits
, int oflags
)
485 /* This function is called from common_open. It checks if
486 * there is at least one reader/writer pair for the pipe, if not
487 * it suspends the caller, otherwise it revives all other blocked
488 * processes hanging on the pipe.
491 if ((bits
& (R_BIT
|W_BIT
)) == (R_BIT
|W_BIT
)) return(ENXIO
);
493 /* Find the reader/writer at the other end of the pipe */
494 if (find_filp(vp
, bits
& W_BIT
? R_BIT
: W_BIT
) == NULL
) {
496 if (oflags
& O_NONBLOCK
) {
497 if (bits
& W_BIT
) return(ENXIO
);
499 /* Let's wait for the other side to show up */
500 fp
->fp_popen
.fd
= fd
;
501 suspend(FP_BLOCKED_ON_POPEN
);
504 } else if (susp_count
> 0) { /* revive blocked processes */
505 release(vp
, VFS_OPEN
, susp_count
);
511 /*===========================================================================*
513 *===========================================================================*/
516 /* Perform the mknod(name, mode, addr) system call. */
517 register mode_t bits
, mode_bits
;
521 char fullpath
[PATH_MAX
];
522 struct lookup resolve
;
524 size_t vname1_length
;
527 vname1
= job_m_in
.m_lc_vfs_mknod
.name
;
528 vname1_length
= job_m_in
.m_lc_vfs_mknod
.len
;
529 mode_bits
= job_m_in
.m_lc_vfs_mknod
.mode
;
530 dev
= job_m_in
.m_lc_vfs_mknod
.device
;
532 /* If the path names a symbolic link, mknod() shall fail with EEXIST. */
533 lookup_init(&resolve
, fullpath
, PATH_RET_SYMLINK
, &vmp
, &vp
);
534 resolve
.l_vmnt_lock
= VMNT_WRITE
;
535 resolve
.l_vnode_lock
= VNODE_WRITE
;
537 /* Only the super_user may make nodes other than fifos. */
538 if (!super_user
&& !S_ISFIFO(mode_bits
))
541 bits
= (mode_bits
& S_IFMT
) | (mode_bits
& ACCESSPERMS
& fp
->fp_umask
);
543 /* Open directory that's going to hold the new node. */
544 if (fetch_name(vname1
, vname1_length
, fullpath
) != OK
) return(err_code
);
545 if ((vp
= last_dir(&resolve
, fp
)) == NULL
) return(err_code
);
547 /* Make sure that the object is a directory */
548 if (!S_ISDIR(vp
->v_mode
)) {
550 } else if ((r
= forbidden(fp
, vp
, W_BIT
|X_BIT
)) == OK
) {
551 r
= req_mknod(vp
->v_fs_e
, vp
->v_inode_nr
, fullpath
, fp
->fp_effuid
,
552 fp
->fp_effgid
, bits
, dev
);
561 /*===========================================================================*
563 *===========================================================================*/
566 /* Perform the mkdir(name, mode) system call. */
567 mode_t bits
; /* mode bits for the new inode */
571 char fullpath
[PATH_MAX
];
572 struct lookup resolve
;
575 if (copy_path(fullpath
, sizeof(fullpath
)) != OK
)
577 dirmode
= job_m_in
.m_lc_vfs_path
.mode
;
579 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
580 resolve
.l_vmnt_lock
= VMNT_WRITE
;
581 resolve
.l_vnode_lock
= VNODE_WRITE
;
583 bits
= I_DIRECTORY
| (dirmode
& RWX_MODES
& fp
->fp_umask
);
584 if ((vp
= last_dir(&resolve
, fp
)) == NULL
) return(err_code
);
586 /* Make sure that the object is a directory */
587 if (!S_ISDIR(vp
->v_mode
)) {
589 } else if ((r
= forbidden(fp
, vp
, W_BIT
|X_BIT
)) == OK
) {
590 r
= req_mkdir(vp
->v_fs_e
, vp
->v_inode_nr
, fullpath
, fp
->fp_effuid
,
591 fp
->fp_effgid
, bits
);
600 /*===========================================================================*
602 *===========================================================================*/
603 int actual_lseek(struct fproc
*rfp
, int seekfd
, int seekwhence
, off_t offset
,
606 register struct filp
*rfilp
;
610 /* Check to see if the file descriptor is valid. */
611 if ( (rfilp
= get_filp2(rfp
, seekfd
, VNODE_READ
)) == NULL
) {
615 /* No lseek on pipes. */
616 if (S_ISFIFO(rfilp
->filp_vno
->v_mode
)) {
621 /* The value of 'whence' determines the start position to use. */
623 case SEEK_SET
: pos
= 0; break;
624 case SEEK_CUR
: pos
= rfilp
->filp_pos
; break;
625 case SEEK_END
: pos
= rfilp
->filp_vno
->v_size
; break;
626 default: unlock_filp(rfilp
); return(EINVAL
);
629 newpos
= pos
+ offset
;
631 /* Check for overflow. */
632 if ((offset
> 0) && (newpos
<= pos
)) {
634 } else if ((offset
< 0) && (newpos
>= pos
)) {
637 if (newposp
!= NULL
) *newposp
= newpos
;
639 if (newpos
!= rfilp
->filp_pos
) {
640 rfilp
->filp_pos
= newpos
;
642 /* Inhibit read ahead request */
643 r
= req_inhibread(rfilp
->filp_vno
->v_fs_e
,
644 rfilp
->filp_vno
->v_inode_nr
);
652 /*===========================================================================*
654 *===========================================================================*/
657 /* Perform the lseek(2) system call. */
661 if ((r
= actual_lseek(fp
, job_m_in
.m_lc_vfs_lseek
.fd
,
662 job_m_in
.m_lc_vfs_lseek
.whence
, job_m_in
.m_lc_vfs_lseek
.offset
,
666 /* insert the new position into the output message */
667 job_m_out
.m_vfs_lc_lseek
.offset
= newpos
;
671 /*===========================================================================*
673 *===========================================================================*/
676 /* Perform the close(fd) or closenb(fd) system call. */
679 fd
= job_m_in
.m_lc_vfs_close
.fd
;
680 nblock
= job_m_in
.m_lc_vfs_close
.nblock
;
682 return close_fd(fp
, fd
, !nblock
/*may_suspend*/);
686 /*===========================================================================*
688 *===========================================================================*/
690 close_fd(struct fproc
* rfp
, int fd_nr
, int may_suspend
)
692 /* Perform the close(fd) system call. */
693 register struct filp
*rfilp
;
694 register struct vnode
*vp
;
695 struct file_lock
*flp
;
698 /* First locate the vnode that belongs to the file descriptor. */
699 if ( (rfilp
= get_filp2(rfp
, fd_nr
, VNODE_OPCL
)) == NULL
) return(err_code
);
701 vp
= rfilp
->filp_vno
;
703 /* first, make all future get_filp2()'s fail; otherwise
704 * we might try to close the same fd in different threads
706 rfp
->fp_filp
[fd_nr
] = NULL
;
708 r
= close_filp(rfilp
, may_suspend
);
710 FD_CLR(fd_nr
, &rfp
->fp_cloexec_set
);
712 /* Check to see if the file is locked. If so, release all locks. */
714 lock_count
= nr_locks
; /* save count of locks */
715 for (flp
= &file_lock
[0]; flp
< &file_lock
[NR_LOCKS
]; flp
++) {
716 if (flp
->lock_type
== 0) continue; /* slot not in use */
717 if (flp
->lock_vnode
== vp
&& flp
->lock_pid
== rfp
->fp_pid
) {
722 if (nr_locks
< lock_count
)
723 lock_revive(); /* one or more locks released */