summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-06-06 00:08:13 -0700
committerH. Peter Anvin <hpa@zytor.com>2008-06-06 00:09:58 -0700
commitaf06a0d5ae28673eb7927b29cd92a4f30d882d92 (patch)
treebe170c8e49c7e40e66c8797b3dcdc643c53669d6
parent3bccdf02682afec39d253aeec25a376c7573486d (diff)
downloadsyslinux-af06a0d5ae28673eb7927b29cd92a4f30d882d92.tar.gz
FAT: Support VFAT long filenamessyslinux-3.70-pre13
Initial support for VFAT long filenames; currently hard-coded to codepage 865, no support for other codepages or for accessing files with names which aren't in the current codepage. This hopefully shouldn't be an issue for SYSLINUX applications.
-rw-r--r--NEWS1
-rw-r--r--codepage/Makefile10
-rw-r--r--core/Makefile15
-rw-r--r--core/ldlinux.asm162
4 files changed, 176 insertions, 12 deletions
diff --git a/NEWS b/NEWS
index bdda87cb..085b5b82 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,7 @@ Changes in 3.70:
all three.
* Change default dir for auxiliary files from
/usr/lib/syslinux to /usr/share/syslinux.
+ * SYSLINUX: VFAT long filename support.
Changes in 3.64:
* SYSLINUX/EXTLINUX: support "localboot" with the same feature
diff --git a/codepage/Makefile b/codepage/Makefile
index ac0b234d..d426eaad 100644
--- a/codepage/Makefile
+++ b/codepage/Makefile
@@ -6,14 +6,14 @@ GENFILES = $(patsubst %.txt,%.bin,$(CPSRC))
all: $(GENFILES)
-tidy:
+%.bin: %.txt cptable.pl UnicodeData
+ $(PERL) cptable.pl UnicodeData $< $@
-clean:
+tidy:
rm -f $(GENFILES)
+clean: tidy
+
dist: tidy
spotless: clean
-
-%.bin: %.txt cptable.pl UnicodeData
- $(PERL) cptable.pl UnicodeData $< $@
diff --git a/core/Makefile b/core/Makefile
index f763b0b3..7289294a 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -45,6 +45,11 @@ PERL = perl
VERSION := $(shell cat ../version)
+# This is very similar to cp437; technically it's for Norway and Denmark,
+# but it's unlikely the characters that are different will be used in
+# filenames by other users.
+CODEPAGE = cp865
+
# _bin.c files required by both BTARGET and ITARGET installers
BINFILES = bootsect_bin.c ldlinux_bin.c \
extlinux_bss_bin.c extlinux_sys_bin.c
@@ -140,6 +145,12 @@ extlinux_bss_bin.c: extlinux.bss ../bin2c.pl
extlinux_sys_bin.c: extlinux.sys ../bin2c.pl
$(PERL) ../bin2c.pl extlinux_image 512 < $< > $@
+# NASM prior to 2.03 wouldn't auto-generate this dependency...
+ldlinux.o: codepage.bin
+
+codepage.bin: ../codepage/$(CODEPAGE).bin
+ cp -f $< $@
+
install: installer
install-lib: installer
@@ -149,12 +160,12 @@ install-all: install install-lib
netinstall: installer
tidy dist:
- rm -f *.o *.elf *_bin.c stupid.* patch.offset
+ rm -f codepage.bin *.o *.elf stupid.* patch.offset
rm -f *.lsr *.lst *.map *.sec
rm -f $(OBSOLETE)
clean: tidy
- rm -f $(ITARGET)
+ rm -f $(ITARGET) *_bin.c
spotless: clean
rm -f $(BTARGET) .depend
diff --git a/core/ldlinux.asm b/core/ldlinux.asm
index 86de4588..8243188a 100644
--- a/core/ldlinux.asm
+++ b/core/ldlinux.asm
@@ -957,11 +957,27 @@ search_dos_dir:
jnz .alloc_failure
push cx
+ push dx
push gs
push es
push ds
pop es ; ES = DS
+ ; Compute the value of a possible VFAT longname
+ ; "last" entry (which, of course, comes first...)
+ push ax
+ push dx
+ mov ax,[NameLen]
+ add ax,12
+ xor dx,dx
+ mov cx,13
+ div cx
+ or al,40h
+ mov [VFATInit],al
+ mov [VFATNext],al
+ pop dx
+ pop ax
+
.scansector:
; EAX <- directory sector to scan
call getcachesector
@@ -971,9 +987,108 @@ search_dos_dir:
.scanentry:
cmp byte [gs:si],0
jz .failure ; Hit directory high water mark
- test byte [gs:si+11],8 ; Ignore volume labels and
- ; VFAT long filename entries
+ cmp word [gs:si+11],0Fh ; Long filename
+ jne .short_entry
+
+ ; Process a VFAT long entry
+ pusha
+ mov al,[gs:si]
+ cmp al,[VFATNext]
+ jne .not_us
+ mov bl,[gs:si+13]
+ test al,40h
+ jz .match_csum
+ ; Get the initial checksum value
+ mov [VFATCsum],bl
+ jmp .done_csum
+.match_csum:
+ cmp bl,[VFATCsum]
+ jne .not_us ; Checksum mismatch
+.done_csum:
+ and ax,03fh
+ jz .not_us ; Can't be zero...
+ dec ax
+ mov [VFATNext],al ; Optimistically...
+ mov bx,ax
+ shl bx,2 ; *4
+ add ax,bx ; *5
+ add bx,bx ; *8
+ add bx,ax ; *13
+ cmp bx,[NameLen]
+ jae .not_us
+ mov di,[NameStart]
+ inc si
+ mov cx,13
+.vfat_cmp:
+ gs lodsw
+ push bx
+ cmp bx,[NameLen]
+ jae .vfat_tail
+ movzx bx,byte [bx+di]
+ shl bx,2
+ cmp ax,[ucs_codepage+bx] ; Primary case
+ je .ucs_ok
+ cmp ax,[ucs_codepage+bx+2] ; Alternate case
+ je .ucs_ok
+ ; Mismatch...
+ jmp .not_us_pop
+.vfat_tail:
+ ; *AT* the end we should have 0x0000, *AFTER* the end
+ ; we should have 0xFFFF...
+ je .vfat_end
+ inc ax ; 0xFFFF -> 0x0000
+.vfat_end:
+ and ax,ax
+ jnz .not_us_pop
+.ucs_ok:
+ pop bx
+ inc bx
+ cmp cx,3
+ je .vfat_adj_add2
+ cmp cx,9
+ jne .vfat_adj_add0
+.vfat_adj_add3: inc si
+.vfat_adj_add2: inc si
+.vfat_adj_add1: inc si
+.vfat_adj_add0:
+ loop .vfat_cmp
+ ; Okay, if we got here we had a match on this particular
+ ; entry... live to see another one.
+ popa
+ jmp .next_entry
+
+.not_us_pop:
+ pop bx
+.not_us:
+ popa
+ jmp .nomatch
+
+.short_entry:
+ test byte [gs:si+11],8 ; Ignore volume labels
jnz .nomatch
+
+ cmp byte [VFATNext],0 ; Do we have a longname match?
+ jne .no_long_match
+
+ ; We already have a VFAT longname match, however,
+ ; the match is only valid if the checksum matches
+ push cx
+ push si
+ push ax
+ xor ax,ax
+ mov cx,11
+.csum_loop:
+ gs lodsb
+ ror ah,1
+ add ah,al
+ loop .csum_loop
+ cmp ah,[VFATCsum]
+ pop ax
+ pop si
+ pop cx
+ je .found ; Got a match on longname
+
+.no_long_match: ; Look for a shortname match
push cx
push si
push di
@@ -983,10 +1098,15 @@ search_dos_dir:
pop di
pop si
pop cx
- jz .found
+ je .found
.nomatch:
+ ; Reset the VFAT matching state machine
+ mov dh,[VFATInit]
+ mov [VFATNext],dh
+.next_entry:
add si,32
- loop .scanentry
+ dec cx
+ jnz .scanentry
call nextsector
jnc .scansector ; CF is set if we're at end
@@ -995,6 +1115,7 @@ search_dos_dir:
.failure:
pop es
pop gs
+ pop dx
pop cx
.alloc_failure:
pop bx
@@ -1022,10 +1143,22 @@ search_dos_dir:
pop es
pop gs
+ pop dx
pop cx
pop bx
ret
+ section .data
+ alignb 4
+ucs_codepage:
+ incbin "codepage.bin"
+
+ section .bss
+VFATInit resb 1
+VFATNext resb 1
+VFATCsum resb 1
+
+ section .text
;
; close_file:
; Deallocates a file structure (pointer in SI)
@@ -1219,13 +1352,19 @@ unmangle_name: call strcpy
;
; mangle_dos_name:
; Mangle a DOS filename component pointed to by DS:SI
-; into [MangledBuf]; ends on encountering any whitespace or slash.
+; into [MangledBuf]; ends on encountering any whitespace or
+; slash.
+;
+; WARNING: saves pointers into the buffer for longname
+; matches!
+;
; Assumes CS == DS == ES.
;
mangle_dos_name:
pusha
mov di,MangledBuf
+ mov [NameStart],si
mov cx,11 ; # of bytes to write
.loop:
@@ -1255,13 +1394,26 @@ mangle_dos_name:
xlatb
.not_lower: stosb
loop .loop ; Don't continue if too long
+ ; Find the end for the benefit of longname search
+.find_end:
+ lodsb
+ cmp al,' '
+ jna .end
+ cmp al,'/'
+ jne .find_end
.end:
+ dec si
+ sub si,[NameStart]
+ mov [NameLen],si
mov al,' ' ; Space-fill name
rep stosb ; Doesn't do anything if CX=0
popa
ret ; Done
section .bss
+ alignb 2
+NameStart resw 1
+NameLen resw 1
MangledBuf resb 11
section .text