OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/tags/before_ORP/uclinux/uClinux-2.0.x/fs/isofs
    from Rev 901 to Rev 1765
    Reverse comparison

Rev 901 → Rev 1765

/rock.c
0,0 → 1,554
/*
* linux/fs/isofs/rock.c
*
* (C) 1992, 1993 Eric Youngdale
*
* Rock Ridge Extensions to iso9660
*
* Modifed by Russell King 11/02/96
* Allows ISO rock ridge extensions to work on ARM.
*/
 
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/iso_fs.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/malloc.h>
 
#include "rock.h"
 
/* These functions are designed to read the system areas of a directory record
* and extract relevant information. There are different functions provided
* depending upon what information we need at the time. One function fills
* out an inode structure, a second one extracts a filename, a third one
* returns a symbolic link name, and a fourth one returns the extent number
* for the file. */
 
#define SIG(A,B) ((A << 8) | B)
 
 
/* 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;
 
/* 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 */
 
#define CONTINUE_DECLS \
int cont_extent = 0, cont_offset = 0, cont_size = 0; \
void * buffer = 0
 
#define CHECK_CE \
{cont_extent = isonum_733(rr->u.CE.extent); \
cont_offset = isonum_733(rr->u.CE.offset); \
cont_size = isonum_733(rr->u.CE.size);}
 
#define SETUP_ROCK_RIDGE(DE,CHR,LEN) \
{LEN= (int)(((struct iso_directory_record *)0)->name) + DE->name_len[0]; \
if(LEN & 1) LEN++; \
CHR = ((unsigned char *) DE) + LEN; \
LEN = *((unsigned char *) DE) - LEN;}
 
#define MAYBE_CONTINUE(LABEL,DEV) \
{if (buffer) kfree(buffer); \
if (cont_extent){ \
int block, offset, offset1; \
struct buffer_head * bh; \
buffer = kmalloc(cont_size,GFP_KERNEL); \
if (!buffer) goto out; \
block = cont_extent; \
offset = cont_offset; \
offset1 = 0; \
if(ISOFS_BUFFER_SIZE(DEV) == 1024) { \
block <<= 1; \
if (offset >= 1024) block++; \
offset &= 1023; \
if(offset + cont_size >= 1024) { \
bh = bread(DEV->i_dev, block++, ISOFS_BUFFER_SIZE(DEV)); \
if(!bh) {printk("Unable to read continuation Rock Ridge record\n"); \
kfree(buffer); \
buffer = NULL; } else { \
memcpy(buffer, bh->b_data + offset, 1024 - offset); \
brelse(bh); \
offset1 = 1024 - offset; \
offset = 0;} \
} \
}; \
if(buffer) { \
bh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \
if(bh){ \
memcpy(buffer + offset1, bh->b_data + offset, cont_size - offset1); \
brelse(bh); \
chr = (unsigned char *) buffer; \
len = cont_size; \
cont_extent = 0; \
cont_size = 0; \
cont_offset = 0; \
goto LABEL; \
}; \
} \
printk("Unable to read rock-ridge attributes\n"); \
}}
 
/* This is the inner layer of the get filename routine, and is called
for each system area and continuation record related to the file */
 
int find_rock_ridge_relocation(struct iso_directory_record * de,
struct inode * inode) {
int flag;
int len;
int retval;
unsigned char * chr;
CONTINUE_DECLS;
flag = 0;
/* If this is a '..' then we are looking for the parent, otherwise we
are looking for the child */
if (de->name[0]==1 && de->name_len[0]==1) flag = 1;
/* Return value if we do not find appropriate record. */
retval = isonum_733 (de->extent);
if (!inode->i_sb->u.isofs_sb.s_rock) return retval;
 
SETUP_ROCK_RIDGE(de, chr, len);
repeat:
{
int rrflag, sig;
struct rock_ridge * rr;
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];
chr += rr->len;
len -= rr->len;
 
switch(sig){
case SIG('R','R'):
rrflag = rr->u.RR.flags[0];
if (flag && !(rrflag & RR_PL)) goto out;
if (!flag && !(rrflag & RR_CL)) goto out;
break;
case SIG('S','P'):
CHECK_SP(goto out);
break;
case SIG('C','L'):
#ifdef DEBUG
printk("RR: CL\n");
#endif
if (flag == 0) {
retval = isonum_733(rr->u.CL.location);
goto out;
};
break;
case SIG('P','L'):
#ifdef DEBUG
printk("RR: PL\n");
#endif
if (flag != 0) {
retval = isonum_733(rr->u.PL.location);
goto out;
};
break;
case SIG('C','E'):
CHECK_CE; /* This tells is if there is a continuation record */
break;
default:
break;
}
};
};
MAYBE_CONTINUE(repeat, inode);
return retval;
out:
if(buffer) kfree(buffer);
return retval;
}
 
int get_rock_ridge_filename(struct iso_directory_record * de,
char * retname, struct inode * inode)
{
int len;
unsigned char * chr;
CONTINUE_DECLS;
int retnamlen = 0, truncate=0;
if (!inode->i_sb->u.isofs_sb.s_rock) return 0;
*retname = 0;
retnamlen = 0;
 
SETUP_ROCK_RIDGE(de, chr, len);
repeat:
{
struct rock_ridge * rr;
int sig;
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];
chr += rr->len;
len -= rr->len;
 
switch(sig){
case SIG('R','R'):
if((rr->u.RR.flags[0] & RR_NM) == 0) goto out;
break;
case SIG('S','P'):
CHECK_SP(goto out);
break;
case SIG('C','E'):
CHECK_CE;
break;
case SIG('N','M'):
if (truncate) break;
if (rr->u.NM.flags & ~1) {
printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags);
break;
};
if((strlen(retname) + rr->len - 5) >= 254) {
truncate = 1;
break;
};
strncat(retname, rr->u.NM.name, rr->len - 5);
retnamlen += rr->len - 5;
break;
case SIG('R','E'):
#ifdef DEBUG
printk("RR: RE (%x)\n", inode->i_ino);
#endif
if (buffer) kfree(buffer);
return -1;
default:
break;
}
};
}
MAYBE_CONTINUE(repeat,inode);
return retnamlen; /* If 0, this file did not have a NM field */
out:
if(buffer) kfree(buffer);
return 0;
}
 
int parse_rock_ridge_inode(struct iso_directory_record * de,
struct inode * inode){
int len;
unsigned char * chr;
int symlink_len = 0;
CONTINUE_DECLS;
 
if (!inode->i_sb->u.isofs_sb.s_rock) return 0;
 
SETUP_ROCK_RIDGE(de, chr, len);
repeat:
{
int cnt, sig;
struct inode * reloc;
struct rock_ridge * rr;
int rootflag;
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];
chr += rr->len;
len -= rr->len;
switch(sig){
case SIG('R','R'):
if((rr->u.RR.flags[0] &
(RR_PX | RR_TF | RR_SL | RR_CL)) == 0) goto out;
break;
case SIG('S','P'):
CHECK_SP(goto out);
break;
case SIG('C','E'):
CHECK_CE;
break;
case SIG('E','R'):
inode->i_sb->u.isofs_sb.s_rock = 1;
printk(KERN_DEBUG"ISO9660 Extensions: ");
{ int p;
for(p=0;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]);
};
printk("\n");
break;
case SIG('P','X'):
inode->i_mode = isonum_733(rr->u.PX.mode);
inode->i_nlink = isonum_733(rr->u.PX.n_links);
inode->i_uid = isonum_733(rr->u.PX.uid);
inode->i_gid = isonum_733(rr->u.PX.gid);
break;
case SIG('P','N'):
{ int high, low;
high = isonum_733(rr->u.PN.dev_high);
low = isonum_733(rr->u.PN.dev_low);
/*
* The Rock Ridge standard specifies that if sizeof(dev_t) <= 4,
* then the high field is unused, and the device number is completely
* stored in the low field. Some writers may ignore this subtlety,
* and as a result we test to see if the entire device number is
* stored in the low field, and use that.
*/
if((low & ~0xff) && high == 0) {
inode->i_rdev = MKDEV(low >> 8, low & 0xff);
} else {
inode->i_rdev = MKDEV(high, low);
}
};
break;
case SIG('T','F'):
{
struct stamp *times = (struct stamp *) &(rr->u.TF.__times);
/* Some RRIP writers incorrectly place ctime in the TF_CREATE field.
Try to handle this correctly for either case. */
cnt = 0; /* Rock ridge never appears on a High Sierra disk */
if(rr->u.TF.flags & TF_CREATE)
inode->i_ctime = iso_date(times[cnt++].time, 0);
if(rr->u.TF.flags & TF_MODIFY)
inode->i_mtime = iso_date(times[cnt++].time, 0);
if(rr->u.TF.flags & TF_ACCESS)
inode->i_atime = iso_date(times[cnt++].time, 0);
if(rr->u.TF.flags & TF_ATTRIBUTES)
inode->i_ctime = iso_date(times[cnt++].time, 0);
break;
}
case SIG('S','L'):
{int slen;
struct SL_component * slp;
struct SL_component * oldslp;
slen = rr->len - 5;
slp = (struct SL_component *)&rr->u.SL.__link;
inode->i_size = symlink_len;
while (slen > 1){
rootflag = 0;
switch(slp->flags &~1){
case 0:
inode->i_size += slp->len;
break;
case 2:
inode->i_size += 1;
break;
case 4:
inode->i_size += 2;
break;
case 8:
rootflag = 1;
inode->i_size += 1;
break;
default:
printk("Symlink component flag not implemented\n");
};
slen -= slp->len + 2;
oldslp = slp;
slp = (struct SL_component *) (((char *) slp) + slp->len + 2);
 
if(slen < 2) {
if( ((rr->u.SL.flags & 1) != 0)
&& ((oldslp->flags & 1) == 0) ) inode->i_size += 1;
break;
}
 
/*
* If this component record isn't continued, then append a '/'.
*/
if( (!rootflag)
&& ((oldslp->flags & 1) == 0) ) inode->i_size += 1;
}
}
symlink_len = inode->i_size;
break;
case SIG('R','E'):
printk("Attempt to read inode for relocated directory\n");
goto out;
case SIG('C','L'):
#ifdef DEBUG
printk("RR CL (%x)\n",inode->i_ino);
#endif
inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location) <<
inode -> i_sb -> u.isofs_sb.s_log_zone_size;
reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent);
inode->i_mode = reloc->i_mode;
inode->i_nlink = reloc->i_nlink;
inode->i_uid = reloc->i_uid;
inode->i_gid = reloc->i_gid;
inode->i_rdev = reloc->i_rdev;
inode->i_size = reloc->i_size;
inode->i_atime = reloc->i_atime;
inode->i_ctime = reloc->i_ctime;
inode->i_mtime = reloc->i_mtime;
iput(reloc);
break;
default:
break;
}
};
}
MAYBE_CONTINUE(repeat,inode);
return 0;
out:
if(buffer) kfree(buffer);
return 0;
}
 
 
/* Returns the name of the file that this inode is symlinked to. This is
in malloc'd memory, so it needs to be freed, once we are through with it */
 
