From: Andy P. <at...@us...> - 2002-04-09 14:08:31
|
Update of /cvsroot/linux-vax/kernel-2.4/fs/isofs In directory usw-pr-cvs1:/tmp/cvs-serv27691/isofs Modified Files: Makefile inode.c joliet.c rock.c rock.h util.c Added Files: compress.c zisofs.h Log Message: sync 2.4.15 commit 11 --- NEW FILE --- /* -*- linux-c -*- ------------------------------------------------------- * * * Copyright 2001 H. Peter Anvin - All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, * USA; either version 2 of the License, or (at your option) any later * version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ /* * linux/fs/isofs/compress.c * * Transparent decompression of files on an iso9660 filesystem */ #include <linux/config.h> #include <linux/module.h> #include <linux/stat.h> #include <linux/sched.h> #include <linux/iso_fs.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/locks.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/cdrom.h> #include <linux/init.h> #include <linux/nls.h> #include <linux/ctype.h> #include <linux/smp_lock.h> #include <linux/blkdev.h> #include <linux/vmalloc.h> #include <linux/zlib_fs.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/semaphore.h> #include "zisofs.h" /* This should probably be global. */ static char zisofs_sink_page[PAGE_CACHE_SIZE]; /* * This contains the zlib memory allocation and the mutex for the * allocation; this avoids failures at block-decompression time. */ static void *zisofs_zlib_workspace; static struct semaphore zisofs_zlib_semaphore; /* * When decompressing, we typically obtain more than one page * per reference. We inject the additional pages into the page * cache as a form of readahead. */ static int zisofs_readpage(struct file *file, struct page *page) { struct inode *inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; unsigned int maxpage, xpage, fpage, blockindex; unsigned long offset; unsigned long blockptr, blockendptr, cstart, cend, csize; struct buffer_head *bh, *ptrbh[2]; unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); unsigned int bufshift = ISOFS_BUFFER_BITS(inode); unsigned long bufmask = bufsize - 1; int err = -EIO; int i; unsigned int header_size = inode->u.isofs_i.i_format_parm[0]; unsigned int zisofs_block_shift = inode->u.isofs_i.i_format_parm[1]; /* unsigned long zisofs_block_size = 1UL << zisofs_block_shift; */ unsigned int zisofs_block_page_shift = zisofs_block_shift-PAGE_CACHE_SHIFT; unsigned long zisofs_block_pages = 1UL << zisofs_block_page_shift; unsigned long zisofs_block_page_mask = zisofs_block_pages-1; struct page *pages[zisofs_block_pages]; unsigned long index = page->index; int indexblocks; /* We have already been given one page, this is the one we must do. */ xpage = index & zisofs_block_page_mask; pages[xpage] = page; /* The remaining pages need to be allocated and inserted */ offset = index & ~zisofs_block_page_mask; blockindex = offset >> zisofs_block_page_shift; maxpage = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; maxpage = min(zisofs_block_pages, maxpage-offset); for ( i = 0 ; i < maxpage ; i++, offset++ ) { if ( i != xpage ) { pages[i] = grab_cache_page_nowait(mapping, offset); } page = pages[i]; if ( page ) { ClearPageError(page); kmap(page); } } /* This is the last page filled, plus one; used in case of abort. */ fpage = 0; /* Find the pointer to this specific chunk */ /* Note: we're not using isonum_731() here because the data is known aligned */ /* Note: header_size is in 32-bit words (4 bytes) */ blockptr = (header_size + blockindex) << 2; blockendptr = blockptr + 4; indexblocks = ((blockptr^blockendptr) >> bufshift) ? 2 : 1; ptrbh[0] = ptrbh[1] = 0; if ( isofs_get_blocks(inode, blockptr >> bufshift, ptrbh, indexblocks) != indexblocks ) { if ( ptrbh[0] ) brelse(ptrbh[0]); printk(KERN_DEBUG "zisofs: Null buffer on reading block table, inode = %lu, block = %lu\n", inode->i_ino, blockptr >> bufshift); goto eio; } ll_rw_block(READ, indexblocks, ptrbh); bh = ptrbh[0]; if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) { printk(KERN_DEBUG "zisofs: Failed to read block table, inode = %lu, block = %lu\n", inode->i_ino, blockptr >> bufshift); if ( ptrbh[1] ) brelse(ptrbh[1]); goto eio; } cstart = le32_to_cpu(*(u32 *)(bh->b_data + (blockptr & bufmask))); if ( indexblocks == 2 ) { /* We just crossed a block boundary. Switch to the next block */ brelse(bh); bh = ptrbh[1]; if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) { printk(KERN_DEBUG "zisofs: Failed to read block table, inode = %lu, block = %lu\n", inode->i_ino, blockendptr >> bufshift); goto eio; } } cend = le32_to_cpu(*(u32 *)(bh->b_data + (blockendptr & bufmask))); brelse(bh); csize = cend-cstart; /* Now page[] contains an array of pages, any of which can be NULL, and the locks on which we hold. We should now read the data and release the pages. If the pages are NULL the decompressed data for that particular page should be discarded. */ if ( csize == 0 ) { /* This data block is empty. */ for ( fpage = 0 ; fpage < maxpage ; fpage++ ) { if ( (page = pages[fpage]) != NULL ) { memset(page_address(page), 0, PAGE_CACHE_SIZE); flush_dcache_page(page); SetPageUptodate(page); kunmap(page); UnlockPage(page); if ( fpage == xpage ) err = 0; /* The critical page */ else page_cache_release(page); } } } else { /* This data block is compressed. */ z_stream stream; int bail = 0, left_out = -1; int zerr; int needblocks = (csize + (cstart & bufmask) + bufmask) >> bufshift; int haveblocks; struct buffer_head *bhs[needblocks+1]; struct buffer_head **bhptr; /* Because zlib is not thread-safe, do all the I/O at the top. */ blockptr = cstart >> bufshift; memset(bhs, 0, (needblocks+1)*sizeof(struct buffer_head *)); haveblocks = isofs_get_blocks(inode, blockptr, bhs, needblocks); ll_rw_block(READ, haveblocks, bhs); bhptr = &bhs[0]; bh = *bhptr++; /* First block is special since it may be fractional. We also wait for it before grabbing the zlib semaphore; odds are that the subsequent blocks are going to come in in short order so we don't hold the zlib semaphore longer than necessary. */ if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) { printk(KERN_DEBUG "zisofs: Hit null buffer, fpage = %d, xpage = %d, csize = %ld\n", fpage, xpage, csize); goto b_eio; } stream.next_in = bh->b_data + (cstart & bufmask); stream.avail_in = min(bufsize-(cstart & bufmask), csize); csize -= stream.avail_in; stream.workspace = zisofs_zlib_workspace; down(&zisofs_zlib_semaphore); zerr = zlib_fs_inflateInit(&stream); if ( zerr != Z_OK ) { if ( err && zerr == Z_MEM_ERROR ) err = -ENOMEM; printk(KERN_DEBUG "zisofs: zisofs_inflateInit returned %d\n", zerr); goto z_eio; } while ( !bail && fpage < maxpage ) { page = pages[fpage]; if ( page ) stream.next_out = page_address(page); else stream.next_out = (void *)&zisofs_sink_page; stream.avail_out = PAGE_CACHE_SIZE; while ( stream.avail_out ) { int ao, ai; if ( stream.avail_in == 0 && left_out ) { if ( !csize ) { printk(KERN_WARNING "zisofs: ZF read beyond end of input\n"); bail = 1; break; } else { bh = *bhptr++; if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) { /* Reached an EIO */ printk(KERN_DEBUG "zisofs: Hit null buffer, fpage = %d, xpage = %d, csize = %ld\n", fpage, xpage, csize); bail = 1; break; } stream.next_in = bh->b_data; stream.avail_in = min(csize,bufsize); csize -= stream.avail_in; } } ao = stream.avail_out; ai = stream.avail_in; zerr = zlib_fs_inflate(&stream, Z_SYNC_FLUSH); left_out = stream.avail_out; if ( zerr == Z_BUF_ERROR && stream.avail_in == 0 ) continue; if ( zerr != Z_OK ) { /* EOF, error, or trying to read beyond end of input */ if ( err && zerr == Z_MEM_ERROR ) err = -ENOMEM; if ( zerr != Z_STREAM_END ) printk(KERN_DEBUG "zisofs: zisofs_inflate returned %d, inode = %lu, index = %lu, fpage = %d, xpage = %d, avail_in = %d, avail_out = %d, ai = %d, ao = %d\n", zerr, inode->i_ino, index, fpage, xpage, stream.avail_in, stream.avail_out, ai, ao); bail = 1; break; } } if ( stream.avail_out && zerr == Z_STREAM_END ) { /* Fractional page written before EOF. This may be the last page in the file. */ memset(stream.next_out, 0, stream.avail_out); stream.avail_out = 0; } if ( !stream.avail_out ) { /* This page completed */ if ( page ) { flush_dcache_page(page); SetPageUptodate(page); kunmap(page); UnlockPage(page); if ( fpage == xpage ) err = 0; /* The critical page */ else page_cache_release(page); } fpage++; } } zlib_fs_inflateEnd(&stream); z_eio: up(&zisofs_zlib_semaphore); b_eio: for ( i = 0 ; i < haveblocks ; i++ ) { if ( bhs[i] ) brelse(bhs[i]); } } eio: /* Release any residual pages, do not SetPageUptodate */ while ( fpage < maxpage ) { page = pages[fpage]; if ( page ) { flush_dcache_page(page); if ( fpage == xpage ) SetPageError(page); kunmap(page); UnlockPage(page); if ( fpage != xpage ) page_cache_release(page); } fpage++; } /* At this point, err contains 0 or -EIO depending on the "critical" page */ return err; } struct address_space_operations zisofs_aops = { readpage: zisofs_readpage, /* No sync_page operation supported? */ /* No bmap operation supported */ }; static int initialized = 0; int __init zisofs_init(void) { if ( initialized ) { printk("zisofs_init: called more than once\n"); return 0; } zisofs_zlib_workspace = vmalloc(zlib_fs_inflate_workspacesize()); if ( !zisofs_zlib_workspace ) return -ENOMEM; init_MUTEX(&zisofs_zlib_semaphore); initialized = 1; return 0; } void __exit zisofs_cleanup(void) { if ( !initialized ) { printk("zisofs_cleanup: called without initialization\n"); return; } vfree(zisofs_zlib_workspace); initialized = 0; } --- NEW FILE --- /* ----------------------------------------------------------------------- * * * Copyright 2001 H. Peter Anvin - All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, * USA; either version 2 of the License, or (at your option) any later * version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ /* * Prototypes for functions exported from the compressed isofs subsystem */ #ifdef CONFIG_ZISOFS extern struct address_space_operations zisofs_aops; extern int __init zisofs_init(void); extern void __exit zisofs_cleanup(void); #endif Index: Makefile =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/isofs/Makefile,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- Makefile 14 Jan 2001 16:26:08 -0000 1.1.1.1 +++ Makefile 9 Apr 2002 13:11:18 -0000 1.2 @@ -11,7 +11,10 @@ obj-y := namei.o inode.o dir.o util.o rock.o obj-$(CONFIG_JOLIET) += joliet.o +obj-$(CONFIG_ZISOFS) += compress.o obj-m := $(O_TARGET) + +CFLAGS_compress.o := -I $(TOPDIR)/fs/inflate_fs include $(TOPDIR)/Rules.make Index: inode.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/isofs/inode.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- inode.c 25 Feb 2001 23:14:46 -0000 1.1.1.2 +++ inode.c 9 Apr 2002 13:11:18 -0000 1.2 @@ -27,10 +27,13 @@ #include <linux/nls.h> #include <linux/ctype.h> #include <linux/smp_lock.h> +#include <linux/blkdev.h> #include <asm/system.h> #include <asm/uaccess.h> +#include "zisofs.h" + /* * We have no support for "multi volume" CDs, but more and more disks carry * wrong information within the volume descriptors. @@ -108,6 +111,7 @@ char joliet; char cruft; char unhide; + char nocompress; unsigned char check; unsigned int blocksize; mode_t mode; @@ -277,6 +281,7 @@ popt->cruft = 'n'; popt->unhide = 'n'; popt->check = 'u'; /* unset */ + popt->nocompress = 0; popt->blocksize = 1024; popt->mode = S_IRUGO | S_IXUGO; /* r-x for all. The disc could be shared with DOS machines so @@ -310,6 +315,10 @@ popt->utf8 = 1; continue; } + if (strncmp(this_char,"nocompress",10) == 0) { + popt->nocompress = 1; + continue; + } if ((value = strchr(this_char,'=')) != NULL) *value++ = 0; @@ -493,21 +502,21 @@ printk("iocharset = %s\n", opt.iocharset); #endif - /* - * First of all, get the hardware blocksize for this device. - * If we don't know what it is, or the hardware blocksize is - * larger than the blocksize the user specified, then use - * that value. - */ - blocksize = get_hardblocksize(dev); - if(blocksize > opt.blocksize) { - /* - * Force the blocksize we are going to use to be the - * hardware blocksize. - */ - opt.blocksize = blocksize; + /* + * First of all, get the hardware blocksize for this device. + * If we don't know what it is, or the hardware blocksize is + * larger than the blocksize the user specified, then use + * that value. + */ + blocksize = get_hardsect_size(dev); + if(blocksize > opt.blocksize) { + /* + * Force the blocksize we are going to use to be the + * hardware blocksize. + */ + opt.blocksize = blocksize; } - + blocksize_bits = 0; { int i = opt.blocksize; @@ -616,7 +625,7 @@ #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (isonum_723 (h_pri->volume_set_size) != 1) goto out_no_support; -#endif IGNORE_WRONG_MULTI_VOLUME_SPECS +#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */ s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size); s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size); @@ -625,7 +634,7 @@ #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (isonum_723 (pri->volume_set_size) != 1) goto out_no_support; -#endif IGNORE_WRONG_MULTI_VOLUME_SPECS +#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */ s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size); s->u.isofs_sb.s_max_size = isonum_733(pri->volume_space_size); @@ -663,6 +672,9 @@ s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */; + /* Set this for reference. Its not currently used except on write + which we don't have .. */ + /* RDE: data zone now byte offset! */ first_data_zone = ((isonum_733 (rootp->extent) + @@ -740,7 +752,7 @@ if (! s->u.isofs_sb.s_nls_iocharset) { /* Fail only if explicit charset specified */ if (opt.iocharset) - goto out_freebh; + goto out_unlock; s->u.isofs_sb.s_nls_iocharset = load_nls_default(); } } @@ -748,11 +760,13 @@ s->s_op = &isofs_sops; s->u.isofs_sb.s_mapping = opt.map; s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 2 : 0); + s->u.isofs_sb.s_rock_offset = -1; /* initial offset, will guess until SP is found*/ s->u.isofs_sb.s_cruft = opt.cruft; s->u.isofs_sb.s_unhide = opt.unhide; s->u.isofs_sb.s_uid = opt.uid; s->u.isofs_sb.s_gid = opt.gid; s->u.isofs_sb.s_utf8 = opt.utf8; + s->u.isofs_sb.s_nocompress = opt.nocompress; /* * It would be incredibly stupid to allow people to mark every file * on the disk as suid, so we merely allow them to set the default @@ -869,93 +883,108 @@ return 0; } -/* Life is simpler than for other filesystem since we never - * have to create a new block, only find an existing one. +/* + * Get a set of blocks; filling in buffer_heads if already allocated + * or getblk() if they are not. Returns the number of blocks inserted + * (0 == error.) */ -static int isofs_get_block(struct inode *inode, long iblock, - struct buffer_head *bh_result, int create) +int isofs_get_blocks(struct inode *inode, long iblock, + struct buffer_head **bh_result, unsigned long nblocks) { unsigned long b_off; unsigned offset, sect_size; unsigned int firstext; unsigned long nextino; - int i, err; + int section, rv; + unsigned int blocksize = inode->i_sb->s_blocksize; lock_kernel(); - err = -EROFS; - if (create) - goto abort_create_attempted; - - err = -EIO; - if (iblock < 0) - goto abort_negative; + rv = 0; + if (iblock < 0) { + printk("isofs_get_blocks: block < 0\n"); + goto abort; + } b_off = iblock; - - /* If we are *way* beyond the end of the file, print a message. - * Access beyond the end of the file up to the next page boundary - * is normal, however because of the way the page cache works. - * In this case, we just return 0 so that we can properly fill - * the page with useless information without generating any - * I/O errors. - */ - if (b_off > ((inode->i_size + PAGE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) - goto abort_beyond_end; - + offset = 0; firstext = inode->u.isofs_i.i_first_extent; sect_size = inode->u.isofs_i.i_section_size >> ISOFS_BUFFER_BITS(inode); nextino = inode->u.isofs_i.i_next_section_ino; + section = 0; - i = 0; - if (nextino) { - while (b_off >= (offset + sect_size)) { - struct inode *ninode; - - offset += sect_size; - if (nextino == 0) - goto abort; - ninode = iget(inode->i_sb, nextino); - if (!ninode) + while ( nblocks ) { + /* If we are *way* beyond the end of the file, print a message. + * Access beyond the end of the file up to the next page boundary + * is normal, however because of the way the page cache works. + * In this case, we just return 0 so that we can properly fill + * the page with useless information without generating any + * I/O errors. + */ + if (b_off > ((inode->i_size + PAGE_CACHE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) { + printk("isofs_get_blocks: block >= EOF (%ld, %ld)\n", + iblock, (unsigned long) inode->i_size); + goto abort; + } + + if (nextino) { + while (b_off >= (offset + sect_size)) { + struct inode *ninode; + + offset += sect_size; + if (nextino == 0) + goto abort; + ninode = iget(inode->i_sb, nextino); + if (!ninode) + goto abort; + firstext = ninode->u.isofs_i.i_first_extent; + sect_size = ninode->u.isofs_i.i_section_size; + nextino = ninode->u.isofs_i.i_next_section_ino; + iput(ninode); + + if (++section > 100) { + printk("isofs_get_blocks: More than 100 file sections ?!?, aborting...\n"); + printk("isofs_get_blocks: ino=%lu block=%ld firstext=%u sect_size=%u nextino=%lu\n", + inode->i_ino, iblock, firstext, (unsigned) sect_size, nextino); + goto abort; + } + } + } + + if ( *bh_result ) { + (*bh_result)->b_dev = inode->i_dev; + (*bh_result)->b_blocknr = firstext + b_off - offset; + (*bh_result)->b_state |= (1UL << BH_Mapped); + } else { + *bh_result = getblk(inode->i_dev, firstext+b_off-offset, blocksize); + if ( !*bh_result ) goto abort; - firstext = ninode->u.isofs_i.i_first_extent; - sect_size = ninode->u.isofs_i.i_section_size; - nextino = ninode->u.isofs_i.i_next_section_ino; - iput(ninode); - - if (++i > 100) - goto abort_too_many_sections; } + bh_result++; /* Next buffer head */ + b_off++; /* Next buffer offset */ + nblocks--; + rv++; } - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = firstext + b_off - offset; - bh_result->b_state |= (1UL << BH_Mapped); - err = 0; abort: unlock_kernel(); - return err; + return rv; +} -abort_create_attempted: - printk("isofs_get_block: Kernel tries to allocate a block\n"); - goto abort; - -abort_negative: - printk("isofs_get_block: block < 0\n"); - goto abort; - -abort_beyond_end: - printk("isofs_get_block: block >= EOF (%ld, %ld)\n", - iblock, (unsigned long) inode->i_size); - goto abort; - -abort_too_many_sections: - printk("isofs_get_block: More than 100 file sections ?!?, aborting...\n"); - printk("isofs_get_block: ino=%lu block=%ld firstext=%u sect_size=%u nextino=%lu\n", - inode->i_ino, iblock, firstext, (unsigned) sect_size, nextino); - goto abort; +/* + * Used by the standard interfaces. + */ +static int isofs_get_block(struct inode *inode, long iblock, + struct buffer_head *bh_result, int create) +{ + if ( create ) { + printk("isofs_get_block: Kernel tries to allocate a block\n"); + return -EROFS; + } + + return isofs_get_blocks(inode, iblock, &bh_result, 1) ? 0 : -EIO; } static int isofs_bmap(struct inode *inode, int block) @@ -1146,6 +1175,9 @@ de = tmpde; } + /* Assume it is a normal-format file unless told otherwise */ + inode->u.isofs_i.i_file_format = isofs_file_normal; + if (de->flags[-high_sierra] & 2) { inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR; inode->i_nlink = 1; /* Set to 1. We know there are 2, but @@ -1179,11 +1211,14 @@ inode->i_size = isonum_733 (de->size); } - /* There are defective discs out there - we do this to protect - ourselves. A cdrom will never contain more than 800Mb - .. but a DVD may be up to 1Gig (Ulrich Habel) */ - - if ((inode->i_size < 0 || inode->i_size > 1073741824) && + /* + * The ISO-9660 filesystem only stores 32 bits for file size. + * mkisofs handles files up to 2GB-2 = 2147483646 = 0x7FFFFFFE bytes + * in size. This is according to the large file summit paper from 1996. + * WARNING: ISO-9660 filesystems > 1 GB and even > 2 GB are fully + * legal. Do not prevent to use DVD's sch...@fo... + */ + if ((inode->i_size < 0 || inode->i_size > 0x7FFFFFFE) && inode->i_sb->u.isofs_sb.s_cruft == 'n') { printk(KERN_WARNING "Warning: defective CD-ROM. " "Enabling \"cruft\" mount option.\n"); @@ -1229,6 +1264,10 @@ inode->u.isofs_i.i_first_extent = (isonum_733 (de->extent) + isonum_711 (de->ext_attr_length)); + /* Set the number of blocks for stat() - should be done before RR */ + inode->i_blksize = PAGE_CACHE_SIZE; /* For stat() only */ + inode->i_blocks = (inode->i_size + 511) >> 9; + /* * Now test for possible Rock Ridge extensions which will override * some of these numbers in the inode structure. @@ -1268,7 +1307,16 @@ { if (S_ISREG(inode->i_mode)) { inode->i_fop = &generic_ro_fops; - inode->i_data.a_ops = &isofs_aops; + switch ( inode->u.isofs_i.i_file_format ) { +#ifdef CONFIG_ZISOFS + case isofs_file_compressed: + inode->i_data.a_ops = &zisofs_aops; + break; +#endif + default: + inode->i_data.a_ops = &isofs_aops; + break; + } } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &isofs_dir_inode_operations; inode->i_fop = &isofs_dir_operations; @@ -1328,15 +1376,27 @@ static int __init init_iso9660_fs(void) { +#ifdef CONFIG_ZISOFS + int err; + + err = zisofs_init(); + if ( err ) + return err; +#endif return register_filesystem(&iso9660_fs_type); } static void __exit exit_iso9660_fs(void) { unregister_filesystem(&iso9660_fs_type); +#ifdef CONFIG_ZISOFS + zisofs_cleanup(); +#endif } EXPORT_NO_SYMBOLS; module_init(init_iso9660_fs) module_exit(exit_iso9660_fs) +MODULE_LICENSE("GPL"); + Index: joliet.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/isofs/joliet.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- joliet.c 25 Feb 2001 23:14:46 -0000 1.1.1.2 +++ joliet.c 9 Apr 2002 13:11:18 -0000 1.2 @@ -10,6 +10,7 @@ #include <linux/nls.h> #include <linux/slab.h> #include <linux/iso_fs.h> +#include <asm/unaligned.h> /* * Convert Unicode 16 to UTF8 or ASCII. @@ -17,15 +18,15 @@ static int uni16_to_x8(unsigned char *ascii, u16 *uni, int len, struct nls_table *nls) { - wchar_t *ip; + wchar_t *ip, ch; unsigned char *op; ip = uni; op = ascii; - while (*ip && len) { + while ((ch = get_unaligned(ip)) && len) { int llen; - wchar_t ch = be16_to_cpu(*ip); + ch = be16_to_cpu(ch); if ((llen = nls->uni2char(ch, op, NLS_MAX_CHARSET_SIZE)) > 0) op += llen; else Index: rock.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/isofs/rock.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- rock.c 25 Feb 2001 23:14:46 -0000 1.1.1.2 +++ rock.c 9 Apr 2002 13:11:18 -0000 1.2 @@ -24,15 +24,15 @@ * returns a symbolic link name, and a fourth one returns the extent number * for the file. */ -#define SIG(A,B) ((A << 8) | B) +#define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ /* This is a way of ensuring that we have something in the system use fields that is compatible with Rock Ridge */ #define CHECK_SP(FAIL) \ if(rr->u.SP.magic[0] != 0xbe) FAIL; \ - if(rr->u.SP.magic[1] != 0xef) FAIL; - + if(rr->u.SP.magic[1] != 0xef) FAIL; \ + inode->i_sb->u.isofs_sb.s_rock_offset=rr->u.SP.skip; /* We define a series of macros because each function must do exactly the same thing in certain places. We use the macros to ensure that everything is done correctly */ @@ -50,7 +50,14 @@ {LEN= sizeof(struct iso_directory_record) + DE->name_len[0]; \ if(LEN & 1) LEN++; \ CHR = ((unsigned char *) DE) + LEN; \ - LEN = *((unsigned char *) DE) - LEN;} + LEN = *((unsigned char *) DE) - LEN; \ + if (inode->i_sb->u.isofs_sb.s_rock_offset!=-1) \ + { \ + LEN-=inode->i_sb->u.isofs_sb.s_rock_offset; \ + CHR+=inode->i_sb->u.isofs_sb.s_rock_offset; \ + if (LEN<0) LEN=0; \ + } \ +} #define MAYBE_CONTINUE(LABEL,DEV) \ {if (buffer) kfree(buffer); \ @@ -106,7 +113,7 @@ while (len > 1){ /* There may be one byte for padding somewhere */ rr = (struct rock_ridge *) chr; if (rr->len == 0) goto out; /* Something got screwed up here */ - sig = (chr[0] << 8) + chr[1]; + sig = isonum_721(chr); chr += rr->len; len -= rr->len; @@ -167,7 +174,7 @@ while (len > 1){ /* There may be one byte for padding somewhere */ rr = (struct rock_ridge *) chr; if (rr->len == 0) goto out; /* Something got screwed up here */ - sig = (chr[0] << 8) + chr[1]; + sig = isonum_721(chr); chr += rr->len; len -= rr->len; @@ -220,8 +227,8 @@ return 0; } -int parse_rock_ridge_inode(struct iso_directory_record * de, - struct inode * inode){ +int parse_rock_ridge_inode_internal(struct iso_directory_record * de, + struct inode * inode,int regard_xa){ int len; unsigned char * chr; int symlink_len = 0; @@ -230,6 +237,13 @@ if (!inode->i_sb->u.isofs_sb.s_rock) return 0; SETUP_ROCK_RIDGE(de, chr, len); + if (regard_xa) + { + chr+=14; + len-=14; + if (len<0) len=0; + }; + repeat: { int cnt, sig; @@ -240,15 +254,17 @@ while (len > 1){ /* There may be one byte for padding somewhere */ rr = (struct rock_ridge *) chr; if (rr->len == 0) goto out; /* Something got screwed up here */ - sig = (chr[0] << 8) + chr[1]; + sig = isonum_721(chr); chr += rr->len; len -= rr->len; switch(sig){ +#ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ case SIG('R','R'): if((rr->u.RR.flags[0] & (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) goto out; break; +#endif case SIG('S','P'): CHECK_SP(goto out); break; @@ -361,11 +377,36 @@ inode->i_gid = reloc->i_gid; inode->i_rdev = reloc->i_rdev; inode->i_size = reloc->i_size; + inode->i_blocks = reloc->i_blocks; inode->i_atime = reloc->i_atime; inode->i_ctime = reloc->i_ctime; inode->i_mtime = reloc->i_mtime; iput(reloc); break; +#ifdef CONFIG_ZISOFS + case SIG('Z','F'): + if ( !inode->i_sb->u.isofs_sb.s_nocompress ) { + int algo; + algo = isonum_721(rr->u.ZF.algorithm); + if ( algo == SIG('p','z') ) { + int block_shift = isonum_711(&rr->u.ZF.parms[1]); + if ( block_shift < PAGE_CACHE_SHIFT || block_shift > 17 ) { + printk(KERN_WARNING "isofs: Can't handle ZF block size of 2^%d\n", block_shift); + } else { + /* Note: we don't change i_blocks here */ + inode->u.isofs_i.i_file_format = isofs_file_compressed; + /* Parameters to compression algorithm (header size, block size) */ + inode->u.isofs_i.i_format_parm[0] = isonum_711(&rr->u.ZF.parms[0]); + inode->u.isofs_i.i_format_parm[1] = isonum_711(&rr->u.ZF.parms[1]); + inode->i_size = isonum_733(rr->u.ZF.real_size); + } + } else { + printk(KERN_WARNING "isofs: Unknown ZF compression algorithm: %c%c\n", + rr->u.ZF.algorithm[0], rr->u.ZF.algorithm[1]); + } + } + break; +#endif default: break; } @@ -416,7 +457,7 @@ * If there is another SL record, and this component * record isn't continued, then add a slash. */ - if ((rr->u.SL.flags & 1) && !(oldslp->flags & 1)) + if ((!rootflag) && (rr->u.SL.flags & 1) && !(oldslp->flags & 1)) *rpnt++='/'; break; } @@ -431,6 +472,19 @@ return rpnt; } +int parse_rock_ridge_inode(struct iso_directory_record * de, + struct inode * inode) +{ + int result=parse_rock_ridge_inode_internal(de,inode,0); + /* if rockridge flag was reset and we didn't look for attributes + * behind eventual XA attributes, have a look there */ + if ((inode->i_sb->u.isofs_sb.s_rock_offset==-1) + &&(inode->i_sb->u.isofs_sb.s_rock==2)) + { + result=parse_rock_ridge_inode_internal(de,inode,14); + }; + return result; +}; /* readpage() for symlinks: reads symlink contents into the page and either makes it uptodate and returns 0 or returns error (-EIO) */ @@ -481,7 +535,7 @@ rr = (struct rock_ridge *) chr; if (rr->len == 0) goto out; /* Something got screwed up here */ - sig = (chr[0] << 8) + chr[1]; + sig = isonum_721(chr); chr += rr->len; len -= rr->len; Index: rock.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/isofs/rock.h,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- rock.h 14 Jan 2001 16:26:17 -0000 1.1.1.1 +++ rock.h 9 Apr 2002 13:11:18 -0000 1.2 @@ -6,7 +6,7 @@ struct SU_SP{ unsigned char magic[2]; unsigned char skip; -}; +} __attribute__((packed)); struct SU_CE{ char extent[8]; @@ -20,11 +20,11 @@ unsigned char len_src; unsigned char ext_ver; char data[0]; -}; +} __attribute__((packed)); struct RR_RR{ char flags[1]; -}; +} __attribute__((packed)); struct RR_PX{ char mode[8]; @@ -43,17 +43,17 @@ unsigned char flags; unsigned char len; char text[0]; -}; +} __attribute__((packed)); struct RR_SL{ unsigned char flags; struct SL_component link; -}; +} __attribute__((packed)); struct RR_NM{ unsigned char flags; char name[0]; -}; +} __attribute__((packed)); struct RR_CL{ char location[8]; @@ -65,11 +65,18 @@ struct stamp{ char time[7]; -}; +} __attribute__((packed)); struct RR_TF{ char flags; struct stamp times[0]; /* Variable number of these beasts */ +} __attribute__((packed)); + +/* Linux-specific extension for transparent decompression */ +struct RR_ZF{ + char algorithm[2]; + char parms[2]; + char real_size[8]; }; /* These are the bits and their meanings for flags in the TF structure. */ @@ -98,6 +105,7 @@ struct RR_CL CL; struct RR_PL PL; struct RR_TF TF; + struct RR_ZF ZF; } u; }; Index: util.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/fs/isofs/util.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- util.c 14 Jan 2001 16:26:17 -0000 1.1.1.1 +++ util.c 9 Apr 2002 13:11:18 -0000 1.2 @@ -1,90 +1,9 @@ /* * linux/fs/isofs/util.c - * - * The special functions in the file are numbered according to the section - * of the iso 9660 standard in which they are described. isonum_733 will - * convert numbers according to section 7.3.3, etc. - * - * isofs special functions. This file was lifted in its entirety from - * the 386BSD iso9660 filesystem, by Pace Willisson <pa...@bl...>. */ #include <linux/time.h> - -int -isonum_711 (char * p) -{ - return (*p & 0xff); -} - -int -isonum_712 (char * p) -{ - int val; - - val = *p; - if (val & 0x80) - val |= 0xffffff00; - return (val); -} - -int -isonum_721 (char * p) -{ - return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); -} - -int -isonum_722 (char * p) -{ - return (((p[0] & 0xff) << 8) | (p[1] & 0xff)); -} - -int -isonum_723 (char * p) -{ -#if 0 - if (p[0] != p[3] || p[1] != p[2]) { - fprintf (stderr, "invalid format 7.2.3 number\n"); - exit (1); - } -#endif - return (isonum_721 (p)); -} - -int -isonum_731 (char * p) -{ - return ((p[0] & 0xff) - | ((p[1] & 0xff) << 8) - | ((p[2] & 0xff) << 16) - | ((p[3] & 0xff) << 24)); -} - -int -isonum_732 (char * p) -{ - return (((p[0] & 0xff) << 24) - | ((p[1] & 0xff) << 16) - | ((p[2] & 0xff) << 8) - | (p[3] & 0xff)); -} - -int -isonum_733 (char * p) -{ -#if 0 - int i; - - for (i = 0; i < 4; i++) { - if (p[i] != p[7-i]) { - fprintf (stderr, "bad format 7.3.3 number\n"); - exit (1); - } - } -#endif - return (isonum_731 (p)); -} +#include <linux/iso_fs.h> /* * We have to convert from a MM/DD/YY format to the Unix ctime format. |