/*
* This code is based on the ISO filesystem support in MILO (by
* Dave Rusling).
*
* This is a set of functions that provides minimal filesystem
* functionality to the Linux bootstrapper. All we can do is
* open and read files... but that's all we need 8-)
*/
#include <linux/stat.h>
#include <sys/types.h>
#include "string.h"
#include "iso.h"
#include "isolib.h"
#include "utils.h"
/* iso9660 support code */
#define MAX_OPEN_FILES 5
static struct inode_table_entry {
struct iso_inode inode;
int inumber;
int free;
unsigned short old_mode;
unsigned size;
int nlink;
int mode;
void *start;
} inode_table[MAX_OPEN_FILES];
static unsigned long root_inode = 0;
static struct isofs_super_block sb;
static char data_block[1024];
static char big_data_block[2048];
#ifndef S_IRWXUGO
# define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
# define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
# define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
#endif
extern long iso_dev_read (void * buf, long offset, long size);
static int parse_rock_ridge_inode(struct iso_directory_record * de,
struct iso_inode * inode);
static char *get_rock_ridge_symlink(struct iso_inode *inode);
static int get_rock_ridge_filename(struct iso_directory_record * de,
char * retname,
struct iso_inode * inode);
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)
{
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)
{
return isonum_731(p);
}
static int
iso_bmap (struct iso_inode *inode, int block)
{
if (block < 0) {
printf("iso_bmap: block<0");
return 0;
}
return (inode->i_first_extent >> sb.s_blocksize_bits) + block;
}
static int
iso_breadi (struct iso_inode *ip, long blkno, long nblks, char * buffer)
{
long i_size, abs_blkno;
/* do some error checking */
if (!ip || !ip->i_first_extent)
return -1;
i_size = ((struct inode_table_entry *) ip)->size;
/* as in ext2.c - cons_read() doesn't really cope well with
EOF conditions - actually it should be fixed */
if ((blkno+nblks) * sb.s_blocksize > i_size)
nblks = ((i_size + sb.s_blocksize)
/ sb.s_blocksize) - blkno;
/* figure out which iso block number(s) we're being asked for */
abs_blkno = iso_bmap(ip, blkno);
if (!abs_blkno)
return -1;
/* now try and read them (easy since ISO files are continguous) */
return iso_dev_read(buffer, abs_blkno * sb.s_blocksize,
nblks * sb.s_blocksize);
}
/*
* Release our hold on an inode. Since this is a read-only application,
* don't worry about putting back any changes...
*/
static void
iso_iput (struct iso_inode *ip)
{
struct inode_table_entry *itp;
/* Find and free the inode table slot we used... */
itp = (struct inode_table_entry *) ip;
itp->inumber = 0;
itp->free = 1;
}
/*
* Read the specified inode from the disk and return it to the user.
* Returns NULL if the inode can't be read...
*
* Uses data_block
*/
static struct iso_inode *
iso_iget (int ino)
{
int i;
struct iso_inode *inode;
struct inode_table_entry *itp;
struct iso_directory_record * raw_inode;
unsigned char *pnt = NULL;
void *cpnt = NULL;
int high_sierra;
int block;
#ifdef DEBUG_ISO
printf("iso_iget(ino=%d)\n", ino);
#endif
/* find a free inode to play with */
inode = NULL;
itp = NULL;
for (i = 0; i < MAX_OPEN_FILES; i++) {
if (inode_table[i].free) {
itp = &(inode_table[i]);
inode = &(itp->inode);
break;
}
}
if ((inode == NULL) || (itp == NULL)) {
printf("iso9660 (iget): no free inodes\n");
return (NULL);
}
block = ino >> sb.s_blocksize_bits;
if (iso_dev_read(data_block, block * sb.s_blocksize, sb.s_blocksize)
!= sb.s_blocksize) {
printf("iso9660: unable to read i-node block");
return NULL;
}
pnt = ((unsigned char *) data_block + (ino & (sb.s_blocksize - 1)));
raw_inode = ((struct iso_directory_record *) pnt);
high_sierra = sb.s_high_sierra;
if ((ino & (sb.s_blocksize - 1)) + *pnt > sb.s_blocksize){
int frag1, offset;
offset = (ino & (sb.s_blocksize - 1));
frag1 = sb.s_blocksize - offset;
cpnt = big_data_block;
memcpy(cpnt, data_block + offset, frag1);
offset += *pnt - sb.s_blocksize; /* DUH! pnt would get
wiped out by the
iso_dev_read here. */
if (iso_dev_read(data_block, ++block * sb.s_blocksize,
sb.s_blocksize)
!= sb.s_blocksize) {
printf("unable to read i-node block");
return NULL;
}
memcpy((char *)cpnt+frag1, data_block, offset);
pnt = ((unsigned char *) cpnt);
raw_inode = ((struct iso_directory_record *) pnt);
}
if (raw_inode->flags[-high_sierra] & 2) {
itp->mode = S_IRUGO | S_IXUGO | S_IFDIR;
itp->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 {
itp->mode = sb.s_mode; /* Everybody gets to read the file. */
itp->nlink = 1;
itp->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] == ';')
itp->mode |= S_IXUGO; /* execute permission */
}
itp->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 700Mb */
if((itp->size < 0 || itp->size > 700000000) &&
sb.s_cruft == 'n')
{
printf("Warning: defective cdrom. "
|