Blame view
fs/fat/namei_msdos.c
16.7 KB
1da177e4c
|
1 2 3 4 5 6 7 8 9 10 11 |
/* * linux/fs/msdos/namei.c * * Written 1992,1993 by Werner Almesberger * Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu> * Rewritten for constant inumbers 1999 by Al Viro */ #include <linux/module.h> #include <linux/time.h> #include <linux/buffer_head.h> |
9e975dae2
|
12 |
#include "fat.h" |
1da177e4c
|
13 |
|
1da177e4c
|
14 15 |
/* Characters that are undesirable in an MS-DOS file name */ static unsigned char bad_chars[] = "*?<>|\""; |
7557bc66b
|
16 |
static unsigned char bad_if_strict[] = "+=,; "; |
1da177e4c
|
17 18 19 20 21 22 23 24 25 26 27 28 |
/***** Formats an MS-DOS file name. Rejects invalid names. */ static int msdos_format_name(const unsigned char *name, int len, unsigned char *res, struct fat_mount_options *opts) /* * name is the proposed name, len is its length, res is * the resulting name, opts->name_check is either (r)elaxed, * (n)ormal or (s)trict, opts->dotsOK allows dots at the * beginning of name (for hidden files) */ { unsigned char *walk; |
1da177e4c
|
29 30 31 32 33 34 35 36 |
unsigned char c; int space; if (name[0] == '.') { /* dotfile because . and .. already done */ if (opts->dotsOK) { /* Get rid of dot - test for it elsewhere */ name++; len--; |
7557bc66b
|
37 |
} else |
1da177e4c
|
38 39 40 |
return -EINVAL; } /* |
7557bc66b
|
41 |
* disallow names that _really_ start with a dot |
1da177e4c
|
42 |
*/ |
7557bc66b
|
43 |
space = 1; |
1da177e4c
|
44 45 46 47 48 49 |
c = 0; for (walk = res; len && walk - res < 8; walk++) { c = *name++; len--; if (opts->name_check != 'r' && strchr(bad_chars, c)) return -EINVAL; |
7557bc66b
|
50 |
if (opts->name_check == 's' && strchr(bad_if_strict, c)) |
1da177e4c
|
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
return -EINVAL; if (c >= 'A' && c <= 'Z' && opts->name_check == 's') return -EINVAL; if (c < ' ' || c == ':' || c == '\\') return -EINVAL; /* * 0xE5 is legal as a first character, but we must substitute * 0x05 because 0xE5 marks deleted files. Yes, DOS really * does this. * It seems that Microsoft hacked DOS to support non-US * characters after the 0xE5 character was already in use to * mark deleted files. */ if ((res == walk) && (c == 0xE5)) c = 0x05; if (c == '.') break; space = (c == ' '); *walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c - 32 : c; } if (space) return -EINVAL; if (opts->name_check == 's' && len && c != '.') { c = *name++; len--; if (c != '.') return -EINVAL; } while (c != '.' && len--) c = *name++; if (c == '.') { while (walk - res < 8) *walk++ = ' '; while (len > 0 && walk - res < MSDOS_NAME) { c = *name++; len--; if (opts->name_check != 'r' && strchr(bad_chars, c)) return -EINVAL; if (opts->name_check == 's' && |
7557bc66b
|
90 |
strchr(bad_if_strict, c)) |
1da177e4c
|
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
return -EINVAL; if (c < ' ' || c == ':' || c == '\\') return -EINVAL; if (c == '.') { if (opts->name_check == 's') return -EINVAL; break; } if (c >= 'A' && c <= 'Z' && opts->name_check == 's') return -EINVAL; space = c == ' '; if (!opts->nocase && c >= 'a' && c <= 'z') *walk++ = c - 32; else *walk++ = c; } if (space) return -EINVAL; if (opts->name_check == 's' && len) return -EINVAL; } while (walk - res < MSDOS_NAME) *walk++ = ' '; |
094e320d7
|
114 |
|
1da177e4c
|
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
return 0; } /***** Locates a directory entry. Uses unformatted name. */ static int msdos_find(struct inode *dir, const unsigned char *name, int len, struct fat_slot_info *sinfo) { struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb); unsigned char msdos_name[MSDOS_NAME]; int err; err = msdos_format_name(name, len, msdos_name, &sbi->options); if (err) return -ENOENT; err = fat_scan(dir, msdos_name, sinfo); if (!err && sbi->options.dotsOK) { if (name[0] == '.') { if (!(sinfo->de->attr & ATTR_HIDDEN)) err = -ENOENT; } else { if (sinfo->de->attr & ATTR_HIDDEN) err = -ENOENT; } if (err) brelse(sinfo->bh); } return err; } /* * Compute the hash for the msdos name corresponding to the dentry. * Note: if the name is invalid, we leave the hash code unchanged so * that the existing dentry can be used. The msdos fs routines will * return ENOENT or EINVAL as appropriate. */ |
b1e6a015a
|
151 152 |
static int msdos_hash(const struct dentry *dentry, const struct inode *inode, struct qstr *qstr) |
1da177e4c
|
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
{ struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; unsigned char msdos_name[MSDOS_NAME]; int error; error = msdos_format_name(qstr->name, qstr->len, msdos_name, options); if (!error) qstr->hash = full_name_hash(msdos_name, MSDOS_NAME); return 0; } /* * Compare two msdos names. If either of the names are invalid, * we fall back to doing the standard name comparison. */ |
621e155a3
|
168 169 170 |
static int msdos_cmp(const struct dentry *parent, const struct inode *pinode, const struct dentry *dentry, const struct inode *inode, unsigned int len, const char *str, const struct qstr *name) |
1da177e4c
|
171 |
{ |
621e155a3
|
172 |
struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options; |
1da177e4c
|
173 174 |
unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME]; int error; |
621e155a3
|
175 |
error = msdos_format_name(name->name, name->len, a_msdos_name, options); |
1da177e4c
|
176 177 |
if (error) goto old_compare; |
621e155a3
|
178 |
error = msdos_format_name(str, len, b_msdos_name, options); |
1da177e4c
|
179 180 181 182 183 184 185 186 |
if (error) goto old_compare; error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME); out: return error; old_compare: error = 1; |
621e155a3
|
187 188 |
if (name->len == len) error = memcmp(name->name, str, len); |
1da177e4c
|
189 190 |
goto out; } |
ce6cdc474
|
191 |
static const struct dentry_operations msdos_dentry_operations = { |
1da177e4c
|
192 193 194 195 196 197 198 199 200 201 |
.d_hash = msdos_hash, .d_compare = msdos_cmp, }; /* * AV. Wrappers for FAT sb operations. Is it wise? */ /***** Get inode using directory and name */ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry, |
00cd8dd3b
|
202 |
unsigned int flags) |
1da177e4c
|
203 204 205 |
{ struct super_block *sb = dir->i_sb; struct fat_slot_info sinfo; |
45cfbe354
|
206 207 |
struct inode *inode; int err; |
1da177e4c
|
208 |
|
e40b34c79
|
209 |
mutex_lock(&MSDOS_SB(sb)->s_lock); |
45cfbe354
|
210 |
err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo); |
a9049376e
|
211 212 213 214 215 216 217 218 219 220 |
switch (err) { case -ENOENT: inode = NULL; break; case 0: inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); brelse(sinfo.bh); break; default: inode = ERR_PTR(err); |
1da177e4c
|
221 |
} |
e40b34c79
|
222 |
mutex_unlock(&MSDOS_SB(sb)->s_lock); |
3d23985d6
|
223 |
return d_splice_alias(inode, dentry); |
1da177e4c
|
224 225 226 227 228 229 230 |
} /***** Creates a directory entry (name is already formatted). */ static int msdos_add_entry(struct inode *dir, const unsigned char *name, int is_dir, int is_hid, int cluster, struct timespec *ts, struct fat_slot_info *sinfo) { |
b271e067c
|
231 |
struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb); |
1da177e4c
|
232 233 234 235 236 237 238 239 240 |
struct msdos_dir_entry de; __le16 time, date; int err; memcpy(de.name, name, MSDOS_NAME); de.attr = is_dir ? ATTR_DIR : ATTR_ARCH; if (is_hid) de.attr |= ATTR_HIDDEN; de.lcase = 0; |
7decd1cb0
|
241 |
fat_time_unix2fat(sbi, ts, &time, &date, NULL); |
1da177e4c
|
242 243 244 245 246 |
de.cdate = de.adate = 0; de.ctime = 0; de.ctime_cs = 0; de.time = time; de.date = date; |
a943ed71c
|
247 |
fat_set_start(&de, cluster); |
1da177e4c
|
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
de.size = 0; err = fat_add_entries(dir, &de, 1, sinfo); if (err) return err; dir->i_ctime = dir->i_mtime = *ts; if (IS_DIRSYNC(dir)) (void)fat_sync_inode(dir); else mark_inode_dirty(dir); return 0; } /***** Create a file */ |
4acdaf27e
|
264 |
static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode, |
ebfc3b49a
|
265 |
bool excl) |
1da177e4c
|
266 267 |
{ struct super_block *sb = dir->i_sb; |
ae78bf9c4
|
268 |
struct inode *inode = NULL; |
1da177e4c
|
269 270 271 272 |
struct fat_slot_info sinfo; struct timespec ts; unsigned char msdos_name[MSDOS_NAME]; int err, is_hid; |
e40b34c79
|
273 |
mutex_lock(&MSDOS_SB(sb)->s_lock); |
1da177e4c
|
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
err = msdos_format_name(dentry->d_name.name, dentry->d_name.len, msdos_name, &MSDOS_SB(sb)->options); if (err) goto out; is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.'); /* Have to do it due to foo vs. .foo conflicts */ if (!fat_scan(dir, msdos_name, &sinfo)) { brelse(sinfo.bh); err = -EINVAL; goto out; } ts = CURRENT_TIME_SEC; err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo); if (err) goto out; inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); brelse(sinfo.bh); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out; } inode->i_mtime = inode->i_atime = inode->i_ctime = ts; /* timestamp is already written, so mark_inode_dirty() is unneeded. */ d_instantiate(dentry, inode); out: |
e40b34c79
|
302 |
mutex_unlock(&MSDOS_SB(sb)->s_lock); |
ae78bf9c4
|
303 304 |
if (!err) err = fat_flush_inodes(sb, dir, inode); |
1da177e4c
|
305 306 307 308 309 310 |
return err; } /***** Remove a directory */ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) { |
8f5934278
|
311 |
struct super_block *sb = dir->i_sb; |
1da177e4c
|
312 313 314 |
struct inode *inode = dentry->d_inode; struct fat_slot_info sinfo; int err; |
e40b34c79
|
315 |
mutex_lock(&MSDOS_SB(sb)->s_lock); |
1da177e4c
|
316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
/* * Check whether the directory is not in use, then check * whether it is empty. */ err = fat_dir_empty(inode); if (err) goto out; err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo); if (err) goto out; err = fat_remove_entries(dir, &sinfo); /* and releases bh */ if (err) goto out; |
9a53c3a78
|
330 |
drop_nlink(dir); |
1da177e4c
|
331 |
|
ce71ec368
|
332 |
clear_nlink(inode); |
1da177e4c
|
333 334 335 |
inode->i_ctime = CURRENT_TIME_SEC; fat_detach(inode); out: |
e40b34c79
|
336 |
mutex_unlock(&MSDOS_SB(sb)->s_lock); |
ae78bf9c4
|
337 |
if (!err) |
8f5934278
|
338 |
err = fat_flush_inodes(sb, dir, inode); |
1da177e4c
|
339 340 341 342 343 |
return err; } /***** Make a directory */ |
18bb1db3e
|
344 |
static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) |
1da177e4c
|
345 346 347 348 349 350 351 |
{ struct super_block *sb = dir->i_sb; struct fat_slot_info sinfo; struct inode *inode; unsigned char msdos_name[MSDOS_NAME]; struct timespec ts; int err, is_hid, cluster; |
e40b34c79
|
352 |
mutex_lock(&MSDOS_SB(sb)->s_lock); |
1da177e4c
|
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
err = msdos_format_name(dentry->d_name.name, dentry->d_name.len, msdos_name, &MSDOS_SB(sb)->options); if (err) goto out; is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.'); /* foo vs .foo situation */ if (!fat_scan(dir, msdos_name, &sinfo)) { brelse(sinfo.bh); err = -EINVAL; goto out; } ts = CURRENT_TIME_SEC; cluster = fat_alloc_new_dir(dir, &ts); if (cluster < 0) { err = cluster; goto out; } err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo); if (err) goto out_free; |
d8c76e6f4
|
375 |
inc_nlink(dir); |
1da177e4c
|
376 377 378 379 380 381 382 383 |
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); brelse(sinfo.bh); if (IS_ERR(inode)) { err = PTR_ERR(inode); /* the directory was completed, just return a error */ goto out; } |
bfe868486
|
384 |
set_nlink(inode, 2); |
1da177e4c
|
385 386 387 388 |
inode->i_mtime = inode->i_atime = inode->i_ctime = ts; /* timestamp is already written, so mark_inode_dirty() is unneeded. */ d_instantiate(dentry, inode); |
e40b34c79
|
389 |
mutex_unlock(&MSDOS_SB(sb)->s_lock); |
ae78bf9c4
|
390 |
fat_flush_inodes(sb, dir, inode); |
1da177e4c
|
391 392 393 394 395 |
return 0; out_free: fat_free_clusters(dir, cluster); out: |
e40b34c79
|
396 |
mutex_unlock(&MSDOS_SB(sb)->s_lock); |
1da177e4c
|
397 398 399 400 401 402 403 |
return err; } /***** Unlink a file */ static int msdos_unlink(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; |
85cb9bf53
|
404 |
struct super_block *sb = inode->i_sb; |
1da177e4c
|
405 406 |
struct fat_slot_info sinfo; int err; |
e40b34c79
|
407 |
mutex_lock(&MSDOS_SB(sb)->s_lock); |
1da177e4c
|
408 409 410 411 412 413 414 |
err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo); if (err) goto out; err = fat_remove_entries(dir, &sinfo); /* and releases bh */ if (err) goto out; |
ce71ec368
|
415 |
clear_nlink(inode); |
1da177e4c
|
416 417 418 |
inode->i_ctime = CURRENT_TIME_SEC; fat_detach(inode); out: |
e40b34c79
|
419 |
mutex_unlock(&MSDOS_SB(sb)->s_lock); |
ae78bf9c4
|
420 |
if (!err) |
8f5934278
|
421 |
err = fat_flush_inodes(sb, dir, inode); |
1da177e4c
|
422 423 424 425 426 427 428 429 430 431 432 |
return err; } static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, struct dentry *old_dentry, struct inode *new_dir, unsigned char *new_name, struct dentry *new_dentry, int is_hid) { struct buffer_head *dotdot_bh; struct msdos_dir_entry *dotdot_de; |
1da177e4c
|
433 434 435 |
struct inode *old_inode, *new_inode; struct fat_slot_info old_sinfo, sinfo; struct timespec ts; |
7669e8fb0
|
436 |
loff_t new_i_pos; |
1da177e4c
|
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 |
int err, old_attrs, is_dir, update_dotdot, corrupt = 0; old_sinfo.bh = sinfo.bh = dotdot_bh = NULL; old_inode = old_dentry->d_inode; new_inode = new_dentry->d_inode; err = fat_scan(old_dir, old_name, &old_sinfo); if (err) { err = -EIO; goto out; } is_dir = S_ISDIR(old_inode->i_mode); update_dotdot = (is_dir && old_dir != new_dir); if (update_dotdot) { |
7669e8fb0
|
452 |
if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) { |
1da177e4c
|
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
err = -EIO; goto out; } } old_attrs = MSDOS_I(old_inode)->i_attrs; err = fat_scan(new_dir, new_name, &sinfo); if (!err) { if (!new_inode) { /* "foo" -> ".foo" case. just change the ATTR_HIDDEN */ if (sinfo.de != old_sinfo.de) { err = -EINVAL; goto out; } if (is_hid) MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN; else MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN; if (IS_DIRSYNC(old_dir)) { err = fat_sync_inode(old_inode); if (err) { MSDOS_I(old_inode)->i_attrs = old_attrs; goto out; } } else mark_inode_dirty(old_inode); old_dir->i_version++; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; if (IS_DIRSYNC(old_dir)) (void)fat_sync_inode(old_dir); else mark_inode_dirty(old_dir); goto out; } } ts = CURRENT_TIME_SEC; if (new_inode) { if (err) goto out; |
1da177e4c
|
494 495 496 497 498 |
if (is_dir) { err = fat_dir_empty(new_inode); if (err) goto out; } |
9131dd425
|
499 |
new_i_pos = MSDOS_I(new_inode)->i_pos; |
1da177e4c
|
500 501 502 503 504 505 |
fat_detach(new_inode); } else { err = msdos_add_entry(new_dir, new_name, is_dir, is_hid, 0, &ts, &sinfo); if (err) goto out; |
9131dd425
|
506 |
new_i_pos = sinfo.i_pos; |
1da177e4c
|
507 508 509 510 |
} new_dir->i_version++; fat_detach(old_inode); |
9131dd425
|
511 |
fat_attach(old_inode, new_i_pos); |
1da177e4c
|
512 513 514 515 516 517 518 519 520 521 522 523 |
if (is_hid) MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN; else MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN; if (IS_DIRSYNC(new_dir)) { err = fat_sync_inode(old_inode); if (err) goto error_inode; } else mark_inode_dirty(old_inode); if (update_dotdot) { |
a943ed71c
|
524 |
fat_set_start(dotdot_de, MSDOS_I(new_dir)->i_logstart); |
b522412ae
|
525 |
mark_buffer_dirty_inode(dotdot_bh, old_inode); |
1da177e4c
|
526 527 528 529 530 |
if (IS_DIRSYNC(new_dir)) { err = sync_dirty_buffer(dotdot_bh); if (err) goto error_dotdot; } |
9a53c3a78
|
531 |
drop_nlink(old_dir); |
1da177e4c
|
532 |
if (!new_inode) |
d8c76e6f4
|
533 |
inc_nlink(new_dir); |
1da177e4c
|
534 535 536 537 538 539 540 541 542 543 544 545 546 547 |
} err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */ old_sinfo.bh = NULL; if (err) goto error_dotdot; old_dir->i_version++; old_dir->i_ctime = old_dir->i_mtime = ts; if (IS_DIRSYNC(old_dir)) (void)fat_sync_inode(old_dir); else mark_inode_dirty(old_dir); if (new_inode) { |
9a53c3a78
|
548 |
drop_nlink(new_inode); |
1da177e4c
|
549 |
if (is_dir) |
9a53c3a78
|
550 |
drop_nlink(new_inode); |
1da177e4c
|
551 552 553 554 555 556 557 558 559 560 561 562 563 |
new_inode->i_ctime = ts; } out: brelse(sinfo.bh); brelse(dotdot_bh); brelse(old_sinfo.bh); return err; error_dotdot: /* data cluster is shared, serious corruption */ corrupt = 1; if (update_dotdot) { |
a943ed71c
|
564 |
fat_set_start(dotdot_de, MSDOS_I(old_dir)->i_logstart); |
b522412ae
|
565 |
mark_buffer_dirty_inode(dotdot_bh, old_inode); |
1da177e4c
|
566 567 568 569 570 571 572 |
corrupt |= sync_dirty_buffer(dotdot_bh); } error_inode: fat_detach(old_inode); fat_attach(old_inode, old_sinfo.i_pos); MSDOS_I(old_inode)->i_attrs = old_attrs; if (new_inode) { |
9131dd425
|
573 |
fat_attach(new_inode, new_i_pos); |
1da177e4c
|
574 575 576 577 578 579 580 581 582 583 584 585 586 |
if (corrupt) corrupt |= fat_sync_inode(new_inode); } else { /* * If new entry was not sharing the data cluster, it * shouldn't be serious corruption. */ int err2 = fat_remove_entries(new_dir, &sinfo); if (corrupt) corrupt |= err2; sinfo.bh = NULL; } if (corrupt < 0) { |
85c785919
|
587 |
fat_fs_error(new_dir->i_sb, |
1da177e4c
|
588 |
"%s: Filesystem corrupted (i_pos %lld)", |
8e24eea72
|
589 |
__func__, sinfo.i_pos); |
1da177e4c
|
590 591 592 593 594 595 596 597 |
} goto out; } /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */ static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { |
8f5934278
|
598 |
struct super_block *sb = old_dir->i_sb; |
1da177e4c
|
599 600 |
unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME]; int err, is_hid; |
e40b34c79
|
601 |
mutex_lock(&MSDOS_SB(sb)->s_lock); |
1da177e4c
|
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 |
err = msdos_format_name(old_dentry->d_name.name, old_dentry->d_name.len, old_msdos_name, &MSDOS_SB(old_dir->i_sb)->options); if (err) goto out; err = msdos_format_name(new_dentry->d_name.name, new_dentry->d_name.len, new_msdos_name, &MSDOS_SB(new_dir->i_sb)->options); if (err) goto out; is_hid = (new_dentry->d_name.name[0] == '.') && (new_msdos_name[0] != '.'); err = do_msdos_rename(old_dir, old_msdos_name, old_dentry, new_dir, new_msdos_name, new_dentry, is_hid); out: |
e40b34c79
|
620 |
mutex_unlock(&MSDOS_SB(sb)->s_lock); |
ae78bf9c4
|
621 |
if (!err) |
8f5934278
|
622 |
err = fat_flush_inodes(sb, old_dir, new_dir); |
1da177e4c
|
623 624 |
return err; } |
92e1d5be9
|
625 |
static const struct inode_operations msdos_dir_inode_operations = { |
1da177e4c
|
626 627 628 629 630 631 |
.create = msdos_create, .lookup = msdos_lookup, .unlink = msdos_unlink, .mkdir = msdos_mkdir, .rmdir = msdos_rmdir, .rename = msdos_rename, |
1278fdd34
|
632 |
.setattr = fat_setattr, |
da63fc7ce
|
633 |
.getattr = fat_getattr, |
1da177e4c
|
634 |
}; |
3d23985d6
|
635 |
static void setup(struct super_block *sb) |
1da177e4c
|
636 |
{ |
384f5c96e
|
637 |
MSDOS_SB(sb)->dir_ops = &msdos_dir_inode_operations; |
3d23985d6
|
638 |
sb->s_d_op = &msdos_dentry_operations; |
1da177e4c
|
639 |
sb->s_flags |= MS_NOATIME; |
3d23985d6
|
640 641 642 643 |
} static int msdos_fill_super(struct super_block *sb, void *data, int silent) { |
384f5c96e
|
644 |
return fat_fill_super(sb, data, silent, 0, setup); |
1da177e4c
|
645 |
} |
152a08366
|
646 |
static struct dentry *msdos_mount(struct file_system_type *fs_type, |
454e2398b
|
647 |
int flags, const char *dev_name, |
152a08366
|
648 |
void *data) |
1da177e4c
|
649 |
{ |
152a08366
|
650 |
return mount_bdev(fs_type, flags, dev_name, data, msdos_fill_super); |
1da177e4c
|
651 652 653 654 655 |
} static struct file_system_type msdos_fs_type = { .owner = THIS_MODULE, .name = "msdos", |
152a08366
|
656 |
.mount = msdos_mount, |
1da177e4c
|
657 658 659 |
.kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; |
7f78e0351
|
660 |
MODULE_ALIAS_FS("msdos"); |
1da177e4c
|
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
static int __init init_msdos_fs(void) { return register_filesystem(&msdos_fs_type); } static void __exit exit_msdos_fs(void) { unregister_filesystem(&msdos_fs_type); } MODULE_LICENSE("GPL"); MODULE_AUTHOR("Werner Almesberger"); MODULE_DESCRIPTION("MS-DOS filesystem support"); module_init(init_msdos_fs) module_exit(exit_msdos_fs) |