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 #ifdef MODULE
  12 #include <linux/module.h>
  13 #endif
  14 
  15 #include <asm/segment.h>
  16 #include <asm/system.h>
  17 
  18 #include <linux/sched.h>
  19 #include <linux/iso_fs.h>
  20 #include <linux/fcntl.h>
  21 #include <linux/kernel.h>
  22 #include <linux/errno.h>
  23 #include <linux/stat.h>
  24 #include <linux/locks.h>
  25 
  26 #include <linux/dirent.h>
  27 
  28 #define NBUF    32
  29 
  30 #define MIN(a,b) (((a)<(b))?(a):(b))
  31 #define MAX(a,b) (((a)>(b))?(a):(b))
  32 
  33 #include <linux/fs.h>
  34 #include <linux/iso_fs.h>
  35 
  36 static int isofs_file_read(struct inode *, struct file *, char *, int);
  37 
  38 /*
  39  * We have mostly NULL's here: the current defaults are ok for
  40  * the isofs filesystem.
  41  */
  42 static struct file_operations isofs_file_operations = {
  43         NULL,                   /* lseek - default */
  44         isofs_file_read,        /* read */
  45         NULL,                   /* write */
  46         NULL,                   /* readdir - bad */
  47         NULL,                   /* select - default */
  48         NULL,                   /* ioctl - default */
  49         generic_mmap,           /* mmap */
  50         NULL,                   /* no special open is needed */
  51         NULL,                   /* release */
  52         NULL                    /* fsync */
  53 };
  54 
  55 struct inode_operations isofs_file_inode_operations = {
  56         &isofs_file_operations, /* default file operations */
  57         NULL,                   /* create */
  58         NULL,                   /* lookup */
  59         NULL,                   /* link */
  60         NULL,                   /* unlink */
  61         NULL,                   /* symlink */
  62         NULL,                   /* mkdir */
  63         NULL,                   /* rmdir */
  64         NULL,                   /* mknod */
  65         NULL,                   /* rename */
  66         NULL,                   /* readlink */
  67         NULL,                   /* follow_link */
  68         isofs_bmap,             /* bmap */
  69         NULL,                   /* truncate */
  70         NULL                    /* permission */
  71 };
  72 
  73 /* This is a heuristic to determine if a file is text of binary.  If it
  74  * is text, then we translate all 0x0d characters to spaces.  If the 0x0d
  75  * character is not preceded or followed by a 0x0a, then we turn it into
  76  * a 0x0a.  A control-Z is also turned into a linefeed.
  77  */
  78 
  79 static inline void unixify_to_fs(char * outbuf, char * buffer, int chars,
     /* [previous][next][first][last][top][bottom][index][help] */
  80                                  int mode)
  81 {
  82         char outchar;
  83 
  84         while(chars--){
  85                 outchar = *buffer;
  86                 if(outchar == 0x1a) outchar = 0x0a;
  87                 if(outchar == 0x0d){
  88                         if(mode == ISOFS_FILE_TEXT_M) outchar = 0x0a;
  89                         if(mode == ISOFS_FILE_TEXT) outchar = ' ';
  90                 }
  91                 put_user(outchar, outbuf++);
  92                 buffer++;
  93         }
  94 }
  95 
  96 /*This function determines if a given file has a DOS-like text format or not*/
  97 
  98 static void isofs_determine_filetype(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  99 {
 100         int block;
 101         int result, i;
 102         struct buffer_head * bh;
 103         unsigned char * pnt;
 104         
 105         block = isofs_bmap(inode,0);
 106         if (block && (bh = bread(inode->i_dev,block, ISOFS_BUFFER_SIZE(inode)))) {
 107                 pnt = (unsigned char *) bh->b_data;
 108                 result = ISOFS_FILE_TEXT_M;
 109                 for(i=0;i<(inode->i_size < ISOFS_BUFFER_SIZE(inode) ? inode->i_size : ISOFS_BUFFER_SIZE(inode));
 110                     i++,pnt++){
 111                         if(*pnt & 0x80) {result = ISOFS_FILE_BINARY; break;};
 112                         if(*pnt >= 0x20 || *pnt == 0x1a) continue;
 113                         if(*pnt == 0x0a) {result = ISOFS_FILE_TEXT; continue;};
 114                         if(*pnt >= 0x9 && *pnt <= 0x0d) continue;
 115                         result = ISOFS_FILE_BINARY;
 116                         break;
 117                 }
 118                 brelse(bh);
 119                 inode->u.isofs_i.i_file_format = result;
 120         }
 121 }
 122 
 123 static int isofs_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125         int read,left,chars;
 126         int block, blocks, offset, total_blocks;
 127         int bhrequest;
 128         int ra_blocks, max_block, nextblock;
 129         struct buffer_head ** bhb, ** bhe;
 130         struct buffer_head * bhreq[NBUF];
 131         struct buffer_head * buflist[NBUF];
 132         
 133         if (!inode) {
 134                 printk("isofs_file_read: inode = NULL\n");
 135                 return -EINVAL;
 136         }
 137         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
 138                 printk("isofs_file_read: mode = %07o\n",inode->i_mode);
 139                 return -EINVAL;
 140         }
 141         if (inode->u.isofs_i.i_file_format == ISOFS_FILE_UNKNOWN)
 142                 isofs_determine_filetype(inode);
 143         if (filp->f_pos > inode->i_size)
 144                 left = 0;
 145         else
 146                 left = inode->i_size - filp->f_pos;
 147         if (left > count)
 148                 left = count;
 149         if (left <= 0)
 150                 return 0;
 151         read = 0;
 152         block = filp->f_pos >> ISOFS_BUFFER_BITS(inode);
 153         offset = (inode->u.isofs_i.i_first_extent + filp->f_pos)
 154           & (ISOFS_BUFFER_SIZE(inode)-1);
 155         blocks = (left + offset + ISOFS_BUFFER_SIZE(inode) - 1) / ISOFS_BUFFER_SIZE(inode);
 156         bhb = bhe = buflist;
 157 
 158         ra_blocks = read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 159         if(ra_blocks > blocks) blocks = ra_blocks;
 160 
 161         /*
 162          * this is for stopping read ahead at EOF. It's  important for
 163          * reading PhotoCD's, because they have many small data tracks instead
 164          * of one big. And between two data-tracks are some unreadable sectors.
 165          * A read ahead after a EOF may try to read such an unreadable sector.
 166          *    kraxel@cs.tu-berlin.de (Gerd Knorr)
 167          */
 168         total_blocks = (inode->i_size + (1 << ISOFS_BUFFER_BITS(inode)) - 1)
 169            >> ISOFS_BUFFER_BITS(inode);
 170         if (block + blocks > total_blocks)
 171                 blocks = total_blocks - block;
 172 
 173         max_block = (inode->i_size + BLOCK_SIZE - 1)/BLOCK_SIZE;
 174         nextblock = -1;
 175 
 176         /* We do this in a two stage process.  We first try and request
 177            as many blocks as we can, then we wait for the first one to
 178            complete, and then we try and wrap up as many as are actually
 179            done.  This routine is rather generic, in that it can be used
 180            in a filesystem by substituting the appropriate function in
 181            for getblk.
 182 
 183            This routine is optimized to make maximum use of the various
 184            buffers and caches. */
 185 
 186         do {
 187                 bhrequest = 0;
 188                 while (blocks) {
 189                         int uptodate;
 190                         --blocks;
 191                         *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE(inode));
 192                         uptodate = 1;
 193                         if (*bhb && !(*bhb)->b_uptodate) {
 194                                 uptodate = 0;
 195                                 bhreq[bhrequest++] = *bhb;
 196                               };
 197 
 198                         if (++bhb == &buflist[NBUF])
 199                                 bhb = buflist;
 200 
 201                         /* If the block we have on hand is uptodate, go ahead
 202                            and complete processing. */
 203                         if(uptodate) break;
 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                       brelse(*bhe);
 218                       if (++bhe == &buflist[NBUF])
 219                         bhe = buflist;
 220                       left = 0;
 221                       break;
 222                     }
 223                   }
 224                   
 225                   if (left < ISOFS_BUFFER_SIZE(inode) - offset)
 226                     chars = left;
 227                   else
 228                     chars = ISOFS_BUFFER_SIZE(inode) - offset;
 229                   filp->f_pos += chars;
 230                   left -= chars;
 231                   read += chars;
 232                   if (*bhe) {
 233                     if (inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT ||
 234                         inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT_M)
 235                       unixify_to_fs(buf, offset+(*bhe)->b_data, chars, 
 236                                     inode->u.isofs_i.i_file_format);
 237                     else
 238                       memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 239                     brelse(*bhe);
 240                     buf += chars;
 241                   } else {
 242                     while (chars-->0)
 243                       put_user(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] */