char * get_rock_ridge_symlink(struct inode * inode)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
struct buffer_head * bh;
unsigned char * pnt;
void * cpnt = NULL;
char * rpnt;
struct iso_directory_record * raw_inode;
CONTINUE_DECLS;
int block;
int sig;
int rootflag;
int len;
unsigned char * chr;
struct rock_ridge * rr;
if (!inode->i_sb->u.isofs_sb.s_rock)
panic("Cannot have symlink with high sierra variant of iso filesystem\n");
 
rpnt = 0;
block = inode->i_ino >> bufbits;
if (!(bh=bread(inode->i_dev,block, bufsize))) {
printk("unable to read i-node block");
return NULL;
};
pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (bufsize - 1));
raw_inode = ((struct iso_directory_record *) pnt);
if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){
int frag1, offset;
offset = (inode->i_ino & (bufsize - 1));
frag1 = bufsize - offset;
cpnt = kmalloc(*pnt,GFP_KERNEL);
if(!cpnt) return NULL;
memcpy(cpnt, bh->b_data + offset, frag1);
brelse(bh);
if (!(bh = bread(inode->i_dev,++block, bufsize))) {
kfree(cpnt);
printk("unable to read i-node block");
return NULL;
};
offset += *pnt - bufsize;
memcpy((char *)cpnt+frag1, bh->b_data, offset);
pnt = ((unsigned char *) cpnt);
raw_inode = ((struct iso_directory_record *) pnt);
};
/* Now test for possible Rock Ridge extensions which will override some of
these numbers in the inode structure. */
SETUP_ROCK_RIDGE(raw_inode, chr, len);
repeat:
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];
chr += rr->len;
len -= rr->len;
switch(sig){
case SIG('R','R'):
if((rr->u.RR.flags[0] & RR_SL) == 0) goto out;
break;
case SIG('S','P'):
CHECK_SP(goto out);
break;
case SIG('S','L'):
{int slen;
struct SL_component * oldslp;
struct SL_component * slp;
slen = rr->len - 5;
slp = (struct SL_component *)&rr->u.SL.__link;
while (slen > 1){
if (!rpnt){
rpnt = (char *) kmalloc (inode->i_size +1, GFP_KERNEL);
if (!rpnt) goto out;
*rpnt = 0;
};
rootflag = 0;
switch(slp->flags &~1){
case 0:
strncat(rpnt,slp->text, slp->len);
break;
case 2:
strcat(rpnt,".");
break;
case 4:
strcat(rpnt,"..");
break;
case 8:
rootflag = 1;
strcat(rpnt,"/");
break;
default:
printk("Symlink component flag not implemented (%d)\n",slen);
};
slen -= slp->len + 2;
oldslp = slp;
slp = (struct SL_component *) (((char *) slp) + slp->len + 2);
 
if(slen < 2) {
/*
* If there is another SL record, and this component record
* isn't continued, then add a slash.
*/
if( ((rr->u.SL.flags & 1) != 0)
&& ((oldslp->flags & 1) == 0) ) strcat(rpnt,"/");
break;
}
 
/*
* If this component record isn't continued, then append a '/'.
*/
if( (!rootflag)
&& ((oldslp->flags & 1) == 0) ) strcat(rpnt,"/");
 
};
break;
case SIG('C','E'):
CHECK_CE; /* This tells is if there is a continuation record */
break;
default:
break;
}
};
};
MAYBE_CONTINUE(repeat,inode);
brelse(bh);
if (cpnt) {
kfree(cpnt);
cpnt = NULL;
};
 
return rpnt;
out:
if(buffer) kfree(buffer);
return 0;
}
 
 
 
 
 
 
/dir.c
0,0 → 1,320
/*
* linux/fs/isofs/dir.c
*
* (C) 1992, 1993, 1994 Eric Youngdale Modified for ISO9660 filesystem.
*
* (C) 1991 Linus Torvalds - minix filesystem
*
* Steve Beynon : Missing last directory entries fixed
* (stephen@askone.demon.co.uk) : 21st June 1996
*
* isofs directory handling functions
*/
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/iso_fs.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/sched.h>
#include <linux/locks.h>
 
#include <asm/segment.h>
 
 
static int isofs_readdir(struct inode *, struct file *, void *, filldir_t);
 
static struct file_operations isofs_dir_operations =
{
NULL, /* lseek - default */
NULL, /* read */
NULL, /* write - bad */
isofs_readdir, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* fsync */
};
 
/*
* directories can handle most operations...
*/
struct inode_operations isofs_dir_inode_operations =
{
&isofs_dir_operations, /* default directory file-ops */
NULL, /* create */
isofs_lookup, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
isofs_bmap, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
static int parent_inode_number(struct inode * inode, struct iso_directory_record * de)
{
int inode_number = inode->i_ino;
 
if ((inode->i_sb->u.isofs_sb.s_firstdatazone) != inode->i_ino)
inode_number = inode->u.isofs_i.i_backlink;
 
if (inode_number != -1)
return inode_number;
 
/* This should never happen, but who knows. Try to be forgiving */
return isofs_lookup_grandparent(inode, find_rock_ridge_relocation(de, inode));
}
 
static int isofs_name_translate(char * old, int len, char * new)
{
int i, c;
for (i = 0; i < len; i++) {
c = old[i];
if (!c)
break;
if (c >= 'A' && c <= 'Z')
c |= 0x20; /* lower case */
 
/* Drop trailing '.;1' (ISO9660:1988 7.5.1 requires period) */
if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
break;
 
/* Drop trailing ';1' */
if (c == ';' && i == len - 2 && old[i + 1] == '1')
break;
 
/* Convert remaining ';' to '.' */
if (c == ';')
c = '.';
 
new[i] = c;
}
return i;
}
 
/*
* This should _really_ be cleaned up some day..
*/
static int do_isofs_readdir(struct inode *inode, struct file *filp,
void *dirent, filldir_t filldir,
char * tmpname, struct iso_directory_record * tmpde)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
unsigned int block, offset;
int inode_number = 0; /* Quiet GCC */
struct buffer_head *bh;
int len;
int map;
int high_sierra;
int first_de = 1;
char *p = NULL; /* Quiet GCC */
struct iso_directory_record *de;
 
offset = filp->f_pos & (bufsize - 1);
block = isofs_bmap(inode, filp->f_pos >> bufbits);
high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
 
if (!block)
return 0;
 
if (!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size)))
return 0;
 
while (filp->f_pos < inode->i_size) {
int de_len, next_offset;
#ifdef DEBUG
printk("Block, offset, f_pos: %x %x %x\n",
block, offset, filp->f_pos);
printk("inode->i_size = %x\n",inode->i_size);
#endif
/* Next directory_record on next CDROM sector */
if (offset >= bufsize) {
#ifdef DEBUG
printk("offset >= bufsize\n");
#endif
brelse(bh);
offset = 0;
block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
if (!block)
return 0;
bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
if (!bh)
return 0;
continue;
}
 
de = (struct iso_directory_record *) (bh->b_data + offset);
if(first_de) inode_number = (block << bufbits) + (offset & (bufsize - 1));
 
de_len = *(unsigned char *) de;
#ifdef DEBUG
printk("de_len = %ld\n", de_len);
#endif
 
/* If the length byte is zero, we should move on to the next
CDROM sector. If we are at the end of the directory, we
kick out of the while loop. */
 
if (de_len == 0) {
brelse(bh);
filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
+ ISOFS_BLOCK_SIZE);
offset = 0;
block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
if (!block)
return 0;
bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
if (!bh)
return 0;
continue;
}
 
