109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2990e194eSOGAWA Hirofumi /*
3990e194eSOGAWA Hirofumi * linux/fs/msdos/namei.c
4990e194eSOGAWA Hirofumi *
5990e194eSOGAWA Hirofumi * Written 1992,1993 by Werner Almesberger
6990e194eSOGAWA Hirofumi * Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
7990e194eSOGAWA Hirofumi * Rewritten for constant inumbers 1999 by Al Viro
8990e194eSOGAWA Hirofumi */
9990e194eSOGAWA Hirofumi
10990e194eSOGAWA Hirofumi #include <linux/module.h>
112489dbabSJeff Layton #include <linux/iversion.h>
129e975daeSOGAWA Hirofumi #include "fat.h"
13990e194eSOGAWA Hirofumi
14990e194eSOGAWA Hirofumi /* Characters that are undesirable in an MS-DOS file name */
15990e194eSOGAWA Hirofumi static unsigned char bad_chars[] = "*?<>|\"";
16990e194eSOGAWA Hirofumi static unsigned char bad_if_strict[] = "+=,; ";
17990e194eSOGAWA Hirofumi
18990e194eSOGAWA Hirofumi /***** 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)19990e194eSOGAWA Hirofumi static int msdos_format_name(const unsigned char *name, int len,
20990e194eSOGAWA Hirofumi unsigned char *res, struct fat_mount_options *opts)
21990e194eSOGAWA Hirofumi /*
22990e194eSOGAWA Hirofumi * name is the proposed name, len is its length, res is
23990e194eSOGAWA Hirofumi * the resulting name, opts->name_check is either (r)elaxed,
24990e194eSOGAWA Hirofumi * (n)ormal or (s)trict, opts->dotsOK allows dots at the
25990e194eSOGAWA Hirofumi * beginning of name (for hidden files)
26990e194eSOGAWA Hirofumi */
27990e194eSOGAWA Hirofumi {
28990e194eSOGAWA Hirofumi unsigned char *walk;
29990e194eSOGAWA Hirofumi unsigned char c;
30990e194eSOGAWA Hirofumi int space;
31990e194eSOGAWA Hirofumi
32990e194eSOGAWA Hirofumi if (name[0] == '.') { /* dotfile because . and .. already done */
33990e194eSOGAWA Hirofumi if (opts->dotsOK) {
34990e194eSOGAWA Hirofumi /* Get rid of dot - test for it elsewhere */
35990e194eSOGAWA Hirofumi name++;
36990e194eSOGAWA Hirofumi len--;
37990e194eSOGAWA Hirofumi } else
38990e194eSOGAWA Hirofumi return -EINVAL;
39990e194eSOGAWA Hirofumi }
40990e194eSOGAWA Hirofumi /*
41990e194eSOGAWA Hirofumi * disallow names that _really_ start with a dot
42990e194eSOGAWA Hirofumi */
43990e194eSOGAWA Hirofumi space = 1;
44990e194eSOGAWA Hirofumi c = 0;
45990e194eSOGAWA Hirofumi for (walk = res; len && walk - res < 8; walk++) {
46990e194eSOGAWA Hirofumi c = *name++;
47990e194eSOGAWA Hirofumi len--;
48990e194eSOGAWA Hirofumi if (opts->name_check != 'r' && strchr(bad_chars, c))
49990e194eSOGAWA Hirofumi return -EINVAL;
50990e194eSOGAWA Hirofumi if (opts->name_check == 's' && strchr(bad_if_strict, c))
51990e194eSOGAWA Hirofumi return -EINVAL;
52990e194eSOGAWA Hirofumi if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
53990e194eSOGAWA Hirofumi return -EINVAL;
54990e194eSOGAWA Hirofumi if (c < ' ' || c == ':' || c == '\\')
55990e194eSOGAWA Hirofumi return -EINVAL;
56990e194eSOGAWA Hirofumi /*
57990e194eSOGAWA Hirofumi * 0xE5 is legal as a first character, but we must substitute
58990e194eSOGAWA Hirofumi * 0x05 because 0xE5 marks deleted files. Yes, DOS really
59990e194eSOGAWA Hirofumi * does this.
60990e194eSOGAWA Hirofumi * It seems that Microsoft hacked DOS to support non-US
61990e194eSOGAWA Hirofumi * characters after the 0xE5 character was already in use to
62990e194eSOGAWA Hirofumi * mark deleted files.
63990e194eSOGAWA Hirofumi */
64990e194eSOGAWA Hirofumi if ((res == walk) && (c == 0xE5))
65990e194eSOGAWA Hirofumi c = 0x05;
66990e194eSOGAWA Hirofumi if (c == '.')
67990e194eSOGAWA Hirofumi break;
68990e194eSOGAWA Hirofumi space = (c == ' ');
69990e194eSOGAWA Hirofumi *walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c - 32 : c;
70990e194eSOGAWA Hirofumi }
71990e194eSOGAWA Hirofumi if (space)
72990e194eSOGAWA Hirofumi return -EINVAL;
73990e194eSOGAWA Hirofumi if (opts->name_check == 's' && len && c != '.') {
74990e194eSOGAWA Hirofumi c = *name++;
75990e194eSOGAWA Hirofumi len--;
76990e194eSOGAWA Hirofumi if (c != '.')
77990e194eSOGAWA Hirofumi return -EINVAL;
78990e194eSOGAWA Hirofumi }
79990e194eSOGAWA Hirofumi while (c != '.' && len--)
80990e194eSOGAWA Hirofumi c = *name++;
81990e194eSOGAWA Hirofumi if (c == '.') {
82990e194eSOGAWA Hirofumi while (walk - res < 8)
83990e194eSOGAWA Hirofumi *walk++ = ' ';
84990e194eSOGAWA Hirofumi while (len > 0 && walk - res < MSDOS_NAME) {
85990e194eSOGAWA Hirofumi c = *name++;
86990e194eSOGAWA Hirofumi len--;
87990e194eSOGAWA Hirofumi if (opts->name_check != 'r' && strchr(bad_chars, c))
88990e194eSOGAWA Hirofumi return -EINVAL;
89990e194eSOGAWA Hirofumi if (opts->name_check == 's' &&
90990e194eSOGAWA Hirofumi strchr(bad_if_strict, c))
91990e194eSOGAWA Hirofumi return -EINVAL;
92990e194eSOGAWA Hirofumi if (c < ' ' || c == ':' || c == '\\')
93990e194eSOGAWA Hirofumi return -EINVAL;
94990e194eSOGAWA Hirofumi if (c == '.') {
95990e194eSOGAWA Hirofumi if (opts->name_check == 's')
96990e194eSOGAWA Hirofumi return -EINVAL;
97990e194eSOGAWA Hirofumi break;
98990e194eSOGAWA Hirofumi }
99990e194eSOGAWA Hirofumi if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
100990e194eSOGAWA Hirofumi return -EINVAL;
101990e194eSOGAWA Hirofumi space = c == ' ';
102990e194eSOGAWA Hirofumi if (!opts->nocase && c >= 'a' && c <= 'z')
103990e194eSOGAWA Hirofumi *walk++ = c - 32;
104990e194eSOGAWA Hirofumi else
105990e194eSOGAWA Hirofumi *walk++ = c;
106990e194eSOGAWA Hirofumi }
107990e194eSOGAWA Hirofumi if (space)
108990e194eSOGAWA Hirofumi return -EINVAL;
109990e194eSOGAWA Hirofumi if (opts->name_check == 's' && len)
110990e194eSOGAWA Hirofumi return -EINVAL;
111990e194eSOGAWA Hirofumi }
112990e194eSOGAWA Hirofumi while (walk - res < MSDOS_NAME)
113990e194eSOGAWA Hirofumi *walk++ = ' ';
114990e194eSOGAWA Hirofumi
115990e194eSOGAWA Hirofumi return 0;
116990e194eSOGAWA Hirofumi }
117990e194eSOGAWA Hirofumi
118990e194eSOGAWA Hirofumi /***** Locates a directory entry. Uses unformatted name. */
msdos_find(struct inode * dir,const unsigned char * name,int len,struct fat_slot_info * sinfo)119990e194eSOGAWA Hirofumi static int msdos_find(struct inode *dir, const unsigned char *name, int len,
120990e194eSOGAWA Hirofumi struct fat_slot_info *sinfo)
121990e194eSOGAWA Hirofumi {
122990e194eSOGAWA Hirofumi struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
123990e194eSOGAWA Hirofumi unsigned char msdos_name[MSDOS_NAME];
124990e194eSOGAWA Hirofumi int err;
125990e194eSOGAWA Hirofumi
126990e194eSOGAWA Hirofumi err = msdos_format_name(name, len, msdos_name, &sbi->options);
127990e194eSOGAWA Hirofumi if (err)
128990e194eSOGAWA Hirofumi return -ENOENT;
129990e194eSOGAWA Hirofumi
130990e194eSOGAWA Hirofumi err = fat_scan(dir, msdos_name, sinfo);
131990e194eSOGAWA Hirofumi if (!err && sbi->options.dotsOK) {
132990e194eSOGAWA Hirofumi if (name[0] == '.') {
133990e194eSOGAWA Hirofumi if (!(sinfo->de->attr & ATTR_HIDDEN))
134990e194eSOGAWA Hirofumi err = -ENOENT;
135990e194eSOGAWA Hirofumi } else {
136990e194eSOGAWA Hirofumi if (sinfo->de->attr & ATTR_HIDDEN)
137990e194eSOGAWA Hirofumi err = -ENOENT;
138990e194eSOGAWA Hirofumi }
139990e194eSOGAWA Hirofumi if (err)
140990e194eSOGAWA Hirofumi brelse(sinfo->bh);
141990e194eSOGAWA Hirofumi }
142990e194eSOGAWA Hirofumi return err;
143990e194eSOGAWA Hirofumi }
144990e194eSOGAWA Hirofumi
145990e194eSOGAWA Hirofumi /*
146990e194eSOGAWA Hirofumi * Compute the hash for the msdos name corresponding to the dentry.
147990e194eSOGAWA Hirofumi * Note: if the name is invalid, we leave the hash code unchanged so
148990e194eSOGAWA Hirofumi * that the existing dentry can be used. The msdos fs routines will
149990e194eSOGAWA Hirofumi * return ENOENT or EINVAL as appropriate.
150990e194eSOGAWA Hirofumi */
msdos_hash(const struct dentry * dentry,struct qstr * qstr)151da53be12SLinus Torvalds static int msdos_hash(const struct dentry *dentry, struct qstr *qstr)
152990e194eSOGAWA Hirofumi {
153990e194eSOGAWA Hirofumi struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
154990e194eSOGAWA Hirofumi unsigned char msdos_name[MSDOS_NAME];
155990e194eSOGAWA Hirofumi int error;
156990e194eSOGAWA Hirofumi
157990e194eSOGAWA Hirofumi error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
158990e194eSOGAWA Hirofumi if (!error)
1598387ff25SLinus Torvalds qstr->hash = full_name_hash(dentry, msdos_name, MSDOS_NAME);
160990e194eSOGAWA Hirofumi return 0;
161990e194eSOGAWA Hirofumi }
162990e194eSOGAWA Hirofumi
163990e194eSOGAWA Hirofumi /*
164990e194eSOGAWA Hirofumi * Compare two msdos names. If either of the names are invalid,
165990e194eSOGAWA Hirofumi * we fall back to doing the standard name comparison.
166990e194eSOGAWA Hirofumi */
msdos_cmp(const struct dentry * dentry,unsigned int len,const char * str,const struct qstr * name)1676fa67e70SAl Viro static int msdos_cmp(const struct dentry *dentry,
168621e155aSNick Piggin unsigned int len, const char *str, const struct qstr *name)
169990e194eSOGAWA Hirofumi {
170d3fe1985SAl Viro struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
171990e194eSOGAWA Hirofumi unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
172990e194eSOGAWA Hirofumi int error;
173990e194eSOGAWA Hirofumi
174621e155aSNick Piggin error = msdos_format_name(name->name, name->len, a_msdos_name, options);
175990e194eSOGAWA Hirofumi if (error)
176990e194eSOGAWA Hirofumi goto old_compare;
177621e155aSNick Piggin error = msdos_format_name(str, len, b_msdos_name, options);
178990e194eSOGAWA Hirofumi if (error)
179990e194eSOGAWA Hirofumi goto old_compare;
180990e194eSOGAWA Hirofumi error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
181990e194eSOGAWA Hirofumi out:
182990e194eSOGAWA Hirofumi return error;
183990e194eSOGAWA Hirofumi
184990e194eSOGAWA Hirofumi old_compare:
185990e194eSOGAWA Hirofumi error = 1;
186621e155aSNick Piggin if (name->len == len)
187621e155aSNick Piggin error = memcmp(name->name, str, len);
188990e194eSOGAWA Hirofumi goto out;
189990e194eSOGAWA Hirofumi }
190990e194eSOGAWA Hirofumi
191ce6cdc47SAl Viro static const struct dentry_operations msdos_dentry_operations = {
192990e194eSOGAWA Hirofumi .d_hash = msdos_hash,
193990e194eSOGAWA Hirofumi .d_compare = msdos_cmp,
194990e194eSOGAWA Hirofumi };
195990e194eSOGAWA Hirofumi
196990e194eSOGAWA Hirofumi /*
197990e194eSOGAWA Hirofumi * AV. Wrappers for FAT sb operations. Is it wise?
198990e194eSOGAWA Hirofumi */
199990e194eSOGAWA Hirofumi
200990e194eSOGAWA Hirofumi /***** Get inode using directory and name */
msdos_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)201990e194eSOGAWA Hirofumi static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
20200cd8dd3SAl Viro unsigned int flags)
203990e194eSOGAWA Hirofumi {
204990e194eSOGAWA Hirofumi struct super_block *sb = dir->i_sb;
205990e194eSOGAWA Hirofumi struct fat_slot_info sinfo;
20645cfbe35SOGAWA Hirofumi struct inode *inode;
20745cfbe35SOGAWA Hirofumi int err;
208990e194eSOGAWA Hirofumi
209e40b34c7SMarco Stornelli mutex_lock(&MSDOS_SB(sb)->s_lock);
21045cfbe35SOGAWA Hirofumi err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
211a9049376SAl Viro switch (err) {
212a9049376SAl Viro case -ENOENT:
21345cfbe35SOGAWA Hirofumi inode = NULL;
214a9049376SAl Viro break;
215a9049376SAl Viro case 0:
216990e194eSOGAWA Hirofumi inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
217990e194eSOGAWA Hirofumi brelse(sinfo.bh);
218a9049376SAl Viro break;
219a9049376SAl Viro default:
220a9049376SAl Viro inode = ERR_PTR(err);
221990e194eSOGAWA Hirofumi }
222e40b34c7SMarco Stornelli mutex_unlock(&MSDOS_SB(sb)->s_lock);
2233d23985dSAl Viro return d_splice_alias(inode, dentry);
224990e194eSOGAWA Hirofumi }
225990e194eSOGAWA Hirofumi
226990e194eSOGAWA Hirofumi /***** 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 timespec64 * ts,struct fat_slot_info * sinfo)227990e194eSOGAWA Hirofumi static int msdos_add_entry(struct inode *dir, const unsigned char *name,
228990e194eSOGAWA Hirofumi int is_dir, int is_hid, int cluster,
229f423420cSArnd Bergmann struct timespec64 *ts, struct fat_slot_info *sinfo)
230990e194eSOGAWA Hirofumi {
231990e194eSOGAWA Hirofumi struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
232990e194eSOGAWA Hirofumi struct msdos_dir_entry de;
233990e194eSOGAWA Hirofumi __le16 time, date;
234990e194eSOGAWA Hirofumi int err;
235990e194eSOGAWA Hirofumi
236990e194eSOGAWA Hirofumi memcpy(de.name, name, MSDOS_NAME);
237990e194eSOGAWA Hirofumi de.attr = is_dir ? ATTR_DIR : ATTR_ARCH;
238990e194eSOGAWA Hirofumi if (is_hid)
239990e194eSOGAWA Hirofumi de.attr |= ATTR_HIDDEN;
240990e194eSOGAWA Hirofumi de.lcase = 0;
2417decd1cbSOGAWA Hirofumi fat_time_unix2fat(sbi, ts, &time, &date, NULL);
242990e194eSOGAWA Hirofumi de.cdate = de.adate = 0;
243990e194eSOGAWA Hirofumi de.ctime = 0;
244990e194eSOGAWA Hirofumi de.ctime_cs = 0;
245990e194eSOGAWA Hirofumi de.time = time;
246990e194eSOGAWA Hirofumi de.date = date;
247a943ed71SSteven J. Magnani fat_set_start(&de, cluster);
248990e194eSOGAWA Hirofumi de.size = 0;
249990e194eSOGAWA Hirofumi
250990e194eSOGAWA Hirofumi err = fat_add_entries(dir, &de, 1, sinfo);
251990e194eSOGAWA Hirofumi if (err)
252990e194eSOGAWA Hirofumi return err;
253990e194eSOGAWA Hirofumi
254cd83f6b1SFrank Sorenson fat_truncate_time(dir, ts, S_CTIME|S_MTIME);
255990e194eSOGAWA Hirofumi if (IS_DIRSYNC(dir))
256990e194eSOGAWA Hirofumi (void)fat_sync_inode(dir);
257990e194eSOGAWA Hirofumi else
258990e194eSOGAWA Hirofumi mark_inode_dirty(dir);
259990e194eSOGAWA Hirofumi
260990e194eSOGAWA Hirofumi return 0;
261990e194eSOGAWA Hirofumi }
262990e194eSOGAWA Hirofumi
263990e194eSOGAWA Hirofumi /***** Create a file */
msdos_create(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,bool excl)2646c960e68SChristian Brauner static int msdos_create(struct mnt_idmap *idmap, struct inode *dir,
265549c7297SChristian Brauner struct dentry *dentry, umode_t mode, bool excl)
266990e194eSOGAWA Hirofumi {
267990e194eSOGAWA Hirofumi struct super_block *sb = dir->i_sb;
268990e194eSOGAWA Hirofumi struct inode *inode = NULL;
269990e194eSOGAWA Hirofumi struct fat_slot_info sinfo;
27095582b00SDeepa Dinamani struct timespec64 ts;
271990e194eSOGAWA Hirofumi unsigned char msdos_name[MSDOS_NAME];
272990e194eSOGAWA Hirofumi int err, is_hid;
273990e194eSOGAWA Hirofumi
274e40b34c7SMarco Stornelli mutex_lock(&MSDOS_SB(sb)->s_lock);
275990e194eSOGAWA Hirofumi
276990e194eSOGAWA Hirofumi err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
277990e194eSOGAWA Hirofumi msdos_name, &MSDOS_SB(sb)->options);
278990e194eSOGAWA Hirofumi if (err)
279990e194eSOGAWA Hirofumi goto out;
280990e194eSOGAWA Hirofumi is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
281990e194eSOGAWA Hirofumi /* Have to do it due to foo vs. .foo conflicts */
282990e194eSOGAWA Hirofumi if (!fat_scan(dir, msdos_name, &sinfo)) {
283990e194eSOGAWA Hirofumi brelse(sinfo.bh);
284990e194eSOGAWA Hirofumi err = -EINVAL;
285990e194eSOGAWA Hirofumi goto out;
286990e194eSOGAWA Hirofumi }
287990e194eSOGAWA Hirofumi
28802027d42SDeepa Dinamani ts = current_time(dir);
289f423420cSArnd Bergmann err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo);
290990e194eSOGAWA Hirofumi if (err)
291990e194eSOGAWA Hirofumi goto out;
292990e194eSOGAWA Hirofumi inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
293990e194eSOGAWA Hirofumi brelse(sinfo.bh);
294990e194eSOGAWA Hirofumi if (IS_ERR(inode)) {
295990e194eSOGAWA Hirofumi err = PTR_ERR(inode);
296990e194eSOGAWA Hirofumi goto out;
297990e194eSOGAWA Hirofumi }
298cd83f6b1SFrank Sorenson fat_truncate_time(inode, &ts, S_ATIME|S_CTIME|S_MTIME);
299990e194eSOGAWA Hirofumi /* timestamp is already written, so mark_inode_dirty() is unneeded. */
300990e194eSOGAWA Hirofumi
301990e194eSOGAWA Hirofumi d_instantiate(dentry, inode);
302990e194eSOGAWA Hirofumi out:
303e40b34c7SMarco Stornelli mutex_unlock(&MSDOS_SB(sb)->s_lock);
304990e194eSOGAWA Hirofumi if (!err)
305990e194eSOGAWA Hirofumi err = fat_flush_inodes(sb, dir, inode);
306990e194eSOGAWA Hirofumi return err;
307990e194eSOGAWA Hirofumi }
308990e194eSOGAWA Hirofumi
309990e194eSOGAWA Hirofumi /***** Remove a directory */
msdos_rmdir(struct inode * dir,struct dentry * dentry)310990e194eSOGAWA Hirofumi static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
311990e194eSOGAWA Hirofumi {
312990e194eSOGAWA Hirofumi struct super_block *sb = dir->i_sb;
3132b0143b5SDavid Howells struct inode *inode = d_inode(dentry);
314990e194eSOGAWA Hirofumi struct fat_slot_info sinfo;
315990e194eSOGAWA Hirofumi int err;
316990e194eSOGAWA Hirofumi
317e40b34c7SMarco Stornelli mutex_lock(&MSDOS_SB(sb)->s_lock);
318990e194eSOGAWA Hirofumi err = fat_dir_empty(inode);
319990e194eSOGAWA Hirofumi if (err)
320990e194eSOGAWA Hirofumi goto out;
321990e194eSOGAWA Hirofumi err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
322990e194eSOGAWA Hirofumi if (err)
323990e194eSOGAWA Hirofumi goto out;
324990e194eSOGAWA Hirofumi
325990e194eSOGAWA Hirofumi err = fat_remove_entries(dir, &sinfo); /* and releases bh */
326990e194eSOGAWA Hirofumi if (err)
327990e194eSOGAWA Hirofumi goto out;
328990e194eSOGAWA Hirofumi drop_nlink(dir);
329990e194eSOGAWA Hirofumi
330990e194eSOGAWA Hirofumi clear_nlink(inode);
331cd83f6b1SFrank Sorenson fat_truncate_time(inode, NULL, S_CTIME);
332990e194eSOGAWA Hirofumi fat_detach(inode);
333990e194eSOGAWA Hirofumi out:
334e40b34c7SMarco Stornelli mutex_unlock(&MSDOS_SB(sb)->s_lock);
335990e194eSOGAWA Hirofumi if (!err)
336990e194eSOGAWA Hirofumi err = fat_flush_inodes(sb, dir, inode);
337990e194eSOGAWA Hirofumi
338990e194eSOGAWA Hirofumi return err;
339990e194eSOGAWA Hirofumi }
340990e194eSOGAWA Hirofumi
341990e194eSOGAWA Hirofumi /***** Make a directory */
msdos_mkdir(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode)342c54bd91eSChristian Brauner static int msdos_mkdir(struct mnt_idmap *idmap, struct inode *dir,
343549c7297SChristian Brauner struct dentry *dentry, umode_t mode)
344990e194eSOGAWA Hirofumi {
345990e194eSOGAWA Hirofumi struct super_block *sb = dir->i_sb;
346990e194eSOGAWA Hirofumi struct fat_slot_info sinfo;
347990e194eSOGAWA Hirofumi struct inode *inode;
348990e194eSOGAWA Hirofumi unsigned char msdos_name[MSDOS_NAME];
34995582b00SDeepa Dinamani struct timespec64 ts;
350990e194eSOGAWA Hirofumi int err, is_hid, cluster;
351990e194eSOGAWA Hirofumi
352e40b34c7SMarco Stornelli mutex_lock(&MSDOS_SB(sb)->s_lock);
353990e194eSOGAWA Hirofumi
354990e194eSOGAWA Hirofumi err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,
355990e194eSOGAWA Hirofumi msdos_name, &MSDOS_SB(sb)->options);
356990e194eSOGAWA Hirofumi if (err)
357990e194eSOGAWA Hirofumi goto out;
358990e194eSOGAWA Hirofumi is_hid = (dentry->d_name.name[0] == '.') && (msdos_name[0] != '.');
359990e194eSOGAWA Hirofumi /* foo vs .foo situation */
360990e194eSOGAWA Hirofumi if (!fat_scan(dir, msdos_name, &sinfo)) {
361990e194eSOGAWA Hirofumi brelse(sinfo.bh);
362990e194eSOGAWA Hirofumi err = -EINVAL;
363990e194eSOGAWA Hirofumi goto out;
364990e194eSOGAWA Hirofumi }
365990e194eSOGAWA Hirofumi
36602027d42SDeepa Dinamani ts = current_time(dir);
367f423420cSArnd Bergmann cluster = fat_alloc_new_dir(dir, &ts);
368990e194eSOGAWA Hirofumi if (cluster < 0) {
369990e194eSOGAWA Hirofumi err = cluster;
370990e194eSOGAWA Hirofumi goto out;
371990e194eSOGAWA Hirofumi }
372f423420cSArnd Bergmann err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
373990e194eSOGAWA Hirofumi if (err)
374990e194eSOGAWA Hirofumi goto out_free;
375990e194eSOGAWA Hirofumi inc_nlink(dir);
376990e194eSOGAWA Hirofumi
377990e194eSOGAWA Hirofumi inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
378990e194eSOGAWA Hirofumi brelse(sinfo.bh);
379990e194eSOGAWA Hirofumi if (IS_ERR(inode)) {
380990e194eSOGAWA Hirofumi err = PTR_ERR(inode);
381990e194eSOGAWA Hirofumi /* the directory was completed, just return a error */
382990e194eSOGAWA Hirofumi goto out;
383990e194eSOGAWA Hirofumi }
384bfe86848SMiklos Szeredi set_nlink(inode, 2);
385cd83f6b1SFrank Sorenson fat_truncate_time(inode, &ts, S_ATIME|S_CTIME|S_MTIME);
386990e194eSOGAWA Hirofumi /* timestamp is already written, so mark_inode_dirty() is unneeded. */
387990e194eSOGAWA Hirofumi
388990e194eSOGAWA Hirofumi d_instantiate(dentry, inode);
389990e194eSOGAWA Hirofumi
390e40b34c7SMarco Stornelli mutex_unlock(&MSDOS_SB(sb)->s_lock);
391990e194eSOGAWA Hirofumi fat_flush_inodes(sb, dir, inode);
392990e194eSOGAWA Hirofumi return 0;
393990e194eSOGAWA Hirofumi
394990e194eSOGAWA Hirofumi out_free:
395990e194eSOGAWA Hirofumi fat_free_clusters(dir, cluster);
396990e194eSOGAWA Hirofumi out:
397e40b34c7SMarco Stornelli mutex_unlock(&MSDOS_SB(sb)->s_lock);
398990e194eSOGAWA Hirofumi return err;
399990e194eSOGAWA Hirofumi }
400990e194eSOGAWA Hirofumi
401990e194eSOGAWA Hirofumi /***** Unlink a file */
msdos_unlink(struct inode * dir,struct dentry * dentry)402990e194eSOGAWA Hirofumi static int msdos_unlink(struct inode *dir, struct dentry *dentry)
403990e194eSOGAWA Hirofumi {
4042b0143b5SDavid Howells struct inode *inode = d_inode(dentry);
405990e194eSOGAWA Hirofumi struct super_block *sb = inode->i_sb;
406990e194eSOGAWA Hirofumi struct fat_slot_info sinfo;
407990e194eSOGAWA Hirofumi int err;
408990e194eSOGAWA Hirofumi
409e40b34c7SMarco Stornelli mutex_lock(&MSDOS_SB(sb)->s_lock);
410990e194eSOGAWA Hirofumi err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);
411990e194eSOGAWA Hirofumi if (err)
412990e194eSOGAWA Hirofumi goto out;
413990e194eSOGAWA Hirofumi
414990e194eSOGAWA Hirofumi err = fat_remove_entries(dir, &sinfo); /* and releases bh */
415990e194eSOGAWA Hirofumi if (err)
416990e194eSOGAWA Hirofumi goto out;
417990e194eSOGAWA Hirofumi clear_nlink(inode);
418cd83f6b1SFrank Sorenson fat_truncate_time(inode, NULL, S_CTIME);
419990e194eSOGAWA Hirofumi fat_detach(inode);
420990e194eSOGAWA Hirofumi out:
421e40b34c7SMarco Stornelli mutex_unlock(&MSDOS_SB(sb)->s_lock);
422990e194eSOGAWA Hirofumi if (!err)
423990e194eSOGAWA Hirofumi err = fat_flush_inodes(sb, dir, inode);
424990e194eSOGAWA Hirofumi
425990e194eSOGAWA Hirofumi return err;
426990e194eSOGAWA Hirofumi }
427990e194eSOGAWA Hirofumi
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)428990e194eSOGAWA Hirofumi static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
429990e194eSOGAWA Hirofumi struct dentry *old_dentry,
430990e194eSOGAWA Hirofumi struct inode *new_dir, unsigned char *new_name,
431990e194eSOGAWA Hirofumi struct dentry *new_dentry, int is_hid)
432990e194eSOGAWA Hirofumi {
433990e194eSOGAWA Hirofumi struct buffer_head *dotdot_bh;
434990e194eSOGAWA Hirofumi struct msdos_dir_entry *dotdot_de;
435990e194eSOGAWA Hirofumi struct inode *old_inode, *new_inode;
436990e194eSOGAWA Hirofumi struct fat_slot_info old_sinfo, sinfo;
43795582b00SDeepa Dinamani struct timespec64 ts;
4387669e8fbSSteven J. Magnani loff_t new_i_pos;
439990e194eSOGAWA Hirofumi int err, old_attrs, is_dir, update_dotdot, corrupt = 0;
440990e194eSOGAWA Hirofumi
441990e194eSOGAWA Hirofumi old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
4422b0143b5SDavid Howells old_inode = d_inode(old_dentry);
4432b0143b5SDavid Howells new_inode = d_inode(new_dentry);
444990e194eSOGAWA Hirofumi
445990e194eSOGAWA Hirofumi err = fat_scan(old_dir, old_name, &old_sinfo);
446990e194eSOGAWA Hirofumi if (err) {
447990e194eSOGAWA Hirofumi err = -EIO;
448990e194eSOGAWA Hirofumi goto out;
449990e194eSOGAWA Hirofumi }
450990e194eSOGAWA Hirofumi
451990e194eSOGAWA Hirofumi is_dir = S_ISDIR(old_inode->i_mode);
452990e194eSOGAWA Hirofumi update_dotdot = (is_dir && old_dir != new_dir);
453990e194eSOGAWA Hirofumi if (update_dotdot) {
4547669e8fbSSteven J. Magnani if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) {
455990e194eSOGAWA Hirofumi err = -EIO;
456990e194eSOGAWA Hirofumi goto out;
457990e194eSOGAWA Hirofumi }
458990e194eSOGAWA Hirofumi }
459990e194eSOGAWA Hirofumi
460990e194eSOGAWA Hirofumi old_attrs = MSDOS_I(old_inode)->i_attrs;
461990e194eSOGAWA Hirofumi err = fat_scan(new_dir, new_name, &sinfo);
462990e194eSOGAWA Hirofumi if (!err) {
463990e194eSOGAWA Hirofumi if (!new_inode) {
464990e194eSOGAWA Hirofumi /* "foo" -> ".foo" case. just change the ATTR_HIDDEN */
465990e194eSOGAWA Hirofumi if (sinfo.de != old_sinfo.de) {
466990e194eSOGAWA Hirofumi err = -EINVAL;
467990e194eSOGAWA Hirofumi goto out;
468990e194eSOGAWA Hirofumi }
469990e194eSOGAWA Hirofumi if (is_hid)
470990e194eSOGAWA Hirofumi MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
471990e194eSOGAWA Hirofumi else
472990e194eSOGAWA Hirofumi MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
473990e194eSOGAWA Hirofumi if (IS_DIRSYNC(old_dir)) {
474990e194eSOGAWA Hirofumi err = fat_sync_inode(old_inode);
475990e194eSOGAWA Hirofumi if (err) {
476990e194eSOGAWA Hirofumi MSDOS_I(old_inode)->i_attrs = old_attrs;
477990e194eSOGAWA Hirofumi goto out;
478990e194eSOGAWA Hirofumi }
479990e194eSOGAWA Hirofumi } else
480990e194eSOGAWA Hirofumi mark_inode_dirty(old_inode);
481990e194eSOGAWA Hirofumi
4822489dbabSJeff Layton inode_inc_iversion(old_dir);
483cd83f6b1SFrank Sorenson fat_truncate_time(old_dir, NULL, S_CTIME|S_MTIME);
484990e194eSOGAWA Hirofumi if (IS_DIRSYNC(old_dir))
485990e194eSOGAWA Hirofumi (void)fat_sync_inode(old_dir);
486990e194eSOGAWA Hirofumi else
487990e194eSOGAWA Hirofumi mark_inode_dirty(old_dir);
488990e194eSOGAWA Hirofumi goto out;
489990e194eSOGAWA Hirofumi }
490990e194eSOGAWA Hirofumi }
491990e194eSOGAWA Hirofumi
49202027d42SDeepa Dinamani ts = current_time(old_inode);
493990e194eSOGAWA Hirofumi if (new_inode) {
494990e194eSOGAWA Hirofumi if (err)
495990e194eSOGAWA Hirofumi goto out;
496990e194eSOGAWA Hirofumi if (is_dir) {
497990e194eSOGAWA Hirofumi err = fat_dir_empty(new_inode);
498990e194eSOGAWA Hirofumi if (err)
499990e194eSOGAWA Hirofumi goto out;
500990e194eSOGAWA Hirofumi }
501990e194eSOGAWA Hirofumi new_i_pos = MSDOS_I(new_inode)->i_pos;
502990e194eSOGAWA Hirofumi fat_detach(new_inode);
503990e194eSOGAWA Hirofumi } else {
504990e194eSOGAWA Hirofumi err = msdos_add_entry(new_dir, new_name, is_dir, is_hid, 0,
505f423420cSArnd Bergmann &ts, &sinfo);
506990e194eSOGAWA Hirofumi if (err)
507990e194eSOGAWA Hirofumi goto out;
508990e194eSOGAWA Hirofumi new_i_pos = sinfo.i_pos;
509990e194eSOGAWA Hirofumi }
5102489dbabSJeff Layton inode_inc_iversion(new_dir);
511990e194eSOGAWA Hirofumi
512990e194eSOGAWA Hirofumi fat_detach(old_inode);
513990e194eSOGAWA Hirofumi fat_attach(old_inode, new_i_pos);
514990e194eSOGAWA Hirofumi if (is_hid)
515990e194eSOGAWA Hirofumi MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
516990e194eSOGAWA Hirofumi else
517990e194eSOGAWA Hirofumi MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
518990e194eSOGAWA Hirofumi if (IS_DIRSYNC(new_dir)) {
519990e194eSOGAWA Hirofumi err = fat_sync_inode(old_inode);
520990e194eSOGAWA Hirofumi if (err)
521990e194eSOGAWA Hirofumi goto error_inode;
522990e194eSOGAWA Hirofumi } else
523990e194eSOGAWA Hirofumi mark_inode_dirty(old_inode);
524990e194eSOGAWA Hirofumi
525990e194eSOGAWA Hirofumi if (update_dotdot) {
526a943ed71SSteven J. Magnani fat_set_start(dotdot_de, MSDOS_I(new_dir)->i_logstart);
527b522412aSAl Viro mark_buffer_dirty_inode(dotdot_bh, old_inode);
528990e194eSOGAWA Hirofumi if (IS_DIRSYNC(new_dir)) {
529990e194eSOGAWA Hirofumi err = sync_dirty_buffer(dotdot_bh);
530990e194eSOGAWA Hirofumi if (err)
531990e194eSOGAWA Hirofumi goto error_dotdot;
532990e194eSOGAWA Hirofumi }
533990e194eSOGAWA Hirofumi drop_nlink(old_dir);
534990e194eSOGAWA Hirofumi if (!new_inode)
535990e194eSOGAWA Hirofumi inc_nlink(new_dir);
536990e194eSOGAWA Hirofumi }
537990e194eSOGAWA Hirofumi
538990e194eSOGAWA Hirofumi err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
539990e194eSOGAWA Hirofumi old_sinfo.bh = NULL;
540990e194eSOGAWA Hirofumi if (err)
541990e194eSOGAWA Hirofumi goto error_dotdot;
5422489dbabSJeff Layton inode_inc_iversion(old_dir);
543cd83f6b1SFrank Sorenson fat_truncate_time(old_dir, &ts, S_CTIME|S_MTIME);
544990e194eSOGAWA Hirofumi if (IS_DIRSYNC(old_dir))
545990e194eSOGAWA Hirofumi (void)fat_sync_inode(old_dir);
546990e194eSOGAWA Hirofumi else
547990e194eSOGAWA Hirofumi mark_inode_dirty(old_dir);
548990e194eSOGAWA Hirofumi
549990e194eSOGAWA Hirofumi if (new_inode) {
550990e194eSOGAWA Hirofumi drop_nlink(new_inode);
551990e194eSOGAWA Hirofumi if (is_dir)
552990e194eSOGAWA Hirofumi drop_nlink(new_inode);
553cd83f6b1SFrank Sorenson fat_truncate_time(new_inode, &ts, S_CTIME);
554990e194eSOGAWA Hirofumi }
555990e194eSOGAWA Hirofumi out:
556990e194eSOGAWA Hirofumi brelse(sinfo.bh);
557990e194eSOGAWA Hirofumi brelse(dotdot_bh);
558990e194eSOGAWA Hirofumi brelse(old_sinfo.bh);
559990e194eSOGAWA Hirofumi return err;
560990e194eSOGAWA Hirofumi
561990e194eSOGAWA Hirofumi error_dotdot:
562990e194eSOGAWA Hirofumi /* data cluster is shared, serious corruption */
563990e194eSOGAWA Hirofumi corrupt = 1;
564990e194eSOGAWA Hirofumi
565990e194eSOGAWA Hirofumi if (update_dotdot) {
566a943ed71SSteven J. Magnani fat_set_start(dotdot_de, MSDOS_I(old_dir)->i_logstart);
567b522412aSAl Viro mark_buffer_dirty_inode(dotdot_bh, old_inode);
568990e194eSOGAWA Hirofumi corrupt |= sync_dirty_buffer(dotdot_bh);
569990e194eSOGAWA Hirofumi }
570990e194eSOGAWA Hirofumi error_inode:
571990e194eSOGAWA Hirofumi fat_detach(old_inode);
572990e194eSOGAWA Hirofumi fat_attach(old_inode, old_sinfo.i_pos);
573990e194eSOGAWA Hirofumi MSDOS_I(old_inode)->i_attrs = old_attrs;
574990e194eSOGAWA Hirofumi if (new_inode) {
575990e194eSOGAWA Hirofumi fat_attach(new_inode, new_i_pos);
576990e194eSOGAWA Hirofumi if (corrupt)
577990e194eSOGAWA Hirofumi corrupt |= fat_sync_inode(new_inode);
578990e194eSOGAWA Hirofumi } else {
579990e194eSOGAWA Hirofumi /*
580990e194eSOGAWA Hirofumi * If new entry was not sharing the data cluster, it
581990e194eSOGAWA Hirofumi * shouldn't be serious corruption.
582990e194eSOGAWA Hirofumi */
583990e194eSOGAWA Hirofumi int err2 = fat_remove_entries(new_dir, &sinfo);
584990e194eSOGAWA Hirofumi if (corrupt)
585990e194eSOGAWA Hirofumi corrupt |= err2;
586990e194eSOGAWA Hirofumi sinfo.bh = NULL;
587990e194eSOGAWA Hirofumi }
588990e194eSOGAWA Hirofumi if (corrupt < 0) {
58985c78591SDenis Karpov fat_fs_error(new_dir->i_sb,
590990e194eSOGAWA Hirofumi "%s: Filesystem corrupted (i_pos %lld)",
591990e194eSOGAWA Hirofumi __func__, sinfo.i_pos);
592990e194eSOGAWA Hirofumi }
593990e194eSOGAWA Hirofumi goto out;
594990e194eSOGAWA Hirofumi }
595990e194eSOGAWA Hirofumi
596990e194eSOGAWA Hirofumi /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
msdos_rename(struct mnt_idmap * idmap,struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)597*e18275aeSChristian Brauner static int msdos_rename(struct mnt_idmap *idmap,
598549c7297SChristian Brauner struct inode *old_dir, struct dentry *old_dentry,
599f03b8ad8SMiklos Szeredi struct inode *new_dir, struct dentry *new_dentry,
600f03b8ad8SMiklos Szeredi unsigned int flags)
601990e194eSOGAWA Hirofumi {
602990e194eSOGAWA Hirofumi struct super_block *sb = old_dir->i_sb;
603990e194eSOGAWA Hirofumi unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
604990e194eSOGAWA Hirofumi int err, is_hid;
605990e194eSOGAWA Hirofumi
606f03b8ad8SMiklos Szeredi if (flags & ~RENAME_NOREPLACE)
607f03b8ad8SMiklos Szeredi return -EINVAL;
608f03b8ad8SMiklos Szeredi
609e40b34c7SMarco Stornelli mutex_lock(&MSDOS_SB(sb)->s_lock);
610990e194eSOGAWA Hirofumi
611990e194eSOGAWA Hirofumi err = msdos_format_name(old_dentry->d_name.name,
612990e194eSOGAWA Hirofumi old_dentry->d_name.len, old_msdos_name,
613990e194eSOGAWA Hirofumi &MSDOS_SB(old_dir->i_sb)->options);
614990e194eSOGAWA Hirofumi if (err)
615990e194eSOGAWA Hirofumi goto out;
616990e194eSOGAWA Hirofumi err = msdos_format_name(new_dentry->d_name.name,
617990e194eSOGAWA Hirofumi new_dentry->d_name.len, new_msdos_name,
618990e194eSOGAWA Hirofumi &MSDOS_SB(new_dir->i_sb)->options);
619990e194eSOGAWA Hirofumi if (err)
620990e194eSOGAWA Hirofumi goto out;
621990e194eSOGAWA Hirofumi
622990e194eSOGAWA Hirofumi is_hid =
623990e194eSOGAWA Hirofumi (new_dentry->d_name.name[0] == '.') && (new_msdos_name[0] != '.');
624990e194eSOGAWA Hirofumi
625990e194eSOGAWA Hirofumi err = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
626990e194eSOGAWA Hirofumi new_dir, new_msdos_name, new_dentry, is_hid);
627990e194eSOGAWA Hirofumi out:
628e40b34c7SMarco Stornelli mutex_unlock(&MSDOS_SB(sb)->s_lock);
629990e194eSOGAWA Hirofumi if (!err)
630990e194eSOGAWA Hirofumi err = fat_flush_inodes(sb, old_dir, new_dir);
631990e194eSOGAWA Hirofumi return err;
632990e194eSOGAWA Hirofumi }
633990e194eSOGAWA Hirofumi
634990e194eSOGAWA Hirofumi static const struct inode_operations msdos_dir_inode_operations = {
635990e194eSOGAWA Hirofumi .create = msdos_create,
636990e194eSOGAWA Hirofumi .lookup = msdos_lookup,
637990e194eSOGAWA Hirofumi .unlink = msdos_unlink,
638990e194eSOGAWA Hirofumi .mkdir = msdos_mkdir,
639990e194eSOGAWA Hirofumi .rmdir = msdos_rmdir,
640990e194eSOGAWA Hirofumi .rename = msdos_rename,
641990e194eSOGAWA Hirofumi .setattr = fat_setattr,
642990e194eSOGAWA Hirofumi .getattr = fat_getattr,
6436bb885ecSFrank Sorenson .update_time = fat_update_time,
644990e194eSOGAWA Hirofumi };
645990e194eSOGAWA Hirofumi
setup(struct super_block * sb)6463d23985dSAl Viro static void setup(struct super_block *sb)
647990e194eSOGAWA Hirofumi {
648384f5c96SOGAWA Hirofumi MSDOS_SB(sb)->dir_ops = &msdos_dir_inode_operations;
6493d23985dSAl Viro sb->s_d_op = &msdos_dentry_operations;
6501751e8a6SLinus Torvalds sb->s_flags |= SB_NOATIME;
651db719222SJan Blunck }
652990e194eSOGAWA Hirofumi
msdos_fill_super(struct super_block * sb,void * data,int silent)6533d23985dSAl Viro static int msdos_fill_super(struct super_block *sb, void *data, int silent)
6543d23985dSAl Viro {
655384f5c96SOGAWA Hirofumi return fat_fill_super(sb, data, silent, 0, setup);
656990e194eSOGAWA Hirofumi }
657990e194eSOGAWA Hirofumi
msdos_mount(struct file_system_type * fs_type,int flags,const char * dev_name,void * data)658152a0836SAl Viro static struct dentry *msdos_mount(struct file_system_type *fs_type,
659990e194eSOGAWA Hirofumi int flags, const char *dev_name,
660152a0836SAl Viro void *data)
661990e194eSOGAWA Hirofumi {
662152a0836SAl Viro return mount_bdev(fs_type, flags, dev_name, data, msdos_fill_super);
663990e194eSOGAWA Hirofumi }
664990e194eSOGAWA Hirofumi
665990e194eSOGAWA Hirofumi static struct file_system_type msdos_fs_type = {
666990e194eSOGAWA Hirofumi .owner = THIS_MODULE,
667990e194eSOGAWA Hirofumi .name = "msdos",
668152a0836SAl Viro .mount = msdos_mount,
669990e194eSOGAWA Hirofumi .kill_sb = kill_block_super,
6704b789936SChristian Brauner .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
671990e194eSOGAWA Hirofumi };
6727f78e035SEric W. Biederman MODULE_ALIAS_FS("msdos");
673990e194eSOGAWA Hirofumi
init_msdos_fs(void)674990e194eSOGAWA Hirofumi static int __init init_msdos_fs(void)
675990e194eSOGAWA Hirofumi {
676990e194eSOGAWA Hirofumi return register_filesystem(&msdos_fs_type);
677990e194eSOGAWA Hirofumi }
678990e194eSOGAWA Hirofumi
exit_msdos_fs(void)679990e194eSOGAWA Hirofumi static void __exit exit_msdos_fs(void)
680990e194eSOGAWA Hirofumi {
681990e194eSOGAWA Hirofumi unregister_filesystem(&msdos_fs_type);
682990e194eSOGAWA Hirofumi }
683990e194eSOGAWA Hirofumi
684990e194eSOGAWA Hirofumi MODULE_LICENSE("GPL");
685990e194eSOGAWA Hirofumi MODULE_AUTHOR("Werner Almesberger");
686990e194eSOGAWA Hirofumi MODULE_DESCRIPTION("MS-DOS filesystem support");
687990e194eSOGAWA Hirofumi
688990e194eSOGAWA Hirofumi module_init(init_msdos_fs)
689990e194eSOGAWA Hirofumi module_exit(exit_msdos_fs)
690