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         isofs_bmap,             /* bmap */
  63         NULL,                   /* truncate */
  64         NULL                    /* permission */
  65 };
  66 
  67 /* This is a heuristic to determine if a file is text of binary.  If it
  68  * is text, then we translate all 0x0d characters to spaces.  If the 0x0d
  69  * character is not preceded or followed by a 0x0a, then we turn it into
  70  * a 0x0a.  A control-Z is also turned into a linefeed.
  71  */
  72 
  73 static inline void unixify_to_fs(char * outbuf, char * buffer, int chars,
     /* [previous][next][first][last][top][bottom][index][help] */
  74                                  int mode)
  75 {
  76         char outchar;
  77 
  78         while(chars--){
  79                 outchar = *buffer;
  80                 if(outchar == 0x1a) outchar = 0x0a;
  81                 if(outchar == 0x0d){
  82                         if(mode == ISOFS_FILE_TEXT_M) outchar = 0x0a;
  83                         if(mode == ISOFS_FILE_TEXT) outchar = ' ';
  84                 }
  85                 put_user(outchar, outbuf++);
  86                 buffer++;
  87         }
  88 }
  89 
  90 /*This function determines if a given file has a DOS-like text format or not*/
  91 
  92 static void isofs_determine_filetype(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94         int block;
  95         int result, i;
  96         struct buffer_head * bh;
  97         unsigned char * pnt;
  98         
  99         block = isofs_bmap(inode,0);
 100         if (block && (bh = bread(inode->i_dev,block, ISOFS_BUFFER_SIZE(inode)))) {
 101                 pnt = (unsigned char *) bh->b_data;
 102                 result = ISOFS_FILE_TEXT_M;
 103                 for(i=0;i<(inode->i_size < ISOFS_BUFFER_SIZE(inode) ? inode->i_size : ISOFS_BUFFER_SIZE(inode));
 104                     i++,pnt++){
 105                         if(*pnt & 0x80) {result = ISOFS_FILE_BINARY; break;};
 106                         if(*pnt >= 0x20 || *pnt == 0x1a) continue;
 107                         if(*pnt == 0x0a) {result = ISOFS_FILE_TEXT; continue;};
 108                         if(*pnt >= 0x9 && *pnt <= 0x0d) continue;
 109                         result = ISOFS_FILE_BINARY;
 110                         break;
 111                 }
 112                 brelse(bh);
 113                 inode->u.isofs_i.i_file_format = result;
 114         }
 115 }
 116 
 117 static int isofs_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 118 {
 119         int read,left,chars;
 120         int block, blocks, offset, total_blocks;
 121         int bhrequest;
 122         int ra_blocks, max_block, nextblock;
 123         struct buffer_head ** bhb, ** bhe;
 124         struct buffer_head * bhreq[NBUF];
 125         struct buffer_head * buflist[NBUF];
 126         
 127         if (!inode) {
 128                 printk("isofs_file_read: inode = NULL\n");
 129                 return -EINVAL;
 130         }
 131         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
 132                 printk("isofs_file_read: mode = %07o\n",inode->i_mode);
 133                 return -EINVAL;
 134         }
 135         if (inode->u.isofs_i.i_file_format == ISOFS_FILE_UNKNOWN)
 136                 isofs_determine_filetype(inode);
 137         if (filp->f_pos > inode->i_size)
 138                 left = 0;
 139         else
 140                 left = inode->i_size - filp->f_pos;
 141         if (left > count)
 142                 left = count;
 143         if (left <= 0)
 144                 return 0;
 145         read = 0;
 146         block = filp->f_pos >> ISOFS_BUFFER_BITS(inode);
 147         offset = (inode->u.isofs_i.i_first_extent + filp->f_pos)
 148           & (ISOFS_BUFFER_SIZE(inode)-1);
 149         blocks = (left + offset + ISOFS_BUFFER_SIZE(inode) - 1) / ISOFS_BUFFER_SIZE(inode);
 150         bhb = bhe = buflist;
 151 
 152         ra_blocks = read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 153         if(ra_blocks > blocks) blocks = ra_blocks;
 154 
 155         /*
 156          * this is for stopping read ahead at EOF. It's  important for
 157          * reading PhotoCD's, because they have many small data tracks instead
 158          * of one big. And between two data-tracks are some unreadable sectors.
 159          * A read ahead after a EOF may try to read such an unreadable sector.
 160          *    kraxel@cs.tu-berlin.de (Gerd Knorr)
 161          */
 162         total_blocks = (inode->i_size + (1 << ISOFS_BUFFER_BITS(inode)) - 1)
 163            >> ISOFS_BUFFER_BITS(inode);
 164         if (block + blocks > total_blocks)
 165                 blocks = total_blocks - block;
 166 
 167         max_block = (inode->i_size + BLOCK_SIZE - 1)/BLOCK_SIZE;
 168         nextblock = -1;
 169 
 170         /* We do this in a two stage process.  We first try and request
 171            as many blocks as we can, then we wait for the first one to
 172            complete, and then we try and wrap up as many as are actually
 173            done.  This routine is rather generic, in that it can be used
 174            in a filesystem by substituting the appropriate function in
 175            for getblk.
 176 
 177            This routine is optimized to make maximum use of the various
 178            buffers and caches. */
 179 
 180         do {
 181                 bhrequest = 0;
 182                 while (blocks) {
 183                         int uptodate;
 184                         --blocks;
 185                         *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE(inode));
 186                         uptodate = 1;
 187                         if (*bhb && !buffer_uptodate(*bhb)) {
 188                                 uptodate = 0;
 189                                 bhreq[bhrequest++] = *bhb;
 190                               };
 191 
 192                         if (++bhb == &buflist[NBUF])
 193                                 bhb = buflist;
 194 
 195                         /* If the block we have on hand is uptodate, go ahead
 196                            and complete processing. */
 197                         if(uptodate) break;
 198 
 199                         if (bhb == bhe)
 200                                 break;
 201                       }
 202 
 203                 /* Now request them all */
 204                 if (bhrequest)
 205                   ll_rw_block(READ, bhrequest, bhreq);
 206 
 207                 do{ /* Finish off all I/O that has actually completed */
 208                   if (*bhe) {/* test for valid buffer */
 209                     wait_on_buffer(*bhe);
 210                     if (!buffer_uptodate(*bhe)) {
 211                       brelse(*bhe);
 212                       if (++bhe == &buflist[NBUF])
 213                         bhe = buflist;
 214                       left = 0;
 215                       break;
 216                     }
 217                   }
 218                   
 219                   if (left < ISOFS_BUFFER_SIZE(inode) - offset)
 220                     chars = left;
 221                   else
 222                     chars = ISOFS_BUFFER_SIZE(inode) - offset;
 223                   filp->f_pos += chars;
 224                   left -= chars;
 225                   read += chars;
 226                   if (*bhe) {
 227                     if (inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT ||
 228                         inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT_M)
 229                       unixify_to_fs(buf, offset+(*bhe)->b_data, chars, 
 230                                     inode->u.isofs_i.i_file_format);
 231                     else
 232                       memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 233                     brelse(*bhe);
 234                     buf += chars;
 235                   } else {
 236                     while (chars-->0)
 237                       put_user(0,buf++);
 238                   }
 239                   offset = 0;
 240                   if (++bhe == &buflist[NBUF])
 241                     bhe = buflist;
 242                 } while( bhe != bhb && (*bhe == 0 || !buffer_locked(*bhe)) && 
 243                         (left > 0));
 244         } while (left > 0);
 245 
 246 /* Release the read-ahead blocks */
 247         while (bhe != bhb) {
 248           if (*bhe) brelse(*bhe);
 249           if (++bhe == &buflist[NBUF])
 250             bhe = buflist;
 251         };
 252 
 253         filp->f_reada = 1;
 254 
 255         if (!read)
 256                 return -EIO;
 257         return read;
 258 }

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