--- /dev/null
+#include <stdio.h>
+#include <string.h>
+//#include "cache.h"
+#include "core.h"
+#include "disk.h"
+#include "iso9660_fs.h"
+#include "fs.h"
+
+#define DEBUG 1
+
+#define FILENAME_MAX_LG2 8
+#define FILENAME_MAX (1 << FILENAME_MAX_LG2)
+#define MAX_OPEN_LG2 6
+#define MAX_OPEN (1 << MAX_OPEN_LG2)
+#define ISO_SECTOR_SHIFT 11
+#define ISO_SECTOR_SIZE (1 << ISO_SECTOR_SHIFT)
+#define ROOT_DIR_WORD 0x002f
+#define TRACKBUF_SIZE 8192
+
+
+struct open_file_t {
+ uint32_t file_sector;
+ uint32_t file_bytesleft;
+ uint32_t file_left;
+ uint32_t pad;
+};
+extern char Files[];
+
+struct dir_t {
+ uint32_t dir_lba; /* Directory start (LBA) */
+ uint32_t dir_len; /* Length in bytes */
+ uint32_t dir_clust; /* Length in clusters */
+};
+struct dir_t RootDir;
+struct dir_t CurrentDir;
+
+
+extern char trackbuf[TRACKBUF_SIZE];
+uint16_t BufSafe = TRACKBUF_SIZE >> ISO_SECTOR_SHIFT;
+uint16_t BufSafeBytes = TRACKBUF_SIZE;
+
+char ISOFileName[64]; /* ISO filename canonicalizatin buffer */
+char *ISOFileNameEnd = &ISOFileName[64];
+
+uint32_t FirstSecSum; /* checksum of bytes 64-2048 */
+uint32_t ImageDwords; /* isolinux.bin size, dwords */
+uint32_t InitStack; /* Initial stack pointer (SS:SP) */
+uint16_t DiskSys; /* Last INT 13h call */
+uint16_t ImageSectors; /* isolinux.bin size, sectors */
+
+/* These following two are accessed as a single dword ... */
+uint16_t GetlinsecPtr; /* the sector-read pointer */
+uint16_t BIOSType;
+uint8_t DiskError; /* Error code for disk I/O */
+uint8_t DriveNumber; /* CD-ROM BIOS drive number */
+uint8_t ISOFlags; /* Flags for ISO directory search */
+uint8_t RetryCount; /* Used for ISO directory search */
+uint16_t bsSecPerTrack; /* Used in hybrid mode */
+uint16_t bsHeads; /* Used in hybrid mode */
+
+
+/**
+ * allocate_file:
+ *
+ * allocate a file structure
+ *
+ */
+struct open_file_t *allocate_file()
+{
+ struct open_file_t *file;
+ int i = 0;
+
+ file = (struct open_file_t *)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_cdrom(char *buf, sector_t sector_num, int sectors)
+{
+ com32sys_t regs;
+ //static __lowmem char low_buf[65536];
+ /* for safe, we use buf + (sectors << SECTOR_SHIFT) here */
+ int high_addr = (buf + (sectors << ISO_SECTOR_SHIFT)) > (char *)0x100000;
+
+ memset(®s, 0, sizeof regs);
+ regs.eax.l = sector_num;
+ regs.ebp.l = sectors;
+
+ if (high_addr) {
+ regs.es = SEG(core_xfer_buf);
+ regs.ebx.w[0] = OFFS(core_xfer_buf);
+ } else {
+ regs.es = SEG(buf);
+ regs.ebx.w[0] = OFFS(buf);
+ }
+
+ call16(getlinsec, ®s, NULL);
+
+ if (high_addr)
+ memcpy(buf, core_xfer_buf, sectors << ISO_SECTOR_SHIFT);
+}
+
+
+
+
+/**
+ * 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 iso_mangle_name(char *dst, char *src)
+{
+ char *p = dst;
+ int i = FILENAME_MAX - 1;
+
+ while ( *src > ' ' ) {
+ if ( *src == '/' ) {
+ if ( *(src+1) == '/' ) {
+ i --;
+ src ++;
+ continue;
+ }
+ }
+
+ *dst++ = *src ++;
+ i --;
+ }
+
+ while ( 1 ) {
+ if ( dst == p )
+ break;
+
+ if ( (*(dst-1) != '.') && (*(dst-1) != '/') )
+ break;
+
+ dst --;
+ i ++;
+ }
+
+ i ++;
+ for (; i > 0; i -- )
+ *dst++ = '\0';
+}
+
+
+/**
+ * compare the names si and di and report if they are
+ * equal from an ISO 9600 perspective.
+ *
+ * @param: de_name, the name from the file system.
+ * @param: len, the length of de_name, and will return the real name of the de_name
+ * ';' and other terminates excluded.
+ * @param: file_name, the name we want to check, is expected to end with a null
+ *
+ * @return: 1 on match, or 0.
+ *
+ */
+int iso_compare_names(char *de_name, int *len, char *file_name)
+{
+ char *p = ISOFileName;
+ char c1, c2;
+
+ int i = 0;
+
+ while ( (i < *len) && *de_name && (*de_name != ';') && (p < ISOFileNameEnd - 1) ) {
+ *p++ = *de_name++;
+ i++;
+ }
+
+ /* Remove terminal dots */
+ while ( *(p-1) == '.' ) {
+ if ( *len <= 2 )
+ break;
+
+ if ( p <= ISOFileName )
+ break;
+ p --;
+ i--;
+ }
+
+ if ( i <= 0 )
+ return 0;
+
+ *p = '\0';
+
+ /* return the 'real' length of de_name */
+ *len = i;
+
+ p = ISOFileName;
+
+ /* i is the 'real' name length of file_name */
+ while ( i ) {
+ 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 */
+ if ( c1 != c2 )
+ return 0;
+ i --;
+ }
+
+ return 1;
+}
+
+
+/**
+ * iso_getfssec:
+ *
+ * Get multiple clusters from a file, given the file pointer.
+ *
+ * we don't use the fs struct for now
+ *
+ * @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
+ *
+ */
+uint32_t iso_getfssec(struct fs_info *fs, char *buf,
+ void *open_file, int sectors, int *have_more)
+{
+ uint32_t bytes_read = sectors << ISO_SECTOR_SHIFT;
+ struct open_file_t *file = (struct open_file_t *)open_file;
+
+ if ( sectors > file->file_left )
+ sectors = file->file_left;
+
+ getlinsec_cdrom(buf, file->file_sector, sectors);
+
+ file->file_sector += sectors;
+ file->file_left -= sectors;
+
+ if ( bytes_read >= file->file_bytesleft ) {
+ bytes_read = file->file_bytesleft;
+ *have_more = 0;
+ } else
+ *have_more = 1;
+ file->file_bytesleft -= bytes_read;
+
+ 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, uint32_t *file_len, void **res)
+{
+ struct open_file_t *file;
+ struct iso_dir_entry *de;
+ struct iso_dir_entry tmpde;
+
+ uint32_t offset = 0; /* let's start it with the start */
+ uint32_t file_pos = 0;
+ char *de_name;
+ int de_len;
+ int de_name_len;
+ int have_more;
+
+ file = allocate_file();
+ if ( !file )
+ return 0;
+
+ file->file_left = dir->dir_clust;
+ file->file_sector = dir->dir_lba;
+
+ iso_getfssec(NULL, trackbuf, file, BufSafe, &have_more);
+ de = (struct iso_dir_entry *)trackbuf;
+
+ while ( file_pos < dir->dir_len ) {
+ int found = 0;
+
+ if ( (char *)de >= (char *)(trackbuf + TRACKBUF_SIZE) ) {
+ if ( !have_more )
+ return 0;
+
+ iso_getfssec(NULL, trackbuf, file, BufSafe, &have_more);
+ offset = 0;
+ }
+
+ de = (struct iso_dir_entry *) (trackbuf + offset);
+
+ de_len = de->length;
+
+ if ( de_len == 0) {
+ offset = file_pos = (file_pos+ISO_SECTOR_SIZE) & ~(ISO_SECTOR_SIZE-1);
+ continue;
+ }
+
+
+ offset += de_len;
+
+ /* Make sure we have a full directory entry */
+ if ( offset >= TRACKBUF_SIZE ) {
+ int slop = TRACKBUF_SIZE - offset + de_len;
+ memcpy(&tmpde, de, slop);
+ offset &= TRACKBUF_SIZE - 1;
+ file->file_sector ++;
+ if ( offset ) {
+ if ( !have_more )
+ return 0;
+ iso_getfssec(NULL, trackbuf, file, BufSafe, &have_more);
+ memcpy((void*)&tmpde + 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;
+ de_name = (char *)((void *)de + 0x21);
+
+
+ if ( (de_name_len == 1) && (*de_name == 0) ) {
+ found = iso_compare_names(".", &de_name_len, name);
+
+ } else if ( (de_name_len == 1) && (*de_name == 1) ) {
+ de_name_len = 2;
+ found = iso_compare_names("..", &de_name_len, name);
+
+ } else
+ found = iso_compare_names(de_name, &de_name_len, name);
+
+ if (found)
+ break;
+
+ file_pos += de_len;
+ }
+
+ if ( file_pos >= dir->dir_len )
+ return 0; /* not found */
+
+
+ if ( *(name+de_name_len) && (*(name+de_name_len) != '/' ) ) {
+ printf("Something wrong happened during searching file %s\n", name);
+
+ *res = NULL;
+ return 0;
+ }
+
+ if ( de->flags & 0x02 ) {
+ /* it's a directory */
+ dir = &CurrentDir;
+ dir->dir_lba = *(uint32_t *)de->extent;
+ dir->dir_len = *(uint32_t *)de->size;
+ dir->dir_clust = (dir->dir_len + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT;
+
+ *file_len = dir->dir_len;
+ *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 = *(uint32_t *)de->extent;
+ file->file_bytesleft = *(uint32_t *)de->size;
+ file->file_left = (file->file_bytesleft + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT;
+
+ *file_len = file->file_bytesleft;
+ *res = file;
+
+ /* Mark we got a file */
+ return 2;
+ }
+}
+
+
+/**
+ * iso_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)
+ *
+ */
+void iso_searchdir(char *filename, struct file *file)
+{
+ struct open_file_t *open_file = NULL;
+ struct dir_t *dir;
+ uint32_t file_len;
+ int ret;
+ void *res;
+
+ dir = &CurrentDir;
+ if ( *filename == '/' ) {
+ dir = &RootDir;
+ filename ++;
+ }
+
+ while ( *filename ) {
+
+ ret = do_search_dir(dir, filename, &file_len, &res);
+ if ( ret == 1 )
+ dir = (struct dir_t *)res;
+ else if ( ret == 2 )
+ break;
+ else
+ goto err;
+
+ /* 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 ) {
+ open_file = (struct open_file_t *)res;
+ goto found;
+ } else {
+ open_file = allocate_file();
+ if ( !open_file )
+ goto err;
+
+ open_file->file_sector = dir->dir_lba;
+ open_file->file_bytesleft = dir->dir_len;
+ open_file->file_left = (dir->dir_len + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT;
+ goto found;
+ }
+ err:
+ close_file(open_file);
+ file_len = 0;
+ open_file = NULL;
+
+ found:
+ file->file_len = file_len;
+ file->open_file = (void*)open_file;
+
+#if 0
+ if (open_file) {
+ printf("file bytesleft: %d\n", open_file->file_bytesleft);
+ printf("file sector : %d\n", open_file->file_sector);
+ printf("file in sector: %d\n", open_file->file_in_sec);
+ printf("file offsector: %d\n", open_file->file_in_off);
+ }
+#endif
+}
+
+void iso_load_config(com32sys_t *regs)
+{
+ char *config_name = "isolinux.cfg";
+ com32sys_t out_regs;
+
+ strcpy(ConfigName, config_name);
+
+ regs->edi.w[0] = ConfigName;
+ memset(&out_regs, 0, sizeof out_regs);
+ call16(core_open, regs, &out_regs);
+}
+
+
+int iso_fs_init()
+{
+ char *iso_dir;
+ char *boot_dir = "/boot/isolinux";
+ char *isolinux_dir = "/isolinux";
+
+ struct file file;
+ struct open_file_t *open_file;
+ int len;
+ int bi_pvd = 16;
+
+ getlinsec_cdrom(trackbuf, bi_pvd, 1);
+
+ CurrentDir.dir_lba = RootDir.dir_lba = *(uint32_t *)(trackbuf + 156 + 2);
+
+#ifdef DEBUG
+ printf("Root directory at LBA = 0x%x\n", RootDir.dir_lba);
+#endif
+
+ CurrentDir.dir_len = RootDir.dir_len = *(uint32_t*)(trackbuf + 156 + 10);
+ CurrentDir.dir_clust = RootDir.dir_clust = (RootDir.dir_len + ISO_SECTOR_SIZE - 1) >> ISO_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
+ */
+ *(uint16_t *)CurrentDirName = ROOT_DIR_WORD;
+
+ iso_dir = boot_dir;
+ iso_searchdir(boot_dir, &file); /* search for /boot/isolinux */
+ if ( !file.file_len ) {
+ iso_dir = isolinux_dir;
+ iso_searchdir(isolinux_dir, &file); /* search for /isolinux */
+ if ( !file.file_len )
+ goto no_isolinux_dir;
+ }
+
+ strcpy(CurrentDirName, iso_dir);
+ len = strlen(CurrentDirName);
+ CurrentDirName[len] = '/';
+ CurrentDirName[len+1] = '\0';
+
+ open_file = (struct open_file_t *)file.open_file;
+ CurrentDir.dir_len = open_file->file_bytesleft;
+ CurrentDir.dir_clust = open_file->file_left;
+ CurrentDir.dir_lba = open_file->file_sector;
+ close_file(open_file);
+
+#ifdef DEBUG
+ printf("isolinux directory at LBA = %0x%x\n", CurrentDir.dir_lba);
+#endif
+
+ no_isolinux_dir:
+ printf("No isolinux directory found\n");
+
+ /* we do not use cache for now, so we can just return 0 */
+ return 0;
+}
+
+
+const struct fs_ops iso_fs_ops = {
+ .fs_name = "iso",
+ .fs_init = iso_fs_init,
+ .searchdir = iso_searchdir,
+ .getfssec = iso_getfssec,
+ .mangle_name = iso_mangle_name,
+ .unmangle_name = NULL,
+ .load_config = iso_load_config
+};
; Memory below this point is reserved for the BIOS and the MBR
;
section .earlybss
+ global trackbuf
trackbufsize equ 8192
trackbuf resb trackbufsize ; Track buffer goes here
; ends at 2800h
_spec_len equ _spec_end - _spec_start
section .bss16
+ global Files
alignb open_file_t_size
Files resb MAX_OPEN*open_file_t_size
; ES:BX - Target buffer
; BP - Sector count
;
+ global getlinsec
getlinsec: jmp word [cs:GetlinsecPtr]
%ifndef DEBUG_MESSAGES
; (which will be at 16 only for a single-session disk!); from the PVD
; we should be able to find the rest of what we need to know.
;
-get_fs_structures:
- mov eax,[bi_pvd]
- mov bx,trackbuf
- call getonesec
-
- mov eax,[trackbuf+156+2]
- mov [RootDir+dir_lba],eax
- mov [CurrentDir+dir_lba],eax
-%ifdef DEBUG_MESSAGES
- mov si,dbg_rootdir_msg
- call writemsg
- call writehex8
- call crlf
-%endif
- mov eax,[trackbuf+156+10]
- mov [RootDir+dir_len],eax
- mov [CurrentDir+dir_len],eax
- add eax,SECTOR_SIZE-1
- shr eax,SECTOR_SHIFT
- mov [RootDir+dir_clust],eax
- mov [CurrentDir+dir_clust],eax
-
- ; 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 CurrentDirName
- mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName
- mov di,boot_dir ; Search for /boot/isolinux
- mov al,02h
- push di
- call searchdir_iso
- pop di
- jnz .found_dir
- mov di,isolinux_dir
- mov al,02h ; Search for /isolinux
- push di
- call searchdir_iso
- pop di
- jz .no_isolinux_dir
-.found_dir:
- ; Copy current directory name to CurrentDirName
- push si
- push di
- mov si,di
- mov di,CurrentDirName
- call strcpy
- mov byte [di],0 ;done in case it's not word aligned
- dec di
- mov byte [di],'/'
- pop di
- pop si
-
- mov [CurrentDir+dir_len],eax
- mov eax,[si+file_left]
- mov [CurrentDir+dir_clust],eax
- xor eax,eax ; Free this file pointer entry
- xchg eax,[si+file_sector]
- mov [CurrentDir+dir_lba],eax
-%ifdef DEBUG_MESSAGES
- push si
- mov si,dbg_isodir_msg
- call writemsg
- pop si
- call writehex8
- call crlf
-%endif
-.no_isolinux_dir:
+ pushad
+ extern iso_fs_ops
+ mov eax,iso_fs_ops
+ mov dl,[DriveNumber]
+ mov dh,1 ; it's cdrom
+ mov ecx,[bsHidden]
+ mov ebx,[bsHidden+4]
+ pm_call fs_init
+ popad
;
; Locate the configuration file
;
-load_config:
%ifdef DEBUG_MESSAGES
mov si,dbg_config_msg
call writemsg
%endif
- mov si,config_name
- mov di,ConfigName
- call strcpy
-
- mov di,ConfigName
- call open
- jz no_config_file ; Not found or empty
+ pm_call load_config
%ifdef DEBUG_MESSAGES
mov si,dbg_configok_msg
mov bx,trackbuf
mov cx,1 ; Load 1 sector
- call getfssec
+ pm_call getfssec
cmp word [trackbuf+510],0aa55h ; Boot signature
jne .bad_image ; Image not bootable
mov al,bl
.done_sector: ret
-;
-; close_file:
-; Deallocates a file structure (pointer in SI)
-; Assumes CS == DS.
-;
-close_file:
- and si,si
- jz .closed
- mov dword [si],0 ; First dword == file_left
- xor si,si
-.closed: ret
-
-;
-; searchdir:
-;
-; Open a file
-;
-; On entry:
-; DS:DI = filename
-; If successful:
-; ZF clear
-; SI = file pointer
-; EAX = file length in bytes
-; If unsuccessful
-; ZF set
-;
-; Assumes CS == DS == ES, and trashes BX and CX.
-;
-; 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.
-;
-alloc_failure:
- xor ax,ax ; ZF <- 1
- ret
-
-searchdir:
- xor al,al
-searchdir_iso:
- mov [ISOFlags],al
- TRACER 'S'
- call allocate_file ; Temporary file structure for directory
- jnz alloc_failure
- push es
- push ds
- pop es ; ES = DS
- mov si,CurrentDir
- cmp byte [di],'/' ; If filename begins with slash
- jne .not_rooted
- inc di ; Skip leading slash
- mov si,RootDir ; Reference root directory instead
-.not_rooted:
- mov eax,[si+dir_clust]
- mov [bx+file_left],eax
- shl eax,SECTOR_SHIFT
- mov [bx+file_bytesleft],eax
- mov eax,[si+dir_lba]
- mov [bx+file_sector],eax
- mov edx,[si+dir_len]
-
-.look_for_slash:
- mov ax,di
-.scan:
- mov cl,[di]
- inc di
- and cl,cl
- jz .isfile
- cmp cl,'/'
- jne .scan
- mov [di-1],byte 0 ; Terminate at directory name
- mov cl,02h ; Search for directory
- xchg cl,[ISOFlags]
-
- push di ; Save these...
- push cx
-
- ; Create recursion stack frame...
- push word .resume ; Where to "return" to
- push es
-.isfile: xchg ax,di
-
-.getsome:
- ; Get a chunk of the directory
- ; This relies on the fact that ISOLINUX doesn't change SI
- mov si,trackbuf
- TRACER 'g'
- pushad
- xchg bx,si
- mov cx,[BufSafe]
- call getfssec
- popad
-
-.compare:
- movzx eax,byte [si] ; Length of directory entry
- cmp al,33
- jb .next_sector
- TRACER 'c'
- mov cl,[si+25]
- xor cl,[ISOFlags]
- test cl, byte 8Eh ; Unwanted file attributes!
- jnz .not_file
- pusha
- movzx cx,byte [si+32] ; File identifier length
- add si,byte 33 ; File identifier offset
- TRACER 'i'
- call iso_compare_names
- popa
- je .success
-.not_file:
- sub edx,eax ; Decrease bytes left
- jbe .failure
- add si,ax ; Advance pointer
-
-.check_overrun:
- ; Did we finish the buffer?
- cmp si,trackbuf+trackbufsize
- jb .compare ; No, keep going
-
- jmp short .getsome ; Get some more directory
-
-.next_sector:
- ; Advance to the beginning of next sector
- lea ax,[si+SECTOR_SIZE-1]
- and ax,~(SECTOR_SIZE-1)
- sub ax,si
- jmp short .not_file ; We still need to do length checks
-
-.failure: xor eax,eax ; ZF = 1
- mov [bx+file_sector],eax
- pop es
- ret
-
-.success:
- mov eax,[si+2] ; Location of extent
- mov [bx+file_sector],eax
- mov eax,[si+10] ; Data length
- mov [bx+file_bytesleft],eax
- push eax
- add eax,SECTOR_SIZE-1
- shr eax,SECTOR_SHIFT
- mov [bx+file_left],eax
- pop eax
- jz .failure ; Empty file?
- ; ZF = 0
- mov si,bx
- pop es
- ret
-
-.resume: ; We get here if we were only doing part of a lookup
- ; This relies on the fact that .success returns bx == si
- xchg edx,eax ; Directory length in edx
- pop cx ; Old ISOFlags
- pop di ; Next filename pointer
- mov byte [di-1], '/' ; Restore slash
- mov [ISOFlags],cl ; Restore the flags
- jz .failure ; Did we fail? If so fail for real!
- jmp .look_for_slash ; Otherwise, next level
-
-;
-; allocate_file: Allocate a file structure
-;
-; If successful:
-; ZF set
-; BX = file pointer
-; In unsuccessful:
-; ZF clear
-;
-allocate_file:
- TRACER 'a'
- push cx
- mov bx,Files
- mov cx,MAX_OPEN
-.check: cmp dword [bx], byte 0
- je .found
- add bx,open_file_t_size ; ZF = 0
- loop .check
- ; ZF = 0 if we fell out of the loop
-.found: pop cx
- ret
-
-;
-; iso_compare_names:
-; Compare the names DS:SI and DS:DI and report if they are
-; equal from an ISO 9660 perspective. SI is the name from
-; the filesystem; CX indicates its length, and ';' terminates.
-; DI is expected to end with a null.
-;
-; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
-;
-
-iso_compare_names:
- ; First, terminate and canonicalize input filename
- push di
- mov di,ISOFileName
-.canon_loop: jcxz .canon_end
- lodsb
- dec cx
- cmp al,';'
- je .canon_end
- and al,al
- je .canon_end
- stosb
- cmp di,ISOFileNameEnd-1 ; Guard against buffer overrun
- jb .canon_loop
-.canon_end:
- cmp di,ISOFileName
- jbe .canon_done
- cmp byte [di-1],'.' ; Remove terminal dots
- jne .canon_done
- dec di
- jmp short .canon_end
-.canon_done:
- mov [di],byte 0 ; Null-terminate string
- pop di
- mov si,ISOFileName
-.compare:
- lodsb
- mov ah,[di]
- inc di
- and ax,ax
- jz .success ; End of string for both
- and al,al ; Is either one end of string?
- jz .failure ; If so, failure
- and ah,ah
- jz .failure
- or ax,2020h ; Convert to lower case
- cmp al,ah
- je .compare
-.failure: and ax,ax ; ZF = 0 (at least one will be nonzero)
-.success: ret
-
-;
-; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
-; to by ES:DI; ends on encountering any whitespace.
-; DI 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 redundant slashes,
-; so "repe cmpsb" can do a compare, and the
-; path-searching routine gets a bit of an easier job.
-;
-mangle_name:
- push di
- push bx
- xor ax,ax
- mov cx,FILENAME_MAX-1
- mov bx,di
-
-.mn_loop:
- lodsb
- cmp al,' ' ; If control or space, end
- jna .mn_end
- cmp al,ah ; Repeated slash?
- je .mn_skip
- xor ah,ah
- cmp al,'/'
- jne .mn_ok
- mov ah,al
-.mn_ok stosb
-.mn_skip: loop .mn_loop
-.mn_end:
- cmp bx,di ; At the beginning of the buffer?
- jbe .mn_zero
- cmp byte [es:di-1],'.' ; Terminal dot?
- je .mn_kill
- cmp byte [es:di-1],'/' ; Terminal slash?
- jne .mn_zero
-.mn_kill: dec di ; If so, remove it
- inc cx
- jmp short .mn_end
-.mn_zero:
- inc cx ; At least one null byte
- xor ax,ax ; Zero-fill name
- rep stosb
- pop bx
- pop di
- ret ; Done
;
; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
dec di ; Point to final null byte
ret
-;
-; getfssec: Get multiple clusters from a file, given the file pointer.
-;
-; On entry:
-; ES:BX -> Buffer
-; SI -> File pointer
-; CX -> Cluster count
-; On exit:
-; SI -> File pointer (or 0 on EOF)
-; CF = 1 -> Hit EOF
-; ECX -> Bytes actually read
-;
-getfssec:
- TRACER 'F'
- push ds
- push cs
- pop ds ; DS <- CS
-
- movzx ecx,cx
- cmp ecx,[si+file_left]
- jna .ok_size
- mov ecx,[si+file_left]
-.ok_size:
-
- pushad
- mov eax,[si+file_sector]
- mov bp,cx
- TRACER 'l'
- call getlinsec
- popad
-
- ; ECX[31:16] == 0 here...
- add [si+file_sector],ecx
- sub [si+file_left],ecx
- shl ecx,SECTOR_SHIFT ; Convert to bytes
- cmp ecx,[si+file_bytesleft]
- jb .not_all
- mov ecx,[si+file_bytesleft]
-.not_all: sub [si+file_bytesleft],ecx
- jnz .ret ; CF = 0 in this case...
- push eax
- xor eax,eax
- mov [si+file_sector],eax ; Unused
- mov si,ax
- pop eax
- stc
-.ret:
- pop ds
- TRACER 'f'
- ret
; -----------------------------------------------------------------------------
; Common modules