~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/fat/dir.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.