root/fs/isofs/dir.c

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

DEFINITIONS

This source file includes following definitions.
  1. isofs_readdir

   1 /*
   2  *  linux/fs/isofs/dir.c
   3  *
   4  *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
   5  *
   6  *  (C) 1991  Linus Torvalds - minix filesystem
   7  *
   8  *  isofs directory handling functions
   9  */
  10 
  11 #include <linux/errno.h>
  12 
  13 #include <asm/segment.h>
  14 
  15 #include <linux/fs.h>
  16 #include <linux/iso_fs.h>
  17 #include <linux/kernel.h>
  18 #include <linux/stat.h>
  19 #include <linux/string.h>
  20 #include <linux/mm.h>
  21 #include <linux/malloc.h>
  22 
  23 static int isofs_readdir(struct inode *, struct file *, struct dirent *, int);
  24 
  25 static struct file_operations isofs_dir_operations = {
  26         NULL,                   /* lseek - default */
  27         NULL,                   /* read */
  28         NULL,                   /* write - bad */
  29         isofs_readdir,          /* readdir */
  30         NULL,                   /* select - default */
  31         NULL,                   /* ioctl - default */
  32         NULL,                   /* no special open code */
  33         NULL,                   /* no special release code */
  34         NULL                    /* fsync */
  35 };
  36 
  37 /*
  38  * directories can handle most operations...
  39  */
  40 struct inode_operations isofs_dir_inode_operations = {
  41         &isofs_dir_operations,  /* default directory file-ops */
  42         NULL,           /* create */
  43         isofs_lookup,           /* lookup */
  44         NULL,                  /* link */
  45         NULL,                   /* unlink */
  46         NULL,                   /* symlink */
  47         NULL,                   /* mkdir */
  48         NULL,                   /* rmdir */
  49         NULL,                   /* mknod */
  50         NULL,                   /* rename */
  51         NULL,                   /* readlink */
  52         NULL,                   /* follow_link */
  53         isofs_bmap,             /* bmap */
  54         NULL,                   /* truncate */
  55         NULL                    /* permission */
  56 };
  57 
  58 /* This is used to speed up lookup.  Without this we would need to
  59 make a linear search of the directory to find the file that the
  60 directory read just returned.  This is a single element cache. */
  61 
  62 struct lookup_cache cache = {0,};
  63 
  64 static int isofs_readdir(struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
  65         struct dirent * dirent, int count)
  66 {
  67         unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
  68         unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
  69         unsigned int block,offset,i, j;
  70         char c = 0;
  71         int inode_number;
  72         struct buffer_head * bh;
  73         void * cpnt = NULL;
  74         unsigned int old_offset;
  75         int dlen, rrflag;
  76         char * dpnt;
  77         struct iso_directory_record * de;
  78         
  79         if (!inode || !S_ISDIR(inode->i_mode))
  80                 return -EBADF;
  81         
  82         offset = filp->f_pos & (bufsize - 1);
  83         block = isofs_bmap(inode,filp->f_pos>>bufbits);
  84         if (!block || !(bh = bread(inode->i_dev,block,bufsize)))
  85                 return 0;
  86         
  87         while (filp->f_pos < inode->i_size) {
  88 #ifdef DEBUG
  89                 printk("Block, offset: %x %x %x\n",
  90                        block, offset, filp->f_pos);
  91 #endif
  92                 de = (struct iso_directory_record *) (bh->b_data + offset);
  93                 inode_number = (block << bufbits) + (offset & (bufsize - 1));
  94                 
  95                 /* If the length byte is zero, we should move on to the next
  96                    CDROM sector.  If we are at the end of the directory, we
  97                    kick out of the while loop. */
  98                 
  99                 if (*((unsigned char *) de) == 0)  {
 100                         brelse(bh);
 101                         offset = 0;
 102                         filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
 103                                        + ISOFS_BLOCK_SIZE);
 104                         block = isofs_bmap(inode,(filp->f_pos)>>bufbits);
 105                         if (!block
 106                             || !(bh = bread(inode->i_dev,block,bufsize)))
 107                                 return 0;
 108                         continue;
 109                 }
 110 
 111                 /* Make sure that the entire directory record is in the
 112                    current bh block.
 113                    If not, we malloc a buffer, and put the two halves together,
 114                    so that we can cleanly read the block */
 115 
 116                 old_offset = offset;
 117                 offset += *((unsigned char *) de);
 118                 filp->f_pos += *((unsigned char *) de);
 119 
 120                 if (offset >=  bufsize) {
 121                         cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
 122                         memcpy(cpnt, bh->b_data, bufsize);
 123                         de = (struct iso_directory_record *)
 124                                 ((char *)cpnt + old_offset);
 125                         brelse(bh);
 126                         offset = filp->f_pos & (bufsize - 1);
 127                         block = isofs_bmap(inode,(filp->f_pos)>> bufbits);
 128                         if (!block
 129                             || !(bh = bread(inode->i_dev,block,bufsize))) {
 130                                 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 131                                 return 0;
 132                         };
 133                         memcpy((char *)cpnt+bufsize, bh->b_data, bufsize);
 134                 }
 135                 
 136                 /* Handle the case of the '.' directory */
 137 
 138                 rrflag = 0;
 139                 i = 1;
 140                 if (de->name_len[0] == 1 && de->name[0] == 0) {
 141                         put_fs_byte('.',dirent->d_name);
 142                         inode_number = inode->i_ino;
 143                         dpnt = ".";
 144                 }
 145                 
 146                 /* Handle the case of the '..' directory */
 147                 
 148                 else if (de->name_len[0] == 1 && de->name[0] == 1) {
 149                         put_fs_byte('.',dirent->d_name);
 150                         put_fs_byte('.',dirent->d_name+1);
 151                         i = 2;
 152                         dpnt = "..";
 153                         if((inode->i_sb->u.isofs_sb.s_firstdatazone
 154                             << bufbits) != inode->i_ino)
 155                                 inode_number = inode->u.isofs_i.i_backlink;
 156                         else
 157                                 inode_number = inode->i_ino;
 158                         
 159                         /* This should never happen, but who knows.  Try to be forgiving */
 160                         if(inode_number == -1) {
 161                                 inode_number = 
 162                                         isofs_lookup_grandparent(inode,
 163                                              find_rock_ridge_relocation(de, inode));
 164                                 if(inode_number == -1){ /* Should never happen */
 165                                         printk("Backlink not properly set.\n");
 166                                         goto out;
 167                                 };
 168                         }
 169                 }
 170                 
 171                 /* Handle everything else.  Do name translation if there
 172                    is no Rock Ridge NM field. */
 173                 
 174                 else {
 175                         dlen = de->name_len[0];
 176                         dpnt = de->name;
 177                         i = dlen;
 178                         rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, inode);
 179                         if (rrflag) {
 180                           if (rrflag == -1) {  /* This is a rock ridge reloc dir */
 181                             if (cpnt) {
 182                                 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 183                                 cpnt = NULL;
 184                             };
 185                             continue;
 186                           };
 187                           i = dlen;
 188                         }
 189                         else
 190                           if(inode->i_sb->u.isofs_sb.s_mapping == 'n')
 191                             for (i = 0; i < dlen && i < NAME_MAX; i++) {
 192                               if (!(c = dpnt[i])) break;
 193                               if (c >= 'A' && c <= 'Z') c |= 0x20;  /* lower case */
 194                               if (c == ';' && i == dlen-2 && de->name[i+1] == '1') 
 195                                 break;  /* Drop trailing ';1' */
 196                               if (c == ';') c = '.';  /* Convert remaining ';' to '.' */
 197                               dpnt[i] = c;
 198                           };
 199                         
 200                         for(j=0; j<i; j++)
 201                           put_fs_byte(dpnt[j],j+dirent->d_name); /* And save it */
 202                       };
 203 #if 0
 204                 printk("Nchar: %d\n",i);
 205 #endif
 206 
 207                 if (i && i+1 < sizeof(cache.filename)) {
 208                         cache.ino = inode_number;
 209                         cache.dir = inode->i_ino;
 210                         cache.dev = inode->i_dev;
 211                         strncpy(cache.filename, dpnt, i);
 212                         cache.dlen = dlen;
 213                       };
 214 
 215                 if (rrflag) kfree(dpnt);
 216                 if (cpnt) {
 217                         kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 218                         cpnt = NULL;
 219                 };
 220                 
 221                 if (i) {
 222                         put_fs_long(inode_number, &dirent->d_ino);
 223                         put_fs_byte(0,i+dirent->d_name);
 224                         put_fs_word(i,&dirent->d_reclen);
 225                         brelse(bh);
 226                         return i;
 227                 }
 228               }
 229         /* We go here for any condition we cannot handle.  We also drop through
 230            to here at the end of the directory. */
 231  out:
 232         if (cpnt)
 233                 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 234         brelse(bh);
 235         return 0;
 236 }
 237 
 238 
 239 

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