summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhpa <hpa>2005-08-22 15:42:22 +0000
committerhpa <hpa>2005-08-22 15:42:22 +0000
commit21f060a5c6211233b91a48b18a79bda32f1dd5c6 (patch)
tree2e98e91444add94cf56d03bb9f1d697c7166a0e2
parent1ee8eee7896f4b2790a1791c57cb320c54d659e2 (diff)
downloadsyslinux-21f060a5c6211233b91a48b18a79bda32f1dd5c6.tar.gz
Symlink support for EXTLINUX
-rw-r--r--NEWS1
-rw-r--r--comboot.inc15
-rw-r--r--ext2_fs.inc23
-rw-r--r--extlinux.asm197
-rw-r--r--extlinux.doc10
-rw-r--r--strecpy.inc29
6 files changed, 240 insertions, 35 deletions
diff --git a/NEWS b/NEWS
index 2969e896..0f7cfbd5 100644
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,7 @@ Changes in 3.10:
problem has not yet been debugged.
* MEMDISK: the handling of DOSEMU-headered images was broken;
fix it.
+ * EXTLINUX: symlinks are now supported.
Changes in 3.09:
* gcc4 compilation fix.
diff --git a/comboot.inc b/comboot.inc
index e41b1d55..4ed6fa6e 100644
--- a/comboot.inc
+++ b/comboot.inc
@@ -583,6 +583,8 @@ numIPAppends equ ($-IPAppends)/2
comapi_ipappend equ comapi_err
%endif
+ section .text
+
;
; INT 22h AX=0010h Resolve hostname
;
@@ -597,12 +599,7 @@ comapi_dnsresolv:
comapi_dnsresolv equ comapi_err
%endif
- section .data
-%macro int21 2
- db %1
- dw %2
-%endmacro
-
+ section .text
;
; INT 22h AX=0011h Maximum number of shuffle descriptors
@@ -744,6 +741,12 @@ comapi_runkernel:
jmp kernel_good_saved
section .data
+
+%macro int21 2
+ db %1
+ dw %2
+%endmacro
+
int21_table:
int21 00h, comboot_return
int21 01h, comboot_getkey
diff --git a/ext2_fs.inc b/ext2_fs.inc
index c4c8bf71..30416167 100644
--- a/ext2_fs.inc
+++ b/ext2_fs.inc
@@ -1,7 +1,7 @@
; $Id$
; -----------------------------------------------------------------------
;
-; Copyright 1998-1999 H. Peter Anvin - All Rights Reserved
+; Copyright 1998-2005 H. Peter Anvin - All Rights Reserved
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
@@ -46,6 +46,27 @@
%define EXT2_N_BLOCKS (EXT2_TIND_BLOCK+1)
;
+; File types and file modes
+;
+%define S_IFDIR 0040000o ; Directory
+%define S_IFCHR 0020000o ; Character device
+%define S_IFBLK 0060000o ; Block device
+%define S_IFREG 0100000o ; Regular file
+%define S_IFIFO 0010000o ; FIFO
+%define S_IFLNK 0120000o ; Symbolic link
+%define S_IFSOCK 0140000o ; Socket
+
+%define S_IFSHIFT 12
+
+%define T_IFDIR (S_IFDIR >> S_IFSHIFT)
+%define T_IFCHR (S_IFCHR >> S_IFSHIFT)
+%define T_IFBLK (S_IFBLK >> S_IFSHIFT)
+%define T_IFREG (S_IFREG >> S_IFSHIFT)
+%define T_IFIFO (S_IFIFO >> S_IFSHIFT)
+%define T_IFLNK (S_IFLNK >> S_IFSHIFT)
+%define T_IFSOCK (S_IFSOCK >> S_IFSHIFT)
+
+;
; Structure definition for the ext2 superblock
;
struc ext2_super_block
diff --git a/extlinux.asm b/extlinux.asm
index f4770f1b..d291c2c1 100644
--- a/extlinux.asm
+++ b/extlinux.asm
@@ -45,6 +45,10 @@ MAX_OPEN equ (1 << MAX_OPEN_LG2)
SECTOR_SHIFT equ 9
SECTOR_SIZE equ (1 << SECTOR_SHIFT)
+MAX_SYMLINKS equ 64 ; Maximum number of symlinks per lookup
+SYMLINK_SECTORS equ 2 ; Max number of sectors in a symlink
+ ; (should be >= FILENAME_MAX)
+
;
; This is what we need to do when idle
;
@@ -939,17 +943,25 @@ allocate_file:
; ZF clear
; SI = file pointer
; DX:AX = EAX = file length in bytes
+; ThisInode = the first 128 bytes of the inode
; If unsuccessful
; ZF set
;
+; Assumes CS == DS == ES.
+;
open_inode.allocate_failure:
xor eax,eax
+ pop bx
+ pop di
ret
open_inode:
+ push di
+ push bx
call allocate_file
jnz .allocate_failure
+ push cx
push gs
; First, get the appropriate inode group and index
dec eax ; There is no inode 0
@@ -996,9 +1008,13 @@ open_inode:
call getcachesector
add si,dx
- mov ax,[gs:si+i_mode]
+ mov cx,EXT2_GOOD_OLD_INODE_SIZE >> 2
+ mov di,ThisInode
+ gs rep movsd
+
+ mov ax,[ThisInode+i_mode]
mov [bx+file_mode],ax
- mov eax,[gs:si+i_size]
+ mov eax,[ThisInode+i_size]
push eax
add eax,SECTOR_SIZE-1
shr eax,SECTOR_SHIFT
@@ -1009,8 +1025,16 @@ open_inode:
shr edx,16 ; 16-bitism, sigh
and eax,eax ; ZF clear unless zero-length file
pop gs
+ pop cx
+ pop bx
+ pop di
ret
+ section .latebss
+ alignb 4
+ThisInode resb EXT2_GOOD_OLD_INODE_SIZE ; The most recently opened inode
+
+ section .text
;
; close:
; Deallocates a file structure (pointer in SI)
@@ -1042,17 +1066,78 @@ searchdir:
push bx
push cx
push di
+ push bp
+ mov byte [SymlinkCtr],MAX_SYMLINKS
+
mov eax,[CurrentDir]
+.begin_path:
.leadingslash:
cmp byte [di],'/' ; Absolute filename?
- jne .searchloop
+ jne .gotdir
mov eax,EXT2_ROOT_INO
inc di ; Skip slash
+ jmp .leadingslash
+.gotdir:
-.searchloop:
; At this point, EAX contains the directory inode,
; and DS:DI contains a pathname tail.
+.open:
+ push eax ; Save directory inode
+
call open_inode
+ jz .done ; If error, done
+
+ mov cx,[si+file_mode]
+ shr cx,S_IFSHIFT ; Get file type
+
+ cmp cx,T_IFDIR
+ je .directory
+
+ add sp,4 ; Drop directory inode
+
+ cmp cx,T_IFREG
+ je .file
+ cmp cx,T_IFLNK
+ je .symlink
+
+ ; Otherwise, something bad...
+.err:
+ call close
+.err_noclose:
+ xor eax,eax
+ xor si,si
+ cwd ; DX <- 0
+
+.done:
+ and eax,eax ; Set/clear ZF
+ pop bp
+ pop di
+ pop cx
+ pop bx
+ ret
+
+ ;
+ ; It's a file.
+ ;
+.file:
+ cmp byte [di],0 ; End of path?
+ je .done ; If so, done
+ jmp .err ; Otherwise, error
+
+ ;
+ ; It's a directory.
+ ;
+.directory:
+ pop dword [ThisDir] ; Remember what directory we're searching
+
+ cmp byte [di],0 ; More path?
+ je .err ; If not, bad
+
+.skipslash: ; Skip redundant slashes
+ cmp byte [di],'/'
+ jne .readdir
+ inc di
+ jmp .skipslash
.readdir:
mov bx,trackbuf
@@ -1081,38 +1166,99 @@ searchdir:
pop si
popf
jnc .readdir ; There is more
-.failure:
- xor eax,eax
- jmp .done
+ jmp .err ; Otherwise badness...
+
.maybe:
mov eax,[bx+d_inode]
+ ; Does this match the end of the requested filename?
cmp byte [di],0
- je .finish ; It's a real file; done
+ je .finish
cmp byte [di],'/'
- jne .nope ; False alarm
-
- ; It's a match, but it's a directory.
- ; Repeat operation.
- pop bx ; Adjust stack (di)
- pop si
- call close
- pop bx ; Adjust stack (flags)
- inc di ; Skip slash
- jmp .searchloop
-
+ jne .nope
-.finish: ; We found it; now we need to open the file
+ ; We found something; now we need to open the file
+.finish:
pop bx ; Adjust stack (di)
pop si
call close ; Close directory
pop bx ; Adjust stack (flags)
- call open_inode
-.done:
+ jmp .open
+
+ ;
+ ; It's a symlink. We have to determine if it's a fast symlink
+ ; (data stored in the inode) or not (data stored as a regular
+ ; file.) Either which way, we start from the directory
+ ; which we just visited if relative, or from the root directory
+ ; if absolute, and append any remaining part of the path.
+ ;
+.symlink:
+ dec byte [SymlinkCtr]
+ jz .err ; Too many symlink references
+
+ cmp eax,SYMLINK_SECTORS*SECTOR_SIZE
+ jae .err ; Symlink too long
+
+ ; Computation for fast symlink, as defined by ext2/3 spec
+ xor ecx,ecx
+ cmp [ThisInode+i_file_acl],ecx
+ setne cl ; ECX <- i_file_acl ? 1 : 0
+ cmp [ThisInode+i_blocks],ecx
+ jne .slow_symlink
+
+ ; It's a fast symlink
+.fast_symlink:
+ call close ; We've got all we need
+ mov si,ThisInode+i_block
+
+ push di
+ mov di,SymlinkTmpBuf
+ mov ecx,eax
+ rep movsb
+ pop si
+
+.symlink_finish:
+ cmp byte [si],0
+ je .no_slash
+ mov al,'/'
+ stosb
+.no_slash:
+ mov bp,SymlinkTmpBufEnd
+ call strecpy
+ jc .err_noclose ; Buffer overflow
+
+ ; Now copy it to the "real" buffer; we need to have
+ ; two buffers so we avoid overwriting the tail on the
+ ; next copy
+ mov si,SymlinkTmpBuf
+ mov di,SymlinkBuf
+ push di
+ call strcpy
pop di
- pop cx
- pop bx
- ret
+ mov eax,[ThisDir] ; Resume searching previous directory
+ jmp .begin_path
+
+.slow_symlink:
+ mov bx,SymlinkTmpBuf
+ mov cx,SYMLINK_SECTORS
+ call getfssec
+ ; The EOF closed the file
+
+ mov si,di ; SI = filename tail
+ mov di,SymlinkTmpBuf
+ add ax,di ; AX = file length
+ jmp .symlink_finish
+
+
+ section .bss
+ alignb 4
+SymlinkBuf resb SYMLINK_SECTORS*SECTOR_SIZE+64
+SymlinkTmpBuf equ trackbuf
+SymlinkTmpBufEnd equ trackbuf+SYMLINK_SECTORS*SECTOR_SIZE+64
+ThisDir resd 1
+SymlinkCtr resb 1
+
+ section .text
;
; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
; to by ES:DI; ends on encountering any whitespace.
@@ -1405,6 +1551,7 @@ getfssec:
%include "graphics.inc" ; VGA graphics
%include "highmem.inc" ; High memory sizing
%include "strcpy.inc" ; strcpy()
+%include "strecpy.inc" ; strcpy with end pointer check
%include "cache.inc"
; -----------------------------------------------------------------------------
diff --git a/extlinux.doc b/extlinux.doc
index 0bf7487f..79ca7a34 100644
--- a/extlinux.doc
+++ b/extlinux.doc
@@ -30,9 +30,13 @@ It works the same way as SYSLINUX, with a few slight modifications.
limited to 255 characters.
-4. EXTLINUX currently doesn't support symlinks it does, however,
- support hard links. This will be fixed in a future version.
-
+4. EXTLINUX now supports symbolic links. However, extremely long
+ symbolic links might hit the pathname limit. Also, please note
+ that absolute symbolic links are interpreted from the root *of the
+ filesystem*, which might be different from now the running system
+ would interpret it (e.g. in the case of a separate /boot
+ partition.) Therefore, use relative symbolic links if at all
+ possible.
Note that EXTLINUX installs in the filesystem partition like a
diff --git a/strecpy.inc b/strecpy.inc
new file mode 100644
index 00000000..b4013ec6
--- /dev/null
+++ b/strecpy.inc
@@ -0,0 +1,29 @@
+;
+; strecpy: Copy DS:SI -> ES:DI up to and including a null byte;
+; on exit SI and DI point to the byte *after* the null byte.
+; BP holds a pointer to the first byte beyond the end of the
+; target buffer; return with CF=1 if target buffer overflows;
+; the output is still zero-terminated.
+;
+ section .text
+
+strecpy:
+ push ax
+ push bp
+ dec bp
+ dec bp
+.loop: lodsb
+ stosb
+ and al,al ; CF=0
+ jz .done
+ cmp bp,di ; CF set if BP < DI
+ jnc .loop
+
+ ; Zero-terminate overflow string
+ mov al,0 ; Avoid changing flags
+ stosb
+.done:
+ pop bp
+ pop ax
+ ret
+