mfs fix by tveerman from trunk.
[minix.git] / servers / mfs / open.c
blob949c8715d2c9f7e12fa6a013ea58eccf796f6c51
1 #include "fs.h"
2 #include <sys/stat.h>
3 #include <string.h>
4 #include <minix/com.h>
5 #include "buf.h"
6 #include "inode.h"
7 #include "super.h"
8 #include <minix/vfsif.h>
10 FORWARD _PROTOTYPE( struct inode *new_node, (struct inode *ldirp,
11 char *string, mode_t bits, zone_t z0));
14 /*===========================================================================*
15 * fs_create *
16 *===========================================================================*/
17 PUBLIC int fs_create()
19 phys_bytes len;
20 int r;
21 struct inode *ldirp;
22 struct inode *rip;
23 mode_t omode;
24 char lastc[NAME_MAX];
26 /* Read request message */
27 omode = (mode_t) fs_m_in.REQ_MODE;
28 caller_uid = (uid_t) fs_m_in.REQ_UID;
29 caller_gid = (gid_t) fs_m_in.REQ_GID;
31 /* Try to make the file. */
33 /* Copy the last component (i.e., file name) */
34 len = min( (unsigned) fs_m_in.REQ_PATH_LEN, sizeof(lastc));
35 err_code = sys_safecopyfrom(FS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
36 (vir_bytes) 0, (vir_bytes) lastc, (size_t) len, D);
37 if (err_code != OK) return err_code;
38 NUL(lastc, len, sizeof(lastc));
40 /* Get last directory inode (i.e., directory that will hold the new inode) */
41 if ((ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
42 return(ENOENT);
44 /* Create a new inode by calling new_node(). */
45 rip = new_node(ldirp, lastc, omode, NO_ZONE);
46 r = err_code;
48 /* If an error occurred, release inode. */
49 if (r != OK) {
50 put_inode(ldirp);
51 put_inode(rip);
52 return(r);
55 /* Reply message */
56 fs_m_out.RES_INODE_NR = rip->i_num;
57 fs_m_out.RES_MODE = rip->i_mode;
58 fs_m_out.RES_FILE_SIZE_LO = rip->i_size;
60 /* This values are needed for the execution */
61 fs_m_out.RES_UID = rip->i_uid;
62 fs_m_out.RES_GID = rip->i_gid;
64 /* Drop parent dir */
65 put_inode(ldirp);
67 return(OK);
71 /*===========================================================================*
72 * fs_mknod *
73 *===========================================================================*/
74 PUBLIC int fs_mknod()
76 struct inode *ip, *ldirp;
77 char lastc[NAME_MAX];
78 phys_bytes len;
80 /* Copy the last component and set up caller's user and group id */
81 len = min( (unsigned) fs_m_in.REQ_PATH_LEN, sizeof(lastc));
82 err_code = sys_safecopyfrom(FS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
83 (vir_bytes) 0, (vir_bytes) lastc, (size_t) len, D);
84 if (err_code != OK) return err_code;
85 NUL(lastc, len, sizeof(lastc));
87 caller_uid = (uid_t) fs_m_in.REQ_UID;
88 caller_gid = (gid_t) fs_m_in.REQ_GID;
90 /* Get last directory inode */
91 if((ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
92 return(ENOENT);
94 /* Try to create the new node */
95 ip = new_node(ldirp, lastc, (mode_t) fs_m_in.REQ_MODE,
96 (zone_t) fs_m_in.REQ_DEV);
98 put_inode(ip);
99 put_inode(ldirp);
100 return(err_code);
104 /*===========================================================================*
105 * fs_mkdir *
106 *===========================================================================*/
107 PUBLIC int fs_mkdir()
109 int r1, r2; /* status codes */
110 ino_t dot, dotdot; /* inode numbers for . and .. */
111 struct inode *rip, *ldirp;
112 char lastc[NAME_MAX]; /* last component */
113 phys_bytes len;
115 /* Copy the last component and set up caller's user and group id */
116 len = min( (unsigned) fs_m_in.REQ_PATH_LEN, sizeof(lastc));
117 err_code = sys_safecopyfrom(FS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
118 (vir_bytes) 0, (vir_bytes) lastc, (size_t) len, D);
119 if(err_code != OK) return(err_code);
120 NUL(lastc, len, sizeof(lastc));
122 caller_uid = (uid_t) fs_m_in.REQ_UID;
123 caller_gid = (gid_t) fs_m_in.REQ_GID;
125 /* Get last directory inode */
126 if((ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
127 return(ENOENT);
129 /* Next make the inode. If that fails, return error code. */
130 rip = new_node(ldirp, lastc, (mode_t) fs_m_in.REQ_MODE, (zone_t) 0);
132 if(rip == NULL || err_code == EEXIST) {
133 put_inode(rip); /* can't make dir: it already exists */
134 put_inode(ldirp);
135 return(err_code);
138 /* Get the inode numbers for . and .. to enter in the directory. */
139 dotdot = ldirp->i_num; /* parent's inode number */
140 dot = rip->i_num; /* inode number of the new dir itself */
142 /* Now make dir entries for . and .. unless the disk is completely full. */
143 /* Use dot1 and dot2, so the mode of the directory isn't important. */
144 rip->i_mode = (mode_t) fs_m_in.REQ_MODE; /* set mode */
145 r1 = search_dir(rip, dot1, &dot, ENTER, IGN_PERM);/* enter . in the new dir*/
146 r2 = search_dir(rip, dot2, &dotdot, ENTER, IGN_PERM); /* enter .. in the new
147 dir */
149 /* If both . and .. were successfully entered, increment the link counts. */
150 if (r1 == OK && r2 == OK) {
151 /* Normal case. It was possible to enter . and .. in the new dir. */
152 rip->i_nlinks++; /* this accounts for . */
153 ldirp->i_nlinks++; /* this accounts for .. */
154 ldirp->i_dirt = DIRTY; /* mark parent's inode as dirty */
155 } else {
156 /* It was not possible to enter . or .. probably disk was full -
157 * links counts haven't been touched. */
158 if(search_dir(ldirp, lastc, (ino_t *) 0, DELETE, IGN_PERM) != OK)
159 panic("Dir disappeared: %ul", rip->i_num);
160 rip->i_nlinks--; /* undo the increment done in new_node() */
162 rip->i_dirt = DIRTY; /* either way, i_nlinks has changed */
164 put_inode(ldirp); /* return the inode of the parent dir */
165 put_inode(rip); /* return the inode of the newly made dir */
166 return(err_code); /* new_node() always sets 'err_code' */
170 /*===========================================================================*
171 * fs_slink *
172 *===========================================================================*/
173 PUBLIC int fs_slink()
175 phys_bytes len;
176 struct inode *sip; /* inode containing symbolic link */
177 struct inode *ldirp; /* directory containing link */
178 register int r; /* error code */
179 char string[NAME_MAX]; /* last component of the new dir's path name */
180 struct buf *bp; /* disk buffer for link */
182 caller_uid = (uid_t) fs_m_in.REQ_UID;
183 caller_gid = (gid_t) fs_m_in.REQ_GID;
185 /* Copy the link name's last component */
186 len = min( (unsigned) fs_m_in.REQ_PATH_LEN, sizeof(string));
187 r = sys_safecopyfrom(FS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
188 (vir_bytes) 0, (vir_bytes) string, (size_t) len, D);
189 if (r != OK) return(r);
190 NUL(string, len, sizeof(string));
192 /* Temporarily open the dir. */
193 if( (ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
194 return(EINVAL);
196 /* Create the inode for the symlink. */
197 sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES),
198 (zone_t) 0);
200 /* Allocate a disk block for the contents of the symlink.
201 * Copy contents of symlink (the name pointed to) into first disk block. */
202 if( (r = err_code) == OK) {
203 bp = new_block(sip, (off_t) 0);
204 if (bp == NULL)
205 r = err_code;
206 else
207 r = sys_safecopyfrom(FS_PROC_NR,
208 (cp_grant_id_t) fs_m_in.REQ_GRANT3,
209 (vir_bytes) 0, (vir_bytes) bp->b_data,
210 (size_t) fs_m_in.REQ_MEM_SIZE, D);
212 if(bp != NULL && r == OK) {
213 bp->b_data[_MIN_BLOCK_SIZE-1] = '\0';
214 sip->i_size = (off_t) 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 NULL. */
230 if(r != OK) {
231 sip->i_nlinks = NO_LINK;
232 if(search_dir(ldirp, string, NULL, DELETE, IGN_PERM) != OK)
233 panic("Symbolic link vanished");
237 /* put_inode() accepts NULL as a noop, so the below are safe. */
238 put_inode(sip);
239 put_inode(ldirp);
241 return(r);
244 /*===========================================================================*
245 * new_node *
246 *===========================================================================*/
247 PRIVATE struct inode *new_node(struct inode *ldirp,
248 char *string, mode_t bits, zone_t z0)
250 /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().
251 * In all cases it allocates a new inode, makes a directory entry for it in
252 * the ldirp directory with string name, and initializes it.
253 * It returns a pointer to the inode if it can do this;
254 * otherwise it returns NULL. It always sets 'err_code'
255 * to an appropriate value (OK or an error code).
257 * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
258 * has to hold at least NAME_MAX bytes.
261 register struct inode *rip;
262 register int r;
264 /* Get final component of the path. */
265 rip = advance(ldirp, string, IGN_PERM);
267 if (S_ISDIR(bits) && (ldirp->i_nlinks >= LINK_MAX)) {
268 /* New entry is a directory, alas we can't give it a ".." */
269 put_inode(rip);
270 err_code = EMLINK;
271 return(NULL);
274 if ( rip == NULL && err_code == ENOENT) {
275 /* Last path component does not exist. Make new directory entry. */
276 if ( (rip = alloc_inode((ldirp)->i_dev, bits)) == NULL) {
277 /* Can't creat new inode: out of inodes. */
278 return(NULL);
281 /* Force inode to the disk before making directory entry to make
282 * the system more robust in the face of a crash: an inode with
283 * no directory entry is much better than the opposite.
285 rip->i_nlinks++;
286 rip->i_zone[0] = z0; /* major/minor device numbers */
287 rw_inode(rip, WRITING); /* force inode to disk now */
289 /* New inode acquired. Try to make directory entry. */
290 if((r=search_dir(ldirp, string, &rip->i_num, ENTER, IGN_PERM)) != OK) {
291 rip->i_nlinks--; /* pity, have to free disk inode */
292 rip->i_dirt = DIRTY; /* dirty inodes are written out */
293 put_inode(rip); /* this call frees the inode */
294 err_code = r;
295 return(NULL);
298 } else if (err_code == EENTERMOUNT || err_code == ELEAVEMOUNT) {
299 r = EEXIST;
300 } else {
301 /* Either last component exists, or there is some problem. */
302 if (rip != NULL)
303 r = EEXIST;
304 else
305 r = err_code;
308 /* The caller has to return the directory inode (*ldirp). */
309 err_code = r;
310 return(rip);
314 /*===========================================================================*
315 * fs_inhibread *
316 *===========================================================================*/
317 PUBLIC int fs_inhibread()
319 struct inode *rip;
321 if((rip = find_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
322 return(EINVAL);
324 /* inhibit read ahead */
325 rip->i_seek = ISEEK;
327 return(OK);