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
11 * April 2009 (D.C. van Moolenbroek)
18 FORWARD
_PROTOTYPE( int force_remove
, (char *path
, int dir
) );
20 /*===========================================================================*
22 *===========================================================================*/
23 PUBLIC
int do_create()
27 char path
[PATH_MAX
], name
[NAME_MAX
+1];
28 struct inode
*parent
, *ino
;
29 struct hgfs_attr attr
;
33 /* We cannot create files on a read-only file system. */
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
)
41 if (!strcmp(name
, ".") || !strcmp(name
, "..")) return EEXIST
;
43 if ((parent
= find_inode(m_in
.REQ_INODE_NR
)) == NULL
)
46 if ((r
= verify_dentry(parent
, name
, path
, &ino
)) != OK
)
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()) {
61 /* Perform the actual create call. */
62 r
= hgfs_open(path
, O_CREAT
| O_EXCL
| O_RDWR
, m_in
.REQ_MODE
, &handle
);
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.
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");
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.
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
;
128 /*===========================================================================*
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
;
139 /* We cannot create directories on a read-only file system. */
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
)
147 if (!strcmp(name
, ".") || !strcmp(name
, "..")) return EEXIST
;
149 if ((parent
= find_inode(m_in
.REQ_INODE_NR
)) == NULL
)
152 if ((r
= verify_dentry(parent
, name
, path
, &ino
)) != OK
)
155 /* Perform the actual mkdir call. */
156 r
= hgfs_mkdir(path
, m_in
.REQ_MODE
);
165 /* If we thought the new dentry already existed, it was apparently gone
166 * already. Delete it.
177 /*===========================================================================*
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
;
194 /* First try to remove the target. */
196 r
= hgfs_rmdir(path
);
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. */
218 r
= hgfs_rmdir(path
);
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
);
232 /*===========================================================================*
234 *===========================================================================*/
235 PUBLIC
int do_unlink()
239 char path
[PATH_MAX
], name
[NAME_MAX
+1];
240 struct inode
*parent
, *ino
;
243 /* We cannot delete files on a read-only file system. */
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
)
251 if (!strcmp(name
, ".") || !strcmp(name
, "..")) return EPERM
;
253 if ((parent
= find_inode(m_in
.REQ_INODE_NR
)) == NULL
)
256 if ((r
= verify_dentry(parent
, name
, path
, &ino
)) != OK
)
259 /* Perform the unlink call. */
260 r
= force_remove(path
, FALSE
/*dir*/);
269 /* If a dentry existed for this name, it is gone now. */
279 /*===========================================================================*
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
;
290 /* We cannot remove directories on a read-only file system. */
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
)
298 if (!strcmp(name
, ".")) return EINVAL
;
299 if (!strcmp(name
, "..")) return ENOTEMPTY
;
301 if ((parent
= find_inode(m_in
.REQ_INODE_NR
)) == NULL
)
304 if ((r
= verify_dentry(parent
, name
, path
, &ino
)) != OK
)
307 /* Perform the rmdir call. */
308 r
= force_remove(path
, TRUE
/*dir*/);
317 /* If a dentry existed for this name, it is gone now. */
327 /*===========================================================================*
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
;
340 /* We cannot do rename on a read-only file system. */
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
)
360 if ((r
= verify_dentry(old_parent
, old_name
, old_path
, &old_ino
)) != OK
)
363 if ((r
= verify_dentry(new_parent
, new_name
, new_path
, &new_ino
)) != OK
) {
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
);
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
) {
393 /* If the old dentry existed, rename it accordingly. */
394 if (old_ino
!= NULL
) {
397 add_dentry(new_parent
, new_name
, old_ino
);