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                   /* Do not report hidden or associated files */
 187                         high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
 188                         if (de->flags[-high_sierra] & 5) {
 189                           if (cpnt) {
 190                             kfree(cpnt);
 191                             cpnt = NULL;
 192                           };
 193                           continue;
 194                         }
 195                         dlen = de->name_len[0];
 196                         dpnt = de->name;
 197                         i = dlen;
 198                         rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, inode);
 199                         if (rrflag) {
 200                           if (rrflag == -1) {  /* This is a rock ridge reloc dir */
 201                             if (cpnt) {
 202                                 kfree(cpnt);
 203                                 cpnt = NULL;
 204                             };
 205                             continue;
 206                           };
 207                           i = dlen;
 208                         }
 209                         else
 210                           if(inode->i_sb->u.isofs_sb.s_mapping == 'n') {
 211                             dpnt1 = dpnt;
 212                             dpnt = kmalloc(dlen, GFP_KERNEL);
 213                             if (!dpnt) goto out;
 214                             for (i = 0; i < dlen && i < NAME_MAX; i++) {
 215                               if (!(c = dpnt1[i])) break;
 216                               if (c >= 'A' && c <= 'Z') c |= 0x20;  /* lower case */
 217                               if (c == '.' && i == dlen-3 && de->name[i+1] == ';' && de->name[i+2] == '1')
 218                                 break;  /* Drop trailing '.;1' (ISO9660:1988 7.5.1 requires period) */
 219                               if (c == ';' && i == dlen-2 && de->name[i+1] == '1') 
 220                                 break;  /* Drop trailing ';1' */
 221                               if (c == ';') c = '.';  /* Convert remaining ';' to '.' */
 222                               dpnt[i] = c;
 223                             }
 224                           }
 225                         for(j=0; j<i; j++)
 226                           put_fs_byte(dpnt[j],j+dirent->d_name); /* And save it */
 227                         if(dpnt1) {
 228                           kfree(dpnt);
 229                           dpnt = dpnt1;
 230                         }
 231                         
 232                         dcache_add(inode, dpnt, i, inode_number);
 233                       };
 234 #if 0
 235                 printk("Nchar: %d\n",i);
 236 #endif
 237 
 238                 if (rrflag) kfree(dpnt);
 239                 if (cpnt) {
 240                         kfree(cpnt);
 241                         cpnt = NULL;
 242                 };
 243                 
 244                 if (i) {
 245                         put_fs_long(inode_number, &dirent->d_ino);
 246                         put_fs_byte(0,i+dirent->d_name);
 247                         put_fs_word(i,&dirent->d_reclen);
 248                         brelse(bh);
 249                         return ROUND_UP(NAME_OFFSET(dirent) + i + 1);
 250                 }
 251               }
 252         /* We go here for any condition we cannot handle.  We also drop through
 253            to here at the end of the directory. */
 254  out:
 255         if (cpnt)
 256                 kfree(cpnt);
 257         brelse(bh);
 258         return 0;
 259 }
 260 
 261 
 262 

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