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  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 
  22 static int isofs_readdir(struct inode *, struct file *, struct dirent *, int);
  23 
  24 static struct file_operations isofs_dir_operations = {
  25         NULL,                   /* lseek - default */
  26         NULL,                   /* read */
  27         NULL,                   /* write - bad */
  28         isofs_readdir,          /* readdir */
  29         NULL,                   /* select - default */
  30         NULL,                   /* ioctl - default */
  31         NULL,                   /* no special open code */
  32         NULL,                   /* no special release code */
  33         NULL                    /* fsync */
  34 };
  35 
  36 /*
  37  * directories can handle most operations...
  38  */
  39 struct inode_operations isofs_dir_inode_operations = {
  40         &isofs_dir_operations,  /* default directory file-ops */
  41         NULL,           /* create */
  42         isofs_lookup,           /* lookup */
  43         NULL,                  /* link */
  44         NULL,                   /* unlink */
  45         NULL,                   /* symlink */
  46         NULL,                   /* mkdir */
  47         NULL,                   /* rmdir */
  48         NULL,                   /* mknod */
  49         NULL,                   /* rename */
  50         NULL,                   /* readlink */
  51         NULL,                   /* follow_link */
  52         isofs_bmap,             /* bmap */
  53         NULL,                   /* truncate */
  54         NULL                    /* permission */
  55 };
  56 
  57 /* This is used to speed up lookup.  Without this we would need to
  58 make a linear search of the directory to find the file that the
  59 directory read just returned.  This is a single element cache. */
  60 
  61 struct lookup_cache cache = {0,};
  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 int block,offset,i, j;
  67         char c = 0;
  68         int inode_number;
  69         struct buffer_head * bh;
  70         void * cpnt = NULL;
  71         unsigned int old_offset;
  72         int dlen, rrflag;
  73         char * dpnt;
  74         struct iso_directory_record * de;
  75         
  76         if (!inode || !S_ISDIR(inode->i_mode))
  77                 return -EBADF;
  78         
  79         offset = filp->f_pos & (ISOFS_BUFFER_SIZE(inode) - 1);
  80         block = isofs_bmap(inode,(filp->f_pos)>>ISOFS_BUFFER_BITS(inode));
  81         if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE(inode))))
  82                 return 0;
  83         
  84         while (filp->f_pos < inode->i_size) {
  85 #ifdef DEBUG
  86                 printk("Block, offset: %x %x %x\n",block, offset, filp->f_pos);
  87 #endif
  88                 de = (struct iso_directory_record *) (offset + bh->b_data);
  89                 inode_number = (block << ISOFS_BUFFER_BITS(inode))+(offset & (ISOFS_BUFFER_SIZE(inode) - 1));
  90                 
  91                 /* If the length byte is zero, we should move on to the next CDROM sector.
  92                    If we are at the end of the directory, we kick out of the while loop. */
  93                 
  94                 if (*((char*) de) == 0)  {
  95                         brelse(bh);
  96                         offset = 0;
  97                         filp->f_pos =(filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))+ISOFS_BLOCK_SIZE;
  98                         block = isofs_bmap(inode,(filp->f_pos)>>ISOFS_BUFFER_BITS(inode));
  99                         if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE(inode))))
 100                                 return 0;
 101                         continue;
 102                 }
 103 
 104                 /* Make sure that the entire directory record is in the current bh block.
 105                    If not, we malloc a buffer, and put the two halves together, so that
 106                    we can cleanly read the block */
 107                 
 108                 old_offset = offset;
 109                 offset += *((unsigned char*) de);
 110                 filp->f_pos += *((unsigned char*) de);
 111 
 112                 if (offset >=  ISOFS_BUFFER_SIZE(inode)) {
 113                         cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
 114                         memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(inode));
 115                         de = (struct iso_directory_record *) (old_offset + cpnt);
 116                         brelse(bh);
 117                         offset = filp->f_pos & (ISOFS_BUFFER_SIZE(inode) - 1);
 118                         block = isofs_bmap(inode,(filp->f_pos)>> ISOFS_BUFFER_BITS(inode));
 119                         if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE(inode))))
 120                                 return 0;
 121                         memcpy(cpnt+ISOFS_BUFFER_SIZE(inode), bh->b_data, ISOFS_BUFFER_SIZE(inode));
 122                 }
 123                 
 124                 /* Handle the case of the '.' directory */
 125 
 126                 rrflag = 0;
 127                 i = 1;
 128                 if (de->name_len[0] == 1 && de->name[0] == 0) {
 129                         put_fs_byte('.',dirent->d_name);
 130                         inode_number = inode->i_ino;
 131                         dpnt = ".";
 132                 }
 133                 
 134                 /* Handle the case of the '..' directory */
 135                 
 136                 else if (de->name_len[0] == 1 && de->name[0] == 1) {
 137                         put_fs_byte('.',dirent->d_name);
 138                         put_fs_byte('.',dirent->d_name+1);
 139                         i = 2;
 140                         dpnt = "..";
 141                         if((inode->i_sb->u.isofs_sb.s_firstdatazone << ISOFS_BUFFER_BITS(inode)) != inode->i_ino)
 142                                 inode_number = inode->u.isofs_i.i_backlink;
 143                         else
 144                                 inode_number = inode->i_ino;
 145                         
 146                         /* This should never happen, but who knows.  Try to be forgiving */
 147                         if(inode_number == -1) {
 148                                 inode_number = 
 149                                         isofs_lookup_grandparent(inode,
 150                                              find_rock_ridge_relocation(de, inode));
 151                                 if(inode_number == -1){ /* Should never happen */
 152                                         printk("Backlink not properly set.\n");
 153                                         goto out;
 154                                 };
 155                         }
 156                 }
 157                 
 158                 /* Handle everything else.  Do name translation if there
 159                    is no Rock Ridge NM field. */
 160                 
 161                 else {
 162                         dlen = de->name_len[0];
 163                         dpnt = de->name;
 164                         i = dlen;
 165                         rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, inode);
 166                         if (rrflag) {
 167                           if (rrflag == -1) {  /* This is a rock ridge reloc dir */
 168                             if (cpnt) {
 169                                 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 170                                 cpnt = NULL;
 171                             };
 172                             continue;
 173                           };
 174                           i = dlen;
 175                         }
 176                         else
 177                           if(inode->i_sb->u.isofs_sb.s_mapping == 'n')
 178                             for (i = 0; i < dlen && i < NAME_MAX; i++) {
 179                               if (!(c = dpnt[i])) break;
 180                               if (c >= 'A' && c <= 'Z') c |= 0x20;  /* lower case */
 181                               if (c == ';' && i == dlen-2 && de->name[i+1] == '1') 
 182                                 break;  /* Drop trailing ';1' */
 183                               if (c == ';') c = '.';  /* Convert remaining ';' to '.' */
 184                               dpnt[i] = c;
 185                           };
 186                         
 187                         for(j=0; j<i; j++)
 188                           put_fs_byte(dpnt[j],j+dirent->d_name); /* And save it */
 189                       };
 190 #if 0
 191                 printk("Nchar: %d\n",i);
 192 #endif
 193 
 194                 if (i) {
 195                         while (cache.lock);
 196                         cache.lock = 1;
 197                         cache.ino = inode_number;
 198                         cache.dir = inode->i_ino;
 199                         cache.dev = inode->i_dev;
 200                         strncpy(cache.filename, dpnt, i);
 201                         cache.dlen = dlen;
 202                         cache.lock = 0;
 203                       };
 204 
 205                 if (rrflag) kfree(dpnt);
 206                 if (cpnt) {
 207                         kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 208                         cpnt = NULL;
 209                 };
 210                 
 211                 if (i) {
 212                         put_fs_long(inode_number, &dirent->d_ino);
 213                         put_fs_byte(0,i+dirent->d_name);
 214                         put_fs_word(i,&dirent->d_reclen);
 215                         brelse(bh);
 216                         return i;
 217                 }
 218               }
 219         /* We go here for any condition we cannot handle.  We also drop through
 220            to here at the end of the directory. */
 221  out:
 222         if (cpnt)
 223                 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 224         brelse(bh);
 225         return 0;
 226 }
 227 
 228 
 229 

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