diff options
Diffstat (limited to 'package/aboot/src/lib')
-rw-r--r-- | package/aboot/src/lib/Makefile | 42 | ||||
-rw-r--r-- | package/aboot/src/lib/_longjmp.S | 61 | ||||
-rw-r--r-- | package/aboot/src/lib/_setjmp.S | 36 | ||||
-rw-r--r-- | package/aboot/src/lib/divide.S | 160 | ||||
-rw-r--r-- | package/aboot/src/lib/isolib.c | 1590 | ||||
-rw-r--r-- | package/aboot/src/lib/memcpy.c | 23 | ||||
-rw-r--r-- | package/aboot/src/lib/memset.c | 28 | ||||
-rw-r--r-- | package/aboot/src/lib/string.c | 252 | ||||
-rw-r--r-- | package/aboot/src/lib/vsprintf.c | 317 |
9 files changed, 2509 insertions, 0 deletions
diff --git a/package/aboot/src/lib/Makefile b/package/aboot/src/lib/Makefile new file mode 100644 index 000000000..bd6d3c543 --- /dev/null +++ b/package/aboot/src/lib/Makefile @@ -0,0 +1,42 @@ +ifndef ($(CC)) +CC ?= gcc +endif + +override CPPFLAGS += -D__KERNEL__ -I../include +override ASFLAGS += $(CPPFLAGS) -D__ASSEMBLY__ -traditional + +ifeq ($(TESTING),) +ifeq ($(FOREIGN),"yes") +override CFLAGS += -Os -Wall -fno-builtin +else +override CFLAGS += -Os -Wall -mno-fp-regs -fno-builtin +endif +else +override CFLAGS += -Os -g3 -Wall +endif + +ifeq ($(TESTING),) +libaboot.a: vsprintf.o memcpy.o memset.o string.o _setjmp.o \ + _longjmp.o isolib.o __divqu.o __remqu.o __divlu.o \ + __remlu.o + ar cru $@ $? +else +libaboot.a: isolib.o + ar cru $@ $? +endif + +clean: + rm -f libaboot.a *.o + +__divqu.o: divide.S + $(CC) -DDIV -c -o $@ divide.S + +__remqu.o: divide.S + $(CC) -DREM -c -o $@ divide.S + +__divlu.o: divide.S + $(CC) -DDIV -DINTSIZE -c -o $@ divide.S + +__remlu.o: divide.S + $(CC) -DREM -DINTSIZE -c -o $@ divide.S + diff --git a/package/aboot/src/lib/_longjmp.S b/package/aboot/src/lib/_longjmp.S new file mode 100644 index 000000000..19b27a33c --- /dev/null +++ b/package/aboot/src/lib/_longjmp.S @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1995 David Mosberger (davidm@cs.arizona.edu) + */ +#include <setjmp.h> +#include "system.h" + + .extern printf + + .globl _longjmp + .ent _longjmp + +_longjmp: + ldgp $29, 0($27) + + mov $17, $0 + lda $1, JBMAGIC & 0xffff + ldah $1, ((JBMAGIC >> 16) & 0xffff)($1) + cmoveq $0, 1, $0 # ensure $0 != 0 + + ldq $2, JB_MAGIC($16) + subq $1, $2, $1 + ldq $30, JB_SP($16) + bne $1, bad_magic + + ldq $9, JB_S0($16) + ldq $10, JB_S1($16) + ldq $11, JB_S2($16) + ldq $12, JB_S3($16) + ldq $13, JB_S4($16) + ldq $14, JB_S5($16) + ldq $15, JB_S6($16) + ldq $29, JB_GP($16) + ldq $26, JB_RA($16) +#ifdef FPU + ldt $f2, JB_F2($16) + ldt $f3, JB_F3($16) + ldt $f4, JB_F4($16) + ldt $f5, JB_F5($16) + ldt $f6, JB_F6($16) + ldt $f7, JB_F7($16) + ldt $f8, JB_F8($16) + ldt $f9, JB_F9($16) +#endif + ret ($26) + + .data +error_msg: +#ifdef __osf__ + .asciiz "_longjmp: bad magic number" +#else + .asciz "_longjmp: bad magic number" +#endif + + .text +bad_magic: + lda $16, error_msg + lda $27, printf + jsr $27, printf + call_pal PAL_halt + + .end _longjmp diff --git a/package/aboot/src/lib/_setjmp.S b/package/aboot/src/lib/_setjmp.S new file mode 100644 index 000000000..98d6366bb --- /dev/null +++ b/package/aboot/src/lib/_setjmp.S @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1995 David Mosberger (davidm@cs.arizona.edu) + */ +#include <setjmp.h> + + .globl _setjmp + .ent _setjmp + +_setjmp: + stq $29, JB_GP($16) + stq $30, JB_SP($16) + stq $9, JB_S0($16) + stq $10, JB_S1($16) + stq $11, JB_S2($16) + stq $12, JB_S3($16) + stq $13, JB_S4($16) + stq $14, JB_S5($16) + stq $15, JB_S6($16) + stq $26, JB_RA($16) +#ifdef FPU + stt $f2, JB_F2($16) + stt $f3, JB_F3($16) + stt $f4, JB_F4($16) + stt $f5, JB_F5($16) + stt $f6, JB_F6($16) + stt $f7, JB_F7($16) + stt $f8, JB_F8($16) + stt $f9, JB_F9($16) +#endif + lda $1, JBMAGIC & 0xffff + ldah $1, ((JBMAGIC >> 16) & 0xffff)($1) + stq $1, JB_MAGIC($16) + clr $0 + ret ($26) + + .end _setjmp diff --git a/package/aboot/src/lib/divide.S b/package/aboot/src/lib/divide.S new file mode 100644 index 000000000..36668ab59 --- /dev/null +++ b/package/aboot/src/lib/divide.S @@ -0,0 +1,160 @@ +/* + * arch/alpha/lib/divide.S + * + * (C) 1995 Linus Torvalds + * + * Alpha division.. + */ + +/* + * The alpha chip doesn't provide hardware division, so we have to do it + * by hand. The compiler expects the functions + * + * __divqu: 64-bit unsigned long divide + * __remqu: 64-bit unsigned long remainder + * __divqs/__remqs: signed 64-bit + * __divlu/__remlu: unsigned 32-bit + * __divls/__remls: signed 32-bit + * + * These are not normal C functions: instead of the normal + * calling sequence, these expect their arguments in registers + * $24 and $25, and return the result in $27. Register $28 may + * be clobbered (assembly temporary), anything else must be saved. + * + * In short: painful. + * + * This is a rather simple bit-at-a-time algorithm: it's very good + * at dividing random 64-bit numbers, but the more usual case where + * the divisor is small is handled better by the DEC algorithm + * using lookup tables. This uses much less memory, though, and is + * nicer on the cache.. Besides, I don't know the copyright status + * of the DEC code. + */ + +/* + * My temporaries: + * $0 - current bit + * $1 - shifted divisor + * $2 - modulus/quotient + * + * $23 - return address + * $24 - dividend + * $25 - divisor + * + * $27 - quotient/modulus + * $28 - compare status + */ + +#define halt .long 0 + +/* + * Select function type and registers + */ +#define mask $0 +#define divisor $1 +#define compare $28 + +#ifdef DIV +#define func(x) __div##x +#define modulus $2 +#define quotient $27 +#define GETSIGN(x) xor $24,$25,x +#else +#define func(x) __rem##x +#define modulus $27 +#define quotient $2 +#define GETSIGN(x) bis $24,$24,x +#endif + +/* + * For 32-bit operations, we need to extend to 64-bit + */ +#ifdef INTSIZE +#define ufunction func(lu) +#define sfunction func(l) +#define LONGIFY(x) zapnot x,15,x +#define SLONGIFY(x) addl x,0,x +#else +#define ufunction func(qu) +#define sfunction func(q) +#define LONGIFY(x) +#define SLONGIFY(x) +#endif + +.set noat +.globl ufunction +.ent ufunction +ufunction: + subq $30,32,$30 + stq $0, 0($30) + stq $1, 8($30) + stq $2,16($30) + + bis $25,$25,divisor + bis $24,$24,modulus + bis $31,$31,quotient + LONGIFY(divisor) + LONGIFY(modulus) + beq divisor, 9f /* div by zero */ + bis $31,1,mask + + /* shift divisor left */ +1: cmpult divisor,modulus,compare + blt divisor, 3f + addq divisor,divisor,divisor + addq mask,mask,mask + bne compare,1b + + /* ok, start to go right again.. */ +2: srl divisor,1,divisor + beq mask,9f + srl mask,1,mask +3: cmpule divisor,modulus,compare + beq compare,2b + addq quotient,mask,quotient + beq mask,9f + subq modulus,divisor,modulus + br 2b + +9: ldq $0, 0($30) + ldq $1, 8($30) + ldq $2, 16($30) + addq $30,32,$30 + ret $31,($23),1 + .end ufunction + +/* + * Uhh.. Ugly signed division. I'd rather not have it at all, but + * it's needed in some circumstances. There are different ways to + * handle this, really. This does: + * -a / b = a / -b = -(a / b) + * -a % b = a % b + * a % -b = -(a % b) + * which is probably not the best solution, but at least should + * have the property that (x/y)*y + (x%y) = x. + */ +.globl sfunction +.ent sfunction +sfunction: + bis $24,$25,$28 + SLONGIFY($28) + bge $28,ufunction + subq $30,32,$30 + stq $23,0($30) + stq $24,8($30) + stq $25,16($30) + subq $31,$24,$28 + cmovlt $24,$28,$24 /* abs($24) */ + subq $31,$25,$28 + cmovlt $25,$28,$25 /* abs($25) */ + bsr $23,ufunction + ldq $23,0($30) + ldq $24,8($30) + ldq $25,16($30) + addq $30,32,$30 + GETSIGN($28) + SLONGIFY($28) + bge $28,1f + subq $31,$27,$27 +1: ret $31,($23),1 + .end sfunction diff --git a/package/aboot/src/lib/isolib.c b/package/aboot/src/lib/isolib.c new file mode 100644 index 000000000..f0d186e30 --- /dev/null +++ b/package/aboot/src/lib/isolib.c @@ -0,0 +1,1590 @@ +/* + * 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. " + "Enabling \"cruft\" mount option.\n"); + 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(sb.s_cruft == 'y' && + itp->size & 0xff000000) + { + itp->size &= 0x00ffffff; + } + + if (raw_inode->interleave[0]) { + printf("Interleaved files not (yet) supported.\n"); + itp->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){ + printf("File unit size != 0 for ISO file (%d).\n", ino); + } + + /* I have no idea what other flag bits are used for, so + we will flag it for now */ +#ifdef DEBUG_ISO + if ((raw_inode->flags[-high_sierra] & ~2)!= 0){ + printf("Unusual flag settings for ISO file (%d %x).\n", + ino, raw_inode->flags[-high_sierra]); + } +#endif + + inode->i_first_extent = (isonum_733 (raw_inode->extent) + + isonum_711 (raw_inode->ext_attr_length)) + << sb.s_log_zone_size; + + /* Now we check the Rock Ridge extensions for further info */ + + if (sb.s_rock) + parse_rock_ridge_inode(raw_inode,inode); + + /* Will be used for previous directory */ + inode->i_backlink = 0xffffffff; + switch (sb.s_conversion) { + case 'a': + inode->i_file_format = ISOFS_FILE_UNKNOWN; /* File type */ + break; + case 'b': + inode->i_file_format = ISOFS_FILE_BINARY; /* File type */ + break; + case 't': + inode->i_file_format = ISOFS_FILE_TEXT; /* File type */ + break; + case 'm': + inode->i_file_format = ISOFS_FILE_TEXT_M; /* File type */ + break; + } + + /* keep our inode table correct */ + itp->free = 0; + itp->inumber = ino; + + /* return a pointer to it */ + return inode; +} + + +/* + * ok, we cannot use strncmp, as the name is not in our data space. + * Thus we'll have to use iso_match. No big problem. Match also makes + * some sanity tests. + * + * NOTE! unlike strncmp, iso_match returns 1 for success, 0 for failure. + */ +static int +iso_match (int len, const char *name, const char *compare, int dlen) +{ + if (!compare) + return 0; + +#ifdef DEBUG_ISO + printf("iso_match: comparing %d chars of %s with %s\n", + dlen, name, compare); +#endif + + /* 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 (dlen != len) + return 0; + return !memcmp(name, compare, len); +} + +/* + * Find 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. + * + * uses data_block + */ +static int +iso_find_entry (struct iso_inode *dir, const char *name, int namelen, + unsigned long *ino, unsigned long *ino_back) +{ + unsigned long bufsize = sb.s_blocksize; + unsigned char bufbits = sb.s_blocksize_bits; + unsigned int block, f_pos, offset, inode_number = 0; /*shut up, gcc*/ + void * cpnt = NULL; + unsigned int old_offset; + unsigned int backlink; + int dlen, match, i; + struct iso_directory_record * de; + char c; + struct inode_table_entry *itp = (struct inode_table_entry *) dir; + + *ino = 0; + if (!dir) return -1; + + if (!(block = dir->i_first_extent)) return -1; + + f_pos = 0; + offset = 0; + block = iso_bmap(dir,f_pos >> bufbits); + if (!block) return -1; + + if (iso_dev_read(data_block, block * sb.s_blocksize, sb.s_blocksize) + != sb.s_blocksize) return -1; + + while (f_pos < itp->size) { + de = (struct iso_directory_record *) (data_block + offset); + backlink = itp->inumber; + 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) { + offset = 0; + + /* round f_pos up to the nearest blocksize */ + f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1)) + + ISOFS_BLOCK_SIZE); + block = iso_bmap(dir,f_pos>>bufbits); + if (!block) return -1; + if (iso_dev_read(data_block, + block * sb.s_blocksize, + sb.s_blocksize) + != sb.s_blocksize) return -1; + 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 = big_data_block; + memcpy(cpnt, data_block + old_offset, frag1); + + de = (struct iso_directory_record *) cpnt; + offset = f_pos & (bufsize - 1); + block = iso_bmap(dir,f_pos>>bufbits); + if (!block) return -1; + if (iso_dev_read(data_block, + block * sb.s_blocksize, + sb.s_blocksize) + != sb.s_blocksize) return 0; + memcpy((char *)cpnt+frag1, data_block, offset); + } + + /* Handle the '.' case */ + + if (de->name[0]==0 && de->name_len[0]==1) { + inode_number = itp->inumber; + backlink = 0; + } + + /* Handle the '..' case */ + + if (de->name[0]==1 && de->name_len[0]==1) { + + if((int) sb.s_firstdatazone != itp->inumber) + inode_number = (isonum_733(de->extent) + + isonum_711(de->ext_attr_length)) + << sb.s_log_zone_size; + else + inode_number = itp->inumber; + backlink = 0; + } + + { + /* should be sufficient, since get_rock_ridge_filename + * truncates at 254 chars */ + char retname[256]; + dlen = get_rock_ridge_filename(de, retname, dir); + if (dlen) { + strcpy(de->name, retname); + } else { + dlen = isonum_711(de->name_len); + if(sb.s_mapping == 'n') { + for (i = 0; i < dlen; i++) { + c = de->name[i]; + if (c >= 'A' && c <= 'Z') c |= 0x20; /* lower case */ + if (c == ';' && i == dlen-2 + && de->name[i+1] == '1') { + dlen -= 2; + break; + } + if (c == ';') c = '.'; + de->name[i] = c; + } + /* This allows us to match with and without a trailing + period. */ + if(de->name[dlen-1] == '.' && namelen == dlen-1) + dlen--; + } + } + } + /* + * Skip hidden or associated files unless unhide is set + */ + match = 0; + if( !(de->flags[-sb.s_high_sierra] & 5) + || sb.s_unhide == 'y' ) + { + match = iso_match(namelen, name, de->name, dlen); + } + + if (cpnt) cpnt = NULL; + + if (match) { + if ((int) inode_number == -1) { + /* Should never happen */ + printf("iso9660: error inode_number = -1\n"); + return -1; + } + + *ino = inode_number; + *ino_back = backlink; +#ifdef DEBUG_ISO + printf("iso_find_entry returning successfully (ino = %d)\n", + inode_number); +#endif + return 0; + } + } +#ifdef DEBUG_ISO + printf("iso_find_entry returning unsuccessfully (ino = %d)\n", + inode_number); +#endif + return -1; +} + + +/* + * Look up name in the current directory and return its corresponding + * inode if it can be found. + * + */ +struct iso_inode * +iso_lookup(struct iso_inode *dir, const char *name) +{ + struct inode_table_entry *itp = (struct inode_table_entry *) dir; + unsigned long ino, ino_back; + struct iso_inode *result = NULL; + int first, last; + +#ifdef DEBUG_ISO + printf("iso_lookup: %s\n", name); +#endif + + /* is the current inode a directory? */ + if (!S_ISDIR(itp->mode)) { +#ifdef DEBUG_ISO + printf("iso_lookup: inode %d not a directory\n", itp->inumber); +#endif + iso_iput(dir); + return NULL; + } + + /* work through the name finding each directory in turn */ + ino = 0; + first = last = 0; + while (last < (int) strlen(name)) { + if (name[last] == '/') { + if (iso_find_entry(dir, &name[first], last - first, + &ino, &ino_back)) + return NULL; + /* throw away the old directory inode, we + don't need it anymore */ + iso_iput(dir); + + if (!(dir = iso_iget(ino))) + return NULL; + first = last + 1; + last = first; + } else + last++; + } + { + int rv; + if ((rv = iso_find_entry(dir, &name[first], last - first, &ino, &ino_back))) { + iso_iput(dir); + return NULL; + } + } + if (!(result = iso_iget(ino))) { + iso_iput(dir); + return NULL; + } + /* + * 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). + */ + result->i_backlink = ino_back; + + iso_iput(dir); + return result; +} + +/* follow a symbolic link, returning the inode of the file it points to */ +static struct iso_inode * +iso_follow_link(struct iso_inode *from, const char *basename) +{ + struct inode_table_entry *itp = (struct inode_table_entry *)from; + struct iso_inode *root = iso_iget(root_inode); + /* HK: iso_iget expects an "int" but root_inode is "long" ?? */ + struct iso_inode *result = NULL; + char *linkto; + +#ifdef DEBUG_ISO + printf("iso_follow_link(%s): ",basename); +#endif + + if (!S_ISLNK(itp->mode)) /* Hey, that's not a link! */ + return NULL; + + if (!itp->size) + return NULL; + + if (!(linkto = get_rock_ridge_symlink(from))) + return NULL; + + linkto[itp->size]='\0'; +#ifdef DEBUG_ISO + printf("%s->%s\n",basename,linkto ? linkto : "[failed]"); +#endif + + /* Resolve relative links. */ + + if (linkto[0] !='/') { + char *end = strrchr(basename, '/'); + if (end) { + char fullname[(end - basename + 1) + strlen(linkto) + 1]; + strncpy(fullname, basename, end - basename + 1); + fullname[end - basename + 1] = '\0'; + strcat(fullname, linkto); +#ifdef DEBUG_ISO + printf("resolved to %s\n", fullname); +#endif + result = iso_lookup(root,fullname); + } else { + /* Assume it's in the root */ + result = iso_lookup(root,linkto); + } + } else { + result = iso_lookup(root,linkto); + } + free(linkto); + iso_iput(root); + return result; +} + +/* + * look if the driver can tell the multi session redirection value + */ +static inline unsigned int +iso_get_last_session (void) +{ +#ifdef DEBUG_ISO + printf("iso_get_last_session() called\n"); +#endif + return 0; +} + + +int +iso_read_super (void *data, int silent) +{ + static int first_time = 1; + int high_sierra; + unsigned int iso_blknum, vol_desc_start; + char rock = 'y'; + int i; + + struct iso_volume_descriptor *vdp; + struct hs_volume_descriptor *hdp; + + struct iso_primary_descriptor *pri = NULL; + struct hs_primary_descriptor *h_pri = NULL; + + struct iso_directory_record *rootp; + + /* Initialize the inode table */ + for (i = 0; i < MAX_OPEN_FILES; i++) { + inode_table[i].free = 1; + inode_table[i].inumber = 0; + } + +#ifdef DEBUG_ISO + printf("iso_read_super() called\n"); +#endif + + /* set up the block size */ + sb.s_blocksize = 1024; + sb.s_blocksize_bits = 10; + + sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */ + + vol_desc_start = iso_get_last_session(); + + for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; + iso_blknum++) { +#ifdef DEBUG_ISO + printf("iso_read_super: iso_blknum=%d\n", iso_blknum); +#endif + if (iso_dev_read(data_block, iso_blknum * 2048, + sb.s_blocksize) != sb.s_blocksize) + { + printf("iso_read_super: bread failed, dev " + "iso_blknum %d\n", iso_blknum); + return -1; + } + vdp = (struct iso_volume_descriptor *)data_block; + hdp = (struct hs_volume_descriptor *)data_block; + + if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) { + if (isonum_711 (hdp->type) != ISO_VD_PRIMARY) + return -1; + if (isonum_711 (hdp->type) == ISO_VD_END) + return -1; + + sb.s_high_sierra = 1; + high_sierra = 1; + 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_PRIMARY) + return -1; + if (isonum_711 (vdp->type) == ISO_VD_END) + return -1; + + pri = (struct iso_primary_descriptor *)vdp; + break; + } + } + if(iso_blknum == vol_desc_start + 100) { + if (!silent) + printf("iso: Unable to identify CD-ROM format.\n"); + return -1; + } + + if (high_sierra) { + rootp = (struct iso_directory_record *) + h_pri->root_directory_record; +#if 0 +//See http://www.y-adagio.com/public/standards/iso_cdromr/sect_1.htm +//Section 4.16 and 4.17 for explanation why this check is invalid + if (isonum_723 (h_pri->volume_set_size) != 1) { + printf("Multi-volume disks not (yet) supported.\n"); + return -1; + }; +#endif + sb.s_nzones = isonum_733 (h_pri->volume_space_size); + sb.s_log_zone_size = + isonum_723 (h_pri->logical_block_size); + sb.s_max_size = isonum_733(h_pri->volume_space_size); + } else { + rootp = (struct iso_directory_record *) + pri->root_directory_record; +#if 0 +//See http://www.y-adagio.com/public/standards/iso_cdromr/sect_1.htm +//Section 4.16 and 4.17 for explanation why this check is invalid + if (isonum_723 (pri->volume_set_size) != 1) { + printf("Multi-volume disks not (yet) supported.\n"); + return -1; + } +#endif + sb.s_nzones = isonum_733 (pri->volume_space_size); + sb.s_log_zone_size = isonum_723 (pri->logical_block_size); + sb.s_max_size = isonum_733(pri->volume_space_size); + } + + sb.s_ninodes = 0; /* No way to figure this out easily */ + + /* RDE: convert log zone size to bit shift */ + + switch (sb.s_log_zone_size) { + case 512: sb.s_log_zone_size = 9; break; + case 1024: sb.s_log_zone_size = 10; break; + case 2048: sb.s_log_zone_size = 11; break; + + default: + printf("Bad logical zone size %ld\n", sb.s_log_zone_size); + return -1; + } + + /* RDE: data zone now byte offset! */ + + sb.s_firstdatazone = (isonum_733( rootp->extent) + << sb.s_log_zone_size); + /* + * 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). + */ + if (first_time) { + first_time = 0; + printf("iso: Max size:%ld Log zone size:%ld\n", + sb.s_max_size, 1UL << sb.s_log_zone_size); + printf("iso: First datazone:%ld Root inode number %d\n", + sb.s_firstdatazone >> sb.s_log_zone_size, + isonum_733 (rootp->extent) << sb.s_log_zone_size); + if (high_sierra) + printf("iso: Disc in High Sierra format.\n"); + } + + /* set up enough so that it can read an inode */ + + sb.s_mapping = 'n'; + sb.s_rock = (rock == 'y' ? 1 : 0); + sb.s_conversion = 'b'; + sb.s_cruft = 'n'; + sb.s_unhide = 'n'; + /* + * 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. + */ + sb.s_mode = S_IRUGO & 0777; + + /* return successfully */ + root_inode = isonum_733 (rootp->extent) << sb.s_log_zone_size; + /* HK: isonum_733 returns an "int" but root_inode is a long ? */ + return 0; +} + + +int +iso_bread (int fd, long blkno, long nblks, char * buffer) +{ + struct iso_inode *inode; + + /* find the inode for this file */ + inode = &inode_table[fd].inode; + return iso_breadi(inode, blkno, nblks, buffer); +} + + +int +iso_open (const char *filename) +{ + struct iso_inode *inode, *oldinode; + struct iso_inode *root; + + /* get the root directory */ + root = iso_iget(root_inode); +/* HK: iso_iget expects an "int" but root_inode is "long" ?? */ + if (!root) { + printf("iso9660: get root inode failed\n"); + return -1; + } + + /* lookup the file */ + inode = iso_lookup(root, filename); + +#ifdef DEBUG_ISO + if (inode && S_ISLNK(((struct inode_table_entry *)inode)->mode)) { + printf("%s is a link (len %u)\n",filename, + ((struct inode_table_entry *)inode)->size); + } else { + printf("%s is not a link\n",filename); + } +#endif + + while ((inode) && (S_ISLNK(((struct inode_table_entry *)inode)->mode))) { + oldinode = inode; + inode = iso_follow_link(oldinode, filename); + iso_iput(oldinode); + } + if (inode == NULL) + return -1; + else { + struct inode_table_entry * itp = + (struct inode_table_entry *) inode; + return (itp - inode_table); + } +} + + +void +iso_close (int fd) +{ + iso_iput(&inode_table[fd].inode); +} + + +long +iso_map (int fd, long block) +{ + return iso_bmap(&inode_table[fd].inode, block) * sb.s_blocksize; +} + +#include <linux/stat.h> +int +iso_fstat (int fd, struct stat * buf) +{ + struct inode_table_entry * ip = inode_table + fd; + + if (fd >= MAX_OPEN_FILES) + return -1; + + memset(buf, 0, sizeof(struct stat)); + /* fill in relevant fields */ + buf->st_ino = ip->inumber; + buf->st_mode = ip->mode; + buf->st_nlink = ip->nlink; + buf->st_size = ip->size; + return 0; +} + +/* + * NOTE: mixing calls to this and calls to any other function that reads from + * the filesystem will clobber the buffers and cause much wailing and gnashing + * of teeth. + * + * Sorry this function is so ugly. It was written as a way for me to + * learn how the ISO filesystem stuff works. + * + * Will Woods, 2/2001 + * + * Uses data_block + */ +char *iso_readdir_i(int fd, int rewind) { + struct inode_table_entry *itp = &(inode_table[fd]); + struct iso_directory_record *dirent = 0; + unsigned int fraglen = 0, block, dirent_len, name_len = 0, oldoffset; + static unsigned int blockoffset = 0, diroffset = 0; + + if (!S_ISDIR(itp->mode)) { + printf("Not a directory\n"); + return NULL; + } + + /* Initial read to this directory, get the first block */ + if (rewind) { + blockoffset = diroffset = 0; + block = iso_bmap(&itp->inode,0); +#ifdef DEBUG_ISO + printf("fd #%d, inode %d, first_extent %d, block %u\n", + fd,itp->inumber,itp->inode.i_first_extent,block); +#endif + if (!block) return NULL; + + if (iso_dev_read(data_block, block * sb.s_blocksize, sb.s_blocksize) + != sb.s_blocksize) return NULL; + } + + /* keep doing this until we get a filename or we fail */ + while (!name_len) { + /* set up our dirent pointer into the block of data we've read */ + dirent = (struct iso_directory_record *) (data_block + blockoffset); + dirent_len = isonum_711(dirent->length); +#ifdef DEBUG_ISO + printf("diroffset=%u, blockoffset=%u, length=%u\n", + diroffset,blockoffset,dirent_len); +#endif + + /* End of directory listing or end of sector */ + if (dirent_len == 0) { + /* round diroffset up to the nearest blocksize */ + diroffset = ((diroffset & ~(ISOFS_BLOCK_SIZE - 1)) + + ISOFS_BLOCK_SIZE); +#ifdef DEBUG_ISO + printf("dirent_len == 0. diroffset=%u, itp->size=%u. ", + diroffset,itp->size); +#endif + if (diroffset >= itp->size) { +#ifdef DEBUG_ISO + printf("End of directory.\n"); +#endif + return NULL; + } else { +#ifdef DEBUG_ISO + printf("End of sector. Need next block.\n"); +#endif + /* Get the next block. */ + block = iso_bmap(&itp->inode, diroffset>>sb.s_blocksize_bits); + if (!block) return NULL; + if (iso_dev_read(data_block, block * sb.s_blocksize, sb.s_blocksize) + != sb.s_blocksize) return NULL; + + /* set the offsets and the pointers properly */ + blockoffset = 0; + dirent = (struct iso_directory_record *) data_block; + dirent_len = isonum_711(dirent->length); +#ifdef DEBUG_ISO + printf("diroffset=%u, blockoffset=%u, length=%u\n", + diroffset,blockoffset,dirent_len); +#endif + } + } + + /* update the offsets for the next read */ + oldoffset = blockoffset; + blockoffset += dirent_len; + diroffset += dirent_len; + + /* + * directory entry spans two blocks - + * get next block and glue the two halves together + */ + if (blockoffset >= sb.s_blocksize) { + fraglen = sb.s_blocksize - oldoffset; +#ifdef DEBUG_ISO + printf("fragmented block: blockoffset = %u, fraglen = %u\n", + blockoffset, fraglen); +#endif + /* copy the fragment at end of old block to front of new buffer */ + memcpy(big_data_block, data_block + oldoffset, fraglen); + + /* read the next block into the buffer after the old fragment */ + block = iso_bmap(&itp->inode, diroffset >> sb.s_blocksize_bits); + if (!block) return NULL; + if (iso_dev_read(big_data_block + fraglen, block * sb.s_blocksize, sb.s_blocksize) + != sb.s_blocksize) return NULL; +#ifdef DEBUG_ISO + printf("read %u bytes from offset %u\n", + sb.s_blocksize, block * sb.s_blocksize); +#endif + + blockoffset = 0; + dirent = (struct iso_directory_record *) big_data_block; + } + + /* + * Everything's cool, let's get the filename. + * First we need to figure out the length. + */ + name_len = isonum_711(dirent->name_len); +#ifdef DEBUG_ISO + if (name_len==0) printf("dirent->name_len = 0, skipping.\n"); +#endif + + /* skip '.' and '..' */ + if (name_len == 1) { + if (dirent->name[0] == (char)0) name_len = 0; + if (dirent->name[0] == (char)1) name_len = 0; + } + + + if (sb.s_unhide == 'n') { + /* sb.s_high_sierra is the offset for the position of the flags. + this adjusts for differences between iso9660 and high sierra. + + if bit 0 (exists) or bit 2 (associated) are set, we ignore + this record. */ + if (dirent->flags[-sb.s_high_sierra] & 5) name_len = 0; + } + + /* if we have a real filename here.. */ + if (name_len) { + /* should be sufficient, since get_rock_ridge_filename truncates + at 254 characters */ + char rrname[256]; + if ((name_len = get_rock_ridge_filename(dirent, rrname, &itp->inode))) { + rrname[name_len] = '\0'; + /* it's okay if rrname is longer than dirent->name, because + we're just overwriting parts of the now-useless dirent */ + strcpy(dirent->name, rrname); + } else { + int i; + char c; + if (sb.s_mapping == 'n') { /* downcase the name */ + for (i = 0; i < name_len; i++) { + c = dirent->name[i]; + + /* lower case */ + if ((c >= 'A') && (c <= 'Z')) c |= 0x20; + + /* Drop trailing '.;1' */ + if ((c == '.') && (i == name_len-3) && + (dirent->name[i+1] == ';') && + (dirent->name[i+2] == '1')) { + name_len -= 3 ; break; + } + + /* Drop trailing ';1' */ + if ((c == ';') && (i == name_len-2) && + (dirent->name[i+1] == '1')) { + name_len -= 2; break; + } + + /* convert ';' to '.' */ + if (c == ';') + c = '.'; + + dirent->name[i] = c; + } + dirent->name[name_len] = '\0'; + } + } + } + /* now that we're done using it, and it's smaller than a full block, + * copy big_data_block back into data_block */ + if (fraglen) { + int len = sb.s_blocksize - dirent_len; + memcpy(data_block, big_data_block + dirent_len, len); +#ifdef DEBUG_ISO + printf("copied %u bytes of data back to data_block\n", len); +#endif + blockoffset = 0; + fraglen = 0; + } + } + return dirent->name; +} + +/********************************************************************** + * + * Rock Ridge functions and definitions, from the Linux kernel source. + * linux/fs/isofs/rock.c, (c) 1992, 1993 Eric Youngdale. + * + **********************************************************************/ + +#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= sizeof(struct iso_directory_record) + DE->name_len[0]; \ + if(LEN & 1) LEN++; \ + CHR = ((unsigned char *) DE) + LEN; \ + LEN = *((unsigned char *) DE) - LEN;} + +#define MAYBE_CONTINUE(LABEL) \ + {if (buffer) free(buffer); \ + if (cont_extent){ \ + buffer = malloc(cont_size); \ + if (!buffer) goto out; \ + if (iso_dev_read(buffer, cont_extent * ISOFS_BLOCK_SIZE + cont_offset, cont_size) \ + == cont_size) { \ + chr = (unsigned char *) buffer; \ + len = cont_size; \ + cont_extent = cont_size = cont_offset = 0; \ + goto LABEL; \ + }; \ + printf("Unable to read rock-ridge attributes\n"); \ + }} + +int get_rock_ridge_filename(struct iso_directory_record * de, + char * retname, + struct iso_inode * inode) +{ + int len; + unsigned char * chr; + int retnamlen = 0, truncate=0; + int cont_extent = 0, cont_offset = 0, cont_size = 0; + void *buffer = 0; + + /* No rock ridge? well then... */ + if (!sb.s_rock) return 0; + *retname = '\0'; + + len = sizeof(struct iso_directory_record) + isonum_711(de->name_len); + if (len & 1) len++; + chr = ((unsigned char *) de) + len; + len = *((unsigned char *) de) - len; + { + struct rock_ridge * rr; + int sig; + + repeat: + while (len > 1){ /* There may be one byte for padding somewhere */ + rr = (struct rock_ridge *) chr; + if (rr->len == 0) break; /* 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'): + if (rr->u.SP.magic[0] != 0xbe || + rr->u.SP.magic[1] != 0xef) + goto out; + break; + case SIG('C','E'): + cont_extent = isonum_733(rr->u.CE.extent); + cont_offset = isonum_733(rr->u.CE.offset); + cont_size = isonum_733(rr->u.CE.size); + break; + case SIG('N','M'): + if (truncate) break; + /* + * If the flags are 2 or 4, this indicates '.' or '..'. + * We don't want to do anything with this, because it + * screws up the code that calls us. We don't really + * care anyways, since we can just use the non-RR + * name. + */ + if (rr->u.NM.flags & 6) { + break; + } + + if (rr->u.NM.flags & ~1) { + printf("Unsupported NM flag settings (%d)\n",rr->u.NM.flags); + break; + }; + if((strlen(retname) + rr->len - 5) >= 254) { + int i = 254-strlen(retname); + strncat(retname, rr->u.NM.name, i); + retnamlen += i; + truncate = 1; + break; + }; + strncat(retname, rr->u.NM.name, rr->len - 5); + retnamlen += rr->len - 5; + break; + case SIG('R','E'): + goto out; + default: + break; + } + }; + } + if (buffer) free(buffer); + if (cont_extent) { /* we had a continued record */ + buffer = malloc(cont_size); + if (!buffer) goto out; + if (iso_dev_read(buffer, cont_extent * ISOFS_BLOCK_SIZE + cont_offset, cont_size) + != cont_size) goto out; + chr = buffer + cont_offset; + len = cont_size; + cont_extent = cont_size = cont_offset = 0; + goto repeat; + } + return retnamlen; /* If 0, this file did not have a NM field */ + out: + if (buffer) free(buffer); + return 0; +} + +static int parse_rock_ridge_inode(struct iso_directory_record * de, + struct iso_inode * inode){ + int len; + unsigned char *chr; + int symlink_len = 0; + struct inode_table_entry *itp = (struct inode_table_entry *) inode; + CONTINUE_DECLS; + +#ifdef DEBUG_ROCK + printf("parse_rock_ridge_inode(%u)\n",itp->inumber); +#endif + + if (!sb.s_rock) return 0; + + SETUP_ROCK_RIDGE(de, chr, len); + repeat: + { + int sig; + /* struct iso_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'): +#ifdef DEBUG_ROCK + printf("RR "); +#endif + if((rr->u.RR.flags[0] & + (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) goto out; + break; + case SIG('S','P'): +#ifdef DEBUG_ROCK + printf("SP "); +#endif + CHECK_SP(goto out); + break; + case SIG('C','E'): +#ifdef DEBUG_ROCK + printf("CE "); +#endif + CHECK_CE; + break; + case SIG('E','R'): +#ifdef DEBUG_ROCK + printf("ISO 9660 Extensions: "); + { int p; + for(p=0;p<rr->u.ER.len_id;p++) printf("%c",rr->u.ER.data[p]); + }; + printf("\n"); +#endif + break; + case SIG('P','X'): +#ifdef DEBUG_ROCK + printf("PX "); +#endif + itp->mode = isonum_733(rr->u.PX.mode); + itp->nlink = isonum_733(rr->u.PX.n_links); + /* Ignore uid and gid. We're only a simple bootloader, after all. */ + break; + case SIG('P','N'): + /* Ignore device files. */ + break; + case SIG('T','F'): + /* create/modify/access times are uninteresting to us. */ + break; + case SIG('S','L'): +#ifdef DEBUG_ROCK + printf("SL "); +#endif + {int slen; + struct SL_component * slp; + struct SL_component * oldslp; + slen = rr->len - 5; + slp = &rr->u.SL.link; + itp->size = symlink_len; + while (slen > 1){ + rootflag = 0; + switch(slp->flags &~1){ + case 0: + itp->size += slp->len; + break; + case 2: + itp->size += 1; + break; + case 4: + itp->size += 2; + break; + case 8: + rootflag = 1; + itp->size += 1; + break; + default: + printf("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) ) itp->size += 1; + break; + } + + /* + * If this component record isn't continued, then append a '/'. + */ + if( (!rootflag) + && ((oldslp->flags & 1) == 0) ) itp->size += 1; + } + } + symlink_len = itp->size; + break; + case SIG('R','E'): + printf("Attempt to read inode for relocated directory\n"); + goto out; + case SIG('C','L'): +#ifdef DEBUG_ROCK + printf("CL(!) "); +#endif + /* I'm unsure as to the function of this signature. + We'll ignore it and hope that everything will be OK. + */ +#if 0 +#ifdef DEBUG + printf("RR CL (%x)\n",inode->i_ino); +#endif + inode->inode.first_extent = isonum_733(rr->u.CL.location); + reloc = iso_iget(inode->i_sb, + (inode->u.isofs_i.i_first_extent << + inode -> i_sb -> u.isofs_sb.s_log_zone_size)); + if (!reloc) + goto out; + inode->mode = reloc->mode; + inode->nlink = reloc->nlink; + inode->size = reloc->size; + iso_iput(reloc); +#endif /* 0 */ + break; + default: + break; + } + }; + } + MAYBE_CONTINUE(repeat); +#ifdef DEBUG_ROCK + printf("\nparse_rock_ridge_inode(): ok\n"); +#endif + return 1; + out: + if(buffer) free(buffer); +#ifdef DEBUG_ROCK + printf("\nparse_rock_ridge_inode(): failed\n"); +#endif + return 0; +} + +/* Returns the name of the file that this inode is symlinked to. This is + in malloc memory, so we have to free it when we're done */ + +static char * get_rock_ridge_symlink(struct iso_inode *inode) +{ + int blocksize = ISOFS_BLOCK_SIZE; + int blockbits = ISOFS_BLOCK_BITS; + char * rpnt = NULL; + unsigned char * pnt; + struct iso_directory_record * raw_inode; + struct inode_table_entry *itp = (struct inode_table_entry *)inode; + CONTINUE_DECLS; + int block, blockoffset; + int sig; + int rootflag; + int len; + unsigned char * chr, * buf = NULL; + struct rock_ridge * rr; + +#ifdef DEBUG_ROCK + printf("get_rock_ridge_symlink(%u): link is %u bytes long\n",itp->inumber, itp->size); +#endif + + if (!sb.s_rock) goto out; + + block = itp->inumber >> blockbits; + blockoffset = itp->inumber & (blocksize - 1); + + buf=malloc(blocksize); + + if (iso_dev_read(buf, block << blockbits, blocksize) != blocksize) + goto out_noread; + + pnt = ((unsigned char *) buf) + blockoffset; + + raw_inode = ((struct iso_directory_record *) pnt); + + /* + * If we go past the end of the buffer, there is some sort of error. + */ + if (blockoffset + *pnt > blocksize) + goto out_bad_span; + + /* 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; + +#ifdef DEBUG_ROCK + printf("%c%c ",chr[0],chr[1]); +#endif + 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 = &rr->u.SL.link; + while (slen > 1){ + if (!rpnt){ + rpnt = (char *) malloc (itp->size +1); + 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: +#ifdef DEBUG_ROCK + printf("Symlink component flag not implemented (%d)\n",slen); +#endif + break; + }; + 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); + + out_freebh: +#ifdef DEBUG_ROCK + printf("\nget_rock_ridge_symlink() exiting\n"); +#endif + if (buf) + free(buf); + return rpnt; + + /* error exit from macro */ +out: +#ifdef DEBUG_ROCK + printf("abort"); +#endif + if(buffer) + free(buffer); + if(rpnt) + free(rpnt); + rpnt = NULL; + goto out_freebh; +out_noread: + printf("unable to read block"); + goto out_freebh; +out_bad_span: + printf("symlink spans iso9660 blocks\n"); + goto out_freebh; +} + + + diff --git a/package/aboot/src/lib/memcpy.c b/package/aboot/src/lib/memcpy.c new file mode 100644 index 000000000..38fd642ab --- /dev/null +++ b/package/aboot/src/lib/memcpy.c @@ -0,0 +1,23 @@ +/* + * aboot/lib/memcpy.c + * + * Copyright (c) 1995 David Mosberger (davidm@cs.arizona.edu) + */ +#include <linux/types.h> +#include <stddef.h> + +/* + * Booting is I/O bound so rather than a time-optimized, we want + * a space-optimized memcpy. Not that the rest of the loader + * were particularly small, though... + */ +void *__memcpy(void *dest, const void *source, size_t n) +{ + char *dst = dest; + const char *src = source; + + while (n--) { + *dst++ = *src++; + } + return dest; +} diff --git a/package/aboot/src/lib/memset.c b/package/aboot/src/lib/memset.c new file mode 100644 index 000000000..01ebe6758 --- /dev/null +++ b/package/aboot/src/lib/memset.c @@ -0,0 +1,28 @@ +/* + * aboot/lib/memset.c + * + * Copyright (c) 1995 David Mosberger (davidm@cs.arizona.edu) + */ +#include <linux/types.h> +#include <stddef.h> + +/* + * Booting is I/O bound so rather than a time-optimized, we want + * a space-optimized memcpy. Not that the rest of the loader + * were particularly small, though... + */ +void *__memset(void *s, char c, size_t n) +{ + char *dst = s; + + while (n--) { + *dst++ = c; + } + return s; +} + + +void *__constant_c_memset(void *dest, char c, size_t n) +{ + return __memset(dest, c, n); +} diff --git a/package/aboot/src/lib/string.c b/package/aboot/src/lib/string.c new file mode 100644 index 000000000..7b6130b11 --- /dev/null +++ b/package/aboot/src/lib/string.c @@ -0,0 +1,252 @@ +/* + * aboot/lib/string.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * stupid library routines.. The optimized versions should generally be found + * as inline code in <asm-xx/string.h> + * + * These are buggy as well.. + */ + +#include <stddef.h> +#include <linux/types.h> + +char * ___strtok = NULL; + +char * strcpy(char * dest,const char *src) +{ + char *tmp = dest; + + while ((*dest++ = *src++) != '\0') + /* nothing */; + return tmp; +} + +char * strncpy(char * dest,const char *src,size_t count) +{ + char *tmp = dest; + + while (count-- && (*dest++ = *src++) != '\0') + /* nothing */; + + return tmp; +} + +char * strcat(char * dest, const char * src) +{ + char *tmp = dest; + + while (*dest) + dest++; + while ((*dest++ = *src++) != '\0') + ; + + return tmp; +} + +char * strncat(char *dest, const char *src, size_t count) +{ + char *tmp = dest; + + if (count) { + while (*dest) + dest++; + while ((*dest++ = *src++)) { + if (--count == 0) + break; + } + } + + return tmp; +} + +int strcmp(const char * cs,const char * ct) +{ + register signed char __res; + + while (1) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + } + + return __res; +} + +int strncmp(const char * cs,const char * ct,size_t count) +{ + register signed char __res = 0; + + while (count) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + count--; + } + + return __res; +} + +char * strchr(const char * s,char c) +{ + for(; *s != c; ++s) + if (*s == '\0') + return NULL; + return (char *) s; +} + +char * strrchr(const char * s,char c) +{ + const char * r = NULL; + while (*s++) + if (*s == c) r = s; + return (char *) r; +} + +size_t strlen(const char * s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +size_t strnlen(const char * s, size_t count) +{ + const char *sc; + + for (sc = s; *sc != '\0' && count--; ++sc) + /* nothing */; + return sc - s; +} + +size_t strspn(const char *s, const char *accept) +{ + const char *p; + const char *a; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) { + for (a = accept; *a != '\0'; ++a) { + if (*p == *a) + break; + } + if (*a == '\0') + return count; + ++count; + } + + return count; +} + +char * strpbrk(const char * cs,const char * ct) +{ + const char *sc1,*sc2; + + for( sc1 = cs; *sc1 != '\0'; ++sc1) { + for( sc2 = ct; *sc2 != '\0'; ++sc2) { + if (*sc1 == *sc2) + return (char *) sc1; + } + } + return NULL; +} + +char * strtok(char * s,const char * ct) +{ + char *sbegin, *send; + + sbegin = s ? s : ___strtok; + if (!sbegin) { + return NULL; + } + sbegin += strspn(sbegin,ct); + if (*sbegin == '\0') { + ___strtok = NULL; + return( NULL ); + } + send = strpbrk( sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ___strtok = send; + return (sbegin); +} + +void * memset(void * s, int c, size_t count) +{ + char *xs = (char *) s; + + while (count--) + *xs++ = c; + + return s; +} + +char * bcopy(const char * src, char * dest, int count) +{ + char *tmp = dest; + + while (count--) + *tmp++ = *src++; + + return dest; +} + +void * memcpy(void * dest,const void *src,size_t count) +{ + char *tmp = (char *) dest, *s = (char *) src; + + while (count--) + *tmp++ = *s++; + + return dest; +} + +void * memmove(void * dest,const void *src,size_t count) +{ + char *tmp, *s; + + if (dest <= src) { + tmp = (char *) dest; + s = (char *) src; + while (count--) + *tmp++ = *s++; + } + else { + tmp = (char *) dest + count; + s = (char *) src + count; + while (count--) + *--tmp = *--s; + } + + return dest; +} + +int memcmp(const void * cs,const void * ct,size_t count) +{ + const unsigned char *su1, *su2; + signed char res = 0; + + for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) + if ((res = *su1 - *su2) != 0) + break; + return res; +} + +/* + * find the first occurrence of byte 'c', or 1 past the area if none + */ +void * memscan(void * addr, unsigned char c, size_t size) +{ + unsigned char * p = (unsigned char *) addr; + + while (size) { + if (*p == c) + return (void *) p; + p++; + size--; + } + return (void *) p; +} diff --git a/package/aboot/src/lib/vsprintf.c b/package/aboot/src/lib/vsprintf.c new file mode 100644 index 000000000..d6d256c73 --- /dev/null +++ b/package/aboot/src/lib/vsprintf.c @@ -0,0 +1,317 @@ +/* + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include <stdarg.h> +#include <linux/types.h> +#include "string.h" + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') +#define is_xdigit(c) \ + (is_digit(c) || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f')) +#define is_lower(c) (((c) >= 'a') && ((c) <= 'z')) +#define to_upper(c) ((c) + 'a' - 'A') + +unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) +{ + unsigned long result = 0, value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((*cp == 'x') && is_xdigit(cp[1])) { + cp++; + base = 16; + } + } + } + while (is_xdigit(*cp) + && (value = + (is_digit(*cp) + ? *cp - '0' : ((is_lower(*cp) + ? to_upper(*cp) : *cp) - 'A' + 10))) + < base) + { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static char * number(char * str, long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int base = 10; + int i; + char * str; + char *s; + + int flags; /* flags to number() */ + + int field_width = -1; /* width of output field */ + int precision = -1; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier = -1; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = "<NULL>"; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') + if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} + +int sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} + |