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_dir_ioctl
  3. fat_readdir

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

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