/* Make sure that the entire directory record is in the
current bh block.
If not, put the two halves together in "tmpde" */
next_offset = offset + de_len;
if (next_offset > bufsize) {
#ifdef DEBUG
printk("next_offset (%x) > bufsize (%x)\n",next_offset,bufsize);
#endif
next_offset &= (bufsize - 1);
memcpy(tmpde, de, bufsize - offset);
brelse(bh);
block = isofs_bmap(inode, (filp->f_pos + de_len) >> bufbits);
if (!block)
{
return 0;
}
bh = breada(inode->i_dev, block, bufsize,
filp->f_pos,
inode->i_size);
if (!bh)
{
#ifdef DEBUG
printk("!bh block=%ld, bufsize=%ld\n",block,bufsize);
printk("filp->f_pos = %ld\n",filp->f_pos);
printk("inode->i_size = %ld\n", inode->i_size);
#endif
return 0;
}
memcpy(bufsize - offset + (char *) tmpde, bh->b_data, next_offset);
de = tmpde;
}
offset = next_offset;
 
if(de->flags[-high_sierra] & 0x80) {
first_de = 0;
filp->f_pos += de_len;
continue;
}
first_de = 1;
 
/* Handle the case of the '.' directory */
if (de->name_len[0] == 1 && de->name[0] == 0) {
if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
break;
filp->f_pos += de_len;
continue;
}
 
len = 0;
 
/* Handle the case of the '..' directory */
if (de->name_len[0] == 1 && de->name[0] == 1) {
inode_number = parent_inode_number(inode, de);
if (inode_number == -1)
break;
if (filldir(dirent, "..", 2, filp->f_pos, inode_number) < 0)
break;
filp->f_pos += de_len;
continue;
}
 
/* Handle everything else. Do name translation if there
is no Rock Ridge NM field. */
if (inode->i_sb->u.isofs_sb.s_unhide == 'n') {
/* Do not report hidden or associated files */
if (de->flags[-high_sierra] & 5) {
filp->f_pos += de_len;
continue;
}
}
 
map = 1;
if (inode->i_sb->u.isofs_sb.s_rock) {
len = get_rock_ridge_filename(de, tmpname, inode);
if (len != 0) {
p = tmpname;
map = 0;
}
}
if (map) {
if (inode->i_sb->u.isofs_sb.s_joliet_level) {
len = get_joliet_filename(de, inode, tmpname);
p = tmpname;
} else {
if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
len = isofs_name_translate(de->name, de->name_len[0],
tmpname);
p = tmpname;
} else {
p = de->name;
len = de->name_len[0];
}
}
}
if (len > 0) {
if (filldir(dirent, p, len, filp->f_pos, inode_number) < 0)
break;
 
dcache_add(inode, p, len, inode_number);
}
filp->f_pos += de_len;
continue;
}
brelse(bh);
return 0;
}
 
/*
* Handle allocation of temporary space for name translation and
* handling split directory entries.. The real work is done by
* "do_isofs_readdir()".
*/
static int isofs_readdir(struct inode *inode, struct file *filp,
void *dirent, filldir_t filldir)
{
int result;
char * tmpname;
struct iso_directory_record * tmpde;
 
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
 
tmpname = (char *) __get_free_page(GFP_KERNEL);
if (!tmpname)
return -ENOMEM;
tmpde = (struct iso_directory_record *) (tmpname+1024);
 
result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
 
free_page((unsigned long) tmpname);
return result;
}
/inode.c
0,0 → 1,1197
/*
* linux/fs/isofs/inode.c
*
* (C) 1991 Linus Torvalds - minix filesystem
* 1992, 1993, 1994 Eric Youngdale Modified for ISO9660 filesystem.
* 1994 Eberhard Moenkeberg - multi session handling.
* 1995 Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs.
*
*/
 
#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/malloc.h>
#include <linux/errno.h>
#include <linux/cdrom.h>
#include <linux/nls.h>
 
#include <asm/system.h>
#include <asm/segment.h>
 
/*
* We have no support for "multi volume" CDs, but more and more disks carry
* wrong information within the volume descriptors.
*/
#define IGNORE_WRONG_MULTI_VOLUME_SPECS
 
/*
* A home-burnt Joliet level 3 cd-rom with a 100 MB zip file had more than
* 100 file sections, so the limit should be larger than that. What does the
* ISO9660 standard say? (Ulrik Dickow <ukd@kampsax.dk>)
*/
#define MAX_FILE_SECTIONS 1000
 
#ifdef LEAK_CHECK
static int check_malloc = 0;
static int check_bread = 0;
#endif
 
void isofs_put_super(struct super_block *sb)
{
if (sb->u.isofs_sb.s_nls_iocharset) {
unload_nls(sb->u.isofs_sb.s_nls_iocharset);
sb->u.isofs_sb.s_nls_iocharset = NULL;
}
lock_super(sb);
 
#ifdef LEAK_CHECK
printk("Outstanding mallocs:%d, outstanding buffers: %d\n",
check_malloc, check_bread);
#endif
sb->s_dev = 0;
unlock_super(sb);
MOD_DEC_USE_COUNT;
return;
}
 
static struct super_operations isofs_sops = {
isofs_read_inode,
NULL, /* notify_change */
NULL, /* write_inode */
NULL, /* put_inode */
isofs_put_super,
NULL, /* write_super */
isofs_statfs,
NULL
};
 
struct iso9660_options{
char map;
char rock;
char joliet;
char cruft;
char unhide;
unsigned char check;
unsigned char conversion;
unsigned int blocksize;
mode_t mode;
gid_t gid;
uid_t uid;
char *iocharset;
unsigned char utf8;
};
 
static int parse_options(char *options, struct iso9660_options * popt)
{
char *this_char,*value,*p;
int len;
 
popt->map = 'n';
popt->rock = 'y';
popt->joliet = 'y';
popt->cruft = 'n';
popt->unhide = 'n';
popt->check = 's'; /* default: strict */
popt->conversion = 'b'; /* default: no conversion */
popt->blocksize = 1024;
popt->mode = S_IRUGO;
popt->gid = 0;
popt->uid = 0;
popt->iocharset = NULL;
popt->utf8 = 0;
if (!options) return 1;
for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
if (strncmp(this_char,"norock",6) == 0) {
popt->rock = 'n';
continue;
}
if (strncmp(this_char,"nojoliet",8) == 0) {
popt->joliet = 'n';
continue;
}
if (strncmp(this_char,"unhide",6) == 0) {
popt->unhide = 'y';
continue;
}
if (strncmp(this_char,"cruft",5) == 0) {
popt->cruft = 'y';
continue;
}
if (strncmp(this_char,"utf8",4) == 0) {
popt->utf8 = 1;
continue;
}
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
 
if (!strcmp(this_char,"iocharset")) {
p = value;
while (*value && *value != ',') value++;
len = value - p;
if (len) {
popt->iocharset = kmalloc(len+1, GFP_KERNEL);
memcpy(popt->iocharset, p, len);
popt->iocharset[len] = 0;
} else {
popt->iocharset = NULL;
return 0;
}
}
else if (!strcmp(this_char,"map") && value) {
if (value[0] && !value[1] && strchr("on",*value))
popt->map = *value;
else if (!strcmp(value,"off")) popt->map = 'o';
else if (!strcmp(value,"normal")) popt->map = 'n';
else return 0;
}
else if (!strcmp(this_char,"check") && value) {
if (value[0] && !value[1] && strchr("rs",*value))
popt->check = *value;
else if (!strcmp(value,"relaxed")) popt->check = 'r';
else if (!strcmp(value,"strict")) popt->check = 's';
else return 0;
}
else if (!strcmp(this_char,"conv") && value) {
if (value[0] && !value[1] && strchr("btma",*value))
popt->conversion = *value;
else if (!strcmp(value,"binary")) popt->conversion = 'b';
else if (!strcmp(value,"text")) popt->conversion = 't';
else if (!strcmp(value,"mtext")) popt->conversion = 'm';
else if (!strcmp(value,"auto")) popt->conversion = 'a';
else return 0;
}
else if (value &&
(!strcmp(this_char,"block") ||
!strcmp(this_char,"mode") ||
!strcmp(this_char,"uid") ||
!strcmp(this_char,"gid"))) {
char * vpnt = value;
unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
if (*vpnt) return 0;
switch(*this_char) {
case 'b':
if ( ivalue != 512
&& ivalue != 1024
&& ivalue != 2048) return 0;
popt->blocksize = ivalue;
break;
case 'u':
popt->uid = ivalue;
break;
case 'g':
popt->gid = ivalue;
break;
case 'm':
popt->mode = ivalue;
break;
}
}
else return 1;
}
return 1;
}
 
/*
* look if the driver can tell the multi session redirection value
*
* don't change this if you don't know what you do, please!
* Multisession is legal only with XA disks.
* A non-XA disk with more than one volume descriptor may do it right, but
* usually is written in a nowhere standardized "multi-partition" manner.
* Multisession uses absolute addressing (solely the first frame of the whole
* track is #0), multi-partition uses relative addressing (each first frame of
* each track is #0), and a track is not a session.
*
* A broken CDwriter software or drive firmware does not set new standards,
* at least not if conflicting with the existing ones.
*
* emoenke@gwdg.de
*/
#define WE_OBEY_THE_WRITTEN_STANDARDS 1
 
