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         char * cpnt = 0;
  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 & (BLOCK_SIZE - 1);
  80         block = isofs_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
  81         if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE)))
  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 << BLOCK_SIZE_BITS)+(offset & (BLOCK_SIZE - 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)>>BLOCK_SIZE_BITS);
  99                         if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE)))
 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                 if (offset >=  BLOCK_SIZE) {
 112                         cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
 113                         memcpy(cpnt, bh->b_data, BLOCK_SIZE);
 114                         de = (struct iso_directory_record *) (old_offset + cpnt);
 115                         brelse(bh);
 116                         offset = filp->f_pos & (BLOCK_SIZE - 1);
 117                         block = isofs_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
 118                         if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE)))
 119                                 return 0;
 120                         memcpy(cpnt+BLOCK_SIZE, bh->b_data, BLOCK_SIZE);
 121                 }
 122                 
 123                 /* Handle the case of the '.' directory */
 124 
 125                 rrflag = 0;
 126                 i = 1;
 127                 if (de->name_len[0] == 1 && de->name[0] == 0) {
 128                         put_fs_byte('.',dirent->d_name);
 129                         inode_number = inode->i_ino;
 130                         dpnt = ".";
 131                 }
 132                 
 133                 /* Handle the case of the '..' directory */
 134                 
 135                 else if (de->name_len[0] == 1 && de->name[0] == 1) {
 136                         put_fs_byte('.',dirent->d_name);
 137                         put_fs_byte('.',dirent->d_name+1);
 138                         i = 2;
 139                         dpnt = "..";
 140                         if((inode->i_sb->u.isofs_sb.s_firstdatazone << BLOCK_SIZE_BITS) != inode->i_ino)
 141                                 inode_number = inode->u.isofs_i.i_backlink;
 142                         else
 143                                 inode_number = inode->i_ino;
 144                         
 145                         /* This should never happen, but who knows.  Try to be forgiving */
 146                         if(inode_number == -1) {
 147                                 inode_number = 
 148                                         isofs_lookup_grandparent(inode,
 149                                              find_rock_ridge_relocation(de, inode));
 150                                 if(inode_number == -1){ /* Should never happen */
 151                                         printk("Backlink not properly set.\n");
 152                                         goto out;
 153                                 };
 154                         }
 155                 }
 156                 
 157                 /* Handle everything else.  Do name translation if there
 158                    is no Rock Ridge NM field. */
 159                 
 160                 else {
 161                         dlen = de->name_len[0];
 162                         dpnt = de->name;
 163                         i = dlen;
 164                         rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, inode);
 165                         if (rrflag) {
 166                           if (rrflag == -1) {  /* This is a rock ridge reloc dir */
 167                             if (cpnt) {
 168                                 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 169                                 cpnt = 0;
 170                             };
 171                             continue;
 172                           };
 173                           i = dlen;
 174                         }
 175                         else
 176                           if(inode->i_sb->u.isofs_sb.s_mapping == 'n')
 177                             for (i = 0; i < dlen && i < NAME_MAX; i++) {
 178                               if (!(c = dpnt[i])) break;
 179                               if (c >= 'A' && c <= 'Z') c |= 0x20;  /* lower case */
 180                               if (c == ';' && i == dlen-2 && de->name[i+1] == '1') 
 181                                 break;  /* Drop trailing ';1' */
 182                               if (c == ';') c = '.';  /* Convert remaining ';' to '.' */
 183                               dpnt[i] = c;
 184                           };
 185                         
 186                         for(j=0; j<i; j++)
 187                           put_fs_byte(dpnt[j],j+dirent->d_name); /* And save it */
 188                       };
 189 #if 0
 190                 printk("Nchar: %d\n",i);
 191 #endif
 192 
 193                 if (i) {
 194                         while (cache.lock);
 195                         cache.lock = 1;
 196                         cache.ino = inode_number;
 197                         cache.dir = inode->i_ino;
 198                         cache.dev = inode->i_dev;
 199                         strncpy(cache.filename, dpnt, i);
 200                         cache.dlen = dlen;
 201                         cache.lock = 0;
 202                       };
 203 
 204                 if (rrflag) kfree(dpnt);
 205                 if (cpnt) {
 206                         kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 207                         cpnt = 0;
 208                 };
 209                 
 210                 if (i) {
 211                         put_fs_long(inode_number, &dirent->d_ino);
 212                         put_fs_byte(0,i+dirent->d_name);
 213                         put_fs_word(i,&dirent->d_reclen);
 214                         brelse(bh);
 215                         return i;
 216                 }
 217               }
 218         /* We go here for any condition we cannot handle.  We also drop through
 219            to here at the end of the directory. */
 220  out:
 221         if (cpnt) kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 222         brelse(bh);
 223         return 0;
 224 }
 225 
 226 
 227 

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