root/fs/isofs/file.c

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

DEFINITIONS

This source file includes following definitions.
  1. unixify_to_fs
  2. isofs_determine_filetype
  3. isofs_file_read

   1 /*
   2  *  linux/fs/isofs/file.c
   3  *
   4  *  (C) 1992, 1993, 1994  Eric Youngdale Modified for ISO9660 filesystem.
   5  *
   6  *  (C) 1991  Linus Torvalds - minix filesystem
   7  *
   8  *  isofs regular file handling primitives
   9  */
  10 
  11 #include <asm/segment.h>
  12 #include <asm/system.h>
  13 
  14 #include <linux/sched.h>
  15 #include <linux/iso_fs.h>
  16 #include <linux/fcntl.h>
  17 #include <linux/kernel.h>
  18 #include <linux/errno.h>
  19 #include <linux/stat.h>
  20 #include <linux/locks.h>
  21 
  22 #include <linux/dirent.h>
  23 
  24 #define NBUF    32
  25 
  26 #define MIN(a,b) (((a)<(b))?(a):(b))
  27 #define MAX(a,b) (((a)>(b))?(a):(b))
  28 
  29 #include <linux/fs.h>
  30 #include <linux/iso_fs.h>
  31 
  32 static int isofs_file_read(struct inode *, struct file *, char *, int);
  33 
  34 /*
  35  * We have mostly NULL's here: the current defaults are ok for
  36  * the isofs filesystem.
  37  */
  38 static struct file_operations isofs_file_operations = {
  39         NULL,                   /* lseek - default */
  40         isofs_file_read,        /* read */
  41         NULL,                   /* write */
  42         NULL,                   /* readdir - bad */
  43         NULL,                   /* select - default */
  44         NULL,                   /* ioctl - default */
  45         generic_mmap,           /* mmap */
  46         NULL,                   /* no special open is needed */
  47         NULL,                   /* release */
  48         NULL                    /* fsync */
  49 };
  50 
  51 struct inode_operations isofs_file_inode_operations = {
  52         &isofs_file_operations, /* default file operations */
  53         NULL,                   /* create */
  54         NULL,                   /* lookup */
  55         NULL,                   /* link */
  56         NULL,                   /* unlink */
  57         NULL,                   /* symlink */
  58         NULL,                   /* mkdir */
  59         NULL,                   /* rmdir */
  60         NULL,                   /* mknod */
  61         NULL,                   /* rename */
  62         NULL,                   /* readlink */
  63         NULL,                   /* follow_link */
  64         isofs_bmap,             /* bmap */
  65         NULL,                   /* truncate */
  66         NULL                    /* permission */
  67 };
  68 
  69 /* This is a heuristic to determine if a file is text of binary.  If it
  70  * is text, then we translate all 0x0d characters to spaces.  If the 0x0d
  71  * character is not preceded or followed by a 0x0a, then we turn it into
  72  * a 0x0a.  A control-Z is also turned into a linefeed.
  73  */
  74 
  75 static inline void unixify_to_fs(char * outbuf, char * buffer, int chars,
     /* [previous][next][first][last][top][bottom][index][help] */
  76                                  int mode)
  77 {
  78         char outchar;
  79 
  80         while(chars--){
  81                 outchar = *buffer;
  82                 if(outchar == 0x1a) outchar = 0x0a;
  83                 if(outchar == 0x0d){
  84                         if(mode == ISOFS_FILE_TEXT_M) outchar = 0x0a;
  85                         if(mode == ISOFS_FILE_TEXT) outchar = ' ';
  86                 }
  87                 put_fs_byte(outchar, outbuf++);
  88                 buffer++;
  89         }
  90 }
  91 
  92 /*This function determines if a given file has a DOS-like text format or not*/
  93 
  94 static void isofs_determine_filetype(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96         int block;
  97         int result, i;
  98         struct buffer_head * bh;
  99         unsigned char * pnt;
 100         
 101         block = isofs_bmap(inode,0);
 102         if (block && (bh = bread(inode->i_dev,block, ISOFS_BUFFER_SIZE(inode)))) {
 103                 pnt = (unsigned char *) bh->b_data;
 104                 result = ISOFS_FILE_TEXT_M;
 105                 for(i=0;i<(inode->i_size < ISOFS_BUFFER_SIZE(inode) ? inode->i_size : ISOFS_BUFFER_SIZE(inode));
 106                     i++,pnt++){
 107                         if(*pnt & 0x80) {result = ISOFS_FILE_BINARY; break;};
 108                         if(*pnt >= 0x20 || *pnt == 0x1a) continue;
 109                         if(*pnt == 0x0a) {result = ISOFS_FILE_TEXT; continue;};
 110                         if(*pnt >= 0x9 && *pnt <= 0x0d) continue;
 111                         result = ISOFS_FILE_BINARY;
 112                         break;
 113                 }
 114                 brelse(bh);
 115                 inode->u.isofs_i.i_file_format = result;
 116         }
 117 }
 118 
 119 static int isofs_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 120 {
 121         int read,left,chars;
 122         int block, blocks, offset, total_blocks;
 123         int bhrequest;
 124         int ra_blocks, max_block, nextblock;
 125         struct buffer_head ** bhb, ** bhe;
 126         struct buffer_head * bhreq[NBUF];
 127         struct buffer_head * buflist[NBUF];
 128         
 129         if (!inode) {
 130                 printk("isofs_file_read: inode = NULL\n");
 131                 return -EINVAL;
 132         }
 133         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
 134                 printk("isofs_file_read: mode = %07o\n",inode->i_mode);
 135                 return -EINVAL;
 136         }
 137         if (inode->u.isofs_i.i_file_format == ISOFS_FILE_UNKNOWN)
 138                 isofs_determine_filetype(inode);
 139         if (filp->f_pos > inode->i_size)
 140                 left = 0;
 141         else
 142                 left = inode->i_size - filp->f_pos;
 143         if (left > count)
 144                 left = count;
 145         if (left <= 0)
 146                 return 0;
 147         read = 0;
 148         block = filp->f_pos >> ISOFS_BUFFER_BITS(inode);
 149         offset = (inode->u.isofs_i.i_first_extent + filp->f_pos)
 150           & (ISOFS_BUFFER_SIZE(inode)-1);
 151         blocks = (left + offset + ISOFS_BUFFER_SIZE(inode) - 1) / ISOFS_BUFFER_SIZE(inode);
 152         bhb = bhe = buflist;
 153 
 154         ra_blocks = read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 155         if(ra_blocks > blocks) blocks = ra_blocks;
 156 
 157         /*
 158          * this is for stopping read ahead at EOF. It's  important for
 159          * reading PhotoCD's, becauce they have many small data tracks instead
 160          * of one big. And between two data-tracks are some unreadable sectors.
 161          * A read ahead after a EOF may try to read such an unreadable sector.
 162          *    kraxel@cs.tu-berlin.de (Gerd Knorr)
 163          */
 164         total_blocks = inode->i_size >> ISOFS_BUFFER_BITS(inode);
 165         if (inode->i_size & (ISOFS_BUFFER_BITS(inode)-1)) total_blocks++;
 166         while (block + blocks > total_blocks) blocks--;
 167 
 168         max_block = (inode->i_size + BLOCK_SIZE - 1)/BLOCK_SIZE;
 169         nextblock = -1;
 170 
 171         /* We do this in a two stage process.  We first try and request
 172            as many blocks as we can, then we wait for the first one to
 173            complete, and then we try and wrap up as many as are actually
 174            done.  This routine is rather generic, in that it can be used
 175            in a filesystem by substituting the appropriate function in
 176            for getblk.
 177 
 178            This routine is optimized to make maximum use of the various
 179            buffers and caches. */
 180 
 181         do {
 182                 bhrequest = 0;
 183                 while (blocks) {
 184                         int uptodate;
 185                         --blocks;
 186                         *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE(inode));
 187                         uptodate = 1;
 188                         if (*bhb && !(*bhb)->b_uptodate) {
 189                                 uptodate = 0;
 190                                 bhreq[bhrequest++] = *bhb;
 191                               };
 192 
 193                         if (++bhb == &buflist[NBUF])
 194                                 bhb = buflist;
 195 
 196                         /* If the block we have on hand is uptodate, go ahead
 197                            and complete processing. */
 198                         if(uptodate) break;
 199 
 200                         if (bhb == bhe)
 201                                 break;
 202                       }
 203 
 204                 /* Now request them all */
 205                 if (bhrequest)
 206                   ll_rw_block(READ, bhrequest, bhreq);
 207 
 208                 do{ /* Finish off all I/O that has actually completed */
 209                   if (*bhe) {/* test for valid buffer */
 210                     wait_on_buffer(*bhe);
 211                     if (!(*bhe)->b_uptodate) {
 212                       brelse(*bhe);
 213                       if (++bhe == &buflist[NBUF])
 214                         bhe = buflist;
 215                       left = 0;
 216                       break;
 217                     }
 218                   }
 219                   
 220                   if (left < ISOFS_BUFFER_SIZE(inode) - offset)
 221                     chars = left;
 222                   else
 223                     chars = ISOFS_BUFFER_SIZE(inode) - offset;
 224                   filp->f_pos += chars;
 225                   left -= chars;
 226                   read += chars;
 227                   if (*bhe) {
 228                     if (inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT ||
 229                         inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT_M)
 230                       unixify_to_fs(buf, offset+(*bhe)->b_data, chars, 
 231                                     inode->u.isofs_i.i_file_format);
 232                     else
 233                       memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 234                     brelse(*bhe);
 235                     buf += chars;
 236                   } else {
 237                     while (chars-->0)
 238                       put_fs_byte(0,buf++);
 239                   }
 240                   offset = 0;
 241                   if (++bhe == &buflist[NBUF])
 242                     bhe = buflist;
 243                 } while( bhe != bhb && (*bhe == 0 || !(*bhe)->b_lock) && 
 244                         (left > 0));
 245         } while (left > 0);
 246 
 247 /* Release the read-ahead blocks */
 248         while (bhe != bhb) {
 249           if (*bhe) brelse(*bhe);
 250           if (++bhe == &buflist[NBUF])
 251             bhe = buflist;
 252         };
 253 
 254         filp->f_reada = 1;
 255 
 256         if (!read)
 257                 return -EIO;
 258         return read;
 259 }

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