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 static int force_remove(char *path
, int dir
);
20 /*===========================================================================*
22 *===========================================================================*/
27 char path
[PATH_MAX
], name
[NAME_MAX
+1];
28 struct inode
*parent
, *ino
;
29 struct sffs_attr attr
;
33 /* We cannot create files on a read-only file system. */
34 if (state
.s_read_only
)
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
= sffs_table
->t_open(path
, O_CREAT
| O_EXCL
| O_RDWR
, m_in
.REQ_MODE
,
66 /* Let's not try to be too clever with error codes here. If something
67 * is wrong with the directory, we'll find out later anyway.
76 /* Get the created file's attributes. */
77 attr
.a_mask
= SFFS_ATTR_MODE
| SFFS_ATTR_SIZE
;
78 r
= sffs_table
->t_getattr(path
, &attr
);
80 /* If this fails, or returns a directory, we have a problem. This
81 * scenario is in fact possible with race conditions.
82 * Simulate a close and return a somewhat appropriate error.
84 if (r
!= OK
|| S_ISDIR(attr
.a_mode
)) {
85 printf("%s: lost file after creation!\n", sffs_name
);
87 sffs_table
->t_close(handle
);
95 return (r
== OK
) ? EEXIST
: r
;
98 /* We do assume that the underlying open(O_CREAT|O_EXCL) call did its job.
99 * If we previousy found an inode, get rid of it now. It's old.
107 /* Associate the open file handle with an inode, and reply with its details.
109 ino
= get_free_inode();
111 assert(ino
!= NULL
); /* we checked before whether we had a free one */
113 ino
->i_file
= handle
;
114 ino
->i_flags
= I_HANDLE
;
116 add_dentry(parent
, name
, ino
);
118 m_out
.RES_INODE_NR
= INODE_NR(ino
);
119 m_out
.RES_MODE
= get_mode(ino
, attr
.a_mode
);
120 m_out
.RES_FILE_SIZE_HI
= ex64hi(attr
.a_size
);
121 m_out
.RES_FILE_SIZE_LO
= ex64lo(attr
.a_size
);
122 m_out
.RES_UID
= sffs_params
->p_uid
;
123 m_out
.RES_GID
= sffs_params
->p_gid
;
124 m_out
.RES_DEV
= NO_DEV
;
129 /*===========================================================================*
131 *===========================================================================*/
134 /* Make a new directory.
136 char path
[PATH_MAX
], name
[NAME_MAX
+1];
137 struct inode
*parent
, *ino
;
140 /* We cannot create directories on a read-only file system. */
141 if (state
.s_read_only
)
144 /* Get the path string and possibly an inode for the given path. */
145 if ((r
= get_name(m_in
.REQ_GRANT
, m_in
.REQ_PATH_LEN
, name
)) != OK
)
148 if (!strcmp(name
, ".") || !strcmp(name
, "..")) return EEXIST
;
150 if ((parent
= find_inode(m_in
.REQ_INODE_NR
)) == NULL
)
153 if ((r
= verify_dentry(parent
, name
, path
, &ino
)) != OK
)
156 /* Perform the actual mkdir call. */
157 r
= sffs_table
->t_mkdir(path
, m_in
.REQ_MODE
);
166 /* If we thought the new dentry already existed, it was apparently gone
167 * already. Delete it.
178 /*===========================================================================*
180 *===========================================================================*/
181 static int force_remove(path
, dir
)
182 char *path
; /* path to file or directory */
183 int dir
; /* TRUE iff directory */
185 /* Remove a file or directory. Wrapper around unlink and rmdir that makes the
186 * target temporarily writable if the operation fails with an access denied
187 * error. On Windows hosts, read-only files or directories cannot be removed
188 * (even though they can be renamed). In general, the SFFS library follows the
189 * behavior of the host file system, but this case just confuses the hell out
190 * of the MINIX userland..
192 struct sffs_attr attr
;
195 /* First try to remove the target. */
197 r
= sffs_table
->t_rmdir(path
);
199 r
= sffs_table
->t_unlink(path
);
201 if (r
!= EACCES
) return r
;
203 /* If this fails with an access error, retrieve the target's mode. */
204 attr
.a_mask
= SFFS_ATTR_MODE
;
206 r2
= sffs_table
->t_getattr(path
, &attr
);
208 if (r2
!= OK
|| (attr
.a_mode
& S_IWUSR
)) return r
;
210 /* If the target is not writable, temporarily set it to writable. */
211 attr
.a_mode
|= S_IWUSR
;
213 r2
= sffs_table
->t_setattr(path
, &attr
);
215 if (r2
!= OK
) return r
;
217 /* Then try the original operation again. */
219 r
= sffs_table
->t_rmdir(path
);
221 r
= sffs_table
->t_unlink(path
);
223 if (r
== OK
) return r
;
225 /* If the operation still fails, unset the writable bit again. */
226 attr
.a_mode
&= ~S_IWUSR
;
228 sffs_table
->t_setattr(path
, &attr
);
233 /*===========================================================================*
235 *===========================================================================*/
240 char path
[PATH_MAX
], name
[NAME_MAX
+1];
241 struct inode
*parent
, *ino
;
244 /* We cannot delete files on a read-only file system. */
245 if (state
.s_read_only
)
248 /* Get the path string and possibly preexisting inode for the given path. */
249 if ((r
= get_name(m_in
.REQ_GRANT
, m_in
.REQ_PATH_LEN
, name
)) != OK
)
252 if (!strcmp(name
, ".") || !strcmp(name
, "..")) return EPERM
;
254 if ((parent
= find_inode(m_in
.REQ_INODE_NR
)) == NULL
)
257 if ((r
= verify_dentry(parent
, name
, path
, &ino
)) != OK
)
260 /* Perform the unlink call. */
261 r
= force_remove(path
, FALSE
/*dir*/);
270 /* If a dentry existed for this name, it is gone now. */
280 /*===========================================================================*
282 *===========================================================================*/
285 /* Remove an empty directory.
287 char path
[PATH_MAX
], name
[NAME_MAX
+1];
288 struct inode
*parent
, *ino
;
291 /* We cannot remove directories on a read-only file system. */
292 if (state
.s_read_only
)
295 /* Get the path string and possibly preexisting inode for the given path. */
296 if ((r
= get_name(m_in
.REQ_GRANT
, m_in
.REQ_PATH_LEN
, name
)) != OK
)
299 if (!strcmp(name
, ".")) return EINVAL
;
300 if (!strcmp(name
, "..")) return ENOTEMPTY
;
302 if ((parent
= find_inode(m_in
.REQ_INODE_NR
)) == NULL
)
305 if ((r
= verify_dentry(parent
, name
, path
, &ino
)) != OK
)
308 /* Perform the rmdir call. */
309 r
= force_remove(path
, TRUE
/*dir*/);
318 /* If a dentry existed for this name, it is gone now. */
328 /*===========================================================================*
330 *===========================================================================*/
333 /* Rename a file or directory.
335 char old_path
[PATH_MAX
], new_path
[PATH_MAX
];
336 char old_name
[NAME_MAX
+1], new_name
[NAME_MAX
+1];
337 struct inode
*old_parent
, *new_parent
;
338 struct inode
*old_ino
, *new_ino
;
341 /* We cannot do rename on a read-only file system. */
342 if (state
.s_read_only
)
345 /* Get path strings, names, directory inodes and possibly preexisting inodes
346 * for the old and new paths.
348 if ((r
= get_name(m_in
.REQ_REN_GRANT_OLD
, m_in
.REQ_REN_LEN_OLD
,
349 old_name
)) != OK
) return r
;
351 if ((r
= get_name(m_in
.REQ_REN_GRANT_NEW
, m_in
.REQ_REN_LEN_NEW
,
352 new_name
)) != OK
) return r
;
354 if (!strcmp(old_name
, ".") || !strcmp(old_name
, "..") ||
355 !strcmp(new_name
, ".") || !strcmp(new_name
, "..")) return EINVAL
;
357 if ((old_parent
= find_inode(m_in
.REQ_REN_OLD_DIR
)) == NULL
||
358 (new_parent
= find_inode(m_in
.REQ_REN_NEW_DIR
)) == NULL
)
361 if ((r
= verify_dentry(old_parent
, old_name
, old_path
, &old_ino
)) != OK
)
364 if ((r
= verify_dentry(new_parent
, new_name
, new_path
, &new_ino
)) != OK
) {
371 /* Perform the actual rename call. */
372 r
= sffs_table
->t_rename(old_path
, new_path
);
374 /* If we failed, or if we have nothing further to do: both inodes are
375 * NULL, or they both refer to the same file.
377 if (r
!= OK
|| old_ino
== new_ino
) {
378 if (old_ino
!= NULL
) put_inode(old_ino
);
380 if (new_ino
!= NULL
) put_inode(new_ino
);
385 /* If the new dentry already existed, it has now been overwritten.
386 * Delete the associated inode if we had found one.
388 if (new_ino
!= NULL
) {
394 /* If the old dentry existed, rename it accordingly. */
395 if (old_ino
!= NULL
) {
398 add_dentry(new_parent
, new_name
, old_ino
);