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 static int isofs_readdir(struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
  61         struct dirent * dirent, int count)
  62 {
  63         unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
  64         unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
  65         unsigned int block,offset,i, j;
  66         char c = 0;
  67         int inode_number;
  68         struct buffer_head * bh;
  69         void * cpnt = NULL;
  70         unsigned int old_offset;
  71         int dlen, rrflag;
  72         char * dpnt, *dpnt1;
  73         struct iso_directory_record * de;
  74         
  75         dpnt1 = NULL;
  76         if (!inode || !S_ISDIR(inode->i_mode))
  77                 return -EBADF;
  78         
  79         offset = filp->f_pos & (bufsize - 1);
  80         block = isofs_bmap(inode,filp->f_pos>>bufbits);
  81 
  82         if(!block) return 0;
  83 
  84         if(!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size)))
  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 = breada(inode->i_dev, block, bufsize, filp->f_pos, 
 107                                              inode->i_size)))
 108                                 return 0;
 109                         continue;
 110                 }
 111 
 112                 /* Make sure that the entire directory record is in the
 113                    current bh block.
 114                    If not, we malloc a buffer, and put the two halves together,
 115                    so that we can cleanly read the block */
 116 
 117                 old_offset = offset;
 118                 offset += *((unsigned char *) de);
 119                 filp->f_pos += *((unsigned char *) de);
 120 
 121                 if (offset >=  bufsize) {
 122                         unsigned int frag1;
 123                         frag1 = bufsize - old_offset;
 124                         cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
 125                         memcpy(cpnt, bh->b_data + old_offset, frag1);
 126                         de = (struct iso_directory_record *) ((char *)cpnt);
 127                         brelse(bh);
 128                         offset = filp->f_pos & (bufsize - 1);
 129                         block = isofs_bmap(inode,(filp->f_pos)>> bufbits);
 130                         if (!block
 131                             || !(bh = breada(inode->i_dev, block, bufsize,
 132                                              filp->f_pos, inode->i_size))) {
 133                                 kfree(cpnt);
 134                                 return 0;
 135                         };
 136                         memcpy((char *)cpnt+frag1, bh->b_data, offset);
 137                 }
 138                 
 139                 /* Handle the case of the '.' directory */
 140 
 141                 rrflag = 0;
 142                 i = 1;
 143                 if (de->name_len[0] == 1 && de->name[0] == 0) {
 144                         put_fs_byte('.',dirent->d_name);
 145                         inode_number = inode->i_ino;
 146                         dpnt = ".";
 147                 }
 148                 
 149                 /* Handle the case of the '..' directory */
 150                 
 151                 else if (de->name_len[0] == 1 && de->name[0] == 1) {
 152                         put_fs_byte('.',dirent->d_name);
 153                         put_fs_byte('.',dirent->d_name+1);
 154                         i = 2;
 155                         dpnt = "..";
 156                         if((inode->i_sb->u.isofs_sb.s_firstdatazone
 157                             << bufbits) != inode->i_ino)
 158                                 inode_number = inode->u.isofs_i.i_backlink;
 159                         else
 160                                 inode_number = inode->i_ino;
 161                         
 162                         /* This should never happen, but who knows.  Try to be forgiving */
 163                         if(inode_number == -1) {
 164                                 inode_number = 
 165                                         isofs_lookup_grandparent(inode,
 166                                              find_rock_ridge_relocation(de, inode));
 167                                 if(inode_number == -1){ /* Should never happen */
 168                                         printk("Backlink not properly set.\n");
 169                                         goto out;
 170                                 };
 171                         }
 172                 }
 173                 
 174                 /* Handle everything else.  Do name translation if there
 175                    is no Rock Ridge NM field. */
 176                 
 177                 else {
 178                         dlen = de->name_len[0];
 179                         dpnt = de->name;
 180                         i = dlen;
 181                         rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, inode);
 182                         if (rrflag) {
 183                           if (rrflag == -1) {  /* This is a rock ridge reloc dir */
 184                             if (cpnt) {
 185                                 kfree(cpnt);
 186                                 cpnt = NULL;
 187                             };
 188                             continue;
 189                           };
 190                           i = dlen;
 191                         }
 192                         else
 193                           if(inode->i_sb->u.isofs_sb.s_mapping == 'n') {
 194                             dpnt1 = dpnt;
 195                             dpnt = kmalloc(dlen, GFP_KERNEL);
 196                             for (i = 0; i < dlen && i < NAME_MAX; i++) {
 197                               if (!(c = dpnt1[i])) break;
 198                               if (c >= 'A' && c <= 'Z') c |= 0x20;  /* lower case */
 199                               if (c == '.' && i == dlen-3 && de->name[i+1] == ';' && de->name[i+2] == '1')
 200                                 break;  /* Drop trailing '.;1' (ISO9660:1988 7.5.1 requires period) */
 201                               if (c == ';' && i == dlen-2 && de->name[i+1] == '1') 
 202                                 break;  /* Drop trailing ';1' */
 203                               if (c == ';') c = '.';  /* Convert remaining ';' to '.' */
 204                               dpnt[i] = c;
 205                             }
 206                           }
 207                         for(j=0; j<i; j++)
 208                           put_fs_byte(dpnt[j],j+dirent->d_name); /* And save it */
 209                         if(dpnt1) {
 210                           kfree(dpnt);
 211                           dpnt = dpnt1;
 212                         }
 213                         
 214                         dcache_add(inode, dpnt, i, inode_number);
 215                       };
 216 #if 0
 217                 printk("Nchar: %d\n",i);
 218 #endif
 219 
 220                 if (rrflag) kfree(dpnt);
 221                 if (cpnt) {
 222                         kfree(cpnt);
 223                         cpnt = NULL;
 224                 };
 225                 
 226                 if (i) {
 227                         put_fs_long(inode_number, &dirent->d_ino);
 228                         put_fs_byte(0,i+dirent->d_name);
 229                         put_fs_word(i,&dirent->d_reclen);
 230                         brelse(bh);
 231                         return i;
 232                 }
 233               }
 234         /* We go here for any condition we cannot handle.  We also drop through
 235            to here at the end of the directory. */
 236  out:
 237         if (cpnt)
 238                 kfree(cpnt);
 239         brelse(bh);
 240         return 0;
 241 }
 242 
 243 
 244 

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