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
, (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
);
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 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
));
146 /* Check whether the device is mounted or not. If so,
147 then that FS is responsible for this device. Else
148 we default to ROOT_FS. */
149 vp
->v_bfs_e
= ROOT_FS_E
; /* By default */
150 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
)
151 if (vmp
->m_dev
== vp
->v_sdev
)
152 vp
->v_bfs_e
= vmp
->m_fs_e
;
154 /* Get the driver endpoint of the block spec device */
155 dp
= &dmap
[(vp
->v_sdev
>> MAJOR
) & BYTE
];
156 if (dp
->dmap_driver
== NONE
) {
157 printf("VFS: driver not found for device %d\n",
163 /* Send the driver endpoint (even when known already)*/
164 if ((r
= req_newdriver(vp
->v_bfs_e
, vp
->v_sdev
,
165 dp
->dmap_driver
)) != OK
) {
166 printf("VFS: error sending driver endpoint\n");
172 /* Create a mapped inode on PFS which handles reads
173 and writes to this named pipe. */
177 if (vp
->v_ref_count
== 1) {
178 vp
->v_pipe_rd_pos
= 0;
179 vp
->v_pipe_wr_pos
= 0;
181 r
= truncate_vnode(vp
, 0);
183 oflags
|= O_APPEND
; /* force append mode */
184 fil_ptr
->filp_flags
= oflags
;
187 r
= pipe_open(vp
, bits
, oflags
);
190 /* See if someone else is doing a rd or wt on
191 * the FIFO. If so, use its filp entry so the
192 * file position will be automatically shared.
194 b
= (bits
& R_BIT
? R_BIT
: W_BIT
);
195 fil_ptr
->filp_count
= 0; /* don't find self */
196 if ((filp2
= find_filp(vp
, b
)) != NIL_FILP
) {
197 /* Co-reader or writer found. Use it.*/
198 fp
->fp_filp
[m_in
.fd
] = filp2
;
200 filp2
->filp_vno
= vp
;
201 filp2
->filp_flags
= oflags
;
203 /* v_count was incremented after the
204 * vnode has been found. i_count was
205 * incremented incorrectly in FS, not
206 * knowing that we were going to use an
207 * existing filp entry. Correct this
212 /* Nobody else found. Restore filp. */
213 fil_ptr
->filp_count
= 1;
221 /* If error, release inode. */
223 if (r
== SUSPEND
) return(r
); /* Oops, just suspended */
224 fp
->fp_filp
[m_in
.fd
] = NIL_FILP
;
225 FD_CLR(m_in
.fd
, &fp
->fp_filp_inuse
);
226 fil_ptr
->filp_count
= 0;
228 fil_ptr
->filp_vno
= NIL_VNODE
;
236 /*===========================================================================*
238 *===========================================================================*/
239 PRIVATE
struct vnode
*new_node(mode_t bits
)
241 struct vnode
*dirp
, *vp
;
243 struct node_details res
;
246 /* See if the path can be opened down to the last directory. */
247 if ((dirp
= last_dir()) == NIL_VNODE
) return(NIL_VNODE
);
249 /* The final directory is accessible. Get final component of the path. */
250 vp
= advance(dirp
, 0);
251 if (vp
== NIL_VNODE
&& err_code
== ENOENT
) {
252 /* Last path component does not exist. Make a new directory entry. */
253 if ((vp
= get_free_vnode()) == NIL_VNODE
) {
254 /* Can't create new vnode: out of vnodes. */
258 if ((r
= forbidden(dirp
, W_BIT
|X_BIT
)) != OK
||
259 (r
= req_create(dirp
->v_fs_e
, dirp
->v_inode_nr
,bits
, fp
->fp_effuid
,
260 fp
->fp_effgid
, user_fullpath
, &res
)) != OK
) {
261 /* Can't create new directory entry: either no permission or
262 something else is wrong. */
268 /* Store results and mark vnode in use */
269 vp
->v_fs_e
= res
.fs_e
;
270 vp
->v_inode_nr
= res
.inode_nr
;
271 vp
->v_mode
= res
.fmode
;
272 vp
->v_size
= res
.fsize
;
275 vp
->v_sdev
= res
.dev
;
276 vp
->v_vmnt
= dirp
->v_vmnt
;
277 vp
->v_dev
= vp
->v_vmnt
->m_dev
;
281 /* Either last component exists, or there is some other problem. */
294 /*===========================================================================*
296 *===========================================================================*/
297 PRIVATE
int pipe_open(register struct vnode
*vp
, register mode_t bits
,
300 /* This function is called from common_open. It checks if
301 * there is at least one reader/writer pair for the pipe, if not
302 * it suspends the caller, otherwise it revives all other blocked
303 * processes hanging on the pipe.
308 if((bits
& (R_BIT
|W_BIT
)) == (R_BIT
|W_BIT
)) return(ENXIO
);
310 if (find_filp(vp
, bits
& W_BIT
? R_BIT
: W_BIT
) == NIL_FILP
) {
311 if (oflags
& O_NONBLOCK
) {
312 if (bits
& W_BIT
) return(ENXIO
);
314 suspend(FP_BLOCKED_ON_POPEN
); /* suspend caller */
317 } else if (susp_count
> 0) { /* revive blocked processes */
318 release(vp
, OPEN
, susp_count
);
319 release(vp
, CREAT
, susp_count
);
325 /*===========================================================================*
327 *===========================================================================*/
328 PUBLIC
int do_mknod()
330 /* Perform the mknod(name, mode, addr) system call. */
331 register mode_t bits
, mode_bits
;
335 /* Only the super_user may make nodes other than fifos. */
336 mode_bits
= (mode_t
) m_in
.mk_mode
; /* mode of the inode */
337 if(!super_user
&& ((mode_bits
& I_TYPE
) != I_NAMED_PIPE
)) return(EPERM
);
338 bits
= (mode_bits
& I_TYPE
) | (mode_bits
& ALL_MODES
& fp
->fp_umask
);
340 /* Open directory that's going to hold the new node. */
341 if(fetch_name(m_in
.name1
, m_in
.name1_length
, M1
) != OK
) return(err_code
);
342 if((vp
= last_dir()) == NIL_VNODE
) return(err_code
);
344 /* Make sure that the object is a directory */
345 if((vp
->v_mode
& I_TYPE
) != I_DIRECTORY
) {
350 if ((r
= forbidden(vp
, W_BIT
|X_BIT
)) == OK
) {
351 r
= req_mknod(vp
->v_fs_e
, vp
->v_inode_nr
, user_fullpath
, fp
->fp_effuid
,
352 fp
->fp_effgid
, bits
, m_in
.mk_z0
);
360 /*===========================================================================*
362 *===========================================================================*/
363 PUBLIC
int do_mkdir()
365 /* Perform the mkdir(name, mode) system call. */
366 mode_t bits
; /* mode bits for the new inode */
370 if(fetch_name(m_in
.name1
, m_in
.name1_length
, M1
) != OK
) return(err_code
);
372 bits
= I_DIRECTORY
| (m_in
.mode
& RWX_MODES
& fp
->fp_umask
);
375 if((vp
= last_dir()) == NIL_VNODE
) return(err_code
);
377 /* Make sure that the object is a directory */
378 if ((vp
->v_mode
& I_TYPE
) != I_DIRECTORY
) {
383 if ((r
= forbidden(vp
, W_BIT
|X_BIT
)) == OK
) {
384 r
= req_mkdir(vp
->v_fs_e
, vp
->v_inode_nr
, user_fullpath
, fp
->fp_effuid
,
385 fp
->fp_effgid
, bits
);
393 /*===========================================================================*
395 *===========================================================================*/
396 PUBLIC
int do_lseek()
398 /* Perform the lseek(ls_fd, offset, whence) system call. */
399 register struct filp
*rfilp
;
404 /* Check to see if the file descriptor is valid. */
405 if ( (rfilp
= get_filp(m_in
.ls_fd
)) == NIL_FILP
) return(err_code
);
407 /* No lseek on pipes. */
408 if (rfilp
->filp_vno
->v_pipe
== I_PIPE
) return(ESPIPE
);
410 /* The value of 'whence' determines the start position to use. */
411 switch(m_in
.whence
) {
412 case SEEK_SET
: pos
= cvu64(0); break;
413 case SEEK_CUR
: pos
= rfilp
->filp_pos
; break;
414 case SEEK_END
: pos
= cvul64(rfilp
->filp_vno
->v_size
); break;
415 default: return(EINVAL
);
418 offset
= m_in
.offset_lo
;
420 newpos
= add64ul(pos
, offset
);
422 newpos
= sub64ul(pos
, -offset
);
424 /* Check for overflow. */
425 if (ex64hi(newpos
) != 0)
428 if (cmp64(newpos
, rfilp
->filp_pos
) != 0) { /* Inhibit read ahead request */
429 r
= req_inhibread(rfilp
->filp_vno
->v_fs_e
, rfilp
->filp_vno
->v_inode_nr
);
430 if (r
!= OK
) return(r
);
433 rfilp
->filp_pos
= newpos
;
435 /* insert the new position into the output message */
436 m_out
.reply_l1
= ex64lo(newpos
);
442 /*===========================================================================*
444 *===========================================================================*/
445 PUBLIC
int do_llseek()
447 /* Perform the llseek(ls_fd, offset, whence) system call. */
448 register struct filp
*rfilp
;
452 /* Check to see if the file descriptor is valid. */
453 if ( (rfilp
= get_filp(m_in
.ls_fd
)) == NIL_FILP
) return(err_code
);
455 /* No lseek on pipes. */
456 if (rfilp
->filp_vno
->v_pipe
== I_PIPE
) return(ESPIPE
);
458 /* The value of 'whence' determines the start position to use. */
459 switch(m_in
.whence
) {
460 case SEEK_SET
: pos
= cvu64(0); break;
461 case SEEK_CUR
: pos
= rfilp
->filp_pos
; break;
462 case SEEK_END
: pos
= cvul64(rfilp
->filp_vno
->v_size
); break;
463 default: return(EINVAL
);
466 newpos
= add64(pos
, make64(m_in
.offset_lo
, m_in
.offset_high
));
468 /* Check for overflow. */
469 if (((long)m_in
.offset_high
> 0) && cmp64(newpos
, pos
) < 0)
471 if (((long)m_in
.offset_high
< 0) && cmp64(newpos
, pos
) > 0)
474 if (cmp64(newpos
, rfilp
->filp_pos
) != 0) { /* Inhibit read ahead request */
475 r
= req_inhibread(rfilp
->filp_vno
->v_fs_e
, rfilp
->filp_vno
->v_inode_nr
);
476 if (r
!= OK
) return(r
);
479 rfilp
->filp_pos
= newpos
;
480 m_out
.reply_l1
= ex64lo(newpos
);
481 m_out
.reply_l2
= ex64hi(newpos
);
486 /*===========================================================================*
488 *===========================================================================*/
489 PUBLIC
int do_close()
491 /* Perform the close(fd) system call. */
492 return close_fd(fp
, m_in
.fd
);
496 /*===========================================================================*
498 *===========================================================================*/
499 PUBLIC
int close_fd(rfp
, fd_nr
)
503 /* Perform the close(fd) system call. */
504 register struct filp
*rfilp
;
505 register struct vnode
*vp
;
506 struct file_lock
*flp
;
509 /* First locate the vnode that belongs to the file descriptor. */
510 if ( (rfilp
= get_filp2(rfp
, fd_nr
)) == NIL_FILP
) return(err_code
);
511 vp
= rfilp
->filp_vno
;
514 FD_CLR(fd_nr
, &rfp
->fp_cloexec_set
);
515 rfp
->fp_filp
[fd_nr
] = NIL_FILP
;
516 FD_CLR(fd_nr
, &rfp
->fp_filp_inuse
);
518 /* Check to see if the file is locked. If so, release all locks. */
519 if (nr_locks
== 0) return(OK
);
520 lock_count
= nr_locks
; /* save count of locks */
521 for (flp
= &file_lock
[0]; flp
< &file_lock
[NR_LOCKS
]; flp
++) {
522 if (flp
->lock_type
== 0) continue; /* slot not in use */
523 if (flp
->lock_vnode
== vp
&& flp
->lock_pid
== rfp
->fp_pid
) {
528 if (nr_locks
< lock_count
) lock_revive(); /* lock released */
533 /*===========================================================================*
535 *===========================================================================*/
536 PUBLIC
void close_filp(fp
)
544 if (fp
->filp_count
- 1 == 0 && fp
->filp_mode
!= FILP_CLOSED
) {
545 /* Check to see if the file is special. */
546 mode_word
= vp
->v_mode
& I_TYPE
;
547 if (mode_word
== I_CHAR_SPECIAL
|| mode_word
== I_BLOCK_SPECIAL
) {
548 dev
= (dev_t
) vp
->v_sdev
;
549 if (mode_word
== I_BLOCK_SPECIAL
) {
550 if (vp
->v_bfs_e
== ROOT_FS_E
) {
551 /* Invalidate the cache unless the special is
552 * mounted. Assume that the root filesystem's
553 * is open only for fsck.
555 req_flush(vp
->v_bfs_e
, dev
);
558 /* Do any special processing on device close. */
559 (void) dev_close(dev
, fp
-filp
);
561 /* Ignore any errors, even SUSPEND. */
565 /* If the inode being closed is a pipe, release everyone hanging on it. */
566 if (vp
->v_pipe
== I_PIPE
) {
567 rw
= (fp
->filp_mode
& R_BIT
? WRITE
: READ
);
568 release(vp
, rw
, NR_PROCS
);
571 /* If a write has been done, the inode is already marked as DIRTY. */
572 if (--fp
->filp_count
== 0) {
573 if (vp
->v_pipe
== I_PIPE
) {
574 /* Last reader or writer is going. Tell MFS about latest
577 truncate_vnode(vp
, vp
->v_size
);
580 put_vnode(fp
->filp_vno
);
585 /*===========================================================================*
587 *===========================================================================*/
588 PUBLIC
void close_reply()
590 /* No need to do anything */
594 /*===========================================================================*
596 *===========================================================================*/
597 PUBLIC
int do_vm_open()
602 len
= m_in
.VMVO_NAME_LENGTH
;
603 m_out
.VMV_ENDPOINT
= ep
= m_in
.VMVO_ENDPOINT
;
605 /* Do open() call on behalf of any process, performed by VM. */
606 if(len
< 2 || len
> sizeof(user_fullpath
)) {
607 printf("do_vm_open: strange length %d\n", len
);
608 m_out
.VMVRO_FD
= EINVAL
;
609 return(VM_VFS_REPLY_OPEN
);
612 /* Do open on behalf of which process? */
613 if(isokendpt(ep
, &n
) != OK
) {
614 printf("do_vm_open: strange endpoint %d\n", ep
);
615 m_out
.VMVRO_FD
= EINVAL
;
616 return(VM_VFS_REPLY_OPEN
);
619 /* XXX - do open on behalf of this process */
622 /* Get path name from VM address space. */
623 if((r
=sys_safecopyfrom(VM_PROC_NR
, m_in
.VMVO_NAME_GRANT
, 0,
624 (vir_bytes
) user_fullpath
, len
, D
)) != OK
) {
625 printf("do_vm_open: sys_safecopyfrom failed: %d\n", r
);
626 m_out
.VMVRO_FD
= EPERM
;
627 return(VM_VFS_REPLY_OPEN
);
630 /* Check if path is null-terminated. */
631 if(user_fullpath
[len
-1] != '\0') {
632 printf("do_vm_open: name (len %d) not 0-terminated\n", len
);
633 m_out
.VMVRO_FD
= EINVAL
;
634 return(VM_VFS_REPLY_OPEN
);
637 /* Perform open(). */
638 m_out
.VMVRO_FD
= common_open(m_in
.VMVO_FLAGS
, m_in
.VMVO_MODE
);
639 m_out
.VMV_ENDPOINT
= ep
;
641 /* Send open() reply. */
642 return(VM_VFS_REPLY_OPEN
);
646 /*===========================================================================*
648 *===========================================================================*/
649 PUBLIC
int do_vm_close()
654 len
= m_in
.VMVO_NAME_LENGTH
;
656 /* Do close() call on behalf of any process, performed by VM. */
657 m_out
.VMV_ENDPOINT
= ep
= m_in
.VMVC_ENDPOINT
;
658 if(isokendpt(ep
, &n
) != OK
) {
659 printf("do_vm_close: strange endpoint %d\n", ep
);
660 return(VM_VFS_REPLY_CLOSE
);
663 /* Perform close(). */
664 r
= close_fd(&fproc
[n
], m_in
.VMVC_FD
);
666 return(VM_VFS_REPLY_CLOSE
);