static unsigned int isofs_get_last_session(kdev_t dev)
{
struct cdrom_multisession ms_info;
unsigned int vol_desc_start;
struct inode inode_fake;
extern struct file_operations * get_blkfops(unsigned int);
int i;
 
vol_desc_start=0;
if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
{
/* Whoops. We must save the old FS, since otherwise
* we would destroy the kernels idea about FS on root
* mount in read_super... [chexum]
*/
unsigned long old_fs=get_fs();
inode_fake.i_rdev=dev;
ms_info.addr_format=CDROM_LBA;
set_fs(KERNEL_DS);
i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
NULL,
CDROMMULTISESSION,
(unsigned long) &ms_info);
set_fs(old_fs);
#if 0
printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
if (i==0)
{
printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no");
printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
}
#endif 0
if (i==0)
#if WE_OBEY_THE_WRITTEN_STANDARDS
if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
#endif WE_OBEY_THE_WRITTEN_STANDARDS
vol_desc_start=ms_info.addr.lba;
}
return vol_desc_start;
}
 
struct super_block *isofs_read_super(struct super_block *s,void *data,
int silent)
{
struct buffer_head *bh=NULL;
int iso_blknum;
unsigned int blocksize_bits;
int high_sierra;
kdev_t dev = s->s_dev;
unsigned int vol_desc_start;
int orig_zonesize;
char *p;
int joliet_level = 0;
 
struct iso_volume_descriptor *vdp;
struct hs_volume_descriptor *hdp;
 
struct iso_primary_descriptor *pri = NULL;
struct iso_supplementary_descriptor *sec = NULL;
struct hs_primary_descriptor *h_pri = NULL;
 
struct iso_directory_record *rootp;
 
struct iso9660_options opt;
 
MOD_INC_USE_COUNT;
 
if (!parse_options((char *) data,&opt)) {
s->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
 
#if 0
printk("map = %c\n", opt.map);
printk("rock = %c\n", opt.rock);
printk("joliet = %c\n", opt.joliet);
printk("check = %c\n", opt.check);
printk("cruft = %c\n", opt.cruft);
printk("unhide = %c\n", opt.unhide);
printk("conversion = %c\n", opt.conversion);
printk("blocksize = %d\n", opt.blocksize);
printk("gid = %d\n", opt.gid);
printk("uid = %d\n", opt.uid);
#endif
blocksize_bits = 0;
{
int i = opt.blocksize;
while (i != 1){
blocksize_bits++;
i >>=1;
}
}
set_blocksize(dev, opt.blocksize);
 
lock_super(s);
 
s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */
 
vol_desc_start = isofs_get_last_session(dev);
for (iso_blknum = vol_desc_start+16;
iso_blknum < vol_desc_start+100; iso_blknum++)
{
int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits);
 
if (!(bh = bread(dev,b,opt.blocksize))) {
s->s_dev = 0;
printk("isofs_read_super: bread failed, dev "
"%s iso_blknum %d block %d\n",
kdevname(dev), iso_blknum, b);
unlock_super(s);
MOD_DEC_USE_COUNT;
return NULL;
}
 
vdp = (struct iso_volume_descriptor *)bh->b_data;
hdp = (struct hs_volume_descriptor *)bh->b_data;
if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
if (isonum_711 (hdp->type) != ISO_VD_PRIMARY)
goto out;
if (isonum_711 (hdp->type) == ISO_VD_END)
goto out;
s->u.isofs_sb.s_high_sierra = 1;
high_sierra = 1;
opt.rock = 'n';
h_pri = (struct hs_primary_descriptor *)vdp;
break;
}
 
if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
if (isonum_711 (vdp->type) == ISO_VD_END)
break;
if (isonum_711 (vdp->type) == ISO_VD_PRIMARY) {
if (pri == NULL) {
pri = (struct iso_primary_descriptor *)vdp;
}
} else if (isonum_711 (vdp->type) == ISO_VD_SUPPLEMENTARY) {
sec = (struct iso_supplementary_descriptor *)vdp;
if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
if (opt.joliet == 'y') {
if (sec->escape[2] == 0x40) {
joliet_level = 1;
} else if (sec->escape[2] == 0x43) {
joliet_level = 2;
} else if (sec->escape[2] == 0x45) {
joliet_level = 3;
}
printk("ISO9660 Extensions: Microsoft Joliet Level %d\n",
joliet_level);
}
break;
} else {
/* Unknown supplementary volume descriptor */
sec = NULL;
}
}
/* Just skip any volume descriptors we don't recognize */
}
 
brelse(bh);
}
if ((pri == NULL) && (sec == NULL) && (h_pri == NULL)) {
if (!silent)
printk("Unable to identify CD-ROM format.\n");
s->s_dev = 0;
unlock_super(s);
MOD_DEC_USE_COUNT;
return NULL;
}
s->u.isofs_sb.s_joliet_level = joliet_level;
if (joliet_level && opt.rock == 'n') {
/* This is the case of Joliet with the norock mount flag.
* A disc with both Joliet and Rock Ridge is handled later
*/
pri = (struct iso_primary_descriptor *) sec;
}
 
if(high_sierra){
rootp = (struct iso_directory_record *) h_pri->root_directory_record;
#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
if (isonum_723 (h_pri->volume_set_size) != 1) {
printk("Multi-volume disks not supported.\n");
goto out;
}
#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);
} else {
rootp = (struct iso_directory_record *) pri->root_directory_record;
#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
if (isonum_723 (pri->volume_set_size) != 1) {
printk("Multi-volume disks not supported.\n");
goto out;
}
#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);
}
s->u.isofs_sb.s_ninodes = 0; /* No way to figure this out easily */
/* RDE: convert log zone size to bit shift */
 
orig_zonesize = s -> u.isofs_sb.s_log_zone_size;
switch (s -> u.isofs_sb.s_log_zone_size)
{ case 512: s -> u.isofs_sb.s_log_zone_size = 9; break;
case 1024: s -> u.isofs_sb.s_log_zone_size = 10; break;
case 2048: s -> u.isofs_sb.s_log_zone_size = 11; break;
 
default:
printk("Bad logical zone size %ld\n", s -> u.isofs_sb.s_log_zone_size);
goto out;
}
 
s->s_magic = ISOFS_SUPER_MAGIC;
/* The CDROM is read-only, has no nodes (devices) on it, and since
all of the files appear to be owned by root, we really do not want
to allow suid. (suid or devices will not show up unless we have
Rock Ridge extensions) */
s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */;
brelse(bh);
/* RDE: data zone now byte offset! */
 
s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) +
isonum_711 (rootp->ext_attr_length))
<< s -> u.isofs_sb.s_log_zone_size);
printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n",
s->u.isofs_sb.s_max_size,
1UL << s->u.isofs_sb.s_log_zone_size);
printk(KERN_DEBUG "First datazone:%ld Root inode number %ld\n",
s->u.isofs_sb.s_firstdatazone >> s -> u.isofs_sb.s_log_zone_size,
s->u.isofs_sb.s_firstdatazone);
if(high_sierra) printk(KERN_DEBUG "Disc in High Sierra format.\n");
unlock_super(s);
/* set up enough so that it can read an inode */
/*
* Force the blocksize to 512 for 512 byte sectors. The file
* read primitives really get it wrong in a bad way if we don't
* do this.
*/
if( orig_zonesize < opt.blocksize )
{
opt.blocksize = orig_zonesize;
blocksize_bits = 0;
{
int i = opt.blocksize;
while (i != 1){
blocksize_bits++;
i >>=1;
}
}
set_blocksize(dev, opt.blocksize);
printk(KERN_DEBUG "Forcing new log zone size:%d\n", opt.blocksize);
}
 
s->u.isofs_sb.s_nls_iocharset = NULL;
if (joliet_level == 0) {
if (opt.iocharset) {
kfree(opt.iocharset);
opt.iocharset = NULL;
}
} else if (opt.utf8 == 0) {
p = opt.iocharset ? opt.iocharset : "iso8859-1";
s->u.isofs_sb.s_nls_iocharset = load_nls(p);
if (! s->u.isofs_sb.s_nls_iocharset) {
/* Fail only if explicit charset specified */
if (opt.iocharset) {
kfree(opt.iocharset);
goto out;
} else {
s->u.isofs_sb.s_nls_iocharset = load_nls_default();
}
}
}
s->s_dev = dev;
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_name_check = opt.check;
s->u.isofs_sb.s_conversion = opt.conversion;
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;
/*
* 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 permissions.
*/
s->u.isofs_sb.s_mode = opt.mode & 0777;
s->s_blocksize = opt.blocksize;
s->s_blocksize_bits = blocksize_bits;
s->s_mounted = iget(s, s->u.isofs_sb.s_firstdatazone);
 
