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 /*===========================================================================*
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
)
27 struct inode
*parent
, *ino
;
28 struct sffs_attr attr
;
32 /* We cannot create files on a read-only file system. */
36 if ((parent
= find_inode(dir_nr
)) == NULL
)
39 if ((r
= verify_dentry(parent
, name
, path
, &ino
)) != OK
)
42 /* Are we going to need a new inode upon success?
43 * Then make sure there is one available before trying anything.
45 if (ino
== NULL
|| ino
->i_ref
> 1 || HAS_CHILDREN(ino
)) {
46 if (!have_free_inode()) {
54 /* Perform the actual create call. */
55 r
= sffs_table
->t_open(path
, O_CREAT
| O_EXCL
| O_RDWR
, mode
, &handle
);
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.
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
);
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.
76 if (r
!= OK
|| S_ISDIR(attr
.a_mode
)) {
77 printf("%s: lost file after creation!\n", sffs_name
);
79 sffs_table
->t_close(handle
);
87 return (r
== OK
) ? EEXIST
: r
;
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.
99 /* Associate the open file handle with an inode, and reply with its details.
101 ino
= get_free_inode();
103 assert(ino
!= NULL
); /* we checked before whether we had a free one */
105 ino
->i_file
= handle
;
106 ino
->i_flags
= I_HANDLE
;
108 add_dentry(parent
, name
, ino
);
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
;
120 /*===========================================================================*
122 *===========================================================================*/
123 int do_mkdir(ino_t dir_nr
, char *name
, mode_t mode
, uid_t uid
, gid_t gid
)
125 /* Make a new directory.
128 struct inode
*parent
, *ino
;
131 /* We cannot create directories on a read-only file system. */
135 if ((parent
= find_inode(dir_nr
)) == NULL
)
138 if ((r
= verify_dentry(parent
, name
, path
, &ino
)) != OK
)
141 /* Perform the actual mkdir call. */
142 r
= sffs_table
->t_mkdir(path
, mode
);
151 /* If we thought the new dentry already existed, it was apparently gone
152 * already. Delete it.
163 /*===========================================================================*
165 *===========================================================================*/
166 static int force_remove(
167 char *path
, /* path to file or directory */
168 int dir
/* TRUE iff directory */
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..
178 struct sffs_attr attr
;
181 /* First try to remove the target. */
183 r
= sffs_table
->t_rmdir(path
);
185 r
= sffs_table
->t_unlink(path
);
187 if (r
!= EACCES
) return r
;
189 /* If this fails with an access error, retrieve the target's mode. */
190 attr
.a_mask
= SFFS_ATTR_MODE
;
192 r2
= sffs_table
->t_getattr(path
, &attr
);
194 if (r2
!= OK
|| (attr
.a_mode
& S_IWUSR
)) return r
;
196 /* If the target is not writable, temporarily set it to writable. */
197 attr
.a_mode
|= S_IWUSR
;
199 r2
= sffs_table
->t_setattr(path
, &attr
);
201 if (r2
!= OK
) return r
;
203 /* Then try the original operation again. */
205 r
= sffs_table
->t_rmdir(path
);
207 r
= sffs_table
->t_unlink(path
);
209 if (r
== OK
) return r
;
211 /* If the operation still fails, unset the writable bit again. */
212 attr
.a_mode
&= ~S_IWUSR
;
214 sffs_table
->t_setattr(path
, &attr
);
219 /*===========================================================================*
221 *===========================================================================*/
222 int do_unlink(ino_t dir_nr
, char *name
, int call
)
227 struct inode
*parent
, *ino
;
230 /* We cannot delete files on a read-only file system. */
234 if ((parent
= find_inode(dir_nr
)) == NULL
)
237 if ((r
= verify_dentry(parent
, name
, path
, &ino
)) != OK
)
240 /* Perform the unlink call. */
241 r
= force_remove(path
, FALSE
/*dir*/);
250 /* If a dentry existed for this name, it is gone now. */
260 /*===========================================================================*
262 *===========================================================================*/
263 int do_rmdir(ino_t dir_nr
, char *name
, int call
)
265 /* Remove an empty directory.
268 struct inode
*parent
, *ino
;
271 /* We cannot remove directories on a read-only file system. */
275 if ((parent
= find_inode(dir_nr
)) == NULL
)
278 if ((r
= verify_dentry(parent
, name
, path
, &ino
)) != OK
)
281 /* Perform the rmdir call. */
282 r
= force_remove(path
, TRUE
/*dir*/);
291 /* If a dentry existed for this name, it is gone now. */
301 /*===========================================================================*
303 *===========================================================================*/
304 int do_rename(ino_t old_dir_nr
, char *old_name
, ino_t new_dir_nr
,
307 /* Rename a file or directory.
309 char old_path
[PATH_MAX
], new_path
[PATH_MAX
];
310 struct inode
*old_parent
, *new_parent
;
311 struct inode
*old_ino
, *new_ino
;
314 /* We cannot do rename on a read-only file system. */
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
)
323 if ((r
= verify_dentry(old_parent
, old_name
, old_path
, &old_ino
)) != OK
)
326 if ((r
= verify_dentry(new_parent
, new_name
, new_path
, &new_ino
)) != OK
) {
333 /* Perform the actual rename call. */
334 r
= sffs_table
->t_rename(old_path
, new_path
);
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.
339 if (r
!= OK
|| old_ino
== new_ino
) {
340 if (old_ino
!= NULL
) put_inode(old_ino
);
342 if (new_ino
!= NULL
) put_inode(new_ino
);
347 /* If the new dentry already existed, it has now been overwritten.
348 * Delete the associated inode if we had found one.
350 if (new_ino
!= NULL
) {
356 /* If the old dentry existed, rename it accordingly. */
357 if (old_ino
!= NULL
) {
360 add_dentry(new_parent
, new_name
, old_ino
);