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

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