/*
* If this disk has both Rock Ridge and Joliet on it, then we
* want to use Rock Ridge by default. This can be overridden
* by using the norock mount option. There is still one other
* possibility that is not taken into account: a Rock Ridge
* CD with Unicode names. Until someone sees such a beast, it
* will not be supported.
*/
if (joliet_level && opt.rock == 'y' && s->u.isofs_sb.s_rock != 1) {
iput(s->s_mounted);
pri = (struct iso_primary_descriptor *) sec;
rootp = (struct iso_directory_record *)
pri->root_directory_record;
s->u.isofs_sb.s_firstdatazone =
((isonum_733 (rootp->extent) +
isonum_711 (rootp->ext_attr_length))
<< s -> u.isofs_sb.s_log_zone_size);
s->s_mounted = iget(s, s->u.isofs_sb.s_firstdatazone);
s->u.isofs_sb.s_rock = 0;
}
unlock_super(s);
 
if (!(s->s_mounted)) {
s->s_dev = 0;
printk("get root inode failed\n");
if (s->u.isofs_sb.s_nls_iocharset)
unload_nls(s->u.isofs_sb.s_nls_iocharset);
if (opt.iocharset) kfree(opt.iocharset);
MOD_DEC_USE_COUNT;
return NULL;
}
 
#ifdef DO_FUNKY_BROKEN_MEDIA_CHANGE_CHECK
if(!check_disk_change(s->s_dev)) {
return s;
}
if (s->u.isofs_sb.s_nls_iocharset)
unload_nls(s->u.isofs_sb.s_nls_iocharset);
if (opt.iocharset) kfree(opt.iocharset);
#else
check_disk_change(s->s_dev);
return s;
#endif
 
out: /* Kick out for various error conditions */
brelse(bh);
s->s_dev = 0;
unlock_super(s);
MOD_DEC_USE_COUNT;
return NULL;
}
 
void isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
 
tmp.f_type = ISOFS_SUPER_MAGIC;
tmp.f_bsize = sb->s_blocksize;
tmp.f_blocks = (sb->u.isofs_sb.s_nzones
<< (sb->u.isofs_sb.s_log_zone_size - sb->s_blocksize_bits));
tmp.f_bfree = 0;
tmp.f_bavail = 0;
tmp.f_files = sb->u.isofs_sb.s_ninodes;
tmp.f_ffree = 0;
tmp.f_namelen = NAME_MAX;
memcpy_tofs(buf, &tmp, bufsiz);
}
 
int isofs_bmap(struct inode * inode,int block)
{
off_t b_off, offset, size;
struct inode *ino;
unsigned int firstext;
unsigned long nextino;
int i;
 
if (block<0) {
printk("_isofs_bmap: block<0\n");
return 0;
}
 
b_off = block << ISOFS_BUFFER_BITS(inode);
 
/*
* If we are beyond the end of this file, don't give out any
* blocks.
*/
if( (b_off > inode->i_size) ||
((b_off == inode->i_size) && (b_off & (PAGE_SIZE - 1))) )
{
off_t max_legal_read_offset;
 
/*
* 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 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.
*/
max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1)
& ~(PAGE_SIZE - 1);
if( b_off >= max_legal_read_offset )
{
 
printk("_isofs_bmap: block>= EOF(%d, %ld)\n", block,
inode->i_size);
}
return 0;
}
 
offset = 0;
firstext = inode->u.isofs_i.i_first_extent;
size = inode->u.isofs_i.i_section_size;
nextino = inode->u.isofs_i.i_next_section_ino;
#ifdef DEBUG
printk("first inode: inode=%lu nextino=%lu firstext=%u size=%lu\n",
inode->i_ino, nextino, firstext, size);
#endif
i = 0;
if (nextino) {
while(b_off >= offset + size) {
offset += size;
 
if(nextino == 0) return 0;
ino = iget(inode->i_sb, nextino);
if(!ino) return 0;
firstext = ino->u.isofs_i.i_first_extent;
size = ino->u.isofs_i.i_section_size;
#ifdef DEBUG
printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n",
inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size);
#endif
nextino = ino->u.isofs_i.i_next_section_ino;
iput(ino);
if(++i > MAX_FILE_SECTIONS) {
printk("isofs_bmap: More than %d file sections ?!?, aborting...\n",
MAX_FILE_SECTIONS);
printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n",
inode->i_ino, block, firstext, (unsigned)size, nextino);
return 0;
}
}
}
#ifdef DEBUG
printk("isofs_bmap: mapped inode:block %lu:%d to block %lu\n",
inode->i_ino, block, (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode));
#endif
return (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode);
}
 
 
static void test_and_set_uid(uid_t *p, uid_t value)
{
if(value) {
*p = value;
#if 0
printk("Resetting to %d\n", value);
#endif
}
}
 
static int isofs_read_level3_size(struct inode * inode)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
struct buffer_head * bh = NULL;
struct iso_directory_record * raw_inode = NULL; /* quiet gcc */
unsigned char *pnt = NULL;
void *cpnt = NULL;
int block = 0; /* Quiet GCC */
unsigned long ino;
int i;
 
inode->i_size = 0;
inode->u.isofs_i.i_next_section_ino = 0;
ino = inode->i_ino;
i = 0;
do {
if(i > MAX_FILE_SECTIONS) {
printk("isofs_read_level3_size: More than %d file sections ?!?, aborting...\n"
"isofs_read_level3_size: inode=%lu ino=%lu\n", MAX_FILE_SECTIONS,
inode->i_ino, ino);
return 0;
}
 
if(bh == NULL || block != ino >> ISOFS_BUFFER_BITS(inode)) {
if(bh) brelse(bh);
block = ino >> ISOFS_BUFFER_BITS(inode);
if (!(bh=bread(inode->i_dev,block, bufsize))) {
printk("unable to read i-node block");
return 1;
}
}
pnt = ((unsigned char *) bh->b_data
+ (ino & (bufsize - 1)));
if ((ino & (bufsize - 1)) + *pnt > bufsize){
int frag1, offset;
offset = (ino & (bufsize - 1));
frag1 = bufsize - offset;
cpnt = kmalloc(*pnt,GFP_KERNEL);
if (cpnt == NULL) {
printk(KERN_INFO "NoMem ISO inode %lu\n",inode->i_ino);
brelse(bh);
return 1;
}
memcpy(cpnt, bh->b_data + offset, frag1);
brelse(bh);
if (!(bh = bread(inode->i_dev,++block, bufsize))) {
kfree(cpnt);
printk("unable to read i-node block");
return 1;
}
offset += *pnt - bufsize;
memcpy((char *)cpnt+frag1, bh->b_data, offset);
pnt = ((unsigned char *) cpnt);
}
if(*pnt == 0) {
ino = (ino & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE;
continue;
}
raw_inode = ((struct iso_directory_record *) pnt);
 
inode->i_size += isonum_733 (raw_inode->size);
if(i == 1) inode->u.isofs_i.i_next_section_ino = ino;
 
ino += *pnt;
if (cpnt) {
kfree (cpnt);
cpnt = NULL;
}
i++;
} while(raw_inode->flags[-inode->i_sb->u.isofs_sb.s_high_sierra] & 0x80);
brelse(bh);
return 0;
}
 
void isofs_read_inode(struct inode * inode)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
struct buffer_head * bh;
struct iso_directory_record * raw_inode;
unsigned char *pnt = NULL;
void *cpnt = NULL;
int high_sierra;
int block;
int volume_seq_no ;
int i;
 
block = inode->i_ino >> ISOFS_BUFFER_BITS(inode);
if (!(bh=bread(inode->i_dev,block, bufsize))) {
printk("unable to read i-node block");
goto fail;
}
pnt = ((unsigned char *) bh->b_data
+ (inode->i_ino & (bufsize - 1)));
raw_inode = ((struct iso_directory_record *) pnt);
high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
 
if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){
int frag1, offset;
 
offset = (inode->i_ino & (bufsize - 1));
frag1 = bufsize - offset;
cpnt = kmalloc(*pnt,GFP_KERNEL);
if (cpnt == NULL) {
printk(KERN_INFO "NoMem ISO inode %lu\n",inode->i_ino);
brelse(bh);
goto fail;
}
memcpy(cpnt, bh->b_data + offset, frag1);
brelse(bh);
if (!(bh = bread(inode->i_dev,++block, bufsize))) {
kfree(cpnt);
printk("unable to read i-node block");
goto fail;
}
offset += *pnt - bufsize;
memcpy((char *)cpnt+frag1, bh->b_data, offset);
pnt = ((unsigned char *) cpnt);
raw_inode = ((struct iso_directory_record *) pnt);
}
 
if (raw_inode->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
the find utility tries to optimize
if it is 2, and it screws up. It is
easier to give 1 which tells find to
do it the hard way. */
} else {
inode->i_mode = inode->i_sb->u.isofs_sb.s_mode; /* Everybody gets to read the file. */
inode->i_nlink = 1;
inode->i_mode |= S_IFREG;
/* If there are no periods in the name, then set the execute permission bit */
for(i=0; i< raw_inode->name_len[0]; i++)
if(raw_inode->name[i]=='.' || raw_inode->name[i]==';')
break;
if(i == raw_inode->name_len[0] || raw_inode->name[i] == ';')
inode->i_mode |= S_IXUGO; /* execute permission */
}
inode->i_uid = inode->i_sb->u.isofs_sb.s_uid;
inode->i_gid = inode->i_sb->u.isofs_sb.s_gid;
 
