add swifi to the build/install.
[minix.git] / servers / mfs / open.c
blob72ea55c75079cc9d0988593731ca67535c722229
1 #include "fs.h"
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <minix/callnr.h>
7 #include <minix/com.h>
8 #include "buf.h"
9 #include "inode.h"
10 #include "super.h"
11 #include <minix/vfsif.h>
13 PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0};
14 FORWARD _PROTOTYPE( struct inode *new_node, (struct inode *ldirp,
15 char *string, mode_t bits, zone_t z0));
18 /*===========================================================================*
19 * fs_create *
20 *===========================================================================*/
21 PUBLIC int fs_create()
23 phys_bytes len;
24 int r, b;
25 struct inode *ldirp;
26 struct inode *rip;
27 mode_t omode;
28 char lastc[NAME_MAX];
30 /* Read request message */
31 omode = fs_m_in.REQ_MODE;
32 caller_uid = fs_m_in.REQ_UID;
33 caller_gid = fs_m_in.REQ_GID;
35 /* Try to make the file. */
37 /* Copy the last component (i.e., file name) */
38 len = MFS_MIN(fs_m_in.REQ_PATH_LEN, sizeof(lastc));
39 err_code = sys_safecopyfrom(FS_PROC_NR, fs_m_in.REQ_GRANT, 0,
40 (vir_bytes) lastc, (phys_bytes) len, D);
41 if (err_code != OK) return err_code;
42 MFS_NUL(lastc, len, sizeof(lastc));
44 /* Get last directory inode (i.e., directory that will hold the new inode) */
45 if ((ldirp = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE)
46 return(ENOENT);
48 /* Create a new inode by calling new_node(). */
49 rip = new_node(ldirp, lastc, omode, NO_ZONE);
50 r = err_code;
52 /* If an error occurred, release inode. */
53 if (r != OK) {
54 put_inode(ldirp);
55 put_inode(rip);
56 return(r);
59 /* Reply message */
60 fs_m_out.m_source = rip->i_dev; /* filled with FS endpoint by the system */
61 fs_m_out.RES_INODE_NR = rip->i_num;
62 fs_m_out.RES_MODE = rip->i_mode;
63 fs_m_out.RES_FILE_SIZE_LO = rip->i_size;
65 /* This values are needed for the execution */
66 fs_m_out.RES_UID = rip->i_uid;
67 fs_m_out.RES_GID = rip->i_gid;
69 /* Drop parent dir */
70 put_inode(ldirp);
72 return(OK);
76 /*===========================================================================*
77 * fs_mknod *
78 *===========================================================================*/
79 PUBLIC int fs_mknod()
81 struct inode *ip, *ldirp;
82 char lastc[NAME_MAX];
83 phys_bytes len;
85 /* Copy the last component and set up caller's user and group id */
86 len = MFS_MIN(fs_m_in.REQ_PATH_LEN, sizeof(lastc));
87 err_code = sys_safecopyfrom(FS_PROC_NR, fs_m_in.REQ_GRANT, 0,
88 (vir_bytes) lastc, (phys_bytes) len, D);
89 if (err_code != OK) return err_code;
90 MFS_NUL(lastc, len, sizeof(lastc));
92 caller_uid = fs_m_in.REQ_UID;
93 caller_gid = fs_m_in.REQ_GID;
95 /* Get last directory inode */
96 if((ldirp = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE)
97 return(ENOENT);
99 /* Try to create the new node */
100 ip = new_node(ldirp, lastc, fs_m_in.REQ_MODE, (zone_t) fs_m_in.REQ_DEV);
102 put_inode(ip);
103 put_inode(ldirp);
104 return(err_code);
108 /*===========================================================================*
109 * fs_mkdir *
110 *===========================================================================*/
111 PUBLIC int fs_mkdir()
113 int r1, r2; /* status codes */
114 ino_t dot, dotdot; /* inode numbers for . and .. */
115 struct inode *rip, *ldirp;
116 char lastc[NAME_MAX]; /* last component */
117 phys_bytes len;
119 /* Copy the last component and set up caller's user and group id */
120 len = MFS_MIN(fs_m_in.REQ_PATH_LEN, sizeof(lastc));
121 err_code = sys_safecopyfrom(FS_PROC_NR, fs_m_in.REQ_GRANT, 0,
122 (vir_bytes) lastc, (phys_bytes) len, D);
123 if(err_code != OK) return(err_code);
124 MFS_NUL(lastc, len, sizeof(lastc));
126 caller_uid = fs_m_in.REQ_UID;
127 caller_gid = fs_m_in.REQ_GID;
129 /* Get last directory inode */
130 if((ldirp = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE)
131 return(ENOENT);
133 /* Next make the inode. If that fails, return error code. */
134 rip = new_node(ldirp, lastc, fs_m_in.REQ_MODE, (zone_t) 0);
136 if(rip == NIL_INODE || err_code == EEXIST) {
137 put_inode(rip); /* can't make dir: it already exists */
138 put_inode(ldirp);
139 return(err_code);
142 /* Get the inode numbers for . and .. to enter in the directory. */
143 dotdot = ldirp->i_num; /* parent's inode number */
144 dot = rip->i_num; /* inode number of the new dir itself */
146 /* Now make dir entries for . and .. unless the disk is completely full. */
147 /* Use dot1 and dot2, so the mode of the directory isn't important. */
148 rip->i_mode = fs_m_in.REQ_MODE; /* set mode */
149 r1 = search_dir(rip, dot1, &dot, ENTER, IGN_PERM);/* enter . in the new dir*/
150 r2 = search_dir(rip, dot2, &dotdot, ENTER, IGN_PERM); /* enter .. in the new
151 dir */
153 /* If both . and .. were successfully entered, increment the link counts. */
154 if (r1 == OK && r2 == OK) {
155 /* Normal case. It was possible to enter . and .. in the new dir. */
156 rip->i_nlinks++; /* this accounts for . */
157 ldirp->i_nlinks++; /* this accounts for .. */
158 ldirp->i_dirt = DIRTY; /* mark parent's inode as dirty */
159 } else {
160 /* It was not possible to enter . or .. probably disk was full -
161 * links counts haven't been touched. */
162 if(search_dir(ldirp, lastc, (ino_t *) 0, DELETE, IGN_PERM) != OK)
163 panic(__FILE__, "Dir disappeared ", rip->i_num);
164 rip->i_nlinks--; /* undo the increment done in new_node() */
166 rip->i_dirt = DIRTY; /* either way, i_nlinks has changed */
168 put_inode(ldirp); /* return the inode of the parent dir */
169 put_inode(rip); /* return the inode of the newly made dir */
170 return(err_code); /* new_node() always sets 'err_code' */
174 /*===========================================================================*
175 * fs_slink *
176 *===========================================================================*/
177 PUBLIC int fs_slink()
179 phys_bytes len;
180 struct inode *sip; /* inode containing symbolic link */
181 struct inode *ldirp; /* directory containing link */
182 register int r; /* error code */
183 char string[NAME_MAX]; /* last component of the new dir's path name */
184 struct buf *bp; /* disk buffer for link */
186 caller_uid = fs_m_in.REQ_UID;
187 caller_gid = fs_m_in.REQ_GID;
189 /* Copy the link name's last component */
190 len = MFS_MIN(fs_m_in.REQ_PATH_LEN, sizeof(string));
191 r = sys_safecopyfrom(FS_PROC_NR, fs_m_in.REQ_GRANT, 0,
192 (vir_bytes) string, (phys_bytes) len, D);
193 if (r != OK) return(r);
194 MFS_NUL(string, len, sizeof(string));
196 /* Temporarily open the dir. */
197 if( (ldirp = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE)
198 return(EINVAL);
200 /* Create the inode for the symlink. */
201 sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES),
202 (zone_t) 0);
204 /* Allocate a disk block for the contents of the symlink.
205 * Copy contents of symlink (the name pointed to) into first disk block. */
206 if( (r = err_code) == OK) {
207 r = (bp = new_block(sip, (off_t) 0)) == NIL_BUF ? err_code :
208 sys_safecopyfrom(FS_PROC_NR, fs_m_in.REQ_GRANT3, 0,
209 (vir_bytes) bp->b_data,
210 (vir_bytes) fs_m_in.REQ_MEM_SIZE, D);
212 if(r == OK) {
213 bp->b_data[_MIN_BLOCK_SIZE-1] = '\0';
214 sip->i_size = strlen(bp->b_data);
215 if(sip->i_size != fs_m_in.REQ_MEM_SIZE) {
216 /* This can happen if the user provides a buffer
217 * with a \0 in it. This can cause a lot of trouble
218 * when the symlink is used later. We could just use
219 * the strlen() value, but we want to let the user
220 * know he did something wrong. ENAMETOOLONG doesn't
221 * exactly describe the error, but there is no
222 * ENAMETOOWRONG.
224 r = ENAMETOOLONG;
228 put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NIL_BUF. */
230 if(r != OK) {
231 sip->i_nlinks = 0;
232 if(search_dir(ldirp, string, (ino_t *) 0, DELETE,
233 IGN_PERM) != OK)
235 panic(__FILE__, "Symbolic link vanished", NO_NUM);
239 /* put_inode() accepts NIL_INODE as a noop, so the below are safe. */
240 put_inode(sip);
241 put_inode(ldirp);
243 return(r);
247 /*===========================================================================*
248 * fs_newnode *
249 *===========================================================================*/
250 PUBLIC int fs_newnode()
252 register int r;
253 mode_t bits;
254 struct inode *rip;
256 caller_uid = fs_m_in.REQ_UID;
257 caller_gid = fs_m_in.REQ_GID;
258 bits = fs_m_in.REQ_MODE;
260 /* Try to allocate the inode */
261 if( (rip = alloc_inode(fs_dev, bits) ) == NIL_INODE)
262 return err_code;
264 switch (bits & S_IFMT) {
265 case S_IFBLK:
266 case S_IFCHR:
267 rip->i_zone[0] = fs_m_in.REQ_DEV; /* major/minor dev numbers*/
268 break;
271 rw_inode(rip, WRITING); /* mark inode as allocated */
272 rip->i_update = ATIME | CTIME | MTIME;
274 /* Fill in the fields of the response message */
275 fs_m_out.RES_INODE_NR = rip->i_num;
276 fs_m_out.RES_MODE = rip->i_mode;
277 fs_m_out.RES_FILE_SIZE_LO = rip->i_size;
278 fs_m_out.RES_UID = rip->i_uid;
279 fs_m_out.RES_GID = rip->i_gid;
280 fs_m_out.RES_DEV = (dev_t) rip->i_zone[0];
282 return(OK);
286 /*===========================================================================*
287 * new_node *
288 *===========================================================================*/
289 PRIVATE struct inode *new_node(struct inode *ldirp,
290 char *string, mode_t bits, zone_t z0)
292 /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().
293 * In all cases it allocates a new inode, makes a directory entry for it in
294 * the ldirp directory with string name, and initializes it.
295 * It returns a pointer to the inode if it can do this;
296 * otherwise it returns NIL_INODE. It always sets 'err_code'
297 * to an appropriate value (OK or an error code).
299 * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
300 * has to hold at least NAME_MAX bytes.
303 register struct inode *rip;
304 register int r;
306 /* Get final component of the path. */
307 rip = advance(ldirp, string, IGN_PERM);
309 if (S_ISDIR(bits) &&
310 (ldirp)->i_nlinks >= ((ldirp)->i_sp->s_version == V1 ?
311 CHAR_MAX : SHRT_MAX)) {
312 /* New entry is a directory, alas we can't give it a ".." */
313 put_inode(rip);
314 err_code = EMLINK;
315 return(NIL_INODE);
318 if ( rip == NIL_INODE && err_code == ENOENT) {
319 /* Last path component does not exist. Make new directory entry. */
320 if ( (rip = alloc_inode((ldirp)->i_dev, bits)) == NIL_INODE) {
321 /* Can't creat new inode: out of inodes. */
322 return(NIL_INODE);
325 /* Force inode to the disk before making directory entry to make
326 * the system more robust in the face of a crash: an inode with
327 * no directory entry is much better than the opposite.
329 rip->i_nlinks++;
330 rip->i_zone[0] = z0; /* major/minor device numbers */
331 rw_inode(rip, WRITING); /* force inode to disk now */
333 /* New inode acquired. Try to make directory entry. */
334 if((r=search_dir(ldirp, string, &rip->i_num, ENTER, IGN_PERM)) != OK) {
335 rip->i_nlinks--; /* pity, have to free disk inode */
336 rip->i_dirt = DIRTY; /* dirty inodes are written out */
337 put_inode(rip); /* this call frees the inode */
338 err_code = r;
339 return(NIL_INODE);
342 } else if (err_code == EENTERMOUNT || err_code == ELEAVEMOUNT) {
343 r = EEXIST;
344 } else {
345 /* Either last component exists, or there is some problem. */
346 if (rip != NIL_INODE)
347 r = EEXIST;
348 else
349 r = err_code;
352 /* The caller has to return the directory inode (*ldirp). */
353 err_code = r;
354 return(rip);
358 /*===========================================================================*
359 * fs_inhibread *
360 *===========================================================================*/
361 PUBLIC int fs_inhibread()
363 struct inode *rip;
365 if((rip = find_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE)
366 return(EINVAL);
368 /* inhibit read ahead */
369 rip->i_seek = ISEEK;
371 return(OK);