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