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

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