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

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