1 /* This file contains the procedures for creating, opening, closing, and
4 * The entry points into this file are
5 * do_creat: perform the CREAT system call
6 * do_open: perform the OPEN system call
7 * do_mknod: perform the MKNOD system call
8 * do_mkdir: perform the MKDIR system call
9 * do_close: perform the CLOSE system call
10 * do_lseek: perform the LSEEK system call
11 * do_llseek: perform the LLSEEK system call
19 #include <minix/callnr.h>
20 #include <minix/com.h>
21 #include <minix/u64.h>
24 #include "scratchpad.h"
30 #include <minix/vfsif.h>
35 char mode_map
[] = {R_BIT
, W_BIT
, R_BIT
|W_BIT
, 0};
37 static struct vnode
*new_node(struct lookup
*resolve
, int oflags
,
39 static int pipe_open(struct vnode
*vp
, mode_t bits
, int oflags
);
42 /*===========================================================================*
44 *===========================================================================*/
47 /* Perform the creat(name, mode) system call.
48 * syscall might provide 'name' embedded in the message.
51 char fullpath
[PATH_MAX
];
56 vname
= (vir_bytes
) job_m_in
.name
;
57 vname_length
= (size_t) job_m_in
.name_length
;
58 open_mode
= (mode_t
) job_m_in
.mode
;
60 if (copy_name(vname_length
, fullpath
) != OK
) {
61 /* Direct copy failed, try fetching from user space */
62 if (fetch_name(vname
, vname_length
, fullpath
) != OK
)
66 return common_open(fullpath
, O_WRONLY
| O_CREAT
| O_TRUNC
, open_mode
);
69 /*===========================================================================*
71 *===========================================================================*/
74 /* Perform the open(name, flags,...) system call.
75 * syscall might provide 'name' embedded in message when not creating file */
77 int create_mode
; /* is really mode_t but this gives problems */
78 int open_mode
= 0; /* is really mode_t but this gives problems */
80 char fullpath
[PATH_MAX
];
84 open_mode
= (mode_t
) job_m_in
.mode
;
85 create_mode
= job_m_in
.c_mode
;
87 /* If O_CREAT is set, open has three parameters, otherwise two. */
88 if (open_mode
& O_CREAT
) {
89 vname
= (vir_bytes
) job_m_in
.name1
;
90 vname_length
= (size_t) job_m_in
.name1_length
;
91 r
= fetch_name(vname
, vname_length
, fullpath
);
93 vname
= (vir_bytes
) job_m_in
.name
;
94 vname_length
= (size_t) job_m_in
.name_length
;
96 if (copy_name(vname_length
, fullpath
) != OK
) {
97 /* Direct copy failed, try fetching from user space */
98 if (fetch_name(vname
, vname_length
, fullpath
) != OK
)
103 if (r
!= OK
) return(err_code
); /* name was bad */
104 return common_open(fullpath
, open_mode
, create_mode
);
108 /*===========================================================================*
110 *===========================================================================*/
111 int common_open(char path
[PATH_MAX
], int oflags
, mode_t omode
)
113 /* Common code from do_creat and do_open. */
114 int b
, r
, exist
= TRUE
, major_dev
;
117 struct filp
*filp
, *filp2
;
121 struct lookup resolve
;
123 /* Remap the bottom two bits of oflags. */
124 bits
= (mode_t
) mode_map
[oflags
& O_ACCMODE
];
125 if (!bits
) return(EINVAL
);
127 /* See if file descriptor and filp slots are available. */
128 if ((r
= get_fd(0, bits
, &(scratch(fp
).file
.fd_nr
), &filp
)) != OK
) return(r
);
130 lookup_init(&resolve
, path
, PATH_NOFLAGS
, &vmp
, &vp
);
132 /* If O_CREATE is set, try to make the file. */
133 if (oflags
& O_CREAT
) {
134 omode
= I_REGULAR
| (omode
& ALLPERMS
& fp
->fp_umask
);
135 vp
= new_node(&resolve
, oflags
, omode
);
137 if (r
== OK
) exist
= FALSE
; /* We just created the file */
138 else if (r
!= EEXIST
) { /* other error */
139 if (vp
) unlock_vnode(vp
);
143 else exist
= !(oflags
& O_EXCL
);/* file exists, if the O_EXCL
144 flag is set this is an error */
147 resolve
.l_vmnt_lock
= VMNT_READ
;
148 resolve
.l_vnode_lock
= VNODE_OPCL
;
149 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) {
154 if (vmp
!= NULL
) unlock_vmnt(vmp
);
157 /* Claim the file descriptor and filp slot and fill them in. */
158 fp
->fp_filp
[scratch(fp
).file
.fd_nr
] = filp
;
159 FD_SET(scratch(fp
).file
.fd_nr
, &fp
->fp_filp_inuse
);
160 filp
->filp_count
= 1;
162 filp
->filp_flags
= oflags
;
164 /* Only do the normal open code if we didn't just create the file. */
166 /* Check protections. */
167 if ((r
= forbidden(fp
, vp
, bits
)) == OK
) {
168 /* Opening reg. files, directories, and special files differ */
169 switch (vp
->v_mode
& S_IFMT
) {
171 /* Truncate regular file if O_TRUNC. */
172 if (oflags
& O_TRUNC
) {
173 if ((r
= forbidden(fp
, vp
, W_BIT
)) != OK
)
175 truncate_vnode(vp
, 0);
179 /* Directories may be read but not written. */
180 r
= (bits
& W_BIT
? EISDIR
: OK
);
183 /* Invoke the driver for special processing. */
184 dev
= (dev_t
) vp
->v_sdev
;
185 /* TTY needs to know about the O_NOCTTY flag. */
186 r
= dev_open(dev
, who_e
, bits
| (oflags
& O_NOCTTY
));
187 if (r
== SUSPEND
) suspend(FP_BLOCKED_ON_DOPEN
);
188 else vp
= filp
->filp_vno
; /* Might be updated by
189 * dev_open/clone_opcl */
195 /* Invoke the driver for special processing. */
196 dev
= (dev_t
) vp
->v_sdev
;
197 r
= bdev_open(dev
, bits
);
203 major_dev
= major(vp
->v_sdev
);
204 dp
= &dmap
[major_dev
];
205 if (dp
->dmap_driver
== NONE
) {
206 printf("VFS: block driver disappeared!\n");
212 /* Check whether the device is mounted or not. If so,
213 * then that FS is responsible for this device.
214 * Otherwise we default to ROOT_FS.
216 vp
->v_bfs_e
= ROOT_FS_E
; /* By default */
217 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
)
218 if (vmp
->m_dev
== vp
->v_sdev
&&
219 !(vmp
->m_flags
& VMNT_FORCEROOTBSF
)) {
220 vp
->v_bfs_e
= vmp
->m_fs_e
;
223 /* Send the driver label to the file system that will
224 * handle the block I/O requests (even when its label
225 * and endpoint are known already), but only when it is
226 * the root file system. Other file systems will
227 * already have it anyway.
229 if (vp
->v_bfs_e
!= ROOT_FS_E
) {
234 if (req_newdriver(vp
->v_bfs_e
, vp
->v_sdev
,
235 dp
->dmap_label
) != OK
) {
236 printf("VFS: error sending driver label\n");
244 /* Create a mapped inode on PFS which handles reads
245 and writes to this named pipe. */
246 tll_upgrade(&vp
->v_lock
);
247 r
= map_vnode(vp
, PFS_PROC_NR
);
249 if (vp
->v_ref_count
== 1) {
250 vp
->v_pipe_rd_pos
= 0;
251 vp
->v_pipe_wr_pos
= 0;
253 r
= truncate_vnode(vp
, 0);
255 oflags
|= O_APPEND
; /* force append mode */
256 filp
->filp_flags
= oflags
;
259 r
= pipe_open(vp
, bits
, oflags
);
262 /* See if someone else is doing a rd or wt on
263 * the FIFO. If so, use its filp entry so the
264 * file position will be automatically shared.
266 b
= (bits
& R_BIT
? R_BIT
: W_BIT
);
267 filp
->filp_count
= 0; /* don't find self */
268 if ((filp2
= find_filp(vp
, b
)) != NULL
) {
269 /* Co-reader or writer found. Use it.*/
270 fp
->fp_filp
[scratch(fp
).file
.fd_nr
] = filp2
;
272 filp2
->filp_vno
= vp
;
273 filp2
->filp_flags
= oflags
;
275 /* v_count was incremented after the vnode
276 * has been found. i_count was incremented
277 * incorrectly in FS, not knowing that we
278 * were going to use an existing filp
279 * entry. Correct this error.
284 /* Nobody else found. Restore filp. */
285 filp
->filp_count
= 1;
295 /* If error, release inode. */
298 fp
->fp_filp
[scratch(fp
).file
.fd_nr
] = NULL
;
299 FD_CLR(scratch(fp
).file
.fd_nr
, &fp
->fp_filp_inuse
);
300 filp
->filp_count
= 0;
301 filp
->filp_vno
= NULL
;
302 filp
->filp_state
&= ~FS_INVALIDATED
; /* Prevent garbage col. */
306 r
= scratch(fp
).file
.fd_nr
;
313 /*===========================================================================*
315 *===========================================================================*/
316 static struct vnode
*new_node(struct lookup
*resolve
, int oflags
, mode_t bits
)
318 /* Try to create a new inode and return a pointer to it. If the inode already
319 exists, return a pointer to it as well, but set err_code accordingly.
320 NULL is returned if the path cannot be resolved up to the last
321 directory, or when the inode cannot be created due to permissions or
323 struct vnode
*dirp
, *vp
;
324 struct vmnt
*dir_vmp
, *vp_vmp
;
326 struct node_details res
;
327 struct lookup findnode
;
330 path
= resolve
->l_path
; /* For easy access */
332 lookup_init(&findnode
, path
, resolve
->l_flags
, &dir_vmp
, &dirp
);
333 findnode
.l_vmnt_lock
= VMNT_WRITE
;
334 findnode
.l_vnode_lock
= VNODE_WRITE
; /* dir node */
336 /* When O_CREAT and O_EXCL flags are set, the path may not be named by a
338 if (oflags
& O_EXCL
) findnode
.l_flags
|= PATH_RET_SYMLINK
;
340 /* See if the path can be opened down to the last directory. */
341 if ((dirp
= last_dir(&findnode
, fp
)) == NULL
) return(NULL
);
343 /* The final directory is accessible. Get final component of the path. */
344 lookup_init(&findnode
, findnode
.l_path
, findnode
.l_flags
, &vp_vmp
, &vp
);
345 findnode
.l_vmnt_lock
= VMNT_WRITE
;
346 findnode
.l_vnode_lock
= (oflags
& O_TRUNC
) ? VNODE_WRITE
: VNODE_OPCL
;
347 vp
= advance(dirp
, &findnode
, fp
);
348 assert(vp_vmp
== NULL
); /* Lookup to last dir should have yielded lock
349 * on vmp or final component does not exist.
350 * Either way, vp_vmp ought to be not set.
353 /* The combination of a symlink with absolute path followed by a danglink
354 * symlink results in a new path that needs to be re-resolved entirely. */
355 if (path
[0] == '/') {
357 unlock_vmnt(dir_vmp
);
363 return new_node(resolve
, oflags
, bits
);
366 if (vp
== NULL
&& err_code
== ENOENT
) {
367 /* Last path component does not exist. Make a new directory entry. */
368 if ((vp
= get_free_vnode()) == NULL
) {
369 /* Can't create new entry: out of vnodes. */
371 unlock_vmnt(dir_vmp
);
376 lock_vnode(vp
, VNODE_OPCL
);
378 if ((r
= forbidden(fp
, dirp
, W_BIT
|X_BIT
)) != OK
||
379 (r
= req_create(dirp
->v_fs_e
, dirp
->v_inode_nr
,bits
, fp
->fp_effuid
,
380 fp
->fp_effgid
, path
, &res
)) != OK
) {
381 /* Can't create inode either due to permissions or some other
382 * problem. In case r is EEXIST, we might be dealing with a
383 * dangling symlink.*/
385 struct vnode
*slp
, *old_wd
;
387 /* Resolve path up to symlink */
388 findnode
.l_flags
= PATH_RET_SYMLINK
;
389 findnode
.l_vnode_lock
= VNODE_READ
;
390 findnode
.l_vnode
= &slp
;
391 slp
= advance(dirp
, &findnode
, fp
);
393 if (S_ISLNK(slp
->v_mode
)) {
394 /* Get contents of link */
396 r
= req_rdlink(slp
->v_fs_e
,
402 /* Failed to read link */
405 unlock_vmnt(dir_vmp
);
411 path
[r
] = '\0'; /* Terminate path */
417 /* Try to create the inode the dangling symlink was
418 * pointing to. We have to use dirp as starting point
419 * as there might be multiple successive symlinks
420 * crossing multiple mountpoints.
421 * Unlock vnodes and vmnts as we're going to recurse.
425 unlock_vmnt(dir_vmp
);
427 old_wd
= fp
->fp_wd
; /* Save orig. working dirp */
429 vp
= new_node(resolve
, oflags
, bits
);
430 fp
->fp_wd
= old_wd
; /* Restore */
434 *(resolve
->l_vnode
) = vp
;
441 err_code
= EIO
; /* Impossible, we have verified that
442 * the last component doesn't exist and
443 * is not a dangling symlink. */
449 unlock_vmnt(dir_vmp
);
454 /* Store results and mark vnode in use */
456 vp
->v_fs_e
= res
.fs_e
;
457 vp
->v_inode_nr
= res
.inode_nr
;
458 vp
->v_mode
= res
.fmode
;
459 vp
->v_size
= res
.fsize
;
462 vp
->v_sdev
= res
.dev
;
463 vp
->v_vmnt
= dirp
->v_vmnt
;
464 vp
->v_dev
= vp
->v_vmnt
->m_dev
;
468 /* Either last component exists, or there is some other problem. */
470 r
= EEXIST
; /* File exists or a symlink names a file while
473 r
= err_code
; /* Other problem. */
477 /* When dirp equals vp, we shouldn't release the lock as a vp is locked only
478 * once. Releasing the lock would cause the resulting vp not be locked and
479 * cause mayhem later on. */
483 unlock_vmnt(dir_vmp
);
486 *(resolve
->l_vnode
) = vp
;
491 /*===========================================================================*
493 *===========================================================================*/
494 static int pipe_open(struct vnode
*vp
, mode_t bits
, int oflags
)
496 /* This function is called from common_open. It checks if
497 * there is at least one reader/writer pair for the pipe, if not
498 * it suspends the caller, otherwise it revives all other blocked
499 * processes hanging on the pipe.
502 if ((bits
& (R_BIT
|W_BIT
)) == (R_BIT
|W_BIT
)) return(ENXIO
);
504 /* Find the reader/writer at the other end of the pipe */
505 if (find_filp(vp
, bits
& W_BIT
? R_BIT
: W_BIT
) == NULL
) {
507 if (oflags
& O_NONBLOCK
) {
508 if (bits
& W_BIT
) return(ENXIO
);
510 /* Let's wait for the other side to show up */
511 suspend(FP_BLOCKED_ON_POPEN
);
514 } else if (susp_count
> 0) { /* revive blocked processes */
515 release(vp
, OPEN
, susp_count
);
516 release(vp
, CREAT
, susp_count
);
522 /*===========================================================================*
524 *===========================================================================*/
527 /* Perform the mknod(name, mode, addr) system call. */
528 register mode_t bits
, mode_bits
;
532 char fullpath
[PATH_MAX
];
533 struct lookup resolve
;
535 size_t vname1_length
;
538 vname1
= (vir_bytes
) job_m_in
.name1
;
539 vname1_length
= (size_t) job_m_in
.name1_length
;
540 mode_bits
= (mode_t
) job_m_in
.mk_mode
; /* mode of the inode */
541 dev
= job_m_in
.m1_i3
;
543 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
544 resolve
.l_vmnt_lock
= VMNT_WRITE
;
545 resolve
.l_vnode_lock
= VNODE_READ
;
547 /* Only the super_user may make nodes other than fifos. */
548 if (!super_user
&& (!S_ISFIFO(mode_bits
) && !S_ISSOCK(mode_bits
))) {
551 bits
= (mode_bits
& S_IFMT
) | (mode_bits
& ACCESSPERMS
& fp
->fp_umask
);
553 /* Open directory that's going to hold the new node. */
554 if (fetch_name(vname1
, vname1_length
, fullpath
) != OK
) return(err_code
);
555 if ((vp
= last_dir(&resolve
, fp
)) == NULL
) return(err_code
);
557 /* Make sure that the object is a directory */
558 if (!S_ISDIR(vp
->v_mode
)) {
560 } else if ((r
= forbidden(fp
, vp
, W_BIT
|X_BIT
)) == OK
) {
561 r
= req_mknod(vp
->v_fs_e
, vp
->v_inode_nr
, fullpath
, fp
->fp_effuid
,
562 fp
->fp_effgid
, bits
, dev
);
571 /*===========================================================================*
573 *===========================================================================*/
576 /* Perform the mkdir(name, mode) system call. */
577 mode_t bits
; /* mode bits for the new inode */
581 char fullpath
[PATH_MAX
];
582 struct lookup resolve
;
584 size_t vname1_length
;
587 vname1
= (vir_bytes
) job_m_in
.name1
;
588 vname1_length
= (size_t) job_m_in
.name1_length
;
589 dirmode
= (mode_t
) job_m_in
.mode
;
591 lookup_init(&resolve
, fullpath
, PATH_NOFLAGS
, &vmp
, &vp
);
592 resolve
.l_vmnt_lock
= VMNT_WRITE
;
593 resolve
.l_vnode_lock
= VNODE_READ
;
595 if (fetch_name(vname1
, vname1_length
, fullpath
) != OK
) return(err_code
);
596 bits
= I_DIRECTORY
| (dirmode
& RWX_MODES
& fp
->fp_umask
);
597 if ((vp
= last_dir(&resolve
, fp
)) == NULL
) return(err_code
);
599 /* Make sure that the object is a directory */
600 if (!S_ISDIR(vp
->v_mode
)) {
602 } else if ((r
= forbidden(fp
, vp
, W_BIT
|X_BIT
)) == OK
) {
603 r
= req_mkdir(vp
->v_fs_e
, vp
->v_inode_nr
, fullpath
, fp
->fp_effuid
,
604 fp
->fp_effgid
, bits
);
613 /*===========================================================================*
615 *===========================================================================*/
618 /* Perform the lseek(ls_fd, offset, whence) system call. */
619 register struct filp
*rfilp
;
620 int r
= OK
, seekfd
, seekwhence
;
624 seekfd
= job_m_in
.ls_fd
;
625 seekwhence
= job_m_in
.whence
;
626 offset
= (off_t
) job_m_in
.offset_lo
;
628 /* Check to see if the file descriptor is valid. */
629 if ( (rfilp
= get_filp(seekfd
, VNODE_READ
)) == NULL
) return(err_code
);
631 /* No lseek on pipes. */
632 if (S_ISFIFO(rfilp
->filp_vno
->v_mode
)) {
637 /* The value of 'whence' determines the start position to use. */
639 case SEEK_SET
: pos
= cvu64(0); break;
640 case SEEK_CUR
: pos
= rfilp
->filp_pos
; break;
641 case SEEK_END
: pos
= cvul64(rfilp
->filp_vno
->v_size
); break;
642 default: unlock_filp(rfilp
); return(EINVAL
);
646 newpos
= add64ul(pos
, offset
);
648 newpos
= sub64ul(pos
, -offset
);
650 /* Check for overflow. */
651 if (ex64hi(newpos
) != 0) {
653 } else if ((off_t
) ex64lo(newpos
) < 0) { /* no negative file size */
656 /* insert the new position into the output message */
657 m_out
.reply_l1
= ex64lo(newpos
);
659 if (cmp64(newpos
, rfilp
->filp_pos
) != 0) {
660 rfilp
->filp_pos
= newpos
;
662 /* Inhibit read ahead request */
663 r
= req_inhibread(rfilp
->filp_vno
->v_fs_e
,
664 rfilp
->filp_vno
->v_inode_nr
);
672 /*===========================================================================*
674 *===========================================================================*/
677 /* Perform the llseek(ls_fd, offset, whence) system call. */
678 register struct filp
*rfilp
;
680 int r
= OK
, seekfd
, seekwhence
;
683 seekfd
= job_m_in
.ls_fd
;
684 seekwhence
= job_m_in
.whence
;
685 off_hi
= job_m_in
.offset_high
;
686 off_lo
= job_m_in
.offset_lo
;
688 /* Check to see if the file descriptor is valid. */
689 if ( (rfilp
= get_filp(seekfd
, VNODE_READ
)) == NULL
) return(err_code
);
691 /* No lseek on pipes. */
692 if (S_ISFIFO(rfilp
->filp_vno
->v_mode
)) {
697 /* The value of 'whence' determines the start position to use. */
699 case SEEK_SET
: pos
= cvu64(0); break;
700 case SEEK_CUR
: pos
= rfilp
->filp_pos
; break;
701 case SEEK_END
: pos
= cvul64(rfilp
->filp_vno
->v_size
); break;
702 default: unlock_filp(rfilp
); return(EINVAL
);
705 newpos
= add64(pos
, make64(off_lo
, off_hi
));
707 /* Check for overflow. */
708 if ((off_hi
> 0) && cmp64(newpos
, pos
) < 0)
710 else if ((off_hi
< 0) && cmp64(newpos
, pos
) > 0)
713 /* insert the new position into the output message */
714 m_out
.reply_l1
= ex64lo(newpos
);
715 m_out
.reply_l2
= ex64hi(newpos
);
717 if (cmp64(newpos
, rfilp
->filp_pos
) != 0) {
718 rfilp
->filp_pos
= newpos
;
720 /* Inhibit read ahead request */
721 r
= req_inhibread(rfilp
->filp_vno
->v_fs_e
,
722 rfilp
->filp_vno
->v_inode_nr
);
730 /*===========================================================================*
732 *===========================================================================*/
735 /* Perform the close(fd) system call. */
737 scratch(fp
).file
.fd_nr
= job_m_in
.fd
;
738 return close_fd(fp
, scratch(fp
).file
.fd_nr
);
742 /*===========================================================================*
744 *===========================================================================*/
745 int close_fd(rfp
, fd_nr
)
749 /* Perform the close(fd) system call. */
750 register struct filp
*rfilp
;
751 register struct vnode
*vp
;
752 struct file_lock
*flp
;
755 /* First locate the vnode that belongs to the file descriptor. */
756 if ( (rfilp
= get_filp2(rfp
, fd_nr
, VNODE_OPCL
)) == NULL
) return(err_code
);
757 vp
= rfilp
->filp_vno
;
760 rfp
->fp_filp
[fd_nr
] = NULL
;
761 FD_CLR(fd_nr
, &rfp
->fp_cloexec_set
);
762 FD_CLR(fd_nr
, &rfp
->fp_filp_inuse
);
764 /* Check to see if the file is locked. If so, release all locks. */
766 lock_count
= nr_locks
; /* save count of locks */
767 for (flp
= &file_lock
[0]; flp
< &file_lock
[NR_LOCKS
]; flp
++) {
768 if (flp
->lock_type
== 0) continue; /* slot not in use */
769 if (flp
->lock_vnode
== vp
&& flp
->lock_pid
== rfp
->fp_pid
) {
774 if (nr_locks
< lock_count
)
775 lock_revive(); /* one or more locks released */
781 /*===========================================================================*
783 *===========================================================================*/
786 /* No need to do anything */