diff options
author | Liu Aleaxander <Aleaxander@gmail.com> | 2009-05-24 07:11:22 +0800 |
---|---|---|
committer | Liu Aleaxander <Aleaxander@gmail.com> | 2009-05-24 07:11:22 +0800 |
commit | 03fa5dd9baef4e78c011092ffae1b321c9a3e77e (patch) | |
tree | 110b45a1f19b566a397ef0b991011aa610051e82 /isolinux.c | |
parent | 7eb2956a115575912207c6c667e9e8af14ea949a (diff) | |
download | devel-03fa5dd9baef4e78c011092ffae1b321c9a3e77e.tar.gz devel-03fa5dd9baef4e78c011092ffae1b321c9a3e77e.tar.xz devel-03fa5dd9baef4e78c011092ffae1b321c9a3e77e.zip |
Add init. isolinux code file
Diffstat (limited to 'isolinux.c')
-rw-r--r-- | isolinux.c | 542 |
1 files changed, 542 insertions, 0 deletions
diff --git a/isolinux.c b/isolinux.c new file mode 100644 index 0000000..9eb7332 --- /dev/null +++ b/isolinux.c @@ -0,0 +1,542 @@ +#include "iso_fs.h" +#include "cache.h" + +/* + * well, we defined the getlinsec() function here + * Since the sector size of iso is different from + * the disk + */ +//#include "disklab.h" + +#include <stdio.h> +#include <string.h> +#include <malloc.h> + +#define DEBUG 1 + + +/* some generic defines */ +#define FILENAME_MAX_LG2 8 +#define FILENAME_MAX_ ( 1 << FILENAME_MAX_LG2 ) +#define NULLFILE 0 +#define NULLOFFSET 0 +#define retry_count 6 + +#define MAX_OPEN_LG2 6 +#define MAX_OPEN ( 1 << MAX_OPEN_LG2 ) + +#define SECTOR_SHIFT 11 +#define SECTOR_SIZE ( 1 << SECTOR_SHIFT ) + +#define ROOT_DIR_WORD 0x002f + + + + +struct open_file_t { + __u32 file_sector; + __u32 file_bytesleft; + __u32 file_left; + __u32 pad; +}; + + +struct dir_t { + __u32 dir_lba; /* Directory start (LBA) */ + __u32 dir_len; /* Length in bytes */ + __u32 dir_clust; /* Length in clusters */ +}; + + + + + +#define trackbufsize 8192 +char trackbuf[trackbufsize] = {0,}; + +char ISOFileName[64]; /* ISO filename canonicalizatin buffer */ +char *ISOFileNameEnd = &ISOFileName[64]; + +struct dir_t RootDir; +struct dir_t CurrentDir; + +__u32 FirstSecSum; /* checksum of bytes 64-2048 */ +__u32 ImageDwords; /* isolinux.bin size, dwords */ +__u32 InitStack; /* Initial stack pointer (SS:SP) */ +__u16 DiskSys; /* Last INT 13h call */ +__u16 ImageSectors; /* isolinux.bin size, sectors */ + +/* These following two are accessed as a single dword ... */ +__u16 GetlinsecPtr; /* the sector-read pointer */ +__u16 BIOSType; +__u8 DiskError; /* Error code for disk I/O */ +__u8 DriveNumber; /* CD-ROM BIOS drive number */ +__u8 ISOFlags; /* Flags for ISO directory search */ +__u8 RetryCount; /* Used for ISO directory search */ +__u16 bsSecPerTrack; /* Used in hybrid mode */ +__u16 bsHeads; /* Used in hybrid mode */ + + +/* El Torito spec packet */ +__u8 spec_packet; /* Size of packet */ +__u8 sp_media; /* Media type */ +__u8 sp_drive; /* Drive number */ +__u8 sp_controller; /* Controller index */ +__u32 sp_lba; /* LBA for emulated disk image */ +__u32 sp_devspec; /* IDE/SCSI information */ +__u16 sp_buffer; /* User-provided buffer */ +__u16 sp_loadseg; /* Load segment */ +__u16 sp_sectors; /* Sector count */ +__u8 sp_chs; /* Simulated CHS geometry */ +__u8 sp_dummy; /* Scratch, safe to overwrite */ + + + + + +/** + * allocate_file: + * + * allocate a file structure + * + */ +struct open_file_t *allocate_file() +{ + struct open_file_t *file; + int i = 0; + + file = Files; + + for (; i < MAX_OPEN; i ++ ) { + if ( file->file_sector == 0 ) /* found it */ + return file; + file ++; + } + + return NULL; /* not found */ +} + + + + +/** + * close_file: + * + * Deallocates a file structure + * + */ +void close_file(struct open_file_t *file) +{ + if ( file ) + file->file_sector = 0; +} + + +void getlinsec(char *buf, int sector, int sector_cnt) +{ + int bytes_read; + + if ( lseek(fd, sector*SECTOR_SIZE, SEEK_SET) < 0 ) { + printf("seek file ext2.img error ....\n"); + return; + } + + if ( (bytes_read = read(fd, buf, SECTOR_SIZE*sector_cnt)) < SECTOR_SIZE*sector_cnt) + printf("%s:%s: read %d bytes less than %d bytes..\n", + __FILE__, __FUNCTION__, bytes_read, SECTOR_SIZE * sector_cnt); + +} + + + + +/** + * mangle_name: + * + * Mangle a filename pointed to by src into a buffer pointed + * to by dst; ends on encountering any whitespace. + * dst is preserved. + * + * This verifies that a filename is < FilENAME_MAX characters, + * doesn't contain whitespace, zero-pads the output buffer, + * and removes trailing dots and redumndant slashes, so "repe + * cmpsb" can do a compare, and the path-searching routine gets + * a bit of an easier job. + * + */ +void mangle_name(char *dst, char *src) +{ + + char slash_before; + char *p = dst; + + int i = FILENAME_MAX - 1; + + while ( *src > ' ' ) { + if ( *src == '/' ) { + while ( *src == '/' ) { + cx --; + src ++; + } + *dst++ = '/'; + continue; + } + + *dst++ = *src ++; + cx --; + } + + + while ( 1 ) { + if ( dst >= p ) + break; + + if ( (*(dst-1) != '.') && (*(dst-1) != '/') ) + break; + + dst --; + cx ++; + } + + cx ++; + for (; cx > 0; cx -- ) + *dst++ = '\0'; + +} + + + +/** + * compare the names si and di and report if they are + * equal from an ISO 9600 perspective. + * + * @param: si, the name from the file system. + * @param: cx, the length of si + * @param: di, is expected to end with a null + * + * @return: 1 on match, or 0. + * + */ +int iso_compare_names(char *de_name, __u32 len, char *file_name) +{ + + + char *p = ISOFileName; + char c1, c2; + + while ( len && *de_name && (*de_name != ';') && (p < ISOFileNameEnd - 1) ) { + *p++ = *de_name++; + len --; + } + + + while ( 1 ) { + if ( p <= ISOFileName ) + break; + + if ( *(p-1) == '.' ) /* Remove terminal dots */ + p --; + } + + *p = '\0'; + + + p = ISOFileName; + + do { + c1 = *p++; + c2 = *file_name++; + + if ( (c1 == 0) && (c2 == 0) ) + return 1; /* success */ + + else if ( (c1 == 0) || ( c2 == 0 ) ) + return 0; + + c1 |= 0x20; + c2 |= 0x20; /* convert to lower case */ + }while ( c1 == c2 ); + + return 0; +} + + +/** + * getfssec: + * + * Get multiple clusters from a file, given the file pointer. + * + * @param: buf + * @param: file, the address of the open file structure + * @param: sectors, how many we want to read at once + * @param: have_more, to indicate if we have reach the end of the file + * + */ +__u32 getfssec(char *buf, struct open_file_t *file, __u32 sectors, int *have_more) +{ + __u32 bytes_read = sectors << SECTOR_SHIFT; + + if ( sectros > file->file_left ) + sectors = file->file_left; + + getlinsec(buf, file->file_sector, sectors); + + file->file_sector += sectors; + file->file_left -= sectors; + + if ( bytes_read >= file->file_bytesleft ) { + bytes_read = file->file_bytesleft; + file->file_bytesleft = 0; + *have_more = 0; + close_file(file); + } else { + file->file_bytesleft -= bytes_read; + *have_more = 1; + } + + return bytes_read; +} + + + + + +/** + * do_search_dir: + * + * find a file or directory with name within the _dir_ directory. + * + * the return value will tell us what we find, it's a file or dir? + * on 1 be dir, 2 be file, 0 be error. + * + * res will return the result. + * + */ +int do_search_dir(struct dir_t *dir, char *name, void **res) +{ + struct open_file_t *file; + struct iso_dir_entry *de; + + __u32 offset = 0; /* let's start it with the start */ + __u32 file_pos = 0; + + file = allocate_file(); + if ( !file ) + return 0; + + file->file_left = dir->dir_clust; + file->file_sector = dir->dir_lba; + + getfssec(trackbuf, file, BufSafe, &have_more); + de = (struct iso_dir_entry *)trackbuf; + + while ( file_pos < dir->dir_len ) { + if ( (char *)de >= (char *)(trackbuf + trackbufsize) ) { + if ( !have_more ) + return 0; + + getfssec(trackbuf, file, BufSafe, &have_more); + offset = 0; + } + + de = (struct iso_dir_entry *) (trackbuf + offset); + + de_len = iso_dir->length; + + if ( de_len == 0) { + file_pos = (file_pos+SECTOR_SIZE) & ~(SECTOR_SIZE-1); + file->file_sector ++; + if ( !have_more ) + return 0; + getfssec(trackbuf, file, BufSafe, &have_more); + offset = 0; + + continue; + } + + + offset += de_len; + + /* Make sure we have a full directory entry */ + if ( offset >= trackbufsize ) { + int slop = trackbufsize - offset + de_len; + memcpy(tmpde, de, slop); + offset &= trackbufsize - 1; + file->sector ++; + if ( offset ) { + if ( !have_more ) + return 0; + getfssec(trackbuf, file, BufSafe, &have_more); + memcpy((void*) tmp + slop, trackbuf, offset); + } + de = tmpde; + } + + if ( de_len < 33 ) { + printf("Corrutped directory entry in sector %d\n", file->file_sector); + return 0; + } + + de_name_len = de->name_len; + if ( iso_compare_names(de->name, name, de_name_len) ) + break; /* we found it */ + + file_pos += de_len; + } + + + if ( *(filename+de_name) && (*(name+de_name) != '/' ) ) { + *res = NULL; + return 0; + } + + if ( de->flags & 0x02 ) { + /* it's a directory */ + + dir = CurrentDir; + + dir->dir_lba = *(__u32 *)de->extent; + dir->dir_len = *(__u32 *)de->size; + dir->dir_clust = (dir->dir_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT; + + *res = dir; + + /* we can close it now */ + close_file(file); + + /* Mark we got a directory */ + return 1; + + } else { + /* it's a file */ + file->file_sector = *(__u32 *)de->extent; + file->file_bytesleft = *(__u32 *)de->size; + file->file_left = (file->file_bytesleft + SECTOR_SIZE - 1) >> SECTOR_SHIFT; + + *res = file; + + /* Mark we got a file */ + return 2; + } + +} + + + + +/** + * searchdir: + * + * open a file + * + * searchdir_iso is a special entry point for ISOLINUX only. In addition + * to the above, searchdir_iso passes a file flag mask in AL. This is + * useful for searching for directories. + * + * well, it's not like the searchidr function in EXT fs or FAT fs; it also + * can read a diretory.(Just thought of mine, liu) + * + */ +struct open_file_t *searchdir(char *filename) +{ + struct open_file_t *file; + struct dir_t *dir; + struct iso_dir_entry *de; + + void *res; + + int flag = 0; + + dir = CurrentDir; + if ( *filename == '/' ) { + dir = RootDir; + filename ++; + } + + while ( *filename ) { + + ret = do_search_dir(dir, filename, &res); + if ( ret == 1 ) + dir = (struct dir_t *) res; + else if ( ret == 2 ) + break; + else + return NULL; + + /* find the end */ + while ( *filename && (*filename != '/') ) + filename ++; + + /* skip the slash */ + while ( *filename && (*filename == '/') ) + filename++; + } + + /* well , we need recheck it , becuase it can be a directory */ + if ( ret == 2 ) + return (struct open_file_t *)res; + else { + file = allocate_file(); + if ( !file ) + return NULL; + + file->file_sector = dir->dir_lba; + file->file_bytesleft = dir->dir_len; + file->file_left = (dir->dir_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT; + return file; + } +} + + + +void init_fs() +{ + + + getlinsec(trackbuf, bi_pvd, 1); + + CurrentDir->dir_lba = RootDir->dir_lba = *(__u32 *)(trackbuf + 156 + 2); + +#ifdef DEBUG + printf("Root directory at LBA = 0x%x\n", RootDir->dir_lba); +#endif + + CurrentDir->dir_len = RootDir->dir_len = *(__u32*)(trackbuf + 156 + 10); + CurrentDir->dir_clust = RootDir->dir_clust = (RootDir->dir_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT; + + + /* + * Look for an isolinux directory, and if found, + * make it the current directory instead of the + * root directory. + * + * Also copy the name of the directory to CurrrentDirName + */ + *(__u16*)CurrentDirName = ROOT_DIR_WORD; + + iso_dir = boot_dir; + file = searchdir(boot_dir); /* search for /boot/isolinux */ + if ( !file ) { + iso_dir = isolinux_dir; + file = searchdir(isolinux_dir); /* search for /isolinux */ + if ( !file ) + goto no_isolinux_dir; + } + + strcpy(CurrentDirName, iso_dir); + len = strlen(CurrentDirName); + CurrentDirName[len] = '/'; + CurrentDirName[len+1] = '\0'; + + CurrentDir->dir_len = file->file_bytesleft; + CurrentDir->dir_clust = file->file_left; + CurrentDir->dir_lba = file->file_sector; + close_file(file); + +#ifdef DEBUG + printf("isolinux directory at LBA = %0x%x\n", CurrentDirName->dir_lba); +#endif + + no_isolinux_dir: + ; +} |