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

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