]> code.delx.au - refind/commitdiff
Added filesystem drivers.
authorsrs5694 <srs5694@users.sourceforge.net>
Sun, 20 May 2012 17:35:21 +0000 (13:35 -0400)
committersrs5694 <srs5694@users.sourceforge.net>
Sun, 20 May 2012 17:35:21 +0000 (13:35 -0400)
43 files changed:
filesystems/AutoGen.c [new file with mode: 0644]
filesystems/AutoGen.h [new file with mode: 0644]
filesystems/Doxyfile [new file with mode: 0644]
filesystems/LICENSE.txt [new file with mode: 0644]
filesystems/LICENSE_GPL.txt [new file with mode: 0644]
filesystems/Make.common [new file with mode: 0644]
filesystems/Makefile [new file with mode: 0644]
filesystems/VBoxFswParam.h [new file with mode: 0644]
filesystems/design.dox [new file with mode: 0644]
filesystems/fsw_base.h [new file with mode: 0644]
filesystems/fsw_core.c [new file with mode: 0644]
filesystems/fsw_core.h [new file with mode: 0644]
filesystems/fsw_efi.c [new file with mode: 0644]
filesystems/fsw_efi.h [new file with mode: 0644]
filesystems/fsw_efi_base.h [new file with mode: 0644]
filesystems/fsw_efi_lib.c [new file with mode: 0644]
filesystems/fsw_ext2.c [new file with mode: 0644]
filesystems/fsw_ext2.h [new file with mode: 0644]
filesystems/fsw_ext2_disk.h [new file with mode: 0644]
filesystems/fsw_hfs.c [new file with mode: 0644]
filesystems/fsw_hfs.h [new file with mode: 0644]
filesystems/fsw_iso9660.c [new file with mode: 0644]
filesystems/fsw_iso9660.h [new file with mode: 0644]
filesystems/fsw_lib.c [new file with mode: 0644]
filesystems/fsw_reiserfs.c [new file with mode: 0644]
filesystems/fsw_reiserfs.h [new file with mode: 0644]
filesystems/fsw_reiserfs_disk.h [new file with mode: 0644]
filesystems/fsw_strfunc.h [new file with mode: 0644]
filesystems/hfs_format.h [new file with mode: 0644]
filesystems/test/.svn/all-wcprops [new file with mode: 0644]
filesystems/test/.svn/entries [new file with mode: 0644]
filesystems/test/.svn/text-base/README.svn-base [new file with mode: 0644]
filesystems/test/.svn/text-base/fsw_posix.c.svn-base [new file with mode: 0644]
filesystems/test/.svn/text-base/fsw_posix.h.svn-base [new file with mode: 0644]
filesystems/test/.svn/text-base/fsw_posix_base.h.svn-base [new file with mode: 0644]
filesystems/test/.svn/text-base/lslr.c.svn-base [new file with mode: 0644]
filesystems/test/.svn/text-base/lsroot.c.svn-base [new file with mode: 0644]
filesystems/test/README [new file with mode: 0644]
filesystems/test/fsw_posix.c [new file with mode: 0644]
filesystems/test/fsw_posix.h [new file with mode: 0644]
filesystems/test/fsw_posix_base.h [new file with mode: 0644]
filesystems/test/lslr.c [new file with mode: 0644]
filesystems/test/lsroot.c [new file with mode: 0644]

diff --git a/filesystems/AutoGen.c b/filesystems/AutoGen.c
new file mode 100644 (file)
index 0000000..cc01832
--- /dev/null
@@ -0,0 +1,232 @@
+/**
+  DO NOT EDIT
+  FILE auto-generated
+  Module name:
+    AutoGen.c
+  Abstract:       Auto-generated AutoGen.c for building module or library.
+**/
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+// Guids
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileInfoGuid = { 0x09576E92, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemInfoGuid = { 0x09576E93, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = { 0xDB47D7D3, 0xFE81, 0x11D3, { 0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiMdePkgTokenSpaceGuid = { 0x914AEBE7, 0x4635, 0x459b, { 0xAA, 0x1C, 0x11, 0xE2, 0x19, 0xB0, 0x3A, 0x10 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventReadyToBootGuid = { 0x7CE88FB3, 0x4BD7, 0x4679, { 0x87, 0xA8, 0xA8, 0xD8, 0xDE, 0xE5, 0x0D, 0x2B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventLegacyBootGuid = { 0x2A571201, 0x4966, 0x47F6, { 0x8B, 0x86, 0xF3, 0x1E, 0x41, 0xF3, 0x2F, 0x10 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }};
+
+// Protocols
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDiskIoProtocolGuid = { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleFileSystemProtocolGuid = { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollation2ProtocolGuid = {0xa4c751fc, 0x23ae, 0x4c3e, { 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gMsgLogProtocolGuid = {0x511CE018, 0x0018, 0x4002, {0x20, 0x12, 0x17, 0x38, 0x05, 0x01, 0x02, 0x03 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextOutProtocolGuid = { 0x387477C2, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiFontProtocolGuid = {0xe9ca4775, 0x8657, 0x47fc, {0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x08, 0x43, 0x24}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUgaDrawProtocolGuid = { 0x982C298B, 0xF4FA, 0x41CB, { 0xB8, 0x38, 0x77, 0xAA, 0x68, 0x8F, 0xB8, 0x39 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+
+// Definition of PCDs used in this module
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang[5] = {101, 110, 103, 0 };
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang[7] = {101, 110, 45, 85, 83, 0 };
+
+// Definition of PCDs used in libraries
+
+#define _PCD_TOKEN_PcdDebugPrintErrorLevel  5U
+#define _PCD_VALUE_PcdDebugPrintErrorLevel  0x80000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel = _PCD_VALUE_PcdDebugPrintErrorLevel;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel;
+#define _PCD_GET_MODE_32_PcdDebugPrintErrorLevel  _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel
+//#define _PCD_SET_MODE_32_PcdDebugPrintErrorLevel  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDebugClearMemoryValue  10U
+#define _PCD_VALUE_PcdDebugClearMemoryValue  0xAFU
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue = _PCD_VALUE_PcdDebugClearMemoryValue;
+extern const  UINT8  _gPcd_FixedAtBuild_PcdDebugClearMemoryValue;
+#define _PCD_GET_MODE_8_PcdDebugClearMemoryValue  _gPcd_FixedAtBuild_PcdDebugClearMemoryValue
+//#define _PCD_SET_MODE_8_PcdDebugClearMemoryValue  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDebugPropertyMask  11U
+#define _PCD_VALUE_PcdDebugPropertyMask  0x0fU
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask = _PCD_VALUE_PcdDebugPropertyMask;
+extern const  UINT8  _gPcd_FixedAtBuild_PcdDebugPropertyMask;
+#define _PCD_GET_MODE_8_PcdDebugPropertyMask  _gPcd_FixedAtBuild_PcdDebugPropertyMask
+//#define _PCD_SET_MODE_8_PcdDebugPropertyMask  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumLinkedListLength  6U
+#define _PCD_VALUE_PcdMaximumLinkedListLength  1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength = _PCD_VALUE_PcdMaximumLinkedListLength;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumLinkedListLength;
+#define _PCD_GET_MODE_32_PcdMaximumLinkedListLength  _gPcd_FixedAtBuild_PcdMaximumLinkedListLength
+//#define _PCD_SET_MODE_32_PcdMaximumLinkedListLength  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumAsciiStringLength  7U
+#define _PCD_VALUE_PcdMaximumAsciiStringLength  1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength = _PCD_VALUE_PcdMaximumAsciiStringLength;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength;
+#define _PCD_GET_MODE_32_PcdMaximumAsciiStringLength  _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength
+//#define _PCD_SET_MODE_32_PcdMaximumAsciiStringLength  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumUnicodeStringLength  8U
+#define _PCD_VALUE_PcdMaximumUnicodeStringLength  1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength = _PCD_VALUE_PcdMaximumUnicodeStringLength;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength;
+#define _PCD_GET_MODE_32_PcdMaximumUnicodeStringLength  _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength
+//#define _PCD_SET_MODE_32_PcdMaximumUnicodeStringLength  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdVerifyNodeInList  9U
+#define _PCD_VALUE_PcdVerifyNodeInList  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList = _PCD_VALUE_PcdVerifyNodeInList;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdVerifyNodeInList;
+#define _PCD_GET_MODE_BOOL_PcdVerifyNodeInList  _gPcd_FixedAtBuild_PcdVerifyNodeInList
+//#define _PCD_SET_MODE_BOOL_PcdVerifyNodeInList  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDriverDiagnosticsDisable  12U
+#define _PCD_VALUE_PcdDriverDiagnosticsDisable  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable = _PCD_VALUE_PcdDriverDiagnosticsDisable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable;
+#define _PCD_GET_MODE_BOOL_PcdDriverDiagnosticsDisable  _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable
+//#define _PCD_SET_MODE_BOOL_PcdDriverDiagnosticsDisable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdComponentNameDisable  13U
+#define _PCD_VALUE_PcdComponentNameDisable  ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable = _PCD_VALUE_PcdComponentNameDisable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdComponentNameDisable;
+#define _PCD_GET_MODE_BOOL_PcdComponentNameDisable  _gPcd_FixedAtBuild_PcdComponentNameDisable
+//#define _PCD_SET_MODE_BOOL_PcdComponentNameDisable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDriverDiagnostics2Disable  14U
+#define _PCD_VALUE_PcdDriverDiagnostics2Disable  ((BOOLEAN)1U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable = _PCD_VALUE_PcdDriverDiagnostics2Disable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable;
+#define _PCD_GET_MODE_BOOL_PcdDriverDiagnostics2Disable  _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable
+//#define _PCD_SET_MODE_BOOL_PcdDriverDiagnostics2Disable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdComponentName2Disable  15U
+#define _PCD_VALUE_PcdComponentName2Disable  ((BOOLEAN)1U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable = _PCD_VALUE_PcdComponentName2Disable;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdComponentName2Disable;
+#define _PCD_GET_MODE_BOOL_PcdComponentName2Disable  _gPcd_FixedAtBuild_PcdComponentName2Disable
+//#define _PCD_SET_MODE_BOOL_PcdComponentName2Disable  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdUgaConsumeSupport  16U
+#define _PCD_VALUE_PcdUgaConsumeSupport  ((BOOLEAN)1U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport = _PCD_VALUE_PcdUgaConsumeSupport;
+extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdUgaConsumeSupport;
+#define _PCD_GET_MODE_BOOL_PcdUgaConsumeSupport  _gPcd_FixedAtBuild_PcdUgaConsumeSupport
+//#define _PCD_SET_MODE_BOOL_PcdUgaConsumeSupport  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdUefiLibMaxPrintBufferSize  17U
+#define _PCD_VALUE_PcdUefiLibMaxPrintBufferSize  320U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize = _PCD_VALUE_PcdUefiLibMaxPrintBufferSize;
+extern const  UINT32  _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize;
+#define _PCD_GET_MODE_32_PcdUefiLibMaxPrintBufferSize  _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize
+//#define _PCD_SET_MODE_32_PcdUefiLibMaxPrintBufferSize  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+
+EFI_STATUS
+EFIAPI
+UefiBootServicesTableLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+UefiRuntimeServicesTableLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+UefiLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+
+VOID
+EFIAPI
+ProcessLibraryConstructorList (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = UefiBootServicesTableLibConstructor (ImageHandle, SystemTable);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = UefiRuntimeServicesTableLibConstructor (ImageHandle, SystemTable);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = UefiLibConstructor (ImageHandle, SystemTable);
+  ASSERT_EFI_ERROR (Status);
+
+}
+
+
+
+VOID
+EFIAPI
+ProcessLibraryDestructorList (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+
+}
+
+const UINT32 _gUefiDriverRevision = 0x00020000U;
+const UINT32 _gDxeRevision = 0x00000000U;
+
+
+EFI_STATUS
+EFIAPI
+ProcessModuleEntryPointList (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+
+{
+  return fsw_efi_main (ImageHandle, SystemTable);
+}
+
+VOID
+EFIAPI
+ExitDriver (
+  IN EFI_STATUS  Status
+  )
+{
+  if (EFI_ERROR (Status)) {
+    ProcessLibraryDestructorList (gImageHandle, gST);
+  }
+  gBS->Exit (gImageHandle, Status, 0, NULL);
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gDriverUnloadImageCount = 0U;
+
+EFI_STATUS
+EFIAPI
+ProcessModuleUnloadList (
+  IN EFI_HANDLE        ImageHandle
+  )
+{
+  return EFI_SUCCESS;
+}
diff --git a/filesystems/AutoGen.h b/filesystems/AutoGen.h
new file mode 100644 (file)
index 0000000..28080cf
--- /dev/null
@@ -0,0 +1,54 @@
+/**
+  DO NOT EDIT
+  FILE auto-generated
+  Module name:
+    AutoGen.h
+  Abstract:       Auto-generated AutoGen.h for building module or library.
+**/
+
+#ifndef _AUTOGENH_B34E5765_2E02_4DAF_867F_7F40BE6FC33D
+#define _AUTOGENH_B34E5765_2E02_4DAF_867F_7F40BE6FC33D
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/PcdLib.h>
+
+// Definition of PCDs used in this module
+
+#define _PCD_TOKEN_PcdUefiVariableDefaultLang  18U
+#define _PCD_PATCHABLE_PcdUefiVariableDefaultLang_SIZE 5
+#define _PCD_VALUE_PcdUefiVariableDefaultLang  _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang
+extern const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang[5];
+#define _PCD_GET_MODE_PTR_PcdUefiVariableDefaultLang  _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang
+//#define _PCD_SET_MODE_PTR_PcdUefiVariableDefaultLang  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdUefiVariableDefaultPlatformLang  19U
+#define _PCD_PATCHABLE_PcdUefiVariableDefaultPlatformLang_SIZE 7
+#define _PCD_VALUE_PcdUefiVariableDefaultPlatformLang  _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang
+extern const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang[7];
+#define _PCD_GET_MODE_PTR_PcdUefiVariableDefaultPlatformLang  _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang
+//#define _PCD_SET_MODE_PTR_PcdUefiVariableDefaultPlatformLang  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+// Definition of PCDs used in libraries is in AutoGen.c
+
+
+EFI_STATUS
+EFIAPI
+fsw_efi_main (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/filesystems/Doxyfile b/filesystems/Doxyfile
new file mode 100644 (file)
index 0000000..15f4a3f
--- /dev/null
@@ -0,0 +1,277 @@
+# Doxyfile 1.4.7
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME           = "File System Wrapper"
+PROJECT_NUMBER         = 0.1
+OUTPUT_DIRECTORY       = doc
+CREATE_SUBDIRS         = NO
+OUTPUT_LANGUAGE        = English
+USE_WINDOWS_ENCODING   = NO
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = YES
+STRIP_FROM_PATH        = 
+STRIP_FROM_INC_PATH    = 
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = YES
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP         = NO
+INHERIT_DOCS           = YES
+SEPARATE_MEMBER_PAGES  = NO
+TAB_SIZE               = 8
+ALIASES                = 
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+BUILTIN_STL_SUPPORT    = NO
+DISTRIBUTE_GROUP_DOC   = NO
+SUBGROUPING            = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL            = YES
+EXTRACT_PRIVATE        = YES
+EXTRACT_STATIC         = YES
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = NO
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = NO
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = NO
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_BRIEF_DOCS        = NO
+SORT_BY_SCOPE_NAME     = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = YES
+SHOW_DIRECTORIES       = NO
+FILE_VERSION_FILTER    = 
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_NO_PARAMDOC       = NO
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           = 
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+#INPUT                  = /Users/chrisp/efi_toolkit/refit/fsw
+INPUT                  = .
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.d \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.idl \
+                         *.odl \
+                         *.cs \
+                         *.php \
+                         *.php3 \
+                         *.inc \
+                         *.m \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.C \
+                         *.CC \
+                         *.C++ \
+                         *.II \
+                         *.I++ \
+                         *.H \
+                         *.HH \
+                         *.H++ \
+                         *.CS \
+                         *.PHP \
+                         *.PHP3 \
+                         *.M \
+                         *.MM \
+                         *.PY
+RECURSIVE              = NO
+EXCLUDE                = 
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = 
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = *
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             = 
+INPUT_FILTER           = 
+FILTER_PATTERNS        = 
+FILTER_SOURCE_FILES    = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER         = YES
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION    = YES
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS              = NO
+VERBATIM_HEADERS       = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = NO
+COLS_IN_ALPHA_INDEX    = 5
+IGNORE_PREFIX          = 
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+CHM_FILE               = 
+HHC_LOCATION           = 
+GENERATE_CHI           = NO
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = NO
+TREEVIEW_WIDTH         = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = NO
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = NO
+USE_PDFLATEX           = NO
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_SCHEMA             = 
+XML_DTD                = 
+XML_PROGRAMLISTING     = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF   = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX = 
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = YES
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = 
+INCLUDE_FILE_PATTERNS  = 
+PREDEFINED             = HOST_EFI HOST_POSIX
+EXPAND_AS_DEFINED      = VOLSTRUCTNAME \
+                         DNODESTRUCTNAME
+SKIP_FUNCTION_MACROS   = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       = 
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS         = NO
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = YES
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+GROUP_GRAPHS           = YES
+UML_LOOK               = NO
+TEMPLATE_RELATIONS     = NO
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+CALL_GRAPH             = NO
+CALLER_GRAPH           = NO
+GRAPHICAL_HIERARCHY    = YES
+DIRECTORY_GRAPH        = YES
+DOT_IMAGE_FORMAT       = png
+DOT_PATH               = /Applications/Graphviz.app/Contents/MacOS
+DOTFILE_DIRS           = 
+MAX_DOT_GRAPH_WIDTH    = 1024
+MAX_DOT_GRAPH_HEIGHT   = 1024
+MAX_DOT_GRAPH_DEPTH    = 1000
+DOT_TRANSPARENT        = YES
+DOT_MULTI_TARGETS      = NO
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+SEARCHENGINE           = NO
diff --git a/filesystems/LICENSE.txt b/filesystems/LICENSE.txt
new file mode 100644 (file)
index 0000000..68b38fd
--- /dev/null
@@ -0,0 +1,26 @@
+The below was written by Christoph Phisterer with respect to his original
+code. Since then, Oracle and the Clover team have modified the original
+files, and added the HFS+ driver, which bears Oracle and Apple copyrights
+and is released under terms of the GNU GPL.
+
+ File System Wrapper License
+=============================
+
+The various parts of the File System Wrapper source code come from
+different sources and may carry different licenses. Here's a quick
+account of the situation:
+
+ * The core code was written from scratch and is covered by a
+   BSD-style license.
+
+ * The EFI host driver was written from scratch, possibly using code
+   from the TianoCore project and Intel's EFI Application Toolkit. It
+   is covered by a BSD-style license.
+
+ * The ext2 and reiserfs file system drivers use definitions from the
+   Linux kernel source. The actual code was written from scratch,
+   using multiple sources for reference. These drivers are covered by
+   the GNU GPL.
+
+For more details, see each file's boilerplate comment. The full text
+of the GNU GPL is in the file LICENSE_GPL.txt.
diff --git a/filesystems/LICENSE_GPL.txt b/filesystems/LICENSE_GPL.txt
new file mode 100644 (file)
index 0000000..d60c31a
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will 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 to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/filesystems/Make.common b/filesystems/Make.common
new file mode 100644 (file)
index 0000000..99b165a
--- /dev/null
@@ -0,0 +1,141 @@
+#
+# filesystems/Make.common
+# Build control file for rEFInd's EFI filesystem drivers
+#
+
+SRCDIR = .
+
+VPATH = $(SRCDIR)
+
+HOSTARCH        = $(shell uname -m | sed s,i[3456789]86,ia32,)
+ARCH            := $(HOSTARCH)
+
+ifeq ($(ARCH),ia32)
+  ARCHDIR = Ia32
+  FILENAME_CODE = ia32
+endif
+
+ifeq ($(ARCH),x86_64)
+  ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -mcmodel=large
+  ARCHDIR = X64
+  FILENAME_CODE = x64
+endif
+
+EDK2BASE = /usr/local/UDK2010/MyWorkSpace
+
+# Below file defines TARGET (RELEASE or DEBUG), TARGET_ARCH (X64 or IA32), and TOOL_CHAIN_TAG (GCC45, GCC46, or GCC47)
+include $(EDK2BASE)/Conf/target.txt
+
+EFIINC = $(EDK2BASE)/MdePkg/Include/
+EFILIB          = $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library
+ALL_EFILIBS     = $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib/OUTPUT/BaseDebugPrintErrorLevelLib.lib \
+                 $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/BasePrintLib/BasePrintLib/OUTPUT/BasePrintLib.lib \
+                 $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/BasePcdLibNull/BasePcdLibNull/OUTPUT/BasePcdLibNull.lib \
+                 $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut/OUTPUT/UefiDebugLibConOut.lib \
+                 $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/BaseLib/BaseLib/OUTPUT/BaseLib.lib \
+                 $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/BaseMemoryLib/BaseMemoryLib/OUTPUT/BaseMemoryLib.lib \
+                 $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib \
+                 $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib/OUTPUT/UefiMemoryAllocationLib.lib \
+                 $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib/OUTPUT/UefiDevicePathLib.lib \
+                 $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib \
+                 $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiLib/UefiLib/OUTPUT/UefiLib.lib \
+                 $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint/OUTPUT/UefiDriverEntryPoint.lib
+
+OS             = $(shell uname -s)
+CPPFLAGS        = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/Protocol -I$(EFIINC)/$(ARCHDIR) -DNO_BUILTIN_VA_FUNCS
+
+INCLUDE_DIRS    = -I $(EDK2BASE)/MdePkg \
+                  -I $(EDK2BASE)/MdePkg/Include \
+                  -I $(EDK2BASE)/MdePkg/Include/$(ARCHDIR) \
+                 -I $(EDK2BASE)/IntelFrameworkModulePkg \
+                 -I $(EDK2BASE)/IntelFrameworkModulePkg/Include \
+
+FSW_NAMES       = fsw_efi fsw_core fsw_efi_lib fsw_lib AutoGen
+OBJS            = $(FSW_NAMES:=.o)
+#DRIVERNAME      = ext2
+BUILDME          = $(DRIVERNAME)_$(FILENAME_CODE).efi
+
+OPTIMFLAGS      = -fno-strict-aliasing -mno-red-zone -Wno-address -Os
+#OPTIMFLAGS      = -fno-strict-aliasing -mno-red-zone -Wno-address -mcmodel=large -Os 
+DEBUGFLAGS      = -Wall -Werror -Wno-missing-braces -Wno-array-bounds -ffunction-sections -fdata-sections -c -include AutoGen.h
+#CFLAGS          = $(ARCH3264) $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS)
+CFLAGS          = $(ARCH3264) $(OPTIMFLAGS) -g -fshort-wchar -fno-stack-protector $(DEBUGFLAGS)
+ASFLAGS         = $(ARCH3264)
+LDFLAGS         = -nostdlib -znocombreloc -dp --entry=fsw_efi_main
+
+prefix          = /usr/bin/
+CC              = $(prefix)gcc
+AS              = $(prefix)as
+LD              = $(prefix)ld
+AR              = $(prefix)ar
+RANLIB          = $(prefix)ranlib
+OBJCOPY         = $(prefix)objcopy
+GENFW           = $(EDK2BASE)/BaseTools/BinWrappers/PosixLike/GenFw
+
+ifeq ($(ARCH),ia64)
+  # EFI specs allows only lower floating point partition to be used
+  CFLAGS       += -frename-registers -mfixed-range=f32-f127
+endif
+
+ifeq ($(ARCH),x86_64)
+#  CFLAGS += -DEFI_FUNCTION_WRAPPER
+#  CPPFLAGS += -DEFIX64
+
+  ARCH3264 = -m64
+endif
+
+ifeq ($(ARCH),ia32)
+#  CPPFLAGS += -DEFI32
+
+  ARCH3264 = -m32
+
+endif
+
+
+LDSCRIPT = $(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script
+
+LDFLAGS         = -nostdlib -n -q --gc-sections --script=$(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script \
+                  --entry _ModuleEntryPoint -u _ModuleEntryPoint
+LIBS            = $(shell $(CC) $(ARCH3264) -print-libgcc-file-name)
+
+%.o: %.c
+       $(CC) $(CPPFLAGS) $(ARCH_C_FLAGS) $(CFLAGS) $(INCLUDE_DIRS) -DFSTYPE=$(DRIVERNAME) -c $< -o $@
+
+FORMAT   = efi-bsdrv-$(ARCH)
+
+
+ifneq (,$(filter %.efi,$(BUILDME)))
+
+SHLIB_TARGET = $(subst .efi,.lib,$(BUILDME))
+DLL_TARGET = $(subst .efi,.dll,$(BUILDME))
+
+all: $(BUILDME)
+
+$(DLL_TARGET): $(OBJS) fsw_$(DRIVERNAME).o
+       $(LD) -o $(DRIVERNAME)_$(FILENAME_CODE).dll $(LDFLAGS) --start-group $(ALL_EFILIBS) $(OBJS) fsw_$(DRIVERNAME).o --end-group
+
+$(BUILDME): $(DLL_TARGET)
+       $(OBJCOPY) --strip-unneeded $(DLL_TARGET)
+       $(OBJCOPY) $(DLL_TARGET)
+       $(GENFW) -e UEFI_DRIVER -o $(BUILDME) $(DLL_TARGET)
+       mkdir -p ../fs-drivers
+       cp $(BUILDME) ../fs-drivers
+#      $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \
+#                 -j .rela -j .reloc --target=$(FORMAT) $< $@
+
+endif
+
+# rules for libraries
+
+ifneq (,$(filter %.a,$(BUILDME)))
+
+endif
+
+# utility rules
+
+clean:
+       rm -f $(BUILDME) *~ *.so $(OBJS) *.efi *.lib *.dll
+
+
+
+# EOF
diff --git a/filesystems/Makefile b/filesystems/Makefile
new file mode 100644 (file)
index 0000000..d4f0b6c
--- /dev/null
@@ -0,0 +1,39 @@
+# meta-Makefile for rEFInd filesystem drivers
+#
+# Most of the functionality is in Make.common; this Makefile merely
+# deletes critical temporary files and calls Make.common with the
+# name of the driver to be built. This is done because of a dependency
+# in the fsw_efi.c file on the filesystem type; this file must be
+# recompiled for each new filesystem built.
+
+INSTALL_DIR = /boot/efi/EFI/refind/drivers
+
+all:   ext2fs reiserfs iso9660 hfs
+
+ext2fs:
+       rm -f fsw_efi.o
+       make DRIVERNAME=ext2 -f Make.common
+
+reiserfs:
+       rm -f fsw_efi.o
+       make DRIVERNAME=reiserfs -f Make.common
+
+iso9660:
+       rm -f fsw_efi.o
+       make DRIVERNAME=iso9660 -f Make.common
+
+hfs:
+       rm -f fsw_efi.o
+       make DRIVERNAME=hfs -f Make.common
+
+# utility rules
+
+clean:
+       rm -f *~ *.so *.o *.efi *.dll err.txt ext2*.txt hfs*.txt iso9660*.txt reiserfs*.txt
+
+
+install:
+       mkdir -p $(INSTALL_DIR)
+       cp *.efi $(INSTALL_DIR)
+
+# DO NOT DELETE
diff --git a/filesystems/VBoxFswParam.h b/filesystems/VBoxFswParam.h
new file mode 100644 (file)
index 0000000..0f20c9e
--- /dev/null
@@ -0,0 +1,69 @@
+/* $Id: VBoxFswParam.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * VBoxFswParam.h
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef VBOXFSPARAM_H
+#define VBOXFSPARAM_H
+/*
+ * Here is common declarations for EDK<->EDK2 compatibility
+ */
+# include <Base.h>
+# include <Uefi.h>
+# include <Library/DebugLib.h>
+# include <Library/BaseLib.h>
+# include <Protocol/DriverBinding.h>
+# include <Library/BaseMemoryLib.h>
+# include <Library/UefiRuntimeServicesTableLib.h>
+# include <Library/UefiDriverEntryPoint.h>
+# include <Library/UefiBootServicesTableLib.h>
+# include <Library/MemoryAllocationLib.h>
+# include <Library/DevicePathLib.h>
+# include <Protocol/DevicePathFromText.h>
+# include <Protocol/DevicePathToText.h>
+# include <Protocol/DebugPort.h>
+# include <Protocol/DebugSupport.h>
+# include <Library/PrintLib.h>
+# include <Library/UefiLib.h>
+# include <Protocol/SimpleFileSystem.h>
+# include <Protocol/BlockIo.h>
+# include <Protocol/DiskIo.h>
+# include <Guid/FileSystemInfo.h>
+# include <Guid/FileInfo.h>
+# include <Guid/FileSystemVolumeLabelInfo.h>
+# include <Protocol/ComponentName.h>
+
+# define BS gBS
+# define PROTO_NAME(x) gEfi ## x ## Guid
+# define GUID_NAME(x) gEfi ## x ## Guid
+
+# define EFI_FILE_HANDLE_REVISION EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
+# define SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO  SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL
+# define EFI_FILE_SYSTEM_VOLUME_LABEL_INFO EFI_FILE_SYSTEM_VOLUME_LABEL
+# define EFI_SIGNATURE_32(a, b, c, d) SIGNATURE_32(a, b, c, d)
+# define DivU64x32(x,y,z) DivU64x32((x),(y))
+
+
+INTN CompareGuidEdk1(
+  IN EFI_GUID     *Guid1,
+  IN EFI_GUID     *Guid2
+                     );
+
+//#define CompareGuid(x, y) CompareGuidEdk1((x),(y))
+# define HOST_EFI 1
+//# define FSW_DEBUG_LEVEL 3
+
+int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len);
+#endif
diff --git a/filesystems/design.dox b/filesystems/design.dox
new file mode 100644 (file)
index 0000000..df7baf1
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * \file design.dox
+ * Documentation title page with design information
+ */
+
+
+/**
+\mainpage File System Wrapper Documentation
+
+Welcome to the documentation for FSW. This doxygen-generated documentation
+is intended for developers that either want to integrate FSW into their
+own project or want to write additional file system drivers.
+
+\section goals Design Goals
+
+File System Wrapper wants to provide reusable, read-only file system drivers
+for a range of common file systems. Reusability is achieved through a common
+abstraction layer (called the "core"), which serves as the API for the host
+environment driver. Once the required glue code is written for a host
+environment, that host has access to all file system types implemented by FSW,
+with no code to be written per file system type.
+
+Why read-only? There are a range of reasons why FSW only provides read-only
+access:
+
+- Read-only drivers are much easier to write than read-write drivers.
+- Write access isn't easily abstracted in an OS-independent way because
+  of more delicate buffer I/O handling requirements and features like
+  journalling.
+- There is no risk of destroying data on the disk.
+- Having read access is much better than having no access at all.
+  (Read-only drivers for several file systems can be written in the time
+  it would take to develop a read-write driver for just one file system.)
+- Boot loaders only need read access in most cases.
+
+\section model Object and Data Model
+
+\subsection main_objects Main Objects
+
+There are three main "objects" that FSW works with: volume, dnode, and shandle.
+
+The fsw_volume structure keeps the information that applies to a file
+system volume as a whole. Most importantly, it keeps pointers to the host driver
+and file system driver dispatch tables, which are used by the core to call
+the appropriate functions.
+
+The fsw_dnode structure represents a "directory node", that is any file-like
+object in the file system: regular files, directories, symbolic links as well
+as special files like device nodes. When compared with Unix-style file systems,
+a dnode is very similar to an inode, but it retains some essential information
+from the directory: the canonical name and the parent directory. FSW requires that
+a dnode is uniquely identified by an integer number (currently 32 bit in size).
+Inode numbers can be used for this purpose, non-Unix file systems will have to
+come up with a unique number in some way.
+
+The fsw_shandle structure is used to access file data ("storage handle").
+A dnode only represents the file as such and doesn't offer access to its data.
+An shandle is linked to a certain dnode, but there may be several shandles per
+dnode. The shandle stores a file position pointer (byte offset) that can be changed
+at will. With the current design, an shandle is also used for directory iteration,
+even if the file system stores directory information in a central tree structure.
+
+\subsection disk_access Disk Data Access
+
+Data on the disk is accessed in blocks, addressed by a sequential number starting
+at zero. The block size to use can be set by the file system driver. FSW supports
+two separate block sizes: the "physical block size" is used when accessing the disk,
+the "logical block size" is used when accessing a file's data. For most file
+systems, these two are identical, but there may be some where the file allocation
+block size is larger than the sector or block size used to store metadata. (FAT
+comes to mind as an example.)
+
+For accessing the actual file data, the file system driver doesn't handle the
+disk I/O, but merely returns information about the mapping from file logical
+blocks to disk physical blocks in the fsw_extent structure. This allows host OS
+buffer mechanisms to be used for file data. In special cases, like tail-packing,
+fragments or compressed file systems, the file system driver can return file data
+in an allocated buffer.
+
+\subsection data_hooks Data Extension Hooks
+
+File system specific data can be stored by extending the fsw_volume and fsw_dnode
+structures. The core code uses the structure sizes stored in the fsw_fstype_table
+to allocate memory for these structures. The fsw_shandle and fsw_extent structures
+are not designed to be extended.
+
+Host specific data must be stored in separate structures private to the host
+environment driver. The fsw_volume structure provides a host_data variable to
+store a pointer. The fsw_dnode structure has no such field, because it is assumed
+that all actions regarding dnodes are initiated on the host side and so the
+host-specific private structure is known.
+
+\section callconv Calling Conventions
+
+All functions that can fail return a status code in a fsw_status_t. This type is an
+integer. A boolean test yields true if there was an error and false if the function
+executed successfully, i.e. success is signalled by a 0 return value.
+
+Functions that return data do so either by filling a structure passed in by the caller,
+or by allocating a structure on the heap and returning a pointer through a
+double-indirect parameter. A returned object pointer is the last parameter in the
+parameter list.
+
+(More to be written about specific conventions for dnodes, shandles, strings.)
+
+*/
diff --git a/filesystems/fsw_base.h b/filesystems/fsw_base.h
new file mode 100644 (file)
index 0000000..0d5e7ba
--- /dev/null
@@ -0,0 +1,179 @@
+/* $Id: fsw_base.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_base.h - Base definitions switch.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_BASE_H_
+#define _FSW_BASE_H_
+//#define HOST_EFI 1
+#define VBOX
+
+#ifdef VBOX
+#include "VBoxFswParam.h"
+#endif
+
+//#include <Protocol/MsgLog.h> 
+
+#ifndef FSW_DEBUG_LEVEL
+/**
+ * Global debugging level. Can be set locally for the scope of a single
+ * file by defining the macro before fsw_base.h is included.
+ */
+#define FSW_DEBUG_LEVEL 0
+#endif
+
+
+#ifdef HOST_EFI
+#include "fsw_efi_base.h"
+#endif
+
+#ifdef HOST_POSIX
+#include "fsw_posix_base.h"
+#endif
+
+// message printing
+
+#if FSW_DEBUG_LEVEL >= 1
+#define FSW_MSG_ASSERT(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_ASSERT(params)
+#endif
+
+#if FSW_DEBUG_LEVEL >= 2
+#define FSW_MSG_DEBUG(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_DEBUG(params)
+#endif
+
+#if FSW_DEBUG_LEVEL >= 3
+#define FSW_MSG_DEBUGV(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_DEBUGV(params)
+#endif
+
+
+// Documentation for system-dependent defines
+
+/**
+ * \typedef fsw_s8
+ * Signed 8-bit integer.
+ */
+
+/**
+ * \typedef fsw_u8
+ * Unsigned 8-bit integer.
+ */
+
+/**
+ * \typedef fsw_s16
+ * Signed 16-bit integer.
+ */
+
+/**
+ * \typedef fsw_u16
+ * Unsigned 16-bit integer.
+ */
+
+/**
+ * \typedef fsw_s32
+ * Signed 32-bit integer.
+ */
+
+/**
+ * \typedef fsw_u32
+ * Unsigned 32-bit integer.
+ */
+
+/**
+ * \typedef fsw_s64
+ * Signed 64-bit integer.
+ */
+
+/**
+ * \typedef fsw_u64
+ * Unsigned 64-bit integer.
+ */
+
+
+/**
+ * \def fsw_alloc(size,ptrptr)
+ * Allocate memory on the heap. This function or macro allocates \a size
+ * bytes of memory using host-specific methods. The address of the
+ * allocated memory block is stored into the pointer variable pointed
+ * to by \a ptrptr. A status code is returned; FSW_SUCCESS if the block
+ * was allocated or FSW_OUT_OF_MEMORY if there is not enough memory
+ * to allocated the requested block.
+ */
+
+/**
+ * \def fsw_free(ptr)
+ * Release allocated memory. This function or macro returns an allocated
+ * memory block to the heap for reuse. Does not return a status.
+ */
+
+/**
+ * \def fsw_memcpy(dest,src,size)
+ * Copies a block of memory from \a src to \a dest. The two memory blocks
+ * must not overlap, or the result of the operation will be undefined.
+ * Does not return a status.
+ */
+
+/**
+ * \def fsw_memeq(dest,src,size)
+ * Compares two blocks of memory for equality. Returns boolean true if the
+ * memory blocks are equal, boolean false if they are different.
+ */
+
+/**
+ * \def fsw_memzero(dest,size)
+ * Initializes a block of memory with zeros. Does not return a status.
+ */
+
+
+#endif
diff --git a/filesystems/fsw_core.c b/filesystems/fsw_core.c
new file mode 100644 (file)
index 0000000..64d70d7
--- /dev/null
@@ -0,0 +1,932 @@
+/* $Id: fsw_core.c 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_core.c - Core file system wrapper abstraction layer code.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_core.h"
+
+
+// functions
+
+static void fsw_blockcache_free(struct fsw_volume *vol);
+
+#define MAX_CACHE_LEVEL (5)
+
+
+/**
+ * Mount a volume with a given file system driver. This function is called by the
+ * host driver to make a volume accessible. The file system driver to use is specified
+ * by a pointer to its dispatch table. The file system driver will look at the
+ * data on the volume to determine if it can read the format. If the volume is found
+ * unsuitable, FSW_UNSUPPORTED is returned.
+ *
+ * If this function returns FSW_SUCCESS, *vol_out points at a valid volume data
+ * structure. The caller must release it later by calling fsw_unmount.
+ *
+ * If this function returns an error status, the caller only needs to clean up its
+ * own buffers that may have been allocated through the read_block interface.
+ */
+
+fsw_status_t fsw_mount(void *host_data,
+                       struct fsw_host_table *host_table,
+                       struct fsw_fstype_table *fstype_table,
+                       struct fsw_volume **vol_out)
+{
+    fsw_status_t    status;
+    struct fsw_volume *vol;
+
+    // allocate memory for the structure
+    status = fsw_alloc_zero(fstype_table->volume_struct_size, (void **)&vol);
+    if (status)
+        return status;
+
+    // initialize fields
+    vol->phys_blocksize = 512;
+    vol->log_blocksize  = 512;
+    vol->label.type     = FSW_STRING_TYPE_EMPTY;
+    vol->host_data      = host_data;
+    vol->host_table     = host_table;
+    vol->fstype_table   = fstype_table;
+    vol->host_string_type = host_table->native_string_type;
+
+    // let the fs driver mount the file system
+    status = vol->fstype_table->volume_mount(vol);
+    if (status)
+        goto errorexit;
+
+    // TODO: anything else?
+
+    *vol_out = vol;
+    return FSW_SUCCESS;
+
+errorexit:
+    fsw_unmount(vol);
+    return status;
+}
+
+/**
+ * Unmount a volume by releasing all memory associated with it. This function is
+ * called by the host driver when a volume is no longer needed. It is also called
+ * by the core after a failed mount to clean up any allocated memory.
+ *
+ * Note that all dnodes must have been released before calling this function.
+ */
+
+void fsw_unmount(struct fsw_volume *vol)
+{
+    if (vol->root)
+        fsw_dnode_release(vol->root);
+    // TODO: check that no other dnodes are still around
+
+    vol->fstype_table->volume_free(vol);
+
+    fsw_blockcache_free(vol);
+    fsw_strfree(&vol->label);
+    fsw_free(vol);
+}
+
+/**
+ * Get in-depth information on the volume. This function can be called by the host
+ * driver to get additional information on the volume.
+ */
+
+fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb)
+{
+    return vol->fstype_table->volume_stat(vol, sb);
+}
+
+/**
+ * Set the physical and logical block sizes of the volume. This functions is called by
+ * the file system driver to announce the block sizes it wants to use for accessing
+ * the disk (physical) and for addressing file contents (logical).
+ * Usually both sizes will be the same but there may be file systems that need to access
+ * metadata at a smaller block size than the allocation unit for files.
+ *
+ * Calling this function causes the block cache to be dropped. All pointers returned
+ * from fsw_block_get become invalid. This function should only be called while
+ * mounting the file system, not as a part of file access operations.
+ *
+ * Both sizes are measured in bytes, must be powers of 2, and must not be smaller
+ * than 512 bytes. The logical block size cannot be smaller than the physical block size.
+ */
+
+void fsw_set_blocksize(struct fsw_volume *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize)
+{
+    // TODO: Check the sizes. Both must be powers of 2. log_blocksize must not be smaller than
+    //  phys_blocksize.
+
+    // drop core block cache if present
+    fsw_blockcache_free(vol);
+
+    // signal host driver to drop caches etc.
+    vol->host_table->change_blocksize(vol,
+                                      vol->phys_blocksize, vol->log_blocksize,
+                                      phys_blocksize, log_blocksize);
+
+    vol->phys_blocksize = phys_blocksize;
+    vol->log_blocksize = log_blocksize;
+}
+
+/**
+ * Get a block of data from the disk. This function is called by the file system driver
+ * or by core functions. It calls through to the host driver's device access routine.
+ * Given a physical block number, it reads the block into memory (or fetches it from the
+ * block cache) and returns the address of the memory buffer. The caller should provide
+ * an indication of how important the block is in the cache_level parameter. Blocks with
+ * a low level are purged first. Some suggestions for cache levels:
+ *
+ *  - 0: File data
+ *  - 1: Directory data, symlink data
+ *  - 2: File system metadata
+ *  - 3..5: File system metadata with a high rate of access
+ *
+ * If this function returns successfully, the returned data pointer is valid until the
+ * caller calls fsw_block_release.
+ */
+
+fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fsw_u32 cache_level, void **buffer_out)
+{
+    fsw_status_t    status;
+    fsw_u32         i, discard_level, new_bcache_size;
+    struct fsw_blockcache *new_bcache;
+
+    // TODO: allow the host driver to do its own caching; just call through if
+    //  the appropriate function pointers are set
+
+    if (cache_level > MAX_CACHE_LEVEL)
+        cache_level = MAX_CACHE_LEVEL;
+
+    // check block cache
+    for (i = 0; i < vol->bcache_size; i++) {
+        if (vol->bcache[i].phys_bno == phys_bno) {
+            // cache hit!
+            if (vol->bcache[i].cache_level < cache_level)
+                vol->bcache[i].cache_level = cache_level;  // promote the entry
+            vol->bcache[i].refcount++;
+            *buffer_out = vol->bcache[i].data;
+            return FSW_SUCCESS;
+        }
+    }
+
+    // find a free entry in the cache table
+    for (i = 0; i < vol->bcache_size; i++) {
+        if (vol->bcache[i].phys_bno == (fsw_u32)FSW_INVALID_BNO)
+            break;
+    }
+    if (i >= vol->bcache_size) {
+        for (discard_level = 0; discard_level <= MAX_CACHE_LEVEL; discard_level++) {
+            for (i = 0; i < vol->bcache_size; i++) {
+                if (vol->bcache[i].refcount == 0 && vol->bcache[i].cache_level <= discard_level)
+                    break;
+            }
+            if (i < vol->bcache_size)
+                break;
+        }
+    }
+    if (i >= vol->bcache_size) {
+        // enlarge / create the cache
+        if (vol->bcache_size < 16)
+            new_bcache_size = 16;
+        else
+            new_bcache_size = vol->bcache_size << 1;
+        status = fsw_alloc(new_bcache_size * sizeof(struct fsw_blockcache), &new_bcache);
+        if (status)
+            return status;
+        if (vol->bcache_size > 0)
+            fsw_memcpy(new_bcache, vol->bcache, vol->bcache_size * sizeof(struct fsw_blockcache));
+        for (i = vol->bcache_size; i < new_bcache_size; i++) {
+            new_bcache[i].refcount = 0;
+            new_bcache[i].cache_level = 0;
+            new_bcache[i].phys_bno = (fsw_u32)FSW_INVALID_BNO;
+            new_bcache[i].data = NULL;
+        }
+        i = vol->bcache_size;
+
+        // switch caches
+        if (vol->bcache != NULL)
+            fsw_free(vol->bcache);
+        vol->bcache = new_bcache;
+        vol->bcache_size = new_bcache_size;
+    }
+    vol->bcache[i].phys_bno = (fsw_u32)FSW_INVALID_BNO;
+
+    // read the data
+    if (vol->bcache[i].data == NULL) {
+        status = fsw_alloc(vol->phys_blocksize, &vol->bcache[i].data);
+        if (status)
+            return status;
+    }
+    status = vol->host_table->read_block(vol, phys_bno, vol->bcache[i].data);
+    if (status)
+        return status;
+
+    vol->bcache[i].phys_bno = phys_bno;
+    vol->bcache[i].cache_level = cache_level;
+    vol->bcache[i].refcount = 1;
+    *buffer_out = vol->bcache[i].data;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Releases a disk block. This function must be called to release disk blocks returned
+ * from fsw_block_get.
+ */
+
+void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, void *buffer)
+{
+    fsw_u32 i;
+
+    // TODO: allow the host driver to do its own caching; just call through if
+    //  the appropriate function pointers are set
+
+    // update block cache
+    for (i = 0; i < vol->bcache_size; i++) {
+        if (vol->bcache[i].phys_bno == phys_bno && vol->bcache[i].refcount > 0)
+            vol->bcache[i].refcount--;
+    }
+}
+
+/**
+ * Release the block cache. Called internally when changing block sizes and when
+ * unmounting the volume. It frees all data occupied by the generic block cache.
+ */
+
+static void fsw_blockcache_free(struct fsw_volume *vol)
+{
+    fsw_u32 i;
+
+    for (i = 0; i < vol->bcache_size; i++) {
+        if (vol->bcache[i].data != NULL)
+            fsw_free(vol->bcache[i].data);
+    }
+    if (vol->bcache != NULL) {
+        fsw_free(vol->bcache);
+        vol->bcache = NULL;
+    }
+    vol->bcache_size = 0;
+}
+
+/**
+ * Add a new dnode to the list of known dnodes. This internal function is used when a
+ * dnode is created to add it to the dnode list that is used to search for existing
+ * dnodes by id.
+ */
+
+static void fsw_dnode_register(struct fsw_volume *vol, struct fsw_dnode *dno)
+{
+    dno->next = vol->dnode_head;
+    if (vol->dnode_head != NULL)
+        vol->dnode_head->prev = dno;
+    dno->prev = NULL;
+    vol->dnode_head = dno;
+}
+
+/**
+ * Create a dnode representing the root directory. This function is called by the file system
+ * driver while mounting the file system. The root directory is special because it has no parent
+ * dnode, its name is defined to be empty, and its type is also fixed. Otherwise, this functions
+ * behaves in the same way as fsw_dnode_create.
+ */
+
+fsw_status_t fsw_dnode_create_root(struct fsw_volume *vol, fsw_u32 dnode_id, struct fsw_dnode **dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_dnode *dno;
+
+    // allocate memory for the structure
+    status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
+    if (status)
+        return status;
+
+    // fill the structure
+    dno->vol = vol;
+    dno->parent = NULL;
+    dno->dnode_id = dnode_id;
+    dno->type = FSW_DNODE_TYPE_DIR;
+    dno->refcount = 1;
+    dno->name.type = FSW_STRING_TYPE_EMPTY;
+    // TODO: instead, call a function to create an empty string in the native string type
+
+    fsw_dnode_register(vol, dno);
+
+    *dno_out = dno;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Create a new dnode representing a file system object. This function is called by
+ * the file system driver in response to directory lookup or read requests. Note that
+ * if there already is a dnode with the given dnode_id on record, then no new object
+ * is created. Instead, the existing dnode is returned and its reference count
+ * increased. All other parameters are ignored in this case.
+ *
+ * The type passed into this function may be FSW_DNODE_TYPE_UNKNOWN. It is sufficient
+ * to fill the type field during the dnode_fill call.
+ *
+ * The name parameter must describe a string with the object's name. A copy will be
+ * stored in the dnode structure for future reference. The name will not be used to
+ * shortcut directory lookups, but may be used to reconstruct paths.
+ *
+ * If the function returns successfully, *dno_out contains a pointer to the dnode
+ * that must be released by the caller with fsw_dnode_release.
+ */
+
+fsw_status_t fsw_dnode_create(struct fsw_dnode *parent_dno, fsw_u32 dnode_id, int type,
+                              struct fsw_string *name, struct fsw_dnode **dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_volume *vol = parent_dno->vol;
+    struct fsw_dnode *dno;
+
+    // check if we already have a dnode with the same id
+    for (dno = vol->dnode_head; dno; dno = dno->next) {
+        if (dno->dnode_id == dnode_id) {
+            fsw_dnode_retain(dno);
+            *dno_out = dno;
+            return FSW_SUCCESS;
+        }
+    }
+
+    // allocate memory for the structure
+    status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
+    if (status)
+        return status;
+
+    // fill the structure
+    dno->vol = vol;
+    dno->parent = parent_dno;
+    fsw_dnode_retain(dno->parent);
+    dno->dnode_id = dnode_id;
+    dno->type = type;
+    dno->refcount = 1;
+    status = fsw_strdup_coerce(&dno->name, vol->host_table->native_string_type, name);
+    if (status) {
+        fsw_free(dno);
+        return status;
+    }
+
+    fsw_dnode_register(vol, dno);
+
+    *dno_out = dno;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Increases the reference count of a dnode. This must be balanced with
+ * fsw_dnode_release calls. Note that some dnode functions return a retained
+ * dnode pointer to their caller.
+ */
+
+void fsw_dnode_retain(struct fsw_dnode *dno)
+{
+    dno->refcount++;
+}
+
+/**
+ * Release a dnode pointer, deallocating it if this was the last reference.
+ * This function decrements the reference counter of the dnode. If the counter
+ * reaches zero, the dnode is freed. Since the parent dnode is released
+ * during that process, this function may cause it to be freed, too.
+ */
+
+void fsw_dnode_release(struct fsw_dnode *dno)
+{
+    struct fsw_volume *vol = dno->vol;
+    struct fsw_dnode *parent_dno;
+
+    dno->refcount--;
+
+    if (dno->refcount == 0) {
+        parent_dno = dno->parent;
+
+        // de-register from volume's list
+        if (dno->next)
+            dno->next->prev = dno->prev;
+        if (dno->prev)
+            dno->prev->next = dno->next;
+        if (vol->dnode_head == dno)
+            vol->dnode_head = dno->next;
+
+        // run fstype-specific cleanup
+        vol->fstype_table->dnode_free(vol, dno);
+
+        fsw_strfree(&dno->name);
+        fsw_free(dno);
+
+        // release our pointer to the parent, possibly deallocating it, too
+        if (parent_dno)
+            fsw_dnode_release(parent_dno);
+    }
+}
+
+/**
+ * Get full information about a dnode from disk. This function is called by the host
+ * driver as well as by the core functions. Some file systems defer reading full
+ * information on a dnode until it is actually needed (i.e. separation between
+ * directory and inode information). This function makes sure that all information
+ * is available in the dnode structure. The following fields may not have a correct
+ * value until fsw_dnode_fill has been called:
+ *
+ * type, size
+ */
+
+fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno)
+{
+    // TODO: check a flag right here, call fstype's dnode_fill only once per dnode
+
+    return dno->vol->fstype_table->dnode_fill(dno->vol, dno);
+}
+
+/**
+ * Get extended information about a dnode. This function can be called by the host
+ * driver to get a full compliment of information about a dnode in addition to the
+ * fields of the fsw_dnode structure itself.
+ *
+ * Some data requires host-specific conversion to be useful (i.e. timestamps) and
+ * will be passed to callback functions instead of being written into the structure.
+ * These callbacks must be filled in by the caller.
+ */
+
+fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb)
+{
+    fsw_status_t    status;
+
+    status = fsw_dnode_fill(dno);
+    if (status)
+        return status;
+
+    sb->used_bytes = 0;
+    status = dno->vol->fstype_table->dnode_stat(dno->vol, dno, sb);
+    if (!status && !sb->used_bytes)
+        sb->used_bytes = FSW_U64_DIV(dno->size + dno->vol->log_blocksize - 1, dno->vol->log_blocksize);
+    return status;
+}
+
+/**
+ * Lookup a directory entry by name. This function is called by the host driver.
+ * Given a directory dnode and a file name, it looks up the named entry in the
+ * directory.
+ *
+ * If the dnode is not a directory, the call will fail. The caller is responsible for
+ * resolving symbolic links before calling this function.
+ *
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
+                              struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+
+    status = fsw_dnode_fill(dno);
+    if (status)
+        return status;
+    if (dno->type != FSW_DNODE_TYPE_DIR)
+        return FSW_UNSUPPORTED;
+
+    return dno->vol->fstype_table->dir_lookup(dno->vol, dno, lookup_name, child_dno_out);
+}
+
+/**
+ * Find a file system object by path. This function is called by the host driver.
+ * Given a directory dnode and a relative or absolute path, it walks the directory
+ * tree until it finds the target dnode. If an intermediate node turns out to be
+ * a symlink, it is resolved automatically. If the target node is a symlink, it
+ * is not resolved.
+ *
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
+                                   struct fsw_string *lookup_path, char separator,
+                                   struct fsw_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_volume *vol = dno->vol;
+    struct fsw_dnode *child_dno = NULL;
+    struct fsw_string lookup_name;
+    struct fsw_string remaining_path;
+    int             root_if_empty;
+
+    remaining_path = *lookup_path;
+    fsw_dnode_retain(dno);
+
+    // loop over the path
+    for (root_if_empty = 1; fsw_strlen(&remaining_path) > 0; root_if_empty = 0) {
+        // parse next path component
+        fsw_strsplit(&lookup_name, &remaining_path, separator);
+
+        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: split into %d '%s' and %d '%s'\n"),
+                       lookup_name.len, lookup_name.data,
+                       remaining_path.len, remaining_path.data));
+
+        if (fsw_strlen(&lookup_name) == 0) {        // empty path component
+            if (root_if_empty)
+                child_dno = vol->root;
+            else
+                child_dno = dno;
+            fsw_dnode_retain(child_dno);
+
+        } else {
+            // do an actual directory lookup
+
+            // ensure we have full information
+            status = fsw_dnode_fill(dno);
+            if (status)
+                goto errorexit;
+
+            // resolve symlink if necessary
+            if (dno->type == FSW_DNODE_TYPE_SYMLINK) {
+                status = fsw_dnode_resolve(dno, &child_dno);
+                if (status)
+                    goto errorexit;
+
+                // symlink target becomes the new dno
+                fsw_dnode_release(dno);
+                dno = child_dno;   // is already retained
+                child_dno = NULL;
+
+                // ensure we have full information
+                status = fsw_dnode_fill(dno);
+                if (status)
+                    goto errorexit;
+            }
+
+            // make sure we operate on a directory
+            if (dno->type != FSW_DNODE_TYPE_DIR) {
+                return FSW_UNSUPPORTED;
+                goto errorexit;
+            }
+
+            // check special paths
+            if (fsw_streq_cstr(&lookup_name, ".")) {    // self directory
+                child_dno = dno;
+                fsw_dnode_retain(child_dno);
+
+            } else if (fsw_streq_cstr(&lookup_name, "..")) {   // parent directory
+                if (dno->parent == NULL) {
+                    // We cannot go up from the root directory. Caution: Certain apps like the EFI shell
+                    // rely on this behaviour!
+                    status = FSW_NOT_FOUND;
+                    goto errorexit;
+                }
+                child_dno = dno->parent;
+                fsw_dnode_retain(child_dno);
+
+            } else {
+                // do an actual lookup
+                status = vol->fstype_table->dir_lookup(vol, dno, &lookup_name, &child_dno);
+                if (status)
+                    goto errorexit;
+            }
+        }
+
+        // child_dno becomes the new dno
+        fsw_dnode_release(dno);
+        dno = child_dno;   // is already retained
+        child_dno = NULL;
+
+        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: now at inode %d\n"), dno->dnode_id));
+    }
+
+    *child_dno_out = dno;
+    return FSW_SUCCESS;
+
+errorexit:
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: leaving with error %d\n"), status));
+    fsw_dnode_release(dno);
+    if (child_dno != NULL)
+        fsw_dnode_release(child_dno);
+    return status;
+}
+
+/**
+ * Get the next directory item in sequential order. This function is called by the
+ * host driver to read the complete contents of a directory in sequential (file system
+ * defined) order. Calling this function returns the next entry. Iteration state is
+ * kept by a shandle on the directory's dnode. The caller must set up the shandle
+ * when starting the iteration.
+ *
+ * When the end of the directory is reached, this function returns FSW_NOT_FOUND.
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the next directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_dnode *dno = shand->dnode;
+    fsw_u64         saved_pos;
+
+    if (dno->type != FSW_DNODE_TYPE_DIR)
+        return FSW_UNSUPPORTED;
+
+    saved_pos = shand->pos;
+    status = dno->vol->fstype_table->dir_read(dno->vol, dno, shand, child_dno_out);
+    if (status)
+        shand->pos = saved_pos;
+    return status;
+}
+
+/**
+ * Read the target path of a symbolic link. This function is called by the host driver
+ * to read the "content" of a symbolic link, that is the relative or absolute path
+ * it points to.
+ *
+ * If the function returns FSW_SUCCESS, the string handle provided by the caller is
+ * filled with a string in the host's preferred encoding. The caller is responsible
+ * for calling fsw_strfree on the string.
+ */
+
+fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *target_name)
+{
+    fsw_status_t    status;
+
+    status = fsw_dnode_fill(dno);
+    if (status)
+        return status;
+    if (dno->type != FSW_DNODE_TYPE_SYMLINK)
+        return FSW_UNSUPPORTED;
+
+    return dno->vol->fstype_table->readlink(dno->vol, dno, target_name);
+}
+
+/**
+ * Read the target path of a symbolic link by accessing file data. This function can
+ * be called by the file system driver if the file system stores the target path
+ * as normal file data. This function will open an shandle, read the whole content
+ * of the file into a buffer, and build a string from that. Currently the encoding
+ * for the string is fixed as FSW_STRING_TYPE_ISO88591.
+ *
+ * If the function returns FSW_SUCCESS, the string handle provided by the caller is
+ * filled with a string in the host's preferred encoding. The caller is responsible
+ * for calling fsw_strfree on the string.
+ */
+
+fsw_status_t fsw_dnode_readlink_data(struct fsw_dnode *dno, struct fsw_string *link_target)
+{
+    fsw_status_t    status;
+    struct fsw_shandle shand;
+    fsw_u32         buffer_size;
+    char            buffer[FSW_PATH_MAX];
+
+    struct fsw_string s;
+
+    if (dno->size > FSW_PATH_MAX)
+        return FSW_VOLUME_CORRUPTED;
+
+    s.type = FSW_STRING_TYPE_ISO88591;
+    s.size = s.len = (int)dno->size;
+    s.data = buffer;
+
+    // open shandle and read the data
+    status = fsw_shandle_open(dno, &shand);
+    if (status)
+        return status;
+    buffer_size = (fsw_u32)s.size;
+    status = fsw_shandle_read(&shand, &buffer_size, buffer);
+    fsw_shandle_close(&shand);
+    if (status)
+        return status;
+    if ((int)buffer_size < s.size)
+        return FSW_VOLUME_CORRUPTED;
+
+    status = fsw_strdup_coerce(link_target, dno->vol->host_string_type, &s);
+    return status;
+}
+
+/**
+ * Resolve a symbolic link. This function can be called by the host driver to make
+ * sure the a dnode is fully resolved instead of pointing at a symlink. If the dnode
+ * passed in is not a symlink, it is returned unmodified.
+ *
+ * Note that absolute paths will be resolved relative to the root directory of the
+ * volume. If the host is an operating system with its own VFS layer, it should
+ * resolve symlinks on its own.
+ *
+ * If the function returns FSW_SUCCESS, *target_dno_out points at a dnode that is
+ * not a symlink. The caller is responsible for calling fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_string target_name;
+    struct fsw_dnode *target_dno;
+
+    fsw_dnode_retain(dno);
+
+    while (1) {
+        // get full information
+        status = fsw_dnode_fill(dno);
+        if (status)
+            goto errorexit;
+        if (dno->type != FSW_DNODE_TYPE_SYMLINK) {
+            // found a non-symlink target, return it
+            *target_dno_out = dno;
+            return FSW_SUCCESS;
+        }
+        if (dno->parent == NULL) {    // safety measure, cannot happen in theory
+            status = FSW_NOT_FOUND;
+            goto errorexit;
+        }
+
+        // read the link's target
+        status = fsw_dnode_readlink(dno, &target_name);
+        if (status)
+            goto errorexit;
+
+        // resolve it
+        status = fsw_dnode_lookup_path(dno->parent, &target_name, '/', &target_dno);
+        fsw_strfree(&target_name);
+        if (status)
+            goto errorexit;
+
+        // target_dno becomes the new dno
+        fsw_dnode_release(dno);
+        dno = target_dno;   // is already retained
+    }
+
+errorexit:
+    fsw_dnode_release(dno);
+    return status;
+}
+
+/**
+ * Set up a shandle (storage handle) to access a file's data. This function is called
+ * by the host driver and by the core when they need to access a file's data. It is also
+ * used in accessing the raw data of directories and symlinks if the file system uses
+ * the same mechanisms for storing the data of those items.
+ *
+ * The storage for the fsw_shandle structure is provided by the caller. The dnode and pos
+ * fields may be accessed, pos may also be written to to set the file pointer. The file's
+ * data size is available as shand->dnode->size.
+ *
+ * If this function returns FSW_SUCCESS, the caller must call fsw_shandle_close to release
+ * the dnode reference held by the shandle.
+ */
+
+fsw_status_t fsw_shandle_open(struct fsw_dnode *dno, struct fsw_shandle *shand)
+{
+    fsw_status_t    status;
+    struct fsw_volume *vol = dno->vol;
+
+    // read full dnode information into memory
+    status = vol->fstype_table->dnode_fill(vol, dno);
+    if (status)
+        return status;
+
+    // setup shandle
+    fsw_dnode_retain(dno);
+
+    shand->dnode = dno;
+    shand->pos = 0;
+    shand->extent.type = FSW_EXTENT_TYPE_INVALID;
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Close a shandle after accessing the dnode's data. This function is called by the host
+ * driver or core functions when they are finished with accessing a file's data. It
+ * releases the dnode reference and frees any buffers associated with the shandle itself.
+ * The dnode is only released if this was the last reference using it.
+ */
+
+void fsw_shandle_close(struct fsw_shandle *shand)
+{
+    if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
+        fsw_free(shand->extent.buffer);
+    fsw_dnode_release(shand->dnode);
+}
+
+/**
+ * Read data from a shandle (storage handle for a dnode). This function is called by the
+ * host driver or internally when data is read from a file. TODO: more
+ */
+
+fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer_in)
+{
+    fsw_status_t    status;
+    struct fsw_dnode *dno = shand->dnode;
+    struct fsw_volume *vol = dno->vol;
+    fsw_u8          *buffer, *block_buffer;
+    fsw_u32         buflen, copylen, pos;
+    fsw_u32         log_bno, pos_in_extent, phys_bno, pos_in_physblock;
+    fsw_u32         cache_level;
+
+    if (shand->pos >= dno->size) {   // already at EOF
+        *buffer_size_inout = 0;
+        return FSW_SUCCESS;
+    }
+
+    // initialize vars
+    buffer = buffer_in;
+    buflen = *buffer_size_inout;
+    pos = (fsw_u32)shand->pos;
+    cache_level = (dno->type != FSW_DNODE_TYPE_FILE) ? 1 : 0;
+    // restrict read to file size
+    if (buflen > dno->size - pos)
+        buflen = (fsw_u32)(dno->size - pos);
+
+    while (buflen > 0) {
+        // get extent for the current logical block
+        log_bno = pos / vol->log_blocksize;
+        if (shand->extent.type == FSW_EXTENT_TYPE_INVALID ||
+            log_bno < shand->extent.log_start ||
+            log_bno >= shand->extent.log_start + shand->extent.log_count) {
+
+            if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
+                fsw_free(shand->extent.buffer);
+
+            // ask the file system for the proper extent
+            shand->extent.log_start = log_bno;
+            status = vol->fstype_table->get_extent(vol, dno, &shand->extent);
+            if (status) {
+                shand->extent.type = FSW_EXTENT_TYPE_INVALID;
+                return status;
+            }
+        }
+
+        pos_in_extent = pos - shand->extent.log_start * vol->log_blocksize;
+
+        // dispatch by extent type
+        if (shand->extent.type == FSW_EXTENT_TYPE_PHYSBLOCK) {
+            // convert to physical block number and offset
+            phys_bno = shand->extent.phys_start + pos_in_extent / vol->phys_blocksize;
+            pos_in_physblock = pos_in_extent & (vol->phys_blocksize - 1);
+            copylen = vol->phys_blocksize - pos_in_physblock;
+            if (copylen > buflen)
+                copylen = buflen;
+
+            // get one physical block
+            status = fsw_block_get(vol, phys_bno, cache_level, (void **)&block_buffer);
+            if (status)
+                return status;
+
+            // copy data from it
+            fsw_memcpy(buffer, block_buffer + pos_in_physblock, copylen);
+            fsw_block_release(vol, phys_bno, block_buffer);
+
+        } else if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) {
+            copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
+            if (copylen > buflen)
+                copylen = buflen;
+            fsw_memcpy(buffer, (fsw_u8 *)shand->extent.buffer + pos_in_extent, copylen);
+
+        } else {   // _SPARSE or _INVALID
+            copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
+            if (copylen > buflen)
+                copylen = buflen;
+            fsw_memzero(buffer, copylen);
+
+        }
+
+        buffer += copylen;
+        buflen -= copylen;
+        pos    += copylen;
+    }
+
+    *buffer_size_inout = (fsw_u32)(pos - shand->pos);
+    shand->pos = pos;
+
+    return FSW_SUCCESS;
+}
+
+// EOF
diff --git a/filesystems/fsw_core.h b/filesystems/fsw_core.h
new file mode 100644 (file)
index 0000000..284913c
--- /dev/null
@@ -0,0 +1,537 @@
+/* $Id: fsw_core.h 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * fsw_core.h - Core file system wrapper abstraction layer header.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * Portions Copyright (c) The Regents of the University of California.
+ * Portions Copyright (c) UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_CORE_H_
+#define _FSW_CORE_H_
+
+#include "fsw_base.h"
+
+
+/** Maximum size for a path, specifically symlink target paths. */
+#ifndef VBOX
+#define FSW_PATH_MAX (4096)
+#else
+/* Too big allocations are handled with alloca() */
+#define FSW_PATH_MAX (2048)
+#endif
+
+/** Helper macro for token concatenation. */
+#define FSW_CONCAT3(a,b,c) a##b##c
+/** Expands to the name of a fstype dispatch table (fsw_fstype_table) for a named file system type. */
+#define FSW_FSTYPE_TABLE_NAME(t) FSW_CONCAT3(fsw_,t,_table)
+
+/** Indicates that the block cache entry is empty. */
+#define FSW_INVALID_BNO (~0UL)
+
+
+//
+// Byte-swapping macros
+//
+
+
+/**
+ * \name Byte Order Macros
+ * Implements big endian vs. little endian awareness and conversion.
+ */
+/*@{*/
+
+typedef fsw_u16             fsw_u16_le;
+typedef fsw_u16             fsw_u16_be;
+typedef fsw_u32             fsw_u32_le;
+typedef fsw_u32             fsw_u32_be;
+typedef fsw_u64             fsw_u64_le;
+typedef fsw_u64             fsw_u64_be;
+
+#define FSW_SWAPVALUE_U16(v) ((((fsw_u16)(v) & 0xff00) >> 8) | \
+                              (((fsw_u16)(v) & 0x00ff) << 8))
+#define FSW_SWAPVALUE_U32(v) ((((fsw_u32)(v) & 0xff000000UL) >> 24) | \
+                              (((fsw_u32)(v) & 0x00ff0000UL) >> 8)  | \
+                              (((fsw_u32)(v) & 0x0000ff00UL) << 8)  | \
+                              (((fsw_u32)(v) & 0x000000ffUL) << 24))
+#define FSW_SWAPVALUE_U64(v) ((((fsw_u64)(v) & 0xff00000000000000ULL) >> 56) | \
+                              (((fsw_u64)(v) & 0x00ff000000000000ULL) >> 40) | \
+                              (((fsw_u64)(v) & 0x0000ff0000000000ULL) >> 24) | \
+                              (((fsw_u64)(v) & 0x000000ff00000000ULL) >> 8)  | \
+                              (((fsw_u64)(v) & 0x00000000ff000000ULL) << 8)  | \
+                              (((fsw_u64)(v) & 0x0000000000ff0000ULL) << 24) | \
+                              (((fsw_u64)(v) & 0x000000000000ff00ULL) << 40) | \
+                              (((fsw_u64)(v) & 0x00000000000000ffULL) << 56))
+
+#ifdef FSW_LITTLE_ENDIAN
+
+#define fsw_u16_le_swap(v) (v)
+#define fsw_u16_be_swap(v) FSW_SWAPVALUE_U16(v)
+#define fsw_u32_le_swap(v) (v)
+#define fsw_u32_be_swap(v) FSW_SWAPVALUE_U32(v)
+#define fsw_u64_le_swap(v) (v)
+#define fsw_u64_be_swap(v) FSW_SWAPVALUE_U64(v)
+
+#define fsw_u16_le_sip(var)
+#define fsw_u16_be_sip(var) (var = FSW_SWAPVALUE_U16(var))
+#define fsw_u32_le_sip(var)
+#define fsw_u32_be_sip(var) (var = FSW_SWAPVALUE_U32(var))
+#define fsw_u64_le_sip(var)
+#define fsw_u64_be_sip(var) (var = FSW_SWAPVALUE_U64(var))
+
+#else
+#ifdef FSW_BIG_ENDIAN
+
+#define fsw_u16_le_swap(v) FSW_SWAPVALUE_U16(v)
+#define fsw_u16_be_swap(v) (v)
+#define fsw_u32_le_swap(v) FSW_SWAPVALUE_U32(v)
+#define fsw_u32_be_swap(v) (v)
+#define fsw_u64_le_swap(v) FSW_SWAPVALUE_U64(v)
+#define fsw_u64_be_swap(v) (v)
+
+#define fsw_u16_le_sip(var) (var = FSW_SWAPVALUE_U16(var))
+#define fsw_u16_be_sip(var)
+#define fsw_u32_le_sip(var) (var = FSW_SWAPVALUE_U32(var))
+#define fsw_u32_be_sip(var)
+#define fsw_u64_le_sip(var) (var = FSW_SWAPVALUE_U64(var))
+#define fsw_u64_be_sip(var)
+
+#else
+#fail Neither FSW_BIG_ENDIAN nor FSW_LITTLE_ENDIAN are defined
+#endif
+#endif
+
+/*@}*/
+
+
+//
+// The following evil hack avoids a lot of casts between generic and fstype-specific
+// structures.
+//
+
+#ifndef VOLSTRUCTNAME
+#define VOLSTRUCTNAME fsw_volume
+#else
+struct VOLSTRUCTNAME;
+#endif
+#ifndef DNODESTRUCTNAME
+#define DNODESTRUCTNAME fsw_dnode
+#else
+struct DNODESTRUCTNAME;
+#endif
+
+
+/**
+ * Status code type, returned from all functions that can fail.
+ */
+typedef int fsw_status_t;
+
+/**
+ * Possible status codes.
+ */
+enum {
+    FSW_SUCCESS,
+    FSW_OUT_OF_MEMORY,
+    FSW_IO_ERROR,
+    FSW_UNSUPPORTED,
+    FSW_NOT_FOUND,
+    FSW_VOLUME_CORRUPTED,
+    FSW_UNKNOWN_ERROR
+};
+
+
+/**
+ * Core: A string with explicit length and encoding information.
+ */
+
+struct fsw_string {
+    int         type;               //!< Encoding of the string - empty, ISO-8859-1, UTF8, UTF16
+    int         len;                //!< Length in characters
+    int         size;               //!< Total data size in bytes
+    void        *data;              //!< Data pointer (may be NULL if type is EMPTY or len is zero)
+};
+
+/**
+ * Possible string types / encodings. In the case of FSW_STRING_TYPE_EMPTY,
+ * all other members of the fsw_string structure may be invalid.
+ */
+enum {
+    FSW_STRING_TYPE_EMPTY,
+    FSW_STRING_TYPE_ISO88591,
+    FSW_STRING_TYPE_UTF8,
+    FSW_STRING_TYPE_UTF16,
+    FSW_STRING_TYPE_UTF16_SWAPPED
+};
+
+#ifdef FSW_LITTLE_ENDIAN
+#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16
+#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16_SWAPPED
+#else
+#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16_SWAPPED
+#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16
+#endif
+
+/** Static initializer for an empty string. */
+#define FSW_STRING_INIT { FSW_STRING_TYPE_EMPTY, 0, 0, NULL }
+
+
+/* forward declarations */
+
+struct fsw_dnode;
+struct fsw_host_table;
+struct fsw_fstype_table;
+
+struct fsw_blockcache {
+    fsw_u32     refcount;           //!< Reference count
+    fsw_u32     cache_level;        //!< Level of importance of this block
+    fsw_u32     phys_bno;           //!< Physical block number
+    void        *data;              //!< Block data buffer
+};
+
+/**
+ * Core: Represents a mounted volume.
+ */
+
+struct fsw_volume {
+    fsw_u32     phys_blocksize;     //!< Block size for disk access / file system structures
+    fsw_u32     log_blocksize;      //!< Block size for logical file data
+
+    struct DNODESTRUCTNAME *root;   //!< Root directory dnode
+    struct fsw_string label;        //!< Volume label
+
+    struct fsw_dnode *dnode_head;   //!< List of all dnodes allocated for this volume
+
+    struct fsw_blockcache *bcache;  //!< Array of block cache entries
+    fsw_u32     bcache_size;        //!< Number of entries in the block cache array
+
+    void        *host_data;         //!< Hook for a host-specific data structure
+    struct fsw_host_table *host_table;      //!< Dispatch table for host-specific functions
+    struct fsw_fstype_table *fstype_table;  //!< Dispatch table for file system specific functions
+    int         host_string_type;   //!< String type used by the host environment
+};
+
+/**
+ * Core: Represents a "directory node" - a file, directory, symlink, whatever.
+ */
+
+struct fsw_dnode {
+    fsw_u32     refcount;           //!< Reference count
+
+    struct VOLSTRUCTNAME *vol;      //!< The volume this dnode belongs to
+    struct DNODESTRUCTNAME *parent; //!< Parent directory dnode
+    struct fsw_string name;         //!< Name of this item in the parent directory
+
+    fsw_u32     dnode_id;           //!< Unique id number (usually the inode number)
+    int         type;               //!< Type of the dnode - file, dir, symlink, special
+    fsw_u64     size;               //!< Data size in bytes
+
+    struct fsw_dnode *next;         //!< Doubly-linked list of all dnodes: previous dnode
+    struct fsw_dnode *prev;         //!< Doubly-linked list of all dnodes: next dnode
+};
+
+/**
+ * Possible dnode types. FSW_DNODE_TYPE_UNKNOWN may only be used before
+ * fsw_dnode_fill has been called on the dnode.
+ */
+enum {
+    FSW_DNODE_TYPE_UNKNOWN,
+    FSW_DNODE_TYPE_FILE,
+    FSW_DNODE_TYPE_DIR,
+    FSW_DNODE_TYPE_SYMLINK,
+    FSW_DNODE_TYPE_SPECIAL
+};
+
+/**
+ * Core: Stores the mapping of a region of a file to the data on disk.
+ */
+
+struct fsw_extent {
+    fsw_u32     type;               //!< Type of extent specification
+    fsw_u32     log_start;          //!< Starting logical block number
+    fsw_u32     log_count;          //!< Logical block count
+    fsw_u32     phys_start;         //!< Starting physical block number (for FSW_EXTENT_TYPE_PHYSBLOCK only)
+    void        *buffer;            //!< Allocated buffer pointer (for FSW_EXTENT_TYPE_BUFFER only)
+};
+
+/**
+ * Possible extent representation types. FSW_EXTENT_TYPE_INVALID is for shandle's
+ * internal use only, it must not be returned from a get_extent function.
+ */
+enum {
+    FSW_EXTENT_TYPE_INVALID,
+    FSW_EXTENT_TYPE_SPARSE,
+    FSW_EXTENT_TYPE_PHYSBLOCK,
+    FSW_EXTENT_TYPE_BUFFER
+};
+
+/**
+ * Core: An access structure to a dnode's raw data. There can be multiple
+ * shandles per dnode, each of them has its own position pointer.
+ */
+
+struct fsw_shandle {
+    struct fsw_dnode *dnode;        //!< The dnode this handle reads data from
+
+    fsw_u64     pos;                //!< Current file pointer in bytes
+    struct fsw_extent extent;       //!< Current extent
+};
+
+/**
+ * Core: Used in gathering detailed information on a volume.
+ */
+
+struct fsw_volume_stat {
+    fsw_u64     total_bytes;        //!< Total size of data area size in bytes
+    fsw_u64     free_bytes;         //!< Bytes still available for storing file data
+};
+
+/**
+ * Core: Used in gathering detailed information on a dnode.
+ */
+
+struct fsw_dnode_stat {
+    fsw_u64     used_bytes;         //!< Bytes actually used by the file on disk
+    void        (*store_time_posix)(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time);   //!< Callback for storing a Posix-style timestamp
+    void        (*store_attr_posix)(struct fsw_dnode_stat *sb, fsw_u16 posix_mode);   //!< Callback for storing a Posix-style file mode
+    void        *host_data;         //!< Hook for a host-specific data structure
+};
+
+/**
+ * Type of the timestamp passed into store_time_posix.
+ */
+enum {
+    FSW_DNODE_STAT_CTIME,
+    FSW_DNODE_STAT_MTIME,
+    FSW_DNODE_STAT_ATIME
+};
+
+/**
+ * Core: Function table for a host environment.
+ */
+
+struct fsw_host_table
+{
+    int         native_string_type; //!< String type used by the host environment
+
+    void         (*change_blocksize)(struct fsw_volume *vol,
+                                     fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                                     fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+    fsw_status_t (*read_block)(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+};
+
+/**
+ * Core: Function table for a file system driver.
+ */
+
+struct fsw_fstype_table
+{
+    struct fsw_string name;         //!< String giving the name of the file system
+    fsw_u32     volume_struct_size; //!< Size for allocating the fsw_volume structure
+    fsw_u32     dnode_struct_size;  //!< Size for allocating the fsw_dnode structure
+
+    fsw_status_t (*volume_mount)(struct VOLSTRUCTNAME *vol);
+    void         (*volume_free)(struct VOLSTRUCTNAME *vol);
+    fsw_status_t (*volume_stat)(struct VOLSTRUCTNAME *vol, struct fsw_volume_stat *sb);
+
+    fsw_status_t (*dnode_fill)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno);
+    void         (*dnode_free)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno);
+    fsw_status_t (*dnode_stat)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                               struct fsw_dnode_stat *sb);
+    fsw_status_t (*get_extent)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                               struct fsw_extent *extent);
+
+    fsw_status_t (*dir_lookup)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                               struct fsw_string *lookup_name, struct DNODESTRUCTNAME **child_dno);
+    fsw_status_t (*dir_read)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                             struct fsw_shandle *shand, struct DNODESTRUCTNAME **child_dno);
+    fsw_status_t (*readlink)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+                             struct fsw_string *link_target);
+};
+
+
+/**
+ * \name Volume Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_mount(void *host_data,
+                       struct fsw_host_table *host_table,
+                       struct fsw_fstype_table *fstype_table,
+                       struct fsw_volume **vol_out);
+void         fsw_unmount(struct fsw_volume *vol);
+fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb);
+
+void         fsw_set_blocksize(struct VOLSTRUCTNAME *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize);
+fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fsw_u32 cache_level, void **buffer_out);
+void         fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, void *buffer);
+
+/*@}*/
+
+
+/**
+ * \name dnode Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_dnode_create_root(struct VOLSTRUCTNAME *vol, fsw_u32 dnode_id, struct DNODESTRUCTNAME **dno_out);
+fsw_status_t fsw_dnode_create(struct DNODESTRUCTNAME *parent_dno, fsw_u32 dnode_id, int type,
+                              struct fsw_string *name, struct DNODESTRUCTNAME **dno_out);
+void         fsw_dnode_retain(struct fsw_dnode *dno);
+void         fsw_dnode_release(struct fsw_dnode *dno);
+
+fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno);
+fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb);
+
+fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
+                              struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
+                                   struct fsw_string *lookup_path, char separator,
+                                   struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *link_target);
+fsw_status_t fsw_dnode_readlink_data(struct DNODESTRUCTNAME *dno, struct fsw_string *link_target);
+fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out);
+
+/*@}*/
+
+
+/**
+ * \name shandle Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_shandle_open(struct DNODESTRUCTNAME *dno, struct fsw_shandle *shand);
+void         fsw_shandle_close(struct fsw_shandle *shand);
+fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer);
+
+/*@}*/
+
+
+/**
+ * \name Memory Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_alloc_zero(int len, void **ptr_out);
+fsw_status_t fsw_memdup(void **dest_out, void *src, int len);
+
+/*@}*/
+
+
+/**
+ * \name String Functions
+ */
+/*@{*/
+
+int          fsw_strlen(struct fsw_string *s);
+int          fsw_streq(struct fsw_string *s1, struct fsw_string *s2);
+int          fsw_streq_cstr(struct fsw_string *s1, const char *s2);
+fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src);
+void         fsw_strsplit(struct fsw_string *lookup_name, struct fsw_string *buffer, char separator);
+
+void         fsw_strfree(struct fsw_string *s);
+fsw_u16      fsw_to_lower(fsw_u16 ch);
+
+/*@}*/
+
+
+/**
+ * \name Posix Mode Macros
+ * These macros can be used globally to test fields and bits in
+ * Posix-style modes.
+ *
+ * Taken from FreeBSD sys/stat.h.
+ */
+/*@{*/
+#ifndef S_IRWXU
+
+#define        S_ISUID 0004000                 /* set user id on execution */
+#define        S_ISGID 0002000                 /* set group id on execution */
+#define        S_ISTXT 0001000                 /* sticky bit */
+
+#define        S_IRWXU 0000700                 /* RWX mask for owner */
+#define        S_IRUSR 0000400                 /* R for owner */
+#define        S_IWUSR 0000200                 /* W for owner */
+#define        S_IXUSR 0000100                 /* X for owner */
+
+#define        S_IRWXG 0000070                 /* RWX mask for group */
+#define        S_IRGRP 0000040                 /* R for group */
+#define        S_IWGRP 0000020                 /* W for group */
+#define        S_IXGRP 0000010                 /* X for group */
+
+#define        S_IRWXO 0000007                 /* RWX mask for other */
+#define        S_IROTH 0000004                 /* R for other */
+#define        S_IWOTH 0000002                 /* W for other */
+#define        S_IXOTH 0000001                 /* X for other */
+
+#define        S_IFMT   0170000                /* type of file mask */
+#define        S_IFIFO  0010000                /* named pipe (fifo) */
+#define        S_IFCHR  0020000                /* character special */
+#define        S_IFDIR  0040000                /* directory */
+#define        S_IFBLK  0060000                /* block special */
+#define        S_IFREG  0100000                /* regular */
+#define        S_IFLNK  0120000                /* symbolic link */
+#define        S_IFSOCK 0140000                /* socket */
+#define        S_ISVTX  0001000                /* save swapped text even after use */
+#define        S_IFWHT  0160000                /* whiteout */
+
+#define        S_ISDIR(m)      (((m) & 0170000) == 0040000)    /* directory */
+#define        S_ISCHR(m)      (((m) & 0170000) == 0020000)    /* char special */
+#define        S_ISBLK(m)      (((m) & 0170000) == 0060000)    /* block special */
+#define        S_ISREG(m)      (((m) & 0170000) == 0100000)    /* regular file */
+#define        S_ISFIFO(m)     (((m) & 0170000) == 0010000)    /* fifo or socket */
+#define        S_ISLNK(m)      (((m) & 0170000) == 0120000)    /* symbolic link */
+#define        S_ISSOCK(m)     (((m) & 0170000) == 0140000)    /* socket */
+#define        S_ISWHT(m)      (((m) & 0170000) == 0160000)    /* whiteout */
+
+#define S_BLKSIZE      512             /* block size used in the stat struct */
+
+#endif
+/*@}*/
+
+
+#endif
diff --git a/filesystems/fsw_efi.c b/filesystems/fsw_efi.c
new file mode 100644 (file)
index 0000000..e7d2400
--- /dev/null
@@ -0,0 +1,1085 @@
+/* $Id: fsw_efi.c 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_efi.c - EFI host environment code.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_efi.h"
+
+#define DEBUG_LEVEL 0
+
+#ifndef FSTYPE
+#ifdef VBOX
+#error FSTYPE must be defined!
+#else
+#define FSTYPE ext2
+#endif
+#endif
+
+#define DEBUG_VBFS 1
+// CHAR8 *msgCursor;
+// MESSAGE_LOG_PROTOCOL *Msg = NULL; 
+
+#if DEBUG_VBFS==2
+#define DBG(x...)  AsciiPrint(x)
+#elif DEBUG_VBFS==1
+#define DBG(x...)  BootLog(x)
+#else
+#define DBG(x...)
+#endif
+
+
+/** Helper macro for stringification. */
+#define FSW_EFI_STRINGIFY(x) #x
+/** Expands to the EFI driver name given the file system type name. */
+#define FSW_EFI_DRIVER_NAME(t) L"Fsw " FSW_EFI_STRINGIFY(t) L" File System Driver"
+
+// function prototypes
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                                  IN EFI_HANDLE                   ControllerHandle,
+                                                  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath);
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                              IN EFI_HANDLE                   ControllerHandle,
+                                              IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath);
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                             IN  EFI_HANDLE                   ControllerHandle,
+                                             IN  UINTN                        NumberOfChildren,
+                                             IN  EFI_HANDLE                   *ChildHandleBuffer);
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+                                                      IN  CHAR8                        *Language,
+                                                      OUT CHAR16                       **DriverName);
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN  EFI_COMPONENT_NAME_PROTOCOL    *This,
+                                                          IN  EFI_HANDLE                     ControllerHandle,
+                                                          IN  EFI_HANDLE                     ChildHandle  OPTIONAL,
+                                                          IN  CHAR8                          *Language,
+                                                          OUT CHAR16                         **ControllerName);
+
+void fsw_efi_change_blocksize(struct fsw_volume *vol,
+                              fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                              fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+
+EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume);
+
+EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
+                                                OUT EFI_FILE **Root);
+EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
+                                       OUT EFI_FILE **NewFileHandle);
+
+EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
+                             IN OUT UINTN *BufferSize,
+                             OUT VOID *Buffer);
+EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
+                               OUT UINT64 *Position);
+EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
+                               IN UINT64 Position);
+
+EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
+                            OUT EFI_FILE **NewHandle,
+                            IN CHAR16 *FileName,
+                            IN UINT64 OpenMode,
+                            IN UINT64 Attributes);
+EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
+                            IN OUT UINTN *BufferSize,
+                            OUT VOID *Buffer);
+EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
+                              IN UINT64 Position);
+
+EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
+                                 IN EFI_GUID *InformationType,
+                                 IN OUT UINTN *BufferSize,
+                                 OUT VOID *Buffer);
+EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+                                       IN struct fsw_dnode *dno,
+                                       IN OUT UINTN *BufferSize,
+                                       OUT VOID *Buffer);
+
+/**
+ * Interface structure for the EFI Driver Binding protocol.
+ */
+
+EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table = {
+    fsw_efi_DriverBinding_Supported,
+    fsw_efi_DriverBinding_Start,
+    fsw_efi_DriverBinding_Stop,
+    0x10,
+    NULL,
+    NULL
+};
+
+/**
+ * Interface structure for the EFI Component Name protocol.
+ */
+
+EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table = {
+    fsw_efi_ComponentName_GetDriverName,
+    fsw_efi_ComponentName_GetControllerName,
+    "eng"
+};
+
+/**
+ * Dispatch table for our FSW host driver.
+ */
+
+struct fsw_host_table   fsw_efi_host_table = {
+    FSW_STRING_TYPE_UTF16,
+
+    fsw_efi_change_blocksize,
+    fsw_efi_read_block
+};
+
+extern struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+//#include "OverrideFunctions-kabyl.edk2.c.include"
+
+/**
+ * Image entry point. Installs the Driver Binding and Component Name protocols
+ * on the image's handle. Actually mounting a file system is initiated through
+ * the Driver Binding protocol at the firmware's request.
+ */
+EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE         ImageHandle,
+                               IN EFI_SYSTEM_TABLE   *SystemTable)
+{
+    EFI_STATUS  Status;
+
+#ifndef VBOX
+    InitializeLib(ImageHandle, SystemTable);
+#endif
+
+    // complete Driver Binding protocol instance
+    fsw_efi_DriverBinding_table.ImageHandle          = ImageHandle;
+    fsw_efi_DriverBinding_table.DriverBindingHandle  = ImageHandle;
+    // install Driver Binding protocol
+    Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle,
+                                          &PROTO_NAME(DriverBindingProtocol),
+                                          EFI_NATIVE_INTERFACE,
+                                          &fsw_efi_DriverBinding_table);
+    if (EFI_ERROR (Status)) {
+        return Status;
+    }
+
+    // install Component Name protocol
+    Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle,
+                                          &PROTO_NAME(ComponentNameProtocol),
+                                          EFI_NATIVE_INTERFACE,
+                                          &fsw_efi_ComponentName_table);
+    if (EFI_ERROR (Status)) {
+        return Status;
+    }
+
+//     OverrideFunctions();
+//   Msg = NULL;
+//   msgCursor = NULL;
+//   Status = BS->LocateProtocol(&gMsgLogProtocolGuid, NULL, (VOID **) &Msg);
+//   if (!EFI_ERROR(Status) && (Msg != NULL)) {
+//     msgCursor = Msg->Cursor;
+//     BootLog("MsgLog installed into VBoxFs\n");
+//   }
+
+    return EFI_SUCCESS;
+}
+
+/**
+ * Driver Binding EFI protocol, Supported function. This function is called by EFI
+ * to test if this driver can handle a certain device. Our implementation only checks
+ * if the device is a disk (i.e. that it supports the Block I/O and Disk I/O protocols)
+ * and implicitly checks if the disk is already in use by another driver.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                                  IN EFI_HANDLE                   ControllerHandle,
+                                                  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath)
+{
+    EFI_STATUS          Status;
+    EFI_DISK_IO         *DiskIo;
+
+    // we check for both DiskIO and BlockIO protocols
+
+    // first, open DiskIO
+    Status = BS->OpenProtocol(ControllerHandle,
+                              &PROTO_NAME(DiskIoProtocol),
+                              (VOID **) &DiskIo,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_BY_DRIVER);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // we were just checking, close it again
+    BS->CloseProtocol(ControllerHandle,
+                      &PROTO_NAME(DiskIoProtocol),
+                      This->DriverBindingHandle,
+                      ControllerHandle);
+
+    // next, check BlockIO without actually opening it
+    Status = BS->OpenProtocol(ControllerHandle,
+                              &PROTO_NAME(BlockIoProtocol),
+                              NULL,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
+    return Status;
+}
+
+/**
+ * Driver Binding EFI protocol, Start function. This function is called by EFI
+ * to start driving the given device. It is still possible at this point to
+ * return EFI_UNSUPPORTED, and in fact we will do so if the file system driver
+ * cannot find the superblock signature (or equivalent) that it expects.
+ *
+ * This function allocates memory for a per-volume structure, opens the
+ * required protocols (just Disk I/O in our case, Block I/O is only looked
+ * at to get the MediaId field), and lets the FSW core mount the file system.
+ * If successful, an EFI Simple File System protocol is exported on the
+ * device handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                              IN EFI_HANDLE                   ControllerHandle,
+                                              IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath)
+{
+    EFI_STATUS          Status;
+    EFI_BLOCK_IO        *BlockIo;
+    EFI_DISK_IO         *DiskIo;
+    FSW_VOLUME_DATA     *Volume;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_DriverBinding_Start\n");
+#endif
+
+    // open consumed protocols
+    Status = BS->OpenProtocol(ControllerHandle,
+                              &PROTO_NAME(BlockIoProtocol),
+                              (VOID **) &BlockIo,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_GET_PROTOCOL);   // NOTE: we only want to look at the MediaId
+    if (EFI_ERROR(Status)) {
+//        Print(L"Fsw ERROR: OpenProtocol(BlockIo) returned %x\n", Status);
+        return Status;
+    }
+
+    Status = BS->OpenProtocol(ControllerHandle,
+                              &PROTO_NAME(DiskIoProtocol),
+                              (VOID **) &DiskIo,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_BY_DRIVER);
+    if (EFI_ERROR(Status)) {
+        Print(L"Fsw ERROR: OpenProtocol(DiskIo) returned %r\n", Status);
+        return Status;
+    }
+
+    // allocate volume structure
+    Volume = AllocateZeroPool(sizeof(FSW_VOLUME_DATA));
+    Volume->Signature       = FSW_VOLUME_DATA_SIGNATURE;
+    Volume->Handle          = ControllerHandle;
+    Volume->DiskIo          = DiskIo;
+    Volume->MediaId         = BlockIo->Media->MediaId;
+    Volume->LastIOStatus    = EFI_SUCCESS;
+
+    // mount the filesystem
+    Status = fsw_efi_map_status(fsw_mount(Volume, &fsw_efi_host_table,
+                                          &FSW_FSTYPE_TABLE_NAME(FSTYPE), &Volume->vol),
+                                Volume);
+
+    if (!EFI_ERROR(Status)) {
+        // register the SimpleFileSystem protocol
+        Volume->FileSystem.Revision     = EFI_FILE_IO_INTERFACE_REVISION;
+        Volume->FileSystem.OpenVolume   = fsw_efi_FileSystem_OpenVolume;
+        Status = BS->InstallMultipleProtocolInterfaces(&ControllerHandle,
+                                                       &PROTO_NAME(SimpleFileSystemProtocol),
+                                                       &Volume->FileSystem,
+                                                       NULL);
+        if (EFI_ERROR(Status)) {
+//            Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status);
+        }
+    }
+
+    // on errors, close the opened protocols
+    if (EFI_ERROR(Status)) {
+        if (Volume->vol != NULL)
+            fsw_unmount(Volume->vol);
+        FreePool(Volume);
+
+        BS->CloseProtocol(ControllerHandle,
+                          &PROTO_NAME(DiskIoProtocol),
+                          This->DriverBindingHandle,
+                          ControllerHandle);
+    }
+
+    return Status;
+}
+
+/**
+ * Driver Binding EFI protocol, Stop function. This function is called by EFI
+ * to stop the driver on the given device. This translates to an unmount
+ * call for the FSW core.
+ *
+ * We assume that all file handles on the volume have been closed before
+ * the driver is stopped. At least with the EFI shell, that is actually the
+ * case; it closes all file handles between commands.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+                                             IN  EFI_HANDLE                   ControllerHandle,
+                                             IN  UINTN                        NumberOfChildren,
+                                             IN  EFI_HANDLE                   *ChildHandleBuffer)
+{
+    EFI_STATUS          Status;
+    EFI_FILE_IO_INTERFACE *FileSystem;
+    FSW_VOLUME_DATA     *Volume;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_DriverBinding_Stop\n");
+#endif
+
+    // get the installed SimpleFileSystem interface
+    Status = BS->OpenProtocol(ControllerHandle,
+                              &PROTO_NAME(SimpleFileSystemProtocol),
+                              (VOID **) &FileSystem,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+    if (EFI_ERROR(Status))
+        return EFI_UNSUPPORTED;
+
+    // get private data structure
+    Volume = FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem);
+
+    // uninstall Simple File System protocol
+    Status = BS->UninstallMultipleProtocolInterfaces(ControllerHandle,
+                                                     &PROTO_NAME(SimpleFileSystemProtocol), &Volume->FileSystem,
+                                                     NULL);
+    if (EFI_ERROR(Status)) {
+ //       Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status);
+        return Status;
+    }
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n");
+#endif
+
+    // release private data structure
+    if (Volume->vol != NULL)
+        fsw_unmount(Volume->vol);
+    FreePool(Volume);
+
+    // close the consumed protocols
+    Status = BS->CloseProtocol(ControllerHandle,
+                               &PROTO_NAME(DiskIoProtocol),
+                               This->DriverBindingHandle,
+                               ControllerHandle);
+
+    return Status;
+}
+
+/**
+ * Component Name EFI protocol, GetDriverName function. Used by the EFI
+ * environment to inquire the name of this driver. The name returned is
+ * based on the file system type actually used in compilation.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+                                                      IN  CHAR8                        *Language,
+                                                      OUT CHAR16                       **DriverName)
+{
+    if (Language == NULL || DriverName == NULL)
+        return EFI_INVALID_PARAMETER;
+
+    if (Language[0] == 'e' && Language[1] == 'n' && Language[2] == 'g' && Language[3] == 0) {
+        *DriverName = FSW_EFI_DRIVER_NAME(FSTYPE);
+        return EFI_SUCCESS;
+    }
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * Component Name EFI protocol, GetControllerName function. Not implemented
+ * because this is not a "bus" driver in the sense of the EFI Driver Model.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN  EFI_COMPONENT_NAME_PROTOCOL    *This,
+                                                          IN  EFI_HANDLE                     ControllerHandle,
+                                                          IN  EFI_HANDLE                     ChildHandle  OPTIONAL,
+                                                          IN  CHAR8                          *Language,
+                                                          OUT CHAR16                         **ControllerName)
+{
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * FSW interface function for block size changes. This function is called by the FSW core
+ * when the file system driver changes the block sizes for the volume.
+ */
+
+void fsw_efi_change_blocksize(struct fsw_volume *vol,
+                              fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                              fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
+{
+    // nothing to do
+}
+
+/**
+ * FSW interface function to read data blocks. This function is called by the FSW core
+ * to read a block of data from the device. The buffer is allocated by the core code.
+ */
+
+fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer)
+{
+    EFI_STATUS          Status;
+    FSW_VOLUME_DATA     *Volume = (FSW_VOLUME_DATA *)vol->host_data;
+
+//    FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_efi_read_block: %d  (%d)\n"), phys_bno, vol->phys_blocksize));
+
+    // read from disk
+    Status = Volume->DiskIo->ReadDisk(Volume->DiskIo, Volume->MediaId,
+                                      (UINT64)phys_bno * vol->phys_blocksize,
+                                      vol->phys_blocksize,
+                                      buffer);
+    Volume->LastIOStatus = Status;
+    if (EFI_ERROR(Status))
+        return FSW_IO_ERROR;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced
+ * by fsw_efi_read_block, so we map it back to the EFI status code remembered from
+ * the last I/O operation.
+ */
+
+EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume)
+{
+    switch (fsw_status) {
+        case FSW_SUCCESS:
+            return EFI_SUCCESS;
+        case FSW_OUT_OF_MEMORY:
+            return EFI_VOLUME_CORRUPTED;
+        case FSW_IO_ERROR:
+            return Volume->LastIOStatus;
+        case FSW_UNSUPPORTED:
+            return EFI_UNSUPPORTED;
+        case FSW_NOT_FOUND:
+            return EFI_NOT_FOUND;
+        case FSW_VOLUME_CORRUPTED:
+            return EFI_VOLUME_CORRUPTED;
+        default:
+            return EFI_DEVICE_ERROR;
+    }
+}
+
+/**
+ * File System EFI protocol, OpenVolume function. Creates a file handle for
+ * the root directory and returns it. Note that this function may be called
+ * multiple times and returns a new file handle each time. Each returned
+ * handle is closed by the client using it.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
+                                                OUT EFI_FILE **Root)
+{
+    EFI_STATUS          Status;
+    FSW_VOLUME_DATA     *Volume = FSW_VOLUME_FROM_FILE_SYSTEM(This);
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_FileSystem_OpenVolume\n");
+#endif
+
+    Status = fsw_efi_dnode_to_FileHandle(Volume->vol->root, Root);
+
+    return Status;
+}
+
+/**
+ * File Handle EFI protocol, Open function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Open(IN EFI_FILE *This,
+                                          OUT EFI_FILE **NewHandle,
+                                          IN CHAR16 *FileName,
+                                          IN UINT64 OpenMode,
+                                          IN UINT64 Attributes)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+        return fsw_efi_dir_open(File, NewHandle, FileName, OpenMode, Attributes);
+    // not supported for regular files
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, Close function. Closes the FSW shandle
+ * and frees the memory used for the structure.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Close(IN EFI_FILE *This)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_FileHandle_Close\n");
+#endif
+
+    fsw_shandle_close(&File->shand);
+    FreePool(File);
+
+    return EFI_SUCCESS;
+}
+
+/**
+ * File Handle EFI protocol, Delete function. Calls through to Close
+ * and returns a warning because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This)
+{
+    EFI_STATUS          Status;
+
+    Status = This->Close(This);
+    if (Status == EFI_SUCCESS) {
+        // this driver is read-only
+        Status = EFI_WARN_DELETE_FAILURE;
+    }
+
+    return Status;
+}
+
+/**
+ * File Handle EFI protocol, Read function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Read(IN EFI_FILE *This,
+                                          IN OUT UINTN *BufferSize,
+                                          OUT VOID *Buffer)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+        return fsw_efi_file_read(File, BufferSize, Buffer);
+    else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+        return fsw_efi_dir_read(File, BufferSize, Buffer);
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, Write function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Write(IN EFI_FILE *This,
+                                           IN OUT UINTN *BufferSize,
+                                           IN VOID *Buffer)
+{
+    // this driver is read-only
+    return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * File Handle EFI protocol, GetPosition function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_GetPosition(IN EFI_FILE *This,
+                                                 OUT UINT64 *Position)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+        return fsw_efi_file_getpos(File, Position);
+    // not defined for directories
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, SetPosition function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_SetPosition(IN EFI_FILE *This,
+                                                 IN UINT64 Position)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+        return fsw_efi_file_setpos(File, Position);
+    else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+        return fsw_efi_dir_setpos(File, Position);
+    return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, GetInfo function. Dispatches to the common
+ * function implementing this.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_GetInfo(IN EFI_FILE *This,
+                                             IN EFI_GUID *InformationType,
+                                             IN OUT UINTN *BufferSize,
+                                             OUT VOID *Buffer)
+{
+    FSW_FILE_DATA      *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+    return fsw_efi_dnode_getinfo(File, InformationType, BufferSize, Buffer);
+}
+
+/**
+ * File Handle EFI protocol, SetInfo function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_SetInfo(IN EFI_FILE *This,
+                                             IN EFI_GUID *InformationType,
+                                             IN UINTN BufferSize,
+                                             IN VOID *Buffer)
+{
+    // this driver is read-only
+    return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * File Handle EFI protocol, Flush function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Flush(IN EFI_FILE *This)
+{
+    // this driver is read-only
+    return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * Set up a file handle for a dnode. This function allocates a data structure
+ * for a file handle, opens a FSW shandle and populates the EFI_FILE structure
+ * with the interface functions.
+ */
+
+EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
+                                       OUT EFI_FILE **NewFileHandle)
+{
+    EFI_STATUS          Status;
+    FSW_FILE_DATA       *File;
+
+    // make sure the dnode has complete info
+    Status = fsw_efi_map_status(fsw_dnode_fill(dno), (FSW_VOLUME_DATA *)dno->vol->host_data);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // check type
+    if (dno->type != FSW_DNODE_TYPE_FILE && dno->type != FSW_DNODE_TYPE_DIR)
+        return EFI_UNSUPPORTED;
+
+    // allocate file structure
+    File = AllocateZeroPool(sizeof(FSW_FILE_DATA));
+    File->Signature = FSW_FILE_DATA_SIGNATURE;
+    if (dno->type == FSW_DNODE_TYPE_FILE)
+        File->Type = FSW_EFI_FILE_TYPE_FILE;
+    else if (dno->type == FSW_DNODE_TYPE_DIR)
+        File->Type = FSW_EFI_FILE_TYPE_DIR;
+
+    // open shandle
+    Status = fsw_efi_map_status(fsw_shandle_open(dno, &File->shand),
+                                (FSW_VOLUME_DATA *)dno->vol->host_data);
+    if (EFI_ERROR(Status)) {
+        FreePool(File);
+        return Status;
+    }
+
+    // populate the file handle
+    File->FileHandle.Revision    = EFI_FILE_HANDLE_REVISION;
+    File->FileHandle.Open        = fsw_efi_FileHandle_Open;
+    File->FileHandle.Close       = fsw_efi_FileHandle_Close;
+    File->FileHandle.Delete      = fsw_efi_FileHandle_Delete;
+    File->FileHandle.Read        = fsw_efi_FileHandle_Read;
+    File->FileHandle.Write       = fsw_efi_FileHandle_Write;
+    File->FileHandle.GetPosition = fsw_efi_FileHandle_GetPosition;
+    File->FileHandle.SetPosition = fsw_efi_FileHandle_SetPosition;
+    File->FileHandle.GetInfo     = fsw_efi_FileHandle_GetInfo;
+    File->FileHandle.SetInfo     = fsw_efi_FileHandle_SetInfo;
+    File->FileHandle.Flush       = fsw_efi_FileHandle_Flush;
+
+    *NewFileHandle = &File->FileHandle;
+    return EFI_SUCCESS;
+}
+
+/**
+ * Data read function for regular files. Calls through to fsw_shandle_read.
+ */
+
+EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
+                             IN OUT UINTN *BufferSize,
+                             OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    fsw_u32             buffer_size;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_file_read %d bytes\n", *BufferSize);
+#endif
+
+    buffer_size = (fsw_u32)*BufferSize;
+    Status = fsw_efi_map_status(fsw_shandle_read(&File->shand, &buffer_size, Buffer),
+                                (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data);
+    *BufferSize = buffer_size;
+
+    return Status;
+}
+
+/**
+ * Get file position for regular files.
+ */
+
+EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
+                               OUT UINT64 *Position)
+{
+    *Position = File->shand.pos;
+    return EFI_SUCCESS;
+}
+
+/**
+ * Set file position for regular files. EFI specifies the all-ones value
+ * to be a special value for the end of the file.
+ */
+
+EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
+                               IN UINT64 Position)
+{
+    if (Position == 0xFFFFFFFFFFFFFFFFULL)
+        File->shand.pos = File->shand.dnode->size;
+    else
+        File->shand.pos = Position;
+    return EFI_SUCCESS;
+}
+
+/**
+ * Open function used to open new file handles relative to a directory.
+ * In EFI, the "open file" function is implemented by directory file handles
+ * and is passed a relative or volume-absolute path to the file or directory
+ * to open. We use fsw_dnode_lookup_path to find the node plus an additional
+ * call to fsw_dnode_resolve because EFI has no concept of symbolic links.
+ */
+
+EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
+                            OUT EFI_FILE **NewHandle,
+                            IN CHAR16 *FileName,
+                            IN UINT64 OpenMode,
+                            IN UINT64 Attributes)
+{
+    EFI_STATUS          Status;
+    FSW_VOLUME_DATA     *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+    struct fsw_dnode    *dno;
+    struct fsw_dnode    *target_dno;
+    struct fsw_string   lookup_path;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_dir_open: '%s'\n", FileName);
+#endif
+
+    if (OpenMode != EFI_FILE_MODE_READ)
+        return EFI_WRITE_PROTECTED;
+
+    lookup_path.type = FSW_STRING_TYPE_UTF16;
+    lookup_path.len  = (int)StrLen(FileName);
+    lookup_path.size = lookup_path.len * sizeof(fsw_u16);
+    lookup_path.data = FileName;
+
+    // resolve the path (symlinks along the way are automatically resolved)
+    Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode, &lookup_path, '\\', &dno),
+                                Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // if the final node is a symlink, also resolve it
+    Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno),
+                                Volume);
+    fsw_dnode_release(dno);
+    if (EFI_ERROR(Status))
+        return Status;
+    dno = target_dno;
+
+    // make a new EFI handle for the target dnode
+    Status = fsw_efi_dnode_to_FileHandle(dno, NewHandle);
+    fsw_dnode_release(dno);
+    return Status;
+}
+
+/**
+ * Read function for directories. A file handle read on a directory retrieves
+ * the next directory entry.
+ */
+
+EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
+                            IN OUT UINTN *BufferSize,
+                            OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    FSW_VOLUME_DATA     *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+    struct fsw_dnode    *dno;
+
+#if DEBUG_LEVEL
+    Print(L"fsw_efi_dir_read...\n");
+#endif
+
+    // read the next entry
+    Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno),
+                                Volume);
+    if (Status == EFI_NOT_FOUND) {
+        // end of directory
+        *BufferSize = 0;
+#if DEBUG_LEVEL
+        Print(L"...no more entries\n");
+#endif
+        return EFI_SUCCESS;
+    }
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // get info into buffer
+    Status = fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer);
+    fsw_dnode_release(dno);
+    return Status;
+}
+
+/**
+ * Set file position for directories. The only allowed set position operation
+ * for directories is to rewind the directory completely by setting the
+ * position to zero.
+ */
+
+EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
+                              IN UINT64 Position)
+{
+    if (Position == 0) {
+        File->shand.pos = 0;
+        return EFI_SUCCESS;
+    } else {
+        // directories can only rewind to the start
+        return EFI_UNSUPPORTED;
+    }
+}
+
+/**
+ * Get file or volume information. This function implements the GetInfo call
+ * for all file handles. Control is dispatched according to the type of information
+ * requested by the caller.
+ */
+
+EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
+                                 IN EFI_GUID *InformationType,
+                                 IN OUT UINTN *BufferSize,
+                                 OUT VOID *Buffer)
+{
+    EFI_STATUS            Status;
+    FSW_VOLUME_DATA       *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+    EFI_FILE_SYSTEM_INFO  *FSInfo;
+    UINTN                 RequiredSize;
+    struct fsw_volume_stat vsb;
+
+
+    if (CompareGuid(InformationType, &gEfiFileInfoGuid)) {
+#if DEBUG_LEVEL
+        Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n");
+#endif
+
+        Status = fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, BufferSize, Buffer);
+
+    } else if (CompareGuid(InformationType, &gEfiFileSystemInfoGuid)) {
+#if DEBUG_LEVEL
+        Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n");
+#endif
+
+        // check buffer size
+        RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + fsw_efi_strsize(&Volume->vol->label);
+        if (*BufferSize < RequiredSize) {
+            *BufferSize = RequiredSize;
+            return EFI_BUFFER_TOO_SMALL;
+        }
+
+        // fill structure
+        FSInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
+        FSInfo->Size        = RequiredSize;
+        FSInfo->ReadOnly    = TRUE;
+        FSInfo->BlockSize   = Volume->vol->log_blocksize;
+        fsw_efi_strcpy(FSInfo->VolumeLabel, &Volume->vol->label);
+
+        // get the missing info from the fs driver
+        ZeroMem(&vsb, sizeof(struct fsw_volume_stat));
+        Status = fsw_efi_map_status(fsw_volume_stat(Volume->vol, &vsb), Volume);
+        if (EFI_ERROR(Status))
+            return Status;
+        FSInfo->VolumeSize  = vsb.total_bytes;
+        FSInfo->FreeSpace   = vsb.free_bytes;
+
+        // prepare for return
+        *BufferSize = RequiredSize;
+        Status = EFI_SUCCESS;
+
+    } else if (CompareGuid(InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+#if DEBUG_LEVEL
+        Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n");
+#endif
+
+        // check buffer size
+        RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + fsw_efi_strsize(&Volume->vol->label);
+        if (*BufferSize < RequiredSize) {
+            *BufferSize = RequiredSize;
+            return EFI_BUFFER_TOO_SMALL;
+        }
+
+        // copy volume label
+        fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Buffer)->VolumeLabel, &Volume->vol->label);
+
+        // prepare for return
+        *BufferSize = RequiredSize;
+        Status = EFI_SUCCESS;
+
+    } else {
+        Status = EFI_UNSUPPORTED;
+    }
+
+    return Status;
+}
+
+/**
+ * Time mapping callback for the fsw_dnode_stat call. This function converts
+ * a Posix style timestamp into an EFI_TIME structure and writes it to the
+ * appropriate member of the EFI_FILE_INFO structure that we're filling.
+ */
+
+static void fsw_efi_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    if (which == FSW_DNODE_STAT_CTIME)
+        fsw_efi_decode_time(&FileInfo->CreateTime,       posix_time);
+    else if (which == FSW_DNODE_STAT_MTIME)
+        fsw_efi_decode_time(&FileInfo->ModificationTime, posix_time);
+    else if (which == FSW_DNODE_STAT_ATIME)
+        fsw_efi_decode_time(&FileInfo->LastAccessTime,   posix_time);
+}
+
+/**
+ * Mode mapping callback for the fsw_dnode_stat call. This function looks at
+ * the Posix mode passed by the file system driver and makes appropriate
+ * adjustments to the EFI_FILE_INFO structure that we're filling.
+ */
+
+static void fsw_efi_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    if ((posix_mode & S_IWUSR) == 0)
+        FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+}
+
+/**
+ * Common function to fill an EFI_FILE_INFO with information about a dnode.
+ */
+
+EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+                                       IN struct fsw_dnode *dno,
+                                       IN OUT UINTN *BufferSize,
+                                       OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    EFI_FILE_INFO       *FileInfo;
+    UINTN               RequiredSize;
+    struct fsw_dnode_stat sb;
+
+    // make sure the dnode has complete info
+    Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // TODO: check/assert that the dno's name is in UTF16
+
+    // check buffer size
+    RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_efi_strsize(&dno->name);
+    if (*BufferSize < RequiredSize) {
+        // TODO: wind back the directory in this case
+
+#if DEBUG_LEVEL
+        Print(L"...BUFFER TOO SMALL\n");
+#endif
+        *BufferSize = RequiredSize;
+        return EFI_BUFFER_TOO_SMALL;
+    }
+
+    // fill structure
+    ZeroMem(Buffer, RequiredSize);
+    FileInfo = (EFI_FILE_INFO *)Buffer;
+    FileInfo->Size = RequiredSize;
+    FileInfo->FileSize          = dno->size;
+    FileInfo->Attribute         = 0;
+    if (dno->type == FSW_DNODE_TYPE_DIR)
+        FileInfo->Attribute    |= EFI_FILE_DIRECTORY;
+    fsw_efi_strcpy(FileInfo->FileName, &dno->name);
+
+    // get the missing info from the fs driver
+    ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
+    sb.store_time_posix = fsw_efi_store_time_posix;
+    sb.store_attr_posix = fsw_efi_store_attr_posix;
+    sb.host_data = FileInfo;
+    Status = fsw_efi_map_status(fsw_dnode_stat(dno, &sb), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+    FileInfo->PhysicalSize      = sb.used_bytes;
+
+    // prepare for return
+    *BufferSize = RequiredSize;
+#if DEBUG_LEVEL
+    Print(L"...returning '%s'\n", FileInfo->FileName);
+#endif
+    return EFI_SUCCESS;
+}
+
+// EOF
diff --git a/filesystems/fsw_efi.h b/filesystems/fsw_efi.h
new file mode 100644 (file)
index 0000000..6ca5a86
--- /dev/null
@@ -0,0 +1,118 @@
+/* $Id: fsw_efi.h 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * fsw_efi.h - EFI host environment header.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_EFI_H_
+#define _FSW_EFI_H_
+
+#include "fsw_core.h"
+
+// extern CHAR8     *msgCursor;
+// extern MESSAGE_LOG_PROTOCOL *Msg;
+
+/**
+ * EFI Host: Private per-volume structure.
+ */
+
+typedef struct {
+    UINT64                      Signature;      //!< Used to identify this structure
+
+    EFI_FILE_IO_INTERFACE       FileSystem;     //!< Published EFI protocol interface structure
+
+    EFI_HANDLE                  Handle;         //!< The device handle the protocol is attached to
+    EFI_DISK_IO                 *DiskIo;        //!< The Disk I/O protocol we use for disk access
+    UINT32                      MediaId;        //!< The media ID from the Block I/O protocol
+    EFI_STATUS                  LastIOStatus;   //!< Last status from Disk I/O
+
+    struct fsw_volume           *vol;           //!< FSW volume structure
+
+} FSW_VOLUME_DATA;
+
+/** Signature for the volume structure. */
+#define FSW_VOLUME_DATA_SIGNATURE  EFI_SIGNATURE_32 ('f', 's', 'w', 'V')
+/** Access macro for the volume structure. */
+#define FSW_VOLUME_FROM_FILE_SYSTEM(a)  CR (a, FSW_VOLUME_DATA, FileSystem, FSW_VOLUME_DATA_SIGNATURE)
+
+/**
+ * EFI Host: Private structure for a EFI_FILE interface.
+ */
+
+typedef struct {
+    UINT64                      Signature;      //!< Used to identify this structure
+
+    EFI_FILE                    FileHandle;     //!< Published EFI protocol interface structure
+
+    UINT64                       Type;           //!< File type used for dispatching
+    struct fsw_shandle          shand;          //!< FSW handle for this file
+
+} FSW_FILE_DATA;
+
+/** File type: regular file. */
+#define FSW_EFI_FILE_TYPE_FILE  (0)
+/** File type: directory. */
+#define FSW_EFI_FILE_TYPE_DIR   (1)
+
+/** Signature for the file handle structure. */
+#define FSW_FILE_DATA_SIGNATURE    EFI_SIGNATURE_32 ('f', 's', 'w', 'F')
+/** Access macro for the file handle structure. */
+#define FSW_FILE_FROM_FILE_HANDLE(a)  CR (a, FSW_FILE_DATA, FileHandle, FSW_FILE_DATA_SIGNATURE)
+
+
+//
+// Library functions
+//
+
+VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime);
+
+UINTN fsw_efi_strsize(struct fsw_string *s);
+VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src);
+
+
+#endif
diff --git a/filesystems/fsw_efi_base.h b/filesystems/fsw_efi_base.h
new file mode 100644 (file)
index 0000000..7c7af75
--- /dev/null
@@ -0,0 +1,98 @@
+/* $Id: fsw_efi_base.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_efi_base.h - Base definitions for the EFI host environment.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_EFI_BASE_H_
+#define _FSW_EFI_BASE_H_
+
+#ifndef VBOX
+#include <efi.h>
+#include <efilib.h>
+#define PROTO_NAME(x) x
+#endif
+
+#define FSW_LITTLE_ENDIAN (1)
+
+
+// types, reuse EFI types
+
+typedef INT8    fsw_s8;
+typedef UINT8   fsw_u8;
+typedef INT16   fsw_s16;
+typedef UINT16  fsw_u16;
+typedef INT32   fsw_s32;
+typedef UINT32  fsw_u32;
+typedef INT64   fsw_s64;
+typedef UINT64  fsw_u64;
+
+
+// allocation functions
+
+#define fsw_alloc(size, ptrptr) (((*(ptrptr) = AllocatePool(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS)
+#define fsw_free(ptr) FreePool(ptr)
+
+// memory functions
+
+#define fsw_memzero(dest,size) ZeroMem(dest,size)
+#define fsw_memcpy(dest,src,size) CopyMem(dest,src,size)
+#define fsw_memeq(p1,p2,size) (CompareMem(p1,p2,size) == 0)
+
+// message printing
+
+#define FSW_MSGSTR(s) L##s
+#define FSW_MSGFUNC Print
+
+// 64-bit hooks
+
+#define FSW_U64_SHR(val,shiftbits) RShiftU64((val), (shiftbits))
+#define FSW_U64_DIV(val,divisor) DivU64x32((val), (divisor), NULL)
+
+
+#endif
diff --git a/filesystems/fsw_efi_lib.c b/filesystems/fsw_efi_lib.c
new file mode 100644 (file)
index 0000000..956e9ee
--- /dev/null
@@ -0,0 +1,162 @@
+/* $Id: fsw_efi_lib.c 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_efi_lib.c - EFI host environment library functions.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_efi.h"
+
+
+//
+// time conversion
+//
+// Adopted from public domain code in FreeBSD libc.
+//
+
+#define SECSPERMIN      60
+#define MINSPERHOUR     60
+#define HOURSPERDAY     24
+#define DAYSPERWEEK     7
+#define DAYSPERNYEAR    365
+#define DAYSPERLYEAR    366
+#define SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY      ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR     12
+
+#define EPOCH_YEAR      1970
+#define EPOCH_WDAY      TM_THURSDAY
+
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+#define LEAPS_THRU_END_OF(y)    ((y) / 4 - (y) / 100 + (y) / 400)
+
+static const int mon_lengths[2][MONSPERYEAR] = {
+    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+static const int year_lengths[2] = {
+    DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime)
+{
+    long        days, rem;
+    int         y, newy, yleap;
+    const int   *ip;
+
+    ZeroMem(EfiTime, sizeof(EFI_TIME));
+
+    days = UnixTime / SECSPERDAY;
+    rem = UnixTime % SECSPERDAY;
+
+    EfiTime->Hour = (UINT8) (rem / SECSPERHOUR);
+    rem = rem % SECSPERHOUR;
+    EfiTime->Minute = (UINT8) (rem / SECSPERMIN);
+    EfiTime->Second = (UINT8) (rem % SECSPERMIN);
+
+    y = EPOCH_YEAR;
+    while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
+        newy = y + days / DAYSPERNYEAR;
+        if (days < 0)
+            --newy;
+        days -= (newy - y) * DAYSPERNYEAR +
+            LEAPS_THRU_END_OF(newy - 1) -
+            LEAPS_THRU_END_OF(y - 1);
+        y = newy;
+    }
+    EfiTime->Year = (UINT16)y;
+    ip = mon_lengths[yleap];
+    for (EfiTime->Month = 0; days >= (long) ip[EfiTime->Month]; ++(EfiTime->Month))
+        days = days - (long) ip[EfiTime->Month];
+    EfiTime->Month++;  // adjust range to EFI conventions
+    EfiTime->Day = (UINT8) (days + 1);
+}
+
+//
+// String functions, used for file and volume info
+//
+
+UINTN fsw_efi_strsize(struct fsw_string *s)
+{
+    if (s->type == FSW_STRING_TYPE_EMPTY)
+        return sizeof(CHAR16);
+    return (s->len + 1) * sizeof(CHAR16);
+}
+
+VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src)
+{
+    if (src->type == FSW_STRING_TYPE_EMPTY) {
+        Dest[0] = 0;
+    } else if (src->type == FSW_STRING_TYPE_UTF16) {
+        CopyMem(Dest, src->data, src->size);
+        Dest[src->len] = 0;
+    } else {
+        // TODO: coerce, recurse
+        Dest[0] = 0;
+    }
+}
+
+#ifdef VBOX
+int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+
+    for (i = 0; i<len; i++)
+    {
+        if (fsw_to_lower(p1[i]) != fsw_to_lower(p2[i]))
+        {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif
+
+// EOF
diff --git a/filesystems/fsw_ext2.c b/filesystems/fsw_ext2.c
new file mode 100644 (file)
index 0000000..5c98ede
--- /dev/null
@@ -0,0 +1,558 @@
+/**
+ * \file fsw_ext2.c
+ * ext2 file system driver code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will 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 to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "fsw_ext2.h"
+
+
+// functions
+
+static fsw_status_t fsw_ext2_volume_mount(struct fsw_ext2_volume *vol);
+static void         fsw_ext2_volume_free(struct fsw_ext2_volume *vol);
+static fsw_status_t fsw_ext2_volume_stat(struct fsw_ext2_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_ext2_dnode_fill(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno);
+static void         fsw_ext2_dnode_free(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno);
+static fsw_status_t fsw_ext2_dnode_stat(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                        struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_ext2_get_extent(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                        struct fsw_extent *extent);
+
+static fsw_status_t fsw_ext2_dir_lookup(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                        struct fsw_string *lookup_name, struct fsw_ext2_dnode **child_dno);
+static fsw_status_t fsw_ext2_dir_read(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                      struct fsw_shandle *shand, struct fsw_ext2_dnode **child_dno);
+static fsw_status_t fsw_ext2_read_dentry(struct fsw_shandle *shand, struct ext2_dir_entry *entry);
+
+static fsw_status_t fsw_ext2_readlink(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                      struct fsw_string *link);
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(ext2) = {
+    { FSW_STRING_TYPE_ISO88591, 4, 4, "ext2" },
+    sizeof(struct fsw_ext2_volume),
+    sizeof(struct fsw_ext2_dnode),
+    
+    fsw_ext2_volume_mount,
+    fsw_ext2_volume_free,
+    fsw_ext2_volume_stat,
+    fsw_ext2_dnode_fill,
+    fsw_ext2_dnode_free,
+    fsw_ext2_dnode_stat,
+    fsw_ext2_get_extent,
+    fsw_ext2_dir_lookup,
+    fsw_ext2_dir_read,
+    fsw_ext2_readlink,
+};
+
+/**
+ * Mount an ext2 volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_ext2_volume_mount(struct fsw_ext2_volume *vol)
+{
+    fsw_status_t    status;
+    void            *buffer;
+    fsw_u32         blocksize;
+    fsw_u32         groupcnt, groupno, gdesc_per_block, gdesc_bno, gdesc_index;
+    struct ext2_group_desc *gdesc;
+    int             i;
+    struct fsw_string s;
+    
+    // allocate memory to keep the superblock around
+    status = fsw_alloc(sizeof(struct ext2_super_block), &vol->sb);
+    if (status)
+        return status;
+    
+    // read the superblock into its buffer
+    fsw_set_blocksize(vol, EXT2_SUPERBLOCK_BLOCKSIZE, EXT2_SUPERBLOCK_BLOCKSIZE);
+    status = fsw_block_get(vol, EXT2_SUPERBLOCK_BLOCKNO, 0, &buffer);
+    if (status)
+        return status;
+    fsw_memcpy(vol->sb, buffer, sizeof(struct ext2_super_block));
+    fsw_block_release(vol, EXT2_SUPERBLOCK_BLOCKNO, buffer);
+    
+    // check the superblock
+    if (vol->sb->s_magic != EXT2_SUPER_MAGIC)
+        return FSW_UNSUPPORTED;
+    if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV &&
+        vol->sb->s_rev_level != EXT2_DYNAMIC_REV)
+        return FSW_UNSUPPORTED;
+    if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV &&
+        (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER)))
+        return FSW_UNSUPPORTED;
+
+    /*
+     if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV &&
+         (vol->sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER))
+     Print(L"Ext2 WARNING: This ext3 file system needs recovery, trying to use it anyway.\n");
+     */
+
+    // set real blocksize
+    blocksize = EXT2_BLOCK_SIZE(vol->sb);
+    fsw_set_blocksize(vol, blocksize, blocksize);
+
+    // get other info from superblock
+    vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb);
+    vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt;
+    vol->inode_size = EXT2_INODE_SIZE(vol->sb);
+
+    for (i = 0; i < 16; i++)
+        if (vol->sb->s_volume_name[i] == 0)
+            break;
+    s.type = FSW_STRING_TYPE_ISO88591;
+    s.size = s.len = i;
+    s.data = vol->sb->s_volume_name;
+    status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+    if (status)
+        return status;
+
+    // read the group descriptors to get inode table offsets
+    groupcnt = ((vol->sb->s_inodes_count - 2) / vol->sb->s_inodes_per_group) + 1;
+    gdesc_per_block = (vol->g.phys_blocksize / sizeof(struct ext2_group_desc));
+
+    status = fsw_alloc(sizeof(fsw_u32) * groupcnt, &vol->inotab_bno);
+    if (status)
+        return status;
+    for (groupno = 0; groupno < groupcnt; groupno++) {
+        // get the block group descriptor
+        gdesc_bno = (vol->sb->s_first_data_block + 1) + groupno / gdesc_per_block;
+        gdesc_index = groupno % gdesc_per_block;
+        status = fsw_block_get(vol, gdesc_bno, 1, (void **)&buffer);
+        if (status)
+            return status;
+        gdesc = ((struct ext2_group_desc *)(buffer)) + gdesc_index;
+        vol->inotab_bno[groupno] = gdesc->bg_inode_table;
+        fsw_block_release(vol, gdesc_bno, buffer);
+    }
+    
+    // setup the root dnode
+    status = fsw_dnode_create_root(vol, EXT2_ROOT_INO, &vol->g.root);
+    if (status)
+        return status;
+    
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext2_volume_mount: success, blocksize %d\n"), blocksize));
+    
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_ext2_volume_free(struct fsw_ext2_volume *vol)
+{
+    if (vol->sb)
+        fsw_free(vol->sb);
+    if (vol->inotab_bno)
+        fsw_free(vol->inotab_bno);
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_ext2_volume_stat(struct fsw_ext2_volume *vol, struct fsw_volume_stat *sb)
+{
+    sb->total_bytes = (fsw_u64)vol->sb->s_blocks_count      * vol->g.log_blocksize;
+    sb->free_bytes  = (fsw_u64)vol->sb->s_free_blocks_count * vol->g.log_blocksize;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode. In the case of ext2, we
+ * delay fetching of the inode structure until dnode_fill is called. The size and
+ * type fields are invalid until this function has been called.
+ */
+
+static fsw_status_t fsw_ext2_dnode_fill(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno)
+{
+    fsw_status_t    status;
+    fsw_u32         groupno, ino_in_group, ino_bno, ino_index;
+    fsw_u8          *buffer;
+    
+    if (dno->raw)
+        return FSW_SUCCESS;
+    
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext2_dnode_fill: inode %d\n"), dno->g.dnode_id));
+    
+    // read the inode block
+    groupno = (dno->g.dnode_id - 1) / vol->sb->s_inodes_per_group;
+    ino_in_group = (dno->g.dnode_id - 1) % vol->sb->s_inodes_per_group;
+    ino_bno = vol->inotab_bno[groupno] +
+        ino_in_group / (vol->g.phys_blocksize / vol->inode_size);
+    ino_index = ino_in_group % (vol->g.phys_blocksize / vol->inode_size);
+    status = fsw_block_get(vol, ino_bno, 2, (void **)&buffer);
+    if (status)
+        return status;
+    
+    // keep our inode around
+    status = fsw_memdup((void **)&dno->raw, buffer + ino_index * vol->inode_size, vol->inode_size);
+    fsw_block_release(vol, ino_bno, buffer);
+    if (status)
+        return status;
+    
+    // get info from the inode
+    dno->g.size = dno->raw->i_size;
+    // TODO: check docs for 64-bit sized files
+    if (S_ISREG(dno->raw->i_mode))
+        dno->g.type = FSW_DNODE_TYPE_FILE;
+    else if (S_ISDIR(dno->raw->i_mode))
+        dno->g.type = FSW_DNODE_TYPE_DIR;
+    else if (S_ISLNK(dno->raw->i_mode))
+        dno->g.type = FSW_DNODE_TYPE_SYMLINK;
+    else
+        dno->g.type = FSW_DNODE_TYPE_SPECIAL;
+    
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_ext2_dnode_free(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno)
+{
+    if (dno->raw)
+        fsw_free(dno->raw);
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_ext2_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_ext2_dnode_stat(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                        struct fsw_dnode_stat *sb)
+{
+    sb->used_bytes = dno->raw->i_blocks * 512;   // very, very strange...
+    sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime);
+    sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime);
+    sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime);
+    sb->store_attr_posix(sb, dno->raw->i_mode);
+    
+    return FSW_SUCCESS;
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_ext2_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ *
+ * The ext2 file system does not use extents, but stores a list of block numbers
+ * using the usual direct, indirect, double-indirect, triple-indirect scheme. To
+ * optimize access, this function checks if the following file blocks are mapped
+ * to consecutive disk blocks and returns a combined extent if possible.
+ */
+
+static fsw_status_t fsw_ext2_get_extent(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                        struct fsw_extent *extent)
+{
+    fsw_status_t    status;
+    fsw_u32         bno, release_bno, buf_bcnt, file_bcnt;
+    fsw_u32         *buffer;
+    int             path[5], i;
+    
+    // Preconditions: The caller has checked that the requested logical block
+    //  is within the file's size. The dnode has complete information, i.e.
+    //  fsw_ext2_dnode_read_info was called successfully on it.
+    
+    extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+    extent->log_count = 1;
+    bno = extent->log_start;
+    
+    // try direct block pointers in the inode
+    if (bno < EXT2_NDIR_BLOCKS) {
+        path[0] = bno;
+        path[1] = -1;
+    } else {
+        bno -= EXT2_NDIR_BLOCKS;
+        
+        // try indirect block
+        if (bno < vol->ind_bcnt) {
+            path[0] = EXT2_IND_BLOCK;
+            path[1] = bno;
+            path[2] = -1;
+        } else {
+            bno -= vol->ind_bcnt;
+        
+            // try double-indirect block
+            if (bno < vol->dind_bcnt) {
+                path[0] = EXT2_DIND_BLOCK;
+                path[1] = bno / vol->ind_bcnt;
+                path[2] = bno % vol->ind_bcnt;
+                path[3] = -1;
+            } else {
+                bno -= vol->dind_bcnt;
+                
+                // use the triple-indirect block
+                path[0] = EXT2_TIND_BLOCK;
+                path[1] = bno / vol->dind_bcnt;
+                path[2] = (bno / vol->ind_bcnt) % vol->ind_bcnt;
+                path[3] = bno % vol->ind_bcnt;
+                path[4] = -1;
+            }
+        }
+    }
+    
+    // follow the indirection path
+    buffer = dno->raw->i_block;
+    buf_bcnt = EXT2_NDIR_BLOCKS;
+    release_bno = 0;
+    for (i = 0; ; i++) {
+        bno = buffer[path[i]];
+        if (bno == 0) {
+            extent->type = FSW_EXTENT_TYPE_SPARSE;
+            if (release_bno)
+                fsw_block_release(vol, release_bno, buffer);
+            return FSW_SUCCESS;
+        }
+        if (path[i+1] < 0)
+            break;
+        
+        if (release_bno)
+            fsw_block_release(vol, release_bno, buffer);
+        status = fsw_block_get(vol, bno, 1, (void **)&buffer);
+        if (status)
+            return status;
+        release_bno = bno;
+        buf_bcnt = vol->ind_bcnt;
+    }
+    extent->phys_start = bno;
+    
+    // check if the following blocks can be aggregated into one extent
+    file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1));
+    while (path[i]           + extent->log_count < buf_bcnt &&    // indirect block has more block pointers
+           extent->log_start + extent->log_count < file_bcnt) {   // file has more blocks
+        if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1)
+            extent->log_count++;
+        else
+            break;
+    }
+    
+    if (release_bno)
+        fsw_block_release(vol, release_bno, buffer);
+    return FSW_SUCCESS;
+}
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_ext2_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_ext2_dir_lookup(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                        struct fsw_string *lookup_name, struct fsw_ext2_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_shandle shand;
+    fsw_u32         child_ino;
+    struct ext2_dir_entry entry;
+    struct fsw_string entry_name;
+    
+    // Preconditions: The caller has checked that dno is a directory node.
+    
+    entry_name.type = FSW_STRING_TYPE_ISO88591;
+    
+    // setup handle to read the directory
+    status = fsw_shandle_open(dno, &shand);
+    if (status)
+        return status;
+    
+    // scan the directory for the file
+    child_ino = 0;
+    while (child_ino == 0) {
+        // read next entry
+        status = fsw_ext2_read_dentry(&shand, &entry);
+        if (status)
+            goto errorexit;
+        if (entry.inode == 0) {
+            // end of directory reached
+            status = FSW_NOT_FOUND;
+            goto errorexit;
+        }
+        
+        // compare name
+        entry_name.len = entry_name.size = entry.name_len;
+        entry_name.data = entry.name;
+        if (fsw_streq(lookup_name, &entry_name)) {
+            child_ino = entry.inode;
+            break;
+        }
+    }
+    
+    // setup a dnode for the child item
+    status = fsw_dnode_create(dno, child_ino, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+    
+errorexit:
+    fsw_shandle_close(&shand);
+    return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_ext2_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_ext2_dir_read(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                      struct fsw_shandle *shand, struct fsw_ext2_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct ext2_dir_entry entry;
+    struct fsw_string entry_name;
+    
+    // Preconditions: The caller has checked that dno is a directory node. The caller
+    //  has opened a storage handle to the directory's storage and keeps it around between
+    //  calls.
+    
+    while (1) {
+        // read next entry
+        status = fsw_ext2_read_dentry(shand, &entry);
+        if (status)
+            return status;
+        if (entry.inode == 0)   // end of directory
+            return FSW_NOT_FOUND;
+        
+        // skip . and ..
+        if ((entry.name_len == 1 && entry.name[0] == '.') ||
+            (entry.name_len == 2 && entry.name[0] == '.' && entry.name[1] == '.'))
+            continue;
+        break;
+    }
+    
+    // setup name
+    entry_name.type = FSW_STRING_TYPE_ISO88591;
+    entry_name.len = entry_name.size = entry.name_len;
+    entry_name.data = entry.name;
+    
+    // setup a dnode for the child item
+    status = fsw_dnode_create(dno, entry.inode, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+    
+    return status;
+}
+
+/**
+ * Read a directory entry from the directory's raw data. This internal function is used
+ * to read a raw ext2 directory entry into memory. The shandle's position pointer is adjusted
+ * to point to the next entry.
+ */
+
+static fsw_status_t fsw_ext2_read_dentry(struct fsw_shandle *shand, struct ext2_dir_entry *entry)
+{
+    fsw_status_t    status;
+    fsw_u32         buffer_size;
+    
+    while (1) {
+        // read dir_entry header (fixed length)
+        buffer_size = 8;
+        status = fsw_shandle_read(shand, &buffer_size, entry);
+        if (status)
+            return status;
+        
+        if (buffer_size < 8 || entry->rec_len == 0) {
+            // end of directory reached
+            entry->inode = 0;
+            return FSW_SUCCESS;
+        }
+        if (entry->rec_len < 8)
+            return FSW_VOLUME_CORRUPTED;
+        if (entry->inode != 0) {
+            // this entry is used
+            if (entry->rec_len < 8 + entry->name_len)
+                return FSW_VOLUME_CORRUPTED;
+            break;
+        }
+        
+        // valid, but unused entry, skip it
+        shand->pos += entry->rec_len - 8;
+    }
+    
+    // read file name (variable length)
+    buffer_size = entry->name_len;
+    status = fsw_shandle_read(shand, &buffer_size, entry->name);
+    if (status)
+        return status;
+    if (buffer_size < entry->name_len)
+        return FSW_VOLUME_CORRUPTED;
+    
+    // skip any remaining padding
+    shand->pos += entry->rec_len - (8 + entry->name_len);
+    
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_ext2_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ * For ext2, the target path can be stored inline in the inode structure (in the space
+ * otherwise occupied by the block pointers) or in the inode's data. There is no flag
+ * indicating this, only the number of blocks entry (i_blocks) can be used as an
+ * indication. The check used here comes from the Linux kernel.
+ */
+
+static fsw_status_t fsw_ext2_readlink(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+                                      struct fsw_string *link_target)
+{
+    fsw_status_t    status;
+    int             ea_blocks;
+    struct fsw_string s;
+    
+    if (dno->g.size > FSW_PATH_MAX)
+        return FSW_VOLUME_CORRUPTED;
+    
+    ea_blocks = dno->raw->i_file_acl ? (vol->g.log_blocksize >> 9) : 0;
+    
+    if (dno->raw->i_blocks - ea_blocks == 0) {
+        // "fast" symlink, path is stored inside the inode
+        s.type = FSW_STRING_TYPE_ISO88591;
+        s.size = s.len = (int)dno->g.size;
+        s.data = dno->raw->i_block;
+        status = fsw_strdup_coerce(link_target, vol->g.host_string_type, &s);
+    } else {
+        // "slow" symlink, path is stored in normal inode data
+        status = fsw_dnode_readlink_data(dno, link_target);
+    }
+    
+    return status;
+}
+
+// EOF
diff --git a/filesystems/fsw_ext2.h b/filesystems/fsw_ext2.h
new file mode 100644 (file)
index 0000000..13b4caa
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+ * \file fsw_ext2.h
+ * ext2 file system driver header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will 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 to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _FSW_EXT2_H_
+#define _FSW_EXT2_H_
+
+#define VOLSTRUCTNAME fsw_ext2_volume
+#define DNODESTRUCTNAME fsw_ext2_dnode
+#include "fsw_core.h"
+
+#include "fsw_ext2_disk.h"
+
+
+//! Block size to be used when reading the ext2 superblock.
+#define EXT2_SUPERBLOCK_BLOCKSIZE  1024
+//! Block number where the (master copy of the) ext2 superblock resides.
+#define EXT2_SUPERBLOCK_BLOCKNO       1
+
+
+/**
+ * ext2: Volume structure with ext2-specific data.
+ */
+
+struct fsw_ext2_volume {
+    struct fsw_volume g;            //!< Generic volume structure
+    
+    struct ext2_super_block *sb;    //!< Full raw ext2 superblock structure
+    fsw_u32     *inotab_bno;        //!< Block numbers of the inode tables
+    fsw_u32     ind_bcnt;           //!< Number of blocks addressable through an indirect block
+    fsw_u32     dind_bcnt;          //!< Number of blocks addressable through a double-indirect block
+    fsw_u32     inode_size;         //!< Size of inode structure in bytes
+};
+
+/**
+ * ext2: Dnode structure with ext2-specific data.
+ */
+
+struct fsw_ext2_dnode {
+    struct fsw_dnode g;             //!< Generic dnode structure
+    
+    struct ext2_inode *raw;         //!< Full raw inode structure
+};
+
+
+#endif
diff --git a/filesystems/fsw_ext2_disk.h b/filesystems/fsw_ext2_disk.h
new file mode 100644 (file)
index 0000000..759c9bc
--- /dev/null
@@ -0,0 +1,367 @@
+/**
+ * \file fsw_ext2_disk.h
+ * ext2 file system on-disk structures.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ * Portions Copyright (c) 1991-2006 by various Linux kernel contributors
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will 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 to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _FSW_EXT2_DISK_H_
+#define _FSW_EXT2_DISK_H_
+
+// types
+
+typedef fsw_s8  __s8;
+typedef fsw_u8  __u8;
+typedef fsw_s16 __s16;
+typedef fsw_u16 __u16;
+typedef fsw_s32 __s32;
+typedef fsw_u32 __u32;
+typedef fsw_s64 __s64;
+typedef fsw_u64 __u64;
+
+typedef __u16   __le16;
+typedef __u32   __le32;
+typedef __u64   __le64;
+
+//
+// from Linux kernel, include/linux/ext2_fs.h
+//
+
+/*
+ * Special inode numbers
+ */
+#define EXT2_BAD_INO             1      /* Bad blocks inode */
+#define EXT2_ROOT_INO            2      /* Root inode */
+#define EXT2_BOOT_LOADER_INO     5      /* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO       6      /* Undelete directory inode */
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_SUPER_MAGIC        0xEF53
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT2_MIN_BLOCK_SIZE             1024
+#define EXT2_MAX_BLOCK_SIZE             4096
+#define EXT2_MIN_BLOCK_LOG_SIZE           10
+#define EXT2_BLOCK_SIZE(s)              (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#define EXT2_ADDR_PER_BLOCK(s)          (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
+#define EXT2_BLOCK_SIZE_BITS(s)         ((s)->s_log_block_size + 10)
+#define EXT2_INODE_SIZE(s)      (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+                                 EXT2_GOOD_OLD_INODE_SIZE : \
+                                 (s)->s_inode_size)
+#define EXT2_FIRST_INO(s)       (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+                                 EXT2_GOOD_OLD_FIRST_INO : \
+                                 (s)->s_first_ino)
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext2_group_desc
+{
+    __le32  bg_block_bitmap;        /* Blocks bitmap block */
+    __le32  bg_inode_bitmap;        /* Inodes bitmap block */
+    __le32  bg_inode_table;         /* Inodes table block */
+    __le16  bg_free_blocks_count;   /* Free blocks count */
+    __le16  bg_free_inodes_count;   /* Free inodes count */
+    __le16  bg_used_dirs_count;     /* Directories count */
+    __le16  bg_pad;
+    __le32  bg_reserved[3];
+};
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#define EXT2_BLOCKS_PER_GROUP(s)       ((s)->s_blocks_per_group)
+#define EXT2_DESC_PER_BLOCK(s)         (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+#define EXT2_INODES_PER_GROUP(s)       ((s)->s_inodes_per_group)
+
+/*
+ * Constants relative to the data blocks
+ */
+#define EXT2_NDIR_BLOCKS                12
+#define EXT2_IND_BLOCK                  EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK                 (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define EXT2_SECRM_FL                   0x00000001 /* Secure deletion */
+#define EXT2_UNRM_FL                    0x00000002 /* Undelete */
+#define EXT2_COMPR_FL                   0x00000004 /* Compress file */
+#define EXT2_SYNC_FL                    0x00000008 /* Synchronous updates */
+#define EXT2_IMMUTABLE_FL               0x00000010 /* Immutable file */
+#define EXT2_APPEND_FL                  0x00000020 /* writes to file may only append */
+#define EXT2_NODUMP_FL                  0x00000040 /* do not dump file */
+#define EXT2_NOATIME_FL                 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT2_DIRTY_FL                   0x00000100
+#define EXT2_COMPRBLK_FL                0x00000200 /* One or more compressed clusters */
+#define EXT2_NOCOMP_FL                  0x00000400 /* Don't compress */
+#define EXT2_ECOMPR_FL                  0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */      
+#define EXT2_BTREE_FL                   0x00001000 /* btree format dir */
+#define EXT2_INDEX_FL                   0x00001000 /* hash-indexed directory */
+#define EXT2_IMAGIC_FL                  0x00002000 /* AFS directory */
+#define EXT2_JOURNAL_DATA_FL            0x00004000 /* Reserved for ext3 */
+#define EXT2_NOTAIL_FL                  0x00008000 /* file tail should not be merged */
+#define EXT2_DIRSYNC_FL                 0x00010000 /* dirsync behaviour (directories only) */
+#define EXT2_TOPDIR_FL                  0x00020000 /* Top of directory hierarchies*/
+#define EXT2_RESERVED_FL                0x80000000 /* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE            0x0003DFFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE         0x000380FF /* User modifiable flags */
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext2_inode {
+    __le16  i_mode;         /* 0: File mode */
+    __le16  i_uid;          /* 2: Low 16 bits of Owner Uid */
+    __le32  i_size;         /* 4: Size in bytes */
+    __le32  i_atime;        /* 8: Access time */
+    __le32  i_ctime;        /* 12: Creation time */
+    __le32  i_mtime;        /* 16: Modification time */
+    __le32  i_dtime;        /* 20: Deletion Time */
+    __le16  i_gid;          /* 24: Low 16 bits of Group Id */
+    __le16  i_links_count;  /* 26: Links count */
+    __le32  i_blocks;       /* 28: Blocks count */
+    __le32  i_flags;        /* 32: File flags */
+    union {
+        struct {
+            __le32  l_i_reserved1;
+        } linux1;
+        struct {
+            __le32  h_i_translator;
+        } hurd1;
+        struct {
+            __le32  m_i_reserved1;
+        } masix1;
+    } osd1;                         /* 36: OS dependent 1 */
+    __le32  i_block[EXT2_N_BLOCKS];/* 40: Pointers to blocks */
+    __le32  i_generation;   /* 100: File version (for NFS) */
+    __le32  i_file_acl;     /* 104: File ACL */
+    __le32  i_dir_acl;      /* 108: Directory ACL */
+    __le32  i_faddr;        /* 112: Fragment address */
+    union {
+        struct {
+            __u8    l_i_frag;       /* 116: Fragment number */
+            __u8    l_i_fsize;      /* 117: Fragment size */
+            __u16   i_pad1;
+            __le16  l_i_uid_high;   /* 120: these 2 fields    */
+            __le16  l_i_gid_high;   /* 122: were reserved2[0] */
+            __u32   l_i_reserved2;
+        } linux2;
+        struct {
+            __u8    h_i_frag;       /* Fragment number */
+            __u8    h_i_fsize;      /* Fragment size */
+            __le16  h_i_mode_high;
+            __le16  h_i_uid_high;
+            __le16  h_i_gid_high;
+            __le32  h_i_author;
+        } hurd2;
+        struct {
+            __u8    m_i_frag;       /* Fragment number */
+            __u8    m_i_fsize;      /* Fragment size */
+            __u16   m_pad1;
+            __u32   m_i_reserved2[2];
+        } masix2;
+    } osd2;                         /* OS dependent 2 */
+};
+
+#define i_size_high     i_dir_acl
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+    __le32  s_inodes_count;         /* Inodes count */
+    __le32  s_blocks_count;         /* Blocks count */
+    __le32  s_r_blocks_count;       /* Reserved blocks count */
+    __le32  s_free_blocks_count;    /* Free blocks count */
+    __le32  s_free_inodes_count;    /* Free inodes count */
+    __le32  s_first_data_block;     /* First Data Block */
+    __le32  s_log_block_size;       /* Block size */
+    __le32  s_log_frag_size;        /* Fragment size */
+    __le32  s_blocks_per_group;     /* # Blocks per group */
+    __le32  s_frags_per_group;      /* # Fragments per group */
+    __le32  s_inodes_per_group;     /* # Inodes per group */
+    __le32  s_mtime;                /* Mount time */
+    __le32  s_wtime;                /* Write time */
+    __le16  s_mnt_count;            /* Mount count */
+    __le16  s_max_mnt_count;        /* Maximal mount count */
+    __le16  s_magic;                /* Magic signature */
+    __le16  s_state;                /* File system state */
+    __le16  s_errors;               /* Behaviour when detecting errors */
+    __le16  s_minor_rev_level;      /* minor revision level */
+    __le32  s_lastcheck;            /* time of last check */
+    __le32  s_checkinterval;        /* max. time between checks */
+    __le32  s_creator_os;           /* OS */
+    __le32  s_rev_level;            /* Revision level */
+    __le16  s_def_resuid;           /* Default uid for reserved blocks */
+    __le16  s_def_resgid;           /* Default gid for reserved blocks */
+    /*
+     * These fields are for EXT2_DYNAMIC_REV superblocks only.
+     *
+     * Note: the difference between the compatible feature set and
+     * the incompatible feature set is that if there is a bit set
+     * in the incompatible feature set that the kernel doesn't
+     * know about, it should refuse to mount the filesystem.
+     * 
+     * e2fsck's requirements are more strict; if it doesn't know
+     * about a feature in either the compatible or incompatible
+     * feature set, it must abort and not try to meddle with
+     * things it doesn't understand...
+     */
+    __le32  s_first_ino;            /* First non-reserved inode */
+    __le16  s_inode_size;           /* size of inode structure */
+    __le16  s_block_group_nr;       /* block group # of this superblock */
+    __le32  s_feature_compat;       /* compatible feature set */
+    __le32  s_feature_incompat;     /* incompatible feature set */
+    __le32  s_feature_ro_compat;    /* readonly-compatible feature set */
+    __u8    s_uuid[16];             /* 128-bit uuid for volume */
+    char    s_volume_name[16];      /* volume name */
+    char    s_last_mounted[64];     /* directory where last mounted */
+    __le32  s_algorithm_usage_bitmap; /* For compression */
+    /*
+     * Performance hints.  Directory preallocation should only
+     * happen if the EXT2_COMPAT_PREALLOC flag is on.
+     */
+    __u8    s_prealloc_blocks;      /* Nr of blocks to try to preallocate*/
+    __u8    s_prealloc_dir_blocks;  /* Nr to preallocate for dirs */
+    __u16   s_padding1;
+    /*
+     * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
+     */
+    __u8    s_journal_uuid[16];     /* uuid of journal superblock */
+    __u32   s_journal_inum;         /* inode number of journal file */
+    __u32   s_journal_dev;          /* device number of journal file */
+    __u32   s_last_orphan;          /* start of list of inodes to delete */
+    __u32   s_hash_seed[4];         /* HTREE hash seed */
+    __u8    s_def_hash_version;     /* Default hash version to use */
+    __u8    s_reserved_char_pad;
+    __u16   s_reserved_word_pad;
+    __le32  s_default_mount_opts;
+    __le32  s_first_meta_bg;        /* First metablock block group */
+    __u32   s_reserved[190];        /* Padding to the end of the block */
+};
+
+/*
+ * Revision levels
+ */
+#define EXT2_GOOD_OLD_REV       0       /* The good old (original) format */
+#define EXT2_DYNAMIC_REV        1       /* V2 format w/ dynamic inode sizes */
+
+#define EXT2_CURRENT_REV        EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV       EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask)                        \
+        ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)                     \
+        ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)                      \
+        ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
+#define EXT2_SET_COMPAT_FEATURE(sb,mask)                        \
+        EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
+#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask)                     \
+        EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
+#define EXT2_SET_INCOMPAT_FEATURE(sb,mask)                      \
+        EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
+#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask)                      \
+        EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
+#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask)                   \
+        EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
+#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask)                    \
+        EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC        0x0001
+#define EXT2_FEATURE_COMPAT_IMAGIC_INODES       0x0002
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL         0x0004
+#define EXT2_FEATURE_COMPAT_EXT_ATTR            0x0008
+#define EXT2_FEATURE_COMPAT_RESIZE_INO          0x0010
+#define EXT2_FEATURE_COMPAT_DIR_INDEX           0x0020
+#define EXT2_FEATURE_COMPAT_ANY                 0xffffffff
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER     0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE       0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR        0x0004
+#define EXT2_FEATURE_RO_COMPAT_ANY              0xffffffff
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION       0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE          0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER           0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV       0x0008
+#define EXT2_FEATURE_INCOMPAT_META_BG           0x0010
+#define EXT2_FEATURE_INCOMPAT_ANY               0xffffffff
+
+/*
+#define EXT2_FEATURE_COMPAT_SUPP        EXT2_FEATURE_COMPAT_EXT_ATTR
+#define EXT2_FEATURE_INCOMPAT_SUPP      (EXT2_FEATURE_INCOMPAT_FILETYPE| \
+                                         EXT2_FEATURE_INCOMPAT_META_BG)
+#define EXT2_FEATURE_RO_COMPAT_SUPP     (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+                                         EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+                                         EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED      ~EXT2_FEATURE_RO_COMPAT_SUPP
+#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED       ~EXT2_FEATURE_INCOMPAT_SUPP
+*/
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT2_NAME_LEN 255
+
+struct ext2_dir_entry {
+    __le32  inode;                  /* Inode number */
+    __le16  rec_len;                /* Directory entry length */
+    __u8    name_len;               /* Name length */
+    __u8    file_type;
+    char    name[EXT2_NAME_LEN];    /* File name */
+};
+// NOTE: The original Linux kernel header defines ext2_dir_entry with the original
+//  layout and ext2_dir_entry_2 with the revised layout. We simply use the revised one.
+
+/*
+ * Ext2 directory file types.  Only the low 3 bits are used.  The
+ * other bits are reserved for now.
+ */
+enum {
+    EXT2_FT_UNKNOWN,
+    EXT2_FT_REG_FILE,
+    EXT2_FT_DIR,
+    EXT2_FT_CHRDEV,
+    EXT2_FT_BLKDEV,
+    EXT2_FT_FIFO,
+    EXT2_FT_SOCK,
+    EXT2_FT_SYMLINK,
+    EXT2_FT_MAX
+};
+
+
+#endif
diff --git a/filesystems/fsw_hfs.c b/filesystems/fsw_hfs.c
new file mode 100644 (file)
index 0000000..59823c6
--- /dev/null
@@ -0,0 +1,1320 @@
+/* $Id: fsw_hfs.c 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * fsw_hfs.c - HFS file system driver code, see
+ *
+ *   http://developer.apple.com/technotes/tn/tn1150.html
+ *
+ * Current limitations:
+ *  - Doesn't support permissions
+ *  - Complete Unicode case-insensitiveness disabled (large tables)
+ *  - No links
+ *  - Only supports pure HFS+ (i.e. no HFS, or HFS+ embedded to HFS)
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "fsw_hfs.h"
+
+#ifdef HOST_POSIX
+#define DPRINT(x) printf(x)
+#define DPRINT2(x,y) printf(x,y)
+#define BP(msg)    do { printf("ERROR: %s", msg); asm("int3"); } while (0)
+#else
+#define CONCAT(x,y) x##y
+#define DPRINT(x) Print(CONCAT(L,x))
+#define DPRINT2(x,y) Print(CONCAT(L,x), y)
+#define BP(msg) DPRINT(msg)
+#endif
+
+// functions
+#if 0
+void dump_str(fsw_u16* p, fsw_u32 len, int swap)
+{
+    int i;
+
+    for (i=0; i<len; i++)
+    {
+        fprintf(stderr, "%c", swap ? be16_to_cpu(p[i]) : p[i]);
+    }
+    fprintf(stderr, "\n");
+}
+#endif
+
+static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol);
+static void         fsw_hfs_volume_free(struct fsw_hfs_volume *vol);
+static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
+static void         fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
+static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                           struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                           struct fsw_extent *extent);
+
+static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                           struct fsw_string *lookup_name, struct fsw_hfs_dnode **child_dno);
+static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                         struct fsw_shandle *shand, struct fsw_hfs_dnode **child_dno);
+#if 0
+static fsw_status_t fsw_hfs_read_dirrec(struct fsw_shandle *shand, struct hfs_dirrec_buffer *dirrec_buffer);
+#endif
+
+static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                         struct fsw_string *link);
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(hfs) = {
+    { FSW_STRING_TYPE_ISO88591, 4, 4, "hfs" },
+    sizeof(struct fsw_hfs_volume),
+    sizeof(struct fsw_hfs_dnode),
+
+    fsw_hfs_volume_mount, // volume open
+    fsw_hfs_volume_free,  // volume close
+    fsw_hfs_volume_stat,  // volume info: total_bytes, free_bytes
+    fsw_hfs_dnode_fill,   //return FSW_SUCCESS;
+    fsw_hfs_dnode_free,          // empty
+    fsw_hfs_dnode_stat,         //size and times
+    fsw_hfs_get_extent,         // get the physical disk block number for the requested logical block number
+    fsw_hfs_dir_lookup,  //retrieve the directory entry with the given name
+    fsw_hfs_dir_read,  // next directory entry when reading a directory
+    fsw_hfs_readlink,   // return FSW_UNSUPPORTED;
+};
+
+static fsw_s32
+fsw_hfs_read_block (struct fsw_hfs_dnode    * dno,
+                    fsw_u32                   log_bno,
+                    fsw_u32                   off,
+                    fsw_s32                   len,
+                    fsw_u8                  * buf)
+{
+    fsw_status_t          status;
+    struct fsw_extent     extent;
+    fsw_u32               phys_bno;
+    fsw_u8*                 buffer;
+
+    extent.log_start = log_bno;
+    status = fsw_hfs_get_extent(dno->g.vol, dno, &extent);
+    if (status)
+        return status;
+
+    phys_bno = extent.phys_start;
+  //Slice - increase cache level from 0 to 3
+    status = fsw_block_get(dno->g.vol, phys_bno, 3, (void **)&buffer);
+    if (status)
+        return status;
+
+    fsw_memcpy(buf, buffer + off, len);
+
+    fsw_block_release(dno->g.vol, phys_bno, buffer);
+
+    return FSW_SUCCESS;
+
+}
+
+/* Read data from HFS file. */
+static fsw_s32
+fsw_hfs_read_file (struct fsw_hfs_dnode    * dno,
+                   fsw_u64                   pos,
+                   fsw_s32                   len,
+                   fsw_u8                  * buf)
+{
+
+    fsw_status_t          status;
+    fsw_u32               log_bno;
+    fsw_u32               block_size_bits = dno->g.vol->block_size_shift;
+    fsw_u32               block_size = (1 << block_size_bits);
+    fsw_u32               block_size_mask = block_size - 1;
+    fsw_s32               read = 0;
+
+    while (len > 0)
+    {
+        fsw_u32 off = (fsw_u32)(pos & block_size_mask);
+        fsw_s32 next_len = len;
+
+        log_bno = (fsw_u32)RShiftU64(pos, block_size_bits);
+
+        if (   next_len >= 0
+            && (fsw_u32)next_len >  block_size)
+            next_len = block_size;
+        status = fsw_hfs_read_block(dno, log_bno, off, next_len, buf);
+        if (status)
+            return -1;
+        buf  += next_len;
+        pos  += next_len;
+        len  -= next_len;
+        read += next_len;
+    }
+
+    return read;
+}
+
+
+static fsw_s32
+fsw_hfs_compute_shift(fsw_u32 size)
+{
+    fsw_s32 i;
+
+    for (i=0; i<32; i++)
+    {
+        if ((size >> i) == 0)
+            return i - 1;
+    }
+
+//    BP("BUG\n");
+    return 0;
+}
+
+/**
+ * Mount an HFS+ volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+//algo from Chameleon
+/*
+void
+HFSGetDescription(CICell ih, char *str, long strMaxLen)
+{
+  
+  UInt16 nodeSize;
+  UInt32 firstLeafNode;
+  long long dirIndex;
+  char *name;
+  long flags, time;
+  
+  if (HFSInitPartition(ih) == -1)  { return; }
+  
+  // Fill some crucial data structures by side effect. 
+  dirIndex = 0;
+  HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);
+  
+  // Now we can loook up the volume name node. 
+  nodeSize = be16_to_cpu(gBTHeaders[kBTreeCatalog]->nodeSize);
+  firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);
+  
+  dirIndex = (long long) firstLeafNode * nodeSize;
+  
+  GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);
+  
+  strncpy(str, name, strMaxLen);
+  str[strMaxLen] = '\0';
+}
+*/
+
+
+static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol)
+{
+    fsw_status_t           status, rv;
+    void                  *buffer = NULL;
+    HFSPlusVolumeHeader   *voldesc;
+    fsw_u32                blockno;
+    struct fsw_string      s;
+  HFSMasterDirectoryBlock* mdb;
+  UINTN i;
+
+    rv = FSW_UNSUPPORTED;
+
+    vol->primary_voldesc = NULL;
+    fsw_set_blocksize(vol, HFS_BLOCKSIZE, HFS_BLOCKSIZE);
+    blockno = HFS_SUPERBLOCK_BLOCKNO;
+
+#define CHECK(s)         \
+        if (status)  {   \
+            rv = status; \
+            break;       \
+        }
+
+    vol->emb_block_off = 0;
+    vol->hfs_kind = 0;
+    do {
+        fsw_u16       signature;
+        BTHeaderRec   tree_header;
+        fsw_s32       r;
+        fsw_u32       block_size;
+
+        status = fsw_block_get(vol, blockno, 0, &buffer);
+        CHECK(status);
+        voldesc = (HFSPlusVolumeHeader *)buffer;
+        mdb = (HFSMasterDirectoryBlock*)buffer;
+        signature = be16_to_cpu(voldesc->signature);
+
+        if ((signature == kHFSPlusSigWord) || (signature == kHFSXSigWord)) //H+ or HX
+        {
+            if (vol->hfs_kind == 0)
+            {
+    //            DPRINT("found HFS+\n");
+                vol->hfs_kind = FSW_HFS_PLUS;
+            }
+        }
+        else if (signature == kHFSSigWord) // 'BD'
+        {
+//            HFSMasterDirectoryBlock* mdb = (HFSMasterDirectoryBlock*)buffer;
+//VolumeName = mdb->drVN 28bytes
+            if (be16_to_cpu(mdb->drEmbedSigWord) == kHFSPlusSigWord)
+            {
+                DPRINT("found HFS+ inside HFS, untested\n");
+                vol->hfs_kind = FSW_HFS_PLUS_EMB;
+                vol->emb_block_off = be32_to_cpu(mdb->drEmbedExtent.startBlock);
+                blockno += vol->emb_block_off;
+                /* retry */
+                continue;
+            }
+            else
+            {
+                DPRINT("found plain HFS, unsupported\n");
+                vol->hfs_kind = FSW_HFS_PLAIN;
+            }
+            rv = FSW_UNSUPPORTED;
+            break;
+        }
+        else
+        {
+            rv = FSW_UNSUPPORTED;
+            break;
+        }
+
+        status = fsw_memdup((void **)&vol->primary_voldesc, voldesc,
+                            sizeof(*voldesc));
+        CHECK(status);
+
+
+        block_size = be32_to_cpu(voldesc->blockSize);
+        vol->block_size_shift = fsw_hfs_compute_shift(block_size);
+
+        fsw_block_release(vol, blockno, buffer);
+        buffer = NULL;
+        voldesc = NULL;
+        fsw_set_blocksize(vol, block_size, block_size);
+
+        /* get volume name */
+      for (i = kHFSMaxVolumeNameChars; i > 0; i--)
+        if (mdb->drVN[i-1] != ' ')
+          break;
+      
+        s.type = FSW_STRING_TYPE_ISO88591;
+        s.size = s.len = 0;
+      s.data = NULL; //&mdb->drVN; //"HFS+ volume";
+      
+       //fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src)
+        status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+        CHECK(status);
+
+        /* Setup catalog dnode */
+        status = fsw_dnode_create_root(vol, kHFSCatalogFileID, &vol->catalog_tree.file);
+        CHECK(status);
+        fsw_memcpy (vol->catalog_tree.file->extents,
+                    vol->primary_voldesc->catalogFile.extents,
+                    sizeof vol->catalog_tree.file->extents);
+        vol->catalog_tree.file->g.size =
+                be64_to_cpu(vol->primary_voldesc->catalogFile.logicalSize);
+
+        /* Setup extents overflow file */
+        status = fsw_dnode_create_root(vol, kHFSExtentsFileID, &vol->extents_tree.file);
+        fsw_memcpy (vol->extents_tree.file->extents,
+                    vol->primary_voldesc->extentsFile.extents,
+                    sizeof vol->extents_tree.file->extents);
+        vol->extents_tree.file->g.size =
+                be64_to_cpu(vol->primary_voldesc->extentsFile.logicalSize);
+
+        /* Setup the root dnode */
+        status = fsw_dnode_create_root(vol, kHFSRootFolderID, &vol->g.root);
+        CHECK(status);
+
+        /*
+         * Read catalog file, we know that first record is in the first node, right after
+         * the node descriptor.
+         */
+        r = fsw_hfs_read_file(vol->catalog_tree.file,
+                              sizeof (BTNodeDescriptor),
+                              sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
+        if (r <= 0)
+        {
+            status = FSW_VOLUME_CORRUPTED;
+            break;
+        }
+        vol->case_sensitive =
+                (signature == kHFSXSigWord) &&
+                (tree_header.keyCompareType == kHFSBinaryCompare);
+        vol->catalog_tree.root_node = be32_to_cpu (tree_header.rootNode);
+        vol->catalog_tree.node_size = be16_to_cpu (tree_header.nodeSize);
+
+        /* Read extents overflow file */
+        r = fsw_hfs_read_file(vol->extents_tree.file,
+                              sizeof (BTNodeDescriptor),
+                              sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
+        if (r <= 0)
+        {
+            status = FSW_VOLUME_CORRUPTED;
+            break;
+        }
+
+        vol->extents_tree.root_node = be32_to_cpu (tree_header.rootNode);
+        vol->extents_tree.node_size = be16_to_cpu (tree_header.nodeSize);
+
+        rv = FSW_SUCCESS;
+    } while (0);
+
+#undef CHECK
+
+
+    if (buffer != NULL)
+        fsw_block_release(vol, blockno, buffer);
+
+    return rv;
+}
+//Here is a method to obtain Volume label from Apple
+//how to implement it?
+/*
+UInt16 nodeSize;
+UInt32 firstLeafNode;
+long long dirIndex;
+char *name;
+long flags, time;
+ char              *nodeBuf, *testKey, *entry;
+
+
+if (HFSInitPartition(ih) == -1)  { return; }
+
+// Fill some crucial data structures by side effect. 
+dirIndex = 0;
+HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);
+
+// Now we can loook up the volume name node.
+nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);
+firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);
+
+dirIndex = (long long) firstLeafNode * nodeSize;
+ index   = (long) (*dirIndex % nodeSize); == 0
+ curNode = (long) (*dirIndex / nodeSize); == firstLeafNode
+
+//GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);
+ // Read the BTree node and get the record for index.
+ ReadExtent(extent, extentSize, kHFSCatalogFileID,
+ (long long) curNode * nodeSize, nodeSize, nodeBuf, 1);
+ GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry);
+ utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode,
+ SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length),
+ (u_int8_t *)gTempStr, 256, OSBigEndian);
+ *name = gTempStr; 
+
+strncpy(str, name, strMaxLen);
+str[strMaxLen] = '\0';
+*/
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol)
+{
+    if (vol->primary_voldesc)
+    {
+        fsw_free(vol->primary_voldesc);
+        vol->primary_voldesc = NULL;
+    }
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb)
+{
+    sb->total_bytes = be32_to_cpu(vol->primary_voldesc->totalBlocks) << vol->block_size_shift;
+    sb->free_bytes = be32_to_cpu(vol->primary_voldesc->freeBlocks) << vol->block_size_shift;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode.
+ */
+
+static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
+{
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
+{
+}
+
+static fsw_u32 mac_to_posix(fsw_u32 mac_time)
+{
+  /* Mac time is 1904 year based */
+  return mac_time ?  mac_time - 2082844800 : 0;
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_hfs_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol,
+                                       struct fsw_hfs_dnode  *dno,
+                                       struct fsw_dnode_stat *sb)
+{
+  sb->used_bytes = dno->used_bytes;
+  sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, mac_to_posix(dno->ctime));
+  sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, mac_to_posix(dno->mtime));
+  sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0);
+  sb->store_attr_posix(sb, 0700);
+
+  return FSW_SUCCESS;
+}
+
+static int
+fsw_hfs_find_block(HFSPlusExtentRecord * exts,
+                   fsw_u32             * lbno,
+                   fsw_u32             * pbno)
+{
+    int i;
+    fsw_u32 cur_lbno = *lbno;
+
+    for (i = 0; i < 8; i++)
+    {
+        fsw_u32 start = be32_to_cpu ((*exts)[i].startBlock);
+        fsw_u32 count = be32_to_cpu ((*exts)[i].blockCount);
+
+        if (cur_lbno < count)
+        {
+            *pbno = start + cur_lbno;
+            return 1;
+        }
+
+        cur_lbno -= count;
+    }
+
+    *lbno = cur_lbno;
+
+    return 0;
+}
+
+/* Find record offset, numbering starts from the end */
+static fsw_u32
+fsw_hfs_btree_recoffset (struct fsw_hfs_btree * btree,
+                         BTNodeDescriptor     * node,
+                         fsw_u32                index)
+{
+  fsw_u8 *cnode = (fsw_u8 *) node;
+  fsw_u16 *recptr;
+  recptr = (fsw_u16 *) (cnode+btree->node_size - index * 2 - 2);
+  return be16_to_cpu(*recptr);
+}
+
+/* Pointer to the key inside node */
+static BTreeKey *
+fsw_hfs_btree_rec (struct fsw_hfs_btree   * btree,
+                   BTNodeDescriptor       * node,
+                   fsw_u32                  index)
+{
+  fsw_u8 *cnode = (fsw_u8 *) node;
+  fsw_u32 offset;
+  offset = fsw_hfs_btree_recoffset (btree, node, index);
+  return (BTreeKey *) (cnode + offset);
+}
+
+
+static fsw_status_t
+fsw_hfs_btree_search (struct fsw_hfs_btree * btree,
+                      BTreeKey             * key,
+                      int (*compare_keys) (BTreeKey* key1, BTreeKey* key2),
+                      BTNodeDescriptor    ** result,
+                      fsw_u32              * key_offset)
+{
+    BTNodeDescriptor* node;
+    fsw_u32 currnode;
+    fsw_u32 rec;
+    fsw_status_t status;
+    fsw_u8* buffer = NULL;
+
+    currnode = btree->root_node;
+    status = fsw_alloc(btree->node_size, &buffer);
+    if (status)
+        return status;
+    node = (BTNodeDescriptor*)buffer;
+
+    while (1)
+    {
+        int cmp = 0;
+        int match;
+        fsw_u32 count;
+
+    readnode:
+        match = 0;
+        /* Read a node.  */
+        if (fsw_hfs_read_file (btree->file,
+                               (fsw_u64)currnode * btree->node_size,
+                               btree->node_size, buffer) <= 0)
+        {
+            status = FSW_VOLUME_CORRUPTED;
+            break;
+        }
+
+        if (be16_to_cpu(*(fsw_u16*)(buffer + btree->node_size - 2)) != sizeof(BTNodeDescriptor))
+            BP("corrupted node\n");
+
+        count = be16_to_cpu (node->numRecords);
+
+#if 1
+        for (rec = 0; rec < count; rec++)
+        {
+             BTreeKey *currkey;
+
+             currkey = fsw_hfs_btree_rec (btree, node, rec);
+             cmp = compare_keys (currkey, key);
+             //fprintf(stderr, "rec=%d cmp=%d kind=%d \n", rec, cmp, node->kind);
+
+             /* Leaf node. */
+             if (node->kind == kBTLeafNode)
+             {
+               if (cmp == 0)
+               {
+                 /* Found!  */
+                 *result = node;
+                 *key_offset = rec;
+
+                 status = FSW_SUCCESS;
+                 goto done;
+               }
+             }
+             else if (node->kind == kBTIndexNode)
+             {
+                 fsw_u32 *pointer;
+
+                 if (cmp > 0)
+                     break;
+
+                 pointer = (fsw_u32 *) ((char *) currkey
+                                        + be16_to_cpu (currkey->length16)
+                                        + 2);
+                 currnode = be32_to_cpu (*pointer);
+                 match = 1;
+             }
+        }
+
+        if (node->kind == kBTLeafNode && cmp < 0 && node->fLink)
+        {
+            currnode = be32_to_cpu(node->fLink);
+            goto readnode;
+        }
+        else if (!match)
+        {
+            status = FSW_NOT_FOUND;
+            break;
+        }
+#else
+         /* Perform binary search */
+         fsw_u32 lower = 0;
+         fsw_u32 upper = count - 1;
+         fsw_s32 cmp = -1;
+         BTreeKey *currkey = NULL;
+
+         if (count == 0)
+         {
+             status = FSW_NOT_FOUND;
+             goto done;
+         }
+
+         while (lower <= upper)
+         {
+             fsw_u32 index = (lower + upper) / 2;
+
+             currkey = fsw_hfs_btree_rec (btree, node, index);
+
+             cmp = compare_keys (currkey, key);
+             if (cmp < 0)  upper = index - 1;
+             if (cmp > 0)  lower = index + 1;
+             if (cmp == 0)
+             {
+                 /* Found!  */
+                 *result = node;
+                 *key_offset = rec;
+
+                 status = FSW_SUCCESS;
+                 goto done;
+             }
+         }
+
+         if (cmp < 0)
+             currkey = fsw_hfs_btree_rec (btree, node, upper);
+
+         if (node->kind == kBTIndexNode && currkey)
+         {
+             fsw_u32 *pointer;
+
+             pointer = (fsw_u32 *) ((char *) currkey
+                                    + be16_to_cpu (currkey->length16)
+                                    + 2);
+             currnode = be32_to_cpu (*pointer);
+         }
+         else
+         {
+             status = FSW_NOT_FOUND;
+             break;
+         }
+#endif
+    }
+
+
+  done:
+    if (buffer != NULL && status != FSW_SUCCESS)
+        fsw_free(buffer);
+
+    return status;
+}
+typedef struct
+{
+    fsw_u32                 id;
+    fsw_u32                 type;
+    struct fsw_string     * name;
+    fsw_u64                 size;
+    fsw_u64                 used;
+    fsw_u32                 ctime;
+    fsw_u32                 mtime;
+    HFSPlusExtentRecord     extents;
+} file_info_t;
+
+typedef struct
+{
+    fsw_u32                 cur_pos; /* current position */
+    fsw_u32                 parent;
+    struct fsw_hfs_volume * vol;
+
+    struct fsw_shandle *    shandle; /* this one track iterator's state */
+    file_info_t             file_info;
+} visitor_parameter_t;
+
+static int
+fsw_hfs_btree_visit_node(BTreeKey *record, void* param)
+{
+    visitor_parameter_t* vp = (visitor_parameter_t*)param;
+    fsw_u8* base = (fsw_u8*)record->rawData + be16_to_cpu(record->length16) + 2;
+    fsw_u16 rec_type =  be16_to_cpu(*(fsw_u16*)base);
+    struct HFSPlusCatalogKey* cat_key = (HFSPlusCatalogKey*)record;
+    fsw_u16   name_len;
+    fsw_u16   *name_ptr;
+    fsw_u32   i;
+    struct fsw_string * file_name;
+
+    if (be32_to_cpu(cat_key->parentID) != vp->parent)
+        return -1;
+
+    /* not smth we care about */
+    if (vp->shandle->pos != vp->cur_pos++)
+        return 0;
+
+    switch (rec_type)
+    {
+        case kHFSPlusFolderRecord:
+        {
+            HFSPlusCatalogFolder* folder_info = (HFSPlusCatalogFolder*)base;
+
+            vp->file_info.id = be32_to_cpu(folder_info->folderID);
+            vp->file_info.type = FSW_DNODE_TYPE_DIR;
+            vp->file_info.size = be32_to_cpu(folder_info->valence);
+            vp->file_info.used = be32_to_cpu(folder_info->valence);
+            vp->file_info.ctime = be32_to_cpu(folder_info->createDate);
+            vp->file_info.mtime = be32_to_cpu(folder_info->contentModDate);
+            break;
+        }
+        case kHFSPlusFileRecord:
+        {
+            HFSPlusCatalogFile* file_info = (HFSPlusCatalogFile*)base;
+
+            vp->file_info.id = be32_to_cpu(file_info->fileID);
+            vp->file_info.type = FSW_DNODE_TYPE_FILE;
+            vp->file_info.size = be64_to_cpu(file_info->dataFork.logicalSize);
+            vp->file_info.used = LShiftU64(be32_to_cpu(file_info->dataFork.totalBlocks),
+                                           vp->vol->block_size_shift);
+            vp->file_info.ctime = be32_to_cpu(file_info->createDate);
+            vp->file_info.mtime = be32_to_cpu(file_info->contentModDate);
+            fsw_memcpy(&vp->file_info.extents, &file_info->dataFork.extents,
+                       sizeof vp->file_info.extents);
+            break;
+        }
+        case kHFSPlusFolderThreadRecord:
+        case kHFSPlusFileThreadRecord:
+        {
+            vp->shandle->pos++;
+            return 0;
+        }
+        default:
+            BP("unknown file type\n");
+            vp->file_info.type = FSW_DNODE_TYPE_UNKNOWN;
+            break;
+    }
+
+    name_len = be16_to_cpu(cat_key->nodeName.length);
+
+    file_name =  vp->file_info.name;
+    file_name->len = name_len;
+    fsw_memdup(&file_name->data, &cat_key->nodeName.unicode[0], 2*name_len);
+    file_name->size = 2*name_len;
+    file_name->type = FSW_STRING_TYPE_UTF16;
+    name_ptr = (fsw_u16*)file_name->data;
+    for (i=0; i<name_len; i++)
+    {
+        name_ptr[i] = be16_to_cpu(name_ptr[i]);
+    }
+    vp->shandle->pos++;
+
+    return 1;
+}
+
+static fsw_status_t
+fsw_hfs_btree_iterate_node (struct fsw_hfs_btree * btree,
+                            BTNodeDescriptor     * first_node,
+                            fsw_u32                first_rec,
+                            int                    (*callback) (BTreeKey *record, void* param),
+                            void                  * param)
+{
+  fsw_status_t status;
+  /* We modify node, so make a copy */
+  BTNodeDescriptor*     node = first_node;
+  fsw_u8* buffer = NULL;
+
+  status = fsw_alloc(btree->node_size, &buffer);
+  if (status)
+      return status;
+
+  while (1)
+  {
+      fsw_u32 i;
+      fsw_u32 count =  be16_to_cpu(node->numRecords);
+      fsw_u32 next_node;
+
+      /* Iterate over all records in this node.  */
+      for (i = first_rec; i < count; i++)
+      {
+          int rv = callback(fsw_hfs_btree_rec (btree, node, i), param);
+
+          switch (rv)
+          {
+              case 1:
+                  status = FSW_SUCCESS;
+                  goto done;
+              case -1:
+                  status = FSW_NOT_FOUND;
+                  goto done;
+          }
+          /* if callback returned 0 - continue */
+      }
+
+      next_node = be32_to_cpu(node->fLink);
+
+      if (!next_node)
+      {
+          status = FSW_NOT_FOUND;
+          break;
+      }
+
+      if (fsw_hfs_read_file (btree->file,
+                             next_node * btree->node_size,
+                             btree->node_size, buffer) <= 0)
+      {
+          status = FSW_VOLUME_CORRUPTED;
+          return 1;
+      }
+
+      node = (BTNodeDescriptor*)buffer;
+      first_rec = 0;
+  }
+ done:
+  if (buffer)
+      fsw_free(buffer);
+
+  return status;
+}
+
+#if 0
+void deb(fsw_u16* p, int len, int swap)
+{
+    int i;
+    for (i=0; i<len; i++)
+    {
+      printf("%c", swap ?  be16_to_cpu(p[i]) : p[i]);
+    }
+    printf("\n");
+}
+#endif
+
+static int
+fsw_hfs_cmp_extkey(BTreeKey* key1, BTreeKey* key2)
+{
+    HFSPlusExtentKey* ekey1 = (HFSPlusExtentKey*)key1;
+    HFSPlusExtentKey* ekey2 = (HFSPlusExtentKey*)key2;
+    int result;
+
+    /* First key is read from the FS data, second is in-memory in CPU endianess */
+    result = be32_to_cpu(ekey1->fileID) - ekey2->fileID;
+
+    if (result)
+        return result;
+
+    result = ekey1->forkType - ekey2->forkType;
+
+    if (result)
+        return result;
+
+    result = be32_to_cpu(ekey1->startBlock) - ekey2->startBlock;
+    return result;
+}
+
+static int
+fsw_hfs_cmp_catkey (BTreeKey *key1, BTreeKey *key2)
+{
+  HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
+  HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
+
+  int      apos, bpos, lc;
+  fsw_u16  ac, bc;
+  fsw_u32  parentId1;
+  int      key1Len;
+  fsw_u16 *p1;
+  fsw_u16 *p2;
+
+  parentId1 = be32_to_cpu(ckey1->parentID);
+
+  if (parentId1 > ckey2->parentID)
+      return 1;
+  if (parentId1 < ckey2->parentID)
+      return -1;
+
+  p1 = &ckey1->nodeName.unicode[0];
+  p2 = &ckey2->nodeName.unicode[0];
+  key1Len = be16_to_cpu (ckey1->nodeName.length);
+  apos = bpos = 0;
+
+  while(1)
+  {
+    /* get next valid character from ckey1 */
+    for (lc = 0; lc == 0 && apos < key1Len; apos++) {
+      ac = be16_to_cpu(p1[apos]);
+      lc = ac;
+    };
+    ac = (fsw_u16)lc;
+
+    /* get next valid character from ckey2 */
+    for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
+      bc = p2[bpos];
+      lc = bc;
+    };
+    bc = (fsw_u16)lc;
+
+    if (ac != bc || (ac == 0  && bc == 0))
+      return ac - bc;
+  }
+}
+
+static int
+fsw_hfs_cmpi_catkey (BTreeKey *key1, BTreeKey *key2)
+{
+  HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
+  HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
+
+  int      apos, bpos, lc;
+  fsw_u16  ac, bc;
+  fsw_u32  parentId1;
+  int      key1Len;
+  fsw_u16 *p1;
+  fsw_u16 *p2;
+
+  parentId1 = be32_to_cpu(ckey1->parentID);
+
+  if (parentId1 > ckey2->parentID)
+      return 1;
+  if (parentId1 < ckey2->parentID)
+      return -1;
+
+  key1Len = be16_to_cpu (ckey1->nodeName.length);
+
+  if (key1Len == 0 && ckey2->nodeName.length == 0)
+      return 0;
+
+  p1 = &ckey1->nodeName.unicode[0];
+  p2 = &ckey2->nodeName.unicode[0];
+
+  apos = bpos = 0;
+
+  while(1)
+  {
+    /* get next valid character from ckey1 */
+    for (lc = 0; lc == 0 && apos < key1Len; apos++) {
+      ac = be16_to_cpu(p1[apos]);
+      lc = ac ? fsw_to_lower(ac) : 0;
+    };
+    ac = (fsw_u16)lc;
+
+    /* get next valid character from ckey2 */
+    for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
+      bc = p2[bpos];
+      lc = bc ? fsw_to_lower(bc) : 0;
+    };
+    bc = (fsw_u16)lc;
+
+    if (ac != bc || (ac == 0  && bc == 0))
+      return ac - bc;
+  }
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_hfs_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume * vol,
+                                       struct fsw_hfs_dnode  * dno,
+                                       struct fsw_extent     * extent)
+{
+    fsw_status_t         status;
+    fsw_u32              lbno;
+    HFSPlusExtentRecord  *exts;
+    BTNodeDescriptor     *node = NULL;
+
+    extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+    extent->log_count = 1;
+    lbno = extent->log_start;
+
+    /* we only care about data forks atm, do we? */
+    exts = &dno->extents;
+
+    while (1)
+    {
+        struct HFSPlusExtentKey* key;
+        struct HFSPlusExtentKey  overflowkey;
+        fsw_u32                  ptr;
+        fsw_u32                  phys_bno;
+
+        if (fsw_hfs_find_block(exts, &lbno, &phys_bno))
+        {
+            extent->phys_start = phys_bno + vol->emb_block_off;
+            status = FSW_SUCCESS;
+            break;
+        }
+
+
+        /* Find appropriate overflow record */
+        overflowkey.fileID = dno->g.dnode_id;
+        overflowkey.startBlock = extent->log_start - lbno;
+
+        if (node != NULL)
+        {
+            fsw_free(node);
+            node = NULL;
+        }
+
+        status = fsw_hfs_btree_search (&vol->extents_tree,
+                                       (BTreeKey*)&overflowkey,
+                                       fsw_hfs_cmp_extkey,
+                                       &node, &ptr);
+        if (status)
+            break;
+
+        key = (struct HFSPlusExtentKey *)
+                fsw_hfs_btree_rec (&vol->extents_tree, node, ptr);
+        exts = (HFSPlusExtentRecord*) (key + 1);
+    }
+
+    if (node != NULL)
+        fsw_free(node);
+
+    return status;
+}
+
+static const fsw_u16* g_blacklist[] =
+{
+    //L"AppleIntelCPUPowerManagement.kext",
+    NULL
+};
+
+
+//#define HFS_FILE_INJECTION
+
+#ifdef HFS_FILE_INJECTION
+static struct
+{
+  const fsw_u16* path;
+  const fsw_u16* name;
+} g_injectList[] =
+{
+  {
+    L"/System/Library/Extensions",
+    L"ApplePS2Controller.kext"
+  },
+  {
+    NULL,
+    NULL
+  }
+};
+#endif
+
+static fsw_status_t
+create_hfs_dnode(struct fsw_hfs_dnode  * dno,
+                 file_info_t           * file_info,
+                 struct fsw_hfs_dnode ** child_dno_out)
+{
+    fsw_status_t           status;
+    struct fsw_hfs_dnode * baby;
+
+    status = fsw_dnode_create(dno, file_info->id, file_info->type,
+                              file_info->name, &baby);
+    if (status)
+        return status;
+
+    baby->g.size = file_info->size;
+    baby->used_bytes = file_info->used;
+    baby->ctime = file_info->ctime;
+    baby->mtime = file_info->mtime;
+
+
+    /* Fill-in extents info */
+    if (file_info->type == FSW_DNODE_TYPE_FILE)
+    {
+        fsw_memcpy(baby->extents, &file_info->extents, sizeof file_info->extents);
+    }
+
+    *child_dno_out = baby;
+
+    return FSW_SUCCESS;
+}
+
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume * vol,
+                                       struct fsw_hfs_dnode  * dno,
+                                       struct fsw_string     * lookup_name,
+                                       struct fsw_hfs_dnode ** child_dno_out)
+{
+    fsw_status_t               status;
+    struct HFSPlusCatalogKey   catkey;
+    fsw_u32                    ptr;
+    fsw_u16                    rec_type;
+    BTNodeDescriptor *         node = NULL;
+    struct fsw_string          rec_name;
+    int                        free_data = 0, i;
+    HFSPlusCatalogKey*         file_key;
+    file_info_t                file_info;
+    fsw_u8*                    base;
+
+
+    fsw_memzero(&file_info, sizeof file_info);
+    file_info.name = &rec_name;
+
+    catkey.parentID = dno->g.dnode_id;
+    catkey.nodeName.length = (fsw_u16)lookup_name->len;
+
+    /* no need to allocate anything */
+    if (lookup_name->type == FSW_STRING_TYPE_UTF16)
+    {
+        fsw_memcpy(catkey.nodeName.unicode, lookup_name->data, lookup_name->size);
+        rec_name = *lookup_name;
+    } else
+    {
+        status = fsw_strdup_coerce(&rec_name, FSW_STRING_TYPE_UTF16, lookup_name);
+        /* nothing allocated so far */
+        if (status)
+            goto done;
+        free_data = 1;
+        fsw_memcpy(catkey.nodeName.unicode, rec_name.data, rec_name.size);
+    }
+
+    /* Dirty hack: blacklisting of certain files on FS driver level */
+    for (i = 0; g_blacklist[i]; i++)
+    {
+        if (fsw_memeq(g_blacklist[i], catkey.nodeName.unicode, catkey.nodeName.length*2))
+        {
+            DPRINT2("Blacklisted %s\n", g_blacklist[i]);
+            status = FSW_NOT_FOUND;
+            goto done;
+        }
+    }
+
+#ifdef HFS_FILE_INJECTION
+    if (fsw_hfs_inject(vol,
+                       dno,
+                       catkey.nodeName.unicode,
+                       catkey.nodeName.length,
+                       &file_info))
+    {
+        status = FSW_SUCCESS;
+        goto create;
+    }
+#endif
+
+    catkey.keyLength = (fsw_u16)(5 + rec_name.size);
+
+    status = fsw_hfs_btree_search (&vol->catalog_tree,
+                                   (BTreeKey*)&catkey,
+                                   vol->case_sensitive ?
+                                       fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
+                                   &node, &ptr);
+    if (status)
+        goto done;
+
+    file_key = (HFSPlusCatalogKey *)fsw_hfs_btree_rec (&vol->catalog_tree, node, ptr);
+    /* for plain HFS "-(keySize & 1)" would be needed */
+    base = (fsw_u8*)file_key + be16_to_cpu(file_key->keyLength) + 2;
+    rec_type =  be16_to_cpu(*(fsw_u16*)base);
+
+    /** @todo: read additional info */
+    switch (rec_type)
+    {
+        case kHFSPlusFolderRecord:
+        {
+            HFSPlusCatalogFolder* info = (HFSPlusCatalogFolder*)base;
+
+            file_info.id = be32_to_cpu(info->folderID);
+            file_info.type = FSW_DNODE_TYPE_DIR;
+            /* @todo: return number of elements, maybe use smth else */
+            file_info.size = be32_to_cpu(info->valence);
+            file_info.used = be32_to_cpu(info->valence);
+            file_info.ctime = be32_to_cpu(info->createDate);
+            file_info.mtime = be32_to_cpu(info->contentModDate);
+            break;
+        }
+        case kHFSPlusFileRecord:
+        {
+            HFSPlusCatalogFile* info = (HFSPlusCatalogFile*)base;
+
+            file_info.id = be32_to_cpu(info->fileID);
+            file_info.type = FSW_DNODE_TYPE_FILE;
+            file_info.size = be64_to_cpu(info->dataFork.logicalSize);
+            file_info.used = LShiftU64(be32_to_cpu(info->dataFork.totalBlocks), vol->block_size_shift);
+            file_info.ctime = be32_to_cpu(info->createDate);
+            file_info.mtime = be32_to_cpu(info->contentModDate);
+            fsw_memcpy(&file_info.extents, &info->dataFork.extents,
+                       sizeof file_info.extents);
+            break;
+        }
+        default:
+            BP("unknown file type\n");
+            file_info.type = FSW_DNODE_TYPE_UNKNOWN;
+
+            break;
+    }
+#ifdef HFS_FILE_INJECTION
+create:
+#endif
+    status = create_hfs_dnode(dno, &file_info, child_dno_out);
+    if (status)
+        goto done;
+
+done:
+
+    if (node != NULL)
+        fsw_free(node);
+
+    if (free_data)
+        fsw_strfree(&rec_name);
+
+    return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol,
+                                     struct fsw_hfs_dnode  *dno,
+                                     struct fsw_shandle    *shand,
+                                     struct fsw_hfs_dnode  **child_dno_out)
+{
+    fsw_status_t               status;
+    struct HFSPlusCatalogKey   catkey;
+    fsw_u32                    ptr;
+    BTNodeDescriptor *         node = NULL;
+
+    visitor_parameter_t        param;
+    struct fsw_string          rec_name;
+
+    catkey.parentID = dno->g.dnode_id;
+    catkey.nodeName.length = 0;
+
+    fsw_memzero(&param, sizeof(param));
+
+    rec_name.type = FSW_STRING_TYPE_EMPTY;
+    param.file_info.name = &rec_name;
+
+    status = fsw_hfs_btree_search (&vol->catalog_tree,
+                                   (BTreeKey*)&catkey,
+                                   vol->case_sensitive ?
+                                       fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
+                                   &node, &ptr);
+    if (status)
+        goto done;
+
+    /* Iterator updates shand state */
+    param.vol = vol;
+    param.shandle = shand;
+    param.parent = dno->g.dnode_id;
+    param.cur_pos = 0;
+    status = fsw_hfs_btree_iterate_node (&vol->catalog_tree,
+                                         node,
+                                         ptr,
+                                         fsw_hfs_btree_visit_node,
+                                         &param);
+    if (status)
+      goto done;
+
+    status = create_hfs_dnode(dno, &param.file_info, child_dno_out);
+
+    if (status)
+        goto done;
+
+ done:
+    fsw_strfree(&rec_name);
+
+    return status;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_hfs_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ */
+static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+                                     struct fsw_string *link_target)
+{
+    return FSW_UNSUPPORTED;
+}
+
+// EOF
diff --git a/filesystems/fsw_hfs.h b/filesystems/fsw_hfs.h
new file mode 100644 (file)
index 0000000..6d63643
--- /dev/null
@@ -0,0 +1,192 @@
+/* $Id: fsw_hfs.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_hfs.h - HFS file system driver header.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef _FSW_HFS_H_
+#define _FSW_HFS_H_
+
+#define VOLSTRUCTNAME fsw_hfs_volume
+#define DNODESTRUCTNAME fsw_hfs_dnode
+
+#include "fsw_core.h"
+
+
+//! Block size for HFS volumes.
+#define HFS_BLOCKSIZE            512
+
+//! Block number where the HFS superblock resides.
+#define HFS_SUPERBLOCK_BLOCKNO   2
+
+/* Make world look Applish enough for the system header describing HFS layout  */
+#define __APPLE_API_PRIVATE
+#define __APPLE_API_UNSTABLE
+
+#define u_int8_t  fsw_u8
+#define u_int16_t fsw_u16
+#define u_int32_t fsw_u32
+#define u_int64_t fsw_u64
+#define int8_t    fsw_s8
+#define int16_t   fsw_s16
+#define int32_t   fsw_s32
+#define int64_t   fsw_s64
+
+#include "hfs_format.h"
+
+#undef u_int8_t
+#undef u_int16_t
+#undef u_int32_t
+#undef u_int64_t
+#undef int8_t
+#undef int16_t
+#undef int32_t
+#undef int64_t
+
+#pragma pack(1)
+#ifdef _MSC_VER
+/* vasily: disable warning for non-standard anonymous struct/union
+ * declarations
+ */
+# pragma warning (disable:4201)
+# define inline __inline
+#endif
+
+struct hfs_dirrec {
+    fsw_u8      _dummy;
+};
+
+struct fsw_hfs_key
+{
+  union
+  {
+    struct HFSPlusExtentKey  ext_key;
+    struct HFSPlusCatalogKey cat_key;
+    fsw_u16                  key_len; /* Length is at the beginning of all keys */
+  };
+};
+
+#pragma pack()
+
+typedef enum {
+    /* Regular HFS */
+    FSW_HFS_PLAIN = 0,
+    /* HFS+ */
+    FSW_HFS_PLUS,
+    /* HFS+ embedded to HFS */
+    FSW_HFS_PLUS_EMB
+} fsw_hfs_kind;
+
+/**
+ * HFS: Dnode structure with HFS-specific data.
+ */
+
+struct fsw_hfs_dnode
+{
+  struct fsw_dnode          g;          //!< Generic dnode structure
+  HFSPlusExtentRecord       extents;
+  fsw_u32                   ctime;
+  fsw_u32                   mtime;
+  fsw_u64                   used_bytes;
+};
+
+/**
+ * HFS: In-memory B-tree structure.
+ */
+struct fsw_hfs_btree
+{
+    fsw_u32                  root_node;
+    fsw_u32                  node_size;
+    struct fsw_hfs_dnode*    file;
+};
+
+
+/**
+ * HFS: In-memory volume structure with HFS-specific data.
+ */
+
+struct fsw_hfs_volume
+{
+    struct fsw_volume            g;            //!< Generic volume structure
+
+    struct HFSPlusVolumeHeader   *primary_voldesc;  //!< Volume Descriptor
+    struct fsw_hfs_btree          catalog_tree;     // Catalog tree
+    struct fsw_hfs_btree          extents_tree;     // Extents overflow tree
+    struct fsw_hfs_dnode          root_file;
+    int                           case_sensitive;
+    fsw_u32                       block_size_shift;
+    fsw_hfs_kind                  hfs_kind;
+    fsw_u32                       emb_block_off;
+};
+
+/* Endianess swappers */
+static inline fsw_u16
+swab16(fsw_u16 x)
+{
+    return (x<<8 | ((x & 0xff00)>>8));
+}
+
+static inline fsw_u32
+swab32(fsw_u32 x)
+{
+    return x<<24 | x>>24 |
+            (x & (fsw_u32)0x0000ff00UL)<<8 |
+            (x & (fsw_u32)0x00ff0000UL)>>8;
+}
+
+
+static inline fsw_u64
+swab64(fsw_u64 x)
+{
+    return x<<56 | x>>56 |
+            (x & (fsw_u64)0x000000000000ff00ULL)<<40 |
+            (x & (fsw_u64)0x0000000000ff0000ULL)<<24 |
+            (x & (fsw_u64)0x00000000ff000000ULL)<< 8 |
+            (x & (fsw_u64)0x000000ff00000000ULL)>> 8 |
+            (x & (fsw_u64)0x0000ff0000000000ULL)>>24 |
+            (x & (fsw_u64)0x00ff000000000000ULL)>>40;
+}
+
+static inline fsw_u16
+be16_to_cpu(fsw_u16 x)
+{
+    return swab16(x);
+}
+
+static inline fsw_u16
+cpu_to_be16(fsw_u16 x)
+{
+    return swab16(x);
+}
+
+
+static inline fsw_u32
+cpu_to_be32(fsw_u32 x)
+{
+    return swab32(x);
+}
+
+static inline fsw_u32
+be32_to_cpu(fsw_u32 x)
+{
+    return swab32(x);
+}
+
+static inline fsw_u64
+be64_to_cpu(fsw_u64 x)
+{
+    return swab64(x);
+}
+
+#endif
diff --git a/filesystems/fsw_iso9660.c b/filesystems/fsw_iso9660.c
new file mode 100644 (file)
index 0000000..271c924
--- /dev/null
@@ -0,0 +1,704 @@
+/* $Id: fsw_iso9660.c 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * fsw_iso9660.c - ISO9660 file system driver code.
+ *
+ * Current limitations:
+ *  - Files must be in one extent (i.e. Level 2)
+ *  - No Joliet or Rock Ridge extensions
+ *  - No interleaving
+ *  - inode number generation strategy fails on volumes > 2 GB
+ *  - No blocksizes != 2048
+ *  - No High Sierra or anything else != 'CD001'
+ *  - No volume sets with directories pointing at other volumes
+ *  - No extended attribute records
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_iso9660.h"
+//#include <Protocol/MsgLog.h>
+
+#ifndef DEBUG_ISO
+#define DEBUG_ISO 1
+#endif
+
+#if DEBUG_ISO == 2
+#define DBG(x...)      AsciiPrint(x)
+#elif DEBUG_ISO == 1
+#define DBG(x...)      BootLog(x)
+#else
+#define DBG(x...)
+#endif
+
+//#define MsgLog(x...) if(msgCursor){AsciiSPrint(msgCursor, BOOTER_LOG_SIZE, x); while(*msgCursor){msgCursor++;}}
+
+// extern CHAR8     *msgCursor;
+// extern MESSAGE_LOG_PROTOCOL *Msg;
+// functions
+
+static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol);
+static void         fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol);
+static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno);
+static void         fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno);
+static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_extent *extent);
+
+static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno);
+static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                         struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno);
+static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer);
+
+static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                         struct fsw_string *link);
+
+static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp);
+static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str);
+static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin);
+//static void dump_dirrec(struct iso9660_dirrec *dirrec);
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(iso9660) = {
+    { FSW_STRING_TYPE_ISO88591, 4, 4, "iso9660" },
+    sizeof(struct fsw_iso9660_volume),
+    sizeof(struct fsw_iso9660_dnode),
+
+    fsw_iso9660_volume_mount,
+    fsw_iso9660_volume_free,
+    fsw_iso9660_volume_stat,
+    fsw_iso9660_dnode_fill,
+    fsw_iso9660_dnode_free,
+    fsw_iso9660_dnode_stat,
+    fsw_iso9660_get_extent,
+    fsw_iso9660_dir_lookup,
+    fsw_iso9660_dir_read,
+    fsw_iso9660_readlink,
+};
+
+static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp)
+{
+    fsw_u8 *r;
+    int off = 0;
+    struct fsw_rock_ridge_susp_sp *sp;
+    r = (fsw_u8 *)((fsw_u8 *)dirrec + sizeof(*dirrec) + dirrec->file_identifier_length);
+    off = (int)(r - (fsw_u8 *)dirrec);
+    while(off < dirrec->dirrec_length)
+    {
+        if (*r == 'S')
+        {
+            sp = (struct fsw_rock_ridge_susp_sp *)r;
+            if(    sp->e.sig[0] == 'S'
+                && sp->e.sig[1] == 'P'
+                && sp->magic[0] == 0xbe
+                && sp->magic[1] == 0xef)
+            {
+                *psp = sp;
+                return FSW_SUCCESS;
+            }
+        }
+        r++;
+        off = (int)(r - (fsw_u8 *)dirrec);
+    }
+    *psp = NULL;
+    return FSW_NOT_FOUND;
+}
+
+static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str)
+{
+    fsw_u8 *r, *begin;
+    int fCe = 0;
+    struct fsw_rock_ridge_susp_nm *nm;
+    int limit = dirrec->dirrec_length;
+    begin = (fsw_u8 *)dirrec;
+    r = (fsw_u8 *)dirrec + off;
+    str->data = NULL;
+    str->len = 0;
+    str->size = 0;
+    str->type = 0;
+    while(off < limit)
+    {
+        if (r[0] == 'C' && r[1] == 'E' && r[2] == 28)
+        {
+            int rc;
+            int ce_off;
+            union fsw_rock_ridge_susp_ce *ce;
+            if (fCe == 0)
+                fsw_alloc_zero(ISO9660_BLOCKSIZE, (void *)&begin);
+            fCe = 1;
+        //    DEBUG((DEBUG_WARN, "%a:%d we found CE before NM or its continuation\n", __FILE__, __LINE__));
+            ce = (union fsw_rock_ridge_susp_ce *)r;
+            limit = ISOINT(ce->X.len);
+            ce_off = ISOINT(ce->X.offset);
+            rc = rr_read_ce(vol, ce, begin);
+            if (rc != FSW_SUCCESS)
+            {
+                fsw_free(begin);
+                return rc;
+            }
+            begin += ce_off;
+            r = begin;
+        }
+        if (r[0] == 'N' && r[1] == 'M')
+        {
+            nm = (struct fsw_rock_ridge_susp_nm *)r;
+            if(    nm->e.sig[0] == 'N'
+                && nm->e.sig[1] == 'M')
+            {
+                int len = 0;
+                fsw_u8 *tmp = NULL;
+                if (nm->flags & RR_NM_CURR)
+                {
+                     fsw_memdup(str->data, ".", 1);
+                     str->len = 1;
+                     goto done;
+                }
+                if (nm->flags & RR_NM_PARE)
+                {
+                     fsw_memdup(str->data, "..", 2);
+                     str->len = 2;
+                     goto done;
+                }
+                len = nm->e.len - sizeof(struct fsw_rock_ridge_susp_nm) + 1;
+                fsw_alloc_zero(str->len + len, (void **)&tmp);
+                if (str->data != NULL)
+                {
+                    fsw_memcpy(tmp, str->data, str->len);
+                    fsw_free(str->data);
+                }
+           //     DEBUG((DEBUG_INFO, "dst:%p src:%p len:%d\n", tmp + str->len, &nm->name[0], len));
+                fsw_memcpy(tmp + str->len, &nm->name[0], len);
+                str->data = tmp;
+                str->len += len;
+
+                if ((nm->flags & RR_NM_CONT) == 0);
+                    goto done;
+            }
+        }
+        r++;
+        off = (int)(r - (fsw_u8 *)begin);
+    }
+    if(fCe == 1)
+        fsw_free(begin);
+    return FSW_NOT_FOUND;
+done:
+    str->type = FSW_STRING_TYPE_ISO88591;
+    str->size = str->len;
+    if(fCe == 1)
+        fsw_free(begin);
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin)
+{
+    int rc;
+//    int i;
+//    fsw_u8 *r = begin + ISOINT(ce->X.offset);
+//    int len = ISOINT(ce->X.len);
+    rc = vol->g.host_table->read_block(&vol->g, ISOINT(ce->X.block_loc), begin);
+    if (rc != FSW_SUCCESS)
+        return rc;
+/*    for (i = 0; i < len; ++i)
+    {
+        DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i]));
+    }*/
+    return FSW_SUCCESS;
+}
+/*
+static void dump_dirrec(struct iso9660_dirrec *dirrec)
+{
+    int i;
+    fsw_u8 *r = (fsw_u8 *)dirrec + dirrec->file_identifier_length;
+    int len = dirrec->dirrec_length;
+    for (i = dirrec->file_identifier_length; i < len; ++i)
+    {
+        DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i]));
+    }
+}*/
+/**
+ * Mount an ISO9660 volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol)
+{
+    fsw_status_t    status;
+    void            *buffer;
+    fsw_u32         blockno;
+    struct iso9660_volume_descriptor *voldesc;
+    struct iso9660_primary_volume_descriptor *pvoldesc;
+    fsw_u32         voldesc_type;
+    int             i;
+    struct fsw_string s;
+    struct iso9660_dirrec rootdir;
+    int sua_pos;
+    char *sig;
+    int skip;
+    struct fsw_rock_ridge_susp_entry *entry;
+
+    // read through the Volume Descriptor Set
+    fsw_set_blocksize(vol, ISO9660_BLOCKSIZE, ISO9660_BLOCKSIZE);
+    blockno = ISO9660_SUPERBLOCK_BLOCKNO;
+
+    do {
+//      DBG("iso9660: check blockno=%d\n", blockno);
+        status = fsw_block_get(vol, blockno, 0, &buffer);
+        if (status)
+            return status;
+
+        voldesc = (struct iso9660_volume_descriptor *)buffer;
+        voldesc_type = voldesc->volume_descriptor_type;
+        if (fsw_memeq(voldesc->standard_identifier, "CD001", 5)) {
+            // descriptor follows ISO 9660 standard
+            if (voldesc_type == 1 && voldesc->volume_descriptor_version == 1) {
+                // suitable Primary Volume Descriptor found
+//              DBG("iso9660: suitable Primary Volume Descriptor found\n");
+                if (vol->primary_voldesc) {
+                    fsw_free(vol->primary_voldesc);
+                    vol->primary_voldesc = NULL;
+                }
+                status = fsw_memdup((void **)&vol->primary_voldesc, voldesc, ISO9660_BLOCKSIZE);
+            }
+        } else if (!fsw_memeq(voldesc->standard_identifier, "CD", 2)) {
+            // completely alien standard identifier, stop reading
+            voldesc_type = 255;
+        }
+
+        fsw_block_release(vol, blockno, buffer);
+        blockno++;
+    } while (!status && voldesc_type != 255);
+    if (status)
+        return status;
+
+    // get information from Primary Volume Descriptor
+    if (vol->primary_voldesc == NULL)
+        return FSW_UNSUPPORTED;
+    pvoldesc = vol->primary_voldesc;
+    if (ISOINT(pvoldesc->logical_block_size) != 2048)
+        return FSW_UNSUPPORTED;
+
+    // get volume name
+    for (i = 32; i > 0; i--)
+        if (pvoldesc->volume_identifier[i-1] != ' ')
+            break;
+    s.type = FSW_STRING_TYPE_ISO88591;
+    s.size = s.len = i;
+    s.data = pvoldesc->volume_identifier;
+    status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+    if (status)
+        return status;
+
+    // setup the root dnode
+    status = fsw_dnode_create_root(vol, ISO9660_SUPERBLOCK_BLOCKNO << ISO9660_BLOCKSIZE_BITS, &vol->g.root);
+    if (status)
+        return status;
+    fsw_memcpy(&vol->g.root->dirrec, &pvoldesc->root_directory, sizeof(struct iso9660_dirrec));
+
+    if (   pvoldesc->escape[0] == 0x25
+        && pvoldesc->escape[1] == 0x2f
+        && (   pvoldesc->escape[2] == 0x40
+            || pvoldesc->escape[2] == 0x43
+            || pvoldesc->escape[2] == 0x45))
+    {
+ //       FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (joliet!!!)\n")));
+//      DBG("fsw_iso9660_volume_mount: success (joliet!!!)\n");
+        vol->fJoliet = 1;
+    }
+
+
+    rootdir = pvoldesc->root_directory;
+    sua_pos = (sizeof(struct iso9660_dirrec)) + rootdir.file_identifier_length + (rootdir.file_identifier_length % 2) - 2;
+    //int sua_size = rootdir.dirrec_length - rootdir.file_identifier_length;
+    //FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (SUA(pos:%x, sz:%d)!!!)\n"), sua_pos, sua_size));
+
+#if 1
+    status = fsw_block_get(vol, ISOINT(rootdir.extent_location), 0, &buffer);
+    sig = (char *)buffer + sua_pos;
+    skip = 0;
+    entry = (struct fsw_rock_ridge_susp_entry *)sig;
+    if (   entry->sig[0] == 'S'
+        && entry->sig[1] == 'P')
+    {
+        struct fsw_rock_ridge_susp_sp *sp = (struct fsw_rock_ridge_susp_sp *)entry;
+        if (sp->magic[0] == 0xbe && sp->magic[1] == 0xef)
+        {
+            vol->fRockRidge = 1;
+        } else {
+ //           FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: SP magic isn't valid\n")));
+//          DBG("fsw_iso9660_volume_mount: SP magic isn't valid\n");
+        }
+        skip = sp->skip;
+    }
+#endif
+    // release volume descriptors
+    fsw_free(vol->primary_voldesc);
+    vol->primary_voldesc = NULL;
+
+
+//    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success\n")));
+//  DBG("fsw_iso9660_volume_mount: success\n");
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol)
+{
+    if (vol->primary_voldesc)
+        fsw_free(vol->primary_voldesc);
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb)
+{
+    sb->total_bytes = 0; //(fsw_u64)vol->sb->s_blocks_count      * vol->g.log_blocksize;
+    sb->free_bytes  = 0;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode. In the case of iso9660, we
+ * delay fetching of the inode structure until dnode_fill is called. The size and
+ * type fields are invalid until this function has been called.
+ */
+
+static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno)
+{
+    // get info from the directory record
+    dno->g.size = ISOINT(dno->dirrec.data_length);
+    if (dno->dirrec.file_flags & 0x02)
+        dno->g.type = FSW_DNODE_TYPE_DIR;
+    else
+        dno->g.type = FSW_DNODE_TYPE_FILE;
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno)
+{
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_iso9660_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_dnode_stat *sb)
+{
+    sb->used_bytes = (dno->g.size + (ISO9660_BLOCKSIZE-1)) & ~(ISO9660_BLOCKSIZE-1);
+    /*
+    sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime);
+    sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime);
+    sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime);
+    sb->store_attr_posix(sb, dno->raw->i_mode);
+    */
+
+    return FSW_SUCCESS;
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_extent *extent)
+{
+    // Preconditions: The caller has checked that the requested logical block
+    //  is within the file's size. The dnode has complete information, i.e.
+    //  fsw_iso9660_dnode_read_info was called successfully on it.
+
+    extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+    extent->phys_start = ISOINT(dno->dirrec.extent_location);
+    extent->log_start = 0;
+    extent->log_count = (ISOINT(dno->dirrec.data_length) + (ISO9660_BLOCKSIZE-1)) >> ISO9660_BLOCKSIZE_BITS;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                           struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_shandle shand;
+    struct iso9660_dirrec_buffer dirrec_buffer;
+    struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec;
+
+    // Preconditions: The caller has checked that dno is a directory node.
+
+    // setup handle to read the directory
+    status = fsw_shandle_open(dno, &shand);
+    if (status)
+        return status;
+
+    // scan the directory for the file
+    while (1) {
+        // read next entry
+        status = fsw_iso9660_read_dirrec(vol, &shand, &dirrec_buffer);
+        if (status)
+            goto errorexit;
+        if (dirrec->dirrec_length == 0) {
+            // end of directory reached
+            status = FSW_NOT_FOUND;
+            goto errorexit;
+        }
+
+        // skip . and ..
+        if (dirrec->file_identifier_length == 1 &&
+            (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1))
+            continue;
+
+        // compare name
+        if (fsw_streq(lookup_name, &dirrec_buffer.name))  // TODO: compare case-insensitively
+            break;
+    }
+
+    // setup a dnode for the child item
+    status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out);
+    if (status == FSW_SUCCESS)
+        fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec));
+
+errorexit:
+    fsw_shandle_close(&shand);
+    return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                         struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct iso9660_dirrec_buffer dirrec_buffer;
+    struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec;
+
+    // Preconditions: The caller has checked that dno is a directory node. The caller
+    //  has opened a storage handle to the directory's storage and keeps it around between
+    //  calls.
+    /* (vasily) directory nodes are 4096 bytes that is two logical blocks so read dir operation
+     * should read both blocks.
+     */
+
+    while (1) {
+        // read next entry
+        if (shand->pos >= dno->g.size)
+            return FSW_NOT_FOUND; // end of directory
+        status = fsw_iso9660_read_dirrec(vol, shand, &dirrec_buffer);
+        if (status)
+            return status;
+        if (dirrec->dirrec_length == 0)
+        {
+            // try the next block
+            shand->pos =(shand->pos & ~(vol->g.log_blocksize - 1)) + vol->g.log_blocksize;
+            continue;
+        }
+
+        // skip . and ..
+        if (dirrec->file_identifier_length == 1 &&
+            (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1))
+            continue;
+        break;
+    }
+
+    // setup a dnode for the child item
+    status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out);
+    if (status == FSW_SUCCESS)
+        fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec));
+
+    return status;
+}
+
+/**
+ * Read a directory entry from the directory's raw data. This internal function is used
+ * to read a raw iso9660 directory entry into memory. The shandle's position pointer is adjusted
+ * to point to the next entry.
+ */
+
+static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer)
+{
+    fsw_status_t    status;
+    fsw_u32         i, buffer_size, remaining_size, name_len;
+    struct fsw_rock_ridge_susp_sp *sp = NULL;
+    struct iso9660_dirrec *dirrec = &dirrec_buffer->dirrec;
+    int sp_off;
+    int rc;
+
+    dirrec_buffer->ino = (ISOINT(((struct fsw_iso9660_dnode *)shand->dnode)->dirrec.extent_location)
+                          << ISO9660_BLOCKSIZE_BITS)
+        + (fsw_u32)shand->pos;
+
+    // read fixed size part of directory record
+    buffer_size = 33;
+    status = fsw_shandle_read(shand, &buffer_size, dirrec);
+    if (status)
+    {
+    //    DEBUG((DEBUG_INFO, "%a:%d \n", __FILE__, __LINE__));
+        return status;
+    }
+
+    if (buffer_size < 33 || dirrec->dirrec_length == 0) {
+        // end of directory reached
+        fsw_u8 *r;
+        r = (fsw_u8 *)dirrec;
+ //       DEBUG((DEBUG_INFO, "%a:%d bs:%d dl:%d\n", __FILE__, __LINE__, buffer_size, dirrec->dirrec_length));
+        for(i = 0; i < buffer_size; ++i)
+        {
+            DEBUG((DEBUG_INFO, "r[%d]:%c", i, r[i]));
+        }
+        dirrec->dirrec_length = 0;
+        return FSW_SUCCESS;
+    }
+    if (dirrec->dirrec_length < 33 ||
+        dirrec->dirrec_length < 33 + dirrec->file_identifier_length)
+        return FSW_VOLUME_CORRUPTED;
+
+//    DEBUG((DEBUG_INFO, "%a:%d, dirrec_length: %d\n", __FILE__, __LINE__, dirrec->dirrec_length));
+
+    // read variable size part of directory record
+    buffer_size = remaining_size = dirrec->dirrec_length - 33;
+    status = fsw_shandle_read(shand, &buffer_size, dirrec->file_identifier);
+    if (status)
+        return status;
+    if (buffer_size < remaining_size)
+        return FSW_VOLUME_CORRUPTED;
+
+//     dump_dirrec(dirrec);
+     if (vol->fRockRidge)
+     {
+         sp_off = sizeof(*dirrec) + dirrec->file_identifier_length;
+         rc = rr_find_sp(dirrec, &sp);
+         if (   rc == FSW_SUCCESS
+             && sp != NULL)
+         {
+            sp_off = (fsw_u8 *)&sp[1] - (fsw_u8*)dirrec + sp->skip;
+         }
+         rc = rr_find_nm(vol, dirrec, sp_off,  &dirrec_buffer->name);
+         if (rc == FSW_SUCCESS)
+            return FSW_SUCCESS;
+    }
+
+    // setup name
+    name_len = dirrec->file_identifier_length;
+    for (i = name_len - 1; i > 0; i--) {
+        if (dirrec->file_identifier[i] == ';') {
+            name_len = i;   // cut the ISO9660 version number off
+            break;
+        }
+    }
+    if (name_len > 0 && dirrec->file_identifier[name_len-1] == '.')
+        name_len--;   // also cut the extension separator if the extension is empty
+    dirrec_buffer->name.type = FSW_STRING_TYPE_ISO88591;
+    dirrec_buffer->name.len = dirrec_buffer->name.size = name_len;
+    dirrec_buffer->name.data = dirrec->file_identifier;
+//    DEBUG((DEBUG_INFO, "%a:%d: dirrec_buffer->name.data:%a\n", __FILE__, __LINE__, dirrec_buffer->name.data));
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_iso9660_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ * For iso9660, the target path can be stored inline in the inode structure (in the space
+ * otherwise occupied by the block pointers) or in the inode's data. There is no flag
+ * indicating this, only the number of blocks entry (i_blocks) can be used as an
+ * indication. The check used here comes from the Linux kernel.
+ */
+
+static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+                                         struct fsw_string *link_target)
+{
+    fsw_status_t    status;
+
+    if (dno->g.size > FSW_PATH_MAX)
+        return FSW_VOLUME_CORRUPTED;
+
+    status = fsw_dnode_readlink_data(dno, link_target);
+
+    return status;
+}
+
+// EOF
diff --git a/filesystems/fsw_iso9660.h b/filesystems/fsw_iso9660.h
new file mode 100644 (file)
index 0000000..c1dd94b
--- /dev/null
@@ -0,0 +1,206 @@
+/* $Id: fsw_iso9660.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_iso9660.h - ISO9660 file system driver header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_ISO9660_H_
+#define _FSW_ISO9660_H_
+
+#define VOLSTRUCTNAME fsw_iso9660_volume
+#define DNODESTRUCTNAME fsw_iso9660_dnode
+#include "fsw_core.h"
+
+
+//! Block size for ISO9660 volumes.
+#define ISO9660_BLOCKSIZE          2048
+#define ISO9660_BLOCKSIZE_BITS       11
+//! Block number where the ISO9660 superblock resides.
+#define ISO9660_SUPERBLOCK_BLOCKNO   16
+//Slice - we already have shifted blockIO by 16
+//but we should use ParentBlockIo
+//#define ISO9660_SUPERBLOCK_BLOCKNO   0
+
+#pragma pack(1)
+
+typedef struct {
+    fsw_u16     lsb;
+    fsw_u16     msb;
+} iso9660_u16;
+
+typedef struct {
+    fsw_u32     lsb;
+    fsw_u32     msb;
+} iso9660_u32;
+
+#define ISOINT(lsbmsbvalue) ((lsbmsbvalue).lsb)
+
+struct iso9660_dirrec {
+    fsw_u8      dirrec_length;
+    fsw_u8      ear_length;
+    iso9660_u32 extent_location;
+    iso9660_u32 data_length;
+    fsw_u8      recording_datetime[7];
+    fsw_u8      file_flags;
+    fsw_u8      file_unit_size;
+    fsw_u8      interleave_gap_size;
+    iso9660_u16 volume_sequence_number;
+    fsw_u8      file_identifier_length;
+    char        file_identifier[1];
+};
+//#if sizeof(struct fsw_iso9660_dirrec) != 34
+//#fail Structure fsw_iso9660_dirrec has wrong size
+//#endif
+
+struct iso9660_volume_descriptor {
+    fsw_u8      volume_descriptor_type;
+    char        standard_identifier[5];
+    fsw_u8      volume_descriptor_version;
+};
+
+struct iso9660_primary_volume_descriptor {
+    fsw_u8      volume_descriptor_type;
+    char        standard_identifier[5];
+    fsw_u8      volume_descriptor_version;
+    fsw_u8      unused1;
+    char        system_identifier[32];
+    char        volume_identifier[32];
+    fsw_u8      unused2[8];
+    iso9660_u32 volume_space_size;
+    fsw_u8      unused3[4];
+    fsw_u8      escape[3];
+    fsw_u8      unused4[25];
+    iso9660_u16 volume_set_size;
+    iso9660_u16 volume_sequence_number;
+    iso9660_u16 logical_block_size;
+    iso9660_u32 path_table_size;
+    fsw_u32     location_type_l_path_table;
+    fsw_u32     location_optional_type_l_path_table;
+    fsw_u32     location_type_m_path_table;
+    fsw_u32     location_optional_type_m_path_table;
+    struct iso9660_dirrec root_directory;
+    char        volume_set_identifier[128];
+    char        publisher_identifier[128];
+    char        data_preparer_identifier[128];
+    char        application_identifier[128];
+    char        copyright_file_identifier[37];
+    char        abstract_file_identifier[37];
+    char        bibliographic_file_identifier[37];
+    char        volume_creation_datetime[17];
+    char        volume_modification_datetime[17];
+    char        volume_expiration_datetime[17];
+    char        volume_effective_datetime[17];
+    fsw_u8      file_structure_version;
+    fsw_u8      reserved1;
+    fsw_u8      application_use[512];
+    fsw_u8      reserved2[653];
+};
+//#if sizeof(struct fsw_iso9660_volume_descriptor) != 2048
+//#fail Structure fsw_iso9660_volume_descriptor has wrong size
+//#endif
+
+#pragma pack()
+
+struct iso9660_dirrec_buffer {
+    fsw_u32     ino;
+    struct fsw_string name;
+    struct iso9660_dirrec dirrec;
+    char        dirrec_buffer[222];
+};
+
+
+/**
+ * ISO9660: Volume structure with ISO9660-specific data.
+ */
+
+struct fsw_iso9660_volume {
+    struct fsw_volume g;            //!< Generic volume structure
+    /*Note: don't move g!*/
+    int fJoliet;
+    /*Joliet specific fields*/
+    int fRockRidge;
+    /*Rock Ridge specific fields*/
+    int rr_susp_skip;
+
+    struct iso9660_primary_volume_descriptor *primary_voldesc;  //!< Full Primary Volume Descriptor
+};
+
+/**
+ * ISO9660: Dnode structure with ISO9660-specific data.
+ */
+
+struct fsw_iso9660_dnode {
+    struct fsw_dnode g;             //!< Generic dnode structure
+
+    struct iso9660_dirrec dirrec;   //!< Fixed part of the directory record (i.e. w/o name)
+};
+
+
+struct fsw_rock_ridge_susp_entry
+{
+    fsw_u8  sig[2];
+    fsw_u8  len;
+    fsw_u8  ver;
+};
+
+struct fsw_rock_ridge_susp_sp
+{
+    struct fsw_rock_ridge_susp_entry e;
+    fsw_u8  magic[2];
+    fsw_u8  skip;
+};
+
+struct fsw_rock_ridge_susp_nm
+{
+    struct fsw_rock_ridge_susp_entry e;
+    fsw_u8  flags;
+    fsw_u8  name[1];
+};
+
+#define RR_NM_CONT (1<<0)
+#define RR_NM_CURR (1<<1)
+#define RR_NM_PARE (1<<2)
+
+union fsw_rock_ridge_susp_ce
+{
+    struct X{
+        struct fsw_rock_ridge_susp_entry e;
+        iso9660_u32 block_loc;
+        iso9660_u32 offset;
+        iso9660_u32 len;
+    } X;
+    fsw_u8 raw[28];
+};
+
+#endif
diff --git a/filesystems/fsw_lib.c b/filesystems/fsw_lib.c
new file mode 100644 (file)
index 0000000..ade2b6b
--- /dev/null
@@ -0,0 +1,547 @@
+/* $Id: fsw_lib.c 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * fsw_lib.c - Core file system wrapper library functions.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_core.h"
+
+/* Include generated string encoding specific functions */
+#include "fsw_strfunc.h"
+
+
+/**
+ * Allocate memory and clear it.
+ */
+
+fsw_status_t fsw_alloc_zero(int len, void **ptr_out)
+{
+    fsw_status_t status;
+
+    status = fsw_alloc(len, ptr_out);
+    if (status)
+        return status;
+    fsw_memzero(*ptr_out, len);
+    return FSW_SUCCESS;
+}
+
+/**
+ * Duplicate a piece of data.
+ */
+
+fsw_status_t fsw_memdup(void **dest_out, void *src, int len)
+{
+    fsw_status_t status;
+
+    status = fsw_alloc(len, dest_out);
+    if (status)
+        return status;
+    fsw_memcpy(*dest_out, src, len);
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get the length of a string. Returns the number of characters in the string.
+ */
+
+int fsw_strlen(struct fsw_string *s)
+{
+    if (s->type == FSW_STRING_TYPE_EMPTY)
+        return 0;
+    return s->len;
+}
+
+#if 0
+static const fsw_u16
+fsw_lower_case_table[] =
+{
+
+    /* High-byte indices ( == 0 iff no case mapping and no ignorables ) */
+
+    /* 0 */    0x0000, 0x0100, 0x0000, 0x0200, 0x0300, 0x0400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 1 */    0x0500, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 2 */    0x0600, 0x0700, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 3 */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 4 */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 5 */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 6 */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 7 */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 8 */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 9 */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* A */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* B */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* C */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* D */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* E */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* F */    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0800, 0x0900,
+
+    /* Table 1 (for high byte 0x01) */
+
+    /* 0 */    0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F,
+    /* 1 */    0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117, 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F,
+    /* 2 */    0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F,
+    /* 3 */    0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140,
+    /* 4 */    0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147, 0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F,
+    /* 5 */    0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157, 0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F,
+    /* 6 */    0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167, 0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F,
+    /* 7 */    0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, 0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F,
+    /* 8 */    0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, 0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
+    /* 9 */    0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, 0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
+    /* A */    0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8, 0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF,
+    /* B */    0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292, 0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
+    /* C */    0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9, 0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF,
+    /* D */    0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7, 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF,
+    /* E */    0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7, 0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF,
+    /* F */    0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF,
+
+    /* Table 2 (for high byte 0x03) */
+
+    /* 0 */    0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F,
+    /* 1 */    0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, 0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F,
+    /* 2 */    0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, 0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F,
+    /* 3 */    0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F,
+    /* 4 */    0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F,
+    /* 5 */    0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F,
+    /* 6 */    0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F,
+    /* 7 */    0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F,
+    /* 8 */    0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F,
+    /* 9 */    0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+    /* A */    0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+    /* B */    0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+    /* C */    0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF,
+    /* D */    0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7, 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,
+    /* E */    0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7, 0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
+    /* F */    0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7, 0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,
+
+    /* Table 3 (for high byte 0x04) */
+
+    /* 0 */    0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407, 0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F,
+    /* 1 */    0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+    /* 2 */    0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+    /* 3 */    0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+    /* 4 */    0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+    /* 5 */    0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F,
+    /* 6 */    0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, 0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F,
+    /* 7 */    0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477, 0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F,
+    /* 8 */    0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,
+    /* 9 */    0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, 0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F,
+    /* A */    0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7, 0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF,
+    /* B */    0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7, 0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF,
+    /* C */    0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8, 0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF,
+    /* D */    0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7, 0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF,
+    /* E */    0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7, 0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF,
+    /* F */    0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7, 0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF,
+
+    /* Table 4 (for high byte 0x05) */
+
+    /* 0 */    0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F,
+    /* 1 */    0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, 0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F,
+    /* 2 */    0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, 0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F,
+    /* 3 */    0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+    /* 4 */    0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+    /* 5 */    0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, 0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F,
+    /* 6 */    0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+    /* 7 */    0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+    /* 8 */    0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, 0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F,
+    /* 9 */    0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, 0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F,
+    /* A */    0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7, 0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF,
+    /* B */    0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, 0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+    /* C */    0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7, 0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF,
+    /* D */    0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+    /* E */    0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF,
+    /* F */    0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7, 0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF,
+
+    /* Table 5 (for high byte 0x10) */
+
+    /* 0 */    0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
+    /* 1 */    0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017, 0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F,
+    /* 2 */    0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027, 0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F,
+    /* 3 */    0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037, 0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F,
+    /* 4 */    0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, 0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F,
+    /* 5 */    0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, 0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F,
+    /* 6 */    0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067, 0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F,
+    /* 7 */    0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077, 0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F,
+    /* 8 */    0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, 0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F,
+    /* 9 */    0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, 0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F,
+    /* A */    0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+    /* B */    0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+    /* C */    0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7, 0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF,
+    /* D */    0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+    /* E */    0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+    /* F */    0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7, 0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF,
+
+    /* Table 6 (for high byte 0x20) */
+
+    /* 0 */    0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 1 */    0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F,
+    /* 2 */    0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, 0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F,
+    /* 3 */    0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F,
+    /* 4 */    0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047, 0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F,
+    /* 5 */    0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F,
+    /* 6 */    0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067, 0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 7 */    0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F,
+    /* 8 */    0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F,
+    /* 9 */    0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097, 0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F,
+    /* A */    0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7, 0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF,
+    /* B */    0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7, 0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF,
+    /* C */    0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, 0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF,
+    /* D */    0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, 0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF,
+    /* E */    0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7, 0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF,
+    /* F */    0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7, 0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF,
+
+    /* Table 7 (for high byte 0x21) */
+
+    /* 0 */    0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, 0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F,
+    /* 1 */    0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, 0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F,
+    /* 2 */    0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F,
+    /* 3 */    0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F,
+    /* 4 */    0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F,
+    /* 5 */    0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,
+    /* 6 */    0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+    /* 7 */    0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+    /* 8 */    0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, 0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F,
+    /* 9 */    0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F,
+    /* A */    0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7, 0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF,
+    /* B */    0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7, 0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF,
+    /* C */    0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7, 0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF,
+    /* D */    0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7, 0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF,
+    /* E */    0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7, 0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF,
+    /* F */    0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7, 0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF,
+
+    /* Table 8 (for high byte 0xFE) */
+
+    /* 0 */    0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07, 0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F,
+    /* 1 */    0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17, 0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F,
+    /* 2 */    0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27, 0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F,
+    /* 3 */    0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37, 0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F,
+    /* 4 */    0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47, 0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F,
+    /* 5 */    0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57, 0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F,
+    /* 6 */    0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67, 0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F,
+    /* 7 */    0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77, 0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F,
+    /* 8 */    0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87, 0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F,
+    /* 9 */    0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97, 0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F,
+    /* A */    0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF,
+    /* B */    0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF,
+    /* C */    0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF,
+    /* D */    0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7, 0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF,
+    /* E */    0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF,
+    /* F */    0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7, 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000,
+
+    /* Table 9 (for high byte 0xFF) */
+
+    /* 0 */    0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F,
+    /* 1 */    0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F,
+    /* 2 */    0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+    /* 3 */    0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F,
+    /* 4 */    0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+    /* 5 */    0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F,
+    /* 6 */    0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
+    /* 7 */    0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77, 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
+    /* 8 */    0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
+    /* 9 */    0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
+    /* A */    0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7, 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF,
+    /* B */    0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7, 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF,
+    /* C */    0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF,
+    /* D */    0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7, 0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF,
+    /* E */    0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7, 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF,
+    /* F */    0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
+};
+#endif
+
+static const fsw_u16 fsw_latin_case_fold[] =
+{
+    /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+    /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+    /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+    /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+    /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+    /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+    /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+    /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+    /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+    /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+    /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+    /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+    /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF,
+    /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+    /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+};
+
+
+fsw_u16 fsw_to_lower(fsw_u16 ch)
+{
+#if 0
+    fsw_u16 temp = temp;
+#endif
+
+    if (ch < 0x0100)
+        return fsw_latin_case_fold[ch];
+#if 0
+    /*
+     * Uncomment this along with above huge table (fsw_lower_case_table)
+     * for full UTF-16 case insensitivity
+     */
+    temp = fsw_lower_case_table[ch>>8];
+    if (temp != 0)
+        return fsw_lower_case_table[temp + (ch & 0x00FF)];
+#endif
+
+    return ch;
+}
+
+/**
+ * Compare two strings for equality. The two strings are compared, taking their
+ * encoding into account. If they are considered equal, boolean true is returned.
+ * Otherwise, boolean false is returned.
+ */
+
+int fsw_streq(struct fsw_string *s1, struct fsw_string *s2)
+{
+    struct fsw_string temp_s;
+
+    // handle empty strings
+    if (s1->type == FSW_STRING_TYPE_EMPTY) {
+        temp_s.type = FSW_STRING_TYPE_ISO88591;
+        temp_s.size = temp_s.len = 0;
+        temp_s.data = NULL;
+        return fsw_streq(&temp_s, s2);
+    }
+    if (s2->type == FSW_STRING_TYPE_EMPTY) {
+        temp_s.type = FSW_STRING_TYPE_ISO88591;
+        temp_s.size = temp_s.len = 0;
+        temp_s.data = NULL;
+        return fsw_streq(s1, &temp_s);
+    }
+
+    // check length (count of chars)
+    if (s1->len != s2->len)
+        return 0;
+    if (s1->len == 0)   // both strings are empty
+        return 1;
+
+    if (s1->type == s2->type) {
+        // same type, do a dumb memory compare
+        if (s1->size != s2->size)
+            return 0;
+        return fsw_memeq(s1->data, s2->data, s1->size);
+    }
+
+    // dispatch to type-specific functions
+    #define STREQ_DISPATCH(type1, type2) \
+      if (s1->type == FSW_STRING_TYPE_##type1 && s2->type == FSW_STRING_TYPE_##type2) \
+        return fsw_streq_##type1##_##type2(s1->data, s2->data, s1->len); \
+      if (s2->type == FSW_STRING_TYPE_##type1 && s1->type == FSW_STRING_TYPE_##type2) \
+        return fsw_streq_##type1##_##type2(s2->data, s1->data, s1->len);
+    STREQ_DISPATCH(ISO88591, UTF8);
+    STREQ_DISPATCH(ISO88591, UTF16);
+    STREQ_DISPATCH(ISO88591, UTF16_SWAPPED);
+    STREQ_DISPATCH(UTF8, UTF16);
+    STREQ_DISPATCH(UTF8, UTF16_SWAPPED);
+    STREQ_DISPATCH(UTF16, UTF16_SWAPPED);
+
+    // final fallback
+    return 0;
+}
+
+/**
+ * Compare a string with a C string constant. This sets up a string descriptor
+ * for the string constant (second argument) and runs fsw_streq on the two
+ * strings. Currently the C string is interpreted as ISO 8859-1.
+ * Returns boolean true if the strings are considered equal, boolean false otherwise.
+ */
+
+int fsw_streq_cstr(struct fsw_string *s1, const char *s2)
+{
+    struct fsw_string temp_s;
+    int i;
+
+    for (i = 0; s2[i]; i++)
+        ;
+
+    temp_s.type = FSW_STRING_TYPE_ISO88591;
+    temp_s.size = temp_s.len = i;
+    temp_s.data = (char *)s2;
+
+    return fsw_streq(s1, &temp_s);
+}
+
+/**
+ * Creates a duplicate of a string, converting it to the given encoding during the copy.
+ * If the function returns FSW_SUCCESS, the caller must free the string later with
+ * fsw_strfree.
+ */
+
+fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src)
+{
+    fsw_status_t    status;
+
+    if (src->type == FSW_STRING_TYPE_EMPTY || src->len == 0) {
+        dest->type = type;
+        dest->size = dest->len = 0;
+        dest->data = NULL;
+        return FSW_SUCCESS;
+    }
+
+    if (src->type == type) {
+        dest->type = type;
+        dest->len  = src->len;
+        dest->size = src->size;
+        status = fsw_alloc(dest->size, &dest->data);
+        if (status)
+            return status;
+
+        fsw_memcpy(dest->data, src->data, dest->size);
+        return FSW_SUCCESS;
+    }
+
+    // dispatch to type-specific functions
+    #define STRCOERCE_DISPATCH(type1, type2) \
+      if (src->type == FSW_STRING_TYPE_##type1 && type == FSW_STRING_TYPE_##type2) \
+        return fsw_strcoerce_##type1##_##type2(src->data, src->len, dest);
+    STRCOERCE_DISPATCH(UTF8, ISO88591);
+    STRCOERCE_DISPATCH(UTF16, ISO88591);
+    STRCOERCE_DISPATCH(UTF16_SWAPPED, ISO88591);
+    STRCOERCE_DISPATCH(ISO88591, UTF8);
+    STRCOERCE_DISPATCH(UTF16, UTF8);
+    STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF8);
+    STRCOERCE_DISPATCH(ISO88591, UTF16);
+    STRCOERCE_DISPATCH(UTF8, UTF16);
+    STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF16);
+
+    return FSW_UNSUPPORTED;
+}
+
+/**
+ * Splits a string at the first occurrence of the separator character.
+ * The buffer string is searched for the separator character. If it is found, the
+ * element string descriptor is filled to point at the part of the buffer string
+ * before the separator. The buffer string itself is adjusted to point at the
+ * remaining part of the string (without the separator).
+ *
+ * If the separator is not found in the buffer string, then element is changed to
+ * point at the whole buffer string, and the buffer string itself is changed into
+ * an empty string.
+ *
+ * This function only manipulates the pointers and lengths in the two string descriptors,
+ * it does not change the actual string. If the buffer string is dynamically allocated,
+ * you must make a copy of it so that you can release it later.
+ */
+
+void fsw_strsplit(struct fsw_string *element, struct fsw_string *buffer, char separator)
+{
+    int i, maxlen;
+
+    if (buffer->type == FSW_STRING_TYPE_EMPTY || buffer->len == 0) {
+        element->type = FSW_STRING_TYPE_EMPTY;
+        return;
+    }
+
+    maxlen = buffer->len;
+    *element = *buffer;
+
+    if (buffer->type == FSW_STRING_TYPE_ISO88591) {
+        fsw_u8 *p;
+
+        p = (fsw_u8 *)element->data;
+        for (i = 0; i < maxlen; i++, p++) {
+            if (*p == separator) {
+                buffer->data = p + 1;
+                buffer->len -= i + 1;
+                break;
+            }
+        }
+        element->len = i;
+        if (i == maxlen) {
+            buffer->data = p;
+            buffer->len -= i;
+        }
+
+        element->size = element->len;
+        buffer->size  = buffer->len;
+
+    } else if (buffer->type == FSW_STRING_TYPE_UTF16) {
+        fsw_u16 *p;
+
+        p = (fsw_u16 *)element->data;
+        for (i = 0; i < maxlen; i++, p++) {
+            if (*p == separator) {
+                buffer->data = p + 1;
+                buffer->len -= i + 1;
+                break;
+            }
+        }
+        element->len = i;
+        if (i == maxlen) {
+            buffer->data = p;
+            buffer->len -= i;
+        }
+
+        element->size = element->len * sizeof(fsw_u16);
+        buffer->size  = buffer->len  * sizeof(fsw_u16);
+
+    } else {
+        // fallback
+        buffer->type = FSW_STRING_TYPE_EMPTY;
+    }
+
+    // TODO: support UTF8 and UTF16_SWAPPED
+}
+
+/**
+ * Frees the memory used by a string returned from fsw_strdup_coerce.
+ */
+
+void fsw_strfree(struct fsw_string *s)
+{
+    if (s->type != FSW_STRING_TYPE_EMPTY && s->data)
+        fsw_free(s->data);
+    s->type = FSW_STRING_TYPE_EMPTY;
+}
+
+// EOF
diff --git a/filesystems/fsw_reiserfs.c b/filesystems/fsw_reiserfs.c
new file mode 100644 (file)
index 0000000..7c403f6
--- /dev/null
@@ -0,0 +1,874 @@
+/**
+ * \file fsw_reiserfs.c
+ * ReiserFS file system driver code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will 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 to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "fsw_reiserfs.h"
+
+
+// functions
+
+static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol);
+static void         fsw_reiserfs_volume_free(struct fsw_reiserfs_volume *vol);
+static fsw_status_t fsw_reiserfs_volume_stat(struct fsw_reiserfs_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno);
+static void         fsw_reiserfs_dnode_free(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno);
+static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                        struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                        struct fsw_extent *extent);
+
+static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                        struct fsw_string *lookup_name, struct fsw_reiserfs_dnode **child_dno);
+static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                      struct fsw_shandle *shand, struct fsw_reiserfs_dnode **child_dno);
+
+static fsw_status_t fsw_reiserfs_readlink(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                      struct fsw_string *link);
+
+static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol,
+                                             fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset,
+                                             struct fsw_reiserfs_item *item);
+static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol,
+                                           struct fsw_reiserfs_item *item);
+static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol,
+                                      struct fsw_reiserfs_item *item);
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(reiserfs) = {
+    { FSW_STRING_TYPE_ISO88591, 8, 8, "reiserfs" },
+    sizeof(struct fsw_reiserfs_volume),
+    sizeof(struct fsw_reiserfs_dnode),
+    
+    fsw_reiserfs_volume_mount,
+    fsw_reiserfs_volume_free,
+    fsw_reiserfs_volume_stat,
+    fsw_reiserfs_dnode_fill,
+    fsw_reiserfs_dnode_free,
+    fsw_reiserfs_dnode_stat,
+    fsw_reiserfs_get_extent,
+    fsw_reiserfs_dir_lookup,
+    fsw_reiserfs_dir_read,
+    fsw_reiserfs_readlink,
+};
+
+// misc data
+
+static fsw_u32  superblock_offsets[3] = {
+    REISERFS_DISK_OFFSET_IN_BYTES     >> REISERFS_SUPERBLOCK_BLOCKSIZEBITS,
+    REISERFS_OLD_DISK_OFFSET_IN_BYTES >> REISERFS_SUPERBLOCK_BLOCKSIZEBITS,
+    0
+};
+
+/**
+ * Mount an reiserfs volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol)
+{
+    fsw_status_t    status;
+    void            *buffer;
+    fsw_u32         blocksize;
+    int             i;
+    struct fsw_string s;
+    
+    // allocate memory to keep the superblock around
+    status = fsw_alloc(sizeof(struct reiserfs_super_block), &vol->sb);
+    if (status)
+        return status;
+    
+    // read the superblock into its buffer
+    fsw_set_blocksize(vol, REISERFS_SUPERBLOCK_BLOCKSIZE, REISERFS_SUPERBLOCK_BLOCKSIZE);
+    for (i = 0; superblock_offsets[i]; i++) {
+        status = fsw_block_get(vol, superblock_offsets[i], 0, &buffer);
+        if (status)
+            return status;
+        fsw_memcpy(vol->sb, buffer, sizeof(struct reiserfs_super_block));
+        fsw_block_release(vol, superblock_offsets[i], buffer);
+        
+        // check for one of the magic strings
+        if (fsw_memeq(vol->sb->s_v1.s_magic,
+                      REISERFS_SUPER_MAGIC_STRING, 8)) {
+            vol->version = REISERFS_VERSION_1;
+            break;
+        } else if (fsw_memeq(vol->sb->s_v1.s_magic,
+                             REISER2FS_SUPER_MAGIC_STRING, 9)) {
+            vol->version = REISERFS_VERSION_2;
+            break;
+        } else if (fsw_memeq(vol->sb->s_v1.s_magic,
+                             REISER2FS_JR_SUPER_MAGIC_STRING, 9)) {
+            vol->version = vol->sb->s_v1.s_version;
+            if (vol->version == REISERFS_VERSION_1 || vol->version == REISERFS_VERSION_2)
+                break;
+        }
+    }
+    if (superblock_offsets[i] == 0)
+        return FSW_UNSUPPORTED;
+    
+    // check the superblock
+    if (vol->sb->s_v1.s_root_block == -1)   // unfinished 'reiserfsck --rebuild-tree'
+        return FSW_VOLUME_CORRUPTED;
+    
+    /*
+    if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV &&
+        vol->sb->s_rev_level != EXT2_DYNAMIC_REV)
+        return FSW_UNSUPPORTED;
+    if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV &&
+        (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER)))
+        return FSW_UNSUPPORTED;
+    */
+    
+    // set real blocksize
+    blocksize = vol->sb->s_v1.s_blocksize;
+    fsw_set_blocksize(vol, blocksize, blocksize);
+    
+    // get other info from superblock
+    /*
+    vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb);
+    vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt;
+    vol->inode_size = EXT2_INODE_SIZE(vol->sb);
+    */
+    
+    for (i = 0; i < 16; i++)
+        if (vol->sb->s_label[i] == 0)
+            break;
+    s.type = FSW_STRING_TYPE_ISO88591;
+    s.size = s.len = i;
+    s.data = vol->sb->s_label;
+    status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+    if (status)
+        return status;
+    
+    // setup the root dnode
+    status = fsw_dnode_create_root(vol, REISERFS_ROOT_OBJECTID, &vol->g.root);
+    if (status)
+        return status;
+    vol->g.root->dir_id = REISERFS_ROOT_PARENT_OBJECTID;
+    
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_volume_mount: success, blocksize %d tree height %d\n"),
+                   blocksize, vol->sb->s_v1.s_tree_height));
+    
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_reiserfs_volume_free(struct fsw_reiserfs_volume *vol)
+{
+    if (vol->sb)
+        fsw_free(vol->sb);
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_reiserfs_volume_stat(struct fsw_reiserfs_volume *vol, struct fsw_volume_stat *sb)
+{
+    sb->total_bytes = (fsw_u64)vol->sb->s_v1.s_block_count * vol->g.log_blocksize;
+    sb->free_bytes  = (fsw_u64)vol->sb->s_v1.s_free_blocks * vol->g.log_blocksize;
+    return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode. In the case of reiserfs, we
+ * delay fetching of the stat data until dnode_fill is called. The size and
+ * type fields are invalid until this function has been called.
+ */
+
+static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno)
+{
+    fsw_status_t    status;
+    fsw_u32         item_len, mode;
+    struct fsw_reiserfs_item item;
+    
+    if (dno->sd_v1 || dno->sd_v2)
+        return FSW_SUCCESS;
+    
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_dnode_fill: object %d/%d\n"), dno->dir_id, dno->g.dnode_id));
+    
+    // find stat data item in reiserfs tree
+    status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, 0, &item);
+    if (status == FSW_NOT_FOUND) {
+        FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: cannot find stat_data for object %d/%d\n"),
+                        dno->dir_id, dno->g.dnode_id));
+        return FSW_VOLUME_CORRUPTED;
+    }
+    if (status)
+        return status;
+    if (item.item_offset != 0) {
+        FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: got item that's not stat_data\n")));
+        fsw_reiserfs_item_release(vol, &item);
+        return FSW_VOLUME_CORRUPTED;
+    }
+    item_len = item.ih.ih_item_len;
+    
+    // get data in appropriate version
+    if (item.ih.ih_version == KEY_FORMAT_3_5 && item_len == SD_V1_SIZE) {
+        // have stat_data_v1 structure
+        status = fsw_memdup((void **)&dno->sd_v1, item.item_data, item_len);
+        fsw_reiserfs_item_release(vol, &item);
+        if (status)
+            return status;
+        
+        // get info from the inode
+        dno->g.size = dno->sd_v1->sd_size;
+        mode = dno->sd_v1->sd_mode;
+        
+    } else if (item.ih.ih_version == KEY_FORMAT_3_6 && item_len == SD_V2_SIZE) {
+        // have stat_data_v2 structure
+        status = fsw_memdup((void **)&dno->sd_v2, item.item_data, item_len);
+        fsw_reiserfs_item_release(vol, &item);
+        if (status)
+            return status;
+        
+        // get info from the inode
+        dno->g.size = dno->sd_v2->sd_size;
+        mode = dno->sd_v2->sd_mode;
+        
+    } else {
+        FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: version %d(%d) and size %d(%d) not recognized for stat_data\n"),
+                        item.ih.ih_version, KEY_FORMAT_3_6, item_len, SD_V2_SIZE));
+        fsw_reiserfs_item_release(vol, &item);
+        return FSW_VOLUME_CORRUPTED;
+    }
+    
+    // get node type from mode field
+    if (S_ISREG(mode))
+        dno->g.type = FSW_DNODE_TYPE_FILE;
+    else if (S_ISDIR(mode))
+        dno->g.type = FSW_DNODE_TYPE_DIR;
+    else if (S_ISLNK(mode))
+        dno->g.type = FSW_DNODE_TYPE_SYMLINK;
+    else
+        dno->g.type = FSW_DNODE_TYPE_SPECIAL;
+    
+    return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_reiserfs_dnode_free(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno)
+{
+    if (dno->sd_v1)
+        fsw_free(dno->sd_v1);
+    if (dno->sd_v2)
+        fsw_free(dno->sd_v2);
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_reiserfs_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                            struct fsw_dnode_stat *sb)
+{
+    if (dno->sd_v1) {
+        if (dno->g.type == FSW_DNODE_TYPE_SPECIAL)
+            sb->used_bytes = 0;
+        else
+            sb->used_bytes = dno->sd_v1->u.sd_blocks * vol->g.log_blocksize;
+        sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v1->sd_ctime);
+        sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v1->sd_atime);
+        sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v1->sd_mtime);
+        sb->store_attr_posix(sb, dno->sd_v1->sd_mode);
+    } else if (dno->sd_v2) {
+        sb->used_bytes = dno->sd_v2->sd_blocks * vol->g.log_blocksize;
+        sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v2->sd_ctime);
+        sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v2->sd_atime);
+        sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v2->sd_mtime);
+        sb->store_attr_posix(sb, dno->sd_v2->sd_mode);
+    }
+    
+    return FSW_SUCCESS;
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_reiserfs_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                            struct fsw_extent *extent)
+{
+    fsw_status_t    status;
+    fsw_u64         search_offset, intra_offset;
+    struct fsw_reiserfs_item item;
+    fsw_u32         intra_bno, nr_item;
+    
+    // Preconditions: The caller has checked that the requested logical block
+    //  is within the file's size. The dnode has complete information, i.e.
+    //  fsw_reiserfs_dnode_read_info was called successfully on it.
+    
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_get_extent: mapping block %d of object %d/%d\n"),
+                   extent->log_start, dno->dir_id, dno->g.dnode_id));
+    
+    extent->type = FSW_EXTENT_TYPE_SPARSE;
+    extent->log_count = 1;
+    
+    // get the item for the requested block
+    search_offset = (fsw_u64)extent->log_start * vol->g.log_blocksize + 1;
+    status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, search_offset, &item);
+    if (status)
+        return status;
+    if (item.item_offset == 0) {
+        fsw_reiserfs_item_release(vol, &item);
+        return FSW_SUCCESS;       // no data items found, assume all-sparse file
+    }
+    intra_offset = search_offset - item.item_offset;
+    
+    // check the kind of block
+    if (item.item_type == TYPE_INDIRECT || item.item_type == V1_INDIRECT_UNIQUENESS) {
+        // indirect item, contains block numbers
+        
+        if (intra_offset & (vol->g.log_blocksize - 1)) {
+            FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not block-aligned for indirect block\n")));
+            goto bail;
+        }
+        intra_bno = (fsw_u32)FSW_U64_DIV(intra_offset, vol->g.log_blocksize);
+        nr_item = item.ih.ih_item_len / sizeof(fsw_u32);
+        if (intra_bno >= nr_item) {
+            FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: indirect block too small\n")));
+            goto bail;
+        }
+        extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+        extent->phys_start = ((fsw_u32 *)item.item_data)[intra_bno];
+        
+        // TODO: check if the following blocks can be aggregated into one extent
+        
+        fsw_reiserfs_item_release(vol, &item);
+        return FSW_SUCCESS;
+        
+    } else if (item.item_type == TYPE_DIRECT || item.item_type == V1_DIRECT_UNIQUENESS) {
+        // direct item, contains file data
+        
+        // TODO: Check if direct items always start on block boundaries. If not, we may have
+        //  to do extra work here.
+        
+        if (intra_offset != 0) {
+            FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not aligned for direct block\n")));
+            goto bail;
+        }
+        
+        extent->type = FSW_EXTENT_TYPE_BUFFER;
+        status = fsw_memdup(&extent->buffer, item.item_data, item.ih.ih_item_len);
+        fsw_reiserfs_item_release(vol, &item);
+        if (status)
+            return status;
+        
+        return FSW_SUCCESS;
+        
+    }
+    
+bail:
+    fsw_reiserfs_item_release(vol, &item);
+    return FSW_VOLUME_CORRUPTED;
+    
+    /*    
+    // check if the following blocks can be aggregated into one extent
+    file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1));
+    while (path[i]           + extent->log_count < buf_bcnt &&    // indirect block has more block pointers
+           extent->log_start + extent->log_count < file_bcnt) {   // file has more blocks
+        if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1)
+            extent->log_count++;
+        else
+            break;
+    }
+    */
+}
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_reiserfs_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                            struct fsw_string *lookup_name, struct fsw_reiserfs_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_reiserfs_item item;
+    fsw_u32         nr_item, i, name_offset, next_name_offset, name_len;
+    fsw_u32         child_dir_id;
+    struct reiserfs_de_head *dhead;
+    struct fsw_string entry_name;
+    
+    // Preconditions: The caller has checked that dno is a directory node.
+    
+    // BIG TODOS: Use the hash function to start with the item containing the entry.
+    //  Use binary search within the item.
+    
+    entry_name.type = FSW_STRING_TYPE_ISO88591;
+    
+    // get the item for that position
+    status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, FIRST_ITEM_OFFSET, &item);
+    if (status)
+        return status;
+    if (item.item_offset == 0) {
+        fsw_reiserfs_item_release(vol, &item);
+        return FSW_NOT_FOUND;       // empty directory or something
+    }
+    
+    for(;;) {
+        
+        // search the directory item
+        dhead = (struct reiserfs_de_head *)item.item_data;
+        nr_item = item.ih.u.ih_entry_count;
+        next_name_offset = item.ih.ih_item_len;
+        for (i = 0; i < nr_item; i++, dhead++, next_name_offset = name_offset) {
+            // get the name
+            name_offset = dhead->deh_location;
+            name_len = next_name_offset - name_offset;
+            while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0)
+                name_len--;
+            
+            entry_name.len = entry_name.size = name_len;
+            entry_name.data = item.item_data + name_offset;
+            
+            // compare name
+            if (fsw_streq(lookup_name, &entry_name)) {
+                // found the entry we're looking for!
+                
+                // setup a dnode for the child item
+                status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+                child_dir_id = dhead->deh_dir_id;
+                fsw_reiserfs_item_release(vol, &item);
+                if (status)
+                    return status;
+                (*child_dno_out)->dir_id = child_dir_id;
+                
+                return FSW_SUCCESS;
+            }
+        }
+        
+        // We didn't find the next directory entry in this item. Look for the next
+        // item of the directory.
+        
+        status = fsw_reiserfs_item_next(vol, &item);
+        if (status)
+            return status;
+        
+    }
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_reiserfs_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                          struct fsw_shandle *shand, struct fsw_reiserfs_dnode **child_dno_out)
+{
+    fsw_status_t    status;
+    struct fsw_reiserfs_item item;
+    fsw_u32         nr_item, i, name_offset, next_name_offset, name_len;
+    fsw_u32         child_dir_id;
+    struct reiserfs_de_head *dhead;
+    struct fsw_string entry_name;
+    
+    // Preconditions: The caller has checked that dno is a directory node. The caller
+    //  has opened a storage handle to the directory's storage and keeps it around between
+    //  calls.
+    
+    // BIG TODOS: Use binary search within the item.
+    
+    // adjust pointer to first entry if necessary
+    if (shand->pos == 0)
+        shand->pos = FIRST_ITEM_OFFSET;
+    
+    // get the item for that position
+    status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, shand->pos, &item);
+    if (status)
+        return status;
+    if (item.item_offset == 0) {
+        fsw_reiserfs_item_release(vol, &item);
+        return FSW_NOT_FOUND;       // empty directory or something
+    }
+    
+    for(;;) {
+        
+        // search the directory item
+        dhead = (struct reiserfs_de_head *)item.item_data;
+        nr_item = item.ih.u.ih_entry_count;
+        for (i = 0; i < nr_item; i++, dhead++) {
+            if (dhead->deh_offset < shand->pos)
+                continue;  // not yet past the last entry returned
+            if (dhead->deh_offset == DOT_OFFSET || dhead->deh_offset == DOT_DOT_OFFSET)
+                continue;  // never report . or ..
+            
+            // get the name
+            name_offset = dhead->deh_location;
+            if (i == 0)
+                next_name_offset = item.ih.ih_item_len;
+            else
+                next_name_offset = dhead[-1].deh_location;
+            name_len = next_name_offset - name_offset;
+            while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0)
+                name_len--;
+            
+            entry_name.type = FSW_STRING_TYPE_ISO88591;
+            entry_name.len = entry_name.size = name_len;
+            entry_name.data = item.item_data + name_offset;
+            
+            if (fsw_streq_cstr(&entry_name, ".reiserfs_priv"))
+                continue;  // never report this special file
+            
+            // found the next entry!
+            shand->pos = dhead->deh_offset + 1;
+            
+            // setup a dnode for the child item
+            status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+            child_dir_id = dhead->deh_dir_id;
+            fsw_reiserfs_item_release(vol, &item);
+            if (status)
+                return status;
+            (*child_dno_out)->dir_id = child_dir_id;
+            
+            return FSW_SUCCESS;
+        }
+        
+        // We didn't find the next directory entry in this item. Look for the next
+        // item of the directory.
+        
+        status = fsw_reiserfs_item_next(vol, &item);
+        if (status)
+            return status;
+        
+    }
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_reiserfs_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ */
+
+static fsw_status_t fsw_reiserfs_readlink(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+                                          struct fsw_string *link_target)
+{
+    return fsw_dnode_readlink_data(dno, link_target);
+}
+
+/**
+ * Compare an on-disk tree key against the search key.
+ */
+
+static int fsw_reiserfs_compare_key(struct reiserfs_key *key,
+                                    fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset)
+{
+    fsw_u32 key_type;
+    fsw_u64 key_offset;
+    
+    if (key->k_dir_id > dir_id)
+        return FIRST_GREATER;
+    if (key->k_dir_id < dir_id)
+        return SECOND_GREATER;
+    
+    if (key->k_objectid > objectid)
+        return FIRST_GREATER;
+    if (key->k_objectid < objectid)
+        return SECOND_GREATER;
+    
+    // determine format of the on-disk key
+    key_type = (fsw_u32)FSW_U64_SHR(key->u.k_offset_v2.v, 60);
+    if (key_type != TYPE_DIRECT && key_type != TYPE_INDIRECT && key_type != TYPE_DIRENTRY) {
+        // detected 3.5 format (_v1)
+        key_offset = key->u.k_offset_v1.k_offset;
+    } else {
+        // detected 3.6 format (_v2)
+        key_offset = key->u.k_offset_v2.v & (~0ULL >> 4);
+    }
+    if (key_offset > offset)
+        return FIRST_GREATER;
+    if (key_offset < offset)
+        return SECOND_GREATER;
+    return KEYS_IDENTICAL;
+}
+
+/**
+ * Find an item by key in the reiserfs tree.
+ */
+
+static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol,
+                                            fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset,
+                                            struct fsw_reiserfs_item *item)
+{
+    fsw_status_t    status;
+    int             comp_result;
+    fsw_u32         tree_bno, next_tree_bno, tree_level, nr_item, i;
+    fsw_u8          *buffer;
+    struct block_head *bhead;
+    struct reiserfs_key *key;
+    struct item_head *ihead;
+    
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: searching %d/%d/%lld\n"), dir_id, objectid, offset));
+    
+    // BIG TODOS: Use binary search within the item.
+    //  Remember tree path for "get next item" function.
+    
+    item->valid = 0;
+    item->block_bno = 0;
+    
+    // walk the tree
+    tree_bno = vol->sb->s_v1.s_root_block;
+    for (tree_level = vol->sb->s_v1.s_tree_height - 1; ; tree_level--) {
+        
+        // get the current tree block into memory
+        status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer);
+        if (status)
+            return status;
+        bhead = (struct block_head *)buffer;
+        if (bhead->blk_level != tree_level) {
+            FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_search: tree block %d has not expected level %d\n"), tree_bno, tree_level));
+            fsw_block_release(vol, tree_bno, buffer);
+            return FSW_VOLUME_CORRUPTED;
+        }
+        nr_item = bhead->blk_nr_item;
+        FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_search: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item));
+        item->path_bno[tree_level] = tree_bno;
+        
+        // check if we have reached a leaf block
+        if (tree_level == DISK_LEAF_NODE_LEVEL)
+            break;
+        
+        // search internal node block, look for the path to follow
+        key = (struct reiserfs_key *)(buffer + BLKH_SIZE);
+        for (i = 0; i < nr_item; i++, key++) {
+            if (fsw_reiserfs_compare_key(key, dir_id, objectid, offset) == FIRST_GREATER)
+                break;
+        }
+        item->path_index[tree_level] = i;
+        next_tree_bno = ((struct disk_child *)(buffer + BLKH_SIZE + nr_item * KEY_SIZE))[i].dc_block_number;
+        fsw_block_release(vol, tree_bno, buffer);
+        tree_bno = next_tree_bno;
+    }
+    
+    // search leaf node block, look for our data
+    ihead = (struct item_head *)(buffer + BLKH_SIZE);
+    for (i = 0; i < nr_item; i++, ihead++) {
+        comp_result = fsw_reiserfs_compare_key(&ihead->ih_key, dir_id, objectid, offset);
+        if (comp_result == KEYS_IDENTICAL)
+            break;
+        if (comp_result == FIRST_GREATER) {
+            // Current key is greater than the search key. Use the last key before this
+            // one as the preliminary result.
+            if (i == 0) {
+                fsw_block_release(vol, tree_bno, buffer);
+                return FSW_NOT_FOUND;
+            }
+            i--, ihead--;
+            break;
+        }
+    }
+    if (i >= nr_item) {
+        // Go back to the last key, it was smaller than the search key.
+        // NOTE: The first key of the next leaf block is guaranteed to be greater than
+        //  our search key.
+        i--, ihead--;
+    }
+    item->path_index[tree_level] = i;
+    // Since we may have a key that is smaller than the search key, verify that
+    // it is for the same object.
+    if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) {
+        fsw_block_release(vol, tree_bno, buffer);
+        return FSW_NOT_FOUND;   // Found no key for this object at all
+    }
+    
+    // return results
+    fsw_memcpy(&item->ih, ihead, sizeof(struct item_head));
+    item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60);
+    if (item->item_type != TYPE_DIRECT &&
+        item->item_type != TYPE_INDIRECT &&
+        item->item_type != TYPE_DIRENTRY) {
+        // 3.5 format (_v1)
+        item->item_type = ihead->ih_key.u.k_offset_v1.k_uniqueness;
+        item->item_offset = ihead->ih_key.u.k_offset_v1.k_offset;
+    } else {
+        // 3.6 format (_v2)
+        item->item_offset = ihead->ih_key.u.k_offset_v2.v & (~0ULL >> 4);
+    }
+    item->item_data = buffer + ihead->ih_item_location;
+    item->valid = 1;
+    
+    // add information for block release
+    item->block_bno = tree_bno;
+    item->block_buffer = buffer;
+    
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: found %d/%d/%lld (%d)\n"),
+                   ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type));
+    return FSW_SUCCESS;
+}
+
+/**
+ * Find the next item in the reiserfs tree for an already-found item.
+ */
+
+static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol,
+                                          struct fsw_reiserfs_item *item)
+{
+    fsw_status_t    status;
+    fsw_u32         dir_id, objectid;
+    fsw_u64         offset;
+    fsw_u32         tree_bno, next_tree_bno, tree_level, nr_item, nr_ptr_item;
+    fsw_u8          *buffer;
+    struct block_head *bhead;
+    struct item_head *ihead;
+    
+    if (!item->valid)
+        return FSW_NOT_FOUND;
+    fsw_reiserfs_item_release(vol, item);   // TODO: maybe delay this and/or use the cached block!
+    
+    dir_id = item->ih.ih_key.k_dir_id;
+    objectid = item->ih.ih_key.k_objectid;
+    offset = item->item_offset;
+    
+    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: next for %d/%d/%lld\n"), dir_id, objectid, offset));
+    
+    // find a node that has more items, moving up until we find one
+    
+    for (tree_level = DISK_LEAF_NODE_LEVEL; tree_level < vol->sb->s_v1.s_tree_height; tree_level++) {
+        
+        // get the current tree block into memory
+        tree_bno = item->path_bno[tree_level];
+        status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer);
+        if (status)
+            return status;
+        bhead = (struct block_head *)buffer;
+        if (bhead->blk_level != tree_level) {
+            FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_next: tree block %d has not expected level %d\n"), tree_bno, tree_level));
+            fsw_block_release(vol, tree_bno, buffer);
+            return FSW_VOLUME_CORRUPTED;
+        }
+        nr_item = bhead->blk_nr_item;
+        FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item));
+        
+        nr_ptr_item = nr_item + ((tree_level > DISK_LEAF_NODE_LEVEL) ? 1 : 0);  // internal nodes have (nr_item) keys and (nr_item+1) pointers
+        item->path_index[tree_level]++;
+        if (item->path_index[tree_level] >= nr_ptr_item) {
+            item->path_index[tree_level] = 0;
+            fsw_block_release(vol, tree_bno, buffer);
+            continue;  // this node doesn't have any more items, move up one level
+        }
+        
+        // we have a new path to follow, move down to the leaf node again
+        while (tree_level > DISK_LEAF_NODE_LEVEL) {
+            // get next pointer from current block
+            next_tree_bno = ((struct disk_child *)(buffer + BLKH_SIZE + nr_item * KEY_SIZE))[item->path_index[tree_level]].dc_block_number;
+            fsw_block_release(vol, tree_bno, buffer);
+            tree_bno = next_tree_bno;
+            tree_level--;
+            
+            // get the current tree block into memory
+            status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer);
+            if (status)
+                return status;
+            bhead = (struct block_head *)buffer;
+            if (bhead->blk_level != tree_level) {
+                FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_next: tree block %d has not expected level %d\n"), tree_bno, tree_level));
+                fsw_block_release(vol, tree_bno, buffer);
+                return FSW_VOLUME_CORRUPTED;
+            }
+            nr_item = bhead->blk_nr_item;
+            FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item));
+            item->path_bno[tree_level] = tree_bno;
+        }
+        
+        // get the item from the leaf node
+        ihead = ((struct item_head *)(buffer + BLKH_SIZE)) + item->path_index[tree_level];
+        
+        // We now have the item that follows the previous one in the tree. Check that it
+        // belongs to the same object.
+        if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) {
+            fsw_block_release(vol, tree_bno, buffer);
+            return FSW_NOT_FOUND;   // Found no next key for this object
+        }
+        
+        // return results
+        fsw_memcpy(&item->ih, ihead, sizeof(struct item_head));
+        item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60);
+        if (item->item_type != TYPE_DIRECT &&
+            item->item_type != TYPE_INDIRECT &&
+            item->item_type != TYPE_DIRENTRY) {
+            // 3.5 format (_v1)
+            item->item_type = ihead->ih_key.u.k_offset_v1.k_uniqueness;
+            item->item_offset = ihead->ih_key.u.k_offset_v1.k_offset;
+        } else {
+            // 3.6 format (_v2)
+            item->item_offset = ihead->ih_key.u.k_offset_v2.v & (~0ULL >> 4);
+        }
+        item->item_data = buffer + ihead->ih_item_location;
+        item->valid = 1;
+        
+        // add information for block release
+        item->block_bno = tree_bno;
+        item->block_buffer = buffer;
+        
+        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: found %d/%d/%lld (%d)\n"),
+                       ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type));
+        return FSW_SUCCESS;
+    }
+    
+    // we went to the highest level node and there still were no more items...
+    return FSW_NOT_FOUND;
+}
+
+/**
+ * Release the disk block still referenced by an item search result.
+ */
+
+static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol,
+                                      struct fsw_reiserfs_item *item)
+{
+    if (!item->valid)
+        return;
+    
+    if (item->block_bno > 0) {
+        fsw_block_release(vol, item->block_bno, item->block_buffer);
+        item->block_bno = 0;
+    }
+}
+
+// EOF
diff --git a/filesystems/fsw_reiserfs.h b/filesystems/fsw_reiserfs.h
new file mode 100644 (file)
index 0000000..cbb1ea9
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+ * \file fsw_reiserfs.h
+ * ReiserFS file system driver header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will 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 to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _FSW_REISERFS_H_
+#define _FSW_REISERFS_H_
+
+#define VOLSTRUCTNAME fsw_reiserfs_volume
+#define DNODESTRUCTNAME fsw_reiserfs_dnode
+#include "fsw_core.h"
+
+#include "fsw_reiserfs_disk.h"
+
+
+//! Block size (in shift bits) to be used when reading the reiserfs superblock.
+#define REISERFS_SUPERBLOCK_BLOCKSIZEBITS  12
+//! Block size (in bytes) to be used when reading the reiserfs superblock.
+#define REISERFS_SUPERBLOCK_BLOCKSIZE  (1<<REISERFS_SUPERBLOCK_BLOCKSIZEBITS)
+
+
+/**
+ * ReiserFS: Results from a tree search.
+ */
+
+struct fsw_reiserfs_item {
+    int valid;
+    
+    // the found item
+    struct item_head ih;
+    fsw_u64 item_offset;
+    fsw_u32 item_type;
+    
+    fsw_u8 *item_data;
+    
+    // path information
+    fsw_u32 path_bno[MAX_HEIGHT];
+    fsw_u32 path_index[MAX_HEIGHT];
+    
+    // block release information
+    fsw_u32 block_bno;
+    void *block_buffer;
+};
+
+
+/**
+ * ReiserFS: Volume structure with reiserfs-specific data.
+ */
+
+struct fsw_reiserfs_volume {
+    struct fsw_volume g;            //!< Generic volume structure
+    
+    struct reiserfs_super_block *sb;  //!< Full raw reiserfs superblock structure
+    int version;                    //!< Flag for 3.5 or 3.6 format
+};
+
+/**
+ * ReiserFS: Dnode structure with reiserfs-specific data.
+ */
+
+struct fsw_reiserfs_dnode {
+    struct fsw_dnode g;             //!< Generic dnode structure
+    
+    fsw_u32 dir_id;                 //!< Locality ID for the reiserfs tree (parent dir id)
+    struct stat_data_v1 *sd_v1;     //!< Full stat_data, version 1
+    struct stat_data *sd_v2;        //!< Full stat_data, version 2
+};
+
+
+#endif
diff --git a/filesystems/fsw_reiserfs_disk.h b/filesystems/fsw_reiserfs_disk.h
new file mode 100644 (file)
index 0000000..885a2e0
--- /dev/null
@@ -0,0 +1,1677 @@
+/**
+ * \file fsw_reiserfs_disk.h
+ * ReiserFS file system on-disk structures.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ * Portions Copyright (c) 1991-2006 by various Linux kernel contributors
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will 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 to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _FSW_REISERFS_DISK_H_
+#define _FSW_REISERFS_DISK_H_
+
+// types
+
+typedef fsw_s8  __s8;
+typedef fsw_u8  __u8;
+typedef fsw_s16 __s16;
+typedef fsw_u16 __u16;
+typedef fsw_s32 __s32;
+typedef fsw_u32 __u32;
+typedef fsw_s64 __s64;
+typedef fsw_u64 __u64;
+
+typedef __u16   __le16;
+typedef __u32   __le32;
+typedef __u64   __le64;
+
+#define le16_to_cpu(x) (x)
+#define cpu_to_le16(x) (x)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+#define le64_to_cpu(x) (x)
+#define cpu_to_le64(x) (x)
+
+#ifdef __GCC__
+#define ATTR_PACKED __attribute__ ((__packed__))
+#else
+#define ATTR_PACKED
+#endif
+
+#pragma pack(1)
+
+//
+// from Linux kernel, include/linux/reiserfs_fs.h
+//
+
+
+
+/*
+ * Disk Data Structures
+ */
+
+/***************************************************************************/
+/*                             SUPER BLOCK                                 */
+/***************************************************************************/
+
+/*
+ * Structure of super block on disk, a version of which in RAM is often accessed as REISERFS_SB(s)->s_rs
+ * the version in RAM is part of a larger structure containing fields never written to disk.
+ */
+#define UNSET_HASH 0           // read_super will guess about, what hash names
+                    // in directories were sorted with
+#define TEA_HASH  1
+#define YURA_HASH 2
+#define R5_HASH   3
+#define DEFAULT_HASH R5_HASH
+
+struct journal_params {
+       __le32 jp_journal_1st_block;    /* where does journal start from on its
+                                        * device */
+       __le32 jp_journal_dev;  /* journal device st_rdev */
+       __le32 jp_journal_size; /* size of the journal */
+       __le32 jp_journal_trans_max;    /* max number of blocks in a transaction. */
+       __le32 jp_journal_magic;        /* random value made on fs creation (this
+                                        * was sb_journal_block_count) */
+       __le32 jp_journal_max_batch;    /* max number of blocks to batch into a
+                                        * trans */
+       __le32 jp_journal_max_commit_age;       /* in seconds, how old can an async
+                                                * commit be */
+       __le32 jp_journal_max_trans_age;        /* in seconds, how old can a transaction
+                                                * be */
+};
+
+/* this is the super from 3.5.X, where X >= 10 */
+struct reiserfs_super_block_v1 {
+       __le32 s_block_count;   /* blocks count         */
+       __le32 s_free_blocks;   /* free blocks count    */
+       __le32 s_root_block;    /* root block number    */
+       struct journal_params s_journal;
+       __le16 s_blocksize;     /* block size */
+       __le16 s_oid_maxsize;   /* max size of object id array, see
+                                * get_objectid() commentary  */
+       __le16 s_oid_cursize;   /* current size of object id array */
+       __le16 s_umount_state;  /* this is set to 1 when filesystem was
+                                * umounted, to 2 - when not */
+       char s_magic[10];       /* reiserfs magic string indicates that
+                                * file system is reiserfs:
+                                * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
+       __le16 s_fs_state;      /* it is set to used by fsck to mark which
+                                * phase of rebuilding is done */
+       __le32 s_hash_function_code;    /* indicate, what hash function is being use
+                                        * to sort names in a directory*/
+       __le16 s_tree_height;   /* height of disk tree */
+       __le16 s_bmap_nr;       /* amount of bitmap blocks needed to address
+                                * each block of file system */
+       __le16 s_version;       /* this field is only reliable on filesystem
+                                * with non-standard journal */
+       __le16 s_reserved_for_journal;  /* size in blocks of journal area on main
+                                        * device, we need to keep after
+                                        * making fs with non-standard journal */
+} ATTR_PACKED;
+
+#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))
+
+/* this is the on disk super block */
+struct reiserfs_super_block {
+       struct reiserfs_super_block_v1 s_v1;
+       __le32 s_inode_generation;
+       __le32 s_flags;         /* Right now used only by inode-attributes, if enabled */
+       unsigned char s_uuid[16];       /* filesystem unique identifier */
+       unsigned char s_label[16];      /* filesystem volume label */
+       char s_unused[88];      /* zero filled by mkreiserfs and
+                                * reiserfs_convert_objectid_map_v1()
+                                * so any additions must be updated
+                                * there as well. */
+} ATTR_PACKED;
+
+#define SB_SIZE (sizeof(struct reiserfs_super_block))
+
+#define REISERFS_VERSION_1 0
+#define REISERFS_VERSION_2 2
+
+// on-disk super block fields converted to cpu form
+#define SB_DISK_SUPER_BLOCK(s) (REISERFS_SB(s)->s_rs)
+#define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1))
+#define SB_BLOCKSIZE(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize))
+#define SB_BLOCK_COUNT(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count))
+#define SB_FREE_BLOCKS(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks))
+#define SB_REISERFS_MAGIC(s) \
+        (SB_V1_DISK_SUPER_BLOCK(s)->s_magic)
+#define SB_ROOT_BLOCK(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_root_block))
+#define SB_TREE_HEIGHT(s) \
+        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height))
+#define SB_REISERFS_STATE(s) \
+        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state))
+#define SB_VERSION(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_version))
+#define SB_BMAP_NR(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr))
+
+#define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal)
+#define SB_ONDISK_JOURNAL_SIZE(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size))
+#define SB_ONDISK_JOURNAL_1st_BLOCK(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_1st_block))
+#define SB_ONDISK_JOURNAL_DEVICE(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev))
+#define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \
+         le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal))
+
+#define is_block_in_log_or_reserved_area(s, block) \
+         block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \
+         && block < SB_JOURNAL_1st_RESERVED_BLOCK(s) +  \
+         ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \
+         SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s)))
+
+                               /* used by gcc */
+#define REISERFS_SUPER_MAGIC 0x52654973
+                               /* used by file system utilities that
+                                  look at the superblock, etc. */
+#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs"
+
+/* ReiserFS leaves the first 64k unused, so that partition labels have
+   enough space.  If someone wants to write a fancy bootloader that
+   needs more than 64k, let us know, and this will be increased in size.
+   This number must be larger than than the largest block size on any
+   platform, or code will break.  -Hans */
+#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
+#define REISERFS_FIRST_BLOCK unused_define
+#define REISERFS_JOURNAL_OFFSET_IN_BYTES REISERFS_DISK_OFFSET_IN_BYTES
+
+/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */
+#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
+
+// reiserfs internal error code (used by search_by_key adn fix_nodes))
+#define CARRY_ON      0
+#define REPEAT_SEARCH -1
+#define IO_ERROR      -2
+#define NO_DISK_SPACE -3
+#define NO_BALANCING_NEEDED  (-4)
+#define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5)
+#define QUOTA_EXCEEDED -6
+
+typedef __u32 b_blocknr_t;
+typedef __le32 unp_t;
+
+struct unfm_nodeinfo {
+       unp_t unfm_nodenum;
+       unsigned short unfm_freespace;
+};
+
+/* there are two formats of keys: 3.5 and 3.6
+ */
+#define KEY_FORMAT_3_5 0
+#define KEY_FORMAT_3_6 1
+
+/* there are two stat datas */
+#define STAT_DATA_V1 0
+#define STAT_DATA_V2 1
+
+
+
+/** this says about version of key of all items (but stat data) the
+    object consists of */
+#define get_inode_item_key_version( inode )                                    \
+    ((REISERFS_I(inode)->i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5)
+
+#define set_inode_item_key_version( inode, version )                           \
+         ({ if((version)==KEY_FORMAT_3_6)                                      \
+                REISERFS_I(inode)->i_flags |= i_item_key_version_mask;      \
+            else                                                               \
+                REISERFS_I(inode)->i_flags &= ~i_item_key_version_mask; })
+
+#define get_inode_sd_version(inode)                                            \
+    ((REISERFS_I(inode)->i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1)
+
+#define set_inode_sd_version(inode, version)                                   \
+         ({ if((version)==STAT_DATA_V2)                                        \
+                REISERFS_I(inode)->i_flags |= i_stat_data_version_mask;     \
+            else                                                               \
+                REISERFS_I(inode)->i_flags &= ~i_stat_data_version_mask; })
+
+/* This is an aggressive tail suppression policy, I am hoping it
+   improves our benchmarks. The principle behind it is that percentage
+   space saving is what matters, not absolute space saving.  This is
+   non-intuitive, but it helps to understand it if you consider that the
+   cost to access 4 blocks is not much more than the cost to access 1
+   block, if you have to do a seek and rotate.  A tail risks a
+   non-linear disk access that is significant as a percentage of total
+   time cost for a 4 block file and saves an amount of space that is
+   less significant as a percentage of space, or so goes the hypothesis.
+   -Hans */
+#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \
+(\
+  (!(n_tail_size)) || \
+  (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \
+   ( (n_file_size) >= (n_block_size) * 4 ) || \
+   ( ( (n_file_size) >= (n_block_size) * 3 ) && \
+     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \
+   ( ( (n_file_size) >= (n_block_size) * 2 ) && \
+     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \
+   ( ( (n_file_size) >= (n_block_size) ) && \
+     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \
+)
+
+/* Another strategy for tails, this one means only create a tail if all the
+   file would fit into one DIRECT item.
+   Primary intention for this one is to increase performance by decreasing
+   seeking.
+*/
+#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \
+(\
+  (!(n_tail_size)) || \
+  (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \
+)
+
+/*
+ * values for s_umount_state field
+ */
+#define REISERFS_VALID_FS    1
+#define REISERFS_ERROR_FS    2
+
+//
+// there are 5 item types currently
+//
+#define TYPE_STAT_DATA 0
+#define TYPE_INDIRECT 1
+#define TYPE_DIRECT 2
+#define TYPE_DIRENTRY 3
+#define TYPE_MAXTYPE 3
+#define TYPE_ANY 15            // FIXME: comment is required
+
+/***************************************************************************/
+/*                       KEY & ITEM HEAD                                   */
+/***************************************************************************/
+
+//
+// directories use this key as well as old files
+//
+struct offset_v1 {
+       __le32 k_offset;
+       __le32 k_uniqueness;
+} ATTR_PACKED;
+
+struct offset_v2 {
+       __le64 v;
+} ATTR_PACKED;
+
+/*
+static inline __u16 offset_v2_k_type(const struct offset_v2 *v2)
+{
+       __u8 type = le64_to_cpu(v2->v) >> 60;
+       return (type <= TYPE_MAXTYPE) ? type : TYPE_ANY;
+}
+
+static inline loff_t offset_v2_k_offset(const struct offset_v2 *v2)
+{
+       return le64_to_cpu(v2->v) & (~0ULL >> 4);
+}
+*/
+
+/* Key of an item determines its location in the S+tree, and
+   is composed of 4 components */
+struct reiserfs_key {
+       __le32 k_dir_id;        /* packing locality: by default parent
+                                  directory object id */
+       __le32 k_objectid;      /* object identifier */
+       union {
+               struct offset_v1 k_offset_v1;
+               struct offset_v2 k_offset_v2;
+       } ATTR_PACKED u;
+} ATTR_PACKED;
+
+struct in_core_key {
+       __u32 k_dir_id;         /* packing locality: by default parent
+                                  directory object id */
+       __u32 k_objectid;       /* object identifier */
+       __u64 k_offset;
+       __u8 k_type;
+};
+
+struct cpu_key {
+       struct in_core_key on_disk_key;
+       int version;
+       int key_length;         /* 3 in all cases but direct2indirect and
+                                  indirect2direct conversion */
+};
+
+/* Our function for comparing keys can compare keys of different
+   lengths.  It takes as a parameter the length of the keys it is to
+   compare.  These defines are used in determining what is to be passed
+   to it as that parameter. */
+#define REISERFS_FULL_KEY_LEN     4
+#define REISERFS_SHORT_KEY_LEN    2
+
+/* The result of the key compare */
+#define FIRST_GREATER 1
+#define SECOND_GREATER -1
+#define KEYS_IDENTICAL 0
+#define KEY_FOUND 1
+#define KEY_NOT_FOUND 0
+
+#define KEY_SIZE (sizeof(struct reiserfs_key))
+#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32))
+
+/* return values for search_by_key and clones */
+#define ITEM_FOUND 1
+#define ITEM_NOT_FOUND 0
+#define ENTRY_FOUND 1
+#define ENTRY_NOT_FOUND 0
+#define DIRECTORY_NOT_FOUND -1
+#define REGULAR_FILE_FOUND -2
+#define DIRECTORY_FOUND -3
+#define BYTE_FOUND 1
+#define BYTE_NOT_FOUND 0
+#define FILE_NOT_FOUND -1
+
+#define POSITION_FOUND 1
+#define POSITION_NOT_FOUND 0
+
+// return values for reiserfs_find_entry and search_by_entry_key
+#define NAME_FOUND 1
+#define NAME_NOT_FOUND 0
+#define GOTO_PREVIOUS_ITEM 2
+#define NAME_FOUND_INVISIBLE 3
+
+/*  Everything in the filesystem is stored as a set of items.  The
+    item head contains the key of the item, its free space (for
+    indirect items) and specifies the location of the item itself
+    within the block.  */
+
+struct item_head {
+       /* Everything in the tree is found by searching for it based on
+        * its key.*/
+       struct reiserfs_key ih_key;
+       union {
+               /* The free space in the last unformatted node of an
+                  indirect item if this is an indirect item.  This
+                  equals 0xFFFF iff this is a direct item or stat data
+                  item. Note that the key, not this field, is used to
+                  determine the item type, and thus which field this
+                  union contains. */
+               __le16 ih_free_space_reserved;
+               /* Iff this is a directory item, this field equals the
+                  number of directory entries in the directory item. */
+               __le16 ih_entry_count;
+       } ATTR_PACKED u;
+       __le16 ih_item_len;     /* total size of the item body */
+       __le16 ih_item_location;        /* an offset to the item body
+                                        * within the block */
+       __le16 ih_version;      /* 0 for all old items, 2 for new
+                                  ones. Highest bit is set by fsck
+                                  temporary, cleaned after all
+                                  done */
+} ATTR_PACKED;
+/* size of item header     */
+#define IH_SIZE (sizeof(struct item_head))
+
+#define ih_free_space(ih)            le16_to_cpu((ih)->u.ih_free_space_reserved)
+#define ih_version(ih)               le16_to_cpu((ih)->ih_version)
+#define ih_entry_count(ih)           le16_to_cpu((ih)->u.ih_entry_count)
+#define ih_location(ih)              le16_to_cpu((ih)->ih_item_location)
+#define ih_item_len(ih)              le16_to_cpu((ih)->ih_item_len)
+
+#define unreachable_item(ih) (ih_version(ih) & (1 << 15))
+
+#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih))
+
+/* these operate on indirect items, where you've got an array of ints
+** at a possibly unaligned location.  These are a noop on ia32
+** 
+** p is the array of __u32, i is the index into the array, v is the value
+** to store there.
+*/
+#define get_block_num(p, i) le32_to_cpu(get_unaligned((p) + (i)))
+
+//
+// in old version uniqueness field shows key type
+//
+#define V1_SD_UNIQUENESS 0
+#define V1_INDIRECT_UNIQUENESS 0xfffffffe
+#define V1_DIRECT_UNIQUENESS 0xffffffff
+#define V1_DIRENTRY_UNIQUENESS 500
+#define V1_ANY_UNIQUENESS 555  // FIXME: comment is required
+
+//
+// here are conversion routines
+//
+/*
+static inline int uniqueness2type(__u32 uniqueness)
+{
+       switch ((int)uniqueness) {
+       case V1_SD_UNIQUENESS:
+               return TYPE_STAT_DATA;
+       case V1_INDIRECT_UNIQUENESS:
+               return TYPE_INDIRECT;
+       case V1_DIRECT_UNIQUENESS:
+               return TYPE_DIRECT;
+       case V1_DIRENTRY_UNIQUENESS:
+               return TYPE_DIRENTRY;
+       default:
+               reiserfs_warning(NULL, "vs-500: unknown uniqueness %d",
+                                uniqueness);
+       case V1_ANY_UNIQUENESS:
+               return TYPE_ANY;
+       }
+}
+
+static inline __u32 type2uniqueness(int type)
+{
+       switch (type) {
+       case TYPE_STAT_DATA:
+               return V1_SD_UNIQUENESS;
+       case TYPE_INDIRECT:
+               return V1_INDIRECT_UNIQUENESS;
+       case TYPE_DIRECT:
+               return V1_DIRECT_UNIQUENESS;
+       case TYPE_DIRENTRY:
+               return V1_DIRENTRY_UNIQUENESS;
+       default:
+               reiserfs_warning(NULL, "vs-501: unknown type %d", type);
+       case TYPE_ANY:
+               return V1_ANY_UNIQUENESS;
+       }
+}
+*/
+
+//
+// key is pointer to on disk key which is stored in le, result is cpu,
+// there is no way to get version of object from key, so, provide
+// version to these defines
+//
+/*
+static inline loff_t le_key_k_offset(int version,
+                                    const struct reiserfs_key *key)
+{
+       return (version == KEY_FORMAT_3_5) ?
+           le32_to_cpu(key->u.k_offset_v1.k_offset) :
+           offset_v2_k_offset(&(key->u.k_offset_v2));
+}
+
+static inline loff_t le_ih_k_offset(const struct item_head *ih)
+{
+       return le_key_k_offset(ih_version(ih), &(ih->ih_key));
+}
+
+static inline loff_t le_key_k_type(int version, const struct reiserfs_key *key)
+{
+       return (version == KEY_FORMAT_3_5) ?
+           uniqueness2type(le32_to_cpu(key->u.k_offset_v1.k_uniqueness)) :
+           offset_v2_k_type(&(key->u.k_offset_v2));
+}
+
+static inline loff_t le_ih_k_type(const struct item_head *ih)
+{
+       return le_key_k_type(ih_version(ih), &(ih->ih_key));
+}
+*/
+
+#define is_direntry_le_key(version,key) (le_key_k_type (version, key) == TYPE_DIRENTRY)
+#define is_direct_le_key(version,key) (le_key_k_type (version, key) == TYPE_DIRECT)
+#define is_indirect_le_key(version,key) (le_key_k_type (version, key) == TYPE_INDIRECT)
+#define is_statdata_le_key(version,key) (le_key_k_type (version, key) == TYPE_STAT_DATA)
+
+//
+// item header has version.
+//
+#define is_direntry_le_ih(ih) is_direntry_le_key (ih_version (ih), &((ih)->ih_key))
+#define is_direct_le_ih(ih) is_direct_le_key (ih_version (ih), &((ih)->ih_key))
+#define is_indirect_le_ih(ih) is_indirect_le_key (ih_version(ih), &((ih)->ih_key))
+#define is_statdata_le_ih(ih) is_statdata_le_key (ih_version (ih), &((ih)->ih_key))
+
+//
+// key is pointer to cpu key, result is cpu
+//
+/*
+static inline loff_t cpu_key_k_offset(const struct cpu_key *key)
+{
+       return key->on_disk_key.k_offset;
+}
+
+static inline loff_t cpu_key_k_type(const struct cpu_key *key)
+{
+       return key->on_disk_key.k_type;
+}
+
+static inline void cpu_key_k_offset_dec(struct cpu_key *key)
+{
+       key->on_disk_key.k_offset--;
+}
+*/
+
+#define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY)
+#define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT)
+#define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT)
+#define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA)
+
+/* are these used ? */
+#define is_direntry_cpu_ih(ih) (is_direntry_cpu_key (&((ih)->ih_key)))
+#define is_direct_cpu_ih(ih) (is_direct_cpu_key (&((ih)->ih_key)))
+#define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key)))
+#define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key)))
+
+#define I_K_KEY_IN_ITEM(p_s_ih, p_s_key, n_blocksize) \
+    ( ! COMP_SHORT_KEYS(p_s_ih, p_s_key) && \
+          I_OFF_BYTE_IN_ITEM(p_s_ih, k_offset (p_s_key), n_blocksize) )
+
+/* maximal length of item */
+#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE)
+#define MIN_ITEM_LEN 1
+
+/* object identifier for root dir */
+#define REISERFS_ROOT_OBJECTID 2
+#define REISERFS_ROOT_PARENT_OBJECTID 1
+
+/* 
+ * Picture represents a leaf of the S+tree
+ *  ______________________________________________________
+ * |      |  Array of     |                   |           |
+ * |Block |  Object-Item  |      F r e e      |  Objects- |
+ * | head |  Headers      |     S p a c e     |   Items   |
+ * |______|_______________|___________________|___________|
+ */
+
+/* Header of a disk block.  More precisely, header of a formatted leaf
+   or internal node, and not the header of an unformatted node. */
+struct block_head {
+       __le16 blk_level;       /* Level of a block in the tree. */
+       __le16 blk_nr_item;     /* Number of keys/items in a block. */
+       __le16 blk_free_space;  /* Block free space in bytes. */
+       __le16 blk_reserved;
+       /* dump this in v4/planA */
+       struct reiserfs_key blk_right_delim_key;        /* kept only for compatibility */
+};
+
+#define BLKH_SIZE                     (sizeof(struct block_head))
+#define blkh_level(p_blkh)            (le16_to_cpu((p_blkh)->blk_level))
+#define blkh_nr_item(p_blkh)          (le16_to_cpu((p_blkh)->blk_nr_item))
+#define blkh_free_space(p_blkh)       (le16_to_cpu((p_blkh)->blk_free_space))
+#define blkh_reserved(p_blkh)         (le16_to_cpu((p_blkh)->blk_reserved))
+#define blkh_right_delim_key(p_blkh)  ((p_blkh)->blk_right_delim_key)
+
+/*
+ * values for blk_level field of the struct block_head
+ */
+
+#define FREE_LEVEL 0           /* when node gets removed from the tree its
+                                  blk_level is set to FREE_LEVEL. It is then
+                                  used to see whether the node is still in the
+                                  tree */
+
+#define DISK_LEAF_NODE_LEVEL  1        /* Leaf node level. */
+
+/* Given the buffer head of a formatted node, resolve to the block head of that node. */
+#define B_BLK_HEAD(p_s_bh)            ((struct block_head *)((p_s_bh)->b_data))
+/* Number of items that are in buffer. */
+#define B_NR_ITEMS(p_s_bh)            (blkh_nr_item(B_BLK_HEAD(p_s_bh)))
+#define B_LEVEL(p_s_bh)               (blkh_level(B_BLK_HEAD(p_s_bh)))
+#define B_FREE_SPACE(p_s_bh)          (blkh_free_space(B_BLK_HEAD(p_s_bh)))
+
+/* Get right delimiting key. -- little endian */
+#define B_PRIGHT_DELIM_KEY(p_s_bh)   (&(blk_right_delim_key(B_BLK_HEAD(p_s_bh))
+
+/* Does the buffer contain a disk leaf. */
+#define B_IS_ITEMS_LEVEL(p_s_bh)     (B_LEVEL(p_s_bh) == DISK_LEAF_NODE_LEVEL)
+
+/* Does the buffer contain a disk internal node */
+#define B_IS_KEYS_LEVEL(p_s_bh)      (B_LEVEL(p_s_bh) > DISK_LEAF_NODE_LEVEL \
+                                            && B_LEVEL(p_s_bh) <= MAX_HEIGHT)
+
+/***************************************************************************/
+/*                             STAT DATA                                   */
+/***************************************************************************/
+
+//
+// old stat data is 32 bytes long. We are going to distinguish new one by
+// different size
+//
+struct stat_data_v1 {
+       __le16 sd_mode;         /* file type, permissions */
+       __le16 sd_nlink;        /* number of hard links */
+       __le16 sd_uid;          /* owner */
+       __le16 sd_gid;          /* group */
+       __le32 sd_size;         /* file size */
+       __le32 sd_atime;        /* time of last access */
+       __le32 sd_mtime;        /* time file was last modified  */
+       __le32 sd_ctime;        /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+       union {
+               __le32 sd_rdev;
+               __le32 sd_blocks;       /* number of blocks file uses */
+       } ATTR_PACKED u;
+       __le32 sd_first_direct_byte;    /* first byte of file which is stored
+                                          in a direct item: except that if it
+                                          equals 1 it is a symlink and if it
+                                          equals ~(__u32)0 there is no
+                                          direct item.  The existence of this
+                                          field really grates on me. Let's
+                                          replace it with a macro based on
+                                          sd_size and our tail suppression
+                                          policy.  Someday.  -Hans */
+} ATTR_PACKED;
+
+#define SD_V1_SIZE              (sizeof(struct stat_data_v1))
+#define stat_data_v1(ih)        (ih_version (ih) == KEY_FORMAT_3_5)
+#define sd_v1_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
+#define set_sd_v1_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
+#define sd_v1_nlink(sdp)        (le16_to_cpu((sdp)->sd_nlink))
+#define set_sd_v1_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le16(v))
+#define sd_v1_uid(sdp)          (le16_to_cpu((sdp)->sd_uid))
+#define set_sd_v1_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le16(v))
+#define sd_v1_gid(sdp)          (le16_to_cpu((sdp)->sd_gid))
+#define set_sd_v1_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le16(v))
+#define sd_v1_size(sdp)         (le32_to_cpu((sdp)->sd_size))
+#define set_sd_v1_size(sdp,v)   ((sdp)->sd_size = cpu_to_le32(v))
+#define sd_v1_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
+#define set_sd_v1_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
+#define sd_v1_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
+#define set_sd_v1_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
+#define sd_v1_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
+#define set_sd_v1_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
+#define sd_v1_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
+#define set_sd_v1_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
+#define sd_v1_blocks(sdp)       (le32_to_cpu((sdp)->u.sd_blocks))
+#define set_sd_v1_blocks(sdp,v) ((sdp)->u.sd_blocks = cpu_to_le32(v))
+#define sd_v1_first_direct_byte(sdp) \
+                                (le32_to_cpu((sdp)->sd_first_direct_byte))
+#define set_sd_v1_first_direct_byte(sdp,v) \
+                                ((sdp)->sd_first_direct_byte = cpu_to_le32(v))
+
+/*
+#include <linux/ext2_fs.h>
+*/
+
+/* inode flags stored in sd_attrs (nee sd_reserved) */
+
+/* we want common flags to have the same values as in ext2,
+   so chattr(1) will work without problems */
+#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
+#define REISERFS_APPEND_FL    EXT2_APPEND_FL
+#define REISERFS_SYNC_FL      EXT2_SYNC_FL
+#define REISERFS_NOATIME_FL   EXT2_NOATIME_FL
+#define REISERFS_NODUMP_FL    EXT2_NODUMP_FL
+#define REISERFS_SECRM_FL     EXT2_SECRM_FL
+#define REISERFS_UNRM_FL      EXT2_UNRM_FL
+#define REISERFS_COMPR_FL     EXT2_COMPR_FL
+#define REISERFS_NOTAIL_FL    EXT2_NOTAIL_FL
+
+/* persistent flags that file inherits from the parent directory */
+#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL |        \
+                               REISERFS_SYNC_FL |      \
+                               REISERFS_NOATIME_FL |   \
+                               REISERFS_NODUMP_FL |    \
+                               REISERFS_SECRM_FL |     \
+                               REISERFS_COMPR_FL |     \
+                               REISERFS_NOTAIL_FL )
+
+/* Stat Data on disk (reiserfs version of UFS disk inode minus the
+   address blocks) */
+struct stat_data {
+       __le16 sd_mode;         /* file type, permissions */
+       __le16 sd_attrs;        /* persistent inode flags */
+       __le32 sd_nlink;        /* number of hard links */
+       __le64 sd_size;         /* file size */
+       __le32 sd_uid;          /* owner */
+       __le32 sd_gid;          /* group */
+       __le32 sd_atime;        /* time of last access */
+       __le32 sd_mtime;        /* time file was last modified  */
+       __le32 sd_ctime;        /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+       __le32 sd_blocks;
+       union {
+               __le32 sd_rdev;
+               __le32 sd_generation;
+               //__le32 sd_first_direct_byte;
+               /* first byte of file which is stored in a
+                  direct item: except that if it equals 1
+                  it is a symlink and if it equals
+                  ~(__u32)0 there is no direct item.  The
+                  existence of this field really grates
+                  on me. Let's replace it with a macro
+                  based on sd_size and our tail
+                  suppression policy? */
+       } ATTR_PACKED u;
+} ATTR_PACKED;
+//
+// this is 44 bytes long
+//
+#define SD_SIZE (sizeof(struct stat_data))
+#define SD_V2_SIZE              SD_SIZE
+#define stat_data_v2(ih)        (ih_version (ih) == KEY_FORMAT_3_6)
+#define sd_v2_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
+#define set_sd_v2_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
+/* sd_reserved */
+/* set_sd_reserved */
+#define sd_v2_nlink(sdp)        (le32_to_cpu((sdp)->sd_nlink))
+#define set_sd_v2_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le32(v))
+#define sd_v2_size(sdp)         (le64_to_cpu((sdp)->sd_size))
+#define set_sd_v2_size(sdp,v)   ((sdp)->sd_size = cpu_to_le64(v))
+#define sd_v2_uid(sdp)          (le32_to_cpu((sdp)->sd_uid))
+#define set_sd_v2_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le32(v))
+#define sd_v2_gid(sdp)          (le32_to_cpu((sdp)->sd_gid))
+#define set_sd_v2_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le32(v))
+#define sd_v2_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
+#define set_sd_v2_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
+#define sd_v2_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
+#define set_sd_v2_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
+#define sd_v2_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
+#define set_sd_v2_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
+#define sd_v2_blocks(sdp)       (le32_to_cpu((sdp)->sd_blocks))
+#define set_sd_v2_blocks(sdp,v) ((sdp)->sd_blocks = cpu_to_le32(v))
+#define sd_v2_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
+#define set_sd_v2_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
+#define sd_v2_generation(sdp)   (le32_to_cpu((sdp)->u.sd_generation))
+#define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v))
+#define sd_v2_attrs(sdp)         (le16_to_cpu((sdp)->sd_attrs))
+#define set_sd_v2_attrs(sdp,v)   ((sdp)->sd_attrs = cpu_to_le16(v))
+
+/***************************************************************************/
+/*                      DIRECTORY STRUCTURE                                */
+/***************************************************************************/
+/* 
+   Picture represents the structure of directory items
+   ________________________________________________
+   |  Array of     |   |     |        |       |   |
+   | directory     |N-1| N-2 | ....   |   1st |0th|
+   | entry headers |   |     |        |       |   |
+   |_______________|___|_____|________|_______|___|
+                    <----   directory entries         ------>
+
+ First directory item has k_offset component 1. We store "." and ".."
+ in one item, always, we never split "." and ".." into differing
+ items.  This makes, among other things, the code for removing
+ directories simpler. */
+#define SD_OFFSET  0
+#define SD_UNIQUENESS 0
+#define DOT_OFFSET 1
+#define DOT_DOT_OFFSET 2
+#define DIRENTRY_UNIQUENESS 500
+
+/* */
+#define FIRST_ITEM_OFFSET 1
+
+/*
+   Q: How to get key of object pointed to by entry from entry?  
+
+   A: Each directory entry has its header. This header has deh_dir_id and deh_objectid fields, those are key
+      of object, entry points to */
+
+/* NOT IMPLEMENTED:   
+   Directory will someday contain stat data of object */
+
+struct reiserfs_de_head {
+       __le32 deh_offset;      /* third component of the directory entry key */
+       __le32 deh_dir_id;      /* objectid of the parent directory of the object, that is referenced
+                                  by directory entry */
+       __le32 deh_objectid;    /* objectid of the object, that is referenced by directory entry */
+       __le16 deh_location;    /* offset of name in the whole item */
+       __le16 deh_state;       /* whether 1) entry contains stat data (for future), and 2) whether
+                                  entry is hidden (unlinked) */
+} ATTR_PACKED;
+#define DEH_SIZE                  sizeof(struct reiserfs_de_head)
+#define deh_offset(p_deh)         (le32_to_cpu((p_deh)->deh_offset))
+#define deh_dir_id(p_deh)         (le32_to_cpu((p_deh)->deh_dir_id))
+#define deh_objectid(p_deh)       (le32_to_cpu((p_deh)->deh_objectid))
+#define deh_location(p_deh)       (le16_to_cpu((p_deh)->deh_location))
+#define deh_state(p_deh)          (le16_to_cpu((p_deh)->deh_state))
+
+#define put_deh_offset(p_deh,v)   ((p_deh)->deh_offset = cpu_to_le32((v)))
+#define put_deh_dir_id(p_deh,v)   ((p_deh)->deh_dir_id = cpu_to_le32((v)))
+#define put_deh_objectid(p_deh,v) ((p_deh)->deh_objectid = cpu_to_le32((v)))
+#define put_deh_location(p_deh,v) ((p_deh)->deh_location = cpu_to_le16((v)))
+#define put_deh_state(p_deh,v)    ((p_deh)->deh_state = cpu_to_le16((v)))
+
+/* empty directory contains two entries "." and ".." and their headers */
+#define EMPTY_DIR_SIZE \
+(DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen ("..")))
+
+/* old format directories have this size when empty */
+#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3)
+
+#define DEH_Statdata 0         /* not used now */
+#define DEH_Visible 2
+
+/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */
+#if BITS_PER_LONG == 64 || defined(__s390__) || defined(__hppa__)
+#   define ADDR_UNALIGNED_BITS  (3)
+#endif
+
+/* These are only used to manipulate deh_state.
+ * Because of this, we'll use the ext2_ bit routines,
+ * since they are little endian */
+#ifdef ADDR_UNALIGNED_BITS
+
+#   define aligned_address(addr)           ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1)))
+#   define unaligned_offset(addr)          (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3)
+
+#   define set_bit_unaligned(nr, addr)     ext2_set_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define clear_bit_unaligned(nr, addr)   ext2_clear_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define test_bit_unaligned(nr, addr)    ext2_test_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+
+#else
+
+#   define set_bit_unaligned(nr, addr)     ext2_set_bit(nr, addr)
+#   define clear_bit_unaligned(nr, addr)   ext2_clear_bit(nr, addr)
+#   define test_bit_unaligned(nr, addr)    ext2_test_bit(nr, addr)
+
+#endif
+
+#define mark_de_with_sd(deh)        set_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define mark_de_without_sd(deh)     clear_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define mark_de_visible(deh)       set_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+#define mark_de_hidden(deh)        clear_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+
+#define de_with_sd(deh)                    test_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define de_visible(deh)                    test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+#define de_hidden(deh)             !test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+
+/*
+extern void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
+                                  __le32 par_dirid, __le32 par_objid);
+extern void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
+                               __le32 par_dirid, __le32 par_objid);
+*/
+
+/* array of the entry headers */
+ /* get item body */
+#define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih) )
+#define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih)))
+
+/* length of the directory entry in directory item. This define
+   calculates length of i-th directory entry using directory entry
+   locations from dir entry head. When it calculates length of 0-th
+   directory entry, it uses length of whole item in place of entry
+   location of the non-existent following entry in the calculation.
+   See picture above.*/
+/*
+#define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \
+((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh))))
+*/
+/*
+static inline int entry_length(const struct buffer_head *bh,
+                              const struct item_head *ih, int pos_in_item)
+{
+       struct reiserfs_de_head *deh;
+
+       deh = B_I_DEH(bh, ih) + pos_in_item;
+       if (pos_in_item)
+               return deh_location(deh - 1) - deh_location(deh);
+
+       return ih_item_len(ih) - deh_location(deh);
+}
+*/
+
+/* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */
+#define I_ENTRY_COUNT(ih) (ih_entry_count((ih)))
+
+/* name by bh, ih and entry_num */
+#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num))))
+
+// two entries per block (at least)
+#define REISERFS_MAX_NAME(block_size) 255
+
+/* this structure is used for operations on directory entries. It is
+   not a disk structure. */
+/* When reiserfs_find_entry or search_by_entry_key find directory
+   entry, they return filled reiserfs_dir_entry structure */
+struct reiserfs_dir_entry {
+       struct buffer_head *de_bh;
+       int de_item_num;
+       struct item_head *de_ih;
+       int de_entry_num;
+       struct reiserfs_de_head *de_deh;
+       int de_entrylen;
+       int de_namelen;
+       char *de_name;
+       unsigned long *de_gen_number_bit_string;
+
+       __u32 de_dir_id;
+       __u32 de_objectid;
+
+       struct cpu_key de_entry_key;
+};
+
+/* these defines are useful when a particular member of a reiserfs_dir_entry is needed */
+
+/* pointer to file name, stored in entry */
+#define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + deh_location(deh))
+
+/* length of name */
+#define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \
+(I_DEH_N_ENTRY_LENGTH (ih, deh, entry_num) - (de_with_sd (deh) ? SD_SIZE : 0))
+
+/* hash value occupies bits from 7 up to 30 */
+#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL)
+/* generation number occupies 7 bits starting from 0 up to 6 */
+#define GET_GENERATION_NUMBER(offset) ((offset) & 0x7fLL)
+#define MAX_GENERATION_NUMBER  127
+
+#define SET_GENERATION_NUMBER(offset,gen_number) (GET_HASH_VALUE(offset)|(gen_number))
+
+/*
+ * Picture represents an internal node of the reiserfs tree
+ *  ______________________________________________________
+ * |      |  Array of     |  Array of         |  Free     |
+ * |block |    keys       |  pointers         | space     |
+ * | head |      N        |      N+1          |           |
+ * |______|_______________|___________________|___________|
+ */
+
+/***************************************************************************/
+/*                      DISK CHILD                                         */
+/***************************************************************************/
+/* Disk child pointer: The pointer from an internal node of the tree
+   to a node that is on disk. */
+struct disk_child {
+       __le32 dc_block_number; /* Disk child's block number. */
+       __le16 dc_size;         /* Disk child's used space.   */
+       __le16 dc_reserved;
+};
+
+#define DC_SIZE (sizeof(struct disk_child))
+#define dc_block_number(dc_p)  (le32_to_cpu((dc_p)->dc_block_number))
+#define dc_size(dc_p)          (le16_to_cpu((dc_p)->dc_size))
+
+/* Get disk child by buffer header and position in the tree node. */
+#define B_N_CHILD(p_s_bh,n_pos)  ((struct disk_child *)\
+((p_s_bh)->b_data+BLKH_SIZE+B_NR_ITEMS(p_s_bh)*KEY_SIZE+DC_SIZE*(n_pos)))
+
+/* Get disk child number by buffer header and position in the tree node. */
+#define B_N_CHILD_NUM(p_s_bh,n_pos) (dc_block_number(B_N_CHILD(p_s_bh,n_pos)))
+#define PUT_B_N_CHILD_NUM(p_s_bh,n_pos, val) (put_dc_block_number(B_N_CHILD(p_s_bh,n_pos), val ))
+
+ /* maximal value of field child_size in structure disk_child */
+ /* child size is the combined size of all items and their headers */
+#define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE ))
+
+/* amount of used space in buffer (not including block head) */
+#define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur)))
+
+/* max and min number of keys in internal node */
+#define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) )
+#define MIN_NR_KEY(bh)    (MAX_NR_KEY(bh)/2)
+
+/***************************************************************************/
+/*                      PATH STRUCTURES AND DEFINES                        */
+/***************************************************************************/
+
+/* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the
+   key.  It uses reiserfs_bread to try to find buffers in the cache given their block number.  If it
+   does not find them in the cache it reads them from disk.  For each node search_by_key finds using
+   reiserfs_bread it then uses bin_search to look through that node.  bin_search will find the
+   position of the block_number of the next node if it is looking through an internal node.  If it
+   is looking through a leaf node bin_search will find the position of the item which has key either
+   equal to given key, or which is the maximal key less than the given key. */
+
+struct path_element {
+       struct buffer_head *pe_buffer;  /* Pointer to the buffer at the path in the tree. */
+       int pe_position;        /* Position in the tree node which is placed in the */
+       /* buffer above.                                  */
+};
+
+#define MAX_HEIGHT 5           /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */
+#define EXTENDED_MAX_HEIGHT         7  /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */
+#define FIRST_PATH_ELEMENT_OFFSET   2  /* Must be equal to at least 2. */
+
+#define ILLEGAL_PATH_ELEMENT_OFFSET 1  /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */
+#define MAX_FEB_SIZE 6         /* this MUST be MAX_HEIGHT + 1. See about FEB below */
+
+/* We need to keep track of who the ancestors of nodes are.  When we
+   perform a search we record which nodes were visited while
+   descending the tree looking for the node we searched for. This list
+   of nodes is called the path.  This information is used while
+   performing balancing.  Note that this path information may become
+   invalid, and this means we must check it when using it to see if it
+   is still valid. You'll need to read search_by_key and the comments
+   in it, especially about decrement_counters_in_path(), to understand
+   this structure.  
+
+Paths make the code so much harder to work with and debug.... An
+enormous number of bugs are due to them, and trying to write or modify
+code that uses them just makes my head hurt.  They are based on an
+excessive effort to avoid disturbing the precious VFS code.:-( The
+gods only know how we are going to SMP the code that uses them.
+znodes are the way! */
+
+#define PATH_READA     0x1     /* do read ahead */
+#define PATH_READA_BACK 0x2    /* read backwards */
+
+struct path {
+       int path_length;        /* Length of the array above.   */
+       int reada;
+       struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements.  */
+       int pos_in_item;
+};
+
+#define pos_in_item(path) ((path)->pos_in_item)
+
+#define INITIALIZE_PATH(var) \
+struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
+
+/* Get path element by path and path position. */
+#define PATH_OFFSET_PELEMENT(p_s_path,n_offset)  ((p_s_path)->path_elements +(n_offset))
+
+/* Get buffer header at the path by path and path position. */
+#define PATH_OFFSET_PBUFFER(p_s_path,n_offset)   (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_buffer)
+
+/* Get position in the element at the path by path and path position. */
+#define PATH_OFFSET_POSITION(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_position)
+
+#define PATH_PLAST_BUFFER(p_s_path) (PATH_OFFSET_PBUFFER((p_s_path), (p_s_path)->path_length))
+                               /* you know, to the person who didn't
+                                  write this the macro name does not
+                                  at first suggest what it does.
+                                  Maybe POSITION_FROM_PATH_END? Or
+                                  maybe we should just focus on
+                                  dumping paths... -Hans */
+#define PATH_LAST_POSITION(p_s_path) (PATH_OFFSET_POSITION((p_s_path), (p_s_path)->path_length))
+
+#define PATH_PITEM_HEAD(p_s_path)    B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_path),PATH_LAST_POSITION(p_s_path))
+
+/* in do_balance leaf has h == 0 in contrast with path structure,
+   where root has level == 0. That is why we need these defines */
+#define PATH_H_PBUFFER(p_s_path, h) PATH_OFFSET_PBUFFER (p_s_path, p_s_path->path_length - (h))        /* tb->S[h] */
+#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */
+#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h))
+#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1)      /* tb->S[h]->b_item_order */
+
+#define PATH_H_PATH_OFFSET(p_s_path, n_h) ((p_s_path)->path_length - (n_h))
+
+#define get_last_bh(path) PATH_PLAST_BUFFER(path)
+#define get_ih(path) PATH_PITEM_HEAD(path)
+#define get_item_pos(path) PATH_LAST_POSITION(path)
+#define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path)))
+#define item_moved(ih,path) comp_items(ih, path)
+#define path_changed(ih,path) comp_items (ih, path)
+
+/***************************************************************************/
+/*                       MISC                                              */
+/***************************************************************************/
+
+/* Size of pointer to the unformatted node. */
+#define UNFM_P_SIZE (sizeof(unp_t))
+#define UNFM_P_SHIFT 2
+
+// in in-core inode key is stored on le form
+#define INODE_PKEY(inode) ((struct reiserfs_key *)(REISERFS_I(inode)->i_key))
+
+#define MAX_UL_INT 0xffffffff
+#define MAX_INT    0x7ffffff
+#define MAX_US_INT 0xffff
+
+// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
+#define U32_MAX (~(__u32)0)
+
+/*
+static inline loff_t max_reiserfs_offset(struct inode *inode)
+{
+       if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5)
+               return (loff_t) U32_MAX;
+
+       return (loff_t) ((~(__u64) 0) >> 4);
+}
+*/
+
+/*#define MAX_KEY_UNIQUENESS   MAX_UL_INT*/
+#define MAX_KEY_OBJECTID       MAX_UL_INT
+
+#define MAX_B_NUM  MAX_UL_INT
+#define MAX_FC_NUM MAX_US_INT
+
+/* the purpose is to detect overflow of an unsigned short */
+#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
+
+/* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
+#define REISERFS_KERNEL_MEM            0       /* reiserfs kernel memory mode  */
+#define REISERFS_USER_MEM              1       /* reiserfs user memory mode            */
+
+#define fs_generation(s) (REISERFS_SB(s)->s_generation_counter)
+#define get_generation(s) atomic_read (&fs_generation(s))
+#define FILESYSTEM_CHANGED_TB(tb)  (get_generation((tb)->tb_sb) != (tb)->fs_gen)
+#define __fs_changed(gen,s) (gen != get_generation (s))
+#define fs_changed(gen,s) ({cond_resched(); __fs_changed(gen, s);})
+
+/***************************************************************************/
+/*                  FIXATE NODES                                           */
+/***************************************************************************/
+
+#define VI_TYPE_LEFT_MERGEABLE 1
+#define VI_TYPE_RIGHT_MERGEABLE 2
+
+/* To make any changes in the tree we always first find node, that
+   contains item to be changed/deleted or place to insert a new
+   item. We call this node S. To do balancing we need to decide what
+   we will shift to left/right neighbor, or to a new node, where new
+   item will be etc. To make this analysis simpler we build virtual
+   node. Virtual node is an array of items, that will replace items of
+   node S. (For instance if we are going to delete an item, virtual
+   node does not contain it). Virtual node keeps information about
+   item sizes and types, mergeability of first and last items, sizes
+   of all entries in directory item. We use this array of items when
+   calculating what we can shift to neighbors and how many nodes we
+   have to have if we do not any shiftings, if we shift to left/right
+   neighbor or to both. */
+struct virtual_item {
+       int vi_index;           // index in the array of item operations
+       unsigned short vi_type; // left/right mergeability
+       unsigned short vi_item_len;     /* length of item that it will have after balancing */
+       struct item_head *vi_ih;
+       const char *vi_item;    // body of item (old or new)
+       const void *vi_new_data;        // 0 always but paste mode
+       void *vi_uarea;         // item specific area
+};
+
+struct virtual_node {
+       char *vn_free_ptr;      /* this is a pointer to the free space in the buffer */
+       unsigned short vn_nr_item;      /* number of items in virtual node */
+       short vn_size;          /* size of node , that node would have if it has unlimited size and no balancing is performed */
+       short vn_mode;          /* mode of balancing (paste, insert, delete, cut) */
+       short vn_affected_item_num;
+       short vn_pos_in_item;
+       struct item_head *vn_ins_ih;    /* item header of inserted item, 0 for other modes */
+       const void *vn_data;
+       struct virtual_item *vn_vi;     /* array of items (including a new one, excluding item to be deleted) */
+};
+
+/* used by directory items when creating virtual nodes */
+struct direntry_uarea {
+       int flags;
+       __u16 entry_count;
+       __u16 entry_sizes[1];
+} ATTR_PACKED;
+
+/***************************************************************************/
+/*                  TREE BALANCE                                           */
+/***************************************************************************/
+
+/* This temporary structure is used in tree balance algorithms, and
+   constructed as we go to the extent that its various parts are
+   needed.  It contains arrays of nodes that can potentially be
+   involved in the balancing of node S, and parameters that define how
+   each of the nodes must be balanced.  Note that in these algorithms
+   for balancing the worst case is to need to balance the current node
+   S and the left and right neighbors and all of their parents plus
+   create a new node.  We implement S1 balancing for the leaf nodes
+   and S0 balancing for the internal nodes (S1 and S0 are defined in
+   our papers.)*/
+
+#define MAX_FREE_BLOCK 7       /* size of the array of buffers to free at end of do_balance */
+
+/* maximum number of FEB blocknrs on a single level */
+#define MAX_AMOUNT_NEEDED 2
+
+/* someday somebody will prefix every field in this struct with tb_ */
+struct tree_balance {
+       int tb_mode;
+       int need_balance_dirty;
+       struct super_block *tb_sb;
+       struct reiserfs_transaction_handle *transaction_handle;
+       struct path *tb_path;
+       struct buffer_head *L[MAX_HEIGHT];      /* array of left neighbors of nodes in the path */
+       struct buffer_head *R[MAX_HEIGHT];      /* array of right neighbors of nodes in the path */
+       struct buffer_head *FL[MAX_HEIGHT];     /* array of fathers of the left  neighbors      */
+       struct buffer_head *FR[MAX_HEIGHT];     /* array of fathers of the right neighbors      */
+       struct buffer_head *CFL[MAX_HEIGHT];    /* array of common parents of center node and its left neighbor  */
+       struct buffer_head *CFR[MAX_HEIGHT];    /* array of common parents of center node and its right neighbor */
+
+       struct buffer_head *FEB[MAX_FEB_SIZE];  /* array of empty buffers. Number of buffers in array equals
+                                                  cur_blknum. */
+       struct buffer_head *used[MAX_FEB_SIZE];
+       struct buffer_head *thrown[MAX_FEB_SIZE];
+       int lnum[MAX_HEIGHT];   /* array of number of items which must be
+                                  shifted to the left in order to balance the
+                                  current node; for leaves includes item that
+                                  will be partially shifted; for internal
+                                  nodes, it is the number of child pointers
+                                  rather than items. It includes the new item
+                                  being created. The code sometimes subtracts
+                                  one to get the number of wholly shifted
+                                  items for other purposes. */
+       int rnum[MAX_HEIGHT];   /* substitute right for left in comment above */
+       int lkey[MAX_HEIGHT];   /* array indexed by height h mapping the key delimiting L[h] and
+                                  S[h] to its item number within the node CFL[h] */
+       int rkey[MAX_HEIGHT];   /* substitute r for l in comment above */
+       int insert_size[MAX_HEIGHT];    /* the number of bytes by we are trying to add or remove from
+                                          S[h]. A negative value means removing.  */
+       int blknum[MAX_HEIGHT]; /* number of nodes that will replace node S[h] after
+                                  balancing on the level h of the tree.  If 0 then S is
+                                  being deleted, if 1 then S is remaining and no new nodes
+                                  are being created, if 2 or 3 then 1 or 2 new nodes is
+                                  being created */
+
+       /* fields that are used only for balancing leaves of the tree */
+       int cur_blknum;         /* number of empty blocks having been already allocated                 */
+       int s0num;              /* number of items that fall into left most  node when S[0] splits     */
+       int s1num;              /* number of items that fall into first  new node when S[0] splits     */
+       int s2num;              /* number of items that fall into second new node when S[0] splits     */
+       int lbytes;             /* number of bytes which can flow to the left neighbor from the        left    */
+       /* most liquid item that cannot be shifted from S[0] entirely         */
+       /* if -1 then nothing will be partially shifted */
+       int rbytes;             /* number of bytes which will flow to the right neighbor from the right        */
+       /* most liquid item that cannot be shifted from S[0] entirely         */
+       /* if -1 then nothing will be partially shifted                           */
+       int s1bytes;            /* number of bytes which flow to the first  new node when S[0] splits   */
+       /* note: if S[0] splits into 3 nodes, then items do not need to be cut  */
+       int s2bytes;
+       struct buffer_head *buf_to_free[MAX_FREE_BLOCK];        /* buffers which are to be freed after do_balance finishes by unfix_nodes */
+       char *vn_buf;           /* kmalloced memory. Used to create
+                                  virtual node and keep map of
+                                  dirtied bitmap blocks */
+       int vn_buf_size;        /* size of the vn_buf */
+       struct virtual_node *tb_vn;     /* VN starts after bitmap of bitmap blocks */
+
+       int fs_gen;             /* saved value of `reiserfs_generation' counter
+                                  see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+       struct in_core_key key; /* key pointer, to pass to block allocator or
+                                  another low-level subsystem */
+#endif
+};
+
+/* These are modes of balancing */
+
+/* When inserting an item. */
+#define M_INSERT       'i'
+/* When inserting into (directories only) or appending onto an already
+   existant item. */
+#define M_PASTE                'p'
+/* When deleting an item. */
+#define M_DELETE       'd'
+/* When truncating an item or removing an entry from a (directory) item. */
+#define M_CUT          'c'
+
+/* used when balancing on leaf level skipped (in reiserfsck) */
+#define M_INTERNAL     'n'
+
+/* When further balancing is not needed, then do_balance does not need
+   to be called. */
+#define M_SKIP_BALANCING               's'
+#define M_CONVERT      'v'
+
+/* modes of leaf_move_items */
+#define LEAF_FROM_S_TO_L 0
+#define LEAF_FROM_S_TO_R 1
+#define LEAF_FROM_R_TO_L 2
+#define LEAF_FROM_L_TO_R 3
+#define LEAF_FROM_S_TO_SNEW 4
+
+#define FIRST_TO_LAST 0
+#define LAST_TO_FIRST 1
+
+/* used in do_balance for passing parent of node information that has
+   been gotten from tb struct */
+struct buffer_info {
+       struct tree_balance *tb;
+       struct buffer_head *bi_bh;
+       struct buffer_head *bi_parent;
+       int bi_position;
+};
+
+/* there are 4 types of items: stat data, directory item, indirect, direct.
++-------------------+------------+--------------+------------+
+|                  |  k_offset  | k_uniqueness | mergeable? |
++-------------------+------------+--------------+------------+
+|     stat data     |  0        |      0       |   no       |
++-------------------+------------+--------------+------------+
+| 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS|   no       | 
+| non 1st directory | hash value |              |   yes      |
+|     item          |            |              |            |
++-------------------+------------+--------------+------------+
+| indirect item     | offset + 1 |TYPE_INDIRECT |   if this is not the first indirect item of the object
++-------------------+------------+--------------+------------+
+| direct item       | offset + 1 |TYPE_DIRECT   | if not this is not the first direct item of the object
++-------------------+------------+--------------+------------+
+*/
+
+struct item_operations {
+       int (*bytes_number) (struct item_head * ih, int block_size);
+       void (*decrement_key) (struct cpu_key *);
+       int (*is_left_mergeable) (struct reiserfs_key * ih,
+                                 unsigned long bsize);
+       void (*print_item) (struct item_head *, char *item);
+       void (*check_item) (struct item_head *, char *item);
+
+       int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi,
+                         int is_affected, int insert_size);
+       int (*check_left) (struct virtual_item * vi, int free,
+                          int start_skip, int end_skip);
+       int (*check_right) (struct virtual_item * vi, int free);
+       int (*part_size) (struct virtual_item * vi, int from, int to);
+       int (*unit_num) (struct virtual_item * vi);
+       void (*print_vi) (struct virtual_item * vi);
+};
+
+extern struct item_operations *item_ops[TYPE_ANY + 1];
+
+#define op_bytes_number(ih,bsize)                    item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize)
+#define op_is_left_mergeable(key,bsize)              item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize)
+#define op_print_item(ih,item)                       item_ops[le_ih_k_type (ih)]->print_item (ih, item)
+#define op_check_item(ih,item)                       item_ops[le_ih_k_type (ih)]->check_item (ih, item)
+#define op_create_vi(vn,vi,is_affected,insert_size)  item_ops[le_ih_k_type ((vi)->vi_ih)]->create_vi (vn,vi,is_affected,insert_size)
+#define op_check_left(vi,free,start_skip,end_skip) item_ops[(vi)->vi_index]->check_left (vi, free, start_skip, end_skip)
+#define op_check_right(vi,free)                      item_ops[(vi)->vi_index]->check_right (vi, free)
+#define op_part_size(vi,from,to)                     item_ops[(vi)->vi_index]->part_size (vi, from, to)
+#define op_unit_num(vi)                                     item_ops[(vi)->vi_index]->unit_num (vi)
+#define op_print_vi(vi)                              item_ops[(vi)->vi_index]->print_vi (vi)
+
+#define COMP_SHORT_KEYS comp_short_keys
+
+/* number of blocks pointed to by the indirect item */
+#define I_UNFM_NUM(p_s_ih)     ( ih_item_len(p_s_ih) / UNFM_P_SIZE )
+
+/* the used space within the unformatted node corresponding to pos within the item pointed to by ih */
+#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size))
+
+/* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */
+
+/* get the item header */
+#define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) )
+
+/* get key */
+#define B_N_PDELIM_KEY(bh,item_num) ( (struct reiserfs_key * )((bh)->b_data + BLKH_SIZE) + (item_num) )
+
+/* get the key */
+#define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) )
+
+/* get item body */
+#define B_N_PITEM(bh,item_num) ( (bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(item_num))))
+
+/* get the stat data by the buffer header and the item order */
+#define B_N_STAT_DATA(bh,nr) \
+( (struct stat_data *)((bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(nr))) ) )
+
+    /* following defines use reiserfs buffer header and item header */
+
+/* get stat-data */
+#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + ih_location(ih)) )
+
+// this is 3976 for size==4096
+#define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE)
+
+/* indirect items consist of entries which contain blocknrs, pos
+   indicates which entry, and B_I_POS_UNFM_POINTER resolves to the
+   blocknr contained by the entry pos points to */
+#define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)))
+#define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0)
+
+struct reiserfs_iget_args {
+       __u32 objectid;
+       __u32 dirid;
+};
+
+/***************************************************************************/
+/*                    FUNCTION DECLARATIONS                                */
+/***************************************************************************/
+
+/*#ifdef __KERNEL__*/
+#define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12)
+
+#define journal_trans_half(blocksize) \
+       ((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32))
+
+/* journal.c see journal.c for all the comments here */
+
+/* first block written in a commit.  */
+struct reiserfs_journal_desc {
+       __le32 j_trans_id;      /* id of commit */
+       __le32 j_len;           /* length of commit. len +1 is the commit block */
+       __le32 j_mount_id;      /* mount id of this trans */
+       __le32 j_realblock[1];  /* real locations for each block */
+};
+
+#define get_desc_trans_id(d)   le32_to_cpu((d)->j_trans_id)
+#define get_desc_trans_len(d)  le32_to_cpu((d)->j_len)
+#define get_desc_mount_id(d)   le32_to_cpu((d)->j_mount_id)
+
+#define set_desc_trans_id(d,val)       do { (d)->j_trans_id = cpu_to_le32 (val); } while (0)
+#define set_desc_trans_len(d,val)      do { (d)->j_len = cpu_to_le32 (val); } while (0)
+#define set_desc_mount_id(d,val)       do { (d)->j_mount_id = cpu_to_le32 (val); } while (0)
+
+/* last block written in a commit */
+struct reiserfs_journal_commit {
+       __le32 j_trans_id;      /* must match j_trans_id from the desc block */
+       __le32 j_len;           /* ditto */
+       __le32 j_realblock[1];  /* real locations for each block */
+};
+
+#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id)
+#define get_commit_trans_len(c)        le32_to_cpu((c)->j_len)
+#define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id)
+
+#define set_commit_trans_id(c,val)     do { (c)->j_trans_id = cpu_to_le32 (val); } while (0)
+#define set_commit_trans_len(c,val)    do { (c)->j_len = cpu_to_le32 (val); } while (0)
+
+/* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the
+** last fully flushed transaction.  fully flushed means all the log blocks and all the real blocks are on disk,
+** and this transaction does not need to be replayed.
+*/
+struct reiserfs_journal_header {
+       __le32 j_last_flush_trans_id;   /* id of last fully flushed transaction */
+       __le32 j_first_unflushed_offset;        /* offset in the log of where to start replay after a crash */
+       __le32 j_mount_id;
+       /* 12 */ struct journal_params jh_journal;
+};
+
+/* biggest tunable defines are right here */
+#define JOURNAL_BLOCK_COUNT 8192       /* number of blocks in the journal */
+#define JOURNAL_TRANS_MAX_DEFAULT 1024 /* biggest possible single transaction, don't change for now (8/3/99) */
+#define JOURNAL_TRANS_MIN_DEFAULT 256
+#define JOURNAL_MAX_BATCH_DEFAULT   900        /* max blocks to batch into one transaction, don't make this any bigger than 900 */
+#define JOURNAL_MIN_RATIO 2
+#define JOURNAL_MAX_COMMIT_AGE 30
+#define JOURNAL_MAX_TRANS_AGE 30
+#define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9)
+#ifdef CONFIG_QUOTA
+/* We need to update data and inode (atime) */
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? 2 : 0)
+/* 1 balancing, 1 bitmap, 1 data per write + stat data update */
+#define REISERFS_QUOTA_INIT_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? \
+(DQUOT_INIT_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_INIT_REWRITE+1) : 0)
+/* same as with INIT */
+#define REISERFS_QUOTA_DEL_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? \
+(DQUOT_DEL_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_DEL_REWRITE+1) : 0)
+#else
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) 0
+#define REISERFS_QUOTA_INIT_BLOCKS(s) 0
+#define REISERFS_QUOTA_DEL_BLOCKS(s) 0
+#endif
+
+/* both of these can be as low as 1, or as high as you want.  The min is the
+** number of 4k bitmap nodes preallocated on mount. New nodes are allocated
+** as needed, and released when transactions are committed.  On release, if 
+** the current number of nodes is > max, the node is freed, otherwise, 
+** it is put on a free list for faster use later.
+*/
+#define REISERFS_MIN_BITMAP_NODES 10
+#define REISERFS_MAX_BITMAP_NODES 100
+
+#define JBH_HASH_SHIFT 13      /* these are based on journal hash size of 8192 */
+#define JBH_HASH_MASK 8191
+
+#define _jhashfn(sb,block)     \
+       (((unsigned long)sb>>L1_CACHE_SHIFT) ^ \
+        (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12))))
+#define journal_hash(t,sb,block) ((t)[_jhashfn((sb),(block)) & JBH_HASH_MASK])
+
+// We need these to make journal.c code more readable
+#define journal_find_get_block(s, block) __find_get_block(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+#define journal_getblk(s, block) __getblk(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+#define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+
+//enum reiserfs_bh_state_bits {
+//     BH_JDirty = BH_PrivateStart,    /* buffer is in current transaction */
+//     BH_JDirty_wait,
+//     BH_JNew,                /* disk block was taken off free list before
+//                              * being in a finished transaction, or
+//                              * written to disk. Can be reused immed. */
+//     BH_JPrepared,
+//     BH_JRestore_dirty,
+//     BH_JTest,               // debugging only will go away
+//};
+
+/*
+BUFFER_FNS(JDirty, journaled);
+TAS_BUFFER_FNS(JDirty, journaled);
+BUFFER_FNS(JDirty_wait, journal_dirty);
+TAS_BUFFER_FNS(JDirty_wait, journal_dirty);
+BUFFER_FNS(JNew, journal_new);
+TAS_BUFFER_FNS(JNew, journal_new);
+BUFFER_FNS(JPrepared, journal_prepared);
+TAS_BUFFER_FNS(JPrepared, journal_prepared);
+BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
+TAS_BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
+BUFFER_FNS(JTest, journal_test);
+TAS_BUFFER_FNS(JTest, journal_test);
+*/
+
+/*
+** transaction handle which is passed around for all journal calls
+*/
+struct reiserfs_transaction_handle {
+       struct super_block *t_super;    /* super for this FS when journal_begin was
+                                          called. saves calls to reiserfs_get_super
+                                          also used by nested transactions to make
+                                          sure they are nesting on the right FS
+                                          _must_ be first in the handle
+                                        */
+       int t_refcount;
+       int t_blocks_logged;    /* number of blocks this writer has logged */
+       int t_blocks_allocated; /* number of blocks this writer allocated */
+       unsigned long t_trans_id;       /* sanity check, equals the current trans id */
+       void *t_handle_save;    /* save existing current->journal_info */
+       unsigned displace_new_blocks:1; /* if new block allocation occurres, that block
+                                          should be displaced from others */
+       //struct list_head t_list;
+};
+
+/* used to keep track of ordered and tail writes, attached to the buffer
+ * head through b_journal_head.
+ */
+struct reiserfs_jh {
+       struct reiserfs_journal_list *jl;
+       struct buffer_head *bh;
+       //struct list_head list;
+};
+
+//
+// get key version from on disk key - kludge
+//
+/*
+static inline int le_key_version(const struct reiserfs_key *key)
+{
+       int type;
+
+       type = offset_v2_k_type(&(key->u.k_offset_v2));
+       if (type != TYPE_DIRECT && type != TYPE_INDIRECT
+           && type != TYPE_DIRENTRY)
+               return KEY_FORMAT_3_5;
+
+       return KEY_FORMAT_3_6;
+
+}
+
+static inline void copy_key(struct reiserfs_key *to,
+                           const struct reiserfs_key *from)
+{
+       memcpy(to, from, KEY_SIZE);
+}
+*/
+
+#define i_block_size(inode) ((inode)->i_sb->s_blocksize)
+#define file_size(inode) ((inode)->i_size)
+#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1))
+
+#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\
+!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 )
+
+/* inode.c */
+/* args for the create parameter of reiserfs_get_block */
+#define GET_BLOCK_NO_CREATE 0  /* don't create new blocks or convert tails */
+#define GET_BLOCK_CREATE 1     /* add anything you need to find block */
+#define GET_BLOCK_NO_HOLE 2    /* return -ENOENT for file holes */
+#define GET_BLOCK_READ_DIRECT 4        /* read the tail if indirect item not found */
+#define GET_BLOCK_NO_IMUX     8        /* i_mutex is not held, don't preallocate */
+#define GET_BLOCK_NO_DANGLE   16       /* don't leave any transactions running */
+
+/* bitmap.c */
+
+/* structure contains hints for block allocator, and it is a container for
+ * arguments, such as node, search path, transaction_handle, etc. */
+struct __reiserfs_blocknr_hint {
+       struct inode *inode;    /* inode passed to allocator, if we allocate unf. nodes */
+       long block;             /* file offset, in blocks */
+       struct in_core_key key;
+       struct path *path;      /* search path, used by allocator to deternine search_start by
+                                * various ways */
+       struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and
+                                                * bitmap blocks changes  */
+       b_blocknr_t beg, end;
+       b_blocknr_t search_start;       /* a field used to transfer search start value (block number)
+                                        * between different block allocator procedures
+                                        * (determine_search_start() and others) */
+       int prealloc_size;      /* is set in determine_prealloc_size() function, used by underlayed
+                                * function that do actual allocation */
+
+       unsigned formatted_node:1;      /* the allocator uses different polices for getting disk space for
+                                        * formatted/unformatted blocks with/without preallocation */
+       unsigned preallocate:1;
+};
+
+typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
+
+/* hashes.c */
+__u32 keyed_hash(const signed char *msg, int len);
+__u32 yura_hash(const signed char *msg, int len);
+__u32 r5_hash(const signed char *msg, int len);
+
+/* the ext2 bit routines adjust for big or little endian as
+** appropriate for the arch, so in our laziness we use them rather
+** than using the bit routines they call more directly.  These
+** routines must be used when changing on disk bitmaps.  */
+#define reiserfs_test_and_set_le_bit   ext2_set_bit
+#define reiserfs_test_and_clear_le_bit ext2_clear_bit
+#define reiserfs_test_le_bit           ext2_test_bit
+#define reiserfs_find_next_zero_le_bit ext2_find_next_zero_bit
+
+/* sometimes reiserfs_truncate may require to allocate few new blocks
+   to perform indirect2direct conversion. People probably used to
+   think, that truncate should work without problems on a filesystem
+   without free disk space. They may complain that they can not
+   truncate due to lack of free disk space. This spare space allows us
+   to not worry about it. 500 is probably too much, but it should be
+   absolutely safe */
+#define SPARE_SPACE 500
+
+/* ioctl's command */
+#define REISERFS_IOC_UNPACK            _IOW(0xCD,1,long)
+/* define following flags to be the same as in ext2, so that chattr(1),
+   lsattr(1) will work with us. */
+#define REISERFS_IOC_GETFLAGS          EXT2_IOC_GETFLAGS
+#define REISERFS_IOC_SETFLAGS          EXT2_IOC_SETFLAGS
+#define REISERFS_IOC_GETVERSION                EXT2_IOC_GETVERSION
+#define REISERFS_IOC_SETVERSION                EXT2_IOC_SETVERSION
+
+
+
+#pragma pack()
+
+
+#endif
diff --git a/filesystems/fsw_strfunc.h b/filesystems/fsw_strfunc.h
new file mode 100644 (file)
index 0000000..61cf25d
--- /dev/null
@@ -0,0 +1,472 @@
+/* $Id: fsw_strfunc.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_strfunc.h
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* fsw_strfunc.h generated by mk_fsw_strfunc.py */
+
+static int fsw_streq_ISO88591_UTF8(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u8 *p2 = (fsw_u8 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        c2 = *p2++;
+        if ((c2 & 0xe0) == 0xc0) {
+            c2 = ((c2 & 0x1f) << 6) | (*p2++ & 0x3f);
+        } else if ((c2 & 0xf0) == 0xe0) {
+            c2 = ((c2 & 0x0f) << 12) | ((*p2++ & 0x3f) << 6);
+            c2 |= (*p2++ & 0x3f);
+        } else if ((c2 & 0xf8) == 0xf0) {
+            c2 = ((c2 & 0x07) << 18) | ((*p2++ & 0x3f) << 12);
+            c2 |= ((*p2++ & 0x3f) << 6);
+            c2 |= (*p2++ & 0x3f);
+        }
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+#ifndef HOST_EFI
+static int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        c2 = *p2++;
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+#endif
+
+static int fsw_streq_ISO88591_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static int fsw_streq_UTF8_UTF16(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        if ((c1 & 0xe0) == 0xc0) {
+            c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f);
+        } else if ((c1 & 0xf0) == 0xe0) {
+            c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6);
+            c1 |= (*p1++ & 0x3f);
+        } else if ((c1 & 0xf8) == 0xf0) {
+            c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12);
+            c1 |= ((*p1++ & 0x3f) << 6);
+            c1 |= (*p1++ & 0x3f);
+        }
+        c2 = *p2++;
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static int fsw_streq_UTF8_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u8 *p1 = (fsw_u8 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        if ((c1 & 0xe0) == 0xc0) {
+            c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f);
+        } else if ((c1 & 0xf0) == 0xe0) {
+            c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6);
+            c1 |= (*p1++ & 0x3f);
+        } else if ((c1 & 0xf8) == 0xf0) {
+            c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12);
+            c1 |= ((*p1++ & 0x3f) << 6);
+            c1 |= (*p1++ & 0x3f);
+        }
+        c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static int fsw_streq_UTF16_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+    int i;
+    fsw_u16 *p1 = (fsw_u16 *)s1data;
+    fsw_u16 *p2 = (fsw_u16 *)s2data;
+    fsw_u32 c1, c2;
+    
+    for (i = 0; i < len; i++) {
+        c1 = *p1++;
+        c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+        if (c1 != c2)
+            return 0;
+    }
+    return 1;
+}
+
+static fsw_status_t fsw_strcoerce_UTF8_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u8       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_ISO88591;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u8);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u8 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        if ((c & 0xe0) == 0xc0) {
+            c = ((c & 0x1f) << 6) | (*sp++ & 0x3f);
+        } else if ((c & 0xf0) == 0xe0) {
+            c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6);
+            c |= (*sp++ & 0x3f);
+        } else if ((c & 0xf8) == 0xf0) {
+            c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12);
+            c |= ((*sp++ & 0x3f) << 6);
+            c |= (*sp++ & 0x3f);
+        }
+        *dp++ = (fsw_u8)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u16       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_ISO88591;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u8);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        *dp++ = (fsw_u8)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u16       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_ISO88591;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u8);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++; c = FSW_SWAPVALUE_U16(c);
+        *dp++ = (fsw_u8)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_ISO88591_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u8       *sp;
+    fsw_u16       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_UTF16;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u16);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u8 *)srcdata;
+    dp = (fsw_u16 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        *dp++ = (fsw_u16)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF8_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u8       *sp;
+    fsw_u16       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_UTF16;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u16);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u8 *)srcdata;
+    dp = (fsw_u16 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        if ((c & 0xe0) == 0xc0) {
+            c = ((c & 0x1f) << 6) | (*sp++ & 0x3f);
+        } else if ((c & 0xf0) == 0xe0) {
+            c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6);
+            c |= (*sp++ & 0x3f);
+        } else if ((c & 0xf8) == 0xf0) {
+            c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12);
+            c |= ((*sp++ & 0x3f) << 6);
+            c |= (*sp++ & 0x3f);
+        }
+        *dp++ = (fsw_u16)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i;
+    fsw_u16       *sp;
+    fsw_u16       *dp;
+    fsw_u32         c;
+    
+    dest->type = FSW_STRING_TYPE_UTF16;
+    dest->len  = srclen;
+    dest->size = srclen * sizeof(fsw_u16);
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u16 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++; c = FSW_SWAPVALUE_U16(c);
+        *dp++ = (fsw_u16)c;
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_ISO88591_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i, destsize;
+    fsw_u8       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    sp = (fsw_u8 *)srcdata;
+    destsize = 0;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        
+        if (c < 0x000080)
+            destsize++;
+        else if (c < 0x000800)
+            destsize += 2;
+        else if (c < 0x010000)
+            destsize += 3;
+        else
+            destsize += 4;
+    }
+    
+    dest->type = FSW_STRING_TYPE_UTF8;
+    dest->len  = srclen;
+    dest->size = destsize;
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u8 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        
+        if (c < 0x000080) {
+            *dp++ = (fsw_u8)c;
+        } else if (c < 0x000800) {
+            *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else if (c < 0x010000) {
+            *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else {
+            *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        }
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i, destsize;
+    fsw_u16       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    sp = (fsw_u16 *)srcdata;
+    destsize = 0;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        
+        if (c < 0x000080)
+            destsize++;
+        else if (c < 0x000800)
+            destsize += 2;
+        else if (c < 0x010000)
+            destsize += 3;
+        else
+            destsize += 4;
+    }
+    
+    dest->type = FSW_STRING_TYPE_UTF8;
+    dest->len  = srclen;
+    dest->size = destsize;
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++;
+        
+        if (c < 0x000080) {
+            *dp++ = (fsw_u8)c;
+        } else if (c < 0x000800) {
+            *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else if (c < 0x010000) {
+            *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else {
+            *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        }
+    }
+    return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+    fsw_status_t    status;
+    int             i, destsize;
+    fsw_u16       *sp;
+    fsw_u8       *dp;
+    fsw_u32         c;
+    
+    sp = (fsw_u16 *)srcdata;
+    destsize = 0;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++; c = FSW_SWAPVALUE_U16(c);
+        
+        if (c < 0x000080)
+            destsize++;
+        else if (c < 0x000800)
+            destsize += 2;
+        else if (c < 0x010000)
+            destsize += 3;
+        else
+            destsize += 4;
+    }
+    
+    dest->type = FSW_STRING_TYPE_UTF8;
+    dest->len  = srclen;
+    dest->size = destsize;
+    status = fsw_alloc(dest->size, &dest->data);
+    if (status)
+        return status;
+    
+    sp = (fsw_u16 *)srcdata;
+    dp = (fsw_u8 *)dest->data;
+    for (i = 0; i < srclen; i++) {
+        c = *sp++; c = FSW_SWAPVALUE_U16(c);
+        
+        if (c < 0x000080) {
+            *dp++ = (fsw_u8)c;
+        } else if (c < 0x000800) {
+            *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else if (c < 0x010000) {
+            *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        } else {
+            *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+            *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+        }
+    }
+    return FSW_SUCCESS;
+}
diff --git a/filesystems/hfs_format.h b/filesystems/hfs_format.h
new file mode 100644 (file)
index 0000000..9b800e9
--- /dev/null
@@ -0,0 +1,811 @@
+/* $Id: hfs_format.h 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * hfs_format.h
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+ * This code is based on:
+ *
+ * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+#ifndef __HFS_FORMAT__
+#define __HFS_FORMAT__
+
+#if !defined(VBOX) && !defined(HOST_POSIX)
+#include <sys/types.h>
+#include <sys/appleapiopts.h>
+#endif
+
+#ifdef _MSC_VER
+# pragma pack(push,2)
+# define HFS_ALIGNMENT
+#else
+#define HFS_ALIGNMENT __attribute__((aligned(2), packed))
+#endif
+
+/*
+ * hfs_format.c
+ *
+ * This file describes the on-disk format for HFS and HFS Plus volumes.
+ * The HFS Plus volume format is described in detail in Apple Technote 1150.
+ *
+ * http://developer.apple.com/technotes/tn/tn1150.html
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* some on-disk hfs structures have 68K alignment (misaligned) */
+
+/* Signatures used to differentiate between HFS and HFS Plus volumes */
+enum {
+       kHFSSigWord             = 0x4244,       /* 'BD' in ASCII */
+       kHFSPlusSigWord         = 0x482B,       /* 'H+' in ASCII */
+       kHFSXSigWord            = 0x4858,       /* 'HX' in ASCII */
+
+       kHFSPlusVersion         = 0x0004,       /* 'H+' volumes are version 4 only */
+       kHFSXVersion            = 0x0005,       /* 'HX' volumes start with version 5 */
+
+       kHFSPlusMountVersion    = 0x31302E30,   /* '10.0' for Mac OS X */
+       kHFSJMountVersion       = 0x4846534a,   /* 'HFSJ' for journaled HFS+ on OS X */
+       kFSKMountVersion        = 0x46534b21    /* 'FSK!' for failed journal replay */
+};
+
+
+#ifdef __APPLE_API_PRIVATE
+/*
+ * Mac OS X has two special directories on HFS+ volumes for hardlinked files
+ * and hardlinked directories as well as for open-unlinked files.
+ *
+ * These directories and their contents are not exported from the filesystem
+ * under Mac OS X.
+ */
+#define HFSPLUSMETADATAFOLDER       "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data"
+#define HFSPLUS_DIR_METADATA_FOLDER ".HFS+ Private Directory Data\xd"
+
+/*
+ * Files in the "HFS+ Private Data" folder have one of the following prefixes
+ * followed by a decimal number (no leading zeros) for the file ID.
+ *
+ * Note: Earlier version of Mac OS X used a 32 bit random number for the link
+ * ref number instead of the file id.
+ *
+ * e.g.  iNode7182000 and temp3296
+ */
+#define HFS_INODE_PREFIX       "iNode"
+#define HFS_DELETE_PREFIX      "temp"
+
+/*
+ * Files in the ".HFS+ Private Directory Data" folder have the following
+ * prefix followed by a decimal number (no leading zeros) for the file ID.
+ *
+ * e.g. dir_555
+ */
+#define HFS_DIRINODE_PREFIX    "dir_"
+
+/*
+ * Hardlink inodes save the head of the link chain in
+ * an extended attribute named FIRST_LINK_XATTR_NAME.
+ * The attribute data is the decimal value in ASCII
+ * of the cnid for the first link in the chain.
+ *
+ * This extended attribute is private (i.e. its not
+ * exported in the getxattr/listxattr POSIX APIs).
+ */
+#define FIRST_LINK_XATTR_NAME  "com.apple.system.hfs.firstlink"
+#define FIRST_LINK_XATTR_REC_SIZE (sizeof(HFSPlusAttrData) - 2 + 12)
+
+#endif /* __APPLE_API_PRIVATE */
+
+/*
+ * Indirect link files (hard links) have the following type/creator.
+ */
+enum {
+       kHardLinkFileType = 0x686C6E6B,  /* 'hlnk' */
+       kHFSPlusCreator   = 0x6866732B   /* 'hfs+' */
+};
+
+
+/*
+ *     File type and creator for symbolic links
+ */
+enum {
+      kSymLinkFileType  = 0x736C6E6B, /* 'slnk' */
+      kSymLinkCreator   = 0x72686170  /* 'rhap' */
+};
+
+
+#ifndef _HFSUNISTR255_DEFINED_
+#define _HFSUNISTR255_DEFINED_
+/* Unicode strings are used for HFS Plus file and folder names */
+struct HFSUniStr255 {
+       u_int16_t       length;         /* number of unicode characters */
+       u_int16_t       unicode[255];   /* unicode characters */
+} HFS_ALIGNMENT;
+typedef struct HFSUniStr255 HFSUniStr255;
+typedef const HFSUniStr255 *ConstHFSUniStr255Param;
+#endif /* _HFSUNISTR255_DEFINED_ */
+
+enum {
+       kHFSMaxVolumeNameChars          = 27,
+       kHFSMaxFileNameChars            = 31,
+       kHFSPlusMaxFileNameChars        = 255
+};
+
+
+/* Extent overflow file data structures */
+
+/* HFS Extent key */
+struct HFSExtentKey {
+       u_int8_t        keyLength;      /* length of key, excluding this field */
+       u_int8_t        forkType;       /* 0 = data fork, FF = resource fork */
+       u_int32_t       fileID;         /* file ID */
+       u_int16_t       startBlock;     /* first file allocation block number in this extent */
+} HFS_ALIGNMENT;
+typedef struct HFSExtentKey HFSExtentKey;
+
+/* HFS Plus Extent key */
+struct HFSPlusExtentKey {
+       u_int16_t       keyLength;              /* length of key, excluding this field */
+       u_int8_t        forkType;               /* 0 = data fork, FF = resource fork */
+       u_int8_t        pad;                    /* make the other fields align on 32-bit boundary */
+       u_int32_t       fileID;                 /* file ID */
+       u_int32_t       startBlock;             /* first file allocation block number in this extent */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusExtentKey HFSPlusExtentKey;
+
+/* Number of extent descriptors per extent record */
+enum {
+       kHFSExtentDensity       = 3,
+       kHFSPlusExtentDensity   = 8
+};
+
+/* HFS extent descriptor */
+struct HFSExtentDescriptor {
+       u_int16_t       startBlock;             /* first allocation block */
+       u_int16_t       blockCount;             /* number of allocation blocks */
+} HFS_ALIGNMENT;
+typedef struct HFSExtentDescriptor HFSExtentDescriptor;
+
+/* HFS Plus extent descriptor */
+struct HFSPlusExtentDescriptor {
+       u_int32_t       startBlock;             /* first allocation block */
+       u_int32_t       blockCount;             /* number of allocation blocks */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusExtentDescriptor HFSPlusExtentDescriptor;
+
+/* HFS extent record */
+typedef HFSExtentDescriptor HFSExtentRecord[3];
+
+/* HFS Plus extent record */
+typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[8];
+
+
+/* Finder information */
+struct FndrFileInfo {
+       u_int32_t       fdType;         /* file type */
+       u_int32_t       fdCreator;      /* file creator */
+       u_int16_t       fdFlags;        /* Finder flags */
+       struct {
+           int16_t     v;              /* file's location */
+           int16_t     h;
+       } fdLocation;
+       int16_t opaque;
+} HFS_ALIGNMENT;
+typedef struct FndrFileInfo FndrFileInfo;
+
+struct FndrDirInfo {
+       struct {                        /* folder's window rectangle */
+           int16_t     top;
+           int16_t     left;
+           int16_t     bottom;
+           int16_t     right;
+       } frRect;
+       unsigned short  frFlags;        /* Finder flags */
+       struct {
+           u_int16_t   v;              /* folder's location */
+           u_int16_t   h;
+       } frLocation;
+       int16_t opaque;
+} HFS_ALIGNMENT;
+typedef struct FndrDirInfo FndrDirInfo;
+
+struct FndrOpaqueInfo {
+       int8_t opaque[16];
+} HFS_ALIGNMENT;
+typedef struct FndrOpaqueInfo FndrOpaqueInfo;
+
+
+/* HFS Plus Fork data info - 80 bytes */
+struct HFSPlusForkData {
+       u_int64_t               logicalSize;    /* fork's logical size in bytes */
+       u_int32_t               clumpSize;      /* fork's clump size in bytes */
+       u_int32_t               totalBlocks;    /* total blocks used by this fork */
+       HFSPlusExtentRecord     extents;        /* initial set of extents */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusForkData HFSPlusForkData;
+
+
+/* Mac OS X has 16 bytes worth of "BSD" info.
+ *
+ * Note:  Mac OS 9 implementations and applications
+ * should preserve, but not change, this information.
+ */
+struct HFSPlusBSDInfo {
+       u_int32_t       ownerID;        /* user-id of owner or hard link chain previous link */
+       u_int32_t       groupID;        /* group-id of owner or hard link chain next link */
+       u_int8_t        adminFlags;     /* super-user changeable flags */
+       u_int8_t        ownerFlags;     /* owner changeable flags */
+       u_int16_t       fileMode;       /* file type and permission bits */
+       union {
+           u_int32_t   iNodeNum;       /* indirect node number (hard links only) */
+           u_int32_t   linkCount;      /* links that refer to this indirect node */
+           u_int32_t   rawDevice;      /* special file device (FBLK and FCHR only) */
+       } special;
+} HFS_ALIGNMENT;
+typedef struct HFSPlusBSDInfo HFSPlusBSDInfo;
+
+/*
+ * Hardlink "links" resolve to an inode
+ * and the actual uid/gid comes from that
+ * inode.
+ *
+ * We repurpose the links's uid/gid fields
+ * for the hardlink link chain. The chain
+ * consists of a doubly linked list of file
+ * ids.
+ */
+
+#define hl_firstLinkID     reserved1         /* Valid only if HasLinkChain flag is set (indirect nodes only) */
+
+#define hl_prevLinkID      bsdInfo.ownerID   /* Valid only if HasLinkChain flag is set */
+#define hl_nextLinkID      bsdInfo.groupID   /* Valid only if HasLinkChain flag is set */
+
+#define hl_linkReference   bsdInfo.special.iNodeNum
+#define hl_linkCount       bsdInfo.special.linkCount
+
+
+/* Catalog file data structures */
+
+enum {
+       kHFSRootParentID                = 1,    /* Parent ID of the root folder */
+       kHFSRootFolderID                = 2,    /* Folder ID of the root folder */
+       kHFSExtentsFileID               = 3,    /* File ID of the extents file */
+       kHFSCatalogFileID               = 4,    /* File ID of the catalog file */
+       kHFSBadBlockFileID              = 5,    /* File ID of the bad allocation block file */
+       kHFSAllocationFileID            = 6,    /* File ID of the allocation file (HFS Plus only) */
+       kHFSStartupFileID               = 7,    /* File ID of the startup file (HFS Plus only) */
+       kHFSAttributesFileID            = 8,    /* File ID of the attribute file (HFS Plus only) */
+       kHFSAttributeDataFileID         = 13,   /* Used in Mac OS X runtime for extent based attributes */
+                                               /* kHFSAttributeDataFileID is never stored on disk. */
+       kHFSRepairCatalogFileID         = 14,   /* Used when rebuilding Catalog B-tree */
+       kHFSBogusExtentFileID           = 15,   /* Used for exchanging extents in extents file */
+       kHFSFirstUserCatalogNodeID      = 16
+};
+
+/* HFS catalog key */
+struct HFSCatalogKey {
+       u_int8_t        keyLength;              /* key length (in bytes) */
+       u_int8_t        reserved;               /* reserved (set to zero) */
+       u_int32_t       parentID;               /* parent folder ID */
+       u_int8_t        nodeName[kHFSMaxFileNameChars + 1]; /* catalog node name */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogKey HFSCatalogKey;
+
+/* HFS Plus catalog key */
+struct HFSPlusCatalogKey {
+       u_int16_t               keyLength;      /* key length (in bytes) */
+       u_int32_t               parentID;       /* parent folder ID */
+       HFSUniStr255            nodeName;       /* catalog node name */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogKey HFSPlusCatalogKey;
+
+/* Catalog record types */
+enum {
+       /* HFS Catalog Records */
+       kHFSFolderRecord                = 0x0100,       /* Folder record */
+       kHFSFileRecord                  = 0x0200,       /* File record */
+       kHFSFolderThreadRecord          = 0x0300,       /* Folder thread record */
+       kHFSFileThreadRecord            = 0x0400,       /* File thread record */
+
+       /* HFS Plus Catalog Records */
+       kHFSPlusFolderRecord            = 1,            /* Folder record */
+       kHFSPlusFileRecord              = 2,            /* File record */
+       kHFSPlusFolderThreadRecord      = 3,            /* Folder thread record */
+       kHFSPlusFileThreadRecord        = 4             /* File thread record */
+};
+
+
+/* Catalog file record flags */
+enum {
+       kHFSFileLockedBit       = 0x0000,       /* file is locked and cannot be written to */
+       kHFSFileLockedMask      = 0x0001,
+
+       kHFSThreadExistsBit     = 0x0001,       /* a file thread record exists for this file */
+       kHFSThreadExistsMask    = 0x0002,
+
+       kHFSHasAttributesBit    = 0x0002,       /* object has extended attributes */
+       kHFSHasAttributesMask   = 0x0004,
+
+       kHFSHasSecurityBit      = 0x0003,       /* object has security data (ACLs) */
+       kHFSHasSecurityMask     = 0x0008,
+
+       kHFSHasFolderCountBit   = 0x0004,       /* only for HFSX, folder maintains a separate sub-folder count */
+       kHFSHasFolderCountMask  = 0x0010,       /* (sum of folder records and directory hard links) */
+
+       kHFSHasLinkChainBit     = 0x0005,       /* has hardlink chain (inode or link) */
+       kHFSHasLinkChainMask    = 0x0020,
+
+       kHFSHasChildLinkBit     = 0x0006,       /* folder has a child that's a dir link */
+       kHFSHasChildLinkMask    = 0x0040
+};
+
+
+/* HFS catalog folder record - 70 bytes */
+struct HFSCatalogFolder {
+       int16_t         recordType;             /* == kHFSFolderRecord */
+       u_int16_t               flags;                  /* folder flags */
+       u_int16_t               valence;                /* folder valence */
+       u_int32_t               folderID;               /* folder ID */
+       u_int32_t               createDate;             /* date and time of creation */
+       u_int32_t               modifyDate;             /* date and time of last modification */
+       u_int32_t               backupDate;             /* date and time of last backup */
+       FndrDirInfo             userInfo;               /* Finder information */
+       FndrOpaqueInfo          finderInfo;             /* additional Finder information */
+       u_int32_t               reserved[4];            /* reserved - initialized as zero */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogFolder HFSCatalogFolder;
+
+/* HFS Plus catalog folder record - 88 bytes */
+struct HFSPlusCatalogFolder {
+       int16_t         recordType;             /* == kHFSPlusFolderRecord */
+       u_int16_t               flags;                  /* file flags */
+       u_int32_t               valence;                /* folder's item count */
+       u_int32_t               folderID;               /* folder ID */
+       u_int32_t               createDate;             /* date and time of creation */
+       u_int32_t               contentModDate;         /* date and time of last content modification */
+       u_int32_t               attributeModDate;       /* date and time of last attribute modification */
+       u_int32_t               accessDate;             /* date and time of last access (MacOS X only) */
+       u_int32_t               backupDate;             /* date and time of last backup */
+       HFSPlusBSDInfo          bsdInfo;                /* permissions (for MacOS X) */
+       FndrDirInfo             userInfo;               /* Finder information */
+       FndrOpaqueInfo          finderInfo;             /* additional Finder information */
+       u_int32_t               textEncoding;           /* hint for name conversions */
+       u_int32_t               folderCount;            /* number of enclosed folders, active when HasFolderCount is set */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogFolder HFSPlusCatalogFolder;
+
+/* HFS catalog file record - 102 bytes */
+struct HFSCatalogFile {
+       int16_t         recordType;             /* == kHFSFileRecord */
+       u_int8_t                flags;                  /* file flags */
+       int8_t                  fileType;               /* file type (unused ?) */
+       FndrFileInfo            userInfo;               /* Finder information */
+       u_int32_t               fileID;                 /* file ID */
+       u_int16_t               dataStartBlock;         /* not used - set to zero */
+       int32_t         dataLogicalSize;        /* logical EOF of data fork */
+       int32_t         dataPhysicalSize;       /* physical EOF of data fork */
+       u_int16_t               rsrcStartBlock;         /* not used - set to zero */
+       int32_t                 rsrcLogicalSize;        /* logical EOF of resource fork */
+       int32_t                 rsrcPhysicalSize;       /* physical EOF of resource fork */
+       u_int32_t               createDate;             /* date and time of creation */
+       u_int32_t               modifyDate;             /* date and time of last modification */
+       u_int32_t               backupDate;             /* date and time of last backup */
+       FndrOpaqueInfo          finderInfo;             /* additional Finder information */
+       u_int16_t               clumpSize;              /* file clump size (not used) */
+       HFSExtentRecord         dataExtents;            /* first data fork extent record */
+       HFSExtentRecord         rsrcExtents;            /* first resource fork extent record */
+       u_int32_t               reserved;               /* reserved - initialized as zero */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogFile HFSCatalogFile;
+
+/* HFS Plus catalog file record - 248 bytes */
+struct HFSPlusCatalogFile {
+       int16_t         recordType;             /* == kHFSPlusFileRecord */
+       u_int16_t               flags;                  /* file flags */
+       u_int32_t               reserved1;              /* reserved - initialized as zero */
+       u_int32_t               fileID;                 /* file ID */
+       u_int32_t               createDate;             /* date and time of creation */
+       u_int32_t               contentModDate;         /* date and time of last content modification */
+       u_int32_t               attributeModDate;       /* date and time of last attribute modification */
+       u_int32_t               accessDate;             /* date and time of last access (MacOS X only) */
+       u_int32_t               backupDate;             /* date and time of last backup */
+       HFSPlusBSDInfo          bsdInfo;                /* permissions (for MacOS X) */
+       FndrFileInfo            userInfo;               /* Finder information */
+       FndrOpaqueInfo          finderInfo;             /* additional Finder information */
+       u_int32_t               textEncoding;           /* hint for name conversions */
+       u_int32_t               reserved2;              /* reserved - initialized as zero */
+
+       /* Note: these start on double long (64 bit) boundary */
+       HFSPlusForkData dataFork;               /* size and block data for data fork */
+       HFSPlusForkData resourceFork;           /* size and block data for resource fork */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogFile HFSPlusCatalogFile;
+
+/* HFS catalog thread record - 46 bytes */
+struct HFSCatalogThread {
+       int16_t recordType;             /* == kHFSFolderThreadRecord or kHFSFileThreadRecord */
+       int32_t reserved[2];            /* reserved - initialized as zero */
+       u_int32_t       parentID;               /* parent ID for this catalog node */
+       u_int8_t        nodeName[kHFSMaxFileNameChars + 1]; /* name of this catalog node */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogThread HFSCatalogThread;
+
+/* HFS Plus catalog thread record -- 264 bytes */
+struct HFSPlusCatalogThread {
+       int16_t recordType;             /* == kHFSPlusFolderThreadRecord or kHFSPlusFileThreadRecord */
+       int16_t reserved;               /* reserved - initialized as zero */
+       u_int32_t       parentID;               /* parent ID for this catalog node */
+       HFSUniStr255    nodeName;               /* name of this catalog node (variable length) */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogThread HFSPlusCatalogThread;
+
+#ifdef __APPLE_API_UNSTABLE
+/*
+       These are the types of records in the attribute B-tree.  The values were
+       chosen so that they wouldn't conflict with the catalog record types.
+*/
+enum {
+       kHFSPlusAttrInlineData  = 0x10,   /* attributes whose data fits in a b-tree node */
+       kHFSPlusAttrForkData    = 0x20,   /* extent based attributes (data lives in extents) */
+       kHFSPlusAttrExtents     = 0x30    /* overflow extents for large attributes */
+};
+
+
+/*
+       HFSPlusAttrForkData
+       For larger attributes, whose value is stored in allocation blocks.
+       If the attribute has more than 8 extents, there will be additional
+       records (of type HFSPlusAttrExtents) for this attribute.
+*/
+struct HFSPlusAttrForkData {
+       u_int32_t       recordType;             /* == kHFSPlusAttrForkData*/
+       u_int32_t       reserved;
+       HFSPlusForkData theFork;                /* size and first extents of value*/
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrForkData HFSPlusAttrForkData;
+
+/*
+       HFSPlusAttrExtents
+       This record contains information about overflow extents for large,
+       fragmented attributes.
+*/
+struct HFSPlusAttrExtents {
+       u_int32_t               recordType;     /* == kHFSPlusAttrExtents*/
+       u_int32_t               reserved;
+       HFSPlusExtentRecord     extents;        /* additional extents*/
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrExtents HFSPlusAttrExtents;
+
+/*
+ * Attributes B-tree Data Record
+ *
+ * For small attributes, whose entire value is stored
+ * within a single B-tree record.
+ */
+struct HFSPlusAttrData {
+       u_int32_t    recordType;   /* == kHFSPlusAttrInlineData */
+       u_int32_t    reserved[2];
+       u_int32_t    attrSize;     /* size of attribute data in bytes */
+       u_int8_t     attrData[2];  /* variable length */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrData HFSPlusAttrData;
+
+
+/* HFSPlusAttrInlineData is obsolete use HFSPlusAttrData instead */
+struct HFSPlusAttrInlineData {
+       u_int32_t       recordType;
+       u_int32_t       reserved;
+       u_int32_t       logicalSize;
+       u_int8_t        userData[2];
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrInlineData HFSPlusAttrInlineData;
+
+
+/*     A generic Attribute Record*/
+union HFSPlusAttrRecord {
+       u_int32_t               recordType;
+       HFSPlusAttrInlineData   inlineData;   /* NOT USED */
+       HFSPlusAttrData attrData;
+       HFSPlusAttrForkData     forkData;
+       HFSPlusAttrExtents      overflowExtents;
+};
+typedef union HFSPlusAttrRecord HFSPlusAttrRecord;
+
+/* Attribute key */
+enum { kHFSMaxAttrNameLen = 127 };
+struct HFSPlusAttrKey {
+       u_int16_t     keyLength;       /* key length (in bytes) */
+       u_int16_t     pad;             /* set to zero */
+       u_int32_t     fileID;          /* file associated with attribute */
+       u_int32_t     startBlock;      /* first allocation block number for extents */
+       u_int16_t     attrNameLen;     /* number of unicode characters */
+       u_int16_t     attrName[kHFSMaxAttrNameLen];   /* attribute name (Unicode) */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrKey HFSPlusAttrKey;
+
+#define kHFSPlusAttrKeyMaximumLength   (sizeof(HFSPlusAttrKey) - sizeof(u_int16_t))
+#define kHFSPlusAttrKeyMinimumLength   (kHFSPlusAttrKeyMaximumLength - kHFSMaxAttrNameLen*sizeof(u_int16_t))
+
+#endif /* __APPLE_API_UNSTABLE */
+
+
+/* Key and node lengths */
+enum {
+       kHFSPlusExtentKeyMaximumLength = sizeof(HFSPlusExtentKey) - sizeof(u_int16_t),
+       kHFSExtentKeyMaximumLength      = sizeof(HFSExtentKey) - sizeof(u_int8_t),
+       kHFSPlusCatalogKeyMaximumLength = sizeof(HFSPlusCatalogKey) - sizeof(u_int16_t),
+       kHFSPlusCatalogKeyMinimumLength = kHFSPlusCatalogKeyMaximumLength - sizeof(HFSUniStr255) + sizeof(u_int16_t),
+       kHFSCatalogKeyMaximumLength     = sizeof(HFSCatalogKey) - sizeof(u_int8_t),
+       kHFSCatalogKeyMinimumLength     = kHFSCatalogKeyMaximumLength - (kHFSMaxFileNameChars + 1) + sizeof(u_int8_t),
+       kHFSPlusCatalogMinNodeSize      = 4096,
+       kHFSPlusExtentMinNodeSize       = 512,
+       kHFSPlusAttrMinNodeSize         = 4096
+};
+
+/* HFS and HFS Plus volume attribute bits */
+enum {
+                                                       /* Bits 0-6 are reserved (always cleared by MountVol call) */
+       kHFSVolumeHardwareLockBit       = 7,            /* volume is locked by hardware */
+       kHFSVolumeUnmountedBit          = 8,            /* volume was successfully unmounted */
+       kHFSVolumeSparedBlocksBit       = 9,            /* volume has bad blocks spared */
+       kHFSVolumeNoCacheRequiredBit = 10,              /* don't cache volume blocks (i.e. RAM or ROM disk) */
+       kHFSBootVolumeInconsistentBit = 11,             /* boot volume is inconsistent (System 7.6 and later) */
+       kHFSCatalogNodeIDsReusedBit = 12,
+       kHFSVolumeJournaledBit = 13,                    /* this volume has a journal on it */
+       kHFSVolumeInconsistentBit = 14,                 /* serious inconsistencies detected at runtime */
+       kHFSVolumeSoftwareLockBit       = 15,           /* volume is locked by software */
+
+       kHFSVolumeHardwareLockMask      = 1 << kHFSVolumeHardwareLockBit,
+       kHFSVolumeUnmountedMask         = 1 << kHFSVolumeUnmountedBit,
+       kHFSVolumeSparedBlocksMask      = 1 << kHFSVolumeSparedBlocksBit,
+       kHFSVolumeNoCacheRequiredMask = 1 << kHFSVolumeNoCacheRequiredBit,
+       kHFSBootVolumeInconsistentMask = 1 << kHFSBootVolumeInconsistentBit,
+       kHFSCatalogNodeIDsReusedMask = 1 << kHFSCatalogNodeIDsReusedBit,
+       kHFSVolumeJournaledMask = 1 << kHFSVolumeJournaledBit,
+       kHFSVolumeInconsistentMask = 1 << kHFSVolumeInconsistentBit,
+       kHFSVolumeSoftwareLockMask      = 1 << kHFSVolumeSoftwareLockBit,
+       kHFSMDBAttributesMask           = 0x8380
+};
+
+/* HFS Master Directory Block - 162 bytes */
+/* Stored at sector #2 (3rd sector) and second-to-last sector. */
+struct HFSMasterDirectoryBlock {
+       u_int16_t               drSigWord;      /* == kHFSSigWord = 0x4244 = 'BD' or 'H+' or 'HX'*/
+       u_int32_t               drCrDate;       /* date and time of volume creation */
+       u_int32_t               drLsMod;        /* date and time of last modification */
+       u_int16_t               drAtrb;         /* volume attributes */
+       u_int16_t               drNmFls;        /* number of files in root folder */
+       u_int16_t               drVBMSt;        /* first block of volume bitmap */
+       u_int16_t               drAllocPtr;     /* start of next allocation search */
+       u_int16_t               drNmAlBlks;     /* number of allocation blocks in volume */
+       u_int32_t               drAlBlkSiz;     /* size (in bytes) of allocation blocks */
+       u_int32_t               drClpSiz;       /* default clump size */
+       u_int16_t               drAlBlSt;       /* first allocation block in volume */
+       u_int32_t               drNxtCNID;      /* next unused catalog node ID */
+       u_int16_t               drFreeBks;      /* number of unused allocation blocks */
+       u_int8_t                drVN[kHFSMaxVolumeNameChars + 1];  /* volume name */
+       u_int32_t               drVolBkUp;      /* date and time of last backup */
+       u_int16_t               drVSeqNum;      /* volume backup sequence number */
+       u_int32_t               drWrCnt;        /* volume write count */
+       u_int32_t               drXTClpSiz;     /* clump size for extents overflow file */
+       u_int32_t               drCTClpSiz;     /* clump size for catalog file */
+       u_int16_t               drNmRtDirs;     /* number of directories in root folder */
+       u_int32_t               drFilCnt;       /* number of files in volume */
+       u_int32_t               drDirCnt;       /* number of directories in volume */
+       u_int32_t               drFndrInfo[8];  /* information used by the Finder */
+       u_int16_t               drEmbedSigWord; /* embedded volume signature (formerly drVCSize) */
+       HFSExtentDescriptor     drEmbedExtent;  /* embedded volume location and size (formerly drVBMCSize and drCtlCSize) */
+       u_int32_t               drXTFlSize;     /* size of extents overflow file */
+       HFSExtentRecord         drXTExtRec;     /* extent record for extents overflow file */
+       u_int32_t               drCTFlSize;     /* size of catalog file */
+       HFSExtentRecord drCTExtRec;     /* extent record for catalog file */
+} HFS_ALIGNMENT;
+typedef struct HFSMasterDirectoryBlock HFSMasterDirectoryBlock;
+
+
+#ifdef __APPLE_API_UNSTABLE
+#define SET_HFS_TEXT_ENCODING(hint)  \
+       (0x656e6300 | ((hint) & 0xff))
+#define GET_HFS_TEXT_ENCODING(hint)  \
+       (((hint) & 0xffffff00) == 0x656e6300 ? (hint) & 0x000000ff : 0xffffffffU)
+#endif /* __APPLE_API_UNSTABLE */
+
+  /*
+   48 2B 00 04 80 00 20 00 48 46 53 4A 00 AD 7E 98  //H+ HFSJ
+   C9 12 D3 9E CB 84 F3 1D 00 00 00 00 C9 26 31 A8
+   00 12 1D 9D 00 03 66 B9 00 00 10 00 01 A1 2C CF
+   00 44 67 DF 01 35 EB A8 00 01 00 00 00 01 00 00
+   10 8B 1C EA 08 E4 9C 1B 00 00 00 00 02 00 00 8B
+   00 00 02 E7 10 3F CB 93 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 02 E7 6A 45 F3 37 EF 97 E9 A6
+   00 00 00 00 00 34 30 00 00 00 00 00 00 00 03 43
+   00 00 00 01 00 00 03 43 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   00 00 00 00 00 70 00 00 00 70 00 00 00 00 07 00
+   00 00 13 45 00 00 07 00 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   00 00 00 00 2A F8 00 00 01 90 00 00 00 02 AF 80
+   00 01 AA 55 00 01 90 00 00 14 5A C7 00 00 19 00
+   00 3D E4 E3 00 00 19 00 00 95 44 F7 00 00 19 00
+   00 9D 3B 18 00 00 32 00 00 E3 58 1C 00 00 19 00
+   00 48 1C 72 00 00 19 00 00 BB 6A 05 00 00 19 00
+   00 00 00 00 06 40 00 00 01 90 00 00 00 00 64 00
+   00 06 80 00 00 00 19 00 00 38 2A 2F 00 00 19 00
+   00 38 DB 2C 00 00 19 00 00 A6 A2 1F 00 00 19 00
+   */  
+  
+
+/* HFS Plus Volume Header - 512 bytes */
+/* Stored at sector #2 (3rd sector) and second-to-last sector. */
+struct HFSPlusVolumeHeader {
+       u_int16_t       signature;              /* == kHFSPlusSigWord */
+       u_int16_t       version;                /* == kHFSPlusVersion */
+       u_int32_t       attributes;             /* volume attributes */
+       u_int32_t       lastMountedVersion;     /* implementation version which last mounted volume */
+       u_int32_t       journalInfoBlock;       /* block addr of journal info (if volume is journaled, zero otherwise) */
+
+       u_int32_t       createDate;             /* date and time of volume creation */
+       u_int32_t       modifyDate;             /* date and time of last modification */
+       u_int32_t       backupDate;             /* date and time of last backup */
+       u_int32_t       checkedDate;            /* date and time of last disk check */
+
+       u_int32_t       fileCount;              /* number of files in volume */
+       u_int32_t       folderCount;            /* number of directories in volume */
+
+       u_int32_t       blockSize;              /* size (in bytes) of allocation blocks */
+       u_int32_t       totalBlocks;            /* number of allocation blocks in volume (includes this header and VBM*/
+       u_int32_t       freeBlocks;             /* number of unused allocation blocks */
+
+       u_int32_t       nextAllocation;         /* start of next allocation search */
+       u_int32_t       rsrcClumpSize;          /* default resource fork clump size */
+       u_int32_t       dataClumpSize;          /* default data fork clump size */
+       u_int32_t       nextCatalogID;          /* next unused catalog node ID */
+
+       u_int32_t       writeCount;             /* volume write count */
+       u_int64_t       encodingsBitmap;        /* which encodings have been use  on this volume */
+
+       u_int8_t        finderInfo[32];         /* information used by the Finder */
+
+       HFSPlusForkData  allocationFile;        /* allocation bitmap file */
+       HFSPlusForkData  extentsFile;           /* extents B-tree file */
+       HFSPlusForkData  catalogFile;           /* catalog B-tree file */
+       HFSPlusForkData  attributesFile;        /* extended attributes B-tree file */
+       HFSPlusForkData  startupFile;           /* boot file (secondary loader) */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusVolumeHeader HFSPlusVolumeHeader;
+
+
+/* B-tree structures */
+
+enum BTreeKeyLimits{
+       kMaxKeyLength   = 520
+};
+
+union BTreeKey{
+       u_int8_t        length8;
+       u_int16_t       length16;
+       u_int8_t        rawData [kMaxKeyLength+2];
+};
+typedef union BTreeKey BTreeKey;
+
+/* BTNodeDescriptor -- Every B-tree node starts with these fields. */
+struct BTNodeDescriptor {
+       u_int32_t       fLink;                  /* next node at this level*/
+       u_int32_t       bLink;                  /* previous node at this level*/
+       int8_t          kind;                   /* kind of node (leaf, index, header, map)*/
+       u_int8_t        height;                 /* zero for header, map; child is one more than parent*/
+       u_int16_t       numRecords;             /* number of records in this node*/
+       u_int16_t       reserved;               /* reserved - initialized as zero */
+} HFS_ALIGNMENT;
+typedef struct BTNodeDescriptor BTNodeDescriptor;
+
+/* Constants for BTNodeDescriptor kind */
+enum {
+       kBTLeafNode     = -1,
+       kBTIndexNode    = 0,
+       kBTHeaderNode   = 1,
+       kBTMapNode      = 2
+};
+
+/* BTHeaderRec -- The first record of a B-tree header node */
+struct BTHeaderRec {
+       u_int16_t       treeDepth;              /* maximum height (usually leaf nodes) */
+       u_int32_t       rootNode;               /* node number of root node */
+       u_int32_t       leafRecords;            /* number of leaf records in all leaf nodes */
+       u_int32_t       firstLeafNode;          /* node number of first leaf node */
+       u_int32_t       lastLeafNode;           /* node number of last leaf node */
+       u_int16_t       nodeSize;               /* size of a node, in bytes */
+       u_int16_t       maxKeyLength;           /* reserved */
+       u_int32_t       totalNodes;             /* total number of nodes in tree */
+       u_int32_t       freeNodes;              /* number of unused (free) nodes in tree */
+       u_int16_t       reserved1;              /* unused */
+       u_int32_t       clumpSize;              /* reserved */
+       u_int8_t        btreeType;              /* reserved */
+       u_int8_t        keyCompareType;         /* Key string Comparison Type */
+       u_int32_t       attributes;             /* persistent attributes about the tree */
+       u_int32_t       reserved3[16];          /* reserved */
+} HFS_ALIGNMENT;
+typedef struct BTHeaderRec BTHeaderRec;
+
+/* Constants for BTHeaderRec attributes */
+enum {
+       kBTBadCloseMask          = 0x00000001,  /* reserved */
+       kBTBigKeysMask           = 0x00000002,  /* key length field is 16 bits */
+       kBTVariableIndexKeysMask = 0x00000004   /* keys in index nodes are variable length */
+};
+
+
+/* Catalog Key Name Comparison Type */
+enum {
+       kHFSCaseFolding   = 0xCF,  /* case folding (case-insensitive) */
+       kHFSBinaryCompare = 0xBC  /* binary compare (case-sensitive) */
+};
+
+/* JournalInfoBlock - Structure that describes where our journal lives */
+struct JournalInfoBlock {
+       u_int32_t       flags;
+       u_int32_t       device_signature[8];  // signature used to locate our device.
+       u_int64_t       offset;               // byte offset to the journal on the device
+       u_int64_t       size;                 // size in bytes of the journal
+       u_int32_t       reserved[32];
+} HFS_ALIGNMENT;
+typedef struct JournalInfoBlock JournalInfoBlock;
+
+enum {
+    kJIJournalInFSMask          = 0x00000001,
+    kJIJournalOnOtherDeviceMask = 0x00000002,
+    kJIJournalNeedInitMask      = 0x00000004
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+#ifdef _MSC_VER
+# pragma pack(pop)
+#endif
+
+#endif /* __HFS_FORMAT__ */
diff --git a/filesystems/test/.svn/all-wcprops b/filesystems/test/.svn/all-wcprops
new file mode 100644 (file)
index 0000000..1c8e48f
--- /dev/null
@@ -0,0 +1,41 @@
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test
+END
+fsw_posix_base.h
+K 25
+svn:wc:ra_dav:version-url
+V 65
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test/fsw_posix_base.h
+END
+fsw_posix.c
+K 25
+svn:wc:ra_dav:version-url
+V 60
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test/fsw_posix.c
+END
+lsroot.c
+K 25
+svn:wc:ra_dav:version-url
+V 57
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test/lsroot.c
+END
+fsw_posix.h
+K 25
+svn:wc:ra_dav:version-url
+V 60
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test/fsw_posix.h
+END
+README
+K 25
+svn:wc:ra_dav:version-url
+V 55
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test/README
+END
+lslr.c
+K 25
+svn:wc:ra_dav:version-url
+V 55
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test/lslr.c
+END
diff --git a/filesystems/test/.svn/entries b/filesystems/test/.svn/entries
new file mode 100644 (file)
index 0000000..f594e04
--- /dev/null
@@ -0,0 +1,232 @@
+10
+
+dir
+432
+https://cloverefiboot.svn.sourceforge.net/svnroot/cloverefiboot/VBoxFsDxe/test
+https://cloverefiboot.svn.sourceforge.net/svnroot/cloverefiboot
+
+
+
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+0f885799-303c-4bf3-9050-968124707f2f
+\f
+fsw_posix_base.h
+file
+
+
+
+
+2012-05-15T01:06:34.000000Z
+17516f05bd8d1ca74803cd8e1bc8b20f
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2920
+\f
+fsw_posix.c
+file
+
+
+
+
+2012-05-15T01:06:34.000000Z
+c847b0b03df254cb7f31e25315063957
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+13763
+\f
+lsroot.c
+file
+
+
+
+
+2012-05-15T01:06:34.000000Z
+55a5a9b6c4ec0b2f6ee39d14ec82b276
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2807
+\f
+fsw_posix.h
+file
+
+
+
+
+2012-05-15T01:06:34.000000Z
+cbfe2e553a18fcb978b5ebfd3a06def1
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3297
+\f
+README
+file
+
+
+
+
+2012-05-15T01:06:34.000000Z
+9fbd16e1fb2413b7e0780f603f26de91
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+134
+\f
+lslr.c
+file
+
+
+
+
+2012-05-15T01:06:34.000000Z
+a26b88236b0a0e7bfbb2adaa5d4836f4
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4059
+\f
diff --git a/filesystems/test/.svn/text-base/README.svn-base b/filesystems/test/.svn/text-base/README.svn-base
new file mode 100644 (file)
index 0000000..c7c34e4
--- /dev/null
@@ -0,0 +1,2 @@
+This folder contains tests for VBoxFsDxe module, allowing up 
+and test filesystems without EFI environment and launching whole VBox. 
diff --git a/filesystems/test/.svn/text-base/fsw_posix.c.svn-base b/filesystems/test/.svn/text-base/fsw_posix.c.svn-base
new file mode 100644 (file)
index 0000000..eee8c5f
--- /dev/null
@@ -0,0 +1,479 @@
+/**
+ * \file fsw_posix.c
+ * POSIX user space host environment code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+#ifndef FSTYPE
+/** The file system type name to use. */
+#define FSTYPE ext2
+#endif
+
+
+// function prototypes
+
+fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type,
+                                struct fsw_shandle *shand);
+
+void fsw_posix_change_blocksize(struct fsw_volume *vol,
+                              fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                              fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+
+/**
+ * Dispatch table for our FSW host driver.
+ */
+
+struct fsw_host_table   fsw_posix_host_table = {
+    FSW_STRING_TYPE_ISO88591,
+
+    fsw_posix_change_blocksize,
+    fsw_posix_read_block
+};
+
+extern struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+
+/**
+ * Mount function.
+ */
+
+struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table)
+{
+    fsw_status_t        status;
+    struct fsw_posix_volume *pvol;
+
+    // allocate volume structure
+    status = fsw_alloc_zero(sizeof(struct fsw_posix_volume), (void **)&pvol);
+    if (status)
+        return NULL;
+    pvol->fd = -1;
+
+    // open underlying file/device
+    pvol->fd = open(path, O_RDONLY, 0);
+    if (pvol->fd < 0) {
+        fprintf(stderr, "fsw_posix_mount: %s: %s\n", path, strerror(errno));
+        fsw_free(pvol);
+        return NULL;
+    }
+
+    // mount the filesystem
+    if (fstype_table == NULL)
+        fstype_table = &FSW_FSTYPE_TABLE_NAME(FSTYPE);
+    status = fsw_mount(pvol, &fsw_posix_host_table, fstype_table, &pvol->vol);
+    if (status) {
+        fprintf(stderr, "fsw_posix_mount: fsw_mount returned %d\n", status);
+        fsw_free(pvol);
+        return NULL;
+    }
+
+    return pvol;
+}
+
+/**
+ * Unmount function.
+ */
+
+int fsw_posix_unmount(struct fsw_posix_volume *pvol)
+{
+    if (pvol->vol != NULL)
+        fsw_unmount(pvol->vol);
+    fsw_free(pvol);
+    return 0;
+}
+
+/**
+ * Open a named regular file.
+ */
+
+struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode)
+{
+    fsw_status_t        status;
+    struct fsw_posix_file *file;
+
+    // TODO: check flags for unwanted values
+
+    // allocate file structure
+    status = fsw_alloc(sizeof(struct fsw_posix_file), &file);
+    if (status)
+        return NULL;
+    file->pvol = pvol;
+
+    // open the file
+    status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_FILE, &file->shand);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open: open_dno returned %d\n", status);
+        fsw_free(file);
+        return NULL;
+    }
+
+    return file;
+}
+
+/**
+ * Read data from a regular file.
+ */
+
+ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes)
+{
+    fsw_status_t        status;
+    fsw_u32             buffer_size;
+
+    buffer_size = nbytes;
+    status = fsw_shandle_read(&file->shand, &buffer_size, buf);
+    if (status)
+        return -1;
+    return buffer_size;
+}
+
+/**
+ * Change position within a regular file.
+ */
+
+off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence)
+{
+    fsw_u64             base_offset = 0;
+
+    // get base offset
+    base_offset = 0;
+    if (whence == SEEK_CUR)
+        base_offset = file->shand.pos;
+    else if (whence == SEEK_END)
+        base_offset = file->shand.dnode->size;
+
+    // calculate new offset, prevent seeks before the start of the file
+    if (offset < 0 && -offset > base_offset)
+        file->shand.pos = 0;
+    else
+        file->shand.pos = base_offset + offset;
+
+    return file->shand.pos;
+}
+
+/**
+ * Close a regular file.
+ */
+
+int fsw_posix_close(struct fsw_posix_file *file)
+{
+    fsw_shandle_close(&file->shand);
+    fsw_free(file);
+    return 0;
+}
+
+/**
+ * Open a directory for iteration.
+ */
+
+struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path)
+{
+    fsw_status_t        status;
+    struct fsw_posix_dir *dir;
+
+    // allocate file structure
+    status = fsw_alloc(sizeof(struct fsw_posix_dir), &dir);
+    if (status)
+        return NULL;
+    dir->pvol = pvol;
+
+    // open the directory
+    status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_DIR, &dir->shand);
+    if (status) {
+        fprintf(stderr, "fsw_posix_opendir: open_dno returned %d\n", status);
+        fsw_free(dir);
+        return NULL;
+    }
+
+    return dir;
+}
+
+/**
+ * Read the next entry from a directory.
+ */
+
+struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir)
+{
+    fsw_status_t        status;
+    struct fsw_dnode    *dno;
+    static struct dirent dent;
+
+    // get next entry from file system
+    status = fsw_dnode_dir_read(&dir->shand, &dno);
+    if (status) {
+        if (status != 4)
+            fprintf(stderr, "fsw_posix_readdir: fsw_dnode_dir_read returned %d\n", status);
+        return NULL;
+    }
+    status = fsw_dnode_fill(dno);
+    if (status) {
+        fprintf(stderr, "fsw_posix_readdir: fsw_dnode_fill returned %d\n", status);
+        fsw_dnode_release(dno);
+        return NULL;
+    }
+
+    // fill dirent structure
+    dent.d_fileno = dno->dnode_id;
+    dent.d_reclen = 8 + dno->name.size + 1;
+    switch (dno->type) {
+        case FSW_DNODE_TYPE_FILE:
+            dent.d_type = DT_REG;
+            break;
+        case FSW_DNODE_TYPE_DIR:
+            dent.d_type = DT_DIR;
+            break;
+        case FSW_DNODE_TYPE_SYMLINK:
+            dent.d_type = DT_LNK;
+            break;
+        default:
+            dent.d_type = DT_UNKNOWN;
+            break;
+    }
+#if 0
+    dent.d_namlen = dno->name.size;
+#endif
+    memcpy(dent.d_name, dno->name.data, dno->name.size);
+    dent.d_name[dno->name.size] = 0;
+
+    return &dent;
+}
+
+/**
+ * Rewind a directory to the start.
+ */
+
+void fsw_posix_rewinddir(struct fsw_posix_dir *dir)
+{
+    dir->shand.pos = 0;
+}
+
+/**
+ * Close a directory.
+ */
+
+int fsw_posix_closedir(struct fsw_posix_dir *dir)
+{
+    fsw_shandle_close(&dir->shand);
+    fsw_free(dir);
+    return 0;
+}
+
+/**
+ * Open a shand of a required type by path.
+ */
+
+fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type, struct fsw_shandle *shand)
+{
+    fsw_status_t        status;
+    struct fsw_dnode    *dno;
+    struct fsw_dnode    *target_dno;
+    struct fsw_string   lookup_path;
+
+    lookup_path.type = FSW_STRING_TYPE_ISO88591;
+    lookup_path.len  = strlen(path);
+    lookup_path.size = lookup_path.len;
+    lookup_path.data = (void *)path;
+
+    // resolve the path (symlinks along the way are automatically resolved)
+    status = fsw_dnode_lookup_path(pvol->vol->root, &lookup_path, '/', &dno);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_lookup_path returned %d\n", status);
+        return status;
+    }
+
+    // if the final node is a symlink, also resolve it
+    status = fsw_dnode_resolve(dno, &target_dno);
+    fsw_dnode_release(dno);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_resolve returned %d\n", status);
+        return status;
+    }
+    dno = target_dno;
+
+    // check that it is a regular file
+    status = fsw_dnode_fill(dno);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_fill returned %d\n", status);
+        fsw_dnode_release(dno);
+        return status;
+    }
+    if (dno->type != required_type) {
+        fprintf(stderr, "fsw_posix_open_dno: dnode is not of the requested type\n");
+        fsw_dnode_release(dno);
+        return FSW_UNSUPPORTED;
+    }
+
+    // open shandle
+    status = fsw_shandle_open(dno, shand);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open_dno: fsw_shandle_open returned %d\n", status);
+    }
+    fsw_dnode_release(dno);
+    return status;
+}
+
+/**
+ * FSW interface function for block size changes. This function is called by the FSW core
+ * when the file system driver changes the block sizes for the volume.
+ */
+
+void fsw_posix_change_blocksize(struct fsw_volume *vol,
+                                fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                                fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
+{
+    // nothing to do
+}
+
+/**
+ * FSW interface function to read data blocks. This function is called by the FSW core
+ * to read a block of data from the device. The buffer is allocated by the core code.
+ */
+
+fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer)
+{
+    struct fsw_posix_volume *pvol = (struct fsw_posix_volume *)vol->host_data;
+    off_t           block_offset, seek_result;
+    ssize_t         read_result;
+
+    FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_posix_read_block: %d  (%d)\n"), phys_bno, vol->phys_blocksize));
+
+    // read from disk
+    block_offset = (off_t)phys_bno * vol->phys_blocksize;
+    seek_result = lseek(pvol->fd, block_offset, SEEK_SET);
+    if (seek_result != block_offset)
+        return FSW_IO_ERROR;
+    read_result = read(pvol->fd, buffer, vol->phys_blocksize);
+    if (read_result != vol->phys_blocksize)
+        return FSW_IO_ERROR;
+
+    return FSW_SUCCESS;
+}
+
+
+/**
+ * Time mapping callback for the fsw_dnode_stat call. This function converts
+ * a Posix style timestamp into an EFI_TIME structure and writes it to the
+ * appropriate member of the EFI_FILE_INFO structure that we're filling.
+ */
+
+/*
+static void fsw_posix_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    if (which == FSW_DNODE_STAT_CTIME)
+        fsw_posix_decode_time(&FileInfo->CreateTime,       posix_time);
+    else if (which == FSW_DNODE_STAT_MTIME)
+        fsw_posix_decode_time(&FileInfo->ModificationTime, posix_time);
+    else if (which == FSW_DNODE_STAT_ATIME)
+        fsw_posix_decode_time(&FileInfo->LastAccessTime,   posix_time);
+}
+*/
+
+/**
+ * Mode mapping callback for the fsw_dnode_stat call. This function looks at
+ * the Posix mode passed by the file system driver and makes appropriate
+ * adjustments to the EFI_FILE_INFO structure that we're filling.
+ */
+
+/*
+static void fsw_posix_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    if ((posix_mode & S_IWUSR) == 0)
+        FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+}
+*/
+
+/**
+ * Common function to fill an EFI_FILE_INFO with information about a dnode.
+ */
+
+/*
+EFI_STATUS fsw_posix_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+                                       IN struct fsw_dnode *dno,
+                                       IN OUT UINTN *BufferSize,
+                                       OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    EFI_FILE_INFO       *FileInfo;
+    UINTN               RequiredSize;
+    struct fsw_dnode_stat sb;
+
+    // make sure the dnode has complete info
+    Status = fsw_posix_map_status(fsw_dnode_fill(dno), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // TODO: check/assert that the dno's name is in UTF16
+
+    // check buffer size
+    RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_posix_strsize(&dno->name);
+    if (*BufferSize < RequiredSize) {
+        // TODO: wind back the directory in this case
+
+        *BufferSize = RequiredSize;
+        return EFI_BUFFER_TOO_SMALL;
+    }
+
+    // fill structure
+    ZeroMem(Buffer, RequiredSize);
+    FileInfo = (EFI_FILE_INFO *)Buffer;
+    FileInfo->Size = RequiredSize;
+    FileInfo->FileSize          = dno->size;
+    FileInfo->Attribute         = 0;
+    if (dno->type == FSW_DNODE_TYPE_DIR)
+        FileInfo->Attribute    |= EFI_FILE_DIRECTORY;
+    fsw_posix_strcpy(FileInfo->FileName, &dno->name);
+
+    // get the missing info from the fs driver
+    ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
+    sb.store_time_posix = fsw_posix_store_time_posix;
+    sb.store_attr_posix = fsw_posix_store_attr_posix;
+    sb.host_data = FileInfo;
+    Status = fsw_posix_map_status(fsw_dnode_stat(dno, &sb), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+    FileInfo->PhysicalSize      = sb.used_bytes;
+
+    // prepare for return
+    *BufferSize = RequiredSize;
+    return EFI_SUCCESS;
+}
+*/
+
+// EOF
diff --git a/filesystems/test/.svn/text-base/fsw_posix.h.svn-base b/filesystems/test/.svn/text-base/fsw_posix.h.svn-base
new file mode 100644 (file)
index 0000000..8ab72f5
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+ * \file fsw_posix.h
+ * POSIX user space host environment header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_POSIX_H_
+#define _FSW_POSIX_H_
+
+#include "fsw_core.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+
+
+/**
+ * POSIX Host: Private per-volume structure.
+ */
+
+struct fsw_posix_volume {
+    struct fsw_volume           *vol;           //!< FSW volume structure
+
+    int                         fd;             //!< System file descriptor for data access
+
+};
+
+/**
+ * POSIX Host: Private structure for an open file.
+ */
+
+struct fsw_posix_file {
+    struct fsw_posix_volume     *pvol;          //!< POSIX host volume structure
+
+    struct fsw_shandle          shand;          //!< FSW handle for this file
+
+};
+
+/**
+ * POSIX Host: Private structure for an open directory.
+ */
+
+struct fsw_posix_dir {
+    struct fsw_posix_volume     *pvol;          //!< POSIX host volume structure
+
+    struct fsw_shandle          shand;          //!< FSW handle for this file
+
+};
+
+
+/* functions */
+
+struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table);
+int fsw_posix_unmount(struct fsw_posix_volume *pvol);
+
+struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode);
+ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes);
+off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence);
+int fsw_posix_close(struct fsw_posix_file *file);
+
+struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path);
+struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir);
+void fsw_posix_rewinddir(struct fsw_posix_dir *dir);
+int fsw_posix_closedir(struct fsw_posix_dir *dir);
+
+
+#endif
diff --git a/filesystems/test/.svn/text-base/fsw_posix_base.h.svn-base b/filesystems/test/.svn/text-base/fsw_posix_base.h.svn-base
new file mode 100644 (file)
index 0000000..ee1d96c
--- /dev/null
@@ -0,0 +1,89 @@
+/**
+ * \file fsw_posix_base.h
+ * Base definitions for the POSIX user space host environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_POSIX_BASE_H_
+#define _FSW_POSIX_BASE_H_
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define FSW_LITTLE_ENDIAN (1)
+// TODO: use info from the headers to define FSW_LITTLE_ENDIAN or FSW_BIG_ENDIAN
+
+
+// types
+
+typedef signed char         fsw_s8;
+typedef unsigned char       fsw_u8;
+typedef short               fsw_s16;
+typedef unsigned short      fsw_u16;
+typedef long                fsw_s32;
+typedef unsigned long       fsw_u32;
+typedef long long           fsw_s64;
+typedef unsigned long long  fsw_u64;
+
+
+// allocation functions
+
+#define fsw_alloc(size, ptrptr) (((*(ptrptr) = malloc(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS)
+#define fsw_free(ptr) free(ptr)
+
+// memory functions
+
+#define fsw_memzero(dest,size) memset(dest,0,size)
+#define fsw_memcpy(dest,src,size) memcpy(dest,src,size)
+#define fsw_memeq(p1,p2,size) (memcmp(p1,p2,size) == 0)
+
+// message printing
+
+#define FSW_MSGSTR(s) s
+#define FSW_MSGFUNC printf
+
+// 64-bit hooks
+
+#define FSW_U64_SHR(val,shiftbits) ((val) >> (shiftbits))
+#define FSW_U64_DIV(val,divisor) ((val) / (divisor))
+#define DEBUG(x)
+
+#define RShiftU64(val, shift) ((val) >> (shift))
+#define LShiftU64(val, shift) ((val) << (shift))
+
+#endif
diff --git a/filesystems/test/.svn/text-base/lslr.c.svn-base b/filesystems/test/.svn/text-base/lslr.c.svn-base
new file mode 100644 (file)
index 0000000..d3e4e3c
--- /dev/null
@@ -0,0 +1,136 @@
+/**
+ * \file lslr.c
+ * Test program for the POSIX user space environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2);
+//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+static struct fsw_fstype_table *fstypes[] = {
+    //&FSW_FSTYPE_TABLE_NAME(ext2),
+    //&FSW_FSTYPE_TABLE_NAME(reiserfs),
+    &FSW_FSTYPE_TABLE_NAME(FSTYPE       ),
+    NULL
+};
+
+static int listdir(struct fsw_posix_volume *vol, char *path, int level)
+{
+    struct fsw_posix_dir *dir;
+    struct dirent *dent;
+    int i;
+    char subpath[4096];
+
+    dir = fsw_posix_opendir(vol, path);
+    if (dir == NULL) {
+        printf("opendir(%s) call failed.\n", path);
+        return 1;
+    }
+    while ((dent = fsw_posix_readdir(dir)) != NULL) {
+        for (i = 0; i < level*2; i++)
+            fputc(' ', stdout);
+        printf("%d  %s\n", dent->d_type, dent->d_name);
+
+        if (dent->d_type == DT_DIR) {
+            snprintf(subpath, 4095, "%s%s/", path, dent->d_name);
+            listdir(vol, subpath, level + 1);
+        }
+    }
+    fsw_posix_closedir(dir);
+
+    return 0;
+}
+
+static int catfile(struct fsw_posix_volume *vol, char *path)
+{
+    struct fsw_posix_file *file;
+    int r;
+    char buf[256];
+
+    file = fsw_posix_open(vol, path, 0, 0);
+    if (file == NULL) {
+        printf("open(%s) call failed.\n", path);
+        return 1;
+    }
+    while ((r=fsw_posix_read(file, buf, sizeof(buf))) > 0)
+    {
+        int i;
+        for (i=0; i<r; i++)
+        {
+           printf("%c", buf[i]);
+        }
+    }
+    fsw_posix_close(file);
+
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    struct fsw_posix_volume *vol;
+    int i;
+
+    if (argc != 2) {
+        printf("Usage: lslr <file/device>\n");
+        return 1;
+    }
+
+    for (i = 0; fstypes[i]; i++) {
+        vol = fsw_posix_mount(argv[1], fstypes[i]);
+        if (vol != NULL) {
+            printf("Mounted as '%s'.\n", fstypes[i]->name.data);
+            break;
+        }
+    }
+    if (vol == NULL) {
+        printf("Mounting failed.\n");
+        return 1;
+    }
+
+    //listdir(vol, "/System/Library/Extensions/udf.kext/", 0);
+    //listdir(vol, "/System/Library/Extensions/AppleACPIPlatform.kext/", 0);
+    //listdir(vol, "/System/Library/Extensions/", 0);
+    catfile(vol, "/System/Library/Extensions/AppleHPET.kext/Contents/Info.plist");
+    //listdir(vol, "/", 0);
+
+    fsw_posix_unmount(vol);
+
+    return 0;
+}
+
+// EOF
diff --git a/filesystems/test/.svn/text-base/lsroot.c.svn-base b/filesystems/test/.svn/text-base/lsroot.c.svn-base
new file mode 100644 (file)
index 0000000..bb2cba0
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+ * \file lsroot.c
+ * Example program for the POSIX user space environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs);
+
+int main(int argc, char **argv)
+{
+    struct fsw_posix_volume *vol;
+    struct fsw_posix_dir *dir;
+    struct dirent *dent;
+
+    if (argc != 2) {
+        printf("Usage: lsroot <file/device>\n");
+        return 1;
+    }
+
+    //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(ext2));
+    //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(reiserfs));
+    vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(FSTYPE));
+    if (vol == NULL) {
+        printf("Mounting failed.\n");
+        return 1;
+    }
+    //dir = fsw_posix_opendir(vol, "/drivers/net/");
+    dir = fsw_posix_opendir(vol, "/");
+    if (dir == NULL) {
+        printf("opendir call failed.\n");
+        return 1;
+    }
+    while ((dent = fsw_posix_readdir(dir)) != NULL) {
+        printf("- %s\n", dent->d_name);
+    }
+    fsw_posix_closedir(dir);
+    fsw_posix_unmount(vol);
+
+    return 0;
+}
+
+// EOF
diff --git a/filesystems/test/README b/filesystems/test/README
new file mode 100644 (file)
index 0000000..c7c34e4
--- /dev/null
@@ -0,0 +1,2 @@
+This folder contains tests for VBoxFsDxe module, allowing up 
+and test filesystems without EFI environment and launching whole VBox. 
diff --git a/filesystems/test/fsw_posix.c b/filesystems/test/fsw_posix.c
new file mode 100644 (file)
index 0000000..eee8c5f
--- /dev/null
@@ -0,0 +1,479 @@
+/**
+ * \file fsw_posix.c
+ * POSIX user space host environment code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+#ifndef FSTYPE
+/** The file system type name to use. */
+#define FSTYPE ext2
+#endif
+
+
+// function prototypes
+
+fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type,
+                                struct fsw_shandle *shand);
+
+void fsw_posix_change_blocksize(struct fsw_volume *vol,
+                              fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                              fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+
+/**
+ * Dispatch table for our FSW host driver.
+ */
+
+struct fsw_host_table   fsw_posix_host_table = {
+    FSW_STRING_TYPE_ISO88591,
+
+    fsw_posix_change_blocksize,
+    fsw_posix_read_block
+};
+
+extern struct fsw_fstype_table   FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+
+/**
+ * Mount function.
+ */
+
+struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table)
+{
+    fsw_status_t        status;
+    struct fsw_posix_volume *pvol;
+
+    // allocate volume structure
+    status = fsw_alloc_zero(sizeof(struct fsw_posix_volume), (void **)&pvol);
+    if (status)
+        return NULL;
+    pvol->fd = -1;
+
+    // open underlying file/device
+    pvol->fd = open(path, O_RDONLY, 0);
+    if (pvol->fd < 0) {
+        fprintf(stderr, "fsw_posix_mount: %s: %s\n", path, strerror(errno));
+        fsw_free(pvol);
+        return NULL;
+    }
+
+    // mount the filesystem
+    if (fstype_table == NULL)
+        fstype_table = &FSW_FSTYPE_TABLE_NAME(FSTYPE);
+    status = fsw_mount(pvol, &fsw_posix_host_table, fstype_table, &pvol->vol);
+    if (status) {
+        fprintf(stderr, "fsw_posix_mount: fsw_mount returned %d\n", status);
+        fsw_free(pvol);
+        return NULL;
+    }
+
+    return pvol;
+}
+
+/**
+ * Unmount function.
+ */
+
+int fsw_posix_unmount(struct fsw_posix_volume *pvol)
+{
+    if (pvol->vol != NULL)
+        fsw_unmount(pvol->vol);
+    fsw_free(pvol);
+    return 0;
+}
+
+/**
+ * Open a named regular file.
+ */
+
+struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode)
+{
+    fsw_status_t        status;
+    struct fsw_posix_file *file;
+
+    // TODO: check flags for unwanted values
+
+    // allocate file structure
+    status = fsw_alloc(sizeof(struct fsw_posix_file), &file);
+    if (status)
+        return NULL;
+    file->pvol = pvol;
+
+    // open the file
+    status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_FILE, &file->shand);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open: open_dno returned %d\n", status);
+        fsw_free(file);
+        return NULL;
+    }
+
+    return file;
+}
+
+/**
+ * Read data from a regular file.
+ */
+
+ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes)
+{
+    fsw_status_t        status;
+    fsw_u32             buffer_size;
+
+    buffer_size = nbytes;
+    status = fsw_shandle_read(&file->shand, &buffer_size, buf);
+    if (status)
+        return -1;
+    return buffer_size;
+}
+
+/**
+ * Change position within a regular file.
+ */
+
+off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence)
+{
+    fsw_u64             base_offset = 0;
+
+    // get base offset
+    base_offset = 0;
+    if (whence == SEEK_CUR)
+        base_offset = file->shand.pos;
+    else if (whence == SEEK_END)
+        base_offset = file->shand.dnode->size;
+
+    // calculate new offset, prevent seeks before the start of the file
+    if (offset < 0 && -offset > base_offset)
+        file->shand.pos = 0;
+    else
+        file->shand.pos = base_offset + offset;
+
+    return file->shand.pos;
+}
+
+/**
+ * Close a regular file.
+ */
+
+int fsw_posix_close(struct fsw_posix_file *file)
+{
+    fsw_shandle_close(&file->shand);
+    fsw_free(file);
+    return 0;
+}
+
+/**
+ * Open a directory for iteration.
+ */
+
+struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path)
+{
+    fsw_status_t        status;
+    struct fsw_posix_dir *dir;
+
+    // allocate file structure
+    status = fsw_alloc(sizeof(struct fsw_posix_dir), &dir);
+    if (status)
+        return NULL;
+    dir->pvol = pvol;
+
+    // open the directory
+    status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_DIR, &dir->shand);
+    if (status) {
+        fprintf(stderr, "fsw_posix_opendir: open_dno returned %d\n", status);
+        fsw_free(dir);
+        return NULL;
+    }
+
+    return dir;
+}
+
+/**
+ * Read the next entry from a directory.
+ */
+
+struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir)
+{
+    fsw_status_t        status;
+    struct fsw_dnode    *dno;
+    static struct dirent dent;
+
+    // get next entry from file system
+    status = fsw_dnode_dir_read(&dir->shand, &dno);
+    if (status) {
+        if (status != 4)
+            fprintf(stderr, "fsw_posix_readdir: fsw_dnode_dir_read returned %d\n", status);
+        return NULL;
+    }
+    status = fsw_dnode_fill(dno);
+    if (status) {
+        fprintf(stderr, "fsw_posix_readdir: fsw_dnode_fill returned %d\n", status);
+        fsw_dnode_release(dno);
+        return NULL;
+    }
+
+    // fill dirent structure
+    dent.d_fileno = dno->dnode_id;
+    dent.d_reclen = 8 + dno->name.size + 1;
+    switch (dno->type) {
+        case FSW_DNODE_TYPE_FILE:
+            dent.d_type = DT_REG;
+            break;
+        case FSW_DNODE_TYPE_DIR:
+            dent.d_type = DT_DIR;
+            break;
+        case FSW_DNODE_TYPE_SYMLINK:
+            dent.d_type = DT_LNK;
+            break;
+        default:
+            dent.d_type = DT_UNKNOWN;
+            break;
+    }
+#if 0
+    dent.d_namlen = dno->name.size;
+#endif
+    memcpy(dent.d_name, dno->name.data, dno->name.size);
+    dent.d_name[dno->name.size] = 0;
+
+    return &dent;
+}
+
+/**
+ * Rewind a directory to the start.
+ */
+
+void fsw_posix_rewinddir(struct fsw_posix_dir *dir)
+{
+    dir->shand.pos = 0;
+}
+
+/**
+ * Close a directory.
+ */
+
+int fsw_posix_closedir(struct fsw_posix_dir *dir)
+{
+    fsw_shandle_close(&dir->shand);
+    fsw_free(dir);
+    return 0;
+}
+
+/**
+ * Open a shand of a required type by path.
+ */
+
+fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type, struct fsw_shandle *shand)
+{
+    fsw_status_t        status;
+    struct fsw_dnode    *dno;
+    struct fsw_dnode    *target_dno;
+    struct fsw_string   lookup_path;
+
+    lookup_path.type = FSW_STRING_TYPE_ISO88591;
+    lookup_path.len  = strlen(path);
+    lookup_path.size = lookup_path.len;
+    lookup_path.data = (void *)path;
+
+    // resolve the path (symlinks along the way are automatically resolved)
+    status = fsw_dnode_lookup_path(pvol->vol->root, &lookup_path, '/', &dno);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_lookup_path returned %d\n", status);
+        return status;
+    }
+
+    // if the final node is a symlink, also resolve it
+    status = fsw_dnode_resolve(dno, &target_dno);
+    fsw_dnode_release(dno);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_resolve returned %d\n", status);
+        return status;
+    }
+    dno = target_dno;
+
+    // check that it is a regular file
+    status = fsw_dnode_fill(dno);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_fill returned %d\n", status);
+        fsw_dnode_release(dno);
+        return status;
+    }
+    if (dno->type != required_type) {
+        fprintf(stderr, "fsw_posix_open_dno: dnode is not of the requested type\n");
+        fsw_dnode_release(dno);
+        return FSW_UNSUPPORTED;
+    }
+
+    // open shandle
+    status = fsw_shandle_open(dno, shand);
+    if (status) {
+        fprintf(stderr, "fsw_posix_open_dno: fsw_shandle_open returned %d\n", status);
+    }
+    fsw_dnode_release(dno);
+    return status;
+}
+
+/**
+ * FSW interface function for block size changes. This function is called by the FSW core
+ * when the file system driver changes the block sizes for the volume.
+ */
+
+void fsw_posix_change_blocksize(struct fsw_volume *vol,
+                                fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+                                fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
+{
+    // nothing to do
+}
+
+/**
+ * FSW interface function to read data blocks. This function is called by the FSW core
+ * to read a block of data from the device. The buffer is allocated by the core code.
+ */
+
+fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer)
+{
+    struct fsw_posix_volume *pvol = (struct fsw_posix_volume *)vol->host_data;
+    off_t           block_offset, seek_result;
+    ssize_t         read_result;
+
+    FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_posix_read_block: %d  (%d)\n"), phys_bno, vol->phys_blocksize));
+
+    // read from disk
+    block_offset = (off_t)phys_bno * vol->phys_blocksize;
+    seek_result = lseek(pvol->fd, block_offset, SEEK_SET);
+    if (seek_result != block_offset)
+        return FSW_IO_ERROR;
+    read_result = read(pvol->fd, buffer, vol->phys_blocksize);
+    if (read_result != vol->phys_blocksize)
+        return FSW_IO_ERROR;
+
+    return FSW_SUCCESS;
+}
+
+
+/**
+ * Time mapping callback for the fsw_dnode_stat call. This function converts
+ * a Posix style timestamp into an EFI_TIME structure and writes it to the
+ * appropriate member of the EFI_FILE_INFO structure that we're filling.
+ */
+
+/*
+static void fsw_posix_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    if (which == FSW_DNODE_STAT_CTIME)
+        fsw_posix_decode_time(&FileInfo->CreateTime,       posix_time);
+    else if (which == FSW_DNODE_STAT_MTIME)
+        fsw_posix_decode_time(&FileInfo->ModificationTime, posix_time);
+    else if (which == FSW_DNODE_STAT_ATIME)
+        fsw_posix_decode_time(&FileInfo->LastAccessTime,   posix_time);
+}
+*/
+
+/**
+ * Mode mapping callback for the fsw_dnode_stat call. This function looks at
+ * the Posix mode passed by the file system driver and makes appropriate
+ * adjustments to the EFI_FILE_INFO structure that we're filling.
+ */
+
+/*
+static void fsw_posix_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
+{
+    EFI_FILE_INFO       *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+    if ((posix_mode & S_IWUSR) == 0)
+        FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+}
+*/
+
+/**
+ * Common function to fill an EFI_FILE_INFO with information about a dnode.
+ */
+
+/*
+EFI_STATUS fsw_posix_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+                                       IN struct fsw_dnode *dno,
+                                       IN OUT UINTN *BufferSize,
+                                       OUT VOID *Buffer)
+{
+    EFI_STATUS          Status;
+    EFI_FILE_INFO       *FileInfo;
+    UINTN               RequiredSize;
+    struct fsw_dnode_stat sb;
+
+    // make sure the dnode has complete info
+    Status = fsw_posix_map_status(fsw_dnode_fill(dno), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+
+    // TODO: check/assert that the dno's name is in UTF16
+
+    // check buffer size
+    RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_posix_strsize(&dno->name);
+    if (*BufferSize < RequiredSize) {
+        // TODO: wind back the directory in this case
+
+        *BufferSize = RequiredSize;
+        return EFI_BUFFER_TOO_SMALL;
+    }
+
+    // fill structure
+    ZeroMem(Buffer, RequiredSize);
+    FileInfo = (EFI_FILE_INFO *)Buffer;
+    FileInfo->Size = RequiredSize;
+    FileInfo->FileSize          = dno->size;
+    FileInfo->Attribute         = 0;
+    if (dno->type == FSW_DNODE_TYPE_DIR)
+        FileInfo->Attribute    |= EFI_FILE_DIRECTORY;
+    fsw_posix_strcpy(FileInfo->FileName, &dno->name);
+
+    // get the missing info from the fs driver
+    ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
+    sb.store_time_posix = fsw_posix_store_time_posix;
+    sb.store_attr_posix = fsw_posix_store_attr_posix;
+    sb.host_data = FileInfo;
+    Status = fsw_posix_map_status(fsw_dnode_stat(dno, &sb), Volume);
+    if (EFI_ERROR(Status))
+        return Status;
+    FileInfo->PhysicalSize      = sb.used_bytes;
+
+    // prepare for return
+    *BufferSize = RequiredSize;
+    return EFI_SUCCESS;
+}
+*/
+
+// EOF
diff --git a/filesystems/test/fsw_posix.h b/filesystems/test/fsw_posix.h
new file mode 100644 (file)
index 0000000..8ab72f5
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+ * \file fsw_posix.h
+ * POSIX user space host environment header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_POSIX_H_
+#define _FSW_POSIX_H_
+
+#include "fsw_core.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+
+
+/**
+ * POSIX Host: Private per-volume structure.
+ */
+
+struct fsw_posix_volume {
+    struct fsw_volume           *vol;           //!< FSW volume structure
+
+    int                         fd;             //!< System file descriptor for data access
+
+};
+
+/**
+ * POSIX Host: Private structure for an open file.
+ */
+
+struct fsw_posix_file {
+    struct fsw_posix_volume     *pvol;          //!< POSIX host volume structure
+
+    struct fsw_shandle          shand;          //!< FSW handle for this file
+
+};
+
+/**
+ * POSIX Host: Private structure for an open directory.
+ */
+
+struct fsw_posix_dir {
+    struct fsw_posix_volume     *pvol;          //!< POSIX host volume structure
+
+    struct fsw_shandle          shand;          //!< FSW handle for this file
+
+};
+
+
+/* functions */
+
+struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table);
+int fsw_posix_unmount(struct fsw_posix_volume *pvol);
+
+struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode);
+ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes);
+off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence);
+int fsw_posix_close(struct fsw_posix_file *file);
+
+struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path);
+struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir);
+void fsw_posix_rewinddir(struct fsw_posix_dir *dir);
+int fsw_posix_closedir(struct fsw_posix_dir *dir);
+
+
+#endif
diff --git a/filesystems/test/fsw_posix_base.h b/filesystems/test/fsw_posix_base.h
new file mode 100644 (file)
index 0000000..ee1d96c
--- /dev/null
@@ -0,0 +1,89 @@
+/**
+ * \file fsw_posix_base.h
+ * Base definitions for the POSIX user space host environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_POSIX_BASE_H_
+#define _FSW_POSIX_BASE_H_
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define FSW_LITTLE_ENDIAN (1)
+// TODO: use info from the headers to define FSW_LITTLE_ENDIAN or FSW_BIG_ENDIAN
+
+
+// types
+
+typedef signed char         fsw_s8;
+typedef unsigned char       fsw_u8;
+typedef short               fsw_s16;
+typedef unsigned short      fsw_u16;
+typedef long                fsw_s32;
+typedef unsigned long       fsw_u32;
+typedef long long           fsw_s64;
+typedef unsigned long long  fsw_u64;
+
+
+// allocation functions
+
+#define fsw_alloc(size, ptrptr) (((*(ptrptr) = malloc(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS)
+#define fsw_free(ptr) free(ptr)
+
+// memory functions
+
+#define fsw_memzero(dest,size) memset(dest,0,size)
+#define fsw_memcpy(dest,src,size) memcpy(dest,src,size)
+#define fsw_memeq(p1,p2,size) (memcmp(p1,p2,size) == 0)
+
+// message printing
+
+#define FSW_MSGSTR(s) s
+#define FSW_MSGFUNC printf
+
+// 64-bit hooks
+
+#define FSW_U64_SHR(val,shiftbits) ((val) >> (shiftbits))
+#define FSW_U64_DIV(val,divisor) ((val) / (divisor))
+#define DEBUG(x)
+
+#define RShiftU64(val, shift) ((val) >> (shift))
+#define LShiftU64(val, shift) ((val) << (shift))
+
+#endif
diff --git a/filesystems/test/lslr.c b/filesystems/test/lslr.c
new file mode 100644 (file)
index 0000000..d3e4e3c
--- /dev/null
@@ -0,0 +1,136 @@
+/**
+ * \file lslr.c
+ * Test program for the POSIX user space environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2);
+//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+static struct fsw_fstype_table *fstypes[] = {
+    //&FSW_FSTYPE_TABLE_NAME(ext2),
+    //&FSW_FSTYPE_TABLE_NAME(reiserfs),
+    &FSW_FSTYPE_TABLE_NAME(FSTYPE       ),
+    NULL
+};
+
+static int listdir(struct fsw_posix_volume *vol, char *path, int level)
+{
+    struct fsw_posix_dir *dir;
+    struct dirent *dent;
+    int i;
+    char subpath[4096];
+
+    dir = fsw_posix_opendir(vol, path);
+    if (dir == NULL) {
+        printf("opendir(%s) call failed.\n", path);
+        return 1;
+    }
+    while ((dent = fsw_posix_readdir(dir)) != NULL) {
+        for (i = 0; i < level*2; i++)
+            fputc(' ', stdout);
+        printf("%d  %s\n", dent->d_type, dent->d_name);
+
+        if (dent->d_type == DT_DIR) {
+            snprintf(subpath, 4095, "%s%s/", path, dent->d_name);
+            listdir(vol, subpath, level + 1);
+        }
+    }
+    fsw_posix_closedir(dir);
+
+    return 0;
+}
+
+static int catfile(struct fsw_posix_volume *vol, char *path)
+{
+    struct fsw_posix_file *file;
+    int r;
+    char buf[256];
+
+    file = fsw_posix_open(vol, path, 0, 0);
+    if (file == NULL) {
+        printf("open(%s) call failed.\n", path);
+        return 1;
+    }
+    while ((r=fsw_posix_read(file, buf, sizeof(buf))) > 0)
+    {
+        int i;
+        for (i=0; i<r; i++)
+        {
+           printf("%c", buf[i]);
+        }
+    }
+    fsw_posix_close(file);
+
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    struct fsw_posix_volume *vol;
+    int i;
+
+    if (argc != 2) {
+        printf("Usage: lslr <file/device>\n");
+        return 1;
+    }
+
+    for (i = 0; fstypes[i]; i++) {
+        vol = fsw_posix_mount(argv[1], fstypes[i]);
+        if (vol != NULL) {
+            printf("Mounted as '%s'.\n", fstypes[i]->name.data);
+            break;
+        }
+    }
+    if (vol == NULL) {
+        printf("Mounting failed.\n");
+        return 1;
+    }
+
+    //listdir(vol, "/System/Library/Extensions/udf.kext/", 0);
+    //listdir(vol, "/System/Library/Extensions/AppleACPIPlatform.kext/", 0);
+    //listdir(vol, "/System/Library/Extensions/", 0);
+    catfile(vol, "/System/Library/Extensions/AppleHPET.kext/Contents/Info.plist");
+    //listdir(vol, "/", 0);
+
+    fsw_posix_unmount(vol);
+
+    return 0;
+}
+
+// EOF
diff --git a/filesystems/test/lsroot.c b/filesystems/test/lsroot.c
new file mode 100644 (file)
index 0000000..bb2cba0
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+ * \file lsroot.c
+ * Example program for the POSIX user space environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs);
+
+int main(int argc, char **argv)
+{
+    struct fsw_posix_volume *vol;
+    struct fsw_posix_dir *dir;
+    struct dirent *dent;
+
+    if (argc != 2) {
+        printf("Usage: lsroot <file/device>\n");
+        return 1;
+    }
+
+    //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(ext2));
+    //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(reiserfs));
+    vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(FSTYPE));
+    if (vol == NULL) {
+        printf("Mounting failed.\n");
+        return 1;
+    }
+    //dir = fsw_posix_opendir(vol, "/drivers/net/");
+    dir = fsw_posix_opendir(vol, "/");
+    if (dir == NULL) {
+        printf("opendir call failed.\n");
+        return 1;
+    }
+    while ((dent = fsw_posix_readdir(dir)) != NULL) {
+        printf("- %s\n", dent->d_name);
+    }
+    fsw_posix_closedir(dir);
+    fsw_posix_unmount(vol);
+
+    return 0;
+}
+
+// EOF