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
13 * Jul 2006 (Balazs Gerofi)
21 #include <minix/callnr.h>
22 #include <minix/com.h>
23 #include <minix/u64.h>
31 #include <minix/vfsif.h>
35 #define offset_lo m2_l1
36 #define offset_high m2_l2
38 FORWARD
_PROTOTYPE( int x_open
, (int bits
, int oflags
, int omode
,
39 char *lastc
, struct vnode
**vpp
) );
40 FORWARD
_PROTOTYPE( int common_open
, (int oflags
, mode_t omode
) );
41 FORWARD
_PROTOTYPE( int pipe_open
, (struct vnode
*vp
,mode_t bits
,int oflags
));
43 /*===========================================================================*
45 *===========================================================================*/
48 /* Perform the creat(name, mode) system call. */
51 if (fetch_name(m_in
.name
, m_in
.name_length
, M3
) != OK
) return(err_code
);
52 r
= common_open(O_WRONLY
| O_CREAT
| O_TRUNC
, (mode_t
) m_in
.mode
);
56 /*===========================================================================*
58 *===========================================================================*/
61 /* Perform the open(name, flags,...) system call. */
62 int create_mode
= 0; /* is really mode_t but this gives problems */
65 /* If O_CREAT is set, open has three parameters, otherwise two. */
66 if (m_in
.mode
& O_CREAT
) {
67 create_mode
= m_in
.c_mode
;
68 r
= fetch_name(m_in
.c_name
, m_in
.name1_length
, M1
);
70 r
= fetch_name(m_in
.name
, m_in
.name_length
, M3
);
74 return(err_code
); /* name was bad */
76 r
= common_open(m_in
.mode
, create_mode
);
80 /*===========================================================================*
82 *===========================================================================*/
83 PRIVATE
int common_open(register int oflags
, mode_t omode
)
85 /* Common code from do_creat and do_open. */
91 struct filp
*fil_ptr
, *filp2
;
92 struct vnode
*vp
, *vp2
;
94 char Xlastc
[NAME_MAX
];
98 /* Request and response structures */
99 struct lookup_req Xlookup_req
;
100 struct open_req Xreq
;
102 /* Remap the bottom two bits of oflags. */
103 m
= oflags
& O_ACCMODE
;
105 case O_RDONLY
: bits
= R_BIT
; break;
106 case O_WRONLY
: bits
= W_BIT
; break;
107 case O_RDWR
: bits
= R_BIT
| W_BIT
; break;
108 default: return EINVAL
;
111 /* See if file descriptor and filp slots are available. */
112 if ((r
= get_fd(0, bits
, &m_in
.fd
, &fil_ptr
)) != OK
) return(r
);
114 /* If O_CREATE, set umask */
115 if (oflags
& O_CREAT
) {
116 omode
= I_REGULAR
| (omode
& ALL_MODES
& fp
->fp_umask
);
121 /* Fill in lookup request fields */
122 Xlookup_req
.path
= user_fullpath
;
123 Xlookup_req
.lastc
= Xlastc
;
124 Xlookup_req
.flags
= oflags
&O_CREAT
? (oflags
&O_EXCL
? LAST_DIR
:
125 LAST_DIR_EATSYM
) : EAT_PATH
;
126 Xlookup_req
.flags
= ((oflags
& (O_CREAT
|O_EXCL
)) == (O_CREAT
|O_EXCL
)) ?
128 Xlastc
[0]= '\0'; /* Clear lastc, it will be filled with the part of the
129 * path that cannot be resolved.
133 r
= Xlookup_vp(&Xlookup_req
, &vp
, &pathrem
);
135 if (r
== OK
&& ((oflags
& (O_CREAT
|O_EXCL
)) != (O_CREAT
|O_EXCL
)))
141 /* Hide ENOENT for O_CREAT */
142 if (r
== ENOENT
&& (oflags
& O_CREAT
))
145 panic(__FILE__
, "no pathrem", NO_NUM
);
147 /* If any path remains, but no '/', O_CREAT can continue.
148 * If no path remains, a null filename was provided so ENOENT
152 if (strchr(pathrem
, '/') == 0)
156 printf("common_open: / in pathrem\n");
171 if (!vp
) panic(__FILE__
, "common_open: no vp", NO_NUM
);
173 r
= x_open(bits
, oflags
, omode
, Xlastc
, &vp
);
185 /* Lookup was okay, fill in request fields for
186 * the actual open request. */
187 req
.inode_nr
= res
.inode_nr
;
192 req
.uid
= fp
->fp_effuid
;
193 req
.gid
= fp
->fp_effgid
;
196 if ((r
= req_open(&req
, &res
)) != OK
) return r
;
198 /* Check whether the vnode is already in use */
199 if ((vp2
= find_vnode(res
.fs_e
, res
.inode_nr
)) != NIL_VNODE
) {
201 vp
->v_size
= res
.fsize
; /* In case of trunc... */
205 /* Otherwise use the free one */
207 vp
->v_fs_e
= res
.fs_e
;
208 if ( (vmp
= find_vmnt(vp
->v_fs_e
)) == NIL_VMNT
)
209 printf("VFS: vmnt not found by open()");
211 vp
->v_dev
= vmp
->m_dev
;
212 vp
->v_inode_nr
= res
.inode_nr
;
213 vp
->v_mode
= res
.fmode
;
216 vp
->v_size
= res
.fsize
;
217 vp
->v_sdev
= res
.dev
;
221 vp
->v_index
= res
.inode_index
;
225 /* Claim the file descriptor and filp slot and fill them in. */
226 fp
->fp_filp
[m_in
.fd
] = fil_ptr
;
227 FD_SET(m_in
.fd
, &fp
->fp_filp_inuse
);
228 fil_ptr
->filp_count
= 1;
229 fil_ptr
->filp_flags
= oflags
;
230 fil_ptr
->filp_vno
= vp
;
233 switch (vp
->v_mode
& I_TYPE
) {
235 /* Invoke the driver for special processing. */
236 r
= dev_open(vp
->v_sdev
, who_e
, bits
| (oflags
& ~O_ACCMODE
));
239 case I_BLOCK_SPECIAL
:
240 /* Invoke the driver for special processing. */
241 r
= dev_open(vp
->v_sdev
, who_e
, bits
| (oflags
& ~O_ACCMODE
));
244 panic(__FILE__
, "common_open: dev_open failed", r
);
247 /* Check whether the device is mounted or not */
250 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
) {
251 if (vmp
->m_dev
== vp
->v_sdev
) {
257 /* Who is going to be responsible for this device? */
259 vp
->v_bfs_e
= vmp
->m_fs_e
;
260 vp
->v_blocksize
- vmp
->m_block_size
;
262 else { /* To be handled in the root FS proc if not mounted */
263 vp
->v_bfs_e
= ROOT_FS_E
;
264 vp
->v_blocksize
= _MIN_BLOCK_SIZE
;
267 /* Get the driver endpoint of the block spec device */
268 dp
= &dmap
[(vp
->v_sdev
>> MAJOR
) & BYTE
];
269 if (dp
->dmap_driver
== NONE
) {
270 printf("VFSblock_spec_open: driver not found for device %d\n",
276 /* Send the driver endpoint (even if it is known already...) */
277 if ((r
= req_newdriver(vp
->v_bfs_e
, vp
->v_sdev
, dp
->dmap_driver
))
279 printf("VFSblock_spec_open: error sending driver endpoint\n");
287 oflags
|= O_APPEND
; /* force append mode */
288 fil_ptr
->filp_flags
= oflags
;
289 r
= pipe_open(vp
, bits
, oflags
);
291 /* See if someone else is doing a rd or wt on
292 * the FIFO. If so, use its filp entry so the
293 * file position will be automatically shared.
295 b
= (bits
& R_BIT
? R_BIT
: W_BIT
);
296 assert(fil_ptr
->filp_count
== 1);
297 fil_ptr
->filp_count
= 0; /* don't find self */
298 if ((filp2
= find_filp(vp
, b
)) != NIL_FILP
) {
299 /* Co-reader or writer found. Use it.*/
300 fp
->fp_filp
[m_in
.fd
] = filp2
;
302 filp2
->filp_vno
= vp
;
303 filp2
->filp_flags
= oflags
;
305 /* v_count was incremented after the vnode has
306 * been found, i_count was incremented incorrectly
307 * by eatpath in FS, not knowing that we were going to
308 * use an existing filp entry. Correct this error.
312 /* Nobody else found. Restore filp. */
313 fil_ptr
->filp_count
= 1;
314 if (fil_ptr
->filp_mode
== R_BIT
)
315 fil_ptr
->filp_pos
= cvul64(vp
->v_pipe_rd_pos
);
317 fil_ptr
->filp_pos
= cvul64(vp
->v_pipe_wr_pos
);
323 /* If error, release inode. */
325 if (r
== SUSPEND
) return(r
); /* Oops, just suspended */
326 fp
->fp_filp
[m_in
.fd
] = NIL_FILP
;
327 FD_CLR(m_in
.fd
, &fp
->fp_filp_inuse
);
328 fil_ptr
->filp_count
= 0;
330 fil_ptr
->filp_vno
= NIL_VNODE
;
337 /*===========================================================================*
339 *===========================================================================*/
340 PRIVATE
int x_open(bits
, oflags
, omode
, lastc
, vpp
)
347 int r
, b
, exist
= TRUE
;
348 struct vnode
*vp
, *dvp
, *tmp_vp
;
350 struct node_details res
;
352 /* If O_CREATE is set, try to make the file. */
353 if ((oflags
& O_CREAT
) && lastc
[0] != '\0') {
354 dvp
= *vpp
; /* Parent directory */
356 /* See if a free vnode is available */
357 if ((vp
= get_free_vnode(__FILE__
, __LINE__
)) == NIL_VNODE
) {
358 printf("VFS x_open: no free vnode available\n");
362 r
= req_create(dvp
->v_fs_e
, dvp
->v_inode_nr
, omode
, fp
->fp_effuid
,
363 fp
->fp_effgid
, lastc
, &res
);
368 /* Check whether vnode is already in use or not */
369 if ((tmp_vp
= find_vnode(res
.fs_e
, res
.inode_nr
)) != NIL_VNODE
) {
376 /* Fill in the free vnode's fields */
377 vp
->v_fs_e
= res
.fs_e
;
378 vp
->v_inode_nr
= res
.inode_nr
;
379 vp
->v_mode
= res
.fmode
;
380 vp
->v_size
= res
.fsize
;
383 vp
->v_sdev
= res
.dev
;
385 if ( (vmp
= find_vmnt(vp
->v_fs_e
)) == NIL_VMNT
)
386 panic(__FILE__
, "lookup_vp: vmnt not found", NO_NUM
);
389 vp
->v_dev
= vmp
->m_dev
;
404 /* Only do the normal open code if we didn't just create the file. */
408 /* Check protections. */
409 if ((r
= forbidden(vp
, bits
)) != OK
)
412 /* Opening reg. files directories and special files differ. */
413 switch (vp
->v_mode
& I_TYPE
) {
415 /* Truncate regular file if O_TRUNC. */
416 if (oflags
& O_TRUNC
) {
417 if ((r
= forbidden(vp
, W_BIT
)) !=OK
) break;
423 /* Directories may be read but not written. */
424 r
= (bits
& W_BIT
? EISDIR
: OK
);
428 case I_BLOCK_SPECIAL
:
429 if (vp
->v_sdev
== (dev_t
)-1)
430 panic(__FILE__
, "x_open: bad special", NO_NUM
);
434 if (vp
->v_ref_count
== 1)
438 r
= truncate_vn(vp
, 0);
442 "x_open (fifo): truncate_vn failed: %d\n",
454 /*===========================================================================*
456 *===========================================================================*/
457 PRIVATE
int pipe_open(register struct vnode
*vp
, register mode_t bits
,
460 /* This function is called from common_open. It checks if
461 * there is at least one reader/writer pair for the pipe, if not
462 * it suspends the caller, otherwise it revives all other blocked
463 * processes hanging on the pipe.
468 if((bits
& (R_BIT
|W_BIT
)) == (R_BIT
|W_BIT
)) {
469 printf("pipe opened RW.\n");
473 if (find_filp(vp
, bits
& W_BIT
? R_BIT
: W_BIT
) == NIL_FILP
) {
474 if (oflags
& O_NONBLOCK
) {
475 if (bits
& W_BIT
) return(ENXIO
);
477 suspend(XPOPEN
); /* suspend caller */
480 } else if (susp_count
> 0) {/* revive blocked processes */
481 release(vp
, OPEN
, susp_count
);
482 release(vp
, CREAT
, susp_count
);
490 /*===========================================================================*
492 *===========================================================================*/
493 PUBLIC
int do_mknod()
495 /* Perform the mknod(name, mode, addr) system call. */
496 register mode_t bits
, mode_bits
;
497 char lastc
[NAME_MAX
]; /* last component of the path */
498 struct mknod_req req
;
499 struct lookup_req lookup_req
;
500 struct node_details res
;
503 /* Only the super_user may make nodes other than fifos. */
504 mode_bits
= (mode_t
) m_in
.mk_mode
; /* mode of the inode */
505 if (!super_user
&& ((mode_bits
& I_TYPE
) != I_NAMED_PIPE
)) return(EPERM
);
506 if (fetch_name(m_in
.name1
, m_in
.name1_length
, M1
) != OK
) return(err_code
);
507 bits
= (mode_bits
& I_TYPE
) | (mode_bits
& ALL_MODES
& fp
->fp_umask
);
509 /* Fill in lookup request fields */
510 lookup_req
.path
= user_fullpath
;
511 lookup_req
.lastc
= lastc
;
512 lookup_req
.flags
= LAST_DIR
;
515 if ((r
= lookup(&lookup_req
, &res
)) != OK
) return r
;
517 /* Lookup was okay, fill in request fields for the actual
520 req
.inode_nr
= res
.inode_nr
;
522 req
.dev
= m_in
.mk_z0
;
524 req
.uid
= fp
->fp_effuid
;
525 req
.gid
= fp
->fp_effgid
;
528 return req_mknod(&req
);
532 /*===========================================================================*
534 *===========================================================================*/
535 PUBLIC
int do_mkdir()
537 /* Perform the mkdir(name, mode) system call. */
538 mode_t bits
; /* mode bits for the new inode */
539 char lastc
[NAME_MAX
];
540 struct mkdir_req req
;
541 struct lookup_req lookup_req
;
542 struct node_details res
;
545 /*printf("VFS: mkdir() START:");*/
546 if (fetch_name(m_in
.name1
, m_in
.name1_length
, M1
) != OK
) return(err_code
);
548 bits
= I_DIRECTORY
| (m_in
.mode
& RWX_MODES
& fp
->fp_umask
);
550 /* Fill in lookup request fields */
551 lookup_req
.path
= user_fullpath
;
552 lookup_req
.lastc
= lastc
;
553 lookup_req
.flags
= LAST_DIR
;
556 if ((r
= lookup(&lookup_req
, &res
)) != OK
) return r
;
558 /* Lookup was okay, fill in request message fields
559 * for the actual mknod request. */
561 req
.d_inode_nr
= res
.inode_nr
;
564 req
.uid
= fp
->fp_effuid
;
565 req
.gid
= fp
->fp_effgid
;
568 return req_mkdir(&req
);
574 /*===========================================================================*
576 *===========================================================================*/
577 PUBLIC
int do_lseek()
579 /* Perform the lseek(ls_fd, offset, whence) system call. */
580 register struct filp
*rfilp
;
586 /* Check to see if the file descriptor is valid. */
587 if ( (rfilp
= get_filp(m_in
.ls_fd
)) == NIL_FILP
) return(err_code
);
589 /* No lseek on pipes. */
590 if (rfilp
->filp_vno
->v_pipe
== I_PIPE
) return(ESPIPE
);
592 /* The value of 'whence' determines the start position to use. */
593 switch(m_in
.whence
) {
594 case SEEK_SET
: pos
= cvu64(0); break;
595 case SEEK_CUR
: pos
= rfilp
->filp_pos
; break;
596 case SEEK_END
: pos
= cvul64(rfilp
->filp_vno
->v_size
); break;
597 default: return(EINVAL
);
600 offset
= m_in
.offset_lo
;
602 newpos
= add64ul(pos
, offset
);
604 newpos
= sub64ul(pos
, -offset
);
606 /* Check for overflow. */
607 if (ex64hi(newpos
) != 0)
610 if (cmp64(newpos
, rfilp
->filp_pos
) != 0) { /* Inhibit read ahead request */
611 /* Fill in request message */
612 req
.fs_e
= rfilp
->filp_vno
->v_fs_e
;
613 req
.inode_nr
= rfilp
->filp_vno
->v_inode_nr
;
616 if ((r
= req_inhibread(&req
)) != OK
) return r
;
619 rfilp
->filp_pos
= newpos
;
621 /* insert the new position into the output message */
622 m_out
.reply_l1
= ex64lo(newpos
);
628 /*===========================================================================*
630 *===========================================================================*/
631 PUBLIC
int do_llseek()
633 /* Perform the llseek(ls_fd, offset, whence) system call. */
634 register struct filp
*rfilp
;
639 /* Check to see if the file descriptor is valid. */
640 if ( (rfilp
= get_filp(m_in
.ls_fd
)) == NIL_FILP
) return(err_code
);
642 /* No lseek on pipes. */
643 if (rfilp
->filp_vno
->v_pipe
== I_PIPE
) return(ESPIPE
);
645 /* The value of 'whence' determines the start position to use. */
646 switch(m_in
.whence
) {
647 case SEEK_SET
: pos
= cvu64(0); break;
648 case SEEK_CUR
: pos
= rfilp
->filp_pos
; break;
649 case SEEK_END
: pos
= cvul64(rfilp
->filp_vno
->v_size
); break;
650 default: return(EINVAL
);
653 newpos
= add64(pos
, make64(m_in
.offset_lo
, m_in
.offset_high
));
655 /* Check for overflow. */
656 if (((long)m_in
.offset_high
> 0) && cmp64(newpos
, pos
) < 0)
658 if (((long)m_in
.offset_high
< 0) && cmp64(newpos
, pos
) > 0)
661 if (cmp64(newpos
, rfilp
->filp_pos
) != 0) { /* Inhibit read ahead request */
662 /* Fill in request message */
663 req
.fs_e
= rfilp
->filp_vno
->v_fs_e
;
664 req
.inode_nr
= rfilp
->filp_vno
->v_inode_nr
;
667 if ((r
= req_inhibread(&req
)) != OK
) return r
;
670 rfilp
->filp_pos
= newpos
;
671 m_out
.reply_l1
= ex64lo(newpos
);
672 m_out
.reply_l2
= ex64hi(newpos
);
677 /*===========================================================================*
679 *===========================================================================*/
680 PUBLIC
int do_close()
682 /* Perform the close(fd) system call. */
683 return close_fd(fp
, m_in
.fd
);
687 /*===========================================================================*
689 *===========================================================================*/
690 PUBLIC
int close_fd(rfp
, fd_nr
)
694 /* Perform the close(fd) system call. */
695 register struct filp
*rfilp
;
696 register struct vnode
*vp
;
697 struct file_lock
*flp
;
698 int rw
, mode_word
, lock_count
;
701 /* First locate the vnode that belongs to the file descriptor. */
702 if ( (rfilp
= get_filp2(rfp
, fd_nr
)) == NIL_FILP
) return(err_code
);
704 vp
= rfilp
->filp_vno
;
706 if (rfilp
->filp_count
- 1 == 0 && rfilp
->filp_mode
!= FILP_CLOSED
) {
707 /* Check to see if the file is special. */
708 mode_word
= vp
->v_mode
& I_TYPE
;
709 if (mode_word
== I_CHAR_SPECIAL
|| mode_word
== I_BLOCK_SPECIAL
) {
710 dev
= (dev_t
) vp
->v_sdev
;
711 if (mode_word
== I_BLOCK_SPECIAL
) {
712 if (vp
->v_bfs_e
== ROOT_FS_E
)
714 /* Invalidate the cache unless the special is
715 * mounted. Assume that the root filesystem's
716 * is open only for fsck.
718 req_flush(vp
->v_bfs_e
, dev
);
721 /* Do any special processing on device close. */
726 /* If the inode being closed is a pipe, release everyone hanging on it. */
727 if (vp
->v_pipe
== I_PIPE
) {
728 rw
= (rfilp
->filp_mode
& R_BIT
? WRITE
: READ
);
729 release(vp
, rw
, NR_PROCS
);
732 /* If a write has been done, the inode is already marked as DIRTY. */
733 if (--rfilp
->filp_count
== 0) {
734 if (vp
->v_pipe
== I_PIPE
) {
735 /* Last reader or writer is going. Tell MFS about latest
738 truncate_vn(vp
, vp
->v_size
);
740 if (vp
->v_pipe
== I_PIPE
&& vp
->v_ref_count
> 1) {
741 /* Save the file position in the v-node in case needed later.
742 * The read and write positions are saved separately.
744 if (rfilp
->filp_mode
== R_BIT
)
745 vp
->v_pipe_rd_pos
= ex64lo(rfilp
->filp_pos
);
747 vp
->v_pipe_wr_pos
= ex64lo(rfilp
->filp_pos
);
751 /* Otherwise zero the pipe position fields */
752 vp
->v_pipe_rd_pos
= 0;
753 vp
->v_pipe_wr_pos
= 0;
756 put_vnode(rfilp
->filp_vno
);
759 FD_CLR(fd_nr
, &rfp
->fp_cloexec_set
);
760 rfp
->fp_filp
[fd_nr
] = NIL_FILP
;
761 FD_CLR(fd_nr
, &rfp
->fp_filp_inuse
);
763 /* Check to see if the file is locked. If so, release all locks. */
764 if (nr_locks
== 0) return(OK
);
765 lock_count
= nr_locks
; /* save count of locks */
766 for (flp
= &file_lock
[0]; flp
< &file_lock
[NR_LOCKS
]; flp
++) {
767 if (flp
->lock_type
== 0) continue; /* slot not in use */
768 if (flp
->lock_vnode
== vp
&& flp
->lock_pid
== rfp
->fp_pid
) {
773 if (nr_locks
< lock_count
) lock_revive(); /* lock released */