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>
21 #include "scratchpad.h"
23 #include <sys/dirent.h>
25 #include <minix/vfsif.h>
30 static char mode_map
[] = {R_BIT
, W_BIT
, R_BIT
|W_BIT
, 0};
32 static struct vnode
*new_node(struct lookup
*resolve
, int oflags
,
34 static int pipe_open(struct vnode
*vp
, mode_t bits
, int oflags
);
36 /*===========================================================================*
38 *===========================================================================*/
41 /* Perform the open(name, flags) system call with O_CREAT *not* set. */
43 char fullpath
[PATH_MAX
];
45 open_flags
= job_m_in
.m_lc_vfs_path
.flags
;
47 if (open_flags
& O_CREAT
)
50 if (copy_path(fullpath
, sizeof(fullpath
)) != OK
)
53 return common_open(fullpath
, open_flags
, 0 /*omode*/);
56 /*===========================================================================*
58 *===========================================================================*/
61 /* Perform the open(name, flags, mode) system call with O_CREAT set. */
62 int open_flags
, create_mode
;
63 char fullpath
[PATH_MAX
];
67 vname
= job_m_in
.m_lc_vfs_creat
.name
;
68 vname_length
= job_m_in
.m_lc_vfs_creat
.len
;
69 open_flags
= job_m_in
.m_lc_vfs_creat
.flags
;
70 create_mode
= job_m_in
.m_lc_vfs_creat
.mode
;
72 if (!(open_flags
& O_CREAT
))
75 if (fetch_name(vname
, vname_length
, fullpath
) != OK
)
78 return common_open(fullpath
, open_flags
, create_mode
);
81 /*===========================================================================*
83 *===========================================================================*/
84 int common_open(char path
[PATH_MAX
], int oflags
, mode_t omode
)
86 /* Common code from do_creat and do_open. */
87 int b
, r
, exist
= TRUE
;
91 struct filp
*filp
, *filp2
;
95 struct lookup resolve
;
98 /* Remap the bottom two bits of oflags. */
99 bits
= (mode_t
) mode_map
[oflags
& O_ACCMODE
];
100 if (!bits
) return(EINVAL
);
102 /* See if file descriptor and filp slots are available. */
103 if ((r
= get_fd(fp
, start
, bits
, &(scratch(fp
).file
.fd_nr
),
107 lookup_init(&resolve
, path
, PATH_NOFLAGS
, &vmp
, &vp
);
109 /* If O_CREATE is set, try to make the file. */
110 if (oflags
& O_CREAT
) {
111 omode
= I_REGULAR
| (omode
& ALLPERMS
& fp
->fp_umask
);
112 vp
= new_node(&resolve
, oflags
, omode
);
114 if (r
== OK
) exist
= FALSE
; /* We just created the file */
115 else if (r
!= EEXIST
) { /* other error */
116 if (vp
) unlock_vnode(vp
);
120 else exist
= !(oflags
& O_EXCL
);/* file exists, if the O_EXCL
121 flag is set this is an error */
124 resolve
.l_vmnt_lock
= VMNT_READ
;
125 resolve
.l_vnode_lock
= VNODE_OPCL
;
126 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) {
131 if (vmp
!= NULL
) unlock_vmnt(vmp
);
134 /* Claim the file descriptor and filp slot and fill them in. */
135 fp
->fp_filp
[scratch(fp
).file
.fd_nr
] = filp
;
136 filp
->filp_count
= 1;
138 filp
->filp_flags
= oflags
;
139 if (oflags
& O_CLOEXEC
)
140 FD_SET(scratch(fp
).file
.fd_nr
, &fp
->fp_cloexec_set
);
142 /* Only do the normal open code if we didn't just create the file. */
144 /* Check protections. */
145 if ((r
= forbidden(fp
, vp
, bits
)) == OK
) {
146 /* Opening reg. files, directories, and special files differ */
147 switch (vp
->v_mode
& S_IFMT
) {
149 /* Truncate regular file if O_TRUNC. */
150 if (oflags
& O_TRUNC
) {
151 if ((r
= forbidden(fp
, vp
, W_BIT
)) != OK
)
153 upgrade_vnode_lock(vp
);
154 truncate_vnode(vp
, 0);
158 /* Directories may be read but not written. */
159 r
= (bits
& W_BIT
? EISDIR
: OK
);
162 /* Invoke the driver for special processing. */
164 /* TTY needs to know about the O_NOCTTY flag. */
165 r
= cdev_open(dev
, bits
| (oflags
& O_NOCTTY
));
166 vp
= filp
->filp_vno
; /* Might be updated by
167 * cdev_open after cloning */
173 /* Invoke the driver for special processing. */
175 r
= bdev_open(dev
, bits
);
181 major_dev
= major(vp
->v_sdev
);
182 dp
= &dmap
[major_dev
];
183 if (dp
->dmap_driver
== NONE
) {
184 printf("VFS: block driver disappeared!\n");
190 /* Check whether the device is mounted or not. If so,
191 * then that FS is responsible for this device.
192 * Otherwise we default to ROOT_FS.
194 vp
->v_bfs_e
= ROOT_FS_E
; /* By default */
195 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
)
196 if (vmp
->m_dev
== vp
->v_sdev
&&
197 !(vmp
->m_flags
& VMNT_FORCEROOTBSF
)) {
198 vp
->v_bfs_e
= vmp
->m_fs_e
;
201 /* Send the driver label to the file system that will
202 * handle the block I/O requests (even when its label
203 * and endpoint are known already), but only when it is
204 * the root file system. Other file systems will
205 * already have it anyway.
207 if (vp
->v_bfs_e
!= ROOT_FS_E
) {
212 if (req_newdriver(vp
->v_bfs_e
, vp
->v_sdev
,
213 dp
->dmap_label
) != OK
) {
214 printf("VFS: error sending driver label\n");
222 /* Create a mapped inode on PFS which handles reads
223 and writes to this named pipe. */
224 upgrade_vnode_lock(vp
);
225 r
= map_vnode(vp
, PFS_PROC_NR
);
227 if (vp
->v_ref_count
== 1) {
229 r
= truncate_vnode(vp
, 0);
231 oflags
|= O_APPEND
; /* force append mode */
232 filp
->filp_flags
= oflags
;
235 r
= pipe_open(vp
, bits
, oflags
);
238 /* See if someone else is doing a rd or wt on
239 * the FIFO. If so, use its filp entry so the
240 * file position will be automatically shared.
242 b
= (bits
& R_BIT
? R_BIT
: W_BIT
);
243 filp
->filp_count
= 0; /* don't find self */
244 if ((filp2
= find_filp(vp
, b
)) != NULL
) {
245 /* Co-reader or writer found. Use it.*/
246 fp
->fp_filp
[scratch(fp
).file
.fd_nr
] = filp2
;
248 filp2
->filp_vno
= vp
;
249 filp2
->filp_flags
= oflags
;
251 /* v_count was incremented after the vnode
252 * has been found. i_count was incremented
253 * incorrectly in FS, not knowing that we
254 * were going to use an existing filp
255 * entry. Correct this error.
260 /* Nobody else found. Restore filp. */
261 filp
->filp_count
= 1;
271 /* If error, release inode. */
274 fp
->fp_filp
[scratch(fp
).file
.fd_nr
] = NULL
;
275 filp
->filp_count
= 0;
276 filp
->filp_vno
= NULL
;
280 r
= scratch(fp
).file
.fd_nr
;
287 /*===========================================================================*
289 *===========================================================================*/
290 static struct vnode
*new_node(struct lookup
*resolve
, int oflags
, mode_t bits
)
292 /* Try to create a new inode and return a pointer to it. If the inode already
293 exists, return a pointer to it as well, but set err_code accordingly.
294 NULL is returned if the path cannot be resolved up to the last
295 directory, or when the inode cannot be created due to permissions or
297 struct vnode
*dirp
, *vp
;
298 struct vmnt
*dir_vmp
, *vp_vmp
;
300 struct node_details res
;
301 struct lookup findnode
;
304 path
= resolve
->l_path
; /* For easy access */
306 lookup_init(&findnode
, path
, resolve
->l_flags
, &dir_vmp
, &dirp
);
307 findnode
.l_vmnt_lock
= VMNT_WRITE
;
308 findnode
.l_vnode_lock
= VNODE_WRITE
; /* dir node */
310 /* When O_CREAT and O_EXCL flags are set, the path may not be named by a
312 if (oflags
& O_EXCL
) findnode
.l_flags
|= PATH_RET_SYMLINK
;
314 /* See if the path can be opened down to the last directory. */
315 if ((dirp
= last_dir(&findnode
, fp
)) == NULL
) return(NULL
);
317 /* The final directory is accessible. Get final component of the path. */
318 lookup_init(&findnode
, findnode
.l_path
, findnode
.l_flags
, &vp_vmp
, &vp
);
319 findnode
.l_vmnt_lock
= VMNT_WRITE
;
320 findnode
.l_vnode_lock
= (oflags
& O_TRUNC
) ? VNODE_WRITE
: VNODE_OPCL
;
321 vp
= advance(dirp
, &findnode
, fp
);
322 assert(vp_vmp
== NULL
); /* Lookup to last dir should have yielded lock
323 * on vmp or final component does not exist.
324 * Either way, vp_vmp ought to be not set.
327 /* The combination of a symlink with absolute path followed by a danglink
328 * symlink results in a new path that needs to be re-resolved entirely. */
329 if (path
[0] == '/') {
331 unlock_vmnt(dir_vmp
);
337 return new_node(resolve
, oflags
, bits
);
340 if (vp
== NULL
&& err_code
== ENOENT
) {
341 /* Last path component does not exist. Make a new directory entry. */
342 if ((vp
= get_free_vnode()) == NULL
) {
343 /* Can't create new entry: out of vnodes. */
345 unlock_vmnt(dir_vmp
);
350 lock_vnode(vp
, VNODE_OPCL
);
351 upgrade_vmnt_lock(dir_vmp
); /* Creating file, need exclusive access */
353 if ((r
= forbidden(fp
, dirp
, W_BIT
|X_BIT
)) != OK
||
354 (r
= req_create(dirp
->v_fs_e
, dirp
->v_inode_nr
,bits
, fp
->fp_effuid
,
355 fp
->fp_effgid
, path
, &res
)) != OK
) {
356 /* Can't create inode either due to permissions or some other
357 * problem. In case r is EEXIST, we might be dealing with a
358 * dangling symlink.*/
360 /* Downgrade lock to prevent deadlock during symlink resolving*/
361 downgrade_vmnt_lock(dir_vmp
);
364 struct vnode
*slp
, *old_wd
;
367 /* Resolve path up to symlink */
368 findnode
.l_flags
= PATH_RET_SYMLINK
;
369 findnode
.l_vnode_lock
= VNODE_READ
;
370 findnode
.l_vnode
= &slp
;
371 slp
= advance(dirp
, &findnode
, fp
);
373 if (S_ISLNK(slp
->v_mode
)) {
374 /* Get contents of link */
376 r
= req_rdlink(slp
->v_fs_e
,
382 /* Failed to read link */
385 unlock_vmnt(dir_vmp
);
391 path
[r
] = '\0'; /* Terminate path */
397 /* Try to create the inode the dangling symlink was
398 * pointing to. We have to use dirp as starting point
399 * as there might be multiple successive symlinks
400 * crossing multiple mountpoints.
401 * Unlock vnodes and vmnts as we're going to recurse.
405 unlock_vmnt(dir_vmp
);
407 old_wd
= fp
->fp_wd
; /* Save orig. working dirp */
409 vp
= new_node(resolve
, oflags
, bits
);
410 fp
->fp_wd
= old_wd
; /* Restore */
414 *(resolve
->l_vnode
) = vp
;
421 err_code
= EIO
; /* Impossible, we have verified that
422 * the last component doesn't exist and
423 * is not a dangling symlink. */
427 unlock_vmnt(dir_vmp
);
434 /* Store results and mark vnode in use */
436 vp
->v_fs_e
= res
.fs_e
;
437 vp
->v_inode_nr
= res
.inode_nr
;
438 vp
->v_mode
= res
.fmode
;
439 vp
->v_size
= res
.fsize
;
442 vp
->v_sdev
= res
.dev
;
443 vp
->v_vmnt
= dirp
->v_vmnt
;
444 vp
->v_dev
= vp
->v_vmnt
->m_dev
;
448 /* Either last component exists, or there is some other problem. */
450 r
= EEXIST
; /* File exists or a symlink names a file while
453 r
= err_code
; /* Other problem. */
457 /* When dirp equals vp, we shouldn't release the lock as a vp is locked only
458 * once. Releasing the lock would cause the resulting vp not be locked and
459 * cause mayhem later on. */
463 unlock_vmnt(dir_vmp
);
466 *(resolve
->l_vnode
) = vp
;
471 /*===========================================================================*
473 *===========================================================================*/
474 static int pipe_open(struct vnode
*vp
, mode_t bits
, int oflags
)
476 /* This function is called from common_open. It checks if
477 * there is at least one reader/writer pair for the pipe, if not
478 * it suspends the caller, otherwise it revives all other blocked
479 * processes hanging on the pipe.
482 if ((bits
& (R_BIT
|W_BIT
)) == (R_BIT
|W_BIT
)) return(ENXIO
);
484 /* Find the reader/writer at the other end of the pipe */
485 if (find_filp(vp
, bits
& W_BIT
? R_BIT
: W_BIT
) == NULL
) {
487 if (oflags
& O_NONBLOCK
) {
488 if (bits
& W_BIT
) return(ENXIO
);
490 /* Let's wait for the other side to show up */
491 suspend(FP_BLOCKED_ON_POPEN
);
494 } else if (susp_count
> 0) { /* revive blocked processes */
495 release(vp
, VFS_OPEN
, susp_count
);
501 /*===========================================================================*
503 *===========================================================================*/
506 /* Perform the mknod(name, mode, addr) system call. */
507 register mode_t bits
, mode_bits
;
511 char fullpath
[PATH_MAX
];
512 struct lookup resolve
;
514 size_t vname1_length
;
517 vname1
= job_m_in
.m_lc_vfs_mknod
.name
;
518 vname1_length
= job_m_in
.m_lc_vfs_mknod
.len
;
519 mode_bits
= job_m_in
.m_lc_vfs_mknod
.mode
;
520 dev
= job_m_in
.m_lc_vfs_mknod
.device
;
522 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
523 resolve
.l_vmnt_lock
= VMNT_WRITE
;
524 resolve
.l_vnode_lock
= VNODE_WRITE
;
526 /* Only the super_user may make nodes other than fifos. */
527 if (!super_user
&& (!S_ISFIFO(mode_bits
) && !S_ISSOCK(mode_bits
))) {
530 bits
= (mode_bits
& S_IFMT
) | (mode_bits
& ACCESSPERMS
& fp
->fp_umask
);
532 /* Open directory that's going to hold the new node. */
533 if (fetch_name(vname1
, vname1_length
, fullpath
) != OK
) return(err_code
);
534 if ((vp
= last_dir(&resolve
, fp
)) == NULL
) return(err_code
);
536 /* Make sure that the object is a directory */
537 if (!S_ISDIR(vp
->v_mode
)) {
539 } else if ((r
= forbidden(fp
, vp
, W_BIT
|X_BIT
)) == OK
) {
540 r
= req_mknod(vp
->v_fs_e
, vp
->v_inode_nr
, fullpath
, fp
->fp_effuid
,
541 fp
->fp_effgid
, bits
, dev
);
550 /*===========================================================================*
552 *===========================================================================*/
555 /* Perform the mkdir(name, mode) system call. */
556 mode_t bits
; /* mode bits for the new inode */
560 char fullpath
[PATH_MAX
];
561 struct lookup resolve
;
564 if (copy_path(fullpath
, sizeof(fullpath
)) != OK
)
566 dirmode
= job_m_in
.m_lc_vfs_path
.mode
;
568 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
569 resolve
.l_vmnt_lock
= VMNT_WRITE
;
570 resolve
.l_vnode_lock
= VNODE_WRITE
;
572 bits
= I_DIRECTORY
| (dirmode
& RWX_MODES
& fp
->fp_umask
);
573 if ((vp
= last_dir(&resolve
, fp
)) == NULL
) return(err_code
);
575 /* Make sure that the object is a directory */
576 if (!S_ISDIR(vp
->v_mode
)) {
578 } else if ((r
= forbidden(fp
, vp
, W_BIT
|X_BIT
)) == OK
) {
579 r
= req_mkdir(vp
->v_fs_e
, vp
->v_inode_nr
, fullpath
, fp
->fp_effuid
,
580 fp
->fp_effgid
, bits
);
589 /*===========================================================================*
591 *===========================================================================*/
592 int actual_lseek(struct fproc
*rfp
, int seekfd
, int seekwhence
, off_t offset
,
595 register struct filp
*rfilp
;
599 /* Check to see if the file descriptor is valid. */
600 if ( (rfilp
= get_filp2(rfp
, seekfd
, VNODE_READ
)) == NULL
) {
604 /* No lseek on pipes. */
605 if (S_ISFIFO(rfilp
->filp_vno
->v_mode
)) {
610 /* The value of 'whence' determines the start position to use. */
612 case SEEK_SET
: pos
= 0; break;
613 case SEEK_CUR
: pos
= rfilp
->filp_pos
; break;
614 case SEEK_END
: pos
= rfilp
->filp_vno
->v_size
; break;
615 default: unlock_filp(rfilp
); return(EINVAL
);
618 newpos
= pos
+ offset
;
620 /* Check for overflow. */
621 if ((offset
> 0) && (newpos
<= pos
)) {
623 } else if ((offset
< 0) && (newpos
>= pos
)) {
626 if (newposp
!= NULL
) *newposp
= newpos
;
628 if (newpos
!= rfilp
->filp_pos
) {
629 rfilp
->filp_pos
= newpos
;
631 /* Inhibit read ahead request */
632 r
= req_inhibread(rfilp
->filp_vno
->v_fs_e
,
633 rfilp
->filp_vno
->v_inode_nr
);
641 /*===========================================================================*
643 *===========================================================================*/
646 /* Perform the lseek(2) system call. */
650 if ((r
= actual_lseek(fp
, job_m_in
.m_lc_vfs_lseek
.fd
,
651 job_m_in
.m_lc_vfs_lseek
.whence
, job_m_in
.m_lc_vfs_lseek
.offset
,
655 /* insert the new position into the output message */
656 job_m_out
.m_vfs_lc_lseek
.offset
= newpos
;
660 /*===========================================================================*
662 *===========================================================================*/
665 /* Perform the close(fd) system call. */
666 int thefd
= job_m_in
.m_lc_vfs_close
.fd
;
667 return close_fd(fp
, thefd
);
671 /*===========================================================================*
673 *===========================================================================*/
674 int close_fd(rfp
, fd_nr
)
678 /* Perform the close(fd) system call. */
679 register struct filp
*rfilp
;
680 register struct vnode
*vp
;
681 struct file_lock
*flp
;
684 /* First locate the vnode that belongs to the file descriptor. */
685 if ( (rfilp
= get_filp2(rfp
, fd_nr
, VNODE_OPCL
)) == NULL
) return(err_code
);
687 vp
= rfilp
->filp_vno
;
689 /* first, make all future get_filp2()'s fail; otherwise
690 * we might try to close the same fd in different threads
692 rfp
->fp_filp
[fd_nr
] = NULL
;
696 FD_CLR(fd_nr
, &rfp
->fp_cloexec_set
);
698 /* Check to see if the file is locked. If so, release all locks. */
700 lock_count
= nr_locks
; /* save count of locks */
701 for (flp
= &file_lock
[0]; flp
< &file_lock
[NR_LOCKS
]; flp
++) {
702 if (flp
->lock_type
== 0) continue; /* slot not in use */
703 if (flp
->lock_vnode
== vp
&& flp
->lock_pid
== rfp
->fp_pid
) {
708 if (nr_locks
< lock_count
)
709 lock_revive(); /* one or more locks released */