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
18 #include <minix/callnr.h>
19 #include <minix/com.h>
20 #include <minix/u64.h>
27 #include <minix/vfsif.h>
31 PRIVATE
char mode_map
[] = {R_BIT
, W_BIT
, R_BIT
|W_BIT
, 0};
33 FORWARD
_PROTOTYPE( int common_open
, (int oflags
, mode_t omode
) );
34 FORWARD
_PROTOTYPE( struct vnode
*new_node
, (int oflags
, mode_t bits
) );
35 FORWARD
_PROTOTYPE( int pipe_open
, (struct vnode
*vp
,mode_t bits
,int oflags
));
38 /*===========================================================================*
40 *===========================================================================*/
43 /* Perform the creat(name, mode) system call. */
46 if (fetch_name(m_in
.name
, m_in
.name_length
, M3
) != OK
) return(err_code
);
47 r
= common_open(O_WRONLY
| O_CREAT
| O_TRUNC
, (mode_t
) m_in
.mode
);
52 /*===========================================================================*
54 *===========================================================================*/
57 /* Perform the open(name, flags,...) system call. */
58 int create_mode
= 0; /* is really mode_t but this gives problems */
61 /* If O_CREAT is set, open has three parameters, otherwise two. */
62 if (m_in
.mode
& O_CREAT
) {
63 create_mode
= m_in
.c_mode
;
64 r
= fetch_name(m_in
.c_name
, m_in
.name1_length
, M1
);
66 r
= fetch_name(m_in
.name
, m_in
.name_length
, M3
);
69 if (r
!= OK
) return(err_code
); /* name was bad */
70 r
= common_open(m_in
.mode
, create_mode
);
75 /*===========================================================================*
77 *===========================================================================*/
78 PRIVATE
int common_open(register int oflags
, mode_t omode
)
80 /* Common code from do_creat and do_open. */
81 int b
, r
, exist
= TRUE
;
84 struct filp
*fil_ptr
, *filp2
;
89 /* Remap the bottom two bits of oflags. */
90 bits
= (mode_t
) mode_map
[oflags
& O_ACCMODE
];
91 if (!bits
) return(EINVAL
);
93 /* See if file descriptor and filp slots are available. */
94 if ((r
= get_fd(0, bits
, &m_in
.fd
, &fil_ptr
)) != OK
) return(r
);
96 /* If O_CREATE is set, try to make the file. */
97 if (oflags
& O_CREAT
) {
98 omode
= I_REGULAR
| (omode
& ALL_MODES
& fp
->fp_umask
);
99 vp
= new_node(oflags
, omode
);
101 if (r
== OK
) exist
= FALSE
; /* We just created the file */
102 else if (r
!= EEXIST
) return(r
); /* other error */
103 else exist
= !(oflags
& O_EXCL
); /* file exists, if the O_EXCL
104 flag is set this is an error */
107 if ((vp
= eat_path(PATH_NOFLAGS
)) == NIL_VNODE
) return(err_code
);
110 /* Claim the file descriptor and filp slot and fill them in. */
111 fp
->fp_filp
[m_in
.fd
] = fil_ptr
;
112 FD_SET(m_in
.fd
, &fp
->fp_filp_inuse
);
113 fil_ptr
->filp_count
= 1;
114 fil_ptr
->filp_vno
= vp
;
115 fil_ptr
->filp_flags
= oflags
;
117 /* Only do the normal open code if we didn't just create the file. */
119 /* Check protections. */
120 if ((r
= forbidden(vp
, bits
)) == OK
) {
121 /* Opening reg. files, directories, and special files differ */
122 switch (vp
->v_mode
& I_TYPE
) {
124 /* Truncate regular file if O_TRUNC. */
125 if (oflags
& O_TRUNC
) {
126 if ((r
= forbidden(vp
, W_BIT
)) != OK
)
128 truncate_vnode(vp
, 0);
132 /* Directories may be read but not written. */
133 r
= (bits
& W_BIT
? EISDIR
: OK
);
136 /* Invoke the driver for special processing. */
137 dev
= (dev_t
) vp
->v_sdev
;
138 r
= dev_open(dev
, who_e
, bits
| (oflags
& ~O_ACCMODE
));
139 if (r
== SUSPEND
) suspend(FP_BLOCKED_ON_DOPEN
);
141 case I_BLOCK_SPECIAL
:
142 /* Invoke the driver for special processing. */
143 dev
= (dev_t
) vp
->v_sdev
;
144 r
= dev_open(dev
, who_e
, bits
| (oflags
& ~O_ACCMODE
));
147 /* Check whether the device is mounted or not. If so,
148 then that FS is responsible for this device. Else
149 we default to ROOT_FS. */
150 vp
->v_bfs_e
= ROOT_FS_E
; /* By default */
151 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
)
152 if (vmp
->m_dev
== vp
->v_sdev
)
153 vp
->v_bfs_e
= vmp
->m_fs_e
;
155 /* Get the driver endpoint of the block spec device */
156 dp
= &dmap
[(vp
->v_sdev
>> MAJOR
) & BYTE
];
157 if (dp
->dmap_driver
== NONE
) {
158 printf("VFS: driver not found for device %d\n",
164 /* Send the driver endpoint (even when known already)*/
165 if ((r
= req_newdriver(vp
->v_bfs_e
, vp
->v_sdev
,
166 dp
->dmap_driver
)) != OK
) {
167 printf("VFS: error sending driver endpoint\n");
173 /* Create a mapped inode on PFS which handles reads
174 and writes to this named pipe. */
178 if (vp
->v_ref_count
== 1) {
179 vp
->v_pipe_rd_pos
= 0;
180 vp
->v_pipe_wr_pos
= 0;
182 r
= truncate_vnode(vp
, 0);
184 oflags
|= O_APPEND
; /* force append mode */
185 fil_ptr
->filp_flags
= oflags
;
188 r
= pipe_open(vp
, bits
, oflags
);
191 /* See if someone else is doing a rd or wt on
192 * the FIFO. If so, use its filp entry so the
193 * file position will be automatically shared.
195 b
= (bits
& R_BIT
? R_BIT
: W_BIT
);
196 fil_ptr
->filp_count
= 0; /* don't find self */
197 if ((filp2
= find_filp(vp
, b
)) != NIL_FILP
) {
198 /* Co-reader or writer found. Use it.*/
199 fp
->fp_filp
[m_in
.fd
] = filp2
;
201 filp2
->filp_vno
= vp
;
202 filp2
->filp_flags
= oflags
;
204 /* v_count was incremented after the
205 * vnode has been found. i_count was
206 * incremented incorrectly in FS, not
207 * knowing that we were going to use an
208 * existing filp entry. Correct this
213 /* Nobody else found. Restore filp. */
214 fil_ptr
->filp_count
= 1;
222 /* If error, release inode. */
224 if (r
== SUSPEND
) return(r
); /* Oops, just suspended */
225 fp
->fp_filp
[m_in
.fd
] = NIL_FILP
;
226 FD_CLR(m_in
.fd
, &fp
->fp_filp_inuse
);
227 fil_ptr
->filp_count
= 0;
229 fil_ptr
->filp_vno
= NIL_VNODE
;
237 /*===========================================================================*
239 *===========================================================================*/
240 PRIVATE
struct vnode
*new_node(int oflags
, mode_t bits
)
242 /* Try to create a new inode and return a pointer to it. If the inode already
243 exists, return a pointer to it as well, but set err_code accordingly.
244 NIL_VNODE is returned if the path cannot be resolved up to the last
245 directory, or when the inode cannot be created due to permissions or
247 struct vnode
*dirp
, *vp
;
249 struct node_details res
;
252 /* When O_CREAT and O_EXCL flags are set, the path may not be named by a
254 flags
= PATH_NOFLAGS
;
255 if (oflags
& O_EXCL
) flags
|= PATH_RET_SYMLINK
;
257 /* See if the path can be opened down to the last directory. */
258 if ((dirp
= last_dir()) == NIL_VNODE
) return(NIL_VNODE
);
260 /* The final directory is accessible. Get final component of the path. */
261 vp
= advance(dirp
, flags
);
263 /* The combination of a symlink with absolute path followed by a danglink
264 * symlink results in a new path that needs to be re-resolved entirely. */
265 if (user_fullpath
[0] == '/') return new_node(oflags
, bits
);
267 if (vp
== NIL_VNODE
&& err_code
== ENOENT
) {
268 /* Last path component does not exist. Make a new directory entry. */
269 if ((vp
= get_free_vnode()) == NIL_VNODE
) {
270 /* Can't create new vnode: out of vnodes. */
274 if ((r
= forbidden(dirp
, W_BIT
|X_BIT
)) != OK
||
275 (r
= req_create(dirp
->v_fs_e
, dirp
->v_inode_nr
,bits
, fp
->fp_effuid
,
276 fp
->fp_effgid
, user_fullpath
, &res
)) != OK
) {
277 /* Can't create inode either due to permissions or some other
278 * problem. In case r is EEXIST, we might be dealing with a
279 * dangling symlink.*/
281 struct vnode
*slp
, *old_wd
;
283 /* Resolve path up to symlink */
284 slp
= advance(dirp
, PATH_RET_SYMLINK
);
285 if (slp
!= NIL_VNODE
) {
286 if (S_ISLNK(slp
->v_mode
)) {
287 /* Get contents of link */
290 max_linklen
= sizeof(user_fullpath
)-1;
291 r
= req_rdlink(slp
->v_fs_e
,
297 /* Failed to read link */
303 user_fullpath
[r
] = '\0';/* Term. path*/
308 /* Try to create the inode the dangling symlink was
309 * pointing to. We have to use dirp as starting point
310 * as there might be multiple successive symlinks
311 * crossing multiple mountpoints. */
312 old_wd
= fp
->fp_wd
; /* Save orig. working dirp */
314 vp
= new_node(oflags
, bits
);
315 fp
->fp_wd
= old_wd
; /* Restore */
317 if (vp
!= NIL_VNODE
) {
325 err_code
= EIO
; /* Impossible, we have verified that
326 * the last component doesn't exist and
327 * is not a dangling symlink. */
335 /* Store results and mark vnode in use */
336 vp
->v_fs_e
= res
.fs_e
;
337 vp
->v_inode_nr
= res
.inode_nr
;
338 vp
->v_mode
= res
.fmode
;
339 vp
->v_size
= res
.fsize
;
342 vp
->v_sdev
= res
.dev
;
343 vp
->v_vmnt
= dirp
->v_vmnt
;
344 vp
->v_dev
= vp
->v_vmnt
->m_dev
;
348 /* Either last component exists, or there is some other problem. */
350 r
= EEXIST
; /* File exists or a symlink names a file while
353 r
= err_code
; /* Other problem. */
362 /*===========================================================================*
364 *===========================================================================*/
365 PRIVATE
int pipe_open(register struct vnode
*vp
, register mode_t bits
,
368 /* This function is called from common_open. It checks if
369 * there is at least one reader/writer pair for the pipe, if not
370 * it suspends the caller, otherwise it revives all other blocked
371 * processes hanging on the pipe.
376 if((bits
& (R_BIT
|W_BIT
)) == (R_BIT
|W_BIT
)) return(ENXIO
);
378 if (find_filp(vp
, bits
& W_BIT
? R_BIT
: W_BIT
) == NIL_FILP
) {
379 if (oflags
& O_NONBLOCK
) {
380 if (bits
& W_BIT
) return(ENXIO
);
382 suspend(FP_BLOCKED_ON_POPEN
); /* suspend caller */
385 } else if (susp_count
> 0) { /* revive blocked processes */
386 release(vp
, OPEN
, susp_count
);
387 release(vp
, CREAT
, susp_count
);
393 /*===========================================================================*
395 *===========================================================================*/
396 PUBLIC
int do_mknod()
398 /* Perform the mknod(name, mode, addr) system call. */
399 register mode_t bits
, mode_bits
;
403 /* Only the super_user may make nodes other than fifos. */
404 mode_bits
= (mode_t
) m_in
.mk_mode
; /* mode of the inode */
405 if(!super_user
&& ((mode_bits
& I_TYPE
) != I_NAMED_PIPE
)) return(EPERM
);
406 bits
= (mode_bits
& I_TYPE
) | (mode_bits
& ALL_MODES
& fp
->fp_umask
);
408 /* Open directory that's going to hold the new node. */
409 if(fetch_name(m_in
.name1
, m_in
.name1_length
, M1
) != OK
) return(err_code
);
410 if((vp
= last_dir()) == NIL_VNODE
) return(err_code
);
412 /* Make sure that the object is a directory */
413 if((vp
->v_mode
& I_TYPE
) != I_DIRECTORY
) {
418 if ((r
= forbidden(vp
, W_BIT
|X_BIT
)) == OK
) {
419 r
= req_mknod(vp
->v_fs_e
, vp
->v_inode_nr
, user_fullpath
, fp
->fp_effuid
,
420 fp
->fp_effgid
, bits
, m_in
.mk_z0
);
428 /*===========================================================================*
430 *===========================================================================*/
431 PUBLIC
int do_mkdir()
433 /* Perform the mkdir(name, mode) system call. */
434 mode_t bits
; /* mode bits for the new inode */
438 if(fetch_name(m_in
.name1
, m_in
.name1_length
, M1
) != OK
) return(err_code
);
440 bits
= I_DIRECTORY
| (m_in
.mode
& RWX_MODES
& fp
->fp_umask
);
443 if((vp
= last_dir()) == NIL_VNODE
) return(err_code
);
445 /* Make sure that the object is a directory */
446 if ((vp
->v_mode
& I_TYPE
) != I_DIRECTORY
) {
451 if ((r
= forbidden(vp
, W_BIT
|X_BIT
)) == OK
) {
452 r
= req_mkdir(vp
->v_fs_e
, vp
->v_inode_nr
, user_fullpath
, fp
->fp_effuid
,
453 fp
->fp_effgid
, bits
);
461 /*===========================================================================*
463 *===========================================================================*/
464 PUBLIC
int do_lseek()
466 /* Perform the lseek(ls_fd, offset, whence) system call. */
467 register struct filp
*rfilp
;
472 /* Check to see if the file descriptor is valid. */
473 if ( (rfilp
= get_filp(m_in
.ls_fd
)) == NIL_FILP
) return(err_code
);
475 /* No lseek on pipes. */
476 if (rfilp
->filp_vno
->v_pipe
== I_PIPE
) return(ESPIPE
);
478 /* The value of 'whence' determines the start position to use. */
479 switch(m_in
.whence
) {
480 case SEEK_SET
: pos
= cvu64(0); break;
481 case SEEK_CUR
: pos
= rfilp
->filp_pos
; break;
482 case SEEK_END
: pos
= cvul64(rfilp
->filp_vno
->v_size
); break;
483 default: return(EINVAL
);
486 offset
= m_in
.offset_lo
;
488 newpos
= add64ul(pos
, offset
);
490 newpos
= sub64ul(pos
, -offset
);
492 /* Check for overflow. */
493 if (ex64hi(newpos
) != 0)
496 if (cmp64(newpos
, rfilp
->filp_pos
) != 0) { /* Inhibit read ahead request */
497 r
= req_inhibread(rfilp
->filp_vno
->v_fs_e
, rfilp
->filp_vno
->v_inode_nr
);
498 if (r
!= OK
) return(r
);
501 rfilp
->filp_pos
= newpos
;
503 /* insert the new position into the output message */
504 m_out
.reply_l1
= ex64lo(newpos
);
510 /*===========================================================================*
512 *===========================================================================*/
513 PUBLIC
int do_llseek()
515 /* Perform the llseek(ls_fd, offset, whence) system call. */
516 register struct filp
*rfilp
;
520 /* Check to see if the file descriptor is valid. */
521 if ( (rfilp
= get_filp(m_in
.ls_fd
)) == NIL_FILP
) return(err_code
);
523 /* No lseek on pipes. */
524 if (rfilp
->filp_vno
->v_pipe
== I_PIPE
) return(ESPIPE
);
526 /* The value of 'whence' determines the start position to use. */
527 switch(m_in
.whence
) {
528 case SEEK_SET
: pos
= cvu64(0); break;
529 case SEEK_CUR
: pos
= rfilp
->filp_pos
; break;
530 case SEEK_END
: pos
= cvul64(rfilp
->filp_vno
->v_size
); break;
531 default: return(EINVAL
);
534 newpos
= add64(pos
, make64(m_in
.offset_lo
, m_in
.offset_high
));
536 /* Check for overflow. */
537 if (((long)m_in
.offset_high
> 0) && cmp64(newpos
, pos
) < 0)
539 if (((long)m_in
.offset_high
< 0) && cmp64(newpos
, pos
) > 0)
542 if (cmp64(newpos
, rfilp
->filp_pos
) != 0) { /* Inhibit read ahead request */
543 r
= req_inhibread(rfilp
->filp_vno
->v_fs_e
, rfilp
->filp_vno
->v_inode_nr
);
544 if (r
!= OK
) return(r
);
547 rfilp
->filp_pos
= newpos
;
548 m_out
.reply_l1
= ex64lo(newpos
);
549 m_out
.reply_l2
= ex64hi(newpos
);
554 /*===========================================================================*
556 *===========================================================================*/
557 PUBLIC
int do_close()
559 /* Perform the close(fd) system call. */
560 return close_fd(fp
, m_in
.fd
);
564 /*===========================================================================*
566 *===========================================================================*/
567 PUBLIC
int close_fd(rfp
, fd_nr
)
571 /* Perform the close(fd) system call. */
572 register struct filp
*rfilp
;
573 register struct vnode
*vp
;
574 struct file_lock
*flp
;
577 /* First locate the vnode that belongs to the file descriptor. */
578 if ( (rfilp
= get_filp2(rfp
, fd_nr
)) == NIL_FILP
) return(err_code
);
579 vp
= rfilp
->filp_vno
;
582 FD_CLR(fd_nr
, &rfp
->fp_cloexec_set
);
583 rfp
->fp_filp
[fd_nr
] = NIL_FILP
;
584 FD_CLR(fd_nr
, &rfp
->fp_filp_inuse
);
586 /* Check to see if the file is locked. If so, release all locks. */
587 if (nr_locks
== 0) return(OK
);
588 lock_count
= nr_locks
; /* save count of locks */
589 for (flp
= &file_lock
[0]; flp
< &file_lock
[NR_LOCKS
]; flp
++) {
590 if (flp
->lock_type
== 0) continue; /* slot not in use */
591 if (flp
->lock_vnode
== vp
&& flp
->lock_pid
== rfp
->fp_pid
) {
596 if (nr_locks
< lock_count
) lock_revive(); /* lock released */
601 /*===========================================================================*
603 *===========================================================================*/
604 PUBLIC
void close_filp(fp
)
612 if (fp
->filp_count
- 1 == 0 && fp
->filp_mode
!= FILP_CLOSED
) {
613 /* Check to see if the file is special. */
614 mode_word
= vp
->v_mode
& I_TYPE
;
615 if (mode_word
== I_CHAR_SPECIAL
|| mode_word
== I_BLOCK_SPECIAL
) {
616 dev
= (dev_t
) vp
->v_sdev
;
617 if (mode_word
== I_BLOCK_SPECIAL
) {
618 if (vp
->v_bfs_e
== ROOT_FS_E
) {
619 /* Invalidate the cache unless the special is
620 * mounted. Assume that the root filesystem's
621 * is open only for fsck.
623 req_flush(vp
->v_bfs_e
, dev
);
626 /* Do any special processing on device close. */
627 (void) dev_close(dev
, fp
-filp
);
628 /* Ignore any errors, even SUSPEND. */
630 fp
->filp_mode
= FILP_CLOSED
;
634 /* If the inode being closed is a pipe, release everyone hanging on it. */
635 if (vp
->v_pipe
== I_PIPE
) {
636 rw
= (fp
->filp_mode
& R_BIT
? WRITE
: READ
);
637 release(vp
, rw
, NR_PROCS
);
640 /* If a write has been done, the inode is already marked as DIRTY. */
641 if (--fp
->filp_count
== 0) {
642 if (vp
->v_pipe
== I_PIPE
) {
643 /* Last reader or writer is going. Tell MFS about latest
646 truncate_vnode(vp
, vp
->v_size
);
649 put_vnode(fp
->filp_vno
);
654 /*===========================================================================*
656 *===========================================================================*/
657 PUBLIC
void close_reply()
659 /* No need to do anything */