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 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 };
  65 
  66 /* This is a heuristic to determine if a file is text of binary.  If it
  67  * is text, then we translate all 0x0d characters to spaces.  If the 0x0d
  68  * character is not preceeded or followed by a 0x0a, then we turn it into
  69  * a 0x0a.  A control-Z is also turned into a linefeed.
  70  */
  71 
  72 static inline void unixify_text_buffer(char * buffer, int chars, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74         while(chars--){
  75                 if(*buffer == 0x1a) *buffer = 0x0a;
  76                 if(*buffer == 0x0d){
  77                         if(mode == ISOFS_FILE_TEXT_M) *buffer = 0x0a;
  78                         if(mode == ISOFS_FILE_TEXT) *buffer = ' ';
  79                 }
  80                 buffer++;
  81         }
  82 }
  83 
  84 /*This function determines if a given file has a DOS-like text format or not*/
  85 
  86 static void isofs_determine_filetype(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88         int block;
  89         int result, i;
  90         struct buffer_head * bh;
  91         unsigned char * pnt;
  92         
  93         block = isofs_bmap(inode,0);
  94         if (block && (bh = bread(inode->i_dev,block, ISOFS_BUFFER_SIZE))) {
  95                 pnt = (char*) bh->b_data;
  96                 result = ISOFS_FILE_TEXT_M;
  97                 for(i=0;i<(inode->i_size < ISOFS_BUFFER_SIZE ? inode->i_size : ISOFS_BUFFER_SIZE);
  98                     i++,pnt++){
  99                         if(*pnt & 0x80) {result = ISOFS_FILE_BINARY; break;};
 100                         if(*pnt >= 0x20 || *pnt == 0x1a) continue;
 101                         if(*pnt == 0x0a) {result = ISOFS_FILE_TEXT; continue;};
 102                         if(*pnt >= 0x9 && *pnt <= 0x0d) continue;
 103                         result = ISOFS_FILE_BINARY;
 104                         break;
 105                 }
 106                 brelse(bh);
 107                 inode->u.isofs_i.i_file_format = result;
 108         }
 109 }
 110 
 111 /*
 112  * isofs_file_read() is also needed by the directory read-routine,
 113  * so it's not static. NOTE! reading directories directly is a bad idea,
 114  * but has to be supported for now for compatability reasons with older
 115  * versions.
 116  */
 117 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;
 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;
 147         offset = filp->f_pos & (ISOFS_BUFFER_SIZE-1);
 148         blocks = (left + offset + ISOFS_BUFFER_SIZE - 1) / ISOFS_BUFFER_SIZE;
 149         bhb = bhe = buflist;
 150 
 151         ra_blocks = read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 152         max_block = (inode->i_size + BLOCK_SIZE - 1)/BLOCK_SIZE;
 153         nextblock = -1;
 154 
 155         /* We do this in a two stage process.  We first try and request
 156            as many blocks as we can, then we wait for the first one to
 157            complete, and then we try and wrap up as many as are actually
 158            done.  This routine is rather generic, in that it can be used
 159            in a filesystem by substituting the appropriate function in
 160            for getblk.
 161 
 162            This routine is optimized to make maximum use of the various
 163            buffers and caches. */
 164 
 165         do {
 166                 bhrequest = 0;
 167                 while (blocks) {
 168                         int uptodate;
 169                         --blocks;
 170                         *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE);
 171                         uptodate = 1;
 172                         if (*bhb && !(*bhb)->b_uptodate) {
 173                                 uptodate = 0;
 174                                 bhreq[bhrequest++] = *bhb;
 175                                 nextblock = (*bhb)->b_blocknr + 1;
 176                               };
 177 
 178                         if (++bhb == &buflist[NBUF])
 179                                 bhb = buflist;
 180 
 181                         /* If the block we have on hand is uptodate, go ahead
 182                            and complete processing. */
 183                         if(bhrequest == 0 && uptodate) break;
 184 
 185                         if (bhb == bhe)
 186                                 break;
 187                       }
 188 
 189                 if(blocks == 0 && bhrequest && filp->f_reada && bhb != bhe) { 
 190                   /* If we are going to read something anyways, add in the
 191                      read-ahead blocks */
 192                   while(ra_blocks){
 193                     if (block >= max_block) break;
 194                     if(bhrequest == NBUF) break;  /* Block full */
 195                     --ra_blocks;
 196                     *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE);
 197 
 198                     if (*bhb && !(*bhb)->b_uptodate) {
 199                       if((*bhb)->b_blocknr != nextblock) {
 200                         brelse(*bhb);
 201                         break;
 202                       };
 203                       nextblock = (*bhb)->b_blocknr + 1;
 204                       bhreq[bhrequest++] = *bhb;
 205                     };
 206                     
 207                     if (++bhb == &buflist[NBUF])
 208                       bhb = buflist;
 209                     
 210                     if (bhb == bhe)
 211                       break;
 212                   };
 213                 };
 214                 /* Now request them all */
 215                 if (bhrequest)
 216                   ll_rw_block(READ, bhrequest, bhreq);
 217 
 218                 do{ /* Finish off all I/O that has actually completed */
 219                   if (*bhe) {/* test for valid buffer */
 220                     wait_on_buffer(*bhe);
 221                     if (!(*bhe)->b_uptodate) {
 222                       do {
 223                         brelse(*bhe);
 224                         if (++bhe == &buflist[NBUF])
 225                           bhe = buflist;
 226                       } while (bhe != bhb);
 227                       break;
 228                     }
 229                   }
 230                   
 231                   if (left < ISOFS_BUFFER_SIZE - offset)
 232                     chars = left;
 233                   else
 234                     chars = ISOFS_BUFFER_SIZE - offset;
 235                   filp->f_pos += chars;
 236                   left -= chars;
 237                   read += chars;
 238                   if (*bhe) {
 239                     if (inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT ||
 240                         inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT_M)
 241                       unixify_text_buffer(offset+(*bhe)->b_data,
 242                                           chars, inode->u.isofs_i.i_file_format);
 243                     memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 244                     brelse(*bhe);
 245                     buf += chars;
 246                   } else {
 247                     while (chars-->0)
 248                       put_fs_byte(0,buf++);
 249                   }
 250                   offset = 0;
 251                   if (++bhe == &buflist[NBUF])
 252                     bhe = buflist;
 253                 } while( bhe != bhb && (*bhe == 0 || !(*bhe)->b_lock) && 
 254                         (left > 0));
 255         } while (left > 0);
 256 
 257 /* Release the read-ahead blocks */
 258         while (bhe != bhb) {
 259           if (*bhe) brelse(*bhe);
 260           if (++bhe == &buflist[NBUF])
 261             bhe = buflist;
 262         };
 263 
 264         filp->f_reada = 1;
 265 
 266         if (!read)
 267                 return -EIO;
 268         return read;
 269 }

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