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 common_open
, (int oflags
, mode_t omode
) );
39 FORWARD
_PROTOTYPE( int create_open
, (_mnx_Mode_t omode
, int excl
,
40 struct vnode
**vpp
, int *created
) );
41 FORWARD
_PROTOTYPE( int exists_open
, (struct vnode
*vp
, _mnx_Mode_t bits
,
43 FORWARD
_PROTOTYPE( int pipe_open
, (struct vnode
*vp
,mode_t bits
,int oflags
));
45 /*===========================================================================*
47 *===========================================================================*/
50 /* Perform the creat(name, mode) system call. */
53 if (fetch_name(m_in
.name
, m_in
.name_length
, M3
) != OK
) return(err_code
);
54 r
= common_open(O_WRONLY
| O_CREAT
| O_TRUNC
, (mode_t
) m_in
.mode
);
58 /*===========================================================================*
60 *===========================================================================*/
63 /* Perform the open(name, flags,...) system call. */
64 int create_mode
= 0; /* is really mode_t but this gives problems */
67 /* If O_CREAT is set, open has three parameters, otherwise two. */
68 if (m_in
.mode
& O_CREAT
) {
69 create_mode
= m_in
.c_mode
;
70 r
= fetch_name(m_in
.c_name
, m_in
.name1_length
, M1
);
72 r
= fetch_name(m_in
.name
, m_in
.name_length
, M3
);
76 return(err_code
); /* name was bad */
78 r
= common_open(m_in
.mode
, create_mode
);
82 /*===========================================================================*
84 *===========================================================================*/
85 PRIVATE
int common_open(register int oflags
, mode_t omode
)
87 /* Common code from do_creat and do_open. */
88 int b
, m
, r
, created
, found
;
90 struct filp
*fil_ptr
, *filp2
;
95 /* Remap the bottom two bits of oflags. */
96 m
= oflags
& O_ACCMODE
;
98 case O_RDONLY
: bits
= R_BIT
; break;
99 case O_WRONLY
: bits
= W_BIT
; break;
100 case O_RDWR
: bits
= R_BIT
| W_BIT
; break;
101 default: return EINVAL
;
104 /* See if file descriptor and filp slots are available. */
105 if ((r
= get_fd(0, bits
, &m_in
.fd
, &fil_ptr
)) != OK
) return(r
);
107 /* If O_CREATE, set umask */
108 if (oflags
& O_CREAT
) {
109 omode
= I_REGULAR
| (omode
& ALL_MODES
& fp
->fp_umask
);
112 if (oflags
& O_CREAT
)
113 r
= create_open(omode
, !!(oflags
& O_EXCL
), &vp
, &created
);
117 printf("vfs:common_open: path '%s'\n", user_fullpath
);
120 r
= lookup_vp(0 /*flags*/, 0 /*!use_realuid*/, &vp
);
127 r
= exists_open(vp
, bits
, oflags
);
135 /* Claim the file descriptor and filp slot and fill them in. */
136 fp
->fp_filp
[m_in
.fd
] = fil_ptr
;
137 FD_SET(m_in
.fd
, &fp
->fp_filp_inuse
);
138 fil_ptr
->filp_count
= 1;
139 fil_ptr
->filp_flags
= oflags
;
140 fil_ptr
->filp_vno
= vp
;
142 switch (vp
->v_mode
& I_TYPE
) {
144 /* Invoke the driver for special processing. */
145 r
= dev_open(vp
->v_sdev
, who_e
, bits
| (oflags
& ~O_ACCMODE
));
147 suspend(XDOPEN
); /* suspend caller */
150 case I_BLOCK_SPECIAL
:
151 /* Invoke the driver for special processing. */
152 r
= dev_open(vp
->v_sdev
, who_e
, bits
| (oflags
& ~O_ACCMODE
));
156 /* Check whether the device is mounted or not */
158 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
) {
159 if (vmp
->m_dev
== vp
->v_sdev
) {
165 /* Who is going to be responsible for this device? */
167 vp
->v_bfs_e
= vmp
->m_fs_e
;
169 else { /* To be handled in the root FS proc if not mounted */
170 vp
->v_bfs_e
= ROOT_FS_E
;
173 /* Get the driver endpoint of the block spec device */
174 dp
= &dmap
[(vp
->v_sdev
>> MAJOR
) & BYTE
];
175 if (dp
->dmap_driver
== NONE
) {
176 printf("VFSblock_spec_open: driver not found for device %d\n",
182 /* Send the driver endpoint (even if it is known already...) */
183 if ((r
= req_newdriver(vp
->v_bfs_e
, vp
->v_sdev
, dp
->dmap_driver
))
185 printf("VFSblock_spec_open: error sending driver endpoint\n");
191 oflags
|= O_APPEND
; /* force append mode */
192 fil_ptr
->filp_flags
= oflags
;
193 r
= pipe_open(vp
, bits
, oflags
);
195 /* See if someone else is doing a rd or wt on
196 * the FIFO. If so, use its filp entry so the
197 * file position will be automatically shared.
199 b
= (bits
& R_BIT
? R_BIT
: W_BIT
);
200 assert(fil_ptr
->filp_count
== 1);
201 fil_ptr
->filp_count
= 0; /* don't find self */
202 if ((filp2
= find_filp(vp
, b
)) != NIL_FILP
) {
203 /* Co-reader or writer found. Use it.*/
204 fp
->fp_filp
[m_in
.fd
] = filp2
;
206 filp2
->filp_vno
= vp
;
207 filp2
->filp_flags
= oflags
;
209 /* v_count was incremented after the vnode has
210 * been found, i_count was incremented incorrectly
211 * by eatpath in FS, not knowing that we were going to
212 * use an existing filp entry. Correct this error.
216 /* Nobody else found. Claim filp. */
217 fil_ptr
->filp_count
= 1;
223 /* If error, release inode. */
225 if (r
== SUSPEND
) return(r
); /* Oops, just suspended */
226 fp
->fp_filp
[m_in
.fd
] = NIL_FILP
;
227 FD_CLR(m_in
.fd
, &fp
->fp_filp_inuse
);
228 fil_ptr
->filp_count
= 0;
230 fil_ptr
->filp_vno
= NIL_VNODE
;
238 /*===========================================================================*
240 *===========================================================================*/
241 PRIVATE
int create_open(omode
, excl
, vpp
, created
)
249 struct vnode
*vp
, *dir_vp
, *new_vp
, *start_vp
;
251 struct node_details res
;
252 char lastc
[PATH_MAX
+1];
254 start_vp
= (user_fullpath
[0] == '/' ? fp
->fp_rd
: fp
->fp_wd
);
257 for (i
= 0; i
<SYMLOOP_MAX
; i
++)
260 printf("vfs:create_open: path #%d '%s'\n", i
+1, user_fullpath
);
262 r
= lookup_lastdir_rel(start_vp
, 0 /*!use_realuid*/, &dir_vp
);
267 /* Save the last component of the path */
268 len
= strlen(user_fullpath
)+1;
269 if (len
> sizeof(lastc
))
274 memcpy(lastc
, user_fullpath
, len
);
276 /* Get a free vnode */
277 new_vp
= get_free_vnode(__FILE__
, __LINE__
);
278 if (new_vp
== NIL_VNODE
) {
280 printf("vfs:create_open: no free vnode available\n");
284 r
= forbidden(dir_vp
, W_BIT
|X_BIT
, 0 /*!use_realuid*/);
287 /* Try to create the file */
288 r
= req_create(dir_vp
->v_fs_e
, dir_vp
->v_inode_nr
,
289 omode
, fp
->fp_effuid
, fp
->fp_effgid
, lastc
,
293 if (r
!= EEXIST
&& r
!= EACCES
)
300 /* Check whether vnode is already in use or not */
301 vp
= find_vnode(res
.fs_e
, res
.inode_nr
);
302 if (vp
!= NIL_VNODE
) {
310 /* Fill in the free vnode's fields */
311 vp
->v_fs_e
= res
.fs_e
;
312 vp
->v_inode_nr
= res
.inode_nr
;
313 vp
->v_mode
= res
.fmode
;
314 vp
->v_size
= res
.fsize
;
317 vp
->v_sdev
= res
.dev
;
319 vp
->v_vmnt
= dir_vp
->v_vmnt
;
320 vp
->v_dev
= vp
->v_vmnt
->m_dev
;
332 if (r
== EEXIST
&& excl
)
336 "vfs:create_open: creating existing file with O_EXCL\n");
342 /* Try a regular lookup */
343 memcpy(user_fullpath
, lastc
, len
);
344 r1
= lookup_rel_vp(dir_vp
, 0 /*flags*/, 0 /*!use_realuid*/, &vp
);
358 /* We cannot create a new file and the file does not
365 /* The create failed with EEXIST and the regular lookup
366 * failed with ENOENT. We have to see whether the object
367 * we try to access actually exists, but is a symlink that
368 * cannot be resolved. If the symlink exists, we start
369 * with the contents of the symlink.
371 memcpy(user_fullpath
, lastc
, len
);
372 r
= lookup_rel_vp(dir_vp
, PATH_RET_SYMLINK
, 0 /*!use_realuid*/,
380 if (!S_ISLNK(vp
->v_mode
))
382 /* Strange, we got an object, but it is not a symlink.
383 * Well, just return the object.
391 /* Get the contents of the link */
392 len
= sizeof(user_fullpath
);
393 r
= req_rdlink(vp
->v_fs_e
, vp
->v_inode_nr
, FS_PROC_NR
,
394 (vir_bytes
)user_fullpath
, len
-1);
398 printf("vfs:create_open: req_rdlink failed with %d\n",
406 "vfs:create_open: got bad length %d from req_rdlink\n",
410 user_fullpath
[r
]= '\0';
412 printf("got link target '%s'\n", user_fullpath
);
413 if (user_fullpath
[0] == '/')
428 /*===========================================================================*
430 *===========================================================================*/
431 PRIVATE
int exists_open(vp
, bits
, oflags
/*, omode, lastc, vpp */)
438 /* Check protections. */
439 if ((r
= forbidden(vp
, bits
, 0 /*!use_realuid*/)) != OK
)
442 /* Opening reg. files directories and special files differ. */
443 switch (vp
->v_mode
& I_TYPE
) {
445 /* Truncate regular file if O_TRUNC. */
446 if (oflags
& O_TRUNC
) {
447 if ((r
= forbidden(vp
, W_BIT
, 0 /*!use_realuid*/)) !=OK
) break;
453 /* Directories may be read but not written. */
454 r
= (bits
& W_BIT
? EISDIR
: OK
);
458 case I_BLOCK_SPECIAL
:
459 if (vp
->v_sdev
== (dev_t
)-1)
460 panic(__FILE__
, "vfs:exists_open: bad special", NO_NUM
);
465 printf("vfs:exists_open: fifo vp 0x%x, for %s\n",
466 vp
, ((bits
& W_BIT
) ? "writing" : "reading"));
468 if (vp
->v_ref_count
== 1)
470 vp
->v_pipe_rd_pos
= 0;
471 vp
->v_pipe_wr_pos
= 0;
473 r
= truncate_vn(vp
, 0);
482 /*===========================================================================*
484 *===========================================================================*/
485 PRIVATE
int pipe_open(register struct vnode
*vp
, register mode_t bits
,
488 /* This function is called from common_open. It checks if
489 * there is at least one reader/writer pair for the pipe, if not
490 * it suspends the caller, otherwise it revives all other blocked
491 * processes hanging on the pipe.
496 if((bits
& (R_BIT
|W_BIT
)) == (R_BIT
|W_BIT
)) {
497 printf("pipe opened RW.\n");
501 if (find_filp(vp
, bits
& W_BIT
? R_BIT
: W_BIT
) == NIL_FILP
) {
502 if (oflags
& O_NONBLOCK
) {
503 if (bits
& W_BIT
) return(ENXIO
);
505 suspend(XPOPEN
); /* suspend caller */
508 } else if (susp_count
> 0) {/* revive blocked processes */
509 release(vp
, OPEN
, susp_count
);
510 release(vp
, CREAT
, susp_count
);
516 /*===========================================================================*
518 *===========================================================================*/
519 PUBLIC
int do_mknod()
521 /* Perform the mknod(name, mode, addr) system call. */
522 register mode_t bits
, mode_bits
;
526 /* Only the super_user may make nodes other than fifos. */
527 mode_bits
= (mode_t
) m_in
.mk_mode
; /* mode of the inode */
528 if (!super_user
&& ((mode_bits
& I_TYPE
) != I_NAMED_PIPE
)) return(EPERM
);
529 if (fetch_name(m_in
.name1
, m_in
.name1_length
, M1
) != OK
) return(err_code
);
530 bits
= (mode_bits
& I_TYPE
) | (mode_bits
& ALL_MODES
& fp
->fp_umask
);
533 if ((r
= lookup_lastdir(0 /*!use_realuid*/, &vp
)) != OK
) return r
;
535 /* Make sure that the object is a directory */
536 if ((vp
->v_mode
& I_TYPE
) != I_DIRECTORY
)
542 r
= forbidden(vp
, W_BIT
|X_BIT
, 0 /*!use_realuid*/);
550 r
= req_mknod(vp
->v_fs_e
, vp
->v_inode_nr
, user_fullpath
,
551 fp
->fp_effuid
, fp
->fp_effgid
, bits
, m_in
.mk_z0
);
557 /*===========================================================================*
559 *===========================================================================*/
560 PUBLIC
int do_mkdir()
562 /* Perform the mkdir(name, mode) system call. */
563 mode_t bits
; /* mode bits for the new inode */
567 if (fetch_name(m_in
.name1
, m_in
.name1_length
, M1
) != OK
) return(err_code
);
569 bits
= I_DIRECTORY
| (m_in
.mode
& RWX_MODES
& fp
->fp_umask
);
572 if ((r
= lookup_lastdir(0 /*!use_realuid*/, &vp
)) != OK
) return r
;
574 /* Make sure that the object is a directory */
575 if ((vp
->v_mode
& I_TYPE
) != I_DIRECTORY
)
581 r
= forbidden(vp
, W_BIT
|X_BIT
, 0 /*!use_realuid*/);
589 r
= req_mkdir(vp
->v_fs_e
, vp
->v_inode_nr
, user_fullpath
,
590 fp
->fp_effuid
, fp
->fp_effgid
, bits
);
598 /*===========================================================================*
600 *===========================================================================*/
601 PUBLIC
int do_lseek()
603 /* Perform the lseek(ls_fd, offset, whence) system call. */
604 register struct filp
*rfilp
;
609 /* Check to see if the file descriptor is valid. */
610 if ( (rfilp
= get_filp(m_in
.ls_fd
)) == NIL_FILP
) return(err_code
);
612 /* No lseek on pipes. */
613 if (rfilp
->filp_vno
->v_pipe
== I_PIPE
) return(ESPIPE
);
615 /* The value of 'whence' determines the start position to use. */
616 switch(m_in
.whence
) {
617 case SEEK_SET
: pos
= cvu64(0); break;
618 case SEEK_CUR
: pos
= rfilp
->filp_pos
; break;
619 case SEEK_END
: pos
= cvul64(rfilp
->filp_vno
->v_size
); break;
620 default: return(EINVAL
);
623 offset
= m_in
.offset_lo
;
625 newpos
= add64ul(pos
, offset
);
627 newpos
= sub64ul(pos
, -offset
);
629 /* Check for overflow. */
630 if (ex64hi(newpos
) != 0)
633 if (cmp64(newpos
, rfilp
->filp_pos
) != 0) { /* Inhibit read ahead request */
634 r
= req_inhibread(rfilp
->filp_vno
->v_fs_e
, rfilp
->filp_vno
->v_inode_nr
);
635 if (r
!= OK
) return r
;
638 rfilp
->filp_pos
= newpos
;
640 /* insert the new position into the output message */
641 m_out
.reply_l1
= ex64lo(newpos
);
647 /*===========================================================================*
649 *===========================================================================*/
650 PUBLIC
int do_llseek()
652 /* Perform the llseek(ls_fd, offset, whence) system call. */
653 register struct filp
*rfilp
;
657 /* Check to see if the file descriptor is valid. */
658 if ( (rfilp
= get_filp(m_in
.ls_fd
)) == NIL_FILP
) return(err_code
);
660 /* No lseek on pipes. */
661 if (rfilp
->filp_vno
->v_pipe
== I_PIPE
) return(ESPIPE
);
663 /* The value of 'whence' determines the start position to use. */
664 switch(m_in
.whence
) {
665 case SEEK_SET
: pos
= cvu64(0); break;
666 case SEEK_CUR
: pos
= rfilp
->filp_pos
; break;
667 case SEEK_END
: pos
= cvul64(rfilp
->filp_vno
->v_size
); break;
668 default: return(EINVAL
);
671 newpos
= add64(pos
, make64(m_in
.offset_lo
, m_in
.offset_high
));
673 /* Check for overflow. */
674 if (((long)m_in
.offset_high
> 0) && cmp64(newpos
, pos
) < 0)
676 if (((long)m_in
.offset_high
< 0) && cmp64(newpos
, pos
) > 0)
679 if (cmp64(newpos
, rfilp
->filp_pos
) != 0) { /* Inhibit read ahead request */
680 r
= req_inhibread(rfilp
->filp_vno
->v_fs_e
, rfilp
->filp_vno
->v_inode_nr
);
681 if (r
!= OK
) return r
;
684 rfilp
->filp_pos
= newpos
;
685 m_out
.reply_l1
= ex64lo(newpos
);
686 m_out
.reply_l2
= ex64hi(newpos
);
691 /*===========================================================================*
693 *===========================================================================*/
694 PUBLIC
int do_close()
696 /* Perform the close(fd) system call. */
697 return close_fd(fp
, m_in
.fd
);
701 /*===========================================================================*
703 *===========================================================================*/
704 PUBLIC
int close_fd(rfp
, fd_nr
)
708 /* Perform the close(fd) system call. */
709 register struct filp
*rfilp
;
710 register struct vnode
*vp
;
711 struct file_lock
*flp
;
714 /* First locate the vnode that belongs to the file descriptor. */
715 if ( (rfilp
= get_filp2(rfp
, fd_nr
)) == NIL_FILP
) return(err_code
);
716 vp
= rfilp
->filp_vno
;
719 FD_CLR(fd_nr
, &rfp
->fp_cloexec_set
);
720 rfp
->fp_filp
[fd_nr
] = NIL_FILP
;
721 FD_CLR(fd_nr
, &rfp
->fp_filp_inuse
);
723 /* Check to see if the file is locked. If so, release all locks. */
724 if (nr_locks
== 0) return(OK
);
725 lock_count
= nr_locks
; /* save count of locks */
726 for (flp
= &file_lock
[0]; flp
< &file_lock
[NR_LOCKS
]; flp
++) {
727 if (flp
->lock_type
== 0) continue; /* slot not in use */
728 if (flp
->lock_vnode
== vp
&& flp
->lock_pid
== rfp
->fp_pid
) {
733 if (nr_locks
< lock_count
) lock_revive(); /* lock released */
738 /*===========================================================================*
740 *===========================================================================*/
741 PUBLIC
void close_filp(fp
)
749 if (fp
->filp_count
- 1 == 0 && fp
->filp_mode
!= FILP_CLOSED
) {
750 /* Check to see if the file is special. */
751 mode_word
= vp
->v_mode
& I_TYPE
;
752 if (mode_word
== I_CHAR_SPECIAL
|| mode_word
== I_BLOCK_SPECIAL
) {
753 dev
= (dev_t
) vp
->v_sdev
;
754 if (mode_word
== I_BLOCK_SPECIAL
) {
755 if (vp
->v_bfs_e
== ROOT_FS_E
)
757 /* Invalidate the cache unless the special is
758 * mounted. Assume that the root filesystem's
759 * is open only for fsck.
761 req_flush(vp
->v_bfs_e
, dev
);
764 /* Do any special processing on device close. */
765 (void) dev_close(dev
, fp
-filp
);
767 /* Ignore any errors, even SUSPEND. */
771 /* If the inode being closed is a pipe, release everyone hanging on it. */
772 if (vp
->v_pipe
== I_PIPE
) {
773 rw
= (fp
->filp_mode
& R_BIT
? WRITE
: READ
);
774 release(vp
, rw
, NR_PROCS
);
777 /* If a write has been done, the inode is already marked as DIRTY. */
778 if (--fp
->filp_count
== 0) {
779 if (vp
->v_pipe
== I_PIPE
) {
780 /* Last reader or writer is going. Tell MFS about latest
783 truncate_vn(vp
, vp
->v_size
);
786 put_vnode(fp
->filp_vno
);
791 /*===========================================================================*
793 *===========================================================================*/
794 PUBLIC
void close_reply()
796 /* No need to do anything */
800 /*===========================================================================*
802 *===========================================================================*/
803 PUBLIC
int do_vm_open()
808 len
= m_in
.VMVO_NAME_LENGTH
;
809 m_out
.VMV_ENDPOINT
= ep
= m_in
.VMVO_ENDPOINT
;
811 /* Do open() call on behalf of any process, performed by VM. */
812 if(len
< 2 || len
> sizeof(user_fullpath
)) {
813 printf("do_vm_open: strange length %d\n", len
);
814 m_out
.VMVRO_FD
= EINVAL
;
815 return VM_VFS_REPLY_OPEN
;
818 /* Do open on behalf of which process? */
819 if(isokendpt(ep
, &n
) != OK
) {
820 printf("do_vm_open: strange endpoint %d\n", ep
);
821 m_out
.VMVRO_FD
= EINVAL
;
822 return VM_VFS_REPLY_OPEN
;
825 /* XXX - do open on behalf of this process */
828 /* Get path name from VM address space. */
829 if((r
=sys_safecopyfrom(VM_PROC_NR
, m_in
.VMVO_NAME_GRANT
, 0,
830 (vir_bytes
) user_fullpath
, len
, D
)) != OK
) {
831 printf("do_vm_open: sys_safecopyfrom failed: %d\n", r
);
832 m_out
.VMVRO_FD
= EPERM
;
833 return VM_VFS_REPLY_OPEN
;
836 /* Check if path is null-terminated. */
837 if(user_fullpath
[len
-1] != '\0') {
838 printf("do_vm_open: name (len %d) not 0-terminated\n", len
);
839 m_out
.VMVRO_FD
= EINVAL
;
840 return VM_VFS_REPLY_OPEN
;
843 /* Perform open(). */
844 m_out
.VMVRO_FD
= common_open(m_in
.VMVO_FLAGS
, m_in
.VMVO_MODE
);
845 m_out
.VMV_ENDPOINT
= ep
;
847 /* Send open() reply. */
848 return VM_VFS_REPLY_OPEN
;
851 /*===========================================================================*
853 *===========================================================================*/
854 PUBLIC
int do_vm_close()
859 len
= m_in
.VMVO_NAME_LENGTH
;
861 /* Do close() call on behalf of any process, performed by VM. */
862 m_out
.VMV_ENDPOINT
= ep
= m_in
.VMVC_ENDPOINT
;
863 if(isokendpt(ep
, &n
) != OK
) {
864 printf("do_vm_close: strange endpoint %d\n", ep
);
865 return VM_VFS_REPLY_CLOSE
;
868 /* Perform close(). */
869 r
= close_fd(&fproc
[n
], m_in
.VMVC_FD
);
871 return VM_VFS_REPLY_CLOSE
;