xref: /minix/minix/lib/libsffs/link.c (revision e3b78ef1)
1 /* This file contains directory entry related file system call handlers.
2  *
3  * The entry points into this file are:
4  *   do_create		perform the CREATE file system call
5  *   do_mkdir		perform the MKDIR file system call
6  *   do_unlink		perform the UNLINK file system call
7  *   do_rmdir		perform the RMDIR file system call
8  *   do_rename		perform the RENAME file system call
9  *
10  * Created:
11  *   April 2009 (D.C. van Moolenbroek)
12  */
13 
14 #include "inc.h"
15 
16 #include <fcntl.h>
17 
18 /*===========================================================================*
19  *				do_create				     *
20  *===========================================================================*/
21 int do_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
22 	struct fsdriver_node *node)
23 {
24 /* Create a new file.
25  */
26   char path[PATH_MAX];
27   struct inode *parent, *ino;
28   struct sffs_attr attr;
29   sffs_file_t handle;
30   int r;
31 
32   /* We cannot create files on a read-only file system. */
33   if (read_only)
34 	return EROFS;
35 
36   if ((parent = find_inode(dir_nr)) == NULL)
37 	return EINVAL;
38 
39   if ((r = verify_dentry(parent, name, path, &ino)) != OK)
40 	return r;
41 
42   /* Are we going to need a new inode upon success?
43    * Then make sure there is one available before trying anything.
44    */
45   if (ino == NULL || ino->i_ref > 1 || HAS_CHILDREN(ino)) {
46 	if (!have_free_inode()) {
47 		if (ino != NULL)
48 			put_inode(ino);
49 
50 		return ENFILE;
51 	}
52   }
53 
54   /* Perform the actual create call. */
55   r = sffs_table->t_open(path, O_CREAT | O_EXCL | O_RDWR, mode, &handle);
56 
57   if (r != OK) {
58 	/* Let's not try to be too clever with error codes here. If something
59 	 * is wrong with the directory, we'll find out later anyway.
60 	 */
61 
62 	if (ino != NULL)
63 		put_inode(ino);
64 
65 	return r;
66   }
67 
68   /* Get the created file's attributes. */
69   attr.a_mask = SFFS_ATTR_MODE | SFFS_ATTR_SIZE;
70   r = sffs_table->t_getattr(path, &attr);
71 
72   /* If this fails, or returns a directory, we have a problem. This
73    * scenario is in fact possible with race conditions.
74    * Simulate a close and return a somewhat appropriate error.
75    */
76   if (r != OK || S_ISDIR(attr.a_mode)) {
77 	printf("%s: lost file after creation!\n", sffs_name);
78 
79 	sffs_table->t_close(handle);
80 
81 	if (ino != NULL) {
82 		del_dentry(ino);
83 
84 		put_inode(ino);
85 	}
86 
87 	return (r == OK) ? EEXIST : r;
88   }
89 
90   /* We do assume that the underlying open(O_CREAT|O_EXCL) call did its job.
91    * If we previousy found an inode, get rid of it now. It's old.
92    */
93   if (ino != NULL) {
94 	del_dentry(ino);
95 
96 	put_inode(ino);
97   }
98 
99   /* Associate the open file handle with an inode, and reply with its details.
100    */
101   ino = get_free_inode();
102 
103   assert(ino != NULL); /* we checked before whether we had a free one */
104 
105   ino->i_file = handle;
106   ino->i_flags = I_HANDLE;
107 
108   add_dentry(parent, name, ino);
109 
110   node->fn_ino_nr = INODE_NR(ino);
111   node->fn_mode = get_mode(ino, attr.a_mode);
112   node->fn_size = attr.a_size;
113   node->fn_uid = sffs_params->p_uid;
114   node->fn_gid = sffs_params->p_gid;
115   node->fn_dev = NO_DEV;
116 
117   return OK;
118 }
119 
120 /*===========================================================================*
121  *				do_mkdir				     *
122  *===========================================================================*/
123 int do_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid)
124 {
125 /* Make a new directory.
126  */
127   char path[PATH_MAX];
128   struct inode *parent, *ino;
129   int r;
130 
131   /* We cannot create directories on a read-only file system. */
132   if (read_only)
133 	return EROFS;
134 
135   if ((parent = find_inode(dir_nr)) == NULL)
136 	return EINVAL;
137 
138   if ((r = verify_dentry(parent, name, path, &ino)) != OK)
139 	return r;
140 
141   /* Perform the actual mkdir call. */
142   r = sffs_table->t_mkdir(path, mode);
143 
144   if (r != OK) {
145 	if (ino != NULL)
146 		put_inode(ino);
147 
148 	return r;
149   }
150 
151   /* If we thought the new dentry already existed, it was apparently gone
152    * already. Delete it.
153    */
154   if (ino != NULL) {
155 	del_dentry(ino);
156 
157 	put_inode(ino);
158   }
159 
160   return OK;
161 }
162 
163 /*===========================================================================*
164  *				force_remove				     *
165  *===========================================================================*/
166 static int force_remove(
167 	char *path,	/* path to file or directory */
168 	int dir	   	/* TRUE iff directory */
169 )
170 {
171 /* Remove a file or directory. Wrapper around unlink and rmdir that makes the
172  * target temporarily writable if the operation fails with an access denied
173  * error. On Windows hosts, read-only files or directories cannot be removed
174  * (even though they can be renamed). In general, the SFFS library follows the
175  * behavior of the host file system, but this case just confuses the hell out
176  * of the MINIX userland..
177  */
178   struct sffs_attr attr;
179   int r, r2;
180 
181   /* First try to remove the target. */
182   if (dir)
183 	r = sffs_table->t_rmdir(path);
184   else
185 	r = sffs_table->t_unlink(path);
186 
187   if (r != EACCES) return r;
188 
189   /* If this fails with an access error, retrieve the target's mode. */
190   attr.a_mask = SFFS_ATTR_MODE;
191 
192   r2 = sffs_table->t_getattr(path, &attr);
193 
194   if (r2 != OK || (attr.a_mode & S_IWUSR)) return r;
195 
196   /* If the target is not writable, temporarily set it to writable. */
197   attr.a_mode |= S_IWUSR;
198 
199   r2 = sffs_table->t_setattr(path, &attr);
200 
201   if (r2 != OK) return r;
202 
203   /* Then try the original operation again. */
204   if (dir)
205 	r = sffs_table->t_rmdir(path);
206   else
207 	r = sffs_table->t_unlink(path);
208 
209   if (r == OK) return r;
210 
211   /* If the operation still fails, unset the writable bit again. */
212   attr.a_mode &= ~S_IWUSR;
213 
214   sffs_table->t_setattr(path, &attr);
215 
216   return r;
217 }
218 
219 /*===========================================================================*
220  *				do_unlink				     *
221  *===========================================================================*/
222 int do_unlink(ino_t dir_nr, char *name, int call)
223 {
224 /* Delete a file.
225  */
226   char path[PATH_MAX];
227   struct inode *parent, *ino;
228   int r;
229 
230   /* We cannot delete files on a read-only file system. */
231   if (read_only)
232 	return EROFS;
233 
234   if ((parent = find_inode(dir_nr)) == NULL)
235 	return EINVAL;
236 
237   if ((r = verify_dentry(parent, name, path, &ino)) != OK)
238 	return r;
239 
240   /* Perform the unlink call. */
241   r = force_remove(path, FALSE /*dir*/);
242 
243   if (r != OK) {
244 	if (ino != NULL)
245 		put_inode(ino);
246 
247 	return r;
248   }
249 
250   /* If a dentry existed for this name, it is gone now. */
251   if (ino != NULL) {
252 	del_dentry(ino);
253 
254 	put_inode(ino);
255   }
256 
257   return OK;
258 }
259 
260 /*===========================================================================*
261  *				do_rmdir				     *
262  *===========================================================================*/
263 int do_rmdir(ino_t dir_nr, char *name, int call)
264 {
265 /* Remove an empty directory.
266  */
267   char path[PATH_MAX];
268   struct inode *parent, *ino;
269   int r;
270 
271   /* We cannot remove directories on a read-only file system. */
272   if (read_only)
273 	return EROFS;
274 
275   if ((parent = find_inode(dir_nr)) == NULL)
276 	return EINVAL;
277 
278   if ((r = verify_dentry(parent, name, path, &ino)) != OK)
279 	return r;
280 
281   /* Perform the rmdir call. */
282   r = force_remove(path, TRUE /*dir*/);
283 
284   if (r != OK) {
285 	if (ino != NULL)
286 		put_inode(ino);
287 
288 	return r;
289   }
290 
291   /* If a dentry existed for this name, it is gone now. */
292   if (ino != NULL) {
293 	del_dentry(ino);
294 
295 	put_inode(ino);
296   }
297 
298   return OK;
299 }
300 
301 /*===========================================================================*
302  *				do_rename				     *
303  *===========================================================================*/
304 int do_rename(ino_t old_dir_nr, char *old_name, ino_t new_dir_nr,
305 	char *new_name)
306 {
307 /* Rename a file or directory.
308  */
309   char old_path[PATH_MAX], new_path[PATH_MAX];
310   struct inode *old_parent, *new_parent;
311   struct inode *old_ino, *new_ino;
312   int r;
313 
314   /* We cannot do rename on a read-only file system. */
315   if (read_only)
316 	return EROFS;
317 
318   /* Get possibly preexisting inodes for the old and new paths. */
319   if ((old_parent = find_inode(old_dir_nr)) == NULL ||
320 	(new_parent = find_inode(new_dir_nr)) == NULL)
321 	return EINVAL;
322 
323   if ((r = verify_dentry(old_parent, old_name, old_path, &old_ino)) != OK)
324 	return r;
325 
326   if ((r = verify_dentry(new_parent, new_name, new_path, &new_ino)) != OK) {
327 	if (old_ino != NULL)
328 		put_inode(old_ino);
329 
330 	return r;
331   }
332 
333   /* Perform the actual rename call. */
334   r = sffs_table->t_rename(old_path, new_path);
335 
336   /* If we failed, or if we have nothing further to do: both inodes are
337    * NULL, or they both refer to the same file.
338    */
339   if (r != OK || old_ino == new_ino) {
340 	if (old_ino != NULL) put_inode(old_ino);
341 
342 	if (new_ino != NULL) put_inode(new_ino);
343 
344 	return r;
345   }
346 
347   /* If the new dentry already existed, it has now been overwritten.
348    * Delete the associated inode if we had found one.
349    */
350   if (new_ino != NULL) {
351 	del_dentry(new_ino);
352 
353 	put_inode(new_ino);
354   }
355 
356   /* If the old dentry existed, rename it accordingly. */
357   if (old_ino != NULL) {
358 	del_dentry(old_ino);
359 
360 	add_dentry(new_parent, new_name, old_ino);
361 
362 	put_inode(old_ino);
363   }
364 
365   return OK;
366 }
367