root/fs/isofs/file.c

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

DEFINITIONS

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

   1 /*
   2  *  linux/fs/isofs/file.c
   3  *
   4  *  (C) 1992  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    16
  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         NULL,                   /* no special open is needed */
  46         NULL,                   /* release */
  47         NULL                    /* fsync */
  48 };
  49 
  50 struct inode_operations isofs_file_inode_operations = {
  51         &isofs_file_operations, /* default file operations */
  52         NULL,                   /* create */
  53         NULL,                   /* lookup */
  54         NULL,                   /* link */
  55         NULL,                   /* unlink */
  56         NULL,                   /* symlink */
  57         NULL,                   /* mkdir */
  58         NULL,                   /* rmdir */
  59         NULL,                   /* mknod */
  60         NULL,                   /* rename */
  61         NULL,                   /* readlink */
  62         NULL,                   /* follow_link */
  63         isofs_bmap,             /* bmap */
  64         NULL,                   /* truncate */
  65         NULL                    /* permission */
  66 };
  67 
  68 /* This is a heuristic to determine if a file is text of binary.  If it
  69  * is text, then we translate all 0x0d characters to spaces.  If the 0x0d
  70  * character is not preceeded or followed by a 0x0a, then we turn it into
  71  * a 0x0a.  A control-Z is also turned into a linefeed.
  72  */
  73 
  74 static inline void unixify_text_buffer(char * buffer, int chars, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76         while(chars--){
  77                 if(*buffer == 0x1a) *buffer = 0x0a;
  78                 if(*buffer == 0x0d){
  79                         if(mode == ISOFS_FILE_TEXT_M) *buffer = 0x0a;
  80                         if(mode == ISOFS_FILE_TEXT) *buffer = ' ';
  81                 }
  82                 buffer++;
  83         }
  84 }
  85 
  86 /*This function determines if a given file has a DOS-like text format or not*/
  87 
  88 static void isofs_determine_filetype(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90         int block;
  91         int result, i;
  92         struct buffer_head * bh;
  93         unsigned char * pnt;
  94         
  95         block = isofs_bmap(inode,0);
  96         if (block && (bh = bread(inode->i_dev,block, ISOFS_BUFFER_SIZE))) {
  97                 pnt = (char*) bh->b_data;
  98                 result = ISOFS_FILE_TEXT_M;
  99                 for(i=0;i<(inode->i_size < ISOFS_BUFFER_SIZE ? inode->i_size : ISOFS_BUFFER_SIZE);
 100                     i++,pnt++){
 101                         if(*pnt & 0x80) {result = ISOFS_FILE_BINARY; break;};
 102                         if(*pnt >= 0x20 || *pnt == 0x1a) continue;
 103                         if(*pnt == 0x0a) {result = ISOFS_FILE_TEXT; continue;};
 104                         if(*pnt >= 0x9 && *pnt <= 0x0d) continue;
 105                         result = ISOFS_FILE_BINARY;
 106                         break;
 107                 }
 108                 brelse(bh);
 109                 inode->u.isofs_i.i_file_format = result;
 110         }
 111 }
 112 
 113 static int isofs_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 114 {
 115         int read,left,chars;
 116         int block, blocks, offset;
 117         int bhrequest;
 118         int ra_blocks, max_block, nextblock;
 119         struct buffer_head ** bhb, ** bhe;
 120         struct buffer_head * bhreq[NBUF];
 121         struct buffer_head * buflist[NBUF];
 122         
 123         if (!inode) {
 124                 printk("isofs_file_read: inode = NULL\n");
 125                 return -EINVAL;
 126         }
 127         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
 128                 printk("isofs_file_read: mode = %07o\n",inode->i_mode);
 129                 return -EINVAL;
 130         }
 131         if (inode->u.isofs_i.i_file_format == ISOFS_FILE_UNKNOWN)
 132                 isofs_determine_filetype(inode);
 133         if (filp->f_pos > inode->i_size)
 134                 left = 0;
 135         else
 136                 left = inode->i_size - filp->f_pos;
 137         if (left > count)
 138                 left = count;
 139         if (left <= 0)
 140                 return 0;
 141         read = 0;
 142         block = filp->f_pos >> ISOFS_BUFFER_BITS;
 143         offset = filp->f_pos & (ISOFS_BUFFER_SIZE-1);
 144         blocks = (left + offset + ISOFS_BUFFER_SIZE - 1) / ISOFS_BUFFER_SIZE;
 145         bhb = bhe = buflist;
 146 
 147         ra_blocks = read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 148         max_block = (inode->i_size + BLOCK_SIZE - 1)/BLOCK_SIZE;
 149         nextblock = -1;
 150 
 151         /* We do this in a two stage process.  We first try and request
 152            as many blocks as we can, then we wait for the first one to
 153            complete, and then we try and wrap up as many as are actually
 154            done.  This routine is rather generic, in that it can be used
 155            in a filesystem by substituting the appropriate function in
 156            for getblk.
 157 
 158            This routine is optimized to make maximum use of the various
 159            buffers and caches. */
 160 
 161         do {
 162                 bhrequest = 0;
 163                 while (blocks) {
 164                         int uptodate;
 165                         --blocks;
 166                         *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE);
 167                         uptodate = 1;
 168                         if (*bhb && !(*bhb)->b_uptodate) {
 169                                 uptodate = 0;
 170                                 bhreq[bhrequest++] = *bhb;
 171                                 nextblock = (*bhb)->b_blocknr + 1;
 172                               };
 173 
 174                         if (++bhb == &buflist[NBUF])
 175                                 bhb = buflist;
 176 
 177                         /* If the block we have on hand is uptodate, go ahead
 178                            and complete processing. */
 179                         if(bhrequest == 0 && uptodate) break;
 180 
 181                         if (bhb == bhe)
 182                                 break;
 183                       }
 184 
 185                 if(blocks == 0 && bhrequest && filp->f_reada && bhb != bhe) { 
 186                   /* If we are going to read something anyways, add in the
 187                      read-ahead blocks */
 188                   while(ra_blocks){
 189                     if (block >= max_block) break;
 190                     if(bhrequest == NBUF) break;  /* Block full */
 191                     --ra_blocks;
 192                     *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE);
 193 
 194                     if (*bhb && !(*bhb)->b_uptodate) {
 195                       if((*bhb)->b_blocknr != nextblock) {
 196                         brelse(*bhb);
 197                         break;
 198                       };
 199                       nextblock = (*bhb)->b_blocknr + 1;
 200                       bhreq[bhrequest++] = *bhb;
 201                     };
 202                     
 203                     if (++bhb == &buflist[NBUF])
 204                       bhb = buflist;
 205                     
 206                     if (bhb == bhe)
 207                       break;
 208                   };
 209                 };
 210                 /* Now request them all */
 211                 if (bhrequest)
 212                   ll_rw_block(READ, bhrequest, bhreq);
 213 
 214                 do{ /* Finish off all I/O that has actually completed */
 215                   if (*bhe) {/* test for valid buffer */
 216                     wait_on_buffer(*bhe);
 217                     if (!(*bhe)->b_uptodate) {
 218                       left = 0;
 219                       break;
 220                     }
 221                   }
 222                   
 223                   if (left < ISOFS_BUFFER_SIZE - offset)
 224                     chars = left;
 225                   else
 226                     chars = ISOFS_BUFFER_SIZE - offset;
 227                   filp->f_pos += chars;
 228                   left -= chars;
 229                   read += chars;
 230                   if (*bhe) {
 231                     if (inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT ||
 232                         inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT_M)
 233                       unixify_text_buffer(offset+(*bhe)->b_data,
 234                                           chars, inode->u.isofs_i.i_file_format);
 235                     memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 236                     brelse(*bhe);
 237                     buf += chars;
 238                   } else {
 239                     while (chars-->0)
 240                       put_fs_byte(0,buf++);
 241                   }
 242                   offset = 0;
 243                   if (++bhe == &buflist[NBUF])
 244                     bhe = buflist;
 245                 } while( bhe != bhb && (*bhe == 0 || !(*bhe)->b_lock) && 
 246                         (left > 0));
 247         } while (left > 0);
 248 
 249 /* Release the read-ahead blocks */
 250         while (bhe != bhb) {
 251           if (*bhe) brelse(*bhe);
 252           if (++bhe == &buflist[NBUF])
 253             bhe = buflist;
 254         };
 255 
 256         filp->f_reada = 1;
 257 
 258         if (!read)
 259                 return -EIO;
 260         return read;
 261 }

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