root/fs/fat/dir.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fat_dir_read
  2. fat_readdirx
  3. fat_readdir
  4. vfat_ioctl_fill
  5. fat_dir_ioctl

   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, merged with msdos fs by Henrik Storner
  11  */
  12 
  13 #include <linux/fs.h>
  14 #include <linux/msdos_fs.h>
  15 #include <linux/kernel.h>
  16 #include <linux/errno.h>
  17 #include <linux/stat.h>
  18 #include <linux/string.h>
  19 #include <linux/ioctl.h>
  20 #include <linux/dirent.h>
  21 
  22 #include <asm/segment.h>
  23 
  24 #include "msbuffer.h"
  25 #include "tables.h"
  26 
  27 
  28 #define PRINTK(X)
  29 
  30 static int fat_dir_read(struct inode * inode,struct file * filp, char * buf,int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  31 {
  32         return -EISDIR;
  33 }
  34 
  35 struct file_operations fat_dir_operations = {
  36         NULL,                   /* lseek - default */
  37         fat_dir_read,           /* read */
  38         NULL,                   /* write - bad */
  39         fat_readdir,            /* readdir */
  40         NULL,                   /* select - default */
  41         fat_dir_ioctl,          /* ioctl - default */
  42         NULL,                   /* mmap */
  43         NULL,                   /* no special open code */
  44         NULL,                   /* no special release code */
  45         file_fsync              /* fsync */
  46 };
  47 
  48 int fat_readdirx(
     /* [previous][next][first][last][top][bottom][index][help] */
  49         struct inode *inode,
  50         struct file *filp,
  51         void *dirent,
  52         filldir_t filldir,
  53         int both)
  54 {
  55         struct super_block *sb = inode->i_sb;
  56         int ino,i,i2,last;
  57         char c;
  58         struct buffer_head *bh;
  59         struct msdos_dir_entry *de;
  60         unsigned long oldpos = filp->f_pos;
  61         int is_long;
  62         char longname[275];
  63         unsigned char long_len = 0; /* Make compiler warning go away */
  64         unsigned char alias_checksum = 0; /* Make compiler warning go away */
  65 
  66 
  67         if (!inode || !S_ISDIR(inode->i_mode))
  68                 return -EBADF;
  69 /* Fake . and .. for the root directory. */
  70         if (inode->i_ino == MSDOS_ROOT_INO) {
  71                 while (oldpos < 2) {
  72                         if (filldir(dirent, "..", oldpos+1, oldpos, MSDOS_ROOT_INO) < 0)
  73                                 return 0;
  74                         oldpos++;
  75                         filp->f_pos++;
  76                 }
  77                 if (oldpos == 2)
  78                         filp->f_pos = 0;
  79         }
  80         if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1))
  81                 return -ENOENT;
  82 
  83         bh = NULL;
  84         longname[0] = '\0';
  85         is_long = 0;
  86         ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
  87         while (ino > -1) {
  88                 /* Should we warn about finding extended entries on fs
  89                  * mounted non-vfat ? Deleting or renaming files will cause
  90                  * corruption, as extended entries are not updated.
  91                  */
  92                 if (!MSDOS_SB(sb)->vfat && 
  93                     !MSDOS_SB(sb)->umsdos &&  /* umsdos is safe for us */
  94                     !IS_RDONLY(inode) && 
  95                     (de->attr == ATTR_EXT) &&
  96                     !MSDOS_SB(sb)->quiet) {
  97                         printk("MSDOS-fs warning: vfat directory entry found on fs mounted non-vfat (device %s)\n",
  98                                kdevname(sb->s_dev));
  99                 }
 100 
 101                 /* Check for long filename entry */
 102                 if (MSDOS_SB(sb)->vfat && (de->name[0] == (__s8) DELETED_FLAG)) {
 103                         is_long = 0;
 104                         oldpos = filp->f_pos;
 105                 } else if (MSDOS_SB(sb)->vfat && de->attr ==  ATTR_EXT) {
 106                         int get_new_entry;
 107                         struct msdos_dir_slot *ds;
 108                         unsigned char page, pg_off, ascii;
 109                         unsigned char *uni_page;
 110                         unsigned char offset;
 111                         unsigned char id;
 112                         unsigned char slot;
 113                         unsigned char slots = 0;
 114                         int i;
 115 
 116                         offset = 0;
 117                         ds = (struct msdos_dir_slot *) de;
 118                         id = ds->id;
 119                         if (id & 0x40) {
 120                                 slots = id & ~0x40;
 121                                 is_long = 1;
 122                                 alias_checksum = ds->alias_checksum;
 123                         }
 124 
 125                         get_new_entry = 1;
 126                         slot = slots;
 127                         while (slot > 0) {
 128                                 PRINTK(("1. get_new_entry: %d\n", get_new_entry));
 129                                 if (ds->attr !=  ATTR_EXT) {
 130                                         is_long = 0;
 131                                         get_new_entry = 0;
 132                                         break;
 133                                 }
 134                                 if ((ds->id & ~0x40) != slot) {
 135                                         is_long = 0;
 136                                         break;
 137                                 }
 138                                 if (ds->alias_checksum != alias_checksum) {
 139                                         is_long = 0;
 140                                         break;
 141                                 }
 142                                 slot--;
 143                                 offset = slot * 13;
 144                                 PRINTK(("2. get_new_entry: %d\n", get_new_entry));
 145                                 for (i = 0; i < 10; i += 2) {
 146                                         pg_off = ds->name0_4[i];
 147                                         page = ds->name0_4[i+1];
 148                                         if (pg_off == 0 && page == 0) {
 149                                                 goto found_end;
 150                                         }
 151                                         uni_page = fat_uni2asc_pg[page];
 152                                         ascii = uni_page[pg_off];
 153                                         longname[offset++] = ascii ? ascii : '?';
 154                                 }
 155                                 for (i = 0; i < 12; i += 2) {
 156                                         pg_off = ds->name5_10[i];
 157                                         page = ds->name5_10[i+1];
 158                                         if (pg_off == 0 && page == 0) {
 159                                                 goto found_end;
 160                                         }
 161                                         uni_page = fat_uni2asc_pg[page];
 162                                         ascii = uni_page[pg_off];
 163                                         longname[offset++] = ascii ? ascii : '?';
 164                                 }
 165                                 for (i = 0; i < 4; i += 2) {
 166                                         pg_off = ds->name11_12[i];
 167                                         page = ds->name11_12[i+1];
 168                                         if (pg_off == 0 && page == 0) {
 169                                                 goto found_end;
 170                                         }
 171                                         uni_page = fat_uni2asc_pg[page];
 172                                         ascii = uni_page[pg_off];
 173                                         longname[offset++] = ascii ? ascii : '?';
 174                                 }
 175                                 found_end:
 176                                 PRINTK(("3. get_new_entry: %d\n", get_new_entry));
 177                                 if (ds->id & 0x40) {
 178                                         longname[offset] = '\0';
 179                                         long_len = offset;
 180                                 }
 181                                 if (slot > 0) {
 182                                         ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
 183                                         PRINTK(("4. get_new_entry: %d\n", get_new_entry));
 184                                         if (ino == -1) {
 185                                                 is_long = 0;
 186                                                 get_new_entry = 0;
 187                                                 break;
 188                                         }
 189                                         ds = (struct msdos_dir_slot *) de;
 190                                 }
 191                                 PRINTK(("5. get_new_entry: %d\n", get_new_entry));
 192                         }
 193                         PRINTK(("Long filename: %s, get_new_entry: %d\n", longname, get_new_entry));
 194                 } else if (!IS_FREE(de->name) && !(de->attr & ATTR_VOLUME)) {
 195                         char bufname[14];
 196                         char *ptname = bufname;
 197                         int dotoffset = 0;
 198 
 199                         if (is_long) {
 200                                 unsigned char sum;
 201 
 202                                 for (sum = i = 0; i < 11; i++) {
 203                                         sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
 204                                 }
 205 
 206                                 if (sum != alias_checksum) {
 207                                         PRINTK(("Checksums don't match %d != %d\n", sum, alias_checksum));
 208                                         is_long = 0;
 209                                 }
 210                         }
 211 
 212                         if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->dotsOK) {
 213                                 bufname[0] = '.';
 214                                 dotoffset = 1;
 215                                 ptname = bufname+1;
 216                         }
 217                         for (i = last = 0; i < 8; i++) {
 218                                 if (!(c = de->name[i])) break;
 219                                 if (c >= 'A' && c <= 'Z') c += 32;
 220                                 /* see namei.c, msdos_format_name */
 221                                 if (c == 0x05) c = 0xE5;
 222                                 if (c != ' ')
 223                                         last = i+1;
 224                                 ptname[i] = c;
 225                         }
 226                         i = last;
 227                         ptname[i] = '.';
 228                         i++;
 229                         for (i2 = 0; i2 < 3; i2++) {
 230                                 if (!(c = de->ext[i2])) break;
 231                                 if (c >= 'A' && c <= 'Z') c += 32;
 232                                 if (c != ' ')
 233                                         last = i+1;
 234                                 ptname[i] = c;
 235                                 i++;
 236                         }
 237                         if ((i = last) != 0) {
 238                                 if (!strcmp(de->name,MSDOS_DOT))
 239                                         ino = inode->i_ino;
 240                                 else if (!strcmp(de->name,MSDOS_DOTDOT))
 241                                         ino = fat_parent_ino(inode,0);
 242 
 243                                 if (!is_long) {
 244                                         dcache_add(inode, bufname, i+dotoffset, ino);
 245                                         if (both) {
 246                                                 bufname[i+dotoffset] = '\0';
 247                                         }
 248                                         if (filldir(dirent, bufname, i+dotoffset, oldpos, ino) < 0) {
 249                                                 filp->f_pos = oldpos;
 250                                                 break;
 251                                         }
 252                                 } else {
 253                                         dcache_add(inode, longname, long_len, ino);
 254                                         if (both) {
 255                                                 memcpy(&longname[long_len+1], bufname, i+dotoffset);
 256                                                 long_len += i+dotoffset;
 257                                         }
 258                                         if (filldir(dirent, longname, long_len, oldpos, ino) < 0) {
 259                                                 filp->f_pos = oldpos;
 260                                                 break;
 261                                         }
 262                                 }
 263                                 oldpos = filp->f_pos;
 264                         }
 265                         is_long = 0;
 266                 } else {
 267                         is_long = 0;
 268                         oldpos = filp->f_pos;
 269                 }
 270                 ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);        
 271         }
 272         if (bh) brelse(bh);
 273         return 0;
 274 }
 275 
 276 int fat_readdir(
     /* [previous][next][first][last][top][bottom][index][help] */
 277         struct inode *inode,
 278         struct file *filp,
 279         void *dirent,
 280         filldir_t filldir)
 281 {
 282     return fat_readdirx(inode, filp, dirent, filldir, 0);
 283 }
 284 static int vfat_ioctl_fill(
     /* [previous][next][first][last][top][bottom][index][help] */
 285         void * buf,
 286         const char * name,
 287         int name_len,
 288         off_t offset,
 289         ino_t ino)
 290 {
 291         struct dirent *d1 = (struct dirent *)buf;
 292         struct dirent *d2 = d1 + 1;
 293         int len, slen;
 294         int dotdir;
 295 
 296         if (get_user(&d1->d_reclen) != 0) {
 297                 return -1;
 298         }
 299 
 300         if ((name_len == 1 && name[0] == '.') ||
 301             (name_len == 2 && name[0] == '.' && name[1] == '.')) {
 302                 dotdir = 1;
 303                 len = name_len;
 304         } else {
 305                 dotdir = 0;
 306                 len = strlen(name);
 307         }
 308         if (len != name_len) {
 309                 memcpy_tofs(d2->d_name, name, len);
 310                 put_user(0, d2->d_name + len);
 311                 put_user(len, &d2->d_reclen);
 312                 put_user(ino, &d2->d_ino);
 313                 put_user(offset, &d2->d_off);
 314                 slen = name_len - len;
 315                 memcpy_tofs(d1->d_name, name+len+1, slen);
 316                 put_user(0, d1->d_name+slen);
 317                 put_user(slen, &d1->d_reclen);
 318         } else {
 319                 put_user(0, d2->d_name);
 320                 put_user(0, &d2->d_reclen);
 321                 memcpy_tofs(d1->d_name, name, len);
 322                 put_user(0, d1->d_name+len);
 323                 put_user(len, &d1->d_reclen);
 324         }
 325         PRINTK(("FAT d1=%p d2=%p len=%d, name_len=%d\n",
 326                 d1, d2, len, name_len));
 327 
 328         return 0;
 329 }
 330 
 331 int fat_dir_ioctl(struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 332                   unsigned int cmd, unsigned long arg)
 333 {
 334         /*
 335          * We want to provide an interface for Samba to be able
 336          * to get the short filename for a given long filename.
 337          * Samba should use this ioctl instead of readdir() to
 338          * get the information it needs.
 339          */
 340         switch (cmd) {
 341         case VFAT_IOCTL_READDIR_BOTH: {
 342                 struct dirent *d1 = (struct dirent *)arg;
 343                 put_user(0, &d1->d_reclen);
 344                 return fat_readdirx(inode,filp,(void *)arg,vfat_ioctl_fill,1);
 345         }
 346         default:
 347                 return -EINVAL;
 348         }
 349 
 350         return 0;
 351 }

/* [previous][next][first][last][top][bottom][index][help] */