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

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