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

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