inode->u.isofs_i.i_section_size = isonum_733 (raw_inode->size);
if(raw_inode->flags[-high_sierra] & 0x80) {
if(isofs_read_level3_size(inode)) goto fail;
} else {
inode->i_size = isonum_733 (raw_inode->size);
}
 
/* There are defective discs out there - we do this to protect
ourselves. A cdrom will never contain more than 800Mb
Allow 1Gig for DVD however - Ulrich Habel */
if((inode->i_size < 0 || inode->i_size > 1073741824) &&
inode->i_sb->u.isofs_sb.s_cruft == 'n') {
printk("Warning: defective cdrom. Enabling \"cruft\" mount option.\n");
inode->i_sb->u.isofs_sb.s_cruft = 'y';
}
 
/* Some dipshit decided to store some other bit of information in the high
byte of the file length. Catch this and holler. WARNING: this will make
it impossible for a file to be > 16Mb on the CDROM!!!*/
 
if(inode->i_sb->u.isofs_sb.s_cruft == 'y' &&
inode->i_size & 0xff000000){
/* printk("Illegal format on cdrom. Pester manufacturer.\n"); */
inode->i_size &= 0x00ffffff;
}
if (raw_inode->interleave[0]) {
printk("Interleaved files not (yet) supported.\n");
inode->i_size = 0;
}
 
/* I have no idea what file_unit_size is used for, so
we will flag it for now */
if(raw_inode->file_unit_size[0] != 0){
printk("File unit size != 0 for ISO file (%ld).\n",inode->i_ino);
}
 
/* I have no idea what other flag bits are used for, so
we will flag it for now */
#ifdef DEBUG
if((raw_inode->flags[-high_sierra] & ~2)!= 0){
printk("Unusual flag settings for ISO file (%ld %x).\n",
inode->i_ino, raw_inode->flags[-high_sierra]);
}
#endif
 
#ifdef DEBUG
printk("Get inode %d: %d %d: %d\n",inode->i_ino, block,
((int)pnt) & 0x3ff, inode->i_size);
#endif
inode->i_mtime = inode->i_atime = inode->i_ctime =
iso_date(raw_inode->date, high_sierra);
 
inode->u.isofs_i.i_first_extent = (isonum_733 (raw_inode->extent) +
isonum_711 (raw_inode->ext_attr_length))
<< inode -> i_sb -> u.isofs_sb.s_log_zone_size;
inode->u.isofs_i.i_backlink = 0xffffffff; /* Will be used for previous directory */
switch (inode->i_sb->u.isofs_sb.s_conversion){
case 'a':
inode->u.isofs_i.i_file_format = ISOFS_FILE_UNKNOWN; /* File type */
break;
case 'b':
inode->u.isofs_i.i_file_format = ISOFS_FILE_BINARY; /* File type */
break;
case 't':
inode->u.isofs_i.i_file_format = ISOFS_FILE_TEXT; /* File type */
break;
case 'm':
inode->u.isofs_i.i_file_format = ISOFS_FILE_TEXT_M; /* File type */
break;
}
 
/* Now test for possible Rock Ridge extensions which will override some of
these numbers in the inode structure. */
 
if (!high_sierra) {
parse_rock_ridge_inode(raw_inode, inode);
/* hmm..if we want uid or gid set, override the rock ridge setting */
test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid);
}
#ifdef DEBUG
printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent);
#endif
brelse(bh);
inode->i_op = NULL;
 
/* get the volume sequence number */
volume_seq_no = isonum_723 (raw_inode->volume_sequence_number) ;
 
/*
* Disable checking if we see any volume number other than 0 or 1.
* We could use the cruft option, but that has multiple purposes, one
* of which is limiting the file size to 16Mb. Thus we silently allow
* volume numbers of 0 to go through without complaining.
*/
if (inode->i_sb->u.isofs_sb.s_cruft == 'n' &&
(volume_seq_no != 0) && (volume_seq_no != 1)) {
printk("Warning: defective cdrom (volume sequence number). Enabling \"cruft\" mount option.\n");
inode->i_sb->u.isofs_sb.s_cruft = 'y';
}
 
#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
if (inode->i_sb->u.isofs_sb.s_cruft != 'y' &&
(volume_seq_no != 0) && (volume_seq_no != 1)) {
printk("Multi volume CD somehow got mounted.\n");
} else
#endif IGNORE_WRONG_MULTI_VOLUME_SPECS
{
if (S_ISREG(inode->i_mode))
inode->i_op = &isofs_file_inode_operations;
else if (S_ISDIR(inode->i_mode))
inode->i_op = &isofs_dir_inode_operations;
else if (S_ISLNK(inode->i_mode))
inode->i_op = &isofs_symlink_inode_operations;
else if (S_ISCHR(inode->i_mode))
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
}
if (cpnt) {
kfree (cpnt);
cpnt = NULL;
}
return;
fail:
/* With a data error we return this information */
inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
inode->u.isofs_i.i_first_extent = 0;
inode->u.isofs_i.i_backlink = 0xffffffff;
inode->i_size = 0;
inode->i_nlink = 1;
inode->i_uid = inode->i_gid = 0;
inode->i_mode = S_IFREG; /*Regular file, no one gets to read*/
inode->i_op = NULL;
return;
}
 
/* There are times when we need to know the inode number of a parent of
a particular directory. When control passes through a routine that
has access to the parent information, it fills it into the inode structure,
but sometimes the inode gets flushed out of the queue, and someone
remembers the number. When they try to open up again, we have lost
the information. The '..' entry on the disc points to the data area
for a particular inode, so we can follow these links back up, but since
we do not know the inode number, we do not actually know how large the
directory is. The disc is almost always correct, and there is
enough error checking on the drive itself, but an open ended search
makes me a little nervous.
 
The bsd iso filesystem uses the extent number for an inode, and this
would work really nicely for us except that the read_inode function
would not have any clean way of finding the actual directory record
that goes with the file. If we had such info, then it would pay
to change the inode numbers and eliminate this function.
*/
 
int isofs_lookup_grandparent(struct inode * parent, int extent)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(parent);
unsigned char bufbits = ISOFS_BUFFER_BITS(parent);
unsigned int block,offset;
int parent_dir, inode_number;
int old_offset;
void * cpnt = NULL;
int result;
int directory_size;
struct buffer_head * bh;
struct iso_directory_record * de;
offset = 0;
block = extent << (ISOFS_ZONE_BITS(parent) - bufbits);
if (!(bh = bread(parent->i_dev, block, bufsize))) return -1;
while (1 == 1) {
de = (struct iso_directory_record *) (bh->b_data + offset);
if (*((unsigned char *) de) == 0)
{
brelse(bh);
printk("Directory .. not found\n");
return -1;
}
offset += *((unsigned char *) de);
 
if (offset >= bufsize)
{
printk(".. Directory not in first block"
" of directory.\n");
brelse(bh);
return -1;
}
if (de->name_len[0] == 1 && de->name[0] == 1)
{
parent_dir = find_rock_ridge_relocation(de, parent);
directory_size = isonum_733 (de->size);
brelse(bh);
break;
}
}
#ifdef DEBUG
printk("Parent dir:%x\n",parent_dir);
#endif
/* Now we know the extent where the parent dir starts on. */
result = -1;
 
offset = 0;
block = parent_dir << (ISOFS_ZONE_BITS(parent) - bufbits);
if (!block || !(bh = bread(parent->i_dev,block, bufsize)))
{
return -1;
}
for(;;)
{
de = (struct iso_directory_record *) (bh->b_data + offset);
inode_number = (block << bufbits)+(offset & (bufsize - 1));
/* If the length byte is zero, we should move on to the next
CDROM sector. If we are at the end of the directory, we
kick out of the while loop. */
if (*((unsigned char *) de) == 0)
{
brelse(bh);
offset = 0;
block++;
directory_size -= bufsize;
if(directory_size < 0) return -1;
if((block & 1) && (ISOFS_ZONE_BITS(parent) - bufbits) == 1)
{
return -1;
}
if((block & 3) && (ISOFS_ZONE_BITS(parent) - bufbits) == 2)
{
return -1;
}
if (!block
|| !(bh = bread(parent->i_dev,block, bufsize)))
{
return -1;
}
continue;
}
/* Make sure that the entire directory record is in the current
bh block. If not, we malloc a buffer, and put the two
halves together, so that we can cleanly read the block. */
 
old_offset = offset;
offset += *((unsigned char *) de);
 
if (offset >= bufsize)
{
unsigned int frag1;
frag1 = bufsize - old_offset;
cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
if (!cpnt) return -1;
memcpy(cpnt, bh->b_data + old_offset, frag1);
de = (struct iso_directory_record *) ((char *)cpnt);
brelse(bh);
offset -= bufsize;
directory_size -= bufsize;
if(directory_size < 0)
{
printk("Directory size < 0\n");
return -1;
}
block++;
if(!(bh = bread(parent->i_dev,block,bufsize))) {
kfree(cpnt);
return -1;
}
memcpy((char *)cpnt+frag1, bh->b_data, offset);
}
if (find_rock_ridge_relocation(de, parent) == extent){
result = inode_number;
goto out;
}
if (cpnt) {
kfree(cpnt);
cpnt = NULL;
}
}
 
/* We go here for any condition we cannot handle.
We also drop through to here at the end of the directory. */
 
out:
if (cpnt) {
kfree(cpnt);
cpnt = NULL;
}
brelse(bh);
#ifdef DEBUG
printk("Resultant Inode %d\n",result);
#endif
return result;
}
#ifdef LEAK_CHECK
#undef malloc
#undef free_s
#undef bread
#undef brelse
 
void * leak_check_malloc(unsigned int size){
void * tmp;
check_malloc++;
tmp = kmalloc(size, GFP_KERNEL);
return tmp;
}
 
void leak_check_free_s(void * obj, int size){
check_malloc--;
return kfree_s(obj, size);
}
 
struct buffer_head * leak_check_bread(int dev, int block, int size){
check_bread++;
return bread(dev, block, size);
}
 
void leak_check_brelse(struct buffer_head * bh){
check_bread--;
return brelse(bh);
}
 
#endif
 
static struct file_system_type iso9660_fs_type = {
isofs_read_super, "iso9660", 1, NULL
};
 
int init_iso9660_fs(void)
{
return register_filesystem(&iso9660_fs_type);
}
 
#ifdef MODULE
int init_module(void)
{
int status;
 
if ((status = init_iso9660_fs()) == 0)
register_symtab(0);
return status;
}
 
void cleanup_module(void)
{
unregister_filesystem(&iso9660_fs_type);
}
 
#endif
 
/file.c
0,0 → 1,56
/*
* linux/fs/isofs/file.c
*
* (C) 1992, 1993, 1994 Eric Youngdale Modified for ISO9660 filesystem.
*
* (C) 1991 Linus Torvalds - minix filesystem
*
* isofs regular file handling primitives
*/
 
#include <linux/sched.h>
#include <linux/iso_fs.h>
#include <linux/fcntl.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/locks.h>
#include <linux/fs.h>
#include <linux/iso_fs.h>
 
/*
* We have mostly NULL's here: the current defaults are ok for
* the isofs filesystem.
*/
static struct file_operations isofs_file_operations = {
NULL, /* lseek - default */
generic_file_read, /* read */
NULL, /* write */
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
generic_file_mmap, /* mmap */
NULL, /* no special open is needed */
NULL, /* release */
NULL /* fsync */
};
 
struct inode_operations isofs_file_inode_operations = {
&isofs_file_operations, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
isofs_bmap, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
/rock.h
0,0 → 1,114
/* These structs are used by the system-use-sharing protocol, in which the
Rock Ridge extensions are embedded. It is quite possible that other
extensions are present on the disk, and this is fine as long as they
all use SUSP */
/*
* Altered for word-aligned structure problems on ARM by Russell King.
*/
 
struct SU_SP{
unsigned char magic[2];
unsigned char skip;
};
 
struct SU_CE{
char extent[8];
char offset[8];
char size[8];
};
 
struct SU_ER{
unsigned char len_id;
unsigned char len_des;
unsigned char len_src;
unsigned char ext_ver;
char data[0];
};
 
struct RR_RR{
char flags[1];
};
 
struct RR_PX{
char mode[8];
char n_links[8];
char uid[8];
char gid[8];
};
 
struct RR_PN{
char dev_high[8];
char dev_low[8];
};
 
 
struct SL_component{
unsigned char flags;
unsigned char len;
char text[0];
};
 
struct RR_SL{
unsigned char flags;
unsigned char __link,__dummy;
};
 
struct RR_NM{
unsigned char flags;
char name[0];
};
 
struct RR_CL{
char location[8];
};
 
struct RR_PL{
char location[8];
};
 
struct stamp{
char time[7];
};
 
struct RR_TF{
char flags;
unsigned char __times[0];
};
 
/* These are the bits and their meanings for flags in the TF structure. */
#define TF_CREATE 1
#define TF_MODIFY 2
#define TF_ACCESS 4
#define TF_ATTRIBUTES 8
#define TF_BACKUP 16
#define TF_EXPIRATION 32
#define TF_EFFECTIVE 64
#define TF_LONG_FORM 128
 
struct rock_ridge{
char signature[2];
unsigned char len;
unsigned char version;
union{
struct SU_SP SP;
struct SU_CE CE;
struct SU_ER ER;
struct RR_RR RR;
struct RR_PX PX;
struct RR_PN PN;
struct RR_SL SL;
struct RR_NM NM;
struct RR_CL CL;
struct RR_PL PL;
struct RR_TF TF;
} u;
};
 
#define RR_PX 1 /* POSIX attributes */
#define RR_PN 2 /* POSIX devices */
#define RR_SL 4 /* Symbolic link */
#define RR_NM 8 /* Alternate Name */
#define RR_CL 16 /* Child link */
#define RR_PL 32 /* Parent link */
#define RR_RE 64 /* Relocation directory */
#define RR_TF 128 /* Timestamps */
/symlink.c
0,0 → 1,108
/*
* linux/fs/isofs/symlink.c
*
* (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* isofs symlink handling code. This is only used with the Rock Ridge
* extensions to iso9660
*/
 
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/iso_fs.h>
#include <linux/stat.h>
#include <linux/malloc.h>
 
#include <asm/segment.h>
 
static int isofs_readlink(struct inode *, char *, int);
static int isofs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
 
/*
* symlinks can't do much...
*/
struct inode_operations isofs_symlink_inode_operations = {
NULL, /* no file-operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
isofs_readlink, /* readlink */
isofs_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
static int isofs_follow_link(struct inode * dir, struct inode * inode,
int flag, int mode, struct inode ** res_inode)
{
int error;
char * pnt;
 
if (!dir) {
dir = current->fs->root;
dir->i_count++;
}
if (!inode) {
iput(dir);
*res_inode = NULL;
return -ENOENT;
}
if (!S_ISLNK(inode->i_mode)) {
iput(dir);
*res_inode = inode;
return 0;
}
if ((current->link_count > 5) ||
!(pnt = get_rock_ridge_symlink(inode))) {
iput(dir);
iput(inode);
*res_inode = NULL;
return -ELOOP;
}
iput(inode);
current->link_count++;
error = open_namei(pnt,flag,mode,res_inode,dir);
current->link_count--;
kfree(pnt);
return error;
}
 
static int isofs_readlink(struct inode * inode, char * buffer, int buflen)
{
char * pnt;
int i;
char c;
 
if (!S_ISLNK(inode->i_mode)) {
iput(inode);
return -EINVAL;
}
 
if (buflen > 1023)
buflen = 1023;
pnt = get_rock_ridge_symlink(inode);
 
iput(inode);
if (!pnt)
return 0;
i = 0;
 
while (i<buflen && (c = pnt[i])) {
i++;
put_user(c,buffer++);
}
kfree(pnt);
return i;
}
/joliet.c
0,0 → 1,117
/*
* linux/fs/isofs/joliet.c
*
* (C) 1996 Gordon Chaffee
*
* Joliet: Microsoft's Unicode extensions to iso9660
*/
 
#include <linux/string.h>
#include <linux/nls.h>
#include <linux/malloc.h>
#include <linux/iso_fs.h>
 
/*
* Convert Unicode 16 to UTF8 or ascii.
*/
static int
uni16_to_x8(unsigned char *ascii, unsigned char *uni, int len,
struct nls_table *nls)
{
unsigned char *ip, *op;
unsigned char ch, cl;
unsigned char *uni_page;
 
ip = uni;
op = ascii;
 
while ((*ip || ip[1]) && len) {
ch = *ip++;
cl = *ip++;
 
uni_page = nls->page_uni2charset[ch];
if (uni_page && uni_page[cl]) {
*op++ = uni_page[cl];
} else {
*op++ = '?';
}
len--;
}
*op = 0;
return (op - ascii);
}
 
/* Convert big endian wide character string to utf8 */
static int
wcsntombs_be(__u8 *s, const __u8 *pwcs, int inlen, int maxlen)
{
const __u8 *ip;
__u8 *op;
int size;
__u16 c;
 
op = s;
ip = pwcs;
while ((*ip || ip[1]) && (maxlen > 0) && (inlen > 0)) {
c = (*ip << 8) | ip[1];
if (c > 0x7f) {
size = utf8_wctomb(op, c, maxlen);
if (size == -1) {
/* Ignore character and move on */
maxlen--;
} else {
op += size;
maxlen -= size;
}
} else {
*op++ = (__u8) c;
}
ip += 2;
inlen--;
}
return (op - s);
}
 
int
get_joliet_filename(struct iso_directory_record * de, struct inode * inode,
unsigned char *outname)
{
unsigned char utf8;
struct nls_table *nls;
unsigned char len = 0;
int i;
char c;
 
utf8 = inode->i_sb->u.isofs_sb.s_utf8;
nls = inode->i_sb->u.isofs_sb.s_nls_iocharset;
 
if (utf8) {
len = wcsntombs_be(outname, de->name,
de->name_len[0] >> 1, PAGE_SIZE);
} else {
len = uni16_to_x8(outname, de->name,
de->name_len[0] >> 1, nls);
}
if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1')) {
len -= 2;
}
 
/*
* Windows doesn't like periods at the end of a name
*/
while (len >= 2 && (outname[len-1] == '.')) {
len--;
}
 
if (inode->i_sb->u.isofs_sb.s_name_check == 'r') {
for (i = 0; i < len; i++) {
c = outname[i];
/* lower case */
if (c >= 'A' && c <= 'Z') c |= 0x20;
if (c == ';') c = '.';
outname[i] = c;
}
}
 
return len;
}
/namei.c
0,0 → 1,305
/*
* linux/fs/isofs/namei.c
*
* (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
*
* (C) 1991 Linus Torvalds - minix filesystem
*/
 
#include <linux/sched.h>
#include <linux/iso_fs.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <asm/segment.h>
#include <linux/malloc.h>
 
#include <linux/errno.h>
 
/*
* ok, we cannot use strncmp, as the name is not in our data space.
* Thus we'll have to use isofs_match. No big problem. Match also makes
* some sanity tests.
*
* NOTE! unlike strncmp, isofs_match returns 1 for success, 0 for failure.
*/
static int isofs_match(int len,const char * name, const char * compare, int dlen)
{
if (!compare)
return 0;
 
/* check special "." and ".." files */
if (dlen == 1) {
/* "." */
if (compare[0] == 0) {
if (!len)
return 1;
compare = ".";
} else if (compare[0] == 1) {
compare = "..";
dlen = 2;
}
}
#if 0
if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen);
#endif
if (dlen != len)
return 0;
return !memcmp(name, compare, len);
}
 
/*
* isofs_find_entry()
*
* finds an entry in the specified directory with the wanted name. It
* returns the cache buffer in which the entry was found, and the entry
* itself (as an inode number). It does NOT read the inode of the
* entry - you'll have to do that yourself if you want to.
*/
static struct buffer_head *
isofs_find_entry(struct inode * dir, const char * name, int namelen,
unsigned long * ino, unsigned long * ino_back)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
unsigned int block, i, f_pos, offset, inode_number;
struct buffer_head * bh;
void * cpnt = NULL;
unsigned int old_offset;
unsigned int backlink;
int dlen, match;
char * dpnt;
unsigned char *page = NULL;
struct iso_directory_record * de;
char c;
 
*ino = 0;
if (!dir) return NULL;
if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
f_pos = 0;
 
offset = f_pos & (bufsize - 1);
block = isofs_bmap(dir,f_pos >> bufbits);
 
if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
while (f_pos < dir->i_size) {
de = (struct iso_directory_record *) (bh->b_data + offset);
backlink = dir->i_ino;
inode_number = (block << bufbits) + (offset & (bufsize - 1));
 
/* If byte is zero, this is the end of file, or time to move to
the next sector. Usually 2048 byte boundaries. */
if (*((unsigned char *) de) == 0) {
brelse(bh);
offset = 0;
f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
+ ISOFS_BLOCK_SIZE);
block = isofs_bmap(dir,f_pos>>bufbits);
if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
return NULL;
continue; /* Will kick out if past end of directory */
}
 
old_offset = offset;
offset += *((unsigned char *) de);
f_pos += *((unsigned char *) de);
 
/* Handle case where the directory entry spans two blocks.
Usually 1024 byte boundaries */
if (offset >= bufsize) {
unsigned int frag1;
frag1 = bufsize - old_offset;
cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
if (!cpnt) return NULL;
memcpy(cpnt, bh->b_data + old_offset, frag1);
 
de = (struct iso_directory_record *) cpnt;
brelse(bh);
offset = f_pos & (bufsize - 1);
block = isofs_bmap(dir,f_pos>>bufbits);
if (!block || !(bh = bread(dir->i_dev,block,bufsize))) {
kfree(cpnt);
return NULL;
};
memcpy((char *)cpnt+frag1, bh->b_data, offset);
}
 
dlen = de->name_len[0];
dpnt = de->name;
 
/* Handle the '.' case */
if (*dpnt==0 && dlen==1) {
inode_number = dir->i_ino;
backlink = 0;
}
/* Handle the '..' case */
 
else if (*dpnt==1 && dlen==1) {
#if 0
printk("Doing .. (%d %d)",
dir->i_sb->s_firstdatazone,
dir->i_ino);
#endif
if((dir->i_sb->u.isofs_sb.s_firstdatazone) != dir->i_ino)
inode_number = dir->u.isofs_i.i_backlink;
else
inode_number = dir->i_ino;
backlink = 0;
} else {
if (dir->i_sb->u.isofs_sb.s_rock ||
dir->i_sb->u.isofs_sb.s_joliet_level) {
page = (unsigned char *)
__get_free_page(GFP_KERNEL);
if (!page) return NULL;
}
if (dir->i_sb->u.isofs_sb.s_rock &&
((i = get_rock_ridge_filename(de, page, dir)))){
if (i == -1)
goto out;/* Relocated deep directory */
dlen = i;
dpnt = page;
} else if (dir->i_sb->u.isofs_sb.s_joliet_level) {
dlen = get_joliet_filename(de, dir, page);
dpnt = page;
} else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') {
for (i = 0; i < dlen; i++) {
c = dpnt[i];
/* lower case */
if (c >= 'A' && c <= 'Z') c |= 0x20;
if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
dlen -= 2;
break;
}
if (c == ';') c = '.';
dpnt[i] = c;
}
/* This allows us to match with and without
* a trailing period. */
if(dpnt[dlen-1] == '.' && namelen == dlen-1)
dlen--;
}
}
/*
* Skip hidden or associated files unless unhide is set
*/
match = 0;
if( !(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5)
|| dir->i_sb->u.isofs_sb.s_unhide == 'y' )
{
match = isofs_match(namelen,name,dpnt,dlen);
}
 
if (cpnt)
{
kfree(cpnt);
cpnt = NULL;
}
 
if (page) free_page((unsigned long) page);
if (match) {
if(inode_number == -1) {
/* Should only happen for the '..' entry */
inode_number =
isofs_lookup_grandparent(dir,
find_rock_ridge_relocation(de,dir));
if(inode_number == -1){
/* Should never happen */
printk("Backlink not properly set %x %lx.\n",
isonum_733(de->extent),
dir->i_ino);
goto out;
}
}
*ino = inode_number;
*ino_back = backlink;
return bh;
}
}
out:
if (cpnt)
kfree(cpnt);
brelse(bh);
return NULL;
}
 
int isofs_lookup(struct inode * dir,const char * name, int len,
struct inode ** result)
{
unsigned long ino, ino_back;
struct buffer_head * bh;
 
#ifdef DEBUG
printk("lookup: %x %d\n",dir->i_ino, len);
#endif
*result = NULL;
if (!dir)
return -ENOENT;
 
if (!S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOENT;
}
 
ino = 0;
 
if (dcache_lookup(dir, name, len, &ino)) ino_back = dir->i_ino;
 
 
if (!ino) {
char *lcname;
 
/* First try the original name. If that doesn't work and the fs
* was mounted with check=relaxed, convert the name to lower
* case and try again.
*/
if (!(bh = isofs_find_entry(dir,name,len, &ino, &ino_back))
&& dir->i_sb->u.isofs_sb.s_name_check == 'r'
&& (lcname = kmalloc(len, GFP_KERNEL)) != NULL) {
int i;
char c;
 
for (i=0; i<len; i++) {
c = name[i];
if (c >= 'A' && c <= 'Z') c |= 0x20;
lcname[i] = c;
}
bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back);
kfree(lcname);
}
 
if (!bh) {
iput(dir);
return -ENOENT;
}
if (ino_back == dir->i_ino) {
dcache_add(dir, name, len, ino);
}
brelse(bh);
}
 
if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -EACCES;
}
 
/* We need this backlink for the ".." entry unless the name that we
are looking up traversed a mount point (in which case the inode
may not even be on an iso9660 filesystem, and writing to
u.isofs_i would only cause memory corruption).
*/
if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
(*result)->u.isofs_i.i_backlink = ino_back;
}
iput(dir);
return 0;
}
/Makefile
0,0 → 1,14
#
# Makefile for the linux isofs-filesystem routines.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
# Note 2! The CFLAGS definitions are now in the main makefile...
 
O_TARGET := isofs.o
O_OBJS := namei.o inode.o file.o dir.o util.o rock.o symlink.o joliet.o
M_OBJS := $(O_TARGET)
 
include $(TOPDIR)/Rules.make
/util.c
0,0 → 1,135
/*
* 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 <pace@blitz.com>.
*/
 
#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));
}
 
/* We have to convert from a MM/DD/YY format to the unix ctime format.
* We have to take into account leap years and all of that good stuff.
*/
int iso_date(char * p, int flag)
{
int year, month, day, hour ,minute, second, tz;
int crtime, days, i;
 
year = p[0] - 70;
month = p[1];
day = p[2];
hour = p[3];
minute = p[4];
second = p[5];
if (flag == 0) tz = p[6]; /* High sierra has no time zone */
else tz = 0;
if (year < 0) {
crtime = 0;
} else {
int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
extern struct timezone sys_tz;
 
days = year * 365;
if (year > 2)
days += (year+1) / 4;
for (i = 1; i < month; i++)
days += monlen[i-1];
if (((year+2) % 4) == 0 && month > 2)
days++;
days += day - 1;
crtime = ((((days * 24) + hour) * 60 + minute) * 60)
+ second;
if (sys_tz.tz_dsttime)
crtime -= 3600;
 
/* sign extend */
if (tz & 0x80)
tz |= (-1 << 8);
/* timezone offset is unreliable on some disks */
if (-48 <= tz && tz <= 52)
crtime += tz * 15 * 60;
}
return crtime;
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.