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

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