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