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 <linux/sched.h>
  12 #include <linux/iso_fs.h>
  13 #include <linux/fcntl.h>
  14 #include <linux/kernel.h>
  15 #include <linux/errno.h>
  16 #include <linux/stat.h>
  17 #include <linux/locks.h>
  18 
  19 #include <asm/segment.h>
  20 #include <asm/system.h>
  21 
  22 #define NBUF    32
  23 
  24 #define MIN(a,b) (((a)<(b))?(a):(b))
  25 #define MAX(a,b) (((a)>(b))?(a):(b))
  26 
  27 #include <linux/fs.h>
  28 #include <linux/iso_fs.h>
  29 
  30 static int isofs_file_read(struct inode *, struct file *, char *, int);
  31 
  32 /*
  33  * We have mostly NULL's here: the current defaults are ok for
  34  * the isofs filesystem.
  35  */
  36 static struct file_operations isofs_file_operations = {
  37         NULL,                   /* lseek - default */
  38         isofs_file_read,        /* read */
  39         NULL,                   /* write */
  40         NULL,                   /* readdir - bad */
  41         NULL,                   /* select - default */
  42         NULL,                   /* ioctl - default */
  43         generic_mmap,           /* mmap */
  44         NULL,                   /* no special open is needed */
  45         NULL,                   /* release */
  46         NULL                    /* fsync */
  47 };
  48 
  49 struct inode_operations isofs_file_inode_operations = {
  50         &isofs_file_operations, /* default file operations */
  51         NULL,                   /* create */
  52         NULL,                   /* lookup */
  53         NULL,                   /* link */
  54         NULL,                   /* unlink */
  55         NULL,                   /* symlink */
  56         NULL,                   /* mkdir */
  57         NULL,                   /* rmdir */
  58         NULL,                   /* mknod */
  59         NULL,                   /* rename */
  60         NULL,                   /* readlink */
  61         NULL,                   /* follow_link */
  62         NULL,                   /* readpage */
  63         NULL,                   /* writepage */
  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_user(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, because 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 + (1 << ISOFS_BUFFER_BITS(inode)) - 1)
 165            >> ISOFS_BUFFER_BITS(inode);
 166         if (block + blocks > total_blocks)
 167                 blocks = total_blocks - block;
 168 
 169         max_block = (inode->i_size + BLOCK_SIZE - 1)/BLOCK_SIZE;
 170         nextblock = -1;
 171 
 172         /* We do this in a two stage process.  We first try and request
 173            as many blocks as we can, then we wait for the first one to
 174            complete, and then we try and wrap up as many as are actually
 175            done.  This routine is rather generic, in that it can be used
 176            in a filesystem by substituting the appropriate function in
 177            for getblk.
 178 
 179            This routine is optimized to make maximum use of the various
 180            buffers and caches. */
 181 
 182         do {
 183                 bhrequest = 0;
 184                 while (blocks) {
 185                         int uptodate;
 186                         --blocks;
 187                         *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE(inode));
 188                         uptodate = 1;
 189                         if (*bhb && !buffer_uptodate(*bhb)) {
 190                                 uptodate = 0;
 191                                 bhreq[bhrequest++] = *bhb;
 192                               };
 193 
 194                         if (++bhb == &buflist[NBUF])
 195                                 bhb = buflist;
 196 
 197                         /* If the block we have on hand is uptodate, go ahead
 198                            and complete processing. */
 199                         if(uptodate) break;
 200 
 201                         if (bhb == bhe)
 202                                 break;
 203                       }
 204 
 205                 /* Now request them all */
 206                 if (bhrequest)
 207                   ll_rw_block(READ, bhrequest, bhreq);
 208 
 209                 do{ /* Finish off all I/O that has actually completed */
 210                   if (*bhe) {/* test for valid buffer */
 211                     wait_on_buffer(*bhe);
 212                     if (!buffer_uptodate(*bhe)) {
 213                       brelse(*bhe);
 214                       if (++bhe == &buflist[NBUF])
 215                         bhe = buflist;
 216                       left = 0;
 217                       break;
 218                     }
 219                   }
 220                   
 221                   if (left < ISOFS_BUFFER_SIZE(inode) - offset)
 222                     chars = left;
 223                   else
 224                     chars = ISOFS_BUFFER_SIZE(inode) - offset;
 225                   filp->f_pos += chars;
 226                   left -= chars;
 227                   read += chars;
 228                   if (*bhe) {
 229                     if (inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT ||
 230                         inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT_M)
 231                       unixify_to_fs(buf, offset+(*bhe)->b_data, chars, 
 232                                     inode->u.isofs_i.i_file_format);
 233                     else
 234                       memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 235                     brelse(*bhe);
 236                     buf += chars;
 237                   } else {
 238                     while (chars-->0)
 239                       put_user(0,buf++);
 240                   }
 241                   offset = 0;
 242                   if (++bhe == &buflist[NBUF])
 243                     bhe = buflist;
 244                 } while( bhe != bhb && (*bhe == 0 || !buffer_locked(*bhe)) && 
 245                         (left > 0));
 246         } while (left > 0);
 247 
 248 /* Release the read-ahead blocks */
 249         while (bhe != bhb) {
 250           if (*bhe) brelse(*bhe);
 251           if (++bhe == &buflist[NBUF])
 252             bhe = buflist;
 253         };
 254 
 255         filp->f_reada = 1;
 256 
 257         if (!read)
 258                 return -EIO;
 259         return read;
 260 }

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