Fixes to allow versionless packages on cd
[minix3.git] / servers / hgfs / link.c
blob559235b2047c5dbce3466816f51d14fe78527279
1 /* This file contains directory entry related file system call handlers.
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
10 * Created:
11 * April 2009 (D.C. van Moolenbroek)
14 #include "inc.h"
16 #include <fcntl.h>
18 FORWARD _PROTOTYPE( int force_remove, (char *path, int dir) );
20 /*===========================================================================*
21 * do_create *
22 *===========================================================================*/
23 PUBLIC int do_create()
25 /* Create a new file.
27 char path[PATH_MAX], name[NAME_MAX+1];
28 struct inode *parent, *ino;
29 struct hgfs_attr attr;
30 hgfs_file_t handle;
31 int r;
33 /* We cannot create files on a read-only file system. */
34 if (state.read_only)
35 return EROFS;
37 /* Get path, name, parent inode and possibly inode for the given path. */
38 if ((r = get_name(m_in.REQ_GRANT, m_in.REQ_PATH_LEN, name)) != OK)
39 return r;
41 if (!strcmp(name, ".") || !strcmp(name, "..")) return EEXIST;
43 if ((parent = find_inode(m_in.REQ_INODE_NR)) == NULL)
44 return EINVAL;
46 if ((r = verify_dentry(parent, name, path, &ino)) != OK)
47 return r;
49 /* Are we going to need a new inode upon success?
50 * Then make sure there is one available before trying anything.
52 if (ino == NULL || ino->i_ref > 1 || HAS_CHILDREN(ino)) {
53 if (!have_free_inode()) {
54 if (ino != NULL)
55 put_inode(ino);
57 return ENFILE;
61 /* Perform the actual create call. */
62 r = hgfs_open(path, O_CREAT | O_EXCL | O_RDWR, m_in.REQ_MODE, &handle);
64 if (r != OK) {
65 /* Let's not try to be too clever with error codes here. If something
66 * is wrong with the directory, we'll find out later anyway.
69 if (ino != NULL)
70 put_inode(ino);
72 return r;
75 /* Get the created file's attributes. */
76 attr.a_mask = HGFS_ATTR_MODE | HGFS_ATTR_SIZE;
77 r = hgfs_getattr(path, &attr);
79 /* If this fails, or returns a directory, we have a problem. This
80 * scenario is in fact possible with race conditions.
81 * Simulate a close and return a somewhat appropriate error.
83 if (r != OK || S_ISDIR(attr.a_mode)) {
84 printf("HGFS: lost file after creation!\n");
86 hgfs_close(handle);
88 if (ino != NULL) {
89 del_dentry(ino);
91 put_inode(ino);
94 return (r == OK) ? EEXIST : r;
97 /* We do assume that the HGFS open(O_CREAT|O_EXCL) did its job.
98 * If we previousy found an inode, get rid of it now. It's old.
100 if (ino != NULL) {
101 del_dentry(ino);
103 put_inode(ino);
106 /* Associate the open file handle with an inode, and reply with its details.
108 ino = get_free_inode();
110 assert(ino != NULL); /* we checked before whether we had a free one */
112 ino->i_file = handle;
113 ino->i_flags = I_HANDLE;
115 add_dentry(parent, name, ino);
117 m_out.RES_INODE_NR = INODE_NR(ino);
118 m_out.RES_MODE = get_mode(ino, attr.a_mode);
119 m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size);
120 m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size);
121 m_out.RES_UID = opt.uid;
122 m_out.RES_GID = opt.gid;
123 m_out.RES_DEV = NO_DEV;
125 return OK;
128 /*===========================================================================*
129 * do_mkdir *
130 *===========================================================================*/
131 PUBLIC int do_mkdir()
133 /* Make a new directory.
135 char path[PATH_MAX], name[NAME_MAX+1];
136 struct inode *parent, *ino;
137 int r;
139 /* We cannot create directories on a read-only file system. */
140 if (state.read_only)
141 return EROFS;
143 /* Get the path string and possibly an inode for the given path. */
144 if ((r = get_name(m_in.REQ_GRANT, m_in.REQ_PATH_LEN, name)) != OK)
145 return r;
147 if (!strcmp(name, ".") || !strcmp(name, "..")) return EEXIST;
149 if ((parent = find_inode(m_in.REQ_INODE_NR)) == NULL)
150 return EINVAL;
152 if ((r = verify_dentry(parent, name, path, &ino)) != OK)
153 return r;
155 /* Perform the actual mkdir call. */
156 r = hgfs_mkdir(path, m_in.REQ_MODE);
158 if (r != OK) {
159 if (ino != NULL)
160 put_inode(ino);
162 return r;
165 /* If we thought the new dentry already existed, it was apparently gone
166 * already. Delete it.
168 if (ino != NULL) {
169 del_dentry(ino);
171 put_inode(ino);
174 return OK;
177 /*===========================================================================*
178 * force_remove *
179 *===========================================================================*/
180 PRIVATE int force_remove(path, dir)
181 char *path; /* path to file or directory */
182 int dir; /* TRUE iff directory */
184 /* Remove a file or directory. Wrapper around hgfs_unlink and hgfs_rmdir that
185 * makes the target temporarily writable if the operation fails with an access
186 * denied error. On Windows hosts, read-only files or directories cannot be
187 * removed (even though they can be renamed). In general, the HGFS server
188 * follows the behavior of the host file system, but this case just confuses
189 * the hell out of the MINIX userland..
191 struct hgfs_attr attr;
192 int r, r2;
194 /* First try to remove the target. */
195 if (dir)
196 r = hgfs_rmdir(path);
197 else
198 r = hgfs_unlink(path);
200 if (r != EACCES) return r;
202 /* If this fails with an access error, retrieve the target's mode. */
203 attr.a_mask = HGFS_ATTR_MODE;
205 r2 = hgfs_getattr(path, &attr);
207 if (r2 != OK || (attr.a_mode & S_IWUSR)) return r;
209 /* If the target is not writable, temporarily set it to writable. */
210 attr.a_mode |= S_IWUSR;
212 r2 = hgfs_setattr(path, &attr);
214 if (r2 != OK) return r;
216 /* Then try the original operation again. */
217 if (dir)
218 r = hgfs_rmdir(path);
219 else
220 r = hgfs_unlink(path);
222 if (r == OK) return r;
224 /* If the operation still fails, unset the writable bit again. */
225 attr.a_mode &= ~S_IWUSR;
227 hgfs_setattr(path, &attr);
229 return r;
232 /*===========================================================================*
233 * do_unlink *
234 *===========================================================================*/
235 PUBLIC int do_unlink()
237 /* Delete a file.
239 char path[PATH_MAX], name[NAME_MAX+1];
240 struct inode *parent, *ino;
241 int r;
243 /* We cannot delete files on a read-only file system. */
244 if (state.read_only)
245 return EROFS;
247 /* Get the path string and possibly preexisting inode for the given path. */
248 if ((r = get_name(m_in.REQ_GRANT, m_in.REQ_PATH_LEN, name)) != OK)
249 return r;
251 if (!strcmp(name, ".") || !strcmp(name, "..")) return EPERM;
253 if ((parent = find_inode(m_in.REQ_INODE_NR)) == NULL)
254 return EINVAL;
256 if ((r = verify_dentry(parent, name, path, &ino)) != OK)
257 return r;
259 /* Perform the unlink call. */
260 r = force_remove(path, FALSE /*dir*/);
262 if (r != OK) {
263 if (ino != NULL)
264 put_inode(ino);
266 return r;
269 /* If a dentry existed for this name, it is gone now. */
270 if (ino != NULL) {
271 del_dentry(ino);
273 put_inode(ino);
276 return OK;
279 /*===========================================================================*
280 * do_rmdir *
281 *===========================================================================*/
282 PUBLIC int do_rmdir()
284 /* Remove an empty directory.
286 char path[PATH_MAX], name[NAME_MAX+1];
287 struct inode *parent, *ino;
288 int r;
290 /* We cannot remove directories on a read-only file system. */
291 if (state.read_only)
292 return EROFS;
294 /* Get the path string and possibly preexisting inode for the given path. */
295 if ((r = get_name(m_in.REQ_GRANT, m_in.REQ_PATH_LEN, name)) != OK)
296 return r;
298 if (!strcmp(name, ".")) return EINVAL;
299 if (!strcmp(name, "..")) return ENOTEMPTY;
301 if ((parent = find_inode(m_in.REQ_INODE_NR)) == NULL)
302 return EINVAL;
304 if ((r = verify_dentry(parent, name, path, &ino)) != OK)
305 return r;
307 /* Perform the rmdir call. */
308 r = force_remove(path, TRUE /*dir*/);
310 if (r != OK) {
311 if (ino != NULL)
312 put_inode(ino);
314 return r;
317 /* If a dentry existed for this name, it is gone now. */
318 if (ino != NULL) {
319 del_dentry(ino);
321 put_inode(ino);
324 return OK;
327 /*===========================================================================*
328 * do_rename *
329 *===========================================================================*/
330 PUBLIC int do_rename()
332 /* Rename a file or directory.
334 char old_path[PATH_MAX], new_path[PATH_MAX];
335 char old_name[NAME_MAX+1], new_name[NAME_MAX+1];
336 struct inode *old_parent, *new_parent;
337 struct inode *old_ino, *new_ino;
338 int r;
340 /* We cannot do rename on a read-only file system. */
341 if (state.read_only)
342 return EROFS;
344 /* Get path strings, names, directory inodes and possibly preexisting inodes
345 * for the old and new paths.
347 if ((r = get_name(m_in.REQ_REN_GRANT_OLD, m_in.REQ_REN_LEN_OLD,
348 old_name)) != OK) return r;
350 if ((r = get_name(m_in.REQ_REN_GRANT_NEW, m_in.REQ_REN_LEN_NEW,
351 new_name)) != OK) return r;
353 if (!strcmp(old_name, ".") || !strcmp(old_name, "..") ||
354 !strcmp(new_name, ".") || !strcmp(new_name, "..")) return EINVAL;
356 if ((old_parent = find_inode(m_in.REQ_REN_OLD_DIR)) == NULL ||
357 (new_parent = find_inode(m_in.REQ_REN_NEW_DIR)) == NULL)
358 return EINVAL;
360 if ((r = verify_dentry(old_parent, old_name, old_path, &old_ino)) != OK)
361 return r;
363 if ((r = verify_dentry(new_parent, new_name, new_path, &new_ino)) != OK) {
364 if (old_ino != NULL)
365 put_inode(old_ino);
367 return r;
370 /* Perform the actual rename call. */
371 r = hgfs_rename(old_path, new_path);
373 /* If we failed, or if we have nothing further to do: both inodes are
374 * NULL, or they both refer to the same file.
376 if (r != OK || old_ino == new_ino) {
377 if (old_ino != NULL) put_inode(old_ino);
379 if (new_ino != NULL) put_inode(new_ino);
381 return r;
384 /* If the new dentry already existed, it has now been overwritten.
385 * Delete the associated inode if we had found one.
387 if (new_ino != NULL) {
388 del_dentry(new_ino);
390 put_inode(new_ino);
393 /* If the old dentry existed, rename it accordingly. */
394 if (old_ino != NULL) {
395 del_dentry(old_ino);
397 add_dentry(new_parent, new_name, old_ino);
399 put_inode(old_ino);
402 return OK;