. service tells you which device it couldn't stat
[minix3.git] / servers / mfs / open.c
blobeb5245b9cec803f3d3057176f051100b3d0e5bf8
3 #include "fs.h"
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <minix/callnr.h>
9 #include <minix/com.h>
10 #include "buf.h"
11 #include "inode.h"
12 #include "super.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 /*===========================================================================*
22 * fs_open *
23 *===========================================================================*/
24 PUBLIC int fs_open()
26 int r, b, exist = TRUE;
27 struct inode *ldirp;
28 struct inode *rip;
29 int oflags;
30 mode_t omode;
31 mode_t bits;
32 char lastc[NAME_MAX];
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) {
51 phys_bytes len;
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);
62 return ENOENT;
65 /* Create a new inode by calling new_node(). */
66 rip = new_node(ldirp, lastc, omode, NO_ZONE);
67 r = err_code;
68 if (r == OK) exist = FALSE; /* we just created the file */
69 else if (r != EEXIST) {
70 put_inode(ldirp);
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 */
76 else {
77 /* Get file inode. */
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);
80 return ENOENT;
82 ldirp = NIL_INODE;
85 /* Only do the normal open code if we didn't just create the file. */
86 if (exist) {
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) {
91 case I_REGULAR:
92 /* Truncate regular file if O_TRUNC. */
93 if (oflags & O_TRUNC) {
94 panic(__FILE__, "O_TRUNC in mfs.", oflags);
95 #if 0
96 if ((r = forbidden(rip, W_BIT)) !=OK) break;
97 truncate_inode(rip, 0);
98 wipe_inode(rip);
99 /* Send the inode from the inode cache to the
100 * block cache, so it gets written on the next
101 * cache flush.
103 rw_inode(rip, WRITING);
104 #endif
106 break;
108 case I_DIRECTORY:
109 /* Directories may be read but not written. */
110 r = (bits & W_BIT ? EISDIR : OK);
111 break;
113 case I_CHAR_SPECIAL:
114 case I_BLOCK_SPECIAL:
115 /* Send back the device number */
116 fs_m_out.RES_DEV = (Dev_t) rip->i_zone[0];
117 break;
119 case I_NAMED_PIPE:
120 rip->i_pipe = I_PIPE;
121 break;
126 /* If error, release inode. */
127 if (r != OK) {
128 put_inode(ldirp);
129 put_inode(rip);
130 return(r);
133 /* Reply message */
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 */
146 put_inode(ldirp);
148 return OK;
151 /*===========================================================================*
152 * fs_create *
153 *===========================================================================*/
154 PUBLIC int fs_create()
156 phys_bytes len;
157 int r, b;
158 struct inode *ldirp;
159 struct inode *rip;
160 mode_t omode;
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);
181 return ENOENT;
184 /* Create a new inode by calling new_node(). */
185 rip = new_node(ldirp, lastc, omode, NO_ZONE);
186 r = err_code;
188 /* If error, release inode. */
189 if (r != OK) {
190 put_inode(ldirp);
191 put_inode(rip);
192 return(r);
195 /* Reply message */
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 */
208 put_inode(ldirp);
210 return OK;
213 /*===========================================================================*
214 * fs_mknod *
215 *===========================================================================*/
216 PUBLIC int fs_mknod()
218 struct inode *ip, *ldirp;
219 char lastc[NAME_MAX];
220 phys_bytes len;
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);
235 return ENOENT;
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);
241 put_inode(ip);
242 put_inode(ldirp);
243 return(err_code);
247 /*===========================================================================*
248 * fs_mkdir *
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 */
256 phys_bytes len;
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);
271 return ENOENT;
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 */
279 put_inode(ldirp);
280 return(err_code);
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 */
299 } else {
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 /*===========================================================================*
315 * fs_slink *
316 *===========================================================================*/
317 PUBLIC int fs_slink()
319 phys_bytes len;
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) {
331 return(EINVAL);
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),
343 (zone_t) 0);
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);
354 if(r == OK) {
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
365 * ENAMETOOWRONG.
367 r = ENAMETOOLONG;
371 put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NIL_BUF. */
373 if (r != OK) {
374 sip->i_nlinks = 0;
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. */
381 put_inode(sip);
382 put_inode(ldirp);
384 return(r);
389 /*===========================================================================*
390 * new_node *
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;
407 register int r;
409 /* Get final component of the path. */
410 rip = advance(&ldirp, string);
412 if (S_ISDIR(bits) &&
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 ".." */
416 put_inode(rip);
417 err_code = EMLINK;
418 return(NIL_INODE);
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. */
425 return(NIL_INODE);
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.
432 rip->i_nlinks++;
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 */
441 err_code = r;
442 return(NIL_INODE);
445 } else {
446 /* Either last component exists, or there is some problem. */
447 if (rip != NIL_INODE || err_code == EENTERMOUNT ||
448 err_code == ELEAVEMOUNT)
449 r = EEXIST;
450 else
451 r = err_code;
454 /* The caller has to return the directory inode (*ldirp). */
455 err_code = r;
456 return(rip);
464 /*===========================================================================*
465 * fs_inhibread *
466 *===========================================================================*/
467 PUBLIC int fs_inhibread()
469 struct inode *rip;
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);
473 return EINVAL;
476 /* inhibit read ahead */
477 rip->i_seek = ISEEK;
479 return OK;