1 /*
2 * linux/fs/fat/dir.c
3 *
4 * directory handling functions for fat-based filesystems
5 *
6 * Written 1992,1993 by Werner Almesberger
7 *
8 * Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
9 *
10 * VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
11 * Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
12 * Rewritten for constant inumbers. Plugged buffer overrun in readdir(). AV
13 * Short name translation 1999 by Wolfram Pienkoss <wp@bszh.de>
14 */
15
16 #define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
17
18 #include <linux/version.h>
19 #include <linux/fs.h>
20 #include <linux/msdos_fs.h>
21 #include <linux/nls.h>
22 #include <linux/kernel.h>
23 #include <linux/errno.h>
24 #include <linux/stat.h>
25 #include <linux/string.h>
26 #include <linux/ioctl.h>
27 #include <linux/dirent.h>
28 #include <linux/mm.h>
29 #include <linux/ctype.h>
30
31 #include <asm/uaccess.h>
32
33 #include "msbuffer.h"
34
35 #define PRINTK(X)
36
37 struct file_operations fat_dir_operations = {
38 read: generic_read_dir,
39 readdir: fat_readdir,
40 ioctl: fat_dir_ioctl,
41 fsync: file_fsync,
42 };
43
44 /*
45 * Convert Unicode 16 to UTF8, translated Unicode, or ASCII.
46 * If uni_xlate is enabled and we can't get a 1:1 conversion, use a
47 * colon as an escape character since it is normally invalid on the vfat
48 * filesystem. The following four characters are the hexadecimal digits
49 * of Unicode value. This lets us do a full dump and restore of Unicode
50 * filenames. We could get into some trouble with long Unicode names,
51 * but ignore that right now.
52 * Ahem... Stack smashing in ring 0 isn't fun. Fixed.
53 */
54 static int
55 uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate,
56 struct nls_table *nls)
57 {
58 wchar_t *ip, ec;
59 unsigned char *op, nc;
60 int charlen;
61 int k;
62
63 ip = uni;
64 op = ascii;
65
66 while (*ip) {
67 ec = *ip++;
68 if ( (charlen = nls->uni2char(ec, op, 3)) > 0) {
69 op += charlen;
70 } else {
71 if (uni_xlate == 1) {
72 *op = ':';
73 for (k = 4; k > 0; k--) {
74 nc = ec & 0xF;
75 op[k] = nc > 9 ? nc + ('a' - 10)
76 : nc + '';
77 ec >>= 4;
78 }
79 op += 5;
80 } else {
81 *op++ = '?';
82 }
83 }
84 /* We have some slack there, so it's OK */
85 if (op>ascii+256) {
86 op = ascii + 256;
87 break;
88 }
89 }
90 *op = 0;
91 return (op - ascii);
92 }
93
94 #if 0
95 static void dump_de(struct msdos_dir_entry *de)
96 {
97 int i;
98 unsigned char *p = (unsigned char *) de;
99 printk("[");
100
101 for (i = 0; i < 32; i++, p++) {
102 printk("%02x ", *p);
103 }
104 printk("]\n");
105 }
106 #endif
107
108 static inline unsigned char
109 fat_tolower(struct nls_table *t, unsigned char c)
110 {
111 unsigned char nc = t->charset2lower[c];
112
113 return nc ? nc : c;
114 }
115
116 static inline int
117 fat_short2lower_uni(struct nls_table *t, unsigned char c, wchar_t *uni)
118 {
119 int charlen;
120 unsigned char nc = t->charset2lower[c];
121
122 if (!nc)
123 nc = c;
124
125 if ( (charlen = t->char2uni(&nc, 1, uni)) < 0) {
126 *uni = 0x003f; /* a question mark */
127 }
128 return charlen;
129 }
130
131 static int
132 fat_strnicmp(struct nls_table *t, const unsigned char *s1,
133 const unsigned char *s2, int len)
134 {
135 while(len--)
136 if (fat_tolower(t, *s1++) != fat_tolower(t, *s2++))
137 return 1;
138
139 return 0;
140 }
141
142 /*
143 * Return values: negative -> error, 0 -> not found, positive -> found,
144 * value is the total amount of slots, including the shortname entry.
145 */
146 int fat_search_long(struct inode *inode, const char *name, int name_len,
147 int anycase, loff_t *spos, loff_t *lpos)
148 {
149 struct super_block *sb = inode->i_sb;
150 struct buffer_head *bh = NULL;
151 struct msdos_dir_entry *de;
152 struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
153 struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
154 wchar_t bufuname[14];
155 unsigned char xlate_len, long_slots, *unicode = NULL;
156 char c, bufname[260]; /* 256 + 4 */
157 int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
158 int utf8 = MSDOS_SB(sb)->options.utf8;
159 int ino, i, i2, last, res = 0;
160 loff_t cpos = 0;
161
162 while(1) {
163 if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
164 goto EODir;
165 parse_record:
166 long_slots = 0;
167 if (de->name[0] == (__s8) DELETED_FLAG)
168 continue;
169 if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
170 continue;
171 if (de->attr != ATTR_EXT && IS_FREE(de->name))
172 continue;
173 if (de->attr == ATTR_EXT) {
174 struct msdos_dir_slot *ds;
175 int offset;
176 unsigned char id;
177 unsigned char slot;
178 unsigned char slots;
179 unsigned char sum;
180 unsigned char alias_checksum;
181
182 if (!unicode) {
183 unicode = (unsigned char *)
184 __get_free_page(GFP_KERNEL);
185 if (!unicode) {
186 fat_brelse(sb, bh);
187 return -ENOMEM;
188 }
189 }
190 parse_long:
191 slots = 0;
192 offset = 0;
193 ds = (struct msdos_dir_slot *) de;
194 id = ds->id;
195 if (!(id & 0x40))
196 continue;
197 slots = id & ~0x40;
198 if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
199 continue;
200 long_slots = slots;
201 alias_checksum = ds->alias_checksum;
202
203 slot = slots;
204 while (1) {
205 slot--;
206 offset = slot * 26;
207 memcpy(&unicode[offset], ds->name0_4, 10);
208 memcpy(&unicode[offset+10], ds->name5_10, 12);
209 memcpy(&unicode[offset+22], ds->name11_12, 4);
210 offset += 26;
211
212 if (ds->id & 0x40) {
213 unicode[offset] = 0;
214 unicode[offset+1] = 0;
215 }
216 if (fat_get_entry(inode,&cpos,&bh,&de,&ino)<0)
217 goto EODir;
218 if (slot == 0)
219 break;
220 ds = (struct msdos_dir_slot *) de;
221 if (ds->attr != ATTR_EXT)
222 goto parse_record;
223 if ((ds->id & ~0x40) != slot)
224 goto parse_long;
225 if (ds->alias_checksum != alias_checksum)
226 goto parse_long;
227 }
228 if (de->name[0] == (__s8) DELETED_FLAG)
229 continue;
230 if (de->attr == ATTR_EXT)
231 goto parse_long;
232 if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
233 continue;
234 for (sum = 0, i = 0; i < 11; i++)
235 sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
236 if (sum != alias_checksum)
237 long_slots = 0;
238 }
239
240 for (i = 0, last = 0; i < 8;) {
241 if (!(c = de->name[i])) break;
242 if (c == 0x05) c = 0xE5;
243 fat_short2lower_uni(nls_disk, c, &bufuname[i++]);
244 if (c != ' ')
245 last = i;
246 }
247 i = last;
248 fat_short2lower_uni(nls_disk, '.', &bufuname[i++]);
249 for (i2 = 0; i2 < 3; i2++) {
250 if (!(c = de->ext[i2])) break;
251 fat_short2lower_uni(nls_disk, c, &bufuname[i++]);
252 if (c != ' ')
253 last = i;
254 }
255 if (!last)
256 continue;
257
258 memset(&bufuname[last], 0, sizeof(wchar_t));
259 xlate_len = utf8
260 ?utf8_wcstombs(bufname, bufuname, 260)
261 :uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
262 if (xlate_len == name_len)
263 if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
264 (anycase && !fat_strnicmp(nls_io, name, bufname,
265 xlate_len)))
266 goto Found;
267
268 if (long_slots) {
269 xlate_len = utf8
270 ?utf8_wcstombs(bufname, (wchar_t *) unicode, 260)
271 :uni16_to_x8(bufname, (wchar_t *) unicode, uni_xlate, nls_io);
272 if (xlate_len != name_len)
273 continue;
274 if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
275 (anycase && !fat_strnicmp(nls_io, name, bufname,
276 xlate_len)))
277 goto Found;
278 }
279 }
280
281 Found:
282 res = long_slots + 1;
283 *spos = cpos - sizeof(struct msdos_dir_entry);
284 *lpos = cpos - res*sizeof(struct msdos_dir_entry);
285 EODir:
286 fat_brelse(sb, bh);
287 if (unicode) {
288 free_page((unsigned long) unicode);
289 }
290 return res;
291 }
292
293 static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,
294 filldir_t filldir, int shortnames, int both)
295 {
296 struct super_block *sb = inode->i_sb;
297 struct buffer_head *bh;
298 struct msdos_dir_entry *de;
299 struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
300 struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
301 wchar_t bufuname[14], *ptuname = &bufuname[0];
302 unsigned char long_slots, *unicode = NULL;
303 char c, bufname[56], *ptname = bufname;
304 unsigned long lpos, dummy, *furrfu = &lpos;
305 int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
306 int isvfat = MSDOS_SB(sb)->options.isvfat;
307 int utf8 = MSDOS_SB(sb)->options.utf8;
308 int nocase = MSDOS_SB(sb)->options.nocase;
309 int ino,inum,i,i2,last, dotoffset = 0;
310 loff_t cpos;
311
312 cpos = filp->f_pos;
313 /* Fake . and .. for the root directory. */
314 if (inode->i_ino == MSDOS_ROOT_INO) {
315 while (cpos < 2) {
316 if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO, DT_DIR) < 0)
317 return 0;
318 cpos++;
319 filp->f_pos++;
320 }
321 if (cpos == 2) {
322 dummy = 2;
323 furrfu = &dummy;
324 cpos = 0;
325 }
326 }
327 if (cpos & (sizeof(struct msdos_dir_entry)-1))
328 return -ENOENT;
329
330 bh = NULL;
331 GetNew:
332 long_slots = 0;
333 if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
334 goto EODir;
335 /* Check for long filename entry */
336 if (isvfat) {
337 if (de->name[0] == (__s8) DELETED_FLAG)
338 goto RecEnd;
339 if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
340 goto RecEnd;
341 if (de->attr != ATTR_EXT && IS_FREE(de->name))
342 goto RecEnd;
343 } else {
344 if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name))
345 goto RecEnd;
346 }
347
348 if (isvfat && de->attr == ATTR_EXT) {
349 struct msdos_dir_slot *ds;
350 int offset;
351 unsigned char id;
352 unsigned char slot;
353 unsigned char slots;
354 unsigned char sum;
355 unsigned char alias_checksum;
356
357 if (!unicode) {
358 unicode = (unsigned char *)
359 __get_free_page(GFP_KERNEL);
360 if (!unicode) {
361 filp->f_pos = cpos;
362 fat_brelse(sb, bh);
363 return -ENOMEM;
364 }
365 }
366 ParseLong:
367 slots = 0;
368 offset = 0;
369 ds = (struct msdos_dir_slot *) de;
370 id = ds->id;
371 if (!(id & 0x40))
372 goto RecEnd;
373 slots = id & ~0x40;
374 if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
375 goto RecEnd;
376 long_slots = slots;
377 alias_checksum = ds->alias_checksum;
378
379 slot = slots;
380 while (1) {
381 slot--;
382 offset = slot * 26;
383 memcpy(&unicode[offset], ds->name0_4, 10);
384 memcpy(&unicode[offset+10], ds->name5_10, 12);
385 memcpy(&unicode[offset+22], ds->name11_12, 4);
386 offset += 26;
387
388 if (ds->id & 0x40) {
389 unicode[offset] = 0;
390 unicode[offset+1] = 0;
391 }
392 if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
393 goto EODir;
394 if (slot == 0)
395 break;
396 ds = (struct msdos_dir_slot *) de;
397 if (ds->attr != ATTR_EXT)
398 goto RecEnd; /* XXX */
399 if ((ds->id & ~0x40) != slot)
400 goto ParseLong;
401 if (ds->alias_checksum != alias_checksum)
402 goto ParseLong;
403 }
404 if (de->name[0] == (__s8) DELETED_FLAG)
405 goto RecEnd;
406 if (de->attr == ATTR_EXT)
407 goto ParseLong;
408 if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
409 goto RecEnd;
410 for (sum = 0, i = 0; i < 11; i++)
411 sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
412 if (sum != alias_checksum)
413 long_slots = 0;
414 }
415
416 if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
417 fat_short2lower_uni(nls_disk, '.', ptuname);
418 *ptname++ = '.';
419 dotoffset = 1;
420 }
421 for (i = 0, last = 0; i < 8;) {
422 if (!(c = de->name[i])) break;
423 /* see namei.c, msdos_format_name */
424 if (c == 0x05) c = 0xE5;
425 fat_short2lower_uni(nls_disk, c, &ptuname[i]);
426 ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
427 if (c != ' ')
428 last = i;
429 }
430 i = last;
431 fat_short2lower_uni(nls_disk, '.', &ptuname[i]);
432 ptname[i++] = '.';
433 for (i2 = 0; i2 < 3; i2++) {
434 if (!(c = de->ext[i2])) break;
435 fat_short2lower_uni(nls_disk, c, &ptuname[i]);
436 ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
437 if (c != ' ')
438 last = i;
439 }
440 if (!last)
441 goto RecEnd;
442
443 i = last + dotoffset;
444
445 lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry);
446 if (!memcmp(de->name,MSDOS_DOT,11))
447 inum = inode->i_ino;
448 else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
449 /* inum = fat_parent_ino(inode,0); */
450 inum = filp->f_dentry->d_parent->d_inode->i_ino;
451 } else {
452 struct inode *tmp = fat_iget(sb, ino);
453 if (tmp) {
454 inum = tmp->i_ino;
455 iput(tmp);
456 } else
457 inum = iunique(sb, MSDOS_ROOT_INO);
458 }
459
460 if (isvfat) {
461 memset(&bufuname[i], 0, sizeof(wchar_t));
462 i = utf8 ? utf8_wcstombs(bufname, bufuname, 56)
463 : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
464 }
465
466 if (!long_slots||shortnames) {
467 if (both)
468 bufname[i] = '\0';
469 if (filldir(dirent, bufname, i, *furrfu, inum,
470 (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)
471 goto FillFailed;
472 } else {
473 char longname[275];
474 unsigned char long_len = utf8
475 ? utf8_wcstombs(longname, (wchar_t *) unicode, 275)
476 : uni16_to_x8(longname, (wchar_t *) unicode, uni_xlate,
477 nls_io);
478 if (both) {
479 memcpy(&longname[long_len+1], bufname, i);
480 long_len += i;
481 }
482 if (filldir(dirent, longname, long_len, *furrfu, inum,
483 (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)
484 goto FillFailed;
485 }
486
487 RecEnd:
488 furrfu = &lpos;
489 filp->f_pos = cpos;
490 goto GetNew;
491 EODir:
492 filp->f_pos = cpos;
493 FillFailed:
494 if (bh)
495 fat_brelse(sb, bh);
496 if (unicode) {
497 free_page((unsigned long) unicode);
498 }
499 return 0;
500 }
501
502 int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
503 {
504 struct inode *inode = filp->f_dentry->d_inode;
505 return fat_readdirx(inode, filp, dirent, filldir, 0, 0);
506 }
507
508 static int vfat_ioctl_fill(
509 void * buf,
510 const char * name,
511 int name_len,
512 off_t offset,
513 ino_t ino,
514 unsigned int d_type)
515 {
516 struct dirent *d1 = (struct dirent *)buf;
517 struct dirent *d2 = d1 + 1;
518 int len, slen;
519 int dotdir;
520
521 get_user(len, &d1->d_reclen);
522 if (len != 0) {
523 return -1;
524 }
525
526 if ((name_len == 1 && name[0] == '.') ||
527 (name_len == 2 && name[0] == '.' && name[1] == '.')) {
528 dotdir = 1;
529 len = name_len;
530 } else {
531 dotdir = 0;
532 len = strlen(name);
533 }
534 if (len != name_len) {
535 copy_to_user(d2->d_name, name, len);
536 put_user(0, d2->d_name + len);
537 put_user(len, &d2->d_reclen);
538 put_user(ino, &d2->d_ino);
539 put_user(offset, &d2->d_off);
540 slen = name_len - len;
541 copy_to_user(d1->d_name, name+len+1, slen);
542 put_user(0, d1->d_name+slen);
543 put_user(slen, &d1->d_reclen);
544 } else {
545 put_user(0, d2->d_name);
546 put_user(0, &d2->d_reclen);
547 copy_to_user(d1->d_name, name, len);
548 put_user(0, d1->d_name+len);
549 put_user(len, &d1->d_reclen);
550 }
551 PRINTK(("FAT d1=%p d2=%p len=%d, name_len=%d\n",
552 d1, d2, len, name_len));
553
554 return 0;
555 }
556
557 int fat_dir_ioctl(struct inode * inode, struct file * filp,
558 unsigned int cmd, unsigned long arg)
559 {
560 int err;
561 /*
562 * We want to provide an interface for Samba to be able
563 * to get the short filename for a given long filename.
564 * Samba should use this ioctl instead of readdir() to
565 * get the information it needs.
566 */
567 switch (cmd) {
568 case VFAT_IOCTL_READDIR_BOTH: {
569 struct dirent *d1 = (struct dirent *)arg;
570 err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
571 if (err)
572 return err;
573 put_user(0, &d1->d_reclen);
574 return fat_readdirx(inode,filp,(void *)arg,
575 vfat_ioctl_fill, 0, 1);
576 }
577 case VFAT_IOCTL_READDIR_SHORT: {
578 struct dirent *d1 = (struct dirent *)arg;
579 put_user(0, &d1->d_reclen);
580 err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
581 if (err)
582 return err;
583 return fat_readdirx(inode,filp,(void *)arg,
584 vfat_ioctl_fill, 1, 1);
585 }
586 default:
587 /* forward ioctl to CVF extension */
588 if (MSDOS_SB(inode->i_sb)->cvf_format &&
589 MSDOS_SB(inode->i_sb)->cvf_format->cvf_dir_ioctl)
590 return MSDOS_SB(inode->i_sb)->cvf_format
591 ->cvf_dir_ioctl(inode,filp,cmd,arg);
592 return -EINVAL;
593 }
594
595 return 0;
596 }
597
598 /***** See if directory is empty */
599 int fat_dir_empty(struct inode *dir)
600 {
601 loff_t pos;
602 struct buffer_head *bh;
603 struct msdos_dir_entry *de;
604 int ino,result = 0;
605
606 pos = 0;
607 bh = NULL;
608 while (fat_get_entry(dir,&pos,&bh,&de,&ino) > -1) {
609 /* Ignore vfat longname entries */
610 if (de->attr == ATTR_EXT)
611 continue;
612 if (!IS_FREE(de->name) &&
613 strncmp(de->name,MSDOS_DOT , MSDOS_NAME) &&
614 strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) {
615 result = -ENOTEMPTY;
616 break;
617 }
618 }
619 if (bh)
620 fat_brelse(dir->i_sb, bh);
621
622 return result;
623 }
624
625 /* This assumes that size of cluster is above the 32*slots */
626
627 int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
628 struct msdos_dir_entry **de, int *ino)
629 {
630 struct super_block *sb = dir->i_sb;
631 loff_t offset, curr;
632 int row;
633 struct buffer_head *new_bh;
634
635 offset = curr = 0;
636 *bh = NULL;
637 row = 0;
638 while (fat_get_entry(dir,&curr,bh,de,ino) > -1) {
639 if (IS_FREE((*de)->name)) {
640 if (++row == slots)
641 return offset;
642 } else {
643 row = 0;
644 offset = curr;
645 }
646 }
647 if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32))
648 return -ENOSPC;
649 new_bh = fat_extend_dir(dir);
650 if (!new_bh)
651 return -ENOSPC;
652 fat_brelse(sb, new_bh);
653 do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots);
654 return offset;
655 }
656
657 int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
658 {
659 struct super_block *sb = dir->i_sb;
660 struct buffer_head *bh;
661 struct msdos_dir_entry *de;
662 __u16 date, time;
663
664 if ((bh = fat_extend_dir(dir)) == NULL) return -ENOSPC;
665 /* zeroed out, so... */
666 fat_date_unix2dos(dir->i_mtime,&time,&date);
667 de = (struct msdos_dir_entry*)&bh->b_data[0];
668 memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
669 memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
670 de[0].attr = de[1].attr = ATTR_DIR;
671 de[0].time = de[1].time = CT_LE_W(time);
672 de[0].date = de[1].date = CT_LE_W(date);
673 if (is_vfat) { /* extra timestamps */
674 de[0].ctime = de[1].ctime = CT_LE_W(time);
675 de[0].adate = de[0].cdate =
676 de[1].adate = de[1].cdate = CT_LE_W(date);
677 }
678 de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart);
679 de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);
680 de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);
681 de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);
682 fat_mark_buffer_dirty(sb, bh);
683 fat_brelse(sb, bh);
684 dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
685 mark_inode_dirty(dir);
686
687 return 0;
688 }
689
690 /*
691 * Overrides for Emacs so that we follow Linus's tabbing style.
692 * Emacs will notice this stuff at the end of the file and automatically
693 * adjust the settings for this buffer only. This must remain at the end
694 * of the file.
695 * ---------------------------------------------------------------------------
696 * Local variables:
697 * c-indent-level: 8
698 * c-brace-imaginary-offset: 0
699 * c-brace-offset: -8
700 * c-argdecl-indent: 8
701 * c-label-offset: -8
702 * c-continued-statement-offset: 8
703 * c-continued-brace-offset: 0
704 * End:
705 */
706
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.