summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2012-12-07 11:33:45 +0000
committerMatt Fleming <matt.fleming@intel.com>2012-12-07 11:33:45 +0000
commit10f6cf6eef0a7da7dad1933efdbfb101155792d0 (patch)
treed8ee3bfc6e55e739e0f135cd6d945955c670dd46 /core
parent35928ee37da523e5f992cc462a4a4193d0bfaa4c (diff)
parentddb10ce99c327888ade4d2ba3e4c50ad12aaa059 (diff)
downloadsyslinux-6.00-pre3.tar.gz
Merge tag 'syslinux-5.00' into firmwaresyslinux-6.00-pre3
Conflicts: Makefile com32/elflink/ldlinux/Makefile com32/lib/sys/module/elf_module.c core/cleanup.c core/comboot.inc core/conio.c core/fs/fs.c core/init.c core/mem/free.c core/mem/malloc.c core/timer.inc diag/geodsp/Makefile extlinux/main.c mk/embedded.mk modules/Makefile Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'core')
-rw-r--r--core/bios.c3
-rw-r--r--core/bios.inc1
-rw-r--r--core/call16.c5
-rw-r--r--core/callback.inc6
-rw-r--r--core/cleanup.c2
-rw-r--r--core/com32.inc2
-rw-r--r--core/comboot.inc449
-rw-r--r--core/conio.c309
-rw-r--r--core/diskboot.inc5
-rw-r--r--core/diskfs.inc11
-rw-r--r--core/diskstart.inc4
-rw-r--r--core/elflink/load_env32.c24
-rw-r--r--core/font.c6
-rw-r--r--core/fs/chdir.c4
-rw-r--r--core/fs/fs.c279
-rw-r--r--core/fs/getcwd.c2
-rw-r--r--core/fs/lib/searchconfig.c4
-rw-r--r--core/fs/pxe/pxe.c27
-rw-r--r--core/fs/pxe/pxe.h1
-rw-r--r--core/fs/readdir.c6
-rw-r--r--core/fs/xfs/misc.h50
-rw-r--r--core/fs/xfs/xfs.c439
-rw-r--r--core/fs/xfs/xfs.h752
-rw-r--r--core/fs/xfs/xfs_ag.h189
-rw-r--r--core/fs/xfs/xfs_dinode.c61
-rw-r--r--core/fs/xfs/xfs_dinode.h23
-rw-r--r--core/fs/xfs/xfs_dir2.c759
-rw-r--r--core/fs/xfs/xfs_dir2.h54
-rw-r--r--core/fs/xfs/xfs_fs.h501
-rw-r--r--core/fs/xfs/xfs_readdir.c404
-rw-r--r--core/fs/xfs/xfs_readdir.h30
-rw-r--r--core/fs/xfs/xfs_sb.h206
-rw-r--r--core/fs/xfs/xfs_types.h135
-rw-r--r--core/graphics.c15
-rw-r--r--core/highmem.inc158
-rw-r--r--core/idle.c4
-rw-r--r--core/idle.inc6
-rw-r--r--core/include/bios.h10
-rw-r--r--core/include/fs.h7
-rw-r--r--core/isolinux.asm10
-rw-r--r--core/kaboom.c2
-rw-r--r--core/kernel.inc3
-rw-r--r--core/layout.inc5
-rw-r--r--core/ldlinux.asm2
-rw-r--r--core/localboot.c2
-rw-r--r--core/localboot.inc2
-rw-r--r--core/mem/free.c2
-rw-r--r--core/mem/malloc.c8
-rw-r--r--core/plaincon.c2
-rw-r--r--core/pxelinux.asm9
-rw-r--r--core/rawcon.c2
-rw-r--r--core/serirq.c4
-rw-r--r--core/stack.inc2
-rw-r--r--core/timer.inc8
54 files changed, 3924 insertions, 1092 deletions
diff --git a/core/bios.c b/core/bios.c
index 5b4a8cef..7b41f398 100644
--- a/core/bios.c
+++ b/core/bios.c
@@ -462,6 +462,9 @@ struct vesa_ops bios_vesa_ops = {
static uint32_t min_lowmem_heap = 65536;
extern char __lowmem_heap[];
uint8_t KbdFlags; /* Check for keyboard escapes */
+__export uint8_t KbdMap[256]; /* Keyboard map */
+
+__export uint16_t PXERetry;
static inline void check_escapes(void)
{
diff --git a/core/bios.inc b/core/bios.inc
index 33a3cd4c..2e150594 100644
--- a/core/bios.inc
+++ b/core/bios.inc
@@ -18,7 +18,6 @@
%ifndef _BIOS_INC
%define _BIOS_INC
- global BIOS_fbm, BIOS_timer
; Interrupt vectors
absolute 4*1Ch
diff --git a/core/call16.c b/core/call16.c
index 0943a721..471aef96 100644
--- a/core/call16.c
+++ b/core/call16.c
@@ -20,7 +20,7 @@
#include <stdio.h>
#include "core.h"
-const com32sys_t zero_regs; /* Common all-zero register set */
+__export const com32sys_t zero_regs; /* Common all-zero register set */
static inline uint32_t eflags(void)
{
@@ -38,7 +38,8 @@ static inline uint32_t eflags(void)
return v;
}
-void call16(void (*func)(void), const com32sys_t *ireg, com32sys_t *oreg)
+__export void call16(void (*func)(void), const com32sys_t *ireg,
+ com32sys_t *oreg)
{
com32sys_t xreg = *ireg;
diff --git a/core/callback.inc b/core/callback.inc
index d98d8008..454b4522 100644
--- a/core/callback.inc
+++ b/core/callback.inc
@@ -37,12 +37,12 @@
; - Return segment (== real mode cs == 0)
; - Return flags
;
- global core_farcall
+ global core_farcall:function hidden
core_farcall:
mov eax,[esp+1*4] ; CS:IP
jmp core_syscall
- global core_intcall
+ global core_intcall:function hidden
core_intcall:
movzx eax,byte [esp+1*4] ; INT number
mov eax,[eax*4] ; Get CS:IP from low memory
@@ -142,7 +142,7 @@ core_syscall:
; followed by the return CS:IP and the CS:IP of the target function.
; The value of IF is copied from the calling routine.
;
- global core_cfarcall
+ global core_cfarcall:function hidden
core_cfarcall:
pushfd ; Save IF among other things...
push ebx
diff --git a/core/cleanup.c b/core/cleanup.c
index 4abefcd0..de318d98 100644
--- a/core/cleanup.c
+++ b/core/cleanup.c
@@ -47,7 +47,7 @@ void bios_cleanup_hardware(void)
*
* Shut down anything transient.
*/
-void cleanup_hardware(void)
+__export void cleanup_hardware(void)
{
firmware->cleanup();
}
diff --git a/core/com32.inc b/core/com32.inc
index 929f50ec..9c565f1d 100644
--- a/core/com32.inc
+++ b/core/com32.inc
@@ -40,7 +40,7 @@ com32_entry equ free_high_memory
;
; Danger, Will Robinson: it's not clear the use of
; core_xfer_buf is safe here.
- global __entry_esp, __com32
+ global __com32:data hidden
alignz 4
__entry_esp:
dd 0 ; Dummy to avoid _exit issues
diff --git a/core/comboot.inc b/core/comboot.inc
index fcd6c756..3197c8a7 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -95,7 +95,7 @@ comboot_setup_api:
; Restore the original state of the COMBOOT API vectors, and free
; any low memory allocated by the comboot module.
;
- global comboot_cleanup_api
+ global comboot_cleanup_api:function hidden
comboot_cleanup_api:
pusha
mov si,DOSSaveVectors
@@ -114,7 +114,7 @@ DOSSaveVectors resd 32
comboot_vectors:
dw comboot_return ; INT 20 = exit
- dw comboot_int21 ; INT 21 = DOS-compatible system calls
+ dw comboot_err(21h) ; INT 21 = DOS-compatible system calls
dw comboot_int22 ; INT 22 = native system calls
dw comboot_err(23h) ; INT 23 = DOS Ctrl-C handler
dw comboot_err(24h) ; INT 24 = DOS critical error handler
@@ -148,31 +148,6 @@ comboot_vectors:
section .text16
-; INT 21h: generic DOS system call
-comboot_int21: sti
- push ds
- push es
- push fs
- push gs
- pushad
- cld
- mov bp,cs
- mov ds,bp
- mov es,bp
- mov bp,sp ; Set up stack frame
-
- pm_call pm_adjust_screen ; The COMBOOT program might hav changed the screen
-
- mov cx,int21_count
- mov si,int21_table
-.again: lodsb
- cmp al,P_AH
- lodsw
- loopne .again
- ; The last function in the list is the
- ; "no such function" function
- clc
- call ax ; Call the invoked function
comboot_resume:
mov bp,sp ; In case the function clobbers BP
setc P_FLAGSL ; Propagate CF->error
@@ -212,7 +187,7 @@ comboot_bogus_tail:
jmp kaboom
; Proper return vector
-; Note: this gets invoked both via INT 21h and directly via INT 20h.
+; Note: this gets invoked directly via INT 20h.
; We don't need to cld explicitly here, because comboot_exit does that
; when invoking RESET_STACK_AND_SEGS.
comboot_return:
@@ -367,348 +342,36 @@ comapi_err:
ret
;
-; INT 22h AX=0001h Get SYSLINUX version
+; INT 22h AX=001Ch Get pointer to auxillary data vector
;
-comapi_get_version:
- ; Number of API functions supported
- mov P_AX,int22_count
- ; SYSLINUX version
- mov P_CX,(VERSION_MAJOR << 8)+VERSION_MINOR
- ; SYSLINUX derivative ID byte
- mov P_DX,my_id
- ; For future use
- mov P_BX,cs ; cs == 0
-
+comapi_getadv:
mov P_ES,ds
- ; ES:SI -> version banner
- mov P_SI,syslinux_banner + 2 ; Skip leading CR LF
- ; ES:DI -> copyright string
- mov P_DI,copyright_str + 1 ; Skip leading space
-
-comapi_nop:
- clc
- ret
-
-;
-; INT 22h AX=0002h Write string
-;
-; Write null-terminated string in ES:BX
-;
-comapi_writestr:
- mov ds,P_ES
- mov si,P_BX
- pm_call pm_writestr
- clc
- ret
-
-;
-; INT 22h AX=0003h Run command
-;
-; Terminates the COMBOOT program and executes the command line in
-; ES:BX as if it had been entered by the user.
-;
-comapi_run:
- mov es,P_ES
- mov bx,P_BX
- pm_call pm_env32_run
- ret
-
-;
-; INT 22h AX=0004h Run default command
-;
-; Terminates the COMBOOT program and executes the default command line
-; as if a timeout had happened or the user pressed <Enter>.
-;
-comapi_run_default:
- push auto_boot
- jmp comboot_exit
-
-;
-; INT 22h AX=0005h Force text mode
-;
-; Puts the video in standard text mode
-;
-comapi_textmode:
- pm_call syslinux_force_text_mode
- clc
- ret
-
-;
-; INT 22h AX=0006h Open file
-;
-comapi_open:
- mov es,P_ES
- mov si,P_SI
- pm_call pm_open_file
- mov P_EAX,eax
- mov P_CX,cx
- mov P_SI,si
- ret
-
-;
-; INT 22h AX=0007h Read file
-;
-comapi_read:
- mov es,P_ES
- mov bx,P_BX
- mov si,P_SI
- mov cx,P_CX
- pm_call getfssec
- jnc .noteof
- xor si,si ; SI <- 0 on EOF, CF <- 0
-.noteof: mov P_SI,si
- mov P_ECX,ecx
- ret
-
-;
-; INT 22h AX=0008h Close file
-;
-comapi_close:
- mov si,P_SI
- pm_call pm_close_file
- clc
- ret
-
-;
-; INT 22h AX=0009h Call PXE stack
-;
-%if IS_PXELINUX
-comapi_pxecall:
- mov bx,P_BX
- mov es,P_ES
- mov di,P_DI
- call pxenv
- mov ax,[PXEStatus]
- mov P_AX,ax
+ mov P_BX,adv0.data
+ mov P_CX,ADV_LEN
ret
-%else
-comapi_pxecall equ comapi_err ; Not available
-%endif
;
-; INT 22h AX=000Bh Get Serial Console Configuration
+; INT 22h AX=001Dh Write auxillary data vector
;
-comapi_serialcfg:
- pm_call pm_serialcfg
- mov P_DX,ax
- mov P_CX,cx
- mov P_BX,bx
- clc
- ret
+comapi_writeadv equ adv_write
;
-; INT 22h AX=000Ch Perform final cleanup
+; INT 22h AX=0024h Cleanup, shuffle and boot raw
;
-comapi_cleanup:
+comapi_shufraw:
%if IS_PXELINUX
; Unload PXE if requested
test dl,3
setnz [KeepPXE]
- sub bp,sp ; unload_pxe may move the stack around
+ sub bp,sp ; unload_pxe may move the stack around
pm_call unload_pxe
- add bp,sp ; restore frame pointer...
+ add bp,sp ; restore frame pointer...
%elif IS_SYSLINUX || IS_EXTLINUX
; Restore original FDC table
mov eax,[OrigFDCTabPtr]
mov [fdctab],eax
%endif
pm_call cleanup_hardware
- clc
- ret
-
-;
-; INT 22h AX=000Dh Obsolete
-;
-
-;
-; INT 22h AX=000Eh Get configuration file name
-;
-comapi_configfile:
- mov P_ES,cs
- mov P_BX,ConfigName
- clc
- ret
-
-;
-; INT 22h AX=000Fh Get IPAPPEND strings
-;
-comapi_ipappend:
- mov P_ES,cs
- mov P_CX,numIPAppends
- mov P_BX,IPAppends
- clc
- ret
-
-;
-; INT 22h AX=0010h Resolve hostname
-;
-%if IS_PXELINUX
- extern pm_pxe_dns_resolv
-comapi_dnsresolv:
- mov ds,P_ES
- mov si,P_BX
- pm_call pm_pxe_dns_resolv
- mov P_EAX,eax
- clc
- ret
-%else
-comapi_dnsresolv equ comapi_err
-%endif
-
- section .text16
-
-;
-; INT 22h AX=0011h Obsolete
-;
-
-;
-; INT 22h AX=0012h Obsolete
-;
-
-;
-; INT 22h AX=0013h Idle call
-;
-comapi_idle:
- call do_idle
- clc
- ret
-
-;
-; INT 22h AX=0014h Local boot
-;
-comapi_localboot:
- mov ax,P_DX
- pm_call pm_local_boot
- ret
-
-;
-; INT 22h AX=0015h Feature flags
-;
-comapi_features:
- mov P_ES,cs
- mov P_BX,feature_flags
- mov P_CX,feature_flags_len
- clc
- ret
-
-;
-; INT 22h AX=0016h Run kernel image
-;
-comapi_runkernel:
- ret
-
-;
-; INT 22h AX=0017h Report video mode change
-;
-comapi_usingvga:
- mov ax,P_BX
- cmp ax,0Fh ; Unknown flags = failure
- ja .error
- mov cx,P_CX
- mov dx,P_DX
- pm_call pm_using_vga
- clc
- ret
-.error:
- stc
- ret
-
-;
-; INT 22h AX=0018h Query custom font
-;
-comapi_userfont:
- mov al,[UserFont]
- and al,al
- jz .done
- mov al,[VGAFontSize]
- pm_call pm_userfont
- mov P_ES,es
- mov P_BX,bx
-
-.done: ; CF=0 here
- mov P_AL,al
- ret
-
-;
-; INT 22h AX=0019h Read disk
-;
-%if IS_SYSLINUX || IS_ISOLINUX || IS_EXTLINUX
-comapi_readdisk:
- cmp P_EDI,0 ; Reserved for future expansion
- jnz .err
- mov eax,P_EDX
- mov edx,P_ESI
- mov es,P_ES
- mov bx,P_BX
- mov bp,P_CX ; WE CANNOT use P_* after touching bp!
- call getlinsec
- clc
- ret
-.err:
- stc
- ret
-%else
-comapi_readdisk equ comapi_err
-%endif
-
-;
-; INT 22h AX=001Ah Obsolete
-;
-
-;
-; INT 22h AX=001Bh Obsolete
-;
-
-;
-; INT 22h AX=001Ch Get pointer to auxillary data vector
-;
-comapi_getadv:
- mov P_ES,ds
- mov P_BX,adv0.data
- mov P_CX,ADV_LEN
- ret
-
-;
-; INT 22h AX=001Dh Write auxillary data vector
-;
-comapi_writeadv equ adv_write
-
-;
-; INT 22h AX=001Eh Keyboard remapping table
-comapi_kbdtable:
- cmp P_DX,0
- jne .err
- mov P_AX,1 ; Version
- mov P_CX,256 ; Length
- mov P_ES,cs
- mov P_BX,KbdMap
- ret
-.err:
- stc
- ret
-
-;
-; INT 22h AX=001Fh Get current working directory
-;
-comapi_getcwd:
- mov P_ES,cs
- mov P_BX,CurrentDirName
- clc
- ret
-
-;
-; INT 22h AX=0023h Query shuffler size
-;
-comapi_shufsize:
- ; +15 is padding to guarantee alignment
- mov P_CX,__bcopyxx_len + 15
- ret
-
-;
-; INT 22h AX=0024h Cleanup, shuffle and boot raw
-;
-comapi_shufraw:
- call comapi_cleanup
mov edi,P_EDI
mov esi,P_ESI
mov ecx,P_ECX
@@ -723,62 +386,44 @@ comapi_initadv:
section .data16
-%macro int21 2
- db %1
- dw %2
-%endmacro
-
-int21_table:
- int21 00h, comboot_return
- int21 01h, comboot_getkey
- int21 02h, comboot_writechr
- int21 04h, comboot_writeserial
- int21 08h, comboot_getkeynoecho
- int21 09h, comboot_writestr
- int21 0Bh, comboot_checkkey
- int21 30h, comboot_checkver
- int21 4Ch, comboot_return
- int21 -1, comboot_bad_int21
-int21_count equ ($-int21_table)/3
-
alignz 2
int22_table:
dw comapi_err ; 0000 unimplemented syscall
- dw comapi_get_version ; 0001 get SYSLINUX version
- dw comapi_writestr ; 0002 write string
- dw comapi_run ; 0003 run specified command
- dw comapi_run_default ; 0004 run default command
- dw comapi_textmode ; 0005 force text mode
- dw comapi_open ; 0006 open file
- dw comapi_read ; 0007 read file
- dw comapi_close ; 0008 close file
- dw comapi_pxecall ; 0009 call PXE stack
+ dw comapi_err ; 0001 get SYSLINUX version
+ dw comapi_err ; 0002 write string
+ dw comapi_err ; 0003 run specified command
+ dw comapi_err ; 0004 run default command
+ dw comapi_err ; 0005 force text mode
+ dw comapi_err ; 0006 open file
+ dw comapi_err ; 0007 read file
+ dw comapi_err ; 0008 close file
+ dw comapi_err ; 0009 call PXE stack
dw comapi_err ; 000A derivative-specific info
- dw comapi_serialcfg ; 000B get serial port config
- dw comapi_cleanup ; 000C perform final cleanup
+ dw comapi_err ; 000B get serial port config
+ dw comapi_err ; 000C perform final cleanup
dw comapi_err ; 000D clean up then bootstrap
- dw comapi_configfile ; 000E get name of config file
- dw comapi_ipappend ; 000F get ipappend strings
- dw comapi_dnsresolv ; 0010 resolve hostname
+ dw comapi_err ; 000E get name of config file
+ dw comapi_err ; 000F get ipappend strings
+ dw comapi_err ; 0010 resolve hostname
dw comapi_err ; 0011 maximum shuffle descriptors
dw comapi_err ; 0012 cleanup, shuffle and boot
- dw comapi_idle ; 0013 idle call
- dw comapi_localboot ; 0014 local boot
- dw comapi_features ; 0015 feature flags
- dw comapi_runkernel ; 0016 run kernel image
- dw comapi_usingvga ; 0017 report video mode change
- dw comapi_userfont ; 0018 query custom font
- dw comapi_readdisk ; 0019 read disk
+ dw comapi_err ; 0013 idle call
+ dw comapi_err ; 0014 local boot
+ dw comapi_err ; 0015 feature flags
+ dw comapi_err ; 0016 run kernel image
+ dw comapi_err ; 0017 report video mode change
+ dw comapi_err ; 0018 query custom font
+ dw comapi_err ; 0019 read disk
dw comapi_err ; 001A cleanup, shuffle and boot to pm
dw comapi_err ; 001B cleanup, shuffle and boot to rm
dw comapi_getadv ; 001C get pointer to ADV
dw comapi_writeadv ; 001D write ADV to disk
- dw comapi_kbdtable ; 001E keyboard remapping table
- dw comapi_getcwd ; 001F get current working directory
+ dw comapi_err ; 001E keyboard remapping table
+ dw comapi_err ; 001F get current working directory
dw comapi_err ; 0020 open directory
dw comapi_err ; 0021 read directory
dw comapi_err ; 0022 close directory
- dw comapi_shufsize ; 0023 query shuffler size
+ dw comapi_err ; 0023 query shuffler size
dw comapi_shufraw ; 0024 cleanup, shuffle and boot raw
dw comapi_initadv ; 0025 initialize adv structure
int22_count equ ($-int22_table)/2
@@ -788,32 +433,14 @@ APIKeyFlag db 0
zero_string db 0 ; Empty, null-terminated string
-;
-; This is the feature flag array for INT 22h AX=0015h
-;
-; Note: PXELINUX clears the idle is noop flag if appropriate
-; in pxe_detect_nic_type
-;
- global feature_flags, feature_flags_len
-feature_flags:
- db 1 ; Have local boot, idle is not noop
-feature_flags_len equ ($-feature_flags)
-
err_notdos db ': attempted DOS system call INT ',0
err_comlarge db 'COMBOOT image too large.', CR, LF, 0
- global VGAFontSize, UserFont
- alignz 2
-VGAFontSize dw 16 ; Defaults to 16 byte font
-UserFont db 0 ; Using a user-specified font
-
section .bss16
alignb 4
DOSErrTramp resd 33 ; Error trampolines
- global ConfigName
-ConfigName resb FILENAME_MAX
%ifndef HAVE_CURRENTDIRNAME
- global CurrentDirName
+ global CurrentDirName:data hidden
CurrentDirName resb FILENAME_MAX
%endif
diff --git a/core/conio.c b/core/conio.c
index d34c9cf2..a351fd14 100644
--- a/core/conio.c
+++ b/core/conio.c
@@ -38,30 +38,21 @@ union screen _screensize;
/*
* Serial console stuff.
*/
-uint16_t SerialPort = 0; /* Serial port base (or 0 for no serial port) */
-uint16_t BaudDivisor = 115200/9600; /* Baud rate divisor */
-uint8_t FlowOutput = 0; /* Output to assert for serial flow */
-uint8_t FlowInput = 0; /* Input bits for serial flow */
-uint8_t FlowIgnore = 0; /* Ignore input unless these bits set */
+__export uint16_t SerialPort = 0; /* Serial port base (or 0 for no serial port) */
+__export uint8_t FlowInput = 0; /* Input bits for serial flow */
+__export uint16_t BaudDivisor = 115200/9600; /* Baud rate divisor */
+__export uint8_t FlowIgnore = 0; /* Ignore input unless these bits set */
+__export uint16_t DisplayCon = 0x01; /* Display console enabled */
+__export uint8_t FlowOutput = 0; /* Output to assert for serial flow */
uint8_t ScrollAttribute = 0x07; /* Grey on white (normal text color) */
-uint16_t DisplayCon = 0x01; /* Display console enabled */
-static uint8_t TextAttribute; /* Text attribute for message file */
-static uint8_t DisplayMask; /* Display modes mask */
-
-/* Routine to interpret next print char */
-static void (*NextCharJump)(char);
-
-void msg_initvars(void);
-static void msg_setfg(char data);
-static void msg_putchar(char ch);
/*
* loadkeys: Load a LILO-style keymap
*
* Returns 0 on success, or -1 on error.
*/
-int loadkeys(char *filename)
+__export int loadkeys(char *filename)
{
FILE *f;
@@ -76,53 +67,10 @@ int loadkeys(char *filename)
}
/*
- *
- * get_msg_file: Load a text file and write its contents to the screen,
- * interpreting color codes.
- *
- * Returns 0 on success, -1 on failure.
- */
-int get_msg_file(char *filename)
-{
- FILE *f;
- char ch;
-
- f = fopen(filename, "r");
- if (!f)
- return -1;
-
- TextAttribute = 0x7; /* Default grey on white */
- DisplayMask = 0x7; /* Display text in all modes */
- msg_initvars();
-
- /*
- * Read the text file a byte at a time and interpret that
- * byte.
- */
- while ((ch = getc(f)) != EOF) {
- /* DOS EOF? */
- if (ch == 0x1A)
- break;
-
- /*
- * 01h = text mode
- * 02h = graphics mode
- */
- UsingVGA &= 0x1;
- UsingVGA += 1;
-
- NextCharJump(ch); /* Do what shall be done */
- }
-
- fclose(f);
- return 0;
-}
-
-/*
* write_serial: If serial output is enabled, write character on
* serial port.
*/
-void write_serial(char data)
+__export void write_serial(char data)
{
if (!SerialPort)
return;
@@ -179,16 +127,10 @@ void pm_serialcfg(com32sys_t *regs)
serialcfg(&regs->eax.w[0], &regs->ecx.w[0], &regs->ebx.w[0]);
}
-static void write_serial_displaymask(char data)
-{
- if (DisplayMask & 0x4)
- write_serial(data);
-}
-
/*
* write_serial_str: write_serial for strings
*/
-void write_serial_str(char *data)
+__export void write_serial_str(char *data)
{
char ch;
@@ -197,15 +139,6 @@ void write_serial_str(char *data)
}
/*
- * write_serial_str_displaymask: d:o, but ignore if DisplayMask & 04h == 0
- */
-static void write_serial_str_displaymask(char *data)
-{
- if (DisplayMask & 0x4)
- write_serial_str(data);
-}
-
-/*
* pollchar: check if we have an input character pending
*
* Returns 1 if character pending.
@@ -250,7 +183,7 @@ int bios_pollchar(void)
return data;
}
-int pollchar(void)
+__export int pollchar(void)
{
return firmware->i_ops->pollchar();
}
@@ -334,7 +267,7 @@ char bios_getchar(char *hi)
/*
* getchar: Read a character from keyboard or serial port
*/
-char getchar(char *hi)
+__export char getchar(char *hi)
{
return firmware->i_ops->getchar(hi);
}
@@ -343,223 +276,3 @@ void pm_getchar(com32sys_t *regs)
{
regs->eax.b[0] = getchar((char *)&regs->eax.b[1]);
}
-
-static void msg_setbg(char data)
-{
- if (unhexchar(&data) == 0) {
- data <<= 4;
- if (DisplayMask & UsingVGA)
- TextAttribute = data;
-
- NextCharJump = msg_setfg;
- } else {
- TextAttribute = 0x7; /* Default attribute */
- NextCharJump = msg_putchar;
- }
-}
-
-static void msg_setfg(char data)
-{
- if (unhexchar(&data) == 0) {
- if (DisplayMask & UsingVGA) {
- /* setbg set foreground to 0 */
- TextAttribute |= data;
- }
- } else
- TextAttribute = 0x7; /* Default attribute */
-
- NextCharJump = msg_putchar;
-}
-
-static inline void msg_ctrl_o(void)
-{
- NextCharJump = msg_setbg;
-}
-
-static void msg_gotoxy(void)
-{
- firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
-}
-
-static void msg_newline(void)
-{
- com32sys_t ireg, oreg;
- char crlf_msg[] = { '\r', '\n', '\0' };
-
- write_serial_str_displaymask(crlf_msg);
-
- if (!(DisplayMask & UsingVGA))
- return;
-
- CursorCol = 0;
- if ((CursorRow + 1) <= VidRows)
- CursorRow++;
- else {
- CursorRow = VidRows; /* New cursor at the bottom */
- firmware->o_ops->scroll_up(VidRows, VidCols, ScrollAttribute);
- }
-
- firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
-}
-
-static void msg_formfeed(void)
-{
- char crff_msg[] = { '\r', '\f', '\0' };
-
- write_serial_str_displaymask(crff_msg);
-
- if (DisplayMask & UsingVGA) {
- CursorDX = 0x0; /* Upper left hand corner */
-
- firmware->o_ops->erase(0, 0, VidCols, VidRows, TextAttribute);
- firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
- }
-}
-
-static void msg_novga(void)
-{
- syslinux_force_text_mode();
- msg_initvars();
-}
-
-static void msg_viewimage(void)
-{
- FILE *f;
-
- *VGAFilePtr = '\0'; /* Zero-terminate filename */
-
- mangle_name(VGAFileMBuf, VGAFileBuf);
- f = fopen(VGAFileMBuf, "r");
- if (!f) {
- /* Not there */
- NextCharJump = msg_putchar;
- return;
- }
-
- vgadisplayfile(f);
- fclose(f);
- msg_initvars();
-}
-
-/*
- * Getting VGA filename
- */
-static void msg_filename(char data)
-{
- /* <LF> = end of filename */
- if (data == 0x0A) {
- msg_viewimage();
- return;
- }
-
- /* Ignore space/control char */
- if (data > ' ') {
- if ((char *)VGAFilePtr < (VGAFileBuf + sizeof(VGAFileBuf)))
- *VGAFilePtr++ = data;
- }
-}
-
-static void msg_vga(void)
-{
- NextCharJump = msg_filename;
- VGAFilePtr = (uint16_t *)VGAFileBuf;
-}
-
-static void msg_line_wrap(void)
-{
- if (!(DisplayMask & UsingVGA))
- return;
-
- CursorCol = 0;
- if ((CursorRow + 1) <= VidRows)
- CursorRow++;
- else {
- /* Scroll up one line */
- firmware->o_ops->scroll_up(VidRows, VidCols, ScrollAttribute);
- }
-
- firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
-}
-
-static void msg_normal(char data)
-{
- com32sys_t ireg, oreg;
-
- /* Write to serial port */
- write_serial_displaymask(data);
-
- if (!(DisplayMask & UsingVGA))
- return; /* Not screen */
-
- if (!(DisplayCon & 0x01))
- return;
-
- /* Write to screen */
- firmware->o_ops->write_char(data, TextAttribute);
-
- if ((CursorCol + 1) <= VidCols) {
- CursorCol++;
- firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
- } else
- msg_line_wrap(); /* Screen wraparound */
-}
-
-static void msg_modectl(char data)
-{
- data &= 0x07;
- DisplayMask = data;
- NextCharJump = msg_putchar;
-}
-
-static void msg_putchar(char ch)
-{
- /* 10h to 17h are mode controls */
- if (ch >= 0x10 && ch < 0x18) {
- msg_modectl(ch);
- return;
- }
-
- switch (ch) {
- case 0x0F: /* ^O = color code follows */
- msg_ctrl_o();
- break;
- case 0x0D: /* Ignore <CR> */
- break;
- case 0x0A: /* <LF> = newline */
- msg_newline();
- break;
- case 0x0C: /* <FF> = clear screen */
- msg_formfeed();
- break;
- case 0x07: /* <BEL> = beep */
- if (firmware->o_ops->beep)
- firmware->o_ops->beep();
- break;
- case 0x19: /* <EM> = return to text mode */
- msg_novga();
- break;
- case 0x18: /* <CAN> = VGA filename follows */
- msg_vga();
- break;
- default:
- msg_normal(ch);
- break;
- }
-}
-
-/*
- * Subroutine to initialize variables, also needed after loading
- * graphics file.
- */
-void msg_initvars(void)
-{
- com32sys_t ireg, oreg;
- int x, y;
-
- firmware->o_ops->get_cursor(&x, &y);
- CursorCol = x;
- CursorRow = y;
-
- /* Initialize state machine */
- NextCharJump = msg_putchar;
-}
diff --git a/core/diskboot.inc b/core/diskboot.inc
index be816263..ce75b8c9 100644
--- a/core/diskboot.inc
+++ b/core/diskboot.inc
@@ -103,7 +103,6 @@ superblock_len_fat32 equ $-superblock+54
zb 54 ; Maximum needed size
superblock_max equ $-superblock
- global SecPerClust
SecPerClust equ bxSecPerClust
;
@@ -385,7 +384,11 @@ getonesec_cbios:
;
; kaboom: write a message and bail out.
;
+%ifdef BINFMT
global kaboom
+%else
+ global kaboom:function hidden
+%endif
disk_error:
kaboom:
xor si,si
diff --git a/core/diskfs.inc b/core/diskfs.inc
index dcbc924a..827f5003 100644
--- a/core/diskfs.inc
+++ b/core/diskfs.inc
@@ -60,7 +60,7 @@ vk_end: equ $ ; Should be <= vk_size
; Memory below this point is reserved for the BIOS and the MBR
;
section .earlybss
- global trackbuf
+ global trackbuf:data hidden
trackbufsize equ 8192
trackbuf resb trackbufsize ; Track buffer goes here
; ends at 2800h
@@ -91,24 +91,15 @@ auto_boot:
jmp kaboom
section .bss16
- global CmdOptPtr, KbdMap
alignb 4
ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
KernelExtPtr resw 1 ; During search, final null pointer
-CmdOptPtr resw 1 ; Pointer to first option on cmd line
-KbdFlags resb 1 ; Check for keyboard escapes
FuncFlag resb 1 ; Escape sequences received from keyboard
KernelType resb 1 ; Kernel type, from vkernel, if known
-KbdMap resb 256 ; Keyboard map
global KernelName
KernelName resb FILENAME_MAX ; Mangled name for kernel
- section .config
- global PXERetry
-PXERetry dw 0 ; Extra PXE retries
section .data16
- global SerialNotice
-SerialNotice db 1 ; Only print this once
global IPAppends, numIPAppends
%if IS_PXELINUX
extern IPOption
diff --git a/core/diskstart.inc b/core/diskstart.inc
index 603a6db2..875b4093 100644
--- a/core/diskstart.inc
+++ b/core/diskstart.inc
@@ -92,7 +92,7 @@ BannerPtr dw syslinux_banner - LDLINUX_SYS
; Base directory name and subvolume, if applicable.
;
%define HAVE_CURRENTDIRNAME
- global CurrentDirName, SubvolName
+ global CurrentDirName:data hidden, SubvolName:data hidden
CurrentDirName times CURRENTDIR_MAX db 0
SubvolName times SUBVOL_MAX db 0
@@ -232,7 +232,7 @@ verify_checksum:
;
; This routine assumes CS == DS.
;
- global getlinsec
+ global getlinsec:function hidden
getlinsec:
pushad
add eax,[Hidden] ; Add partition offset
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
index f3dd1e77..1fa43bd6 100644
--- a/core/elflink/load_env32.c
+++ b/core/elflink/load_env32.c
@@ -57,7 +57,7 @@ void init_module_subsystem(struct elf_module *module)
list_add(&module->list, &modules_head);
}
-int start_ldlinux(char **argv)
+__export int start_ldlinux(char **argv)
{
int rv;
@@ -69,9 +69,19 @@ again:
* unload all the modules loaded since ldlinux.c32,
* and restart initialisation. This is especially
* important for config files.
+ *
+ * But before we do that, try our best to make sure
+ * that spawn_load() is gonna succeed, e.g. that we
+ * can find LDLINUX it in PATH.
*/
struct elf_module *ldlinux;
+ FILE *f;
+
+ f = findpath(LDLINUX);
+ if (!f)
+ return ENOENT;
+ fclose(f);
ldlinux = unload_modules_since(LDLINUX);
/*
@@ -113,14 +123,13 @@ void load_env32(com32sys_t * regs __unused)
dprintf("Starting %s elf module subsystem...\n", ELF_MOD_SYS);
- PATH = malloc(strlen(PATH_DEFAULT) + 1);
+ PATH = malloc(strlen(CurrentDirName) + 1);
if (!PATH) {
printf("Couldn't allocate memory for PATH\n");
return;
}
- strcpy(PATH, PATH_DEFAULT);
- PATH[strlen(PATH_DEFAULT)] = '\0';
+ strcpy(PATH, CurrentDirName);
size = (size_t)__dynstr_end - (size_t)__dynstr_start;
core_module.strtable_size = size;
@@ -150,7 +159,7 @@ void load_env32(com32sys_t * regs __unused)
writestr("\nFailed to load ldlinux.c32");
}
-int create_args_and_load(char *cmdline)
+__export int create_args_and_load(char *cmdline)
{
char *p, **argv;
int argc;
@@ -175,9 +184,10 @@ int create_args_and_load(char *cmdline)
* Generate a copy of argv on the stack as this is
* traditionally where process arguments go.
*
- * argv[0] must be the command name.
+ * argv[0] must be the command name. Remember to allocate
+ * space for the sentinel NULL.
*/
- argv = alloca(argc * sizeof(char *));
+ argv = alloca((argc + 1) * sizeof(char *));
for (i = 0, p = cmdline; i < argc; i++) {
char *start;
diff --git a/core/font.c b/core/font.c
index 1e4e606d..edc9de8e 100644
--- a/core/font.c
+++ b/core/font.c
@@ -27,7 +27,9 @@
#include "graphics.h"
#include "core.h"
-__lowmem char fontbuf[8192];
+__export uint8_t UserFont = 0; /* Using a user-specified font */
+
+__export __lowmem char fontbuf[8192];
uint16_t GXPixCols = 1; /* Graphics mode pixel columns */
uint16_t GXPixRows = 1; /* Graphics mode pixel rows */
@@ -36,7 +38,7 @@ uint16_t GXPixRows = 1; /* Graphics mode pixel rows */
* loadfont: Load a .psf font file and install it onto the VGA console
* (if we're not on a VGA screen then ignore.)
*/
-void loadfont(const char *filename)
+__export void loadfont(const char *filename)
{
struct psfheader {
uint16_t magic;
diff --git a/core/fs/chdir.c b/core/fs/chdir.c
index 903cabce..5d3a545f 100644
--- a/core/fs/chdir.c
+++ b/core/fs/chdir.c
@@ -54,7 +54,7 @@ static size_t generic_inode_to_path(struct inode *inode, char *dst, size_t bufsi
return s;
}
-size_t realpath(char *dst, const char *src, size_t bufsize)
+__export size_t realpath(char *dst, const char *src, size_t bufsize)
{
int rv;
struct file *file;
@@ -83,7 +83,7 @@ size_t realpath(char *dst, const char *src, size_t bufsize)
return s;
}
-int chdir(const char *src)
+__export int chdir(const char *src)
{
int rv;
struct file *file;
diff --git a/core/fs/fs.c b/core/fs/fs.c
index 21e7684a..40f97d5e 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -9,13 +9,13 @@
#include "fs.h"
#include "cache.h"
-char *PATH;
+__export char *PATH;
/* The currently mounted filesystem */
-struct fs_info *this_fs = NULL; /* Root filesystem */
+__export struct fs_info *this_fs = NULL; /* Root filesystem */
/* Actual file structures (we don't have malloc yet...) */
-struct file files[MAX_OPEN];
+__export struct file files[MAX_OPEN];
/* Symlink hard limits */
#define MAX_SYMLINK_CNT 20
@@ -74,7 +74,7 @@ static inline void free_file(struct file *file)
memset(file, 0, sizeof *file);
}
-void _close_file(struct file *file)
+__export void _close_file(struct file *file)
{
if (file->fs)
file->fs->fs_ops->close_file(file);
@@ -84,7 +84,7 @@ void _close_file(struct file *file)
/*
* Find and open the configuration file
*/
-int open_config(void)
+__export int open_config(void)
{
int fd, handle;
struct file_info *fp;
@@ -116,7 +116,7 @@ void pm_mangle_name(com32sys_t *regs)
mangle_name(dst, src);
}
-void mangle_name(char *dst, const char *src)
+__export void mangle_name(char *dst, const char *src)
{
this_fs->fs_ops->mangle_name(dst, src);
}
@@ -219,11 +219,10 @@ void pm_searchdir(com32sys_t *regs)
int searchdir(const char *name)
{
- struct inode *inode = NULL;
- struct inode *parent = NULL;
+ static char root_name[] = "/";
struct file *file;
- char *pathbuf = NULL;
- char *part, *p, echar;
+ char *path, *inode_name, *next_inode_name;
+ struct inode *tmp, *inode = NULL;
int symlink_count = MAX_SYMLINK_CNT;
dprintf("searchdir: %s root: %p cwd: %p\n",
@@ -245,113 +244,165 @@ int searchdir(const char *name)
/* else, try the generic-path-lookup method */
- parent = get_inode(this_fs->cwd);
- p = pathbuf = strdup(name);
- if (!pathbuf)
- goto err;
+ /* Copy the path */
+ path = strdup(name);
+ if (!path) {
+ dprintf("searchdir: Couldn't copy path\n");
+ goto err_path;
+ }
+
+ /* Work with the current directory, by default */
+ inode = get_inode(this_fs->cwd);
+ if (!inode) {
+ dprintf("searchdir: Couldn't use current directory\n");
+ goto err_curdir;
+ }
- do {
- got_link:
- if (*p == '/') {
- put_inode(parent);
- parent = get_inode(this_fs->root);
+ for (inode_name = path; inode_name; inode_name = next_inode_name) {
+ /* Root directory? */
+ if (inode_name[0] == '/') {
+ next_inode_name = inode_name + 1;
+ inode_name = root_name;
+ } else {
+ /* Find the next inode name */
+ next_inode_name = strchr(inode_name + 1, '/');
+ if (next_inode_name) {
+ /* Terminate the current inode name and point to next */
+ *next_inode_name++ = '\0';
+ }
+ }
+ if (next_inode_name) {
+ /* Advance beyond redundant slashes */
+ while (*next_inode_name == '/')
+ next_inode_name++;
+
+ /* Check if we're at the end */
+ if (*next_inode_name == '\0')
+ next_inode_name = NULL;
+ }
+ dprintf("searchdir: inode_name: %s\n", inode_name);
+ if (next_inode_name)
+ dprintf("searchdir: Remaining: %s\n", next_inode_name);
+
+ /* Root directory? */
+ if (inode_name[0] == '/') {
+ /* Release any chain that's already been established */
+ put_inode(inode);
+ inode = get_inode(this_fs->root);
+ continue;
}
- do {
- inode = get_inode(parent);
-
- while (*p == '/')
- p++;
-
- if (!*p)
- break;
-
- part = p;
- while ((echar = *p) && echar != '/')
- p++;
- *p++ = '\0';
-
- if (part[0] == '.' && part[1] == '.' && part[2] == '\0') {
- if (inode->parent) {
- put_inode(parent);
- parent = get_inode(inode->parent);
- put_inode(inode);
- inode = NULL;
- if (!echar) {
- /* Terminal double dots */
- inode = parent;
- parent = inode->parent ?
- get_inode(inode->parent) : NULL;
- }
- }
- } else if (part[0] != '.' || part[1] != '\0') {
- inode = this_fs->fs_ops->iget(part, parent);
- if (!inode)
- goto err;
- if (inode->mode == DT_LNK) {
- char *linkbuf, *q;
- int name_len = echar ? strlen(p) : 0;
- int total_len = inode->size + name_len + 2;
- int link_len;
-
- if (!this_fs->fs_ops->readlink ||
- --symlink_count == 0 || /* limit check */
- total_len > MAX_SYMLINK_BUF)
- goto err;
-
- linkbuf = malloc(total_len);
- if (!linkbuf)
- goto err;
-
- link_len = this_fs->fs_ops->readlink(inode, linkbuf);
- if (link_len <= 0) {
- free(linkbuf);
- goto err;
- }
-
- q = linkbuf + link_len;
-
- if (echar) {
- if (link_len > 0 && q[-1] != '/')
- *q++ = '/';
-
- memcpy(q, p, name_len+1);
- } else {
- *q = '\0';
- }
-
- free(pathbuf);
- p = pathbuf = linkbuf;
- put_inode(inode);
- inode = NULL;
- goto got_link;
- }
-
- inode->name = strdup(part);
- dprintf("path component: %s\n", inode->name);
-
- inode->parent = parent;
- parent = NULL;
-
- if (!echar)
- break;
-
- if (inode->mode != DT_DIR)
- goto err;
-
- parent = inode;
- inode = NULL;
+ /* Current directory? */
+ if (!strncmp(inode_name, ".", sizeof "."))
+ continue;
+
+ /* Parent directory? */
+ if (!strncmp(inode_name, "..", sizeof "..")) {
+ /* If there is no parent, just ignore it */
+ if (!inode->parent)
+ continue;
+
+ /* Add a reference to the parent so we can release the child */
+ tmp = get_inode(inode->parent);
+
+ /* Releasing the child will drop the parent back down to 1 */
+ put_inode(inode);
+
+ inode = tmp;
+ continue;
+ }
+
+ /* Anything else */
+ tmp = inode;
+ inode = this_fs->fs_ops->iget(inode_name, inode);
+ if (!inode) {
+ /* Failure. Release the chain */
+ put_inode(tmp);
+ break;
+ }
+
+ /* Sanity-check */
+ if (inode->parent && inode->parent != tmp) {
+ dprintf("searchdir: iget returned a different parent\n");
+ put_inode(inode);
+ inode = NULL;
+ put_inode(tmp);
+ break;
+ }
+ inode->parent = tmp;
+ inode->name = strdup(inode_name);
+ dprintf("searchdir: path component: %s\n", inode->name);
+
+ /* Symlink handling */
+ if (inode->mode == DT_LNK) {
+ char *new_path;
+ int new_len, copied;
+
+ /* target path + NUL */
+ new_len = inode->size + 1;
+
+ if (next_inode_name) {
+ /* target path + slash + remaining + NUL */
+ new_len += strlen(next_inode_name) + 1;
+ }
+
+ if (!this_fs->fs_ops->readlink ||
+ /* limit checks */
+ --symlink_count == 0 ||
+ new_len > MAX_SYMLINK_BUF)
+ goto err_new_len;
+
+ new_path = malloc(new_len);
+ if (!new_path)
+ goto err_new_path;
+
+ copied = this_fs->fs_ops->readlink(inode, new_path);
+ if (copied <= 0)
+ goto err_copied;
+ new_path[copied] = '\0';
+ dprintf("searchdir: Symlink: %s\n", new_path);
+
+ if (next_inode_name) {
+ new_path[copied] = '/';
+ strcpy(new_path + copied + 1, next_inode_name);
+ dprintf("searchdir: New path: %s\n", new_path);
}
- } while (echar);
- } while (0);
- free(pathbuf);
- pathbuf = NULL;
- put_inode(parent);
- parent = NULL;
+ free(path);
+ path = next_inode_name = new_path;
- if (!inode)
+ /* Add a reference to the parent so we can release the child */
+ tmp = get_inode(inode->parent);
+
+ /* Releasing the child will drop the parent back down to 1 */
+ put_inode(inode);
+
+ inode = tmp;
+ continue;
+err_copied:
+ free(new_path);
+err_new_path:
+err_new_len:
+ put_inode(inode);
+ inode = NULL;
+ break;
+ }
+
+ /* If there's more to process, this should be a directory */
+ if (next_inode_name && inode->mode != DT_DIR) {
+ dprintf("searchdir: Expected a directory\n");
+ put_inode(inode);
+ inode = NULL;
+ break;
+ }
+ }
+err_curdir:
+ free(path);
+err_path:
+ if (!inode) {
+ dprintf("searchdir: Not found\n");
goto err;
+ }
file->inode = inode;
file->offset = 0;
@@ -360,16 +411,12 @@ int searchdir(const char *name)
err:
dprintf("serachdir: error seraching file %s\n", name);
- put_inode(inode);
- put_inode(parent);
- if (pathbuf)
- free(pathbuf);
_close_file(file);
err_no_close:
return -1;
}
-int open_file(const char *name, struct com32_filedata *filedata)
+__export int open_file(const char *name, struct com32_filedata *filedata)
{
int rv;
struct file *file;
@@ -419,7 +466,7 @@ void pm_open_file(com32sys_t *regs)
}
}
-void close_file(uint16_t handle)
+__export void close_file(uint16_t handle)
{
struct file *file;
diff --git a/core/fs/getcwd.c b/core/fs/getcwd.c
index ee62411f..70b93152 100644
--- a/core/fs/getcwd.c
+++ b/core/fs/getcwd.c
@@ -1,7 +1,7 @@
#include <string.h>
#include "fs.h"
-char *core_getcwd(char *buf, size_t size)
+__export char *core_getcwd(char *buf, size_t size)
{
char *ret = NULL;
diff --git a/core/fs/lib/searchconfig.c b/core/fs/lib/searchconfig.c
index f2d740b3..b2a964e8 100644
--- a/core/fs/lib/searchconfig.c
+++ b/core/fs/lib/searchconfig.c
@@ -4,8 +4,8 @@
#include <core.h>
#include <fs.h>
-char ConfigName[FILENAME_MAX];
-char config_cwd[FILENAME_MAX];
+__export char ConfigName[FILENAME_MAX];
+__export char config_cwd[FILENAME_MAX];
/*
* This searches for a specified set of filenames in a specified set
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c
index 6f490ce8..11270044 100644
--- a/core/fs/pxe/pxe.c
+++ b/core/fs/pxe/pxe.c
@@ -2,6 +2,7 @@
#include <stdio.h>
#include <string.h>
#include <core.h>
+#include <bios.h>
#include <fs.h>
#include <minmax.h>
#include <sys/cpu.h>
@@ -796,8 +797,10 @@ static void __pxe_searchdir(const char *filename, struct file *file)
sendreq:
timeout = *timeout_ptr++;
- if (!timeout)
+ if (!timeout) {
+ free_socket(inode);
return; /* No file available... */
+ }
oldtime = jiffies();
socket->tftp_remoteip = ip;
@@ -1268,9 +1271,9 @@ static const void *memory_scan(uintptr_t start, int (*func)(const void *))
static const struct pxe_t *memory_scan_for_pxe_struct(void)
{
- extern uint16_t BIOS_fbm; /* Starting segment */
+ uint16_t start = bios_fbm(); /* Starting segment */
- return memory_scan(BIOS_fbm << 10, is_pxe);
+ return memory_scan(start << 10, is_pxe);
}
static const struct pxenv_t *memory_scan_for_pxenv_struct(void)
@@ -1675,11 +1678,11 @@ void unload_pxe(uint16_t flags)
uint16_t Status; /* All calls have this as the first member */
} unload_call;
- dprintf("FBM before unload = %d\n", BIOS_fbm);
+ dprintf("FBM before unload = %d\n", bios_fbm());
err = reset_pxe();
- dprintf("FBM after reset_pxe = %d, err = %d\n", BIOS_fbm, err);
+ dprintf("FBM after reset_pxe = %d, err = %d\n", bios_fbm(), err);
/* If we want to keep PXE around, we still need to reset it */
if (flags || err)
@@ -1699,8 +1702,8 @@ void unload_pxe(uint16_t flags)
}
api = 0xff00;
- if (real_base_mem <= BIOS_fbm) { /* Sanity check */
- dprintf("FBM %d < real_base_mem %d\n", BIOS_fbm, real_base_mem);
+ if (real_base_mem <= bios_fbm()) { /* Sanity check */
+ dprintf("FBM %d < real_base_mem %d\n", bios_fbm(), real_base_mem);
goto cant_free;
}
api++;
@@ -1708,20 +1711,20 @@ void unload_pxe(uint16_t flags)
/* Check that PXE actually unhooked the INT 0x1A chain */
int_addr = (size_t)GET_PTR(*(far_ptr_t *)(4 * 0x1a));
int_addr >>= 10;
- if (int_addr >= real_base_mem || int_addr < BIOS_fbm) {
- BIOS_fbm = real_base_mem;
- dprintf("FBM after unload_pxe = %d\n", BIOS_fbm);
+ if (int_addr >= real_base_mem || int_addr < bios_fbm()) {
+ set_bios_fbm(real_base_mem);
+ dprintf("FBM after unload_pxe = %d\n", bios_fbm());
return;
}
dprintf("Can't free FBM, real_base_mem = %d, "
"FBM = %d, INT 1A = %08x (%d)\n",
- real_base_mem, BIOS_fbm,
+ real_base_mem, bios_fbm(),
*(uint32_t *)(4 * 0x1a), int_addr);
cant_free:
printf("Failed to free base memory error %04x-%08x (%d/%dK)\n",
- api, *(uint32_t *)(4 * 0x1a), BIOS_fbm, real_base_mem);
+ api, *(uint32_t *)(4 * 0x1a), bios_fbm(), real_base_mem);
return;
}
diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h
index 99a2cf25..3439dd6a 100644
--- a/core/fs/pxe/pxe.h
+++ b/core/fs/pxe/pxe.h
@@ -201,7 +201,6 @@ extern bool have_uuid;
extern uint8_t uuid_type;
extern uint8_t uuid[];
-extern uint16_t BIOS_fbm;
extern const uint8_t TimeoutTable[];
/*
diff --git a/core/fs/readdir.c b/core/fs/readdir.c
index d071affd..e2d593fc 100644
--- a/core/fs/readdir.c
+++ b/core/fs/readdir.c
@@ -7,7 +7,7 @@
/*
* Open a directory
*/
-DIR *opendir(const char *path)
+__export DIR *opendir(const char *path)
{
int rv;
struct file *file;
@@ -29,7 +29,7 @@ DIR *opendir(const char *path)
/*
* Read one directory entry at one time.
*/
-struct dirent *readdir(DIR *dir)
+__export struct dirent *readdir(DIR *dir)
{
static struct dirent buf;
struct file *dd_dir = (struct file *)dir;
@@ -47,7 +47,7 @@ struct dirent *readdir(DIR *dir)
/*
* Close a directory
*/
-int closedir(DIR *dir)
+__export int closedir(DIR *dir)
{
struct file *dd_dir = (struct file *)dir;
_close_file(dd_dir);
diff --git a/core/fs/xfs/misc.h b/core/fs/xfs/misc.h
new file mode 100644
index 00000000..7f2f1b33
--- /dev/null
+++ b/core/fs/xfs/misc.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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 the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MISC_H_
+#define MISC_H_
+
+/* Return a 64-bit litte-endian value from a given 64-bit big-endian one */
+static inline uint64_t be64_to_cpu(uint64_t val)
+{
+ return (uint64_t)((((uint64_t)val & (uint64_t)0x00000000000000ffULL) << 56) |
+ (((uint64_t)val & (uint64_t)0x000000000000ff00ULL) << 40) |
+ (((uint64_t)val & (uint64_t)0x0000000000ff0000ULL) << 24) |
+ (((uint64_t)val & (uint64_t)0x00000000ff000000ULL) << 8) |
+ (((uint64_t)val & (uint64_t)0x000000ff00000000ULL) >> 8) |
+ (((uint64_t)val & (uint64_t)0x0000ff0000000000ULL) >> 24) |
+ (((uint64_t)val & (uint64_t)0x00ff000000000000ULL) >> 40) |
+ (((uint64_t)val & (uint64_t)0xff00000000000000ULL) >> 56));
+}
+
+/* Return a 32-bit litte-endian value from a given 32-bit big-endian one */
+static inline uint32_t be32_to_cpu(uint32_t val)
+{
+ return (uint32_t)((((uint32_t)val & (uint32_t)0x000000ffUL) << 24) |
+ (((uint32_t)val & (uint32_t)0x0000ff00UL) << 8) |
+ (((uint32_t)val & (uint32_t)0x00ff0000UL) >> 8) |
+ (((uint32_t)val & (uint32_t)0xff000000UL) >> 24));
+}
+
+/* Return a 16-bit litte-endian value from a given 16-bit big-endian one */
+static inline uint16_t be16_to_cpu(uint16_t val)
+{
+ return (uint16_t)((((uint16_t)val & (uint16_t)0x00ffU) << 8) |
+ (((uint16_t)val & (uint16_t)0xff00U) >> 8));
+}
+
+#endif /* MISC_H_ */
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
new file mode 100644
index 00000000..89a9aef2
--- /dev/null
+++ b/core/fs/xfs/xfs.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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 the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <cache.h>
+#include <core.h>
+#include <disk.h>
+#include <fs.h>
+#include <ilog2.h>
+#include <klibc/compiler.h>
+#include <ctype.h>
+
+#include "codepage.h"
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+#include "xfs_dinode.h"
+#include "xfs_dir2.h"
+#include "xfs_readdir.h"
+
+static inline int xfs_fmt_local_readdir(struct file *file,
+ struct dirent *dirent, xfs_dinode_t *core)
+{
+ return xfs_readdir_dir2_block(file, dirent, core);
+}
+
+static inline int xfs_fmt_extents_readdir(struct file *file,
+ struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ int retval;
+
+ if (be32_to_cpu(core->di_nextents) <= 1) {
+ /* Single-block Directories */
+ retval = xfs_readdir_dir2_block(file, dirent, core);
+ } else if (xfs_dir2_isleaf(file->fs, core)) {
+ /* Leaf Directory */
+ retval = xfs_readdir_dir2_leaf(file, dirent, core);
+ } else {
+ /* Node Directory */
+ retval = xfs_readdir_dir2_node(file, dirent, core);
+ }
+
+ return retval;
+}
+
+static int xfs_readdir(struct file *file, struct dirent *dirent)
+{
+ struct fs_info *fs = file->fs;
+ xfs_dinode_t *core;
+ struct inode *inode = file->inode;
+ int retval = -1;
+
+ core = xfs_dinode_get_core(fs, inode->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino %llx)", inode->ino);
+ return -1;
+ }
+
+ if (core->di_format == XFS_DINODE_FMT_LOCAL)
+ retval = xfs_fmt_local_readdir(file, dirent, core);
+ else if (core->di_format == XFS_DINODE_FMT_EXTENTS)
+ retval = xfs_fmt_extents_readdir(file, dirent, core);
+
+ return retval;
+}
+
+static uint32_t xfs_getfssec(struct file *file, char *buf, int sectors,
+ bool *have_more)
+{
+ return generic_getfssec(file, buf, sectors, have_more);
+}
+
+static int xfs_next_extent(struct inode *inode, uint32_t lstart)
+{
+ struct fs_info *fs = inode->fs;
+ xfs_dinode_t *core = NULL;
+ xfs_bmbt_irec_t rec;
+ block_t bno;
+ xfs_bmdr_block_t *rblock;
+ int fsize;
+ xfs_bmbt_ptr_t *pp;
+ xfs_btree_block_t *blk;
+ uint16_t nextents;
+ block_t nextbno;
+ uint32_t index;
+
+ (void)lstart;
+
+ core = xfs_dinode_get_core(fs, inode->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino %llx)", inode->ino);
+ goto out;
+ }
+
+ /* The data fork contains the file's data extents */
+ if (XFS_PVT(inode)->i_cur_extent == be32_to_cpu(core->di_nextents))
+ goto out;
+
+ if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
+ XFS_PVT(inode)->i_cur_extent++);
+
+ bno = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
+
+ XFS_PVT(inode)->i_offset = rec.br_startoff;
+
+ inode->next_extent.pstart = bno << BLOCK_SHIFT(fs) >> SECTOR_SHIFT(fs);
+ inode->next_extent.len = ((rec.br_blockcount << BLOCK_SHIFT(fs)) +
+ SECTOR_SIZE(fs) - 1) >> SECTOR_SHIFT(fs);
+ } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+ xfs_debug("XFS_DINODE_FMT_BTREE");
+ index = XFS_PVT(inode)->i_cur_extent++;
+ rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0];
+ fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK);
+ pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
+ bno = fsblock_to_bytes(fs, be64_to_cpu(pp[0])) >> BLOCK_SHIFT(fs);
+
+ /* Find the leaf */
+ for (;;) {
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ if (be16_to_cpu(blk->bb_level) == 0)
+ break;
+
+ pp = XFS_BMBT_PTR_ADDR(fs, blk, 1,
+ xfs_bmdr_maxrecs(XFS_INFO(fs)->blocksize, 0));
+ bno = fsblock_to_bytes(fs, be64_to_cpu(pp[0])) >> BLOCK_SHIFT(fs);
+ }
+
+ /* Find the right extent among threaded leaves */
+ for (;;) {
+ nextbno = be64_to_cpu(blk->bb_u.l.bb_rightsib);
+ nextents = be16_to_cpu(blk->bb_numrecs);
+ if (nextents - index > 0) {
+ bmbt_irec_get(&rec, XFS_BMDR_REC_ADDR(blk, index + 1));
+
+ bno = fsblock_to_bytes(fs, rec.br_startblock)
+ >> BLOCK_SHIFT(fs);
+
+ XFS_PVT(inode)->i_offset = rec.br_startoff;
+
+ inode->next_extent.pstart = bno << BLOCK_SHIFT(fs)
+ >> SECTOR_SHIFT(fs);
+ inode->next_extent.len = ((rec.br_blockcount
+ << BLOCK_SHIFT(fs))
+ + SECTOR_SIZE(fs) - 1)
+ >> SECTOR_SHIFT(fs);
+ break;
+ }
+
+ index -= nextents;
+ bno = fsblock_to_bytes(fs, nextbno) >> BLOCK_SHIFT(fs);
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ }
+ }
+
+ return 0;
+
+out:
+ return -1;
+}
+
+static inline struct inode *xfs_fmt_local_find_entry(const char *dname,
+ struct inode *parent,
+ xfs_dinode_t *core)
+{
+ return xfs_dir2_local_find_entry(dname, parent, core);
+}
+
+static inline struct inode *xfs_fmt_extents_find_entry(const char *dname,
+ struct inode *parent,
+ xfs_dinode_t *core)
+{
+ struct inode *inode;
+
+ if (be32_to_cpu(core->di_nextents) <= 1) {
+ /* Single-block Directories */
+ inode = xfs_dir2_block_find_entry(dname, parent, core);
+ } else if (xfs_dir2_isleaf(parent->fs, core)) {
+ /* Leaf Directory */
+ inode = xfs_dir2_leaf_find_entry(dname, parent, core);
+ } else {
+ /* Node Directory */
+ inode = xfs_dir2_node_find_entry(dname, parent, core);
+ }
+
+ return inode;
+}
+
+static inline struct inode *xfs_fmt_btree_find_entry(const char *dname,
+ struct inode *parent,
+ xfs_dinode_t *core)
+{
+ return xfs_dir2_node_find_entry(dname, parent, core);
+}
+
+static struct inode *xfs_iget(const char *dname, struct inode *parent)
+{
+ struct fs_info *fs = parent->fs;
+ xfs_dinode_t *core = NULL;
+ struct inode *inode = NULL;
+
+ xfs_debug("dname %s parent %p parent ino %lu", dname, parent, parent->ino);
+
+ core = xfs_dinode_get_core(fs, parent->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino 0x%llx)", parent->ino);
+ goto out;
+ }
+
+ if (core->di_format == XFS_DINODE_FMT_LOCAL) {
+ inode = xfs_fmt_local_find_entry(dname, parent, core);
+ } else if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ inode = xfs_fmt_extents_find_entry(dname, parent, core);
+ } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+ inode = xfs_fmt_btree_find_entry(dname, parent, core);
+ } else {
+ xfs_debug("format %hhu", core->di_format);
+ xfs_debug("TODO: format \"local\" and \"extents\" are the only "
+ "supported ATM");
+ goto out;
+ }
+
+ if (!inode) {
+ xfs_debug("Entry not found!");
+ goto out;
+ }
+
+ if (inode->mode == DT_REG) {
+ XFS_PVT(inode)->i_offset = 0;
+ XFS_PVT(inode)->i_cur_extent = 0;
+ } else if (inode->mode == DT_DIR) {
+ XFS_PVT(inode)->i_btree_offset = 0;
+ XFS_PVT(inode)->i_leaf_ent_offset = 0;
+ }
+
+ return inode;
+
+out:
+ return NULL;
+}
+
+static int xfs_readlink(struct inode *inode, char *buf)
+{
+ struct fs_info *fs = inode->fs;
+ xfs_dinode_t *core;
+ int pathlen = -1;
+ xfs_bmbt_irec_t rec;
+ block_t db;
+ char *dir_buf;
+
+ core = xfs_dinode_get_core(fs, inode->ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino 0x%llx)", inode->ino);
+ goto out;
+ }
+
+ pathlen = be64_to_cpu(core->di_size);
+ if (!pathlen)
+ goto out;
+
+ if (pathlen < 0 || pathlen > MAXPATHLEN) {
+ xfs_error("inode (%llu) bad symlink length (%d)",
+ inode->ino, pathlen);
+ goto out;
+ }
+
+ if (core->di_format == XFS_DINODE_FMT_LOCAL) {
+ memcpy(buf, (char *)&core->di_literal_area[0], pathlen);
+ } else if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ db = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
+ dir_buf = xfs_dir2_get_dirblks(fs, db, rec.br_blockcount);
+
+ /*
+ * Syslinux only supports filesystem block size larger than or equal to
+ * 4 KiB. Thus, one directory block is far enough to hold the maximum
+ * symbolic link file content, which is only 1024 bytes long.
+ */
+ memcpy(buf, dir_buf, pathlen);
+ free(dir_buf);
+ }
+
+out:
+ return pathlen;
+}
+
+static struct inode *xfs_iget_root(struct fs_info *fs)
+{
+ xfs_dinode_t *core = NULL;
+ struct inode *inode = xfs_new_inode(fs);
+
+ xfs_debug("Looking for the root inode...");
+
+ core = xfs_dinode_get_core(fs, XFS_INFO(fs)->rootino);
+ if (!core) {
+ xfs_error("Inode core's magic number does not match!");
+ xfs_debug("magic number 0x%04x", be16_to_cpu(core->di_magic));
+ goto out;
+ }
+
+ fill_xfs_inode_pvt(fs, inode, XFS_INFO(fs)->rootino);
+
+ xfs_debug("Root inode has been found!");
+
+ if ((be16_to_cpu(core->di_mode) & S_IFMT) != S_IFDIR) {
+ xfs_error("root inode is not a directory ?! No makes sense...");
+ goto out;
+ }
+
+ inode->ino = XFS_INFO(fs)->rootino;
+ inode->mode = DT_DIR;
+ inode->size = be64_to_cpu(core->di_size);
+
+ return inode;
+
+out:
+ free(inode);
+
+ return NULL;
+}
+
+static inline int xfs_read_superblock(struct fs_info *fs, xfs_sb_t *sb)
+{
+ struct disk *disk = fs->fs_dev->disk;
+
+ if (!disk->rdwr_sectors(disk, sb, XFS_SB_DADDR, 1, false))
+ return -1;
+
+ return 0;
+}
+
+static struct xfs_fs_info *xfs_new_sb_info(xfs_sb_t *sb)
+{
+ struct xfs_fs_info *info;
+
+ info = malloc(sizeof *info);
+ if (!info)
+ malloc_error("xfs_fs_info structure");
+
+ info->blocksize = be32_to_cpu(sb->sb_blocksize);
+ info->block_shift = sb->sb_blocklog;
+ info->dirblksize = 1 << (sb->sb_blocklog + sb->sb_dirblklog);
+ info->dirblklog = sb->sb_dirblklog;
+ info->inopb_shift = sb->sb_inopblog;
+ info->agblk_shift = sb->sb_agblklog;
+ info->rootino = be64_to_cpu(sb->sb_rootino);
+ info->agblocks = be32_to_cpu(sb->sb_agblocks);
+ info->agblocks_shift = sb->sb_agblklog;
+ info->agcount = be32_to_cpu(sb->sb_agcount);
+ info->inodesize = be16_to_cpu(sb->sb_inodesize);
+ info->inode_shift = sb->sb_inodelog;
+
+ return info;
+}
+
+static int xfs_fs_init(struct fs_info *fs)
+{
+ struct disk *disk = fs->fs_dev->disk;
+ xfs_sb_t sb;
+ struct xfs_fs_info *info;
+
+ xfs_debug("fs %p", fs);
+
+ SECTOR_SHIFT(fs) = disk->sector_shift;
+ SECTOR_SIZE(fs) = 1 << SECTOR_SHIFT(fs);
+
+ if (xfs_read_superblock(fs, &sb)) {
+ xfs_error("Superblock read failed");
+ goto out;
+ }
+
+ if (!xfs_is_valid_magicnum(&sb)) {
+ xfs_error("Invalid superblock");
+ goto out;
+ }
+
+ xfs_debug("magicnum 0x%lX", be32_to_cpu(sb.sb_magicnum));
+
+ info = xfs_new_sb_info(&sb);
+ if (!info) {
+ xfs_error("Failed to fill in filesystem-specific info structure");
+ goto out;
+ }
+
+ fs->fs_info = info;
+
+ xfs_debug("block_shift %u blocksize 0x%lX (%lu)", info->block_shift,
+ info->blocksize, info->blocksize);
+
+ xfs_debug("rootino 0x%llX (%llu)", info->rootino, info->rootino);
+
+ BLOCK_SHIFT(fs) = info->block_shift;
+ BLOCK_SIZE(fs) = info->blocksize;
+
+ cache_init(fs->fs_dev, BLOCK_SHIFT(fs));
+
+ XFS_INFO(fs)->dirleafblk = xfs_dir2_db_to_da(fs, XFS_DIR2_LEAF_FIRSTDB(fs));
+
+ return BLOCK_SHIFT(fs);
+
+out:
+ return -1;
+}
+
+const struct fs_ops xfs_fs_ops = {
+ .fs_name = "xfs",
+ .fs_flags = FS_USEMEM | FS_THISIND,
+ .fs_init = xfs_fs_init,
+ .iget_root = xfs_iget_root,
+ .searchdir = NULL,
+ .getfssec = xfs_getfssec,
+ .open_config = generic_open_config,
+ .close_file = generic_close_file,
+ .mangle_name = generic_mangle_name,
+ .readdir = xfs_readdir,
+ .iget = xfs_iget,
+ .next_extent = xfs_next_extent,
+ .readlink = xfs_readlink,
+};
diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h
new file mode 100644
index 00000000..da57221a
--- /dev/null
+++ b/core/fs/xfs/xfs.h
@@ -0,0 +1,752 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * Some parts borrowed from Linux kernel tree (linux/fs/xfs):
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * 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 the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_H_
+#define XFS_H_
+
+#include <disk.h>
+#include <fs.h>
+#include <dprintf.h>
+
+#include "xfs_types.h"
+#include "xfs_ag.h"
+
+#define xfs_error(fmt, args...) \
+ printf("xfs: " fmt "\n", ## args);
+
+#define xfs_debug(fmt, args...) \
+ dprintf("%s: " fmt "\n", __func__, ## args);
+
+struct xfs_fs_info;
+
+#define XFS_INFO(fs) ((struct xfs_fs_info *)((fs)->fs_info))
+#define XFS_PVT(ino) ((struct xfs_inode *)((ino)->pvt))
+
+#define XFS_INO_MASK(k) (uint32_t)((1ULL << (k)) - 1)
+#define XFS_INO_OFFSET_BITS(fs) (fs)->inopb_shift
+#define XFS_INO_AGINO_BITS(fs) \
+ (XFS_INFO((fs))->inopb_shift + XFS_INFO((fs))->agblk_shift)
+
+#define XFS_INO_TO_AGINO(fs, i) \
+ ((xfs_agino_t)(i) & XFS_INO_MASK(XFS_INO_AGINO_BITS(fs)))
+
+#define XFS_INO_TO_AGNO(fs, ino) \
+ ((xfs_agnumber_t)((ino) >> (XFS_INFO((fs))->inopb_shift + \
+ XFS_INFO((fs))->agblk_shift)))
+
+#define XFS_INO_TO_OFFSET(fs, i) \
+ ((int)(i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(fs)))
+
+#define XFS_AGNO_TO_FSB(fs, agno) \
+ ((block_t)((agno) << XFS_INFO((fs))->agblocks_shift))
+
+#define XFS_AGI_OFFS(fs, mp) \
+ ((xfs_agi_t *)((uint8_t *)(mp) + 2 * SECTOR_SIZE((fs))))
+
+#define XFS_GET_DIR_INO4(di) \
+ (((uint32_t)(di).i[0] << 24) | ((di).i[1] << 16) | ((di).i[2] << 8) | \
+ ((di).i[3]))
+
+#define XFS_DI_HI(di) \
+ (((uint32_t)(di).i[1] << 16) | ((di).i[2] << 8) | ((di).i[3]))
+
+#define XFS_DI_LO(di) \
+ (((uint32_t)(di).i[4] << 24) | ((di).i[5] << 16) | ((di).i[6] << 8) | \
+ ((di).i[7]))
+
+#define XFS_GET_DIR_INO8(di) \
+ (((xfs_ino_t)XFS_DI_LO(di) & 0xffffffffULL) | \
+ ((xfs_ino_t)XFS_DI_HI(di) << 32))
+
+#define XFS_FSB_TO_AGNO(fs, fsbno) \
+ ((xfs_agnumber_t)((fsbno) >> XFS_INFO((fs))->agblk_shift))
+#define XFS_FSB_TO_AGBNO(fs, fsbno) \
+ ((xfs_agblock_t)((fsbno) & (uint32_t)((1ULL << \
+ XFS_INFO((fs))->agblk_shift) - 1)))
+
+#define agblock_to_bytes(fs, x) \
+ ((uint64_t)(x) << BLOCK_SHIFT((fs)))
+#define agino_to_bytes(fs, x) \
+ ((uint64_t)(x) << XFS_INFO((fs))->inode_shift)
+#define agnumber_to_bytes(fs, x) \
+ agblock_to_bytes(fs, (uint64_t)(x) * XFS_INFO((fs))->agblocks)
+#define fsblock_to_bytes(fs,x) \
+ (agnumber_to_bytes(fs, XFS_FSB_TO_AGNO(fs, (x))) + \
+ agblock_to_bytes(fs, XFS_FSB_TO_AGBNO(fs, (x))))
+#define ino_to_bytes(fs, x) \
+ (agnumber_to_bytes(fs, XFS_INO_TO_AGNO(fs, (x))) + \
+ agino_to_bytes(fs, XFS_INO_TO_AGINO(fs, (x))))
+
+/* Superblock's LBA */
+#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */
+
+/* Magic numbers */
+#define XFS_AGI_MAGIC "XAGI"
+#define XFS_IBT_MAGIC "IABT"
+#define XFS_DINODE_MAGIC "IN"
+
+#define XFS_DIR2_BLOCK_MAGIC 0x58443242U /* XD2B: single block dirs */
+#define XFS_DIR2_DATA_MAGIC 0x58443244U /* XD2D: multiblock dirs */
+#define XFS_DIR2_FREE_MAGIC 0x58443246U /* XD2F: free index blocks */
+
+#define XFS_DIR2_NULL_DATAPTR ((uint32_t)0)
+
+/* File types and modes */
+#define S_IFMT 00170000
+#define S_IFSOCK 0140000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFBLK 0060000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+#define MAXPATHLEN 1024
+/*
+ * NOTE: The fields in the superblock are stored in big-endian format on disk.
+ */
+typedef struct xfs_sb {
+ uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */
+ uint32_t sb_blocksize; /* logical block size, bytes */
+ xfs_drfsbno_t sb_dblocks; /* number of data blocks */
+ xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */
+ xfs_drtbno_t sb_rextents; /* number of realtime extents */
+ uuid_t sb_uuid; /* file system unique id */
+ xfs_dfsbno_t sb_logstart; /* starting block of log if internal */
+ xfs_ino_t sb_rootino; /* root inode number */
+ xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */
+ xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */
+ xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */
+ xfs_agblock_t sb_agblocks; /* size of an allocation group */
+ xfs_agnumber_t sb_agcount; /* number of allocation groups */
+ xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */
+ xfs_extlen_t sb_logblocks; /* number of log blocks */
+ uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */
+ uint16_t sb_sectsize; /* volume sector size, bytes */
+ uint16_t sb_inodesize; /* inode size, bytes */
+ uint16_t sb_inopblock; /* inodes per block */
+ char sb_fname[12]; /* file system name */
+ uint8_t sb_blocklog; /* log2 of sb_blocksize */
+ uint8_t sb_sectlog; /* log2 of sb_sectsize */
+ uint8_t sb_inodelog; /* log2 of sb_inodesize */
+ uint8_t sb_inopblog; /* log2 of sb_inopblock */
+ uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */
+ uint8_t sb_rextslog; /* log2 of sb_rextents */
+ uint8_t sb_inprogress; /* mkfs is in progress, don't mount */
+ uint8_t sb_imax_pct; /* max % of fs for inode space */
+ /* statistics */
+ /*
+ * These fields must remain contiguous. If you really
+ * want to change their layout, make sure you fix the
+ * code in xfs_trans_apply_sb_deltas().
+ */
+ uint64_t sb_icount; /* allocated inodes */
+ uint64_t sb_ifree; /* free inodes */
+ uint64_t sb_fdblocks; /* free data blocks */
+ uint64_t sb_frextents; /* free realtime extents */
+ /*
+ * End contiguous fields.
+ */
+ xfs_ino_t sb_uquotino; /* user quota inode */
+ xfs_ino_t sb_gquotino; /* group quota inode */
+ uint16_t sb_qflags; /* quota flags */
+ uint8_t sb_flags; /* misc. flags */
+ uint8_t sb_shared_vn; /* shared version number */
+ xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */
+ uint32_t sb_unit; /* stripe or raid unit */
+ uint32_t sb_width; /* stripe or raid width */
+ uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */
+ uint8_t sb_logsectlog; /* log2 of the log sector size */
+ uint16_t sb_logsectsize; /* sector size for the log, bytes */
+ uint32_t sb_logsunit; /* stripe unit size for the log */
+ uint32_t sb_features2; /* additional feature bits */
+
+ /*
+ * bad features2 field as a result of failing to pad the sb
+ * structure to 64 bits. Some machines will be using this field
+ * for features2 bits. Easiest just to mark it bad and not use
+ * it for anything else.
+ */
+ uint32_t sb_bad_features2;
+ uint8_t pad[304]; /* must be padded to a sector boundary */
+} __attribute__((__packed__)) xfs_sb_t;
+
+/* In-memory structure that stores filesystem-specific information.
+ * The information stored is basically retrieved from the XFS superblock
+ * to be used statically around the driver.
+ */
+struct xfs_fs_info {
+ uint32_t blocksize; /* Filesystem block size */
+ uint8_t block_shift; /* Filesystem block size in bits */
+ uint32_t dirblksize;
+ uint8_t dirblklog;
+ uint8_t inopb_shift;
+ uint8_t agblk_shift;
+ uint32_t dirleafblk;
+
+ /* AG number bits (MSB of the inode number) */
+ uint8_t ag_number_ino_shift;
+
+ xfs_ino_t rootino; /* Root inode number for the filesystem */
+ xfs_agblock_t agblocks; /* Size of each AG in blocks */
+ uint8_t agblocks_shift; /* agblocks in bits */
+ xfs_agnumber_t agcount; /* Number of AGs in the filesytem */
+ uint16_t inodesize; /* Size of the inode in bytes */
+ uint8_t inode_shift; /* Inode size in bits */
+} __attribute__((__packed__));
+
+typedef struct xfs_agi {
+ /*
+ * Common allocation group header information
+ */
+ uint32_t agi_magicnum; /* magic number == XFS_AGI_MAGIC */
+ uint32_t agi_versionnum; /* header version == XFS_AGI_VERSION */
+ uint32_t agi_seqno; /* sequence # starting from 0 */
+ uint32_t agi_length; /* size in blocks of a.g. */
+ /*
+ * Inode information
+ * Inodes are mapped by interpreting the inode number, so no
+ * mapping data is needed here.
+ */
+ uint32_t agi_count; /* count of allocated inodes */
+ uint32_t agi_root; /* root of inode btree */
+ uint32_t agi_level; /* levels in inode btree */
+ uint32_t agi_freecount; /* number of free inodes */
+ uint32_t agi_newino; /* new inode just allocated */
+ uint32_t agi_dirino; /* last directory inode chunk */
+ /*
+ * Hash table of inodes which have been unlinked but are
+ * still being referenced.
+ */
+ uint32_t agi_unlinked[XFS_AGI_UNLINKED_BUCKETS];
+} __attribute__((__packed__)) xfs_agi_t;
+
+/*
+ * Bmap btree record and extent descriptor.
+ * l0:63 is an extent flag (value 1 indicates non-normal).
+ * l0:9-62 are startoff.
+ * l0:0-8 and l1:21-63 are startblock.
+ * l1:0-20 are blockcount.
+ */
+typedef struct xfs_bmbt_rec {
+ uint64_t l0;
+ uint64_t l1;
+} __attribute__((__packed__)) xfs_bmbt_rec_t;
+
+typedef xfs_bmbt_rec_t xfs_bmdr_rec_t;
+
+/*
+ * Possible extent states.
+ */
+typedef enum {
+ XFS_EXT_NORM,
+ XFS_EXT_UNWRITTEN,
+ XFS_EXT_DMAPI_OFFLINE,
+ XFS_EXT_INVALID,
+} xfs_exntst_t;
+
+typedef struct xfs_bmbt_irec
+{
+ xfs_fileoff_t br_startoff; /* starting file offset */
+ xfs_fsblock_t br_startblock; /* starting block number */
+ xfs_filblks_t br_blockcount; /* number of blocks */
+ xfs_exntst_t br_state; /* extent state */
+} __attribute__((__packed__)) xfs_bmbt_irec_t;
+
+static inline void bmbt_irec_get(xfs_bmbt_irec_t *dest,
+ const xfs_bmbt_rec_t *src)
+{
+ uint64_t l0, l1;
+
+ l0 = be64_to_cpu(src->l0);
+ l1 = be64_to_cpu(src->l1);
+
+ dest->br_startoff = ((xfs_fileoff_t)l0 & 0x7ffffffffffffe00ULL) >> 9;
+ dest->br_startblock = (((xfs_fsblock_t)l0 & 0x00000000000001ffULL) << 43) |
+ (((xfs_fsblock_t)l1) >> 21);
+ dest->br_blockcount = (xfs_filblks_t)(l1 & 0x00000000001fffffULL);
+ dest->br_state = (l0 & 0x8000000000000000ULL) ?
+ XFS_EXT_UNWRITTEN : XFS_EXT_NORM;
+}
+
+typedef struct xfs_timestamp {
+ int32_t t_sec;
+ int32_t t_nsec;
+} __attribute__((__packed__)) xfs_timestamp_t;
+
+/*
+ * Fork identifiers.
+ */
+#define XFS_DATA_FORK 0
+#define xFS_ATTR_FORK 1
+
+typedef enum xfs_dinode_fmt {
+ XFS_DINODE_FMT_DEV,
+ XFS_DINODE_FMT_LOCAL,
+ XFS_DINODE_FMT_EXTENTS,
+ XFS_DINODE_FMT_BTREE,
+ XFS_DINODE_FMT_UUID,
+} xfs_dinode_fmt_t;
+
+typedef struct xfs_dinode {
+ uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */
+ uint16_t di_mode; /* mode and type of file */
+ uint8_t di_version; /* inode version */
+ uint8_t di_format; /* format of di_c data */
+ uint16_t di_onlink; /* old number of links to file */
+ uint32_t di_uid; /* owner's user id */
+ uint32_t di_gid; /* owner's group id */
+ uint32_t di_nlink; /* number of links to file */
+ uint16_t di_projid_lo; /* lower part of owner's project id */
+ uint16_t di_projid_hi; /* higher part owner's project id */
+ uint8_t di_pad[6]; /* unused, zeroed space */
+ uint16_t di_flushiter; /* incremented on flush */
+ xfs_timestamp_t di_atime; /* time last accessed */
+ xfs_timestamp_t di_mtime; /* time last modified */
+ xfs_timestamp_t di_ctime; /* time created/inode modified */
+ uint64_t di_size; /* number of bytes in file */
+ uint64_t di_nblocks; /* # of direct & btree blocks used */
+ uint32_t di_extsize; /* basic/minimum extent size for file */
+ uint32_t di_nextents; /* number of extents in data fork */
+ uint16_t di_anextents; /* number of extents in attribute fork*/
+ uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */
+ int8_t di_aformat; /* format of attr fork's data */
+ uint32_t di_dmevmask; /* DMIG event mask */
+ uint16_t di_dmstate; /* DMIG state info */
+ uint16_t di_flags; /* random flags, XFS_DIFLAG_... */
+ uint32_t di_gen; /* generation number */
+
+ /* di_next_unlinked is the only non-core field in the old dinode */
+ uint32_t di_next_unlinked;/* agi unlinked list ptr */
+ uint8_t di_literal_area[1];
+} __attribute__((packed)) xfs_dinode_t;
+
+/*
+ * Inode size for given fs.
+ */
+#define XFS_LITINO(fs) \
+ ((int)((XFS_INFO(fs)->inodesize) - sizeof(struct xfs_dinode) - 1))
+
+#define XFS_BROOT_SIZE_ADJ \
+ (XFS_BTREE_LBLOCK_LEN - sizeof(xfs_bmdr_block_t))
+
+/*
+ * Inode data & attribute fork sizes, per inode.
+ */
+#define XFS_DFORK_Q(dip) ((dip)->di_forkoff != 0)
+#define XFS_DFORK_BOFF(dip) ((int)((dip)->di_forkoff << 3))
+
+#define XFS_DFORK_DSIZE(dip, fs) \
+ (XFS_DFORK_Q(dip) ? \
+ XFS_DFORK_BOFF(dip) : \
+ XFS_LITINO(fs))
+#define XFS_DFORK_ASIZE(dip, fs) \
+ (XFS_DFORK_Q(dip) ? \
+ XFS_LITINO(fs) - XFS_DFORK_BOFF(dip) : \
+ 0)
+#define XFS_DFORK_SIZE(dip, fs, w) \
+ ((w) == XFS_DATA_FORK ? \
+ XFS_DFORK_DSIZE(dip, fs) : \
+ XFS_DFORK_ASIZE(dip, fs))
+
+struct xfs_inode {
+ xfs_agblock_t i_agblock;
+ block_t i_ino_blk;
+ uint64_t i_block_offset;
+ uint64_t i_offset;
+ uint32_t i_cur_extent;
+ uint32_t i_btree_offset;
+ uint16_t i_leaf_ent_offset;
+};
+
+typedef struct { uint8_t i[8]; } __attribute__((__packed__)) xfs_dir2_ino8_t;
+typedef struct { uint8_t i[4]; } __attribute__((__packed__)) xfs_dir2_ino4_t;
+
+typedef union {
+ xfs_dir2_ino8_t i8;
+ xfs_dir2_ino4_t i4;
+} __attribute__((__packed__)) xfs_dir2_inou_t;
+
+typedef struct { uint8_t i[2]; } __attribute__((__packed__)) xfs_dir2_sf_off_t;
+
+typedef struct xfs_dir2_sf_hdr {
+ uint8_t count; /* count of entries */
+ uint8_t i8count; /* count of 8-byte inode #s */
+ xfs_dir2_inou_t parent; /* parent dir inode number */
+} __attribute__((__packed__)) xfs_dir2_sf_hdr_t;
+
+typedef struct xfs_dir2_sf_entry {
+ uint8_t namelen; /* actual name length */
+ xfs_dir2_sf_off_t offset; /* saved offset */
+ uint8_t name[1]; /* name, variable size */
+ xfs_dir2_inou_t inumber; /* inode number, var. offset */
+} __attribute__((__packed__)) xfs_dir2_sf_entry_t;
+
+typedef struct xfs_dir2_sf {
+ xfs_dir2_sf_hdr_t hdr; /* shortform header */
+ xfs_dir2_sf_entry_t list[1]; /* shortform entries */
+} __attribute__((__packed__)) xfs_dir2_sf_t;
+
+typedef xfs_ino_t xfs_intino_t;
+
+static inline xfs_intino_t xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp,
+ xfs_dir2_inou_t *from)
+{
+ return ((sfp)->hdr.i8count == 0 ? \
+ (xfs_intino_t)XFS_GET_DIR_INO4((from)->i4) : \
+ (xfs_intino_t)XFS_GET_DIR_INO8((from)->i8));
+}
+
+/*
+ * DIR2 Data block structures.
+ *
+ * A pure data block looks like the following drawing on disk:
+ *
+ * +-------------------------------------------------+
+ * | xfs_dir2_data_hdr_t |
+ * +-------------------------------------------------+
+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ * | ... |
+ * +-------------------------------------------------+
+ * | unused space |
+ * +-------------------------------------------------+
+ *
+ * As all the entries are variable size structure the accessors below should
+ * be used to iterate over them.
+ *
+ * In addition to the pure data blocks for the data and node formats.
+ * most structures are also used for the combined data/freespace "block"
+ * format below.
+ */
+#define XFS_DIR2_DATA_ALIGN_LOG 3
+#define XFS_DIR2_DATA_ALIGN (1 << XFS_DIR2_DATA_ALIGN_LOG)
+#define XFS_DIR2_DATA_FREE_TAG 0xffff
+#define XFS_DIR2_DATA_FD_COUNT 3
+
+/*
+ * Directory address space divided into sections.
+ * spaces separated by 32GB.
+ */
+#define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG))
+
+typedef struct xfs_dir2_data_free {
+ uint16_t offset;
+ uint16_t length;
+} __attribute__((__packed__)) xfs_dir2_data_free_t;
+
+typedef struct xfs_dir2_data_hdr {
+ uint32_t magic;
+ xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT];
+} __attribute__((__packed__)) xfs_dir2_data_hdr_t;
+
+typedef struct xfs_dir2_data_entry {
+ uint64_t inumber; /* inode number */
+ uint8_t namelen; /* name length */
+ uint8_t name[]; /* name types, no null */
+ /* uint16_t tag; */ /* starting offset of us */
+} __attribute__((__packed__)) xfs_dir2_data_entry_t;
+
+typedef struct xfs_dir2_data_unused {
+ uint16_t freetag; /* XFS_DIR2_DATA_FREE_TAG */
+ uint16_t length; /* total free length */
+ /* variable offset */
+ /* uint16_t tag; */ /* starting offset of us */
+} __attribute__((__packed__)) xfs_dir2_data_unused_t;
+
+/**
+ * rol32 - rotate a 32-bit value left
+ * @word: value to rotate
+ * @shift: bits to roll
+ */
+static inline uint32_t rol32(uint32_t word, signed int shift)
+{
+ return (word << shift) | (word >> (32 - shift));
+}
+
+#define roundup(x, y) ( \
+{ \
+ const typeof(y) __y = y; \
+ (((x) + (__y - 1)) / __y) * __y; \
+} \
+)
+
+static inline int xfs_dir2_data_entsize(int n)
+{
+ return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n +
+ (unsigned int)sizeof(uint16_t), XFS_DIR2_DATA_ALIGN);
+}
+
+static inline uint16_t *
+xfs_dir2_data_entry_tag_p(struct xfs_dir2_data_entry *dep)
+{
+ return (uint16_t *)((char *)dep +
+ xfs_dir2_data_entsize(dep->namelen) - sizeof(uint16_t));
+}
+
+static inline uint16_t *
+xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup)
+{
+ return (uint16_t *)((char *)dup +
+ be16_to_cpu(dup->length) - sizeof(uint16_t));
+}
+
+typedef struct xfs_dir2_block_tail {
+ uint32_t count; /* count of leaf entries */
+ uint32_t stale; /* count of stale lf entries */
+} __attribute__((__packed__)) xfs_dir2_block_tail_t;
+
+static inline struct xfs_dir2_block_tail *
+xfs_dir2_block_tail_p(struct xfs_fs_info *fs_info, struct xfs_dir2_data_hdr *hdr)
+{
+ return ((struct xfs_dir2_block_tail *)
+ ((char *)hdr + fs_info->dirblksize)) - 1;
+}
+
+static inline uint32_t
+xfs_dir2_db_to_da(struct fs_info *fs, uint32_t db)
+{
+ return db << XFS_INFO(fs)->dirblklog;
+}
+
+static inline int64_t
+xfs_dir2_dataptr_to_byte(uint32_t dp)
+{
+ return (int64_t)dp << XFS_DIR2_DATA_ALIGN_LOG;
+}
+
+static inline uint32_t
+xfs_dir2_byte_to_db(struct fs_info *fs, int64_t by)
+{
+ return (uint32_t)
+ (by >> (XFS_INFO(fs)->block_shift + XFS_INFO(fs)->dirblklog));
+}
+
+static inline uint32_t
+xfs_dir2_dataptr_to_db(struct fs_info *fs, uint32_t dp)
+{
+ return xfs_dir2_byte_to_db(fs, xfs_dir2_dataptr_to_byte(dp));
+}
+
+static inline unsigned int
+xfs_dir2_byte_to_off(struct fs_info *fs, int64_t by)
+{
+ return (unsigned int)(by &
+ (( 1 << (XFS_INFO(fs)->block_shift + XFS_INFO(fs)->dirblklog)) - 1));
+}
+
+static inline unsigned int
+xfs_dir2_dataptr_to_off(struct fs_info *fs, uint32_t dp)
+{
+ return xfs_dir2_byte_to_off(fs, xfs_dir2_dataptr_to_byte(dp));
+}
+
+#define XFS_DIR2_LEAF_SPACE 1
+#define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE)
+#define XFS_DIR2_LEAF_FIRSTDB(fs) \
+ xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET)
+
+typedef struct xfs_da_blkinfo {
+ uint32_t forw;
+ uint32_t back;
+ uint16_t magic;
+ uint16_t pad;
+} __attribute__((__packed__)) xfs_da_blkinfo_t;
+
+typedef struct xfs_dir2_leaf_hdr {
+ xfs_da_blkinfo_t info;
+ uint16_t count;
+ uint16_t stale;
+} __attribute__((__packed__)) xfs_dir2_leaf_hdr_t;
+
+typedef struct xfs_dir2_leaf_entry {
+ uint32_t hashval; /* hash value of name */
+ uint32_t address; /* address of data entry */
+} __attribute__((__packed__)) xfs_dir2_leaf_entry_t;
+
+typedef struct xfs_dir2_leaf {
+ xfs_dir2_leaf_hdr_t hdr; /* leaf header */
+ xfs_dir2_leaf_entry_t ents[]; /* entries */
+} __attribute__((__packed__)) xfs_dir2_leaf_t;
+
+#define XFS_DA_NODE_MAGIC 0xfebeU /* magic number: non-leaf blocks */
+#define XFS_ATTR_LEAF_MAGIC 0xfbeeU /* magic number: attribute leaf blks */
+#define XFS_DIR2_LEAF1_MAGIC 0xd2f1U /* magic number: v2 dirlf single blks */
+#define XFS_DIR2_LEAFN_MAGIC 0xd2ffU /* magic number: V2 dirlf multi blks */
+
+typedef struct xfs_da_intnode {
+ struct xfs_da_node_hdr { /* constant-structure header block */
+ xfs_da_blkinfo_t info; /* block type, links, etc. */
+ uint16_t count; /* count of active entries */
+ uint16_t level; /* level above leaves (leaf == 0) */
+ } hdr;
+ struct xfs_da_node_entry {
+ uint32_t hashval; /* hash value for this descendant */
+ uint32_t before; /* Btree block before this key */
+ } btree[1];
+} __attribute__((__packed__)) xfs_da_intnode_t;
+
+typedef struct xfs_da_node_hdr xfs_da_node_hdr_t;
+typedef struct xfs_da_node_entry xfs_da_node_entry_t;
+
+static inline bool xfs_is_valid_magicnum(const xfs_sb_t *sb)
+{
+ return sb->sb_magicnum == *(uint32_t *)XFS_SB_MAGIC;
+}
+
+static inline bool xfs_is_valid_agi(xfs_agi_t *agi)
+{
+ return agi->agi_magicnum == *(uint32_t *)XFS_AGI_MAGIC;
+}
+
+static inline struct inode *xfs_new_inode(struct fs_info *fs)
+{
+ struct inode *inode;
+
+ inode = alloc_inode(fs, 0, sizeof(struct xfs_inode));
+ if (!inode)
+ malloc_error("xfs_inode structure");
+
+ return inode;
+}
+
+static inline void fill_xfs_inode_pvt(struct fs_info *fs, struct inode *inode,
+ xfs_ino_t ino)
+{
+ XFS_PVT(inode)->i_agblock =
+ agnumber_to_bytes(fs, XFS_INO_TO_AGNO(fs, ino)) >> BLOCK_SHIFT(fs);
+ XFS_PVT(inode)->i_ino_blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
+ XFS_PVT(inode)->i_block_offset = XFS_INO_TO_OFFSET(XFS_INFO(fs), ino) <<
+ XFS_INFO(fs)->inode_shift;
+}
+
+/*
+ * Generic btree header.
+ *
+ * This is a combination of the actual format used on disk for short and long
+ * format btrees. The first three fields are shared by both format, but
+ * the pointers are different and should be used with care.
+ *
+ * To get the size of the actual short or long form headers please use
+ * the size macros belows. Never use sizeof(xfs_btree_block);
+ */
+typedef struct xfs_btree_block {
+ uint32_t bb_magic; /* magic number for block type */
+ uint16_t bb_level; /* 0 is a leaf */
+ uint16_t bb_numrecs; /* current # of data records */
+ union {
+ struct {
+ uint32_t bb_leftsib;
+ uint32_t bb_rightsib;
+ } s; /* short form pointers */
+ struct {
+ uint64_t bb_leftsib;
+ uint64_t bb_rightsib;
+ } l; /* long form pointers */
+ } bb_u; /* rest */
+} xfs_btree_block_t;
+
+#define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */
+#define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */
+
+/*
+ * Bmap root header, on-disk form only.
+ */
+typedef struct xfs_bmdr_block {
+ uint16_t bb_level; /* 0 is a leaf */
+ uint16_t bb_numrecs; /* current # of data records */
+} xfs_bmdr_block_t;
+
+/*
+ * Key structure for non-leaf levels of the tree.
+ */
+typedef struct xfs_bmbt_key {
+ uint64_t br_startoff; /* starting file offset */
+} xfs_bmbt_key_t, xfs_bmdr_key_t;
+
+/* btree pointer type */
+typedef uint64_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
+
+/*
+ * Btree block header size depends on a superblock flag.
+ *
+ * (not quite yet, but soon)
+ */
+#define XFS_BMBT_BLOCK_LEN(fs) XFS_BTREE_LBLOCK_LEN
+
+#define XFS_BMBT_REC_ADDR(fs, block, index) \
+ ((xfs_bmbt_rec_t *) \
+ ((char *)(block) + \
+ XFS_BMBT_BLOCK_LEN(fs) + \
+ ((index) - 1) * sizeof(xfs_bmbt_rec_t)))
+
+#define XFS_BMBT_KEY_ADDR(fs, block, index) \
+ ((xfs_bmbt_key_t *) \
+ ((char *)(block) + \
+ XFS_BMBT_BLOCK_LEN(fs) + \
+ ((index) - 1) * sizeof(xfs_bmbt_key_t)))
+
+#define XFS_BMBT_PTR_ADDR(fs, block, index, maxrecs) \
+ ((xfs_bmbt_ptr_t *) \
+ ((char *)(block) + \
+ XFS_BMBT_BLOCK_LEN(fs) + \
+ (maxrecs) * sizeof(xfs_bmbt_key_t) + \
+ ((index) - 1) * sizeof(xfs_bmbt_ptr_t)))
+
+#define XFS_BMDR_REC_ADDR(block, index) \
+ ((xfs_bmdr_rec_t *) \
+ ((char *)(block) + \
+ sizeof(struct xfs_bmdr_block) + \
+ ((index) - 1) * sizeof(xfs_bmdr_rec_t)))
+
+#define XFS_BMDR_KEY_ADDR(block, index) \
+ ((xfs_bmdr_key_t *) \
+ ((char *)(block) + \
+ sizeof(struct xfs_bmdr_block) + \
+ ((index) - 1) * sizeof(xfs_bmdr_key_t)))
+
+#define XFS_BMDR_PTR_ADDR(block, index, maxrecs) \
+ ((xfs_bmdr_ptr_t *) \
+ ((char *)(block) + \
+ sizeof(struct xfs_bmdr_block) + \
+ (maxrecs) * sizeof(xfs_bmdr_key_t) + \
+ ((index) - 1) * sizeof(xfs_bmdr_ptr_t)))
+
+/*
+ * Calculate number of records in a bmap btree inode root.
+ */
+static inline int
+xfs_bmdr_maxrecs(int blocklen, int leaf)
+{
+ blocklen -= sizeof(xfs_bmdr_block_t);
+
+ if (leaf)
+ return blocklen / sizeof(xfs_bmdr_rec_t);
+
+ return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t));
+}
+
+#endif /* XFS_H_ */
diff --git a/core/fs/xfs/xfs_ag.h b/core/fs/xfs/xfs_ag.h
new file mode 100644
index 00000000..a2988b10
--- /dev/null
+++ b/core/fs/xfs/xfs_ag.h
@@ -0,0 +1,189 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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 the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_AG_H_
+#define XFS_AG_H_
+
+#include "xfs_types.h"
+
+/*
+ * Allocation group header
+ * This is divided into three structures, placed in sequential 512-byte
+ * buffers after a copy of the superblock (also in a 512-byte buffer).
+ */
+
+typedef uint32_t xfs_agino_t;
+
+struct xfs_buf;
+struct xfs_mount;
+struct xfs_trans;
+
+#define XFS_AGF_MAGIC "XAGF"
+#define XFS_AGF_VERSION 1
+#define XFS_AGI_VERSION 1
+
+#define XFS_AGF_GOOD_VERSION(v) ((v) == XFS_AGF_VERSION)
+#define XFS_AGI_GOOD_VERSION(v) ((v) == XFS_AGI_VERSION)
+
+/*
+ * Btree number 0 is bno, 1 is cnt. This value gives the size of the
+ * arrays below.
+ */
+#define XFS_BTNUM_AGF ((int)XFS_BTNUM_CNTi + 1)
+
+/*
+ * The second word of agf_levels in the first a.g. overlaps the EFS
+ * superblock's magic number. Since the magic numbers valid for EFS
+ * are > 64k, our value cannot be confused for an EFS superblock's.
+ */
+
+typedef struct xfs_agf {
+ /*
+ * Common allocation group header information
+ */
+ uint32_t agf_magicnum; /* magic number == XFS_AGF_MAGIC */
+ uint32_t agf_versionnum; /* header version == XFS_AGF_VERSION */
+ uint32_t agf_seqno; /* sequence # starting from 0 */
+ uint32_t agf_length; /* size in blocks of a.g. */
+ /*
+ * Freespace information
+ */
+ uint32_t agf_roots[XFS_BTNUM_AGF]; /* root blocks */
+ uint32_t agf_spare0; /* spare field */
+ uint32_t agf_levels[XFS_BTNUM_AGF]; /* btree levels */
+ uint32_t agf_spare1; /* spare field */
+ uint32_t agf_flfirst; /* first freelist block's index */
+ uint32_t agf_fllast; /* last freelist block's index */
+ uint32_t agf_flcount; /* count of blocks in freelist */
+ uint32_t agf_freeblks; /* total free blocks */
+ uint32_t agf_longest; /* longest free space */
+ uint32_t agf_btreeblks; /* # of blocks held in AGF btrees */
+} xfs_agf_t;
+
+#define XFS_AGF_MAGICNUM 0x00000001
+#define XFS_AGF_VERSIONNUM 0x00000002
+#define XFS_AGF_SEQNO 0x00000004
+#define XFS_AGF_LENGTH 0x00000008
+#define XFS_AGF_ROOTS 0x00000010
+#define XFS_AGF_LEVELS 0x00000020
+#define XFS_AGF_FLFIRST 0x00000040
+#define XFS_AGF_FLLAST 0x00000080
+#define XFS_AGF_FLCOUNT 0x00000100
+#define XFS_AGF_FREEBLKS 0x00000200
+#define XFS_AGF_LONGEST 0x00000400
+#define XFS_AGF_BTREEBLKS 0x00000800
+#define XFS_AGF_NUM_BITS 12
+#define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1)
+
+#define XFS_AGF_FLAGS \
+ { XFS_AGF_MAGICNUM, "MAGICNUM" }, \
+ { XFS_AGF_VERSIONNUM, "VERSIONNUM" }, \
+ { XFS_AGF_SEQNO, "SEQNO" }, \
+ { XFS_AGF_LENGTH, "LENGTH" }, \
+ { XFS_AGF_ROOTS, "ROOTS" }, \
+ { XFS_AGF_LEVELS, "LEVELS" }, \
+ { XFS_AGF_FLFIRST, "FLFIRST" }, \
+ { XFS_AGF_FLLAST, "FLLAST" }, \
+ { XFS_AGF_FLCOUNT, "FLCOUNT" }, \
+ { XFS_AGF_FREEBLKS, "FREEBLKS" }, \
+ { XFS_AGF_LONGEST, "LONGEST" }, \
+ { XFS_AGF_BTREEBLKS, "BTREEBLKS" }
+
+/* disk block (xfs_daddr_t) in the AG */
+#define XFS_AGF_DADDR(mp) ((xfs_daddr_t)(1 << (mp)->m_sectbb_log))
+#define XFS_AGF_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGF_DADDR(mp))
+#define XFS_BUF_TO_AGF(bp) ((xfs_agf_t *)((bp)->b_addr))
+
+extern int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp,
+ xfs_agnumber_t agno, int flags, struct xfs_buf **bpp);
+
+/*
+ * Size of the unlinked inode hash table in the agi.
+ */
+#define XFS_AGI_UNLINKED_BUCKETS 64
+
+#define XFS_AGI_MAGICNUM 0x00000001
+#define XFS_AGI_VERSIONNUM 0x00000002
+#define XFS_AGI_SEQNO 0x00000004
+#define XFS_AGI_LENGTH 0x00000008
+#define XFS_AGI_COUNT 0x00000010
+#define XFS_AGI_ROOT 0x00000020
+#define XFS_AGI_LEVEL 0x00000040
+#define XFS_AGI_FREECOUNT 0x00000080
+#define XFS_AGI_NEWINO 0x00000100
+#define XFS_AGI_DIRINO 0x00000200
+#define XFS_AGI_UNLINKED 0x00000400
+#define XFS_AGI_NUM_BITS 11
+#define XFS_AGI_ALL_BITS ((1 << XFS_AGI_NUM_BITS) - 1)
+
+/* disk block (xfs_daddr_t) in the AG */
+#define XFS_AGI_DADDR(mp) ((xfs_daddr_t)(2 << (mp)->m_sectbb_log))
+#define XFS_AGI_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGI_DADDR(mp))
+#define XFS_BUF_TO_AGI(bp) ((xfs_agi_t *)((bp)->b_addr))
+
+extern int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp,
+ xfs_agnumber_t agno, struct xfs_buf **bpp);
+
+/*
+ * The third a.g. block contains the a.g. freelist, an array
+ * of block pointers to blocks owned by the allocation btree code.
+ */
+#define XFS_AGFL_DADDR(mp) ((xfs_daddr_t)(3 << (mp)->m_sectbb_log))
+#define XFS_AGFL_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR(mp))
+#define XFS_AGFL_SIZE(mp) ((mp)->m_sb.sb_sectsize / sizeof(xfs_agblock_t))
+#define XFS_BUF_TO_AGFL(bp) ((xfs_agfl_t *)((bp)->b_addr))
+
+typedef struct xfs_agfl {
+ uint32_t agfl_bno[1]; /* actually XFS_AGFL_SIZE(mp) */
+} xfs_agfl_t;
+
+/*
+ * tags for inode radix tree
+ */
+#define XFS_ICI_NO_TAG (-1) /* special flag for an untagged lookup
+ in xfs_inode_ag_iterator */
+#define XFS_ICI_RECLAIM_TAG 0 /* inode is to be reclaimed */
+
+#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels)
+#define XFS_MIN_FREELIST_RAW(bl,cl,mp) \
+ (MIN(bl + 1, XFS_AG_MAXLEVELS(mp)) + MIN(cl + 1, XFS_AG_MAXLEVELS(mp)))
+#define XFS_MIN_FREELIST(a,mp) \
+ (XFS_MIN_FREELIST_RAW( \
+ be32_to_cpu((a)->agf_levels[XFS_BTNUM_BNOi]), \
+ be32_to_cpu((a)->agf_levels[XFS_BTNUM_CNTi]), mp))
+#define XFS_MIN_FREELIST_PAG(pag,mp) \
+ (XFS_MIN_FREELIST_RAW( \
+ (unsigned int)(pag)->pagf_levels[XFS_BTNUM_BNOi], \
+ (unsigned int)(pag)->pagf_levels[XFS_BTNUM_CNTi], mp))
+
+/*
+ * For checking for bad ranges of xfs_daddr_t's, covering multiple
+ * allocation groups or a single xfs_daddr_t that's a superblock copy.
+ */
+#define XFS_AG_CHECK_DADDR(mp,d,len) \
+ ((len) == 1 ? \
+ ASSERT((d) == XFS_SB_DADDR || \
+ xfs_daddr_to_agbno(mp, d) != XFS_SB_DADDR) : \
+ ASSERT(xfs_daddr_to_agno(mp, d) == \
+ xfs_daddr_to_agno(mp, (d) + (len) - 1)))
+
+#endif /* XFS_AG_H_ */
diff --git a/core/fs/xfs/xfs_dinode.c b/core/fs/xfs/xfs_dinode.c
new file mode 100644
index 00000000..8e2d8d04
--- /dev/null
+++ b/core/fs/xfs/xfs_dinode.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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 the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cache.h>
+#include <core.h>
+#include <fs.h>
+
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+
+#include "xfs_dinode.h"
+
+xfs_dinode_t *xfs_dinode_get_core(struct fs_info *fs, xfs_ino_t ino)
+{
+ block_t blk;
+ xfs_dinode_t *core;
+ uint64_t offset;
+
+ xfs_debug("ino %lu", ino);
+
+ blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
+ offset = XFS_INO_TO_OFFSET(XFS_INFO(fs), ino) << XFS_INFO(fs)->inode_shift;
+ if (offset > BLOCK_SIZE(fs)) {
+ xfs_error("Invalid inode offset in block!");
+ xfs_debug("offset: 0x%llx", offset);
+ goto out;
+ }
+
+ xfs_debug("blk %llu block offset 0x%llx", blk, blk << BLOCK_SHIFT(fs));
+ xfs_debug("inode offset in block (in bytes) is 0x%llx", offset);
+
+ core = (xfs_dinode_t *)((uint8_t *)get_cache(fs->fs_dev, blk) + offset);
+ if (be16_to_cpu(core->di_magic) !=
+ be16_to_cpu(*(uint16_t *)XFS_DINODE_MAGIC)) {
+ xfs_error("Inode core's magic number does not match!");
+ xfs_debug("magic number 0x%04x", (be16_to_cpu(core->di_magic)));
+ goto out;
+ }
+
+ return core;
+
+out:
+ return NULL;
+}
diff --git a/core/fs/xfs/xfs_dinode.h b/core/fs/xfs/xfs_dinode.h
new file mode 100644
index 00000000..80deec78
--- /dev/null
+++ b/core/fs/xfs/xfs_dinode.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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 the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_DINODE_H_
+#define XFS_DINODE_H_
+
+xfs_dinode_t *xfs_dinode_get_core(struct fs_info *fs, xfs_ino_t ino);
+
+#endif /* XFS_DINODE_H_ */
diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c
new file mode 100644
index 00000000..c52196ae
--- /dev/null
+++ b/core/fs/xfs/xfs_dir2.c
@@ -0,0 +1,759 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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 the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cache.h>
+#include <core.h>
+#include <fs.h>
+
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+#include "xfs_dinode.h"
+
+#include "xfs_dir2.h"
+
+char *xfs_dir2_get_entry_name(uint8_t *start, uint8_t *end)
+{
+ char *s;
+ char *p;
+
+ s = malloc(end - start + 1);
+ if (!s)
+ malloc_error("string");
+
+ p = s;
+ while (start < end)
+ *p++ = *start++;
+
+ *p = '\0';
+
+ return s;
+}
+
+uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen)
+{
+ uint32_t hash;
+
+ /*
+ * Do four characters at a time as long as we can.
+ */
+ for (hash = 0; namelen >= 4; namelen -=4, name += 4)
+ hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^
+ (name[3] << 0) ^ rol32(hash, 7 * 4);
+
+ /*
+ * Now do the rest of the characters.
+ */
+ switch (namelen) {
+ case 3:
+ return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^
+ rol32(hash, 7 * 3);
+ case 2:
+ return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2);
+ case 1:
+ return (name[0] << 0) ^ rol32(hash, 7 * 1);
+ default: /* case 0: */
+ return hash;
+ }
+}
+
+void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock,
+ xfs_filblks_t c)
+{
+ int count = c << XFS_INFO(fs)->dirblklog;
+ uint8_t *p;
+ uint8_t *buf;
+ off_t offset = 0;
+
+ buf = malloc(c * XFS_INFO(fs)->dirblksize);
+ if (!buf)
+ malloc_error("buffer memory");
+
+ memset(buf, 0, XFS_INFO(fs)->dirblksize);
+
+ while (count--) {
+ p = (uint8_t *)get_cache(fs->fs_dev, startblock++);
+ memcpy(buf + offset, p, BLOCK_SIZE(fs));
+ offset += BLOCK_SIZE(fs);
+ }
+
+ return buf;
+}
+
+struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core)
+{
+ xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
+ xfs_dir2_sf_entry_t *sf_entry;
+ uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
+ struct fs_info *fs = parent->fs;
+ struct inode *inode;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore = NULL;
+
+ xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count);
+
+ sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
+ (!sf->hdr.i8count ? 4 : 0));
+ while (count--) {
+ uint8_t *start_name = &sf_entry->name[0];
+ uint8_t *end_name = start_name + sf_entry->namelen;
+ char *name;
+
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ xfs_debug("entry name: %s", name);
+
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+
+ sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name[0]) +
+ sf_entry->namelen +
+ (sf->hdr.i8count ? 8 : 4));
+ }
+
+ return NULL;
+
+found:
+ inode = xfs_new_inode(fs);
+
+ ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
+ (uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name[0]) +
+ sf_entry->namelen));
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ ncore = xfs_dinode_get_core(fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto out;
+ }
+
+ fill_xfs_inode_pvt(fs, inode, ino);
+
+ inode->ino = ino;
+ inode->size = be64_to_cpu(ncore->di_size);
+
+ if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+ inode->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+ inode->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", inode->size);
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+ inode->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
+ }
+
+ return inode;
+
+out:
+ free(inode);
+
+ return NULL;
+}
+
+struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core)
+{
+ xfs_bmbt_irec_t r;
+ block_t dir_blk;
+ struct fs_info *fs = parent->fs;
+ uint8_t *dirblk_buf;
+ uint8_t *p, *endp;
+ xfs_dir2_data_hdr_t *hdr;
+ struct inode *inode = NULL;
+ xfs_dir2_block_tail_t *btp;
+ xfs_dir2_data_unused_t *dup;
+ xfs_dir2_data_entry_t *dep;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore;
+
+ bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
+
+ dirblk_buf = xfs_dir2_get_dirblks(fs, dir_blk, r.br_blockcount);
+ hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
+ if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
+ xfs_error("Block directory header's magic number does not match!");
+ xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
+ goto out;
+ }
+
+ p = (uint8_t *)(hdr + 1);
+
+ btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
+ endp = (uint8_t *)((xfs_dir2_leaf_entry_t *)btp - be32_to_cpu(btp->count));
+
+ while (p < endp) {
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+
+ dup = (xfs_dir2_data_unused_t *)p;
+ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+ p += be16_to_cpu(dup->length);
+ continue;
+ }
+
+ dep = (xfs_dir2_data_entry_t *)p;
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+ p += xfs_dir2_data_entsize(dep->namelen);
+ }
+
+out:
+ free(dirblk_buf);
+
+ return NULL;
+
+found:
+ inode = xfs_new_inode(fs);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ ncore = xfs_dinode_get_core(fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto failed;
+ }
+
+ fill_xfs_inode_pvt(fs, inode, ino);
+
+ inode->ino = ino;
+ XFS_PVT(inode)->i_ino_blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
+ inode->size = be64_to_cpu(ncore->di_size);
+
+ if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+ inode->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+ inode->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", inode->size);
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+ inode->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
+ }
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ free(dirblk_buf);
+ return inode;
+
+failed:
+ free(inode);
+ free(dirblk_buf);
+
+ return NULL;
+}
+
+struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core)
+{
+ xfs_dir2_leaf_t *leaf;
+ xfs_bmbt_irec_t irec;
+ block_t leaf_blk, dir_blk;
+ xfs_dir2_leaf_entry_t *lep;
+ int low;
+ int high;
+ int mid = 0;
+ uint32_t hash = 0;
+ uint32_t hashwant;
+ uint32_t newdb, curdb = -1;
+ xfs_dir2_data_entry_t *dep;
+ struct inode *ip;
+ xfs_dir2_data_hdr_t *data_hdr;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore;
+ uint8_t *buf = NULL;
+
+ bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
+ be32_to_cpu(core->di_nextents) - 1);
+ leaf_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
+ BLOCK_SHIFT(parent->fs);
+
+ leaf = (xfs_dir2_leaf_t *)xfs_dir2_get_dirblks(parent->fs, leaf_blk,
+ irec.br_blockcount);
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
+ xfs_error("Single leaf block header's magic number does not match!");
+ goto out;
+ }
+
+ if (!leaf->hdr.count)
+ goto out;
+
+ hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
+
+ /* Binary search */
+ for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1;
+ low <= high; ) {
+ mid = (low + high) >> 1;
+ if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
+ break;
+ if (hash < hashwant)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+
+ /* If hash is not the one we want, then the directory does not contain the
+ * entry we're looking for and there is nothing to do anymore.
+ */
+ if (hash != hashwant)
+ goto out;
+
+ while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
+ mid--;
+
+ for (lep = &leaf->ents[mid];
+ mid < be16_to_cpu(leaf->hdr.count) &&
+ be32_to_cpu(lep->hashval) == hashwant;
+ lep++, mid++) {
+ /* Skip over stale leaf entries. */
+ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
+ continue;
+
+ newdb = xfs_dir2_dataptr_to_db(parent->fs, be32_to_cpu(lep->address));
+ if (newdb != curdb) {
+ if (buf)
+ free(buf);
+
+ bmbt_irec_get(&irec,
+ ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + newdb);
+ dir_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
+ BLOCK_SHIFT(parent->fs);
+ buf = xfs_dir2_get_dirblks(parent->fs, dir_blk, irec.br_blockcount);
+ data_hdr = (xfs_dir2_data_hdr_t *)buf;
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ xfs_error("Leaf directory's data magic No. does not match!");
+ goto out1;
+ }
+
+ curdb = newdb;
+ }
+
+ dep = (xfs_dir2_data_entry_t *)((char *)buf +
+ xfs_dir2_dataptr_to_off(parent->fs, be32_to_cpu(lep->address)));
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+ }
+
+out1:
+ free(buf);
+out:
+ free(leaf);
+
+ return NULL;
+
+found:
+ ip = xfs_new_inode(parent->fs);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ ncore = xfs_dinode_get_core(parent->fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto failed;
+ }
+
+ fill_xfs_inode_pvt(parent->fs, ip, ino);
+
+ ip->ino = ino;
+ XFS_PVT(ip)->i_ino_blk = ino_to_bytes(parent->fs, ino) >>
+ BLOCK_SHIFT(parent->fs);
+ ip->size = be64_to_cpu(ncore->di_size);
+
+ if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+ ip->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+ ip->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", ip->size);
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+ ip->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
+ }
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ free(buf);
+ free(leaf);
+
+ return ip;
+
+failed:
+ free(ip);
+ free(buf);
+ free(leaf);
+
+ return ip;
+}
+
+static xfs_fsblock_t
+select_child(xfs_dfiloff_t off,
+ xfs_bmbt_key_t *kp,
+ xfs_bmbt_ptr_t *pp,
+ int nrecs)
+{
+ int i;
+
+ for (i = 0; i < nrecs; i++) {
+ if (be64_to_cpu(kp[i].br_startoff) == off)
+ return be64_to_cpu(pp[i]);
+ if (be64_to_cpu(kp[i].br_startoff) > off) {
+ if (i == 0)
+ return be64_to_cpu(pp[i]);
+ else
+ return be64_to_cpu(pp[i-1]);
+ }
+ }
+
+ return be64_to_cpu(pp[nrecs - 1]);
+}
+
+block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
+ block_t fsblkno, int *error)
+{
+ uint32_t idx;
+ xfs_bmbt_irec_t irec;
+ block_t bno;
+ block_t nextbno;
+ xfs_bmdr_block_t *rblock;
+ int fsize;
+ int nextents;
+ xfs_bmbt_ptr_t *pp;
+ xfs_bmbt_key_t *kp;
+ xfs_btree_block_t *blk;
+ xfs_bmbt_rec_t *xp;
+
+ *error = 0;
+ if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+ xfs_debug("XFS_DINODE_FMT_EXTENTS");
+ for (idx = 0; idx < be32_to_cpu(core->di_nextents); idx++) {
+ bmbt_irec_get(&irec,
+ ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + idx);
+ if (fsblkno >= irec.br_startoff &&
+ fsblkno < irec.br_startoff + irec.br_blockcount)
+ break;
+ }
+ } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+ xfs_debug("XFS_DINODE_FMT_BTREE");
+ bno = NULLFSBLOCK;
+ rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0];
+ fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK);
+ pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
+ kp = XFS_BMDR_KEY_ADDR(rblock, 1);
+ bno = fsblock_to_bytes(fs,
+ select_child(fsblkno, kp, pp,
+ be16_to_cpu(rblock->bb_numrecs))) >> BLOCK_SHIFT(fs);
+
+ /* Find the leaf */
+ for (;;) {
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ if (be16_to_cpu(blk->bb_level) == 0)
+ break;
+ pp = XFS_BMBT_PTR_ADDR(fs, blk, 1,
+ xfs_bmdr_maxrecs(XFS_INFO(fs)->blocksize, 0));
+ kp = XFS_BMBT_KEY_ADDR(fs, blk, 1);
+ bno = fsblock_to_bytes(fs,
+ select_child(fsblkno, kp, pp,
+ be16_to_cpu(blk->bb_numrecs))) >> BLOCK_SHIFT(fs);
+ }
+
+ /* Find the records among leaves */
+ for (;;) {
+ nextbno = be64_to_cpu(blk->bb_u.l.bb_rightsib);
+ nextents = be16_to_cpu(blk->bb_numrecs);
+ xp = (xfs_bmbt_rec_t *)XFS_BMBT_REC_ADDR(fs, blk, 1);
+ for (idx = 0; idx < nextents; idx++) {
+ bmbt_irec_get(&irec, xp + idx);
+ if (fsblkno >= irec.br_startoff &&
+ fsblkno < irec.br_startoff + irec.br_blockcount) {
+ nextbno = NULLFSBLOCK;
+ break;
+ }
+ }
+ if (nextbno == NULLFSBLOCK)
+ break;
+ bno = fsblock_to_bytes(fs, nextbno) >> BLOCK_SHIFT(fs);
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ }
+ }
+
+ if (fsblkno < irec.br_startoff ||
+ fsblkno >= irec.br_startoff + irec.br_blockcount)
+ *error = 1;
+
+ return fsblock_to_bytes(fs,
+ fsblkno - irec.br_startoff + irec.br_startblock) >>
+ BLOCK_SHIFT(fs);
+}
+
+struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core)
+{
+ block_t fsblkno;
+ xfs_da_intnode_t *node = NULL;
+ uint32_t hashwant;
+ uint32_t hash = 0;
+ xfs_da_node_entry_t *btree;
+ uint16_t max;
+ uint16_t span;
+ uint16_t probe;
+ int error;
+ xfs_dir2_data_hdr_t *data_hdr;
+ xfs_dir2_leaf_t *leaf;
+ xfs_dir2_leaf_entry_t *lep;
+ xfs_dir2_data_entry_t *dep;
+ struct inode *ip;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ int low;
+ int high;
+ int mid = 0;
+ uint32_t newdb, curdb = -1;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore;
+ uint8_t *buf = NULL;
+
+ hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
+
+ fsblkno = xfs_dir2_get_right_blk(parent->fs, core,
+ xfs_dir2_byte_to_db(parent->fs, XFS_DIR2_LEAF_OFFSET),
+ &error);
+ if (error) {
+ xfs_error("Cannot find right rec!");
+ return NULL;
+ }
+
+ node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(parent->fs, fsblkno, 1);
+ if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
+ xfs_error("Node's magic number does not match!");
+ goto out;
+ }
+
+ do {
+ if (!node->hdr.count)
+ goto out;
+
+ /* Given a hash to lookup, you read the node's btree array and first
+ * "hashval" in the array that exceeds the given hash and it can then
+ * be found in the block pointed by the "before" value.
+ */
+ max = be16_to_cpu(node->hdr.count);
+
+ probe = span = max/2;
+ for (btree = &node->btree[probe];
+ span > 4; btree = &node->btree[probe]) {
+ span /= 2;
+ hash = be32_to_cpu(btree->hashval);
+
+ if (hash < hashwant)
+ probe += span;
+ else if (hash > hashwant)
+ probe -= span;
+ else
+ break;
+ }
+
+ while ((probe > 0) && (be32_to_cpu(btree->hashval) >= hashwant)) {
+ btree--;
+ probe--;
+ }
+
+ while ((probe < max) && (be32_to_cpu(btree->hashval) < hashwant)) {
+ btree++;
+ probe++;
+ }
+
+ if (probe == max)
+ fsblkno = be32_to_cpu(node->btree[max-1].before);
+ else
+ fsblkno = be32_to_cpu(node->btree[probe].before);
+
+ fsblkno = xfs_dir2_get_right_blk(parent->fs, core, fsblkno, &error);
+ if (error) {
+ xfs_error("Cannot find right rec!");
+ goto out;
+ }
+
+ free(node);
+ node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(parent->fs,
+ fsblkno, 1);
+ } while(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
+
+ leaf = (xfs_dir2_leaf_t*)node;
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
+ xfs_error("Leaf's magic number does not match!");
+ goto out;
+ }
+
+ if (!leaf->hdr.count)
+ goto out;
+
+ for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1;
+ low <= high; ) {
+ mid = (low + high) >> 1;
+
+ if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
+ break;
+ if (hash < hashwant)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+
+ /* If hash is not the one we want, then the directory does not contain the
+ * entry we're looking for and there is nothing to do anymore.
+ */
+ if (hash != hashwant)
+ goto out;
+
+ while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
+ mid--;
+
+ for (lep = &leaf->ents[mid];
+ mid < be16_to_cpu(leaf->hdr.count) &&
+ be32_to_cpu(lep->hashval) == hashwant;
+ lep++, mid++) {
+ /* Skip over stale leaf entries. */
+ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
+ continue;
+
+ newdb = xfs_dir2_dataptr_to_db(parent->fs, be32_to_cpu(lep->address));
+ if (newdb != curdb) {
+ if (buf)
+ free(buf);
+
+ fsblkno = xfs_dir2_get_right_blk(parent->fs, core, newdb, &error);
+ if (error) {
+ xfs_error("Cannot find data block!");
+ goto out;
+ }
+
+ buf = xfs_dir2_get_dirblks(parent->fs, fsblkno, 1);
+ data_hdr = (xfs_dir2_data_hdr_t *)buf;
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ xfs_error("Leaf directory's data magic No. does not match!");
+ goto out1;
+ }
+
+ curdb = newdb;
+ }
+
+ dep = (xfs_dir2_data_entry_t *)((char *)buf +
+ xfs_dir2_dataptr_to_off(parent->fs, be32_to_cpu(lep->address)));
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+ }
+
+out1:
+ free(buf);
+
+out:
+ free(node);
+
+ return NULL;
+
+found:
+ ip = xfs_new_inode(parent->fs);
+ ino = be64_to_cpu(dep->inumber);
+ ncore = xfs_dinode_get_core(parent->fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto failed;
+ }
+
+ fill_xfs_inode_pvt(parent->fs, ip, ino);
+ ip->ino = ino;
+ XFS_PVT(ip)->i_ino_blk = ino_to_bytes(parent->fs, ino) >>
+ BLOCK_SHIFT(parent->fs);
+ ip->size = be64_to_cpu(ncore->di_size);
+
+ if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
+ ip->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
+ ip->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", ip->size);
+ } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
+ ip->mode = DT_LNK;
+ xfs_debug("Found a symbolic link inode!");
+ }
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ free(buf);
+ free(node);
+
+ return ip;
+
+failed:
+ free(ip);
+ free(buf);
+ free(node);
+
+ return NULL;
+}
diff --git a/core/fs/xfs/xfs_dir2.h b/core/fs/xfs/xfs_dir2.h
new file mode 100644
index 00000000..e1b96227
--- /dev/null
+++ b/core/fs/xfs/xfs_dir2.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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 the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_DIR2_H_
+#define XFS_DIR2_H_
+
+#include <core.h>
+#include <fs.h>
+
+#include "xfs.h"
+
+char *xfs_dir2_get_entry_name(uint8_t *start, uint8_t *end);
+void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock,
+ xfs_filblks_t c);
+uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen);
+block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
+ block_t fsblkno, int *error);
+
+struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core);
+struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core);
+struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core);
+struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
+ xfs_dinode_t *core);
+
+static inline bool xfs_dir2_isleaf(struct fs_info *fs, xfs_dinode_t *dip)
+{
+ uint64_t last = 0;
+ xfs_bmbt_irec_t irec;
+
+ bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&dip->di_literal_area[0]) +
+ be32_to_cpu(dip->di_nextents) - 1);
+ last = irec.br_startoff + irec.br_blockcount;
+
+ return (last == XFS_INFO(fs)->dirleafblk + (1 << XFS_INFO(fs)->dirblklog));
+}
+
+#endif /* XFS_DIR2_H_ */
diff --git a/core/fs/xfs/xfs_fs.h b/core/fs/xfs/xfs_fs.h
new file mode 100644
index 00000000..587820ec
--- /dev/null
+++ b/core/fs/xfs/xfs_fs.h
@@ -0,0 +1,501 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 1995-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_FS_H_
+#define XFS_FS_H_
+
+/*
+ * SGI's XFS filesystem's major stuff (constants, structures)
+ */
+
+/*
+ * Direct I/O attribute record used with XFS_IOC_DIOINFO
+ * d_miniosz is the min xfer size, xfer size multiple and file seek offset
+ * alignment.
+ */
+struct dioattr {
+ uint32_t d_mem; /* data buffer memory alignment */
+ uint32_t d_miniosz; /* min xfer size */
+ uint32_t d_maxiosz; /* max xfer size */
+};
+
+/*
+ * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
+ */
+struct fsxattr {
+ uint32_t fsx_xflags; /* xflags field value (get/set) */
+ uint32_t fsx_extsize; /* extsize field value (get/set)*/
+ uint32_t fsx_nextents; /* nextents field value (get) */
+ uint32_t fsx_projid; /* project identifier (get/set) */
+ unsigned char fsx_pad[12];
+};
+
+/*
+ * Flags for the bs_xflags/fsx_xflags field
+ * There should be a one-to-one correspondence between these flags and the
+ * XFS_DIFLAG_s.
+ */
+#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
+#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
+#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
+#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */
+#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
+#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */
+#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
+#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
+#define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
+#define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
+#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
+#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
+#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
+#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
+#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
+
+/*
+ * Structure for XFS_IOC_GETBMAP.
+ * On input, fill in bmv_offset and bmv_length of the first structure
+ * to indicate the area of interest in the file, and bmv_entries with
+ * the number of array elements given back. The first structure is
+ * updated on return to give the offset and length for the next call.
+ */
+struct getbmap {
+ int64_t bmv_offset; /* file offset of segment in blocks */
+ int64_t bmv_block; /* starting block (64-bit daddr_t) */
+ int64_t bmv_length; /* length of segment, blocks */
+ int32_t bmv_count; /* # of entries in array incl. 1st */
+ int32_t bmv_entries; /* # of entries filled in (output) */
+};
+
+/*
+ * Structure for XFS_IOC_GETBMAPX. Fields bmv_offset through bmv_entries
+ * are used exactly as in the getbmap structure. The getbmapx structure
+ * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field
+ * is only used for the first structure. It contains input flags
+ * specifying XFS_IOC_GETBMAPX actions. The bmv_oflags field is filled
+ * in by the XFS_IOC_GETBMAPX command for each returned structure after
+ * the first.
+ */
+struct getbmapx {
+ int64_t bmv_offset; /* file offset of segment in blocks */
+ int64_t bmv_block; /* starting block (64-bit daddr_t) */
+ int64_t bmv_length; /* length of segment, blocks */
+ int32_t bmv_count; /* # of entries in array incl. 1st */
+ int32_t bmv_entries; /* # of entries filled in (output). */
+ int32_t bmv_iflags; /* input flags (1st structure) */
+ int32_t bmv_oflags; /* output flags (after 1st structure)*/
+ int32_t bmv_unused1; /* future use */
+ int32_t bmv_unused2; /* future use */
+};
+
+/* bmv_iflags values - set by XFS_IOC_GETBMAPX caller. */
+#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */
+#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */
+#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */
+#define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */
+#define BMV_IF_NO_HOLES 0x10 /* Do not return holes */
+#define BMV_IF_VALID \
+ (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \
+ BMV_IF_DELALLOC|BMV_IF_NO_HOLES)
+
+/* bmv_oflags values - returned for each non-header segment */
+#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */
+#define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */
+#define BMV_OF_LAST 0x4 /* segment is the last in the file */
+
+/*
+ * Structure for XFS_IOC_FSSETDM.
+ * For use by backup and restore programs to set the XFS on-disk inode
+ * fields di_dmevmask and di_dmstate. These must be set to exactly and
+ * only values previously obtained via xfs_bulkstat! (Specifically the
+ * xfs_bstat_t fields bs_dmevmask and bs_dmstate.)
+ */
+struct fsdmidata {
+ uint32_t fsd_dmevmask; /* corresponds to di_dmevmask */
+ __u16 fsd_padding;
+ __u16 fsd_dmstate; /* corresponds to di_dmstate */
+};
+
+/*
+ * File segment locking set data type for 64 bit access.
+ * Also used for all the RESV/FREE interfaces.
+ */
+typedef struct xfs_flock64 {
+ __s16 l_type;
+ __s16 l_whence;
+ int64_t l_start;
+ int64_t l_len; /* len == 0 means until end of file */
+ int32_t l_sysid;
+ uint32_t l_pid;
+ int32_t l_pad[4]; /* reserve area */
+} xfs_flock64_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY_V1
+ */
+typedef struct xfs_fsop_geom_v1 {
+ uint32_t blocksize; /* filesystem (data) block size */
+ uint32_t rtextsize; /* realtime extent size */
+ uint32_t agblocks; /* fsblocks in an AG */
+ uint32_t agcount; /* number of allocation groups */
+ uint32_t logblocks; /* fsblocks in the log */
+ uint32_t sectsize; /* (data) sector size, bytes */
+ uint32_t inodesize; /* inode size in bytes */
+ uint32_t imaxpct; /* max allowed inode space(%) */
+ uint64_t datablocks; /* fsblocks in data subvolume */
+ uint64_t rtblocks; /* fsblocks in realtime subvol */
+ uint64_t rtextents; /* rt extents in realtime subvol*/
+ uint64_t logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ uint32_t sunit; /* stripe unit, fsblocks */
+ uint32_t swidth; /* stripe width, fsblocks */
+ int32_t version; /* structure version */
+ uint32_t flags; /* superblock version flags */
+ uint32_t logsectsize; /* log sector size, bytes */
+ uint32_t rtsectsize; /* realtime sector size, bytes */
+ uint32_t dirblocksize; /* directory block size, bytes */
+} xfs_fsop_geom_v1_t;
+
+/*
+ * Output for XFS_IOC_FSGEOMETRY
+ */
+typedef struct xfs_fsop_geom {
+ uint32_t blocksize; /* filesystem (data) block size */
+ uint32_t rtextsize; /* realtime extent size */
+ uint32_t agblocks; /* fsblocks in an AG */
+ uint32_t agcount; /* number of allocation groups */
+ uint32_t logblocks; /* fsblocks in the log */
+ uint32_t sectsize; /* (data) sector size, bytes */
+ uint32_t inodesize; /* inode size in bytes */
+ uint32_t imaxpct; /* max allowed inode space(%) */
+ uint64_t datablocks; /* fsblocks in data subvolume */
+ uint64_t rtblocks; /* fsblocks in realtime subvol */
+ uint64_t rtextents; /* rt extents in realtime subvol*/
+ uint64_t logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ uint32_t sunit; /* stripe unit, fsblocks */
+ uint32_t swidth; /* stripe width, fsblocks */
+ int32_t version; /* structure version */
+ uint32_t flags; /* superblock version flags */
+ uint32_t logsectsize; /* log sector size, bytes */
+ uint32_t rtsectsize; /* realtime sector size, bytes */
+ uint32_t dirblocksize; /* directory block size, bytes */
+ uint32_t logsunit; /* log stripe unit, bytes */
+} xfs_fsop_geom_t;
+
+/* Output for XFS_FS_COUNTS */
+typedef struct xfs_fsop_counts {
+ uint64_t freedata; /* free data section blocks */
+ uint64_t freertx; /* free rt extents */
+ uint64_t freeino; /* free inodes */
+ uint64_t allocino; /* total allocated inodes */
+} xfs_fsop_counts_t;
+
+/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */
+typedef struct xfs_fsop_resblks {
+ uint64_t resblks;
+ uint64_t resblks_avail;
+} xfs_fsop_resblks_t;
+
+#define XFS_FSOP_GEOM_VERSION 0
+
+#define XFS_FSOP_GEOM_FLAGS_ATTR 0x0001 /* attributes in use */
+#define XFS_FSOP_GEOM_FLAGS_NLINK 0x0002 /* 32-bit nlink values */
+#define XFS_FSOP_GEOM_FLAGS_QUOTA 0x0004 /* quotas enabled */
+#define XFS_FSOP_GEOM_FLAGS_IALIGN 0x0008 /* inode alignment */
+#define XFS_FSOP_GEOM_FLAGS_DALIGN 0x0010 /* large data alignment */
+#define XFS_FSOP_GEOM_FLAGS_SHARED 0x0020 /* read-only shared */
+#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x0040 /* special extent flag */
+#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x0080 /* directory version 2 */
+#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */
+#define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */
+#define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */
+#define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */
+#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */
+
+
+/*
+ * Minimum and maximum sizes need for growth checks
+ */
+#define XFS_MIN_AG_BLOCKS 64
+#define XFS_MIN_LOG_BLOCKS 512ULL
+#define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL)
+#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL)
+
+/* keep the maximum size under 2^31 by a small amount */
+#define XFS_MAX_LOG_BYTES \
+ ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES)
+
+/* Used for sanity checks on superblock */
+#define XFS_MAX_DBLOCKS(s) ((xfs_drfsbno_t)(s)->sb_agcount * (s)->sb_agblocks)
+#define XFS_MIN_DBLOCKS(s) ((xfs_drfsbno_t)((s)->sb_agcount - 1) * \
+ (s)->sb_agblocks + XFS_MIN_AG_BLOCKS)
+
+/*
+ * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT
+ */
+typedef struct xfs_growfs_data {
+ uint64_t newblocks; /* new data subvol size, fsblocks */
+ uint32_t imaxpct; /* new inode space percentage limit */
+} xfs_growfs_data_t;
+
+typedef struct xfs_growfs_log {
+ uint32_t newblocks; /* new log size, fsblocks */
+ uint32_t isint; /* 1 if new log is internal */
+} xfs_growfs_log_t;
+
+typedef struct xfs_growfs_rt {
+ uint64_t newblocks; /* new realtime size, fsblocks */
+ uint32_t extsize; /* new realtime extent size, fsblocks */
+} xfs_growfs_rt_t;
+
+
+/*
+ * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE
+ */
+typedef struct xfs_bstime {
+ time_t tv_sec; /* seconds */
+ int32_t tv_nsec; /* and nanoseconds */
+} xfs_bstime_t;
+
+typedef struct xfs_bstat {
+ uint64_t bs_ino; /* inode number */
+ __u16 bs_mode; /* type and mode */
+ __u16 bs_nlink; /* number of links */
+ uint32_t bs_uid; /* user id */
+ uint32_t bs_gid; /* group id */
+ uint32_t bs_rdev; /* device value */
+ int32_t bs_blksize; /* block size */
+ int64_t bs_size; /* file size */
+ xfs_bstime_t bs_atime; /* access time */
+ xfs_bstime_t bs_mtime; /* modify time */
+ xfs_bstime_t bs_ctime; /* inode change time */
+ int64_t bs_blocks; /* number of blocks */
+ uint32_t bs_xflags; /* extended flags */
+ int32_t bs_extsize; /* extent size */
+ int32_t bs_extents; /* number of extents */
+ uint32_t bs_gen; /* generation count */
+ __u16 bs_projid_lo; /* lower part of project id */
+#define bs_projid bs_projid_lo /* (previously just bs_projid) */
+ __u16 bs_forkoff; /* inode fork offset in bytes */
+ __u16 bs_projid_hi; /* higher part of project id */
+ unsigned char bs_pad[10]; /* pad space, unused */
+ uint32_t bs_dmevmask; /* DMIG event mask */
+ __u16 bs_dmstate; /* DMIG state info */
+ __u16 bs_aextents; /* attribute number of extents */
+} xfs_bstat_t;
+
+/*
+ * The user-level BulkStat Request interface structure.
+ */
+typedef struct xfs_fsop_bulkreq {
+ uint64_t __user *lastip; /* last inode # pointer */
+ int32_t icount; /* count of entries in buffer */
+ void __user *ubuffer;/* user buffer for inode desc. */
+ int32_t __user *ocount; /* output count pointer */
+} xfs_fsop_bulkreq_t;
+
+
+/*
+ * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS).
+ */
+typedef struct xfs_inogrp {
+ uint64_t xi_startino; /* starting inode number */
+ int32_t xi_alloccount; /* # bits set in allocmask */
+ uint64_t xi_allocmask; /* mask of allocated inodes */
+} xfs_inogrp_t;
+
+
+/*
+ * Error injection.
+ */
+typedef struct xfs_error_injection {
+ int32_t fd;
+ int32_t errtag;
+} xfs_error_injection_t;
+
+
+/*
+ * The user-level Handle Request interface structure.
+ */
+typedef struct xfs_fsop_handlereq {
+ uint32_t fd; /* fd for FD_TO_HANDLE */
+ void __user *path; /* user pathname */
+ uint32_t oflags; /* open flags */
+ void __user *ihandle;/* user supplied handle */
+ uint32_t ihandlen; /* user supplied length */
+ void __user *ohandle;/* user buffer for handle */
+ uint32_t __user *ohandlen;/* user buffer length */
+} xfs_fsop_handlereq_t;
+
+/*
+ * Compound structures for passing args through Handle Request interfaces
+ * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle
+ * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and
+ * XFS_IOC_ATTRMULTI_BY_HANDLE
+ */
+
+typedef struct xfs_fsop_setdm_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle information */
+ struct fsdmidata __user *data; /* DMAPI data */
+} xfs_fsop_setdm_handlereq_t;
+
+typedef struct xfs_attrlist_cursor {
+ uint32_t opaque[4];
+} xfs_attrlist_cursor_t;
+
+typedef struct xfs_fsop_attrlist_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle interface structure */
+ struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */
+ uint32_t flags; /* which namespace to use */
+ uint32_t buflen; /* length of buffer supplied */
+ void __user *buffer; /* returned names */
+} xfs_fsop_attrlist_handlereq_t;
+
+typedef struct xfs_attr_multiop {
+ uint32_t am_opcode;
+#define ATTR_OP_GET 1 /* return the indicated attr's value */
+#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */
+#define ATTR_OP_REMOVE 3 /* remove the indicated attr */
+ int32_t am_error;
+ void __user *am_attrname;
+ void __user *am_attrvalue;
+ uint32_t am_length;
+ uint32_t am_flags;
+} xfs_attr_multiop_t;
+
+typedef struct xfs_fsop_attrmulti_handlereq {
+ struct xfs_fsop_handlereq hreq; /* handle interface structure */
+ uint32_t opcount;/* count of following multiop */
+ struct xfs_attr_multiop __user *ops; /* attr_multi data */
+} xfs_fsop_attrmulti_handlereq_t;
+
+/*
+ * per machine unique filesystem identifier types.
+ */
+typedef struct { uint32_t val[2]; } xfs_fsid_t; /* file system id type */
+
+typedef struct xfs_fid {
+ __u16 fid_len; /* length of remainder */
+ __u16 fid_pad;
+ uint32_t fid_gen; /* generation number */
+ uint64_t fid_ino; /* 64 bits inode number */
+} xfs_fid_t;
+
+typedef struct xfs_handle {
+ union {
+ int64_t align; /* force alignment of ha_fid */
+ xfs_fsid_t _ha_fsid; /* unique file system identifier */
+ } ha_u;
+ xfs_fid_t ha_fid; /* file system specific file ID */
+} xfs_handle_t;
+#define ha_fsid ha_u._ha_fsid
+
+#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.fid_pad \
+ - (char *) &(handle)) \
+ + (handle).ha_fid.fid_len)
+
+/*
+ * Flags for going down operation
+ */
+#define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */
+#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */
+#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */
+
+/*
+ * ioctl commands that are used by Linux filesystems
+ */
+#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS
+#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS
+#define XFS_IOC_GETVERSION FS_IOC_GETVERSION
+
+/*
+ * ioctl commands that replace IRIX fcntl()'s
+ * For 'documentation' purposed more than anything else,
+ * the "cmd #" field reflects the IRIX fcntl number.
+ */
+#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64)
+#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64)
+#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr)
+#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr)
+#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr)
+#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64)
+#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64)
+#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap)
+#define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata)
+#define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64)
+#define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64)
+#define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64)
+#define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap)
+#define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr)
+/* XFS_IOC_SETBIOSIZE ---- deprecated 46 */
+/* XFS_IOC_GETBIOSIZE ---- deprecated 47 */
+#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap)
+#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64)
+
+/*
+ * ioctl commands that replace IRIX syssgi()'s
+ */
+#define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct xfs_fsop_geom_v1)
+#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq)
+#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq)
+#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq)
+#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq)
+#define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct xfs_fsop_handlereq)
+#define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct xfs_fsop_handlereq)
+#define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct xfs_fsop_handlereq)
+#define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext)
+#define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct xfs_growfs_data)
+#define XFS_IOC_FSGROWFSLOG _IOW ('X', 111, struct xfs_growfs_log)
+#define XFS_IOC_FSGROWFSRT _IOW ('X', 112, struct xfs_growfs_rt)
+#define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts)
+#define XFS_IOC_SET_RESBLKS _IOWR('X', 114, struct xfs_fsop_resblks)
+#define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct xfs_fsop_resblks)
+#define XFS_IOC_ERROR_INJECTION _IOW ('X', 116, struct xfs_error_injection)
+#define XFS_IOC_ERROR_CLEARALL _IOW ('X', 117, struct xfs_error_injection)
+/* XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118 */
+/* XFS_IOC_FREEZE -- FIFREEZE 119 */
+/* XFS_IOC_THAW -- FITHAW 120 */
+#define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct xfs_fsop_setdm_handlereq)
+#define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq)
+#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq)
+#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom)
+#define XFS_IOC_GOINGDOWN _IOR ('X', 125, __uint32_t)
+/* XFS_IOC_GETFSUUID ---------- deprecated 140 */
+
+
+#ifndef HAVE_BBMACROS
+/*
+ * Block I/O parameterization. A basic block (BB) is the lowest size of
+ * filesystem allocation, and must equal 512. Length units given to bio
+ * routines are in BB's.
+ */
+#define BBSHIFT 9
+#define BBSIZE (1<<BBSHIFT)
+#define BBMASK (BBSIZE-1)
+#define BTOBB(bytes) (((uint64_t)(bytes) + BBSIZE - 1) >> BBSHIFT)
+#define BTOBBT(bytes) ((uint64_t)(bytes) >> BBSHIFT)
+#define BBTOB(bbs) ((bbs) << BBSHIFT)
+#endif
+
+#endif /* XFS_FS_H_ */
diff --git a/core/fs/xfs/xfs_readdir.c b/core/fs/xfs/xfs_readdir.c
new file mode 100644
index 00000000..0e013e55
--- /dev/null
+++ b/core/fs/xfs/xfs_readdir.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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 the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cache.h>
+#include <core.h>
+#include <fs.h>
+
+#include "xfs_types.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "misc.h"
+#include "xfs.h"
+#include "xfs_dinode.h"
+#include "xfs_dir2.h"
+
+#include "xfs_readdir.h"
+
+static int fill_dirent(struct fs_info *fs, struct dirent *dirent,
+ uint32_t offset, xfs_ino_t ino, char *name,
+ size_t namelen)
+{
+ xfs_dinode_t *core;
+
+ dirent->d_ino = ino;
+ dirent->d_off = offset;
+ dirent->d_reclen = offsetof(struct dirent, d_name) + namelen + 1;
+
+ core = xfs_dinode_get_core(fs, ino);
+ if (!core) {
+ xfs_error("Failed to get dinode from disk (ino 0x%llx)", ino);
+ return -1;
+ }
+
+ if (be16_to_cpu(core->di_mode) & S_IFDIR)
+ dirent->d_type = DT_DIR;
+ else if (be16_to_cpu(core->di_mode) & S_IFREG)
+ dirent->d_type = DT_REG;
+ else if (be16_to_cpu(core->di_mode) & S_IFLNK)
+ dirent->d_type = DT_LNK;
+
+ memcpy(dirent->d_name, name, namelen + 1);
+
+ return 0;
+}
+
+int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
+ xfs_dir2_sf_entry_t *sf_entry;
+ uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
+ uint32_t offset = file->offset;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_ino_t ino;
+ struct fs_info *fs = file->fs;
+ int retval = 0;
+
+ xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count);
+
+ if (file->offset + 1 > count)
+ return -1;
+
+ file->offset++;
+
+ sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
+ (!sf->hdr.i8count ? 4 : 0));
+
+ if (file->offset - 1) {
+ offset = file->offset;
+ while (--offset) {
+ sf_entry = (xfs_dir2_sf_entry_t *)(
+ (uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name[0]) +
+ sf_entry->namelen +
+ (sf->hdr.i8count ? 8 : 4));
+ }
+ }
+
+ start_name = &sf_entry->name[0];
+ end_name = start_name + sf_entry->namelen;
+
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
+ (uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name[0]) +
+ sf_entry->namelen));
+
+ retval = fill_dirent(fs, dirent, file->offset, ino, (char *)name,
+ end_name - start_name);
+ if (retval)
+ xfs_error("Failed to fill in dirent structure");
+
+ free(name);
+
+ return retval;
+}
+
+int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ xfs_bmbt_irec_t r;
+ block_t dir_blk;
+ struct fs_info *fs = file->fs;
+ uint8_t *dirblk_buf;
+ uint8_t *p;
+ uint32_t offset;
+ xfs_dir2_data_hdr_t *hdr;
+ xfs_dir2_block_tail_t *btp;
+ xfs_dir2_data_unused_t *dup;
+ xfs_dir2_data_entry_t *dep;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_ino_t ino;
+ int retval = 0;
+
+ bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
+
+ dirblk_buf = xfs_dir2_get_dirblks(fs, dir_blk, r.br_blockcount);
+ hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
+ if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
+ xfs_error("Block directory header's magic number does not match!");
+ xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
+
+ free(dirblk_buf);
+
+ return -1;
+ }
+
+ btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
+
+ if (file->offset + 1 > be32_to_cpu(btp->count))
+ return -1;
+
+ file->offset++;
+
+ p = (uint8_t *)(hdr + 1);
+
+ if (file->offset - 1) {
+ offset = file->offset;
+ while (--offset) {
+ dep = (xfs_dir2_data_entry_t *)p;
+
+ dup = (xfs_dir2_data_unused_t *)p;
+ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+ p += be16_to_cpu(dup->length);
+ continue;
+ }
+
+ p += xfs_dir2_data_entsize(dep->namelen);
+ }
+ }
+
+ dep = (xfs_dir2_data_entry_t *)p;
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ retval = fill_dirent(fs, dirent, file->offset, ino, name,
+ end_name - start_name);
+ if (retval)
+ xfs_error("Failed to fill in dirent structure");
+
+ free(dirblk_buf);
+ free(name);
+
+ return retval;
+}
+
+int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ xfs_bmbt_irec_t irec;
+ struct fs_info *fs = file->fs;
+ xfs_dir2_leaf_t *leaf;
+ block_t leaf_blk, dir_blk;
+ xfs_dir2_leaf_entry_t *lep;
+ uint32_t db;
+ unsigned int offset;
+ xfs_dir2_data_entry_t *dep;
+ xfs_dir2_data_hdr_t *data_hdr;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_intino_t ino;
+ uint8_t *buf = NULL;
+ int retval = 0;
+
+ bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
+ be32_to_cpu(core->di_nextents) - 1);
+ leaf_blk = fsblock_to_bytes(fs, irec.br_startblock) >>
+ BLOCK_SHIFT(file->fs);
+
+ leaf = (xfs_dir2_leaf_t *)xfs_dir2_get_dirblks(fs, leaf_blk,
+ irec.br_blockcount);
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
+ xfs_error("Single leaf block header's magic number does not match!");
+ goto out;
+ }
+
+ if (!leaf->hdr.count)
+ goto out;
+
+ if (file->offset + 1 > be16_to_cpu(leaf->hdr.count))
+ goto out;
+
+ lep = &leaf->ents[file->offset++];
+
+ /* Skip over stale leaf entries */
+ for ( ; be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
+ lep++, file->offset++);
+
+ db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
+
+ bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] + db);
+
+ dir_blk = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
+
+ buf = xfs_dir2_get_dirblks(fs, dir_blk, irec.br_blockcount);
+ data_hdr = (xfs_dir2_data_hdr_t *)buf;
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ xfs_error("Leaf directory's data magic number does not match!");
+ goto out1;
+ }
+
+ offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
+
+ dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset);
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ retval = fill_dirent(fs, dirent, file->offset, ino, name,
+ end_name - start_name);
+ if (retval)
+ xfs_error("Failed to fill in dirent structure");
+
+ free(name);
+ free(buf);
+ free(leaf);
+
+ return retval;
+
+out1:
+ free(buf);
+
+out:
+ free(leaf);
+
+ return -1;
+}
+
+int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core)
+{
+ struct fs_info *fs = file->fs;
+ xfs_bmbt_irec_t irec;
+ uint32_t node_off = 0;
+ block_t fsblkno;
+ xfs_da_intnode_t *node = NULL;
+ struct inode *inode = file->inode;
+ int error;
+ xfs_dir2_data_hdr_t *data_hdr;
+ xfs_dir2_leaf_t *leaf;
+ xfs_dir2_leaf_entry_t *lep;
+ unsigned int offset;
+ xfs_dir2_data_entry_t *dep;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ uint32_t db;
+ uint8_t *buf = NULL;
+ int retval = 0;
+
+ do {
+ bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
+ ++node_off);
+ } while (irec.br_startoff < xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET));
+
+ fsblkno = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
+
+ node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(fs, fsblkno, 1);
+ if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
+ xfs_error("Node's magic number does not match!");
+ goto out;
+ }
+
+try_next_btree:
+ if (!node->hdr.count ||
+ XFS_PVT(inode)->i_btree_offset >= be16_to_cpu(node->hdr.count))
+ goto out;
+
+ fsblkno = be32_to_cpu(node->btree[XFS_PVT(inode)->i_btree_offset].before);
+ fsblkno = xfs_dir2_get_right_blk(fs, core, fsblkno, &error);
+ if (error) {
+ xfs_error("Cannot find leaf rec!");
+ goto out;
+ }
+
+ leaf = (xfs_dir2_leaf_t*)xfs_dir2_get_dirblks(fs, fsblkno, 1);
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
+ xfs_error("Leaf's magic number does not match!");
+ goto out1;
+ }
+
+ if (!leaf->hdr.count ||
+ XFS_PVT(inode)->i_leaf_ent_offset >= be16_to_cpu(leaf->hdr.count)) {
+ XFS_PVT(inode)->i_btree_offset++;
+ XFS_PVT(inode)->i_leaf_ent_offset = 0;
+ free(leaf);
+ goto try_next_btree;
+ }
+
+ lep = &leaf->ents[XFS_PVT(inode)->i_leaf_ent_offset];
+
+ /* Skip over stale leaf entries */
+ for ( ; XFS_PVT(inode)->i_leaf_ent_offset < be16_to_cpu(leaf->hdr.count) &&
+ be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
+ lep++, XFS_PVT(inode)->i_leaf_ent_offset++);
+
+ if (XFS_PVT(inode)->i_leaf_ent_offset == be16_to_cpu(leaf->hdr.count)) {
+ XFS_PVT(inode)->i_btree_offset++;
+ XFS_PVT(inode)->i_leaf_ent_offset = 0;
+ free(leaf);
+ goto try_next_btree;
+ } else {
+ XFS_PVT(inode)->i_leaf_ent_offset++;
+ }
+
+ db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
+
+ fsblkno = xfs_dir2_get_right_blk(fs, core, db, &error);
+ if (error) {
+ xfs_error("Cannot find data block!");
+ goto out1;
+ }
+
+ buf = xfs_dir2_get_dirblks(fs, fsblkno, 1);
+ data_hdr = (xfs_dir2_data_hdr_t *)buf;
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ xfs_error("Leaf directory's data magic No. does not match!");
+ goto out2;
+ }
+
+ offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
+
+ dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset);
+
+ start_name = &dep->name[0];
+ end_name = start_name + dep->namelen;
+ name = xfs_dir2_get_entry_name(start_name, end_name);
+
+ retval = fill_dirent(fs, dirent, 0, be64_to_cpu(dep->inumber), name,
+ end_name - start_name);
+ if (retval)
+ xfs_error("Failed to fill in dirent structure");
+
+ free(name);
+ free(buf);
+ free(leaf);
+ free(node);
+
+ return retval;
+
+out2:
+ free(buf);
+
+out1:
+ free(leaf);
+
+out:
+ free(node);
+
+ XFS_PVT(inode)->i_btree_offset = 0;
+ XFS_PVT(inode)->i_leaf_ent_offset = 0;
+
+ return -1;
+}
diff --git a/core/fs/xfs/xfs_readdir.h b/core/fs/xfs/xfs_readdir.h
new file mode 100644
index 00000000..2e564ec8
--- /dev/null
+++ b/core/fs/xfs/xfs_readdir.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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 the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XFS_READDIR_H_
+#define XFS_READDIR_H_
+
+int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core);
+int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core);
+int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core);
+int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
+ xfs_dinode_t *core);
+
+#endif /* XFS_READDIR_H_ */
diff --git a/core/fs/xfs/xfs_sb.h b/core/fs/xfs/xfs_sb.h
new file mode 100644
index 00000000..12024ab3
--- /dev/null
+++ b/core/fs/xfs/xfs_sb.h
@@ -0,0 +1,206 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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 the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef XFS_SB_H_
+#define XFS_SB_H_
+
+#include <stddef.h>
+
+#include <sys/types.h>
+
+typedef unsigned char uuid_t[16];
+
+/*
+ * Super block
+ * Fits into a sector-sized buffer at address 0 of each allocation group.
+ * Only the first of these is ever updated except during growfs.
+ */
+
+struct xfs_buf;
+struct xfs_mount;
+
+#define XFS_SB_MAGIC "XFSB" /* 'XFSB' */
+#define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */
+#define XFS_SB_VERSION_2 2 /* 6.2 - attributes */
+#define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */
+#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */
+#define XFS_SB_VERSION_NUMBITS 0x000f
+#define XFS_SB_VERSION_ALLFBITS 0xfff0
+#define XFS_SB_VERSION_SASHFBITS 0xf000
+#define XFS_SB_VERSION_REALFBITS 0x0ff0
+#define XFS_SB_VERSION_ATTRBIT 0x0010
+#define XFS_SB_VERSION_NLINKBIT 0x0020
+#define XFS_SB_VERSION_QUOTABIT 0x0040
+#define XFS_SB_VERSION_ALIGNBIT 0x0080
+#define XFS_SB_VERSION_DALIGNBIT 0x0100
+#define XFS_SB_VERSION_SHAREDBIT 0x0200
+#define XFS_SB_VERSION_LOGV2BIT 0x0400
+#define XFS_SB_VERSION_SECTORBIT 0x0800
+#define XFS_SB_VERSION_EXTFLGBIT 0x1000
+#define XFS_SB_VERSION_DIRV2BIT 0x2000
+#define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */
+#define XFS_SB_VERSION_MOREBITSBIT 0x8000
+#define XFS_SB_VERSION_OKSASHFBITS \
+ (XFS_SB_VERSION_EXTFLGBIT | \
+ XFS_SB_VERSION_DIRV2BIT | \
+ XFS_SB_VERSION_BORGBIT)
+#define XFS_SB_VERSION_OKREALFBITS \
+ (XFS_SB_VERSION_ATTRBIT | \
+ XFS_SB_VERSION_NLINKBIT | \
+ XFS_SB_VERSION_QUOTABIT | \
+ XFS_SB_VERSION_ALIGNBIT | \
+ XFS_SB_VERSION_DALIGNBIT | \
+ XFS_SB_VERSION_SHAREDBIT | \
+ XFS_SB_VERSION_LOGV2BIT | \
+ XFS_SB_VERSION_SECTORBIT | \
+ XFS_SB_VERSION_MOREBITSBIT)
+#define XFS_SB_VERSION_OKREALBITS \
+ (XFS_SB_VERSION_NUMBITS | \
+ XFS_SB_VERSION_OKREALFBITS | \
+ XFS_SB_VERSION_OKSASHFBITS)
+
+/*
+ * There are two words to hold XFS "feature" bits: the original
+ * word, sb_versionnum, and sb_features2. Whenever a bit is set in
+ * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set.
+ *
+ * These defines represent bits in sb_features2.
+ */
+#define XFS_SB_VERSION2_REALFBITS 0x00ffffff /* Mask: features */
+#define XFS_SB_VERSION2_RESERVED1BIT 0x00000001
+#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */
+#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004
+#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */
+#define XFS_SB_VERSION2_PARENTBIT 0x00000010 /* parent pointers */
+#define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32 bit project id */
+
+#define XFS_SB_VERSION2_OKREALFBITS \
+ (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
+ XFS_SB_VERSION2_ATTR2BIT | \
+ XFS_SB_VERSION2_PROJID32BIT)
+#define XFS_SB_VERSION2_OKSASHFBITS \
+ (0)
+#define XFS_SB_VERSION2_OKREALBITS \
+ (XFS_SB_VERSION2_OKREALFBITS | \
+ XFS_SB_VERSION2_OKSASHFBITS )
+
+/*
+ * Sequence number values for the fields.
+ */
+typedef enum {
+ XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS,
+ XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO,
+ XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS,
+ XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS,
+ XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE,
+ XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG,
+ XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG,
+ XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT,
+ XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO,
+ XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
+ XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
+ XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
+ XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2,
+ XFS_SBS_FIELDCOUNT
+} xfs_sb_field_t;
+
+/*
+ * Mask values, defined based on the xfs_sb_field_t values.
+ * Only define the ones we're using.
+ */
+#define XFS_SB_MVAL(x) (1LL << XFS_SBS_ ## x)
+#define XFS_SB_UUID XFS_SB_MVAL(UUID)
+#define XFS_SB_FNAME XFS_SB_MVAL(FNAME)
+#define XFS_SB_ROOTINO XFS_SB_MVAL(ROOTINO)
+#define XFS_SB_RBMINO XFS_SB_MVAL(RBMINO)
+#define XFS_SB_RSUMINO XFS_SB_MVAL(RSUMINO)
+#define XFS_SB_VERSIONNUM XFS_SB_MVAL(VERSIONNUM)
+#define XFS_SB_UQUOTINO XFS_SB_MVAL(UQUOTINO)
+#define XFS_SB_GQUOTINO XFS_SB_MVAL(GQUOTINO)
+#define XFS_SB_QFLAGS XFS_SB_MVAL(QFLAGS)
+#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN)
+#define XFS_SB_UNIT XFS_SB_MVAL(UNIT)
+#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH)
+#define XFS_SB_ICOUNT XFS_SB_MVAL(ICOUNT)
+#define XFS_SB_IFREE XFS_SB_MVAL(IFREE)
+#define XFS_SB_FDBLOCKS XFS_SB_MVAL(FDBLOCKS)
+#define XFS_SB_FEATURES2 XFS_SB_MVAL(FEATURES2)
+#define XFS_SB_BAD_FEATURES2 XFS_SB_MVAL(BAD_FEATURES2)
+#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT)
+#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1)
+#define XFS_SB_MOD_BITS \
+ (XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
+ XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
+ XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
+ XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \
+ XFS_SB_BAD_FEATURES2)
+
+
+/*
+ * Misc. Flags - warning - these will be cleared by xfs_repair unless
+ * a feature bit is set when the flag is used.
+ */
+#define XFS_SBF_NOFLAGS 0x00 /* no flags set */
+#define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */
+
+/*
+ * define max. shared version we can interoperate with
+ */
+#define XFS_SB_MAX_SHARED_VN 0
+
+#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS)
+
+/*
+ * end of superblock version macros
+ */
+
+#define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
+#define XFS_BUF_TO_SBP(bp) ((xfs_dsb_t *)((bp)->b_addr))
+
+#define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d))
+#define XFS_DADDR_TO_FSB(mp,d) XFS_AGB_TO_FSB(mp, \
+ xfs_daddr_to_agno(mp,d), xfs_daddr_to_agbno(mp,d))
+#define XFS_FSB_TO_DADDR(mp,fsbno) XFS_AGB_TO_DADDR(mp, \
+ XFS_FSB_TO_AGNO(mp,fsbno), XFS_FSB_TO_AGBNO(mp,fsbno))
+
+/*
+ * File system sector to basic block conversions.
+ */
+#define XFS_FSS_TO_BB(mp,sec) ((sec) << (mp)->m_sectbb_log)
+
+/*
+ * File system block to basic block conversions.
+ */
+#define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log)
+#define XFS_BB_TO_FSB(mp,bb) \
+ (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log)
+#define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log)
+
+/*
+ * File system block to byte conversions.
+ */
+#define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) << (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSB(mp,b) \
+ ((((uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSBT(mp,b) (((uint64_t)(b)) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask)
+
+#endif /* XFS_SB_H_ */
diff --git a/core/fs/xfs/xfs_types.h b/core/fs/xfs/xfs_types.h
new file mode 100644
index 00000000..92808865
--- /dev/null
+++ b/core/fs/xfs/xfs_types.h
@@ -0,0 +1,135 @@
+/*
+ * Taken from Linux kernel tree (linux/fs/xfs)
+ *
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
+ *
+ * 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 the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef XFS_TYPES_H_
+#define XFS_TYPES_H_
+
+#include <stddef.h>
+
+#include <sys/types.h>
+
+typedef enum { B_FALSE,B_TRUE } boolean_t;
+typedef uint32_t prid_t; /* project ID */
+typedef uint32_t inst_t; /* an instruction */
+
+typedef int64_t xfs_off_t; /* <file offset> type */
+typedef unsigned long long xfs_ino_t; /* <inode> type */
+typedef int64_t xfs_daddr_t; /* <disk address> type */
+typedef char * xfs_caddr_t; /* <core address> type */
+typedef uint32_t xfs_dev_t;
+typedef uint32_t xfs_nlink_t;
+
+/* __psint_t is the same size as a pointer */
+typedef int32_t __psint_t;
+typedef uint32_t __psunsigned_t;
+
+typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */
+typedef uint32_t xfs_extlen_t; /* extent length in blocks */
+typedef uint32_t xfs_agnumber_t; /* allocation group number */
+typedef int32_t xfs_extnum_t; /* # of extents in a file */
+typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */
+typedef int64_t xfs_fsize_t; /* bytes in a file */
+typedef uint64_t xfs_ufsize_t; /* unsigned bytes in a file */
+
+typedef int32_t xfs_suminfo_t; /* type of bitmap summary info */
+typedef int32_t xfs_rtword_t; /* word type for bitmap manipulations */
+
+typedef int64_t xfs_lsn_t; /* log sequence number */
+typedef int32_t xfs_tid_t; /* transaction identifier */
+
+typedef uint32_t xfs_dablk_t; /* dir/attr block number (in file) */
+typedef uint32_t xfs_dahash_t; /* dir/attr hash value */
+
+/*
+ * These types are 64 bits on disk but are either 32 or 64 bits in memory.
+ * Disk based types:
+ */
+typedef uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */
+typedef uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */
+typedef uint64_t xfs_drtbno_t; /* extent (block) in realtime area */
+typedef uint64_t xfs_dfiloff_t; /* block number in a file */
+typedef uint64_t xfs_dfilblks_t; /* number of blocks in a file */
+
+/*
+ * Memory based types are conditional.
+ */
+typedef uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */
+typedef uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */
+typedef uint64_t xfs_rtblock_t; /* extent (block) in realtime area */
+typedef int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */
+
+typedef uint64_t xfs_fileoff_t; /* block number in a file */
+typedef int64_t xfs_sfiloff_t; /* signed block number in a file */
+typedef uint64_t xfs_filblks_t; /* number of blocks in a file */
+
+/*
+ * Null values for the types.
+ */
+#define NULLDFSBNO ((xfs_dfsbno_t)-1)
+#define NULLDRFSBNO ((xfs_drfsbno_t)-1)
+#define NULLDRTBNO ((xfs_drtbno_t)-1)
+#define NULLDFILOFF ((xfs_dfiloff_t)-1)
+
+#define NULLFSBLOCK ((xfs_fsblock_t)-1)
+#define NULLRFSBLOCK ((xfs_rfsblock_t)-1)
+#define NULLRTBLOCK ((xfs_rtblock_t)-1)
+#define NULLFILEOFF ((xfs_fileoff_t)-1)
+
+#define NULLAGBLOCK ((xfs_agblock_t)-1)
+#define NULLAGNUMBER ((xfs_agnumber_t)-1)
+#define NULLEXTNUM ((xfs_extnum_t)-1)
+
+#define NULLCOMMITLSN ((xfs_lsn_t)-1)
+
+/*
+ * Max values for extlen, extnum, aextnum.
+ */
+#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */
+#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */
+#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */
+
+/*
+ * Min numbers of data/attr fork btree root pointers.
+ */
+#define MINDBTPTRS 3
+#define MINABTPTRS 2
+
+/*
+ * MAXNAMELEN is the length (including the terminating null) of
+ * the longest permissible file (component) name.
+ */
+#define MAXNAMELEN 256
+
+typedef enum {
+ XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi
+} xfs_lookup_t;
+
+typedef enum {
+ XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
+ XFS_BTNUM_MAX
+} xfs_btnum_t;
+
+struct xfs_name {
+ const unsigned char *name;
+ int len;
+};
+
+#endif /* XFS_TYPES_H_ */
diff --git a/core/graphics.c b/core/graphics.c
index bdf48a85..834372ff 100644
--- a/core/graphics.c
+++ b/core/graphics.c
@@ -25,12 +25,13 @@
#include "bios.h"
#include "graphics.h"
-uint8_t UsingVGA = 0;
+__export uint8_t UsingVGA = 0;
uint16_t VGAPos; /* Pointer into VGA memory */
-uint16_t *VGAFilePtr; /* Pointer into VGAFileBuf */
+__export uint16_t *VGAFilePtr; /* Pointer into VGAFileBuf */
+__export uint16_t VGAFontSize = 16; /* Defaults to 16 byte font */
-char VGAFileBuf[VGA_FILE_BUF_SIZE]; /* Unmangled VGA image name */
-char VGAFileMBuf[FILENAME_MAX]; /* Mangled VGA image name */
+__export char VGAFileBuf[VGA_FILE_BUF_SIZE]; /* Unmangled VGA image name */
+__export char VGAFileMBuf[FILENAME_MAX]; /* Mangled VGA image name */
static uint8_t VGARowBuffer[640 + 80]; /* Decompression buffer */
static uint8_t VGAPlaneBuffer[(640/8) * 4]; /* Plane buffers */
@@ -229,7 +230,7 @@ static void outputvga(const void *in, void *out)
/*
* Display a graphical splash screen.
*/
-void vgadisplayfile(FILE *_fd)
+__export void vgadisplayfile(FILE *_fd)
{
char *p;
int size;
@@ -304,7 +305,7 @@ void vgadisplayfile(FILE *_fd)
/*
* Disable VGA graphics.
*/
-void syslinux_force_text_mode(void)
+__export void syslinux_force_text_mode(void)
{
com32sys_t ireg, oreg;
@@ -356,7 +357,7 @@ void vgashowcursor(void)
vgacursorcommon('_');
}
-void using_vga(uint8_t vga, uint16_t pix_cols, uint16_t pix_rows)
+__export void using_vga(uint8_t vga, uint16_t pix_cols, uint16_t pix_rows)
{
UsingVGA = vga;
GXPixCols = pix_cols;
diff --git a/core/highmem.inc b/core/highmem.inc
deleted file mode 100644
index ea386ffc..00000000
--- a/core/highmem.inc
+++ /dev/null
@@ -1,158 +0,0 @@
-;; -----------------------------------------------------------------------
-;;
-;; Copyright 1994-2008 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
-;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
-;; Boston MA 02111-1307, USA; either version 2 of the License, or
-;; (at your option) any later version; incorporated herein by reference.
-;;
-;; -----------------------------------------------------------------------
-
-;;
-;; highmem.inc
-;;
-;; Probe for the size of high memory. This can be overridden by a
-;; mem= command on the command line while booting a new kernel.
-;;
-
- section .text16
-
-;
-; This is set up as a subroutine; it will set up the global variable
-; HighMemSize. All registers are preserved.
-;
-highmemsize:
- push es
- pushfd
- pushad
-
- push cs
- pop es
-
-;
-; First, try INT 15:E820 (get BIOS memory map)
-;
-; Note: we may have to scan this multiple times, because some (daft) BIOSes
-; report main memory as multiple contiguous ranges...
-;
-get_e820:
- mov dword [E820Max],-(1 << 20) ; Max amount of high memory
- mov dword [E820Mem],(1 << 20) ; End of detected high memory
-.start_over:
- mov di,E820Buf
- xor ax,ax
- mov cx,10
- rep stosw ; Clear buffer
- xor ebx,ebx ; Start with first record
- jmp short .do_e820 ; Skip "at end" check first time!
-.int_loop: and ebx,ebx ; If we're back at beginning...
- jz .e820_done ; ... we're done
-.do_e820: mov eax,0000E820h
- mov edx,534D4150h ; "SMAP" backwards
- xor ecx,ecx
- mov cl,20 ; ECX <- 20 (size of buffer)
- mov di,E820Buf
- int 15h
- jnc .no_carry
- ; If carry, ebx == 0 means error, ebx != 0 means we're done
- and ebx,ebx
- jnz .e820_done
- jmp no_e820
-.no_carry:
- cmp eax,534D4150h
- jne no_e820
- cmp cx,20
- jb no_e820
-
-;
-; Look for a memory block starting at <= 1 MB and continuing upward
-;
- cmp dword [E820Buf+4], byte 0
- ja .int_loop ; Start >= 4 GB?
- mov eax, [E820Buf]
- cmp dword [E820Buf+16],1
- je .is_ram ; Is it memory?
- ;
- ; Non-memory range. Remember this as a limit; some BIOSes get the length
- ; of primary RAM incorrect!
- ;
-.not_ram:
- cmp eax, (1 << 20)
- jb .int_loop ; Starts in lowmem region
- cmp eax,[E820Max]
- jae .int_loop ; Already above limit
- mov [E820Max],eax ; Set limit
- jmp .int_loop
-
-.is_ram:
- cmp eax,[E820Mem]
- ja .int_loop ; Not contiguous with our starting point
- add eax,[E820Buf+8]
- jc .overflow
- cmp dword [E820Buf+12],0
- je .nooverflow
-.overflow:
- or eax,-1
-.nooverflow:
- cmp eax,[E820Mem]
- jbe .int_loop ; All is below our baseline
- mov [E820Mem],eax
- jmp .start_over ; Start over in case we find an adjacent range
-
-.e820_done:
- mov eax,[E820Mem]
- cmp eax,[E820Max]
- jna .not_limited
- mov eax,[E820Max]
-.not_limited:
- cmp eax,(1 << 20)
- ja got_highmem ; Did we actually find memory?
- ; otherwise fall through
-
-;
-; INT 15:E820 failed. Try INT 15:E801.
-;
-no_e820:
- mov ax,0e801h ; Query high memory (semi-recent)
- int 15h
- jc no_e801
- cmp ax,3c00h
- ja no_e801 ; > 3C00h something's wrong with this call
- jb e801_hole ; If memory hole we can only use low part
-
- mov ax,bx
- shl eax,16 ; 64K chunks
- add eax,(16 << 20) ; Add first 16M
- jmp short got_highmem
-
-;
-; INT 15:E801 failed. Try INT 15:88.
-;
-no_e801:
- mov ah,88h ; Query high memory (oldest)
- int 15h
- cmp ax,14*1024 ; Don't trust memory >15M
- jna e801_hole
- mov ax,14*1024
-e801_hole:
- and eax,0ffffh
- shl eax,10 ; Convert from kilobytes
- add eax,(1 << 20) ; First megabyte
-got_highmem:
-%if HIGHMEM_SLOP != 0
- sub eax,HIGHMEM_SLOP
-%endif
- mov [HighMemSize],eax
- popad
- popfd
- pop es
- ret ; Done!
-
- section .bss16
- alignb 4
-E820Buf resd 5 ; INT 15:E820 data buffer
-E820Mem resd 1 ; Memory detected by E820
-E820Max resd 1 ; Is E820 memory capped?
-; HighMemSize is defined in com32.inc
diff --git a/core/idle.c b/core/idle.c
index 3f57393b..9514df88 100644
--- a/core/idle.c
+++ b/core/idle.c
@@ -25,7 +25,7 @@
#define TICKS_TO_IDLE 4 /* Also in idle.inc */
extern uint32_t _IdleTimer;
-extern uint16_t NoHalt;
+__export uint16_t NoHalt = 0;
int (*idle_hook_func)(void);
@@ -34,7 +34,7 @@ void reset_idle(void)
_IdleTimer = jiffies();
}
-void __idle(void)
+__export void __idle(void)
{
if (jiffies() - _IdleTimer < TICKS_TO_IDLE)
return;
diff --git a/core/idle.inc b/core/idle.inc
index c93d1773..65d6c5c8 100644
--- a/core/idle.inc
+++ b/core/idle.inc
@@ -22,7 +22,7 @@ reset_idle:
sti ; Guard against BIOS/PXE brokenness...
ret
- global do_idle
+ global do_idle:function hidden
do_idle:
push eax
push ds
@@ -72,10 +72,8 @@ do_idle:
section .data16
alignz 4
- global _IdleTimer
+ global _IdleTimer:data hidden
_IdleTimer dd 0
- global NoHalt
-NoHalt dw 0
hlt_err db 'ERROR: idle with IF=0', CR, LF, 0
diff --git a/core/include/bios.h b/core/include/bios.h
index 49a75f5a..9334c41a 100644
--- a/core/include/bios.h
+++ b/core/include/bios.h
@@ -35,6 +35,16 @@
#define BIOS_magic 0x0472 /* BIOS reset magic */
#define BIOS_vidrows 0x0484 /* Number of screen rows */
+static inline uint16_t bios_fbm(void)
+{
+ return *(volatile uint16_t *)BIOS_fbm;
+}
+
+static inline void set_bios_fbm(uint16_t mem)
+{
+ *(volatile uint16_t *)BIOS_fbm = mem;
+}
+
#define serial_buf_size 4096
#define IO_DELAY_PORT 0x80 /* Invalid port (we hope!) */
diff --git a/core/include/fs.h b/core/include/fs.h
index 4d6c18be..554dc97f 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -101,9 +101,9 @@ struct inode {
const char *name; /* Name, valid for generic path search only */
int refcnt;
int mode; /* FILE , DIR or SYMLINK */
- uint32_t size;
- uint32_t blocks; /* How many blocks the file take */
- uint32_t ino; /* Inode number */
+ uint64_t size;
+ uint64_t blocks; /* How many blocks the file take */
+ uint64_t ino; /* Inode number */
uint32_t atime; /* Access time */
uint32_t mtime; /* Modify time */
uint32_t ctime; /* Create time */
@@ -182,7 +182,6 @@ static inline struct file *handle_to_file(uint16_t handle)
return handle ? &files[handle-1] : NULL;
}
-#define PATH_DEFAULT "/boot/syslinux/:/boot/"
extern char *PATH;
/* fs.c */
diff --git a/core/isolinux.asm b/core/isolinux.asm
index 39e5e5c5..673134b0 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -68,6 +68,7 @@ trackbuf resb trackbufsize ; Track buffer goes here
; Some of these are touched before the whole image
; is loaded. DO NOT move this to .bss16/.uibss.
section .earlybss
+ global BIOSName
alignb 4
FirstSecSum resd 1 ; Checksum of bytes 64-2048
ImageDwords resd 1 ; isolinux.bin size, dwords
@@ -1207,24 +1208,15 @@ debug_tracer: pushad
%endif ; DEBUG_TRACERS
section .bss16
- global CmdOptPtr, KbdMap
alignb 4
ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
KernelExtPtr resw 1 ; During search, final null pointer
-CmdOptPtr resw 1 ; Pointer to first option on cmd line
-KbdFlags resb 1 ; Check for keyboard escapes
FuncFlag resb 1 ; Escape sequences received from keyboard
KernelType resb 1 ; Kernel type, from vkernel, if known
-KbdMap resb 256 ; Keyboard map
global KernelName
KernelName resb FILENAME_MAX ; Mangled name for kernel
- section .config
- global PXERetry
-PXERetry dw 0 ; Extra PXE retries
section .data16
- global SerialNotice
-SerialNotice db 1 ; Only print this once
global IPAppends, numIPAppends
%if IS_PXELINUX
extern IPOption
diff --git a/core/kaboom.c b/core/kaboom.c
index 726ca2be..0b025dd0 100644
--- a/core/kaboom.c
+++ b/core/kaboom.c
@@ -18,7 +18,7 @@ __noreturn __bad_SEG(const volatile void *p)
#undef kaboom
-__noreturn _kaboom(void)
+__export __noreturn _kaboom(void)
{
extern void kaboom(void);
call16(kaboom, &zero_regs, NULL);
diff --git a/core/kernel.inc b/core/kernel.inc
index 245cd6db..5e1c7a39 100644
--- a/core/kernel.inc
+++ b/core/kernel.inc
@@ -62,9 +62,6 @@ linux_fdctab resb 12
cmd_line_here equ $ ; F800 Should be out of the way
endstruc
- global cmd_line
-cmd_line equ core_real_mode + cmd_line_here
-
;
; Old kernel command line signature
;
diff --git a/core/layout.inc b/core/layout.inc
index 24843923..be797ede 100644
--- a/core/layout.inc
+++ b/core/layout.inc
@@ -52,7 +52,6 @@ LATEBSS_START equ 0B800h
;
; 32-bit stack layout
;
- global STACK32_LEN
STACK32_LEN equ 64*1024
section .stack nobits write align=4096
@@ -135,7 +134,7 @@ serial_buf_size equ 4096 ; Should be a power of 2
;
extern xfer_buf_seg
section .xfer_buf write nobits align=65536
- global core_xfer_buf
+ global core_xfer_buf:data hidden
core_xfer_buf resb 65536
;
@@ -145,7 +144,7 @@ core_xfer_buf resb 65536
;
extern real_mode_seg
section .real_mode write nobits align=65536
- global core_real_mode
+ global core_real_mode:data hidden
core_real_mode resb 65536
comboot_seg equ real_mode_seg ; COMBOOT image loading zone
diff --git a/core/ldlinux.asm b/core/ldlinux.asm
index a2f859d0..a1f96b77 100644
--- a/core/ldlinux.asm
+++ b/core/ldlinux.asm
@@ -39,6 +39,8 @@ ROOT_FS_OPS:
dd ext2_fs_ops
extern ntfs_fs_ops
dd ntfs_fs_ops
+ extern xfs_fs_ops
+ dd xfs_fs_ops
extern btrfs_fs_ops
dd btrfs_fs_ops
dd 0
diff --git a/core/localboot.c b/core/localboot.c
index 03ac866d..0f4b5820 100644
--- a/core/localboot.c
+++ b/core/localboot.c
@@ -34,7 +34,7 @@ extern void local_boot16(void);
* Boot a specified local disk. AX specifies the BIOS disk number; or
* -1 in case we should execute INT 18h ("next device.")
*/
-void local_boot(int16_t ax)
+__export void local_boot(int16_t ax)
{
com32sys_t ireg, oreg;
int i;
diff --git a/core/localboot.inc b/core/localboot.inc
index ce971ae4..b7840427 100644
--- a/core/localboot.inc
+++ b/core/localboot.inc
@@ -1,5 +1,5 @@
section .text16
- global local_boot16
+ global local_boot16:function hidden
local_boot16:
mov cx,0
mov ss,cx
diff --git a/core/mem/free.c b/core/mem/free.c
index b0eb7146..6fb8cfdd 100644
--- a/core/mem/free.c
+++ b/core/mem/free.c
@@ -81,7 +81,7 @@ void bios_free(void *ptr)
__free_block(ah);
}
-void free(void *ptr)
+__export void free(void *ptr)
{
dprintf("free(%p) @ %p\n", ptr, __builtin_return_address(0));
diff --git a/core/mem/malloc.c b/core/mem/malloc.c
index fe8af5ad..a3d6b45d 100644
--- a/core/mem/malloc.c
+++ b/core/mem/malloc.c
@@ -96,12 +96,12 @@ static void *_malloc(size_t size, enum heap heap, malloc_tag_t tag)
return p;
}
-void *malloc(size_t size)
+__export void *malloc(size_t size)
{
return _malloc(size, HEAP_MAIN, MALLOC_CORE);
}
-void *lmalloc(size_t size)
+__export void *lmalloc(size_t size)
{
void *p;
@@ -217,12 +217,12 @@ void *bios_realloc(void *ptr, size_t size)
}
}
-void *realloc(void *ptr, size_t size)
+__export void *realloc(void *ptr, size_t size)
{
return firmware->mem->realloc(ptr, size);
}
-void *zalloc(size_t size)
+__export void *zalloc(size_t size)
{
void *ptr;
diff --git a/core/plaincon.c b/core/plaincon.c
index dfeb9784..8f8ca7ca 100644
--- a/core/plaincon.c
+++ b/core/plaincon.c
@@ -9,7 +9,7 @@
* Write a single character in AL to the console without
* mangling any registers; handle video pages correctly.
*/
-void writechr(char data)
+__export void writechr(char data)
{
com32sys_t ireg, oreg;
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index d927b2b2..95f76617 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -280,24 +280,15 @@ Kernel_EAX resd 1
Kernel_SI resw 1
section .bss16
- global CmdOptPtr, KbdMap
alignb 4
ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
KernelExtPtr resw 1 ; During search, final null pointer
-CmdOptPtrj resw 1 ; Pointer to first option on cmd line
-KbdFlags resb 1 ; Check for keyboard escapes
FuncFlag resb 1 ; Escape sequences received from keyboard
KernelType resb 1 ; Kernel type, from vkernel, if known
-KbdMap resb 256 ; Keyboard map
global KernelName
KernelName resb FILENAME_MAX ; Mangled name for kernel
- section .config
- global PXERetry
-PXERetry dw 0 ; Extra PXE retries
section .data16
- global SerialNotice
-SerialNotice db 1 ; Only print this once
extern IPOption
global IPAppends, numIPAppends
alignz 2
diff --git a/core/rawcon.c b/core/rawcon.c
index 1a52c954..92f0898a 100644
--- a/core/rawcon.c
+++ b/core/rawcon.c
@@ -10,7 +10,7 @@
#include "bios.h"
#include "graphics.h"
-void writechr(char data)
+__export void writechr(char data)
{
if (UsingVGA & 0x08)
syslinux_force_text_mode();
diff --git a/core/serirq.c b/core/serirq.c
index e0675c9a..e230b98d 100644
--- a/core/serirq.c
+++ b/core/serirq.c
@@ -123,7 +123,7 @@ static inline void install_irq_vectors(uint32_t *dst, int first)
}
}
-void sirq_install(void)
+__export void sirq_install(void)
{
char val, val2;
@@ -164,7 +164,7 @@ void sirq_install(void)
outb(0xA1, 0);
}
-void sirq_cleanup_nowipe(void)
+__export void sirq_cleanup_nowipe(void)
{
uint32_t *dst;
int i;
diff --git a/core/stack.inc b/core/stack.inc
index 788db647..838d6bab 100644
--- a/core/stack.inc
+++ b/core/stack.inc
@@ -38,7 +38,7 @@
section .data16
alignz 4
- global BaseStack
+ global BaseStack:data hidden
BaseStack dd StackHome ; ESP of the "home" stack pointer
dw 0 ; SS of the "home" stack pointer
diff --git a/core/timer.inc b/core/timer.inc
index 9f42fdf2..80647983 100644
--- a/core/timer.inc
+++ b/core/timer.inc
@@ -32,7 +32,7 @@ timer_init:
mov dword [BIOS_timer_hook],timer_irq
ret
- global bios_timer_cleanup
+ global bios_timer_cleanup:function hidden
bios_timer_cleanup:
; Unhook INT 1Ch
mov eax,[BIOS_timer_next]
@@ -43,18 +43,18 @@ bios_timer_cleanup:
; The specified frequency is 14.31818 MHz/12/65536; this turns out
; to be a period of 54.92542 ms, or 0x36.ece8(187c) hexadecimal.
;
- global timer_irq
+ global timer_irq:function hidden
timer_irq:
inc dword [cs:__jiffies]
add word [cs:__ms_timer_adj],0xece8
adc dword [cs:__ms_timer],0x36
jmp 0:0
- global BIOS_timer_next
+ global BIOS_timer_next:data hidden
BIOS_timer_next equ $-4
section .data16
alignz 4
- global __jiffies, __ms_timer
+ global __jiffies:data hidden, __ms_timer
__jiffies dd 0 ; Clock tick timer
__ms_timer dd 0 ; Millisecond timer
__ms_timer_adj dw 0 ; Millisecond timer correction factor