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

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