8 #include <minix/callnr.h>
14 #include <minix/vfsif.h>
16 PRIVATE
char mode_map
[] = {R_BIT
, W_BIT
, R_BIT
|W_BIT
, 0};
17 FORWARD
_PROTOTYPE( struct inode
*new_node
, (struct inode
*ldirp
,
18 char *string
, mode_t bits
, zone_t z0
));
21 /*===========================================================================*
23 *===========================================================================*/
26 int r
, b
, exist
= TRUE
;
34 /* Read request message */
35 oflags
= fs_m_in
.REQ_FLAGS
;
36 omode
= fs_m_in
.REQ_MODE
;
39 caller_uid
= fs_m_in
.REQ_UID
;
40 caller_gid
= fs_m_in
.REQ_GID
;
42 /* Device number only for device special files */
43 fs_m_out
.RES_DEV
= NO_DEV
;
45 /* Remap the bottom two bits of oflags. */
46 bits
= (mode_t
) mode_map
[oflags
& O_ACCMODE
];
49 /* If O_CREATE is set, try to make the file. */
50 if (oflags
& O_CREAT
) {
52 /* Copy the last component */
53 len
= MFS_MIN(fs_m_in
.REQ_PATH_LEN
, sizeof(lastc
));
54 err_code
= sys_datacopy(FS_PROC_NR
, (vir_bytes
) fs_m_in
.REQ_PATH
,
55 SELF
, (vir_bytes
) lastc
, (phys_bytes
) len
);
56 if (err_code
!= OK
) return err_code
;
57 MFS_NUL(lastc
, len
, sizeof(lastc
));
59 /* Get last directory inode */
60 if ((ldirp
= get_inode(fs_dev
, fs_m_in
.REQ_INODE_NR
)) == NIL_INODE
) {
61 printf("MFS(%d) get_inode for parent dir by creat() failed\n", SELF_E
);
65 /* Create a new inode by calling new_node(). */
66 rip
= new_node(ldirp
, lastc
, omode
, NO_ZONE
);
68 if (r
== OK
) exist
= FALSE
; /* we just created the file */
69 else if (r
!= EEXIST
) {
71 return(r
); /* other error */
73 else exist
= !(oflags
& O_EXCL
); /* file exists, if the O_EXCL
74 flag is set this is an error */
78 if ( (rip
= get_inode(fs_dev
, fs_m_in
.REQ_INODE_NR
)) == NIL_INODE
) {
79 printf("MFS(%d) get_inode by open() failed\n", SELF_E
);
85 /* Only do the normal open code if we didn't just create the file. */
87 /* Check protections. */
88 if ((r
= forbidden(rip
, bits
)) == OK
) {
89 /* Opening reg. files directories and special files differ. */
90 switch (rip
->i_mode
& I_TYPE
) {
92 /* Truncate regular file if O_TRUNC. */
93 if (oflags
& O_TRUNC
) {
94 panic(__FILE__
, "O_TRUNC in mfs.", oflags
);
96 if ((r
= forbidden(rip
, W_BIT
)) !=OK
) break;
97 truncate_inode(rip
, 0);
99 /* Send the inode from the inode cache to the
100 * block cache, so it gets written on the next
103 rw_inode(rip
, WRITING
);
109 /* Directories may be read but not written. */
110 r
= (bits
& W_BIT
? EISDIR
: OK
);
114 case I_BLOCK_SPECIAL
:
115 /* Send back the device number */
116 fs_m_out
.RES_DEV
= (Dev_t
) rip
->i_zone
[0];
120 rip
->i_pipe
= I_PIPE
;
126 /* If error, release inode. */
134 fs_m_out
.m_source
= rip
->i_dev
; /* filled with FS endpoint by the system */
135 fs_m_out
.RES_INODE_NR
= rip
->i_num
;
136 fs_m_out
.RES_MODE
= rip
->i_mode
;
137 fs_m_out
.RES_FILE_SIZE
= rip
->i_size
;
138 fs_m_out
.RES_INODE_INDEX
= (rip
- &inode
[0]) / sizeof(struct inode
);
140 /* This values are needed for the execution */
141 fs_m_out
.RES_UID
= rip
->i_uid
;
142 fs_m_out
.RES_GID
= rip
->i_gid
;
143 if ((rip
->i_mode
& I_TYPE
) == I_REGULAR
) fs_m_out
.RES_CTIME
= rip
->i_ctime
;
145 /* Drop parent dir */
151 /*===========================================================================*
153 *===========================================================================*/
154 PUBLIC
int fs_create()
161 char lastc
[NAME_MAX
];
163 /* Read request message */
164 omode
= fs_m_in
.REQ_MODE
;
166 caller_uid
= fs_m_in
.REQ_UID
;
167 caller_gid
= fs_m_in
.REQ_GID
;
169 /* Try to make the file. */
171 /* Copy the last component */
172 len
= MFS_MIN(fs_m_in
.REQ_PATH_LEN
, sizeof(lastc
));
173 err_code
= sys_datacopy(FS_PROC_NR
, (vir_bytes
) fs_m_in
.REQ_PATH
,
174 SELF
, (vir_bytes
) lastc
, (phys_bytes
) len
);
175 if (err_code
!= OK
) return err_code
;
176 MFS_NUL(lastc
, len
, sizeof(lastc
));
178 /* Get last directory inode */
179 if ((ldirp
= get_inode(fs_dev
, fs_m_in
.REQ_INODE_NR
)) == NIL_INODE
) {
180 printf("MFS(%d) get_inode for parent dir by creat() failed\n", SELF_E
);
184 /* Create a new inode by calling new_node(). */
185 rip
= new_node(ldirp
, lastc
, omode
, NO_ZONE
);
188 /* If error, release inode. */
196 fs_m_out
.m_source
= rip
->i_dev
; /* filled with FS endpoint by the system */
197 fs_m_out
.RES_INODE_NR
= rip
->i_num
;
198 fs_m_out
.RES_MODE
= rip
->i_mode
;
199 fs_m_out
.RES_FILE_SIZE
= rip
->i_size
;
200 fs_m_out
.RES_INODE_INDEX
= (rip
- &inode
[0]) / sizeof(struct inode
);
202 /* This values are needed for the execution */
203 fs_m_out
.RES_UID
= rip
->i_uid
;
204 fs_m_out
.RES_GID
= rip
->i_gid
;
205 if ((rip
->i_mode
& I_TYPE
) == I_REGULAR
) fs_m_out
.RES_CTIME
= rip
->i_ctime
;
207 /* Drop parent dir */
213 /*===========================================================================*
215 *===========================================================================*/
216 PUBLIC
int fs_mknod()
218 struct inode
*ip
, *ldirp
;
219 char lastc
[NAME_MAX
];
222 /* Copy the last component and set up caller's user and group id */
223 len
= MFS_MIN(fs_m_in
.REQ_PATH_LEN
, sizeof(lastc
));
224 err_code
= sys_datacopy(FS_PROC_NR
, (vir_bytes
) fs_m_in
.REQ_PATH
, SELF
,
225 (vir_bytes
) lastc
, (phys_bytes
) len
);
226 if (err_code
!= OK
) return err_code
;
227 MFS_NUL(lastc
, len
, sizeof(lastc
));
229 caller_uid
= fs_m_in
.REQ_UID
;
230 caller_gid
= fs_m_in
.REQ_GID
;
232 /* Get last directory inode */
233 if ((ldirp
= get_inode(fs_dev
, fs_m_in
.REQ_INODE_NR
)) == NIL_INODE
) {
234 printf("MFS(%d) get_inode for parent dir by mknod() failed\n", SELF_E
);
238 /* Try to create the new node */
239 ip
= new_node(ldirp
, lastc
, fs_m_in
.REQ_MODE
, (zone_t
) fs_m_in
.REQ_DEV
);
247 /*===========================================================================*
249 *===========================================================================*/
250 PUBLIC
int fs_mkdir()
252 int r1
, r2
; /* status codes */
253 ino_t dot
, dotdot
; /* inode numbers for . and .. */
254 struct inode
*rip
, *ldirp
;
255 char lastc
[NAME_MAX
]; /* last component */
258 /* Copy the last component and set up caller's user and group id */
259 len
= MFS_MIN(fs_m_in
.REQ_PATH_LEN
, sizeof(lastc
));
260 err_code
= sys_datacopy(FS_PROC_NR
, (vir_bytes
) fs_m_in
.REQ_PATH
, SELF
,
261 (vir_bytes
) lastc
, (phys_bytes
) len
);
262 if (err_code
!= OK
) return err_code
;
263 MFS_NUL(lastc
, len
, sizeof(lastc
));
265 caller_uid
= fs_m_in
.REQ_UID
;
266 caller_gid
= fs_m_in
.REQ_GID
;
268 /* Get last directory inode */
269 if ((ldirp
= get_inode(fs_dev
, fs_m_in
.REQ_INODE_NR
)) == NIL_INODE
) {
270 printf("MFS(%d) get_inode for parent dir by mkdir() failed\n", SELF_E
);
274 /* Next make the inode. If that fails, return error code. */
275 rip
= new_node(ldirp
, lastc
, fs_m_in
.REQ_MODE
, (zone_t
) 0);
277 if (rip
== NIL_INODE
|| err_code
== EEXIST
) {
278 put_inode(rip
); /* can't make dir: it already exists */
283 /* Get the inode numbers for . and .. to enter in the directory. */
284 dotdot
= ldirp
->i_num
; /* parent's inode number */
285 dot
= rip
->i_num
; /* inode number of the new dir itself */
287 /* Now make dir entries for . and .. unless the disk is completely full. */
288 /* Use dot1 and dot2, so the mode of the directory isn't important. */
289 rip
->i_mode
= fs_m_in
.REQ_MODE
; /* set mode */
290 r1
= search_dir(rip
, dot1
, &dot
, ENTER
); /* enter . in the new dir */
291 r2
= search_dir(rip
, dot2
, &dotdot
, ENTER
); /* enter .. in the new dir */
293 /* If both . and .. were successfully entered, increment the link counts. */
294 if (r1
== OK
&& r2
== OK
) {
295 /* Normal case. It was possible to enter . and .. in the new dir. */
296 rip
->i_nlinks
++; /* this accounts for . */
297 ldirp
->i_nlinks
++; /* this accounts for .. */
298 ldirp
->i_dirt
= DIRTY
; /* mark parent's inode as dirty */
300 /* It was not possible to enter . or .. probably disk was full -
301 * links counts haven't been touched.
303 if(search_dir(ldirp
, lastc
, (ino_t
*) 0, DELETE
) != OK
)
304 panic(__FILE__
, "Dir disappeared ", rip
->i_num
);
305 rip
->i_nlinks
--; /* undo the increment done in new_node() */
307 rip
->i_dirt
= DIRTY
; /* either way, i_nlinks has changed */
309 put_inode(ldirp
); /* return the inode of the parent dir */
310 put_inode(rip
); /* return the inode of the newly made dir */
311 return(err_code
); /* new_node() always sets 'err_code' */
314 /*===========================================================================*
316 *===========================================================================*/
317 PUBLIC
int fs_slink()
320 struct inode
*sip
; /* inode containing symbolic link */
321 struct inode
*ldirp
; /* directory containing link */
322 register int r
; /* error code */
323 char string
[NAME_MAX
]; /* last component of the new dir's path name */
324 struct buf
*bp
; /* disk buffer for link */
326 caller_uid
= fs_m_in
.REQ_UID
;
327 caller_gid
= fs_m_in
.REQ_GID
;
329 /* Temporarily open the dir. */
330 if ( (ldirp
= get_inode(fs_dev
, fs_m_in
.REQ_INODE_NR
)) == NIL_INODE
) {
334 /* Copy the link name's last component */
335 len
= MFS_MIN(fs_m_in
.REQ_PATH_LEN
, sizeof(string
));
336 r
= sys_datacopy(FS_PROC_NR
, (vir_bytes
) fs_m_in
.REQ_PATH
,
337 SELF
, (vir_bytes
) string
, (phys_bytes
) len
);
338 if (r
!= OK
) return r
;
339 MFS_NUL(string
, len
, sizeof(string
));
341 /* Create the inode for the symlink. */
342 sip
= new_node(ldirp
, string
, (mode_t
) (I_SYMBOLIC_LINK
| RWX_MODES
),
345 /* Allocate a disk block for the contents of the symlink.
346 * Copy contents of symlink (the name pointed to) into first disk block.
348 if ((r
= err_code
) == OK
) {
349 r
= (bp
= new_block(sip
, (off_t
) 0)) == NIL_BUF
? err_code
:
350 sys_vircopy(fs_m_in
.REQ_WHO_E
, D
, (vir_bytes
) fs_m_in
.REQ_USER_ADDR
,
351 SELF
, D
, (vir_bytes
) bp
->b_data
,
352 (vir_bytes
) fs_m_in
.REQ_SLENGTH
);
355 bp
->b_data
[_MIN_BLOCK_SIZE
-1] = '\0';
356 sip
->i_size
= strlen(bp
->b_data
);
357 /*if(sip->i_size != m_in.name1_length-1) {*/
358 if(sip
->i_size
!= fs_m_in
.REQ_SLENGTH
) {
359 /* This can happen if the user provides a buffer
360 * with a \0 in it. This can cause a lot of trouble
361 * when the symlink is used later. We could just use
362 * the strlen() value, but we want to let the user
363 * know he did something wrong. ENAMETOOLONG doesn't
364 * exactly describe the error, but there is no
371 put_block(bp
, DIRECTORY_BLOCK
); /* put_block() accepts NIL_BUF. */
375 if (search_dir(ldirp
, string
, (ino_t
*) 0, DELETE
) != OK
)
376 panic(__FILE__
, "Symbolic link vanished", NO_NUM
);
380 /* put_inode() accepts NIL_INODE as a noop, so the below are safe. */
389 /*===========================================================================*
391 *===========================================================================*/
392 PRIVATE
struct inode
*new_node(struct inode
*ldirp
,
393 char *string
, mode_t bits
, zone_t z0
)
395 /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().
396 * In all cases it allocates a new inode, makes a directory entry for it in
397 * the ldirp directory with string name, and initializes it.
398 * It returns a pointer to the inode if it can do this;
399 * otherwise it returns NIL_INODE. It always sets 'err_code'
400 * to an appropriate value (OK or an error code).
402 * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
403 * has to hold at least NAME_MAX bytes.
406 register struct inode
*rip
;
409 /* Get final component of the path. */
410 rip
= advance(&ldirp
, string
);
413 (ldirp
)->i_nlinks
>= ((ldirp
)->i_sp
->s_version
== V1
?
414 CHAR_MAX
: SHRT_MAX
)) {
415 /* New entry is a directory, alas we can't give it a ".." */
421 if ( rip
== NIL_INODE
&& err_code
== ENOENT
) {
422 /* Last path component does not exist. Make new directory entry. */
423 if ( (rip
= alloc_inode((ldirp
)->i_dev
, bits
)) == NIL_INODE
) {
424 /* Can't creat new inode: out of inodes. */
428 /* Force inode to the disk before making directory entry to make
429 * the system more robust in the face of a crash: an inode with
430 * no directory entry is much better than the opposite.
433 rip
->i_zone
[0] = z0
; /* major/minor device numbers */
434 rw_inode(rip
, WRITING
); /* force inode to disk now */
436 /* New inode acquired. Try to make directory entry. */
437 if ((r
= search_dir(ldirp
, string
, &rip
->i_num
, ENTER
)) != OK
) {
438 rip
->i_nlinks
--; /* pity, have to free disk inode */
439 rip
->i_dirt
= DIRTY
; /* dirty inodes are written out */
440 put_inode(rip
); /* this call frees the inode */
446 /* Either last component exists, or there is some problem. */
447 if (rip
!= NIL_INODE
|| err_code
== EENTERMOUNT
||
448 err_code
== ELEAVEMOUNT
)
454 /* The caller has to return the directory inode (*ldirp). */
464 /*===========================================================================*
466 *===========================================================================*/
467 PUBLIC
int fs_inhibread()
471 if ((rip
= find_inode(fs_dev
, fs_m_in
.REQ_INODE_NR
))== NIL_INODE
){
472 printf("FSinhibread: couldn't find inode %d\n", fs_m_in
.REQ_INODE_NR
);
476 /* inhibit read ahead */