xref: /minix/minix/fs/mfs/open.c (revision 7f5f010b)
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>
9 
10 static struct inode *new_node(struct inode *ldirp, char *string, mode_t
11 	bits, zone_t z0);
12 
13 /*===========================================================================*
14  *				fs_create				     *
15  *===========================================================================*/
16 int fs_create()
17 {
18   size_t len;
19   int r;
20   struct inode *ldirp;
21   struct inode *rip;
22   mode_t omode;
23   char lastc[MFS_NAME_MAX];
24 
25   /* Read request message */
26   omode = fs_m_in.m_vfs_fs_create.mode;
27   caller_uid = fs_m_in.m_vfs_fs_create.uid;
28   caller_gid = fs_m_in.m_vfs_fs_create.gid;
29 
30   /* Try to make the file. */
31 
32   /* Copy the last component (i.e., file name) */
33   len = min(fs_m_in.m_vfs_fs_create.path_len, sizeof(lastc));
34   err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_create.grant,
35 			      (vir_bytes) 0, (vir_bytes) lastc, len);
36   if (err_code != OK) return err_code;
37   NUL(lastc, len, sizeof(lastc));
38 
39   /* Get last directory inode (i.e., directory that will hold the new inode) */
40   if ((ldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_create.inode)) == NULL)
41 	  return(ENOENT);
42 
43   /* Create a new inode by calling new_node(). */
44   rip = new_node(ldirp, lastc, omode, NO_ZONE);
45   r = err_code;
46 
47   /* If an error occurred, release inode. */
48   if (r != OK) {
49 	  put_inode(ldirp);
50 	  put_inode(rip);
51 	  return(r);
52   }
53 
54   /* Reply message */
55   fs_m_out.m_fs_vfs_create.inode = rip->i_num;
56   fs_m_out.m_fs_vfs_create.mode = rip->i_mode;
57   fs_m_out.m_fs_vfs_create.file_size = rip->i_size;
58 
59   /* These values are needed for the execution */
60   fs_m_out.m_fs_vfs_create.uid = rip->i_uid;
61   fs_m_out.m_fs_vfs_create.gid = rip->i_gid;
62 
63   /* Drop parent dir */
64   put_inode(ldirp);
65 
66   return(OK);
67 }
68 
69 
70 /*===========================================================================*
71  *				fs_mknod				     *
72  *===========================================================================*/
73 int fs_mknod()
74 {
75   struct inode *ip, *ldirp;
76   char lastc[MFS_NAME_MAX];
77   phys_bytes len;
78 
79   /* Copy the last component and set up caller's user and group id */
80   len = min(fs_m_in.m_vfs_fs_mknod.path_len, sizeof(lastc));
81   err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_mknod.grant,
82   			    (vir_bytes) 0, (vir_bytes) lastc, (size_t) len);
83   if (err_code != OK) return err_code;
84   NUL(lastc, len, sizeof(lastc));
85 
86   caller_uid = fs_m_in.m_vfs_fs_mknod.uid;
87   caller_gid = fs_m_in.m_vfs_fs_mknod.gid;
88 
89   /* Get last directory inode */
90   if((ldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_mknod.inode)) == NULL)
91 	  return(ENOENT);
92 
93   /* Try to create the new node */
94   ip = new_node(ldirp, lastc, fs_m_in.m_vfs_fs_mknod.mode,
95   		(zone_t) fs_m_in.m_vfs_fs_mknod.device);
96 
97   put_inode(ip);
98   put_inode(ldirp);
99   return(err_code);
100 }
101 
102 
103 /*===========================================================================*
104  *				fs_mkdir				     *
105  *===========================================================================*/
106 int fs_mkdir()
107 {
108   int r1, r2;			/* status codes */
109   ino_t dot, dotdot;		/* inode numbers for . and .. */
110   struct inode *rip, *ldirp;
111   char lastc[MFS_NAME_MAX];         /* last component */
112   phys_bytes len;
113 
114   /* Copy the last component and set up caller's user and group id */
115   len = min(fs_m_in.m_vfs_fs_mkdir.path_len, sizeof(lastc));
116   err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_mkdir.grant,
117   			   (vir_bytes) 0, (vir_bytes) lastc, (size_t) len);
118   if(err_code != OK) return(err_code);
119   NUL(lastc, len, sizeof(lastc));
120 
121   caller_uid = fs_m_in.m_vfs_fs_mkdir.uid;
122   caller_gid = fs_m_in.m_vfs_fs_mkdir.gid;
123 
124   /* Get last directory inode */
125   if((ldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_mkdir.inode)) == NULL)
126       return(ENOENT);
127 
128   /* Next make the inode. If that fails, return error code. */
129   rip = new_node(ldirp, lastc, fs_m_in.m_vfs_fs_mkdir.mode, (zone_t) 0);
130 
131   if(rip == NULL || err_code == EEXIST) {
132 	  put_inode(rip);		/* can't make dir: it already exists */
133 	  put_inode(ldirp);
134 	  return(err_code);
135   }
136 
137   /* Get the inode numbers for . and .. to enter in the directory. */
138   dotdot = ldirp->i_num;	/* parent's inode number */
139   dot = rip->i_num;		/* inode number of the new dir itself */
140 
141   /* Now make dir entries for . and .. unless the disk is completely full. */
142   /* Use dot1 and dot2, so the mode of the directory isn't important. */
143   rip->i_mode = fs_m_in.m_vfs_fs_mkdir.mode;	/* set mode */
144   r1 = search_dir(rip, dot1, &dot, ENTER, IGN_PERM);/* enter . in the new dir*/
145   r2 = search_dir(rip, dot2, &dotdot, ENTER, IGN_PERM); /* enter .. in the new
146 							 dir */
147 
148   /* If both . and .. were successfully entered, increment the link counts. */
149   if (r1 == OK && r2 == OK) {
150 	  /* Normal case.  It was possible to enter . and .. in the new dir. */
151 	  rip->i_nlinks++;	/* this accounts for . */
152 	  ldirp->i_nlinks++;	/* this accounts for .. */
153 	  IN_MARKDIRTY(ldirp);	/* mark parent's inode as dirty */
154   } else {
155 	  /* It was not possible to enter . or .. probably disk was full -
156 	   * links counts haven't been touched. */
157 	  if(search_dir(ldirp, lastc, NULL, DELETE, IGN_PERM) != OK)
158 		  panic("Dir disappeared: %llu", rip->i_num);
159 	  rip->i_nlinks--;	/* undo the increment done in new_node() */
160   }
161   IN_MARKDIRTY(rip);		/* either way, i_nlinks has changed */
162 
163   put_inode(ldirp);		/* return the inode of the parent dir */
164   put_inode(rip);		/* return the inode of the newly made dir */
165   return(err_code);		/* new_node() always sets 'err_code' */
166 }
167 
168 
169 /*===========================================================================*
170  *                             fs_slink 				     *
171  *===========================================================================*/
172 int fs_slink()
173 {
174   phys_bytes len;
175   struct inode *sip;           /* inode containing symbolic link */
176   struct inode *ldirp;         /* directory containing link */
177   register int r;              /* error code */
178   char string[MFS_NAME_MAX];       /* last component of the new dir's path name */
179   struct buf *bp;              /* disk buffer for link */
180 
181   caller_uid = fs_m_in.m_vfs_fs_slink.uid;
182   caller_gid = fs_m_in.m_vfs_fs_slink.gid;
183 
184   /* Copy the link name's last component */
185   len = min( (unsigned) fs_m_in.m_vfs_fs_slink.path_len, sizeof(string));
186   r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_slink.grant_path,
187   			(vir_bytes) 0, (vir_bytes) string, (size_t) len);
188   if (r != OK) return(r);
189   NUL(string, len, sizeof(string));
190 
191   /* Temporarily open the dir. */
192   if( (ldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_slink.inode)) == NULL)
193 	  return(EINVAL);
194 
195   /* Create the inode for the symlink. */
196   sip = new_node(ldirp, string, (I_SYMBOLIC_LINK | RWX_MODES), 0);
197 
198   /* Allocate a disk block for the contents of the symlink.
199    * Copy contents of symlink (the name pointed to) into first disk block. */
200   if( (r = err_code) == OK) {
201 	size_t namelen = fs_m_in.m_vfs_fs_slink.mem_size;
202   	bp = new_block(sip, (off_t) 0);
203   	if (bp == NULL)
204   		r = err_code;
205   	else {
206 		if(get_block_size(sip->i_dev) <= namelen) {
207 			r = ENAMETOOLONG;
208 		} else {
209 	  		r = sys_safecopyfrom(VFS_PROC_NR,
210   				     fs_m_in.m_vfs_fs_slink.grant_target,
211 				     (vir_bytes) 0, (vir_bytes) b_data(bp),
212 				     namelen);
213 			b_data(bp)[namelen] = '\0';
214 		}
215 	}
216 
217 	if(bp != NULL && r == OK) {
218 		sip->i_size = (off_t) strlen(b_data(bp));
219 		if(sip->i_size != fs_m_in.m_vfs_fs_slink.mem_size) {
220 			/* This can happen if the user provides a buffer
221 			 * with a \0 in it. This can cause a lot of trouble
222 			 * when the symlink is used later. We could just use
223 			 * the strlen() value, but we want to let the user
224 			 * know he did something wrong. ENAMETOOLONG doesn't
225 			 * exactly describe the error, but there is no
226 			 * ENAMETOOWRONG.
227 			 */
228 			r = ENAMETOOLONG;
229 		}
230 	}
231 
232 	put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NULL. */
233 
234 	if(r != OK) {
235 		sip->i_nlinks = NO_LINK;
236 		if(search_dir(ldirp, string, NULL, DELETE, IGN_PERM) != OK)
237 			  panic("Symbolic link vanished");
238 	}
239   }
240 
241   /* put_inode() accepts NULL as a noop, so the below are safe. */
242   put_inode(sip);
243   put_inode(ldirp);
244 
245   return(r);
246 }
247 
248 /*===========================================================================*
249  *				new_node				     *
250  *===========================================================================*/
251 static struct inode *new_node(struct inode *ldirp,
252 	char *string, mode_t bits, zone_t z0)
253 {
254 /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().
255  * In all cases it allocates a new inode, makes a directory entry for it in
256  * the ldirp directory with string name, and initializes it.
257  * It returns a pointer to the inode if it can do this;
258  * otherwise it returns NULL.  It always sets 'err_code'
259  * to an appropriate value (OK or an error code).
260  *
261  * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
262  * has to hold at least MFS_NAME_MAX bytes.
263  */
264 
265   register struct inode *rip;
266   register int r;
267 
268   if (ldirp->i_nlinks == NO_LINK) {	/* Dir does not actually exist */
269   	err_code = ENOENT;
270   	return(NULL);
271   }
272 
273   /* Get final component of the path. */
274   rip = advance(ldirp, string, IGN_PERM);
275 
276   if (S_ISDIR(bits) && (ldirp->i_nlinks >= LINK_MAX)) {
277         /* New entry is a directory, alas we can't give it a ".." */
278         put_inode(rip);
279         err_code = EMLINK;
280         return(NULL);
281   }
282 
283   if ( rip == NULL && err_code == ENOENT) {
284 	/* Last path component does not exist.  Make new directory entry. */
285 	if ( (rip = alloc_inode((ldirp)->i_dev, bits)) == NULL) {
286 		/* Can't creat new inode: out of inodes. */
287 		return(NULL);
288 	}
289 
290 	/* Force inode to the disk before making directory entry to make
291 	 * the system more robust in the face of a crash: an inode with
292 	 * no directory entry is much better than the opposite.
293 	 */
294 	rip->i_nlinks++;
295 	rip->i_zone[0] = z0;		/* major/minor device numbers */
296 	rw_inode(rip, WRITING);		/* force inode to disk now */
297 
298 	/* New inode acquired.  Try to make directory entry. */
299 	if((r=search_dir(ldirp, string, &rip->i_num, ENTER, IGN_PERM)) != OK) {
300 		rip->i_nlinks--;	/* pity, have to free disk inode */
301 		IN_MARKDIRTY(rip);	/* dirty inodes are written out */
302 		put_inode(rip);	/* this call frees the inode */
303 		err_code = r;
304 		return(NULL);
305 	}
306 
307   } else if (err_code == EENTERMOUNT || err_code == ELEAVEMOUNT) {
308   	r = EEXIST;
309   } else {
310 	/* Either last component exists, or there is some problem. */
311 	if (rip != NULL)
312 		r = EEXIST;
313 	else
314 		r = err_code;
315   }
316 
317   /* The caller has to return the directory inode (*ldirp).  */
318   err_code = r;
319   return(rip);
320 }
321 
322 
323 /*===========================================================================*
324  *				fs_inhibread				     *
325  *===========================================================================*/
326 int fs_inhibread()
327 {
328   struct inode *rip;
329 
330   if((rip = find_inode(fs_dev, fs_m_in.m_vfs_fs_inhibread.inode)) == NULL)
331 	  return(EINVAL);
332 
333   /* inhibit read ahead */
334   rip->i_seek = ISEEK;
335 
336   return(OK);
337 }
338 
339