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                                 return 0;
 131                         memcpy((char *)cpnt+bufsize, bh->b_data, bufsize);
 132                 }
 133                 
 134                 /* Handle the case of the '.' directory */
 135 
 136                 rrflag = 0;
 137                 i = 1;
 138                 if (de->name_len[0] == 1 && de->name[0] == 0) {
 139                         put_fs_byte('.',dirent->d_name);
 140                         inode_number = inode->i_ino;
 141                         dpnt = ".";
 142                 }
 143                 
 144                 /* Handle the case of the '..' directory */
 145                 
 146                 else if (de->name_len[0] == 1 && de->name[0] == 1) {
 147                         put_fs_byte('.',dirent->d_name);
 148                         put_fs_byte('.',dirent->d_name+1);
 149                         i = 2;
 150                         dpnt = "..";
 151                         if((inode->i_sb->u.isofs_sb.s_firstdatazone
 152                             << bufbits) != inode->i_ino)
 153                                 inode_number = inode->u.isofs_i.i_backlink;
 154                         else
 155                                 inode_number = inode->i_ino;
 156                         
 157                         /* This should never happen, but who knows.  Try to be forgiving */
 158                         if(inode_number == -1) {
 159                                 inode_number = 
 160                                         isofs_lookup_grandparent(inode,
 161                                              find_rock_ridge_relocation(de, inode));
 162                                 if(inode_number == -1){ /* Should never happen */
 163                                         printk("Backlink not properly set.\n");
 164                                         goto out;
 165                                 };
 166                         }
 167                 }
 168                 
 169                 /* Handle everything else.  Do name translation if there
 170                    is no Rock Ridge NM field. */
 171                 
 172                 else {
 173                         dlen = de->name_len[0];
 174                         dpnt = de->name;
 175                         i = dlen;
 176                         rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, inode);
 177                         if (rrflag) {
 178                           if (rrflag == -1) {  /* This is a rock ridge reloc dir */
 179                             if (cpnt) {
 180                                 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 181                                 cpnt = NULL;
 182                             };
 183                             continue;
 184                           };
 185                           i = dlen;
 186                         }
 187                         else
 188                           if(inode->i_sb->u.isofs_sb.s_mapping == 'n')
 189                             for (i = 0; i < dlen && i < NAME_MAX; i++) {
 190                               if (!(c = dpnt[i])) break;
 191                               if (c >= 'A' && c <= 'Z') c |= 0x20;  /* lower case */
 192                               if (c == ';' && i == dlen-2 && de->name[i+1] == '1') 
 193                                 break;  /* Drop trailing ';1' */
 194                               if (c == ';') c = '.';  /* Convert remaining ';' to '.' */
 195                               dpnt[i] = c;
 196                           };
 197                         
 198                         for(j=0; j<i; j++)
 199                           put_fs_byte(dpnt[j],j+dirent->d_name); /* And save it */
 200                       };
 201 #if 0
 202                 printk("Nchar: %d\n",i);
 203 #endif
 204 
 205                 if (i && i+1 < sizeof(cache.filename)) {
 206                         cache.ino = inode_number;
 207                         cache.dir = inode->i_ino;
 208                         cache.dev = inode->i_dev;
 209                         strncpy(cache.filename, dpnt, i);
 210                         cache.dlen = dlen;
 211                       };
 212 
 213                 if (rrflag) kfree(dpnt);
 214                 if (cpnt) {
 215                         kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 216                         cpnt = NULL;
 217                 };
 218                 
 219                 if (i) {
 220                         put_fs_long(inode_number, &dirent->d_ino);
 221                         put_fs_byte(0,i+dirent->d_name);
 222                         put_fs_word(i,&dirent->d_reclen);
 223                         brelse(bh);
 224                         return i;
 225                 }
 226               }
 227         /* We go here for any condition we cannot handle.  We also drop through
 228            to here at the end of the directory. */
 229  out:
 230         if (cpnt)
 231                 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 232         brelse(bh);
 233         return 0;
 234 }
 235 
 236 
 237 

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