aboutsummaryrefslogtreecommitdiffstats
path: root/isolinux.c
diff options
context:
space:
mode:
authorLiu Aleaxander <Aleaxander@gmail.com>2009-05-24 07:11:22 +0800
committerLiu Aleaxander <Aleaxander@gmail.com>2009-05-24 07:11:22 +0800
commit03fa5dd9baef4e78c011092ffae1b321c9a3e77e (patch)
tree110b45a1f19b566a397ef0b991011aa610051e82 /isolinux.c
parent7eb2956a115575912207c6c667e9e8af14ea949a (diff)
downloaddevel-03fa5dd9baef4e78c011092ffae1b321c9a3e77e.tar.gz
devel-03fa5dd9baef4e78c011092ffae1b321c9a3e77e.tar.xz
devel-03fa5dd9baef4e78c011092ffae1b321c9a3e77e.zip
Add init. isolinux code file
Diffstat (limited to 'isolinux.c')
-rw-r--r--isolinux.c542
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:
+ ;
+}