diff --git a/trunk/firmware/build/libraries/nfs/ARM11/Makefile b/trunk/firmware/build/libraries/nfs/ARM11/Makefile new file mode 100644 index 0000000..a51c8c6 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/ARM11/Makefile @@ -0,0 +1,66 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: CtrBrom - libraries - nfs +# File: Makefile +# +# Copyright 2008-2009 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- + +SUBDIRS = +SUBMAKES = + + +#---------------------------------------------------------------------------- + +# build ARM & THUMB libraries +FIRM_CODEGEN_ALL ?= TRUE + +#------------------------------------------- +#BROM_INCDIR = $(CTRBROM_ROOT)/include $(CTRBROM_ROOT)/build/libraries/fatfs/common/include ../common/include +#GINCLUDES = $(CTRBROM_ROOT)/include $(CTRFIRM_ROOT)/include $(CTRALL_ROOT)/include $(CTRBROM_ROOT)/build/libraries/fatfs/common/include ../common/include +INCDIR = $(BROM_ROOT)/include $(FIRM_ROOT)/include $(FIRM_ROOT)/build/libraries/nfs/common/include \ + ../common/include ../common/include/client ../common/include/driver_interface \ + $(FIRM_ROOT)/include/firm/fatfs +#INCDIR = $(CTRBROM_ROOT)/include ../common/include +SRCDIR = ../common/src ../common/src/client ../common/src/driver_interface +SRCS = \ + wfskrn_Api.cpp wfskrn_Area.cpp wfskrn_BCache.cpp wfskrn_BitField.cpp \ + wfskrn_Dir.cpp wfskrn_DirApi.cpp wfskrn_DirCheck.cpp \ + wfskrn_DirFind.cpp wfskrn_DirNodeStack.cpp wfskrn_DirRxTree.cpp \ + wfskrn_EPTree.cpp wfskrn_Errors.cpp wfskrn_FreeBlkAlloc.cpp \ + wfskrn_FTree.cpp wfskrn_Handles.cpp wfskrn_Heap.cpp wfskrn_Mutex.cpp \ + wfskrn_PathCache.cpp wfskrn_Permission.cpp wfskrn_Permission_AccessList.cpp \ + wfskrn_Permission_File.cpp wfskrn_Permission_Iop.cpp \ + wfskrn_PTree.cpp wfskrn_SubBlkAlloc.cpp wfskrn_Trans.cpp wfskrn_Utils.cpp \ + wfskrn_Volume.cpp my_wfskrn_Device.cpp \ + wfs_Client_Common.cpp randomlib.cpp wfs_Debug.cpp \ + wfs_Heap.cpp wfs_Mutex.cpp wfs_Names.cpp wfs_PathNames.cpp \ + wfscli_Handles.cpp WinOSReport.cpp wfs_AsyncUtils.cpp \ + drnand.c \ +#------------------------------------------------ +#MACRO_FLAGS += --c90 + +TARGET_LIB = libnfs$(FIRM_LIBSUFFIX).a + +include $(CTRFIRM_ROOT)/build/buildtools/commondefs + +INSTALL_TARGETS = $(TARGETS) +INSTALL_DIR = $(FIRM_INSTALL_LIBDIR) + +#---------------------------------------------------------------------------- + +do-build: $(TARGETS) + +include $(CTRFIRM_ROOT)/build/buildtools/modulerules + +#===== End of Makefile ===== diff --git a/trunk/firmware/build/libraries/nfs/ARM9/Makefile b/trunk/firmware/build/libraries/nfs/ARM9/Makefile new file mode 100644 index 0000000..e49a9f1 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/ARM9/Makefile @@ -0,0 +1,53 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: CtrBrom - libraries_sp - nfs +# File: Makefile +# +# Copyright 2008-2009 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- + +SUBDIRS = +#SUBMAKES = Makefile.CALLTRACE \ +# Makefile.FUNCTIONCOST + +#---------------------------------------------------------------------------- + +# build ARM & THUMB libraries +CTR_CODEGEN_ALL ?= TRUE + +# Codegen for sub processer +CTR_PROC = ARM9 + +SRCDIR = . ../common + +SRCS = \ + +TARGET_LIB = libnfs_sp$(CTR_LIBSUFFIX).a + + +#---------------------------------------------------------------------------- + +include $(CTRFIRM_ROOT)/build/buildtools/commondefs + +INSTALL_TARGETS = $(TARGETS) +INSTALL_DIR = $(CTR_INSTALL_LIBDIR) + + +#---------------------------------------------------------------------------- + +do-build: $(TARGETS) + +include $(CTRFIRM_ROOT)/build/buildtools/modulerules + + +#===== End of Makefile ===== diff --git a/trunk/firmware/build/libraries/nfs/Makefile b/trunk/firmware/build/libraries/nfs/Makefile new file mode 100644 index 0000000..bee605f --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/Makefile @@ -0,0 +1,34 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: CtrBrom - libraries - mi +# File: Makefile +# +# Copyright 2008 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- + +include $(CTRFIRM_ROOT)/build/buildtools/commondefs + +#---------------------------------------------------------------------------- + +SUBDIRS = ARM11 + +#ifdef CTR_WITH_ARM9 +#SUBDIRS += ARM9 +#endif + +#---------------------------------------------------------------------------- + +include $(CTRFIRM_ROOT)/build/buildtools/modulerules + + +#===== End of Makefile ===== diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/WinOSReport.h b/trunk/firmware/build/libraries/nfs/common/include/client/WinOSReport.h new file mode 100644 index 0000000..8e65e16 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/WinOSReport.h @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: WinOSReport.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: WinOSReport.h,v $ + Revision 1.6 2008/08/27 04:50:50 nakanose_jin + add function and defines + + Revision 1.5 2007/11/02 00:21:11 paul + started logging changes in the file + +*---------------------------------------------------------------------------*/ + +#pragma once + +#if _WIN32 +extern FILE *fpOSReport; +#endif + +typedef void (*OSReportCallback) (const char *log); + +void DebugPrintCallback(const char *pStr); +void DebugPrintCallback2(const char *pStr); + +OSReportCallback SetOSReportPrintCallback(OSReportCallback cb); + +void InitMyOSReport(); +void MyOSReport(const char *format, ...); +void MyOSPanic(const char* file, int line , const char* msg, ...); diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/_wfs_Server.h b/trunk/firmware/build/libraries/nfs/common/include/client/_wfs_Server.h new file mode 100644 index 0000000..34e7eb9 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/_wfs_Server.h @@ -0,0 +1,73 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFS library + File: wfs_Server.h - Server API + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Server.h,v $ + Revision 1.4 2008/01/10 05:33:20 nakanose_jin + validatePathName => validateDirectory + + Revision 1.3 2007/11/02 00:21:56 paul + started logging changes in the file + +*---------------------------------------------------------------------------*/ + +#ifndef __WFS_SERVER_H__ +#define __WFS_SERVER_H__ + +#include + +WFSResult WFSSRVInit(void *pWorkSpaceBuffer, u32 nWorkSpaceSize); +WFSResult WFSSRVGetDeviceInfo(const utf8 *sDeviceName, WFSDeviceInfo *pDi); +WFSResult WFSSRVMountDevice(const utf8 *sDeviceName, utf8 *sVolumeIdBuffer); +WFSResult WFSSRVUnmountVolume(const utf8 *sVolumeId); +WFSResult WFSSRVInitializeDevice(const utf8 *sDeviceName); +WFSResult WFSSRVGetVolumeId(const utf8 *sDeviceName, utf8 *sVolumeId); +WFSResult WFSSRVGetFreeSpaceSize(const utf8 *sPathName, u64 *pSize); +WFSResult WFSSRVCreateDirectory(const utf8 *sPathName, u32 nFlags, u64 nQuota); +WFSResult WFSSRVCreateAndOpenFile(const utf8 *sPathName, u32 nFlags, u32 nPreAllocateSize, WFSFileHandle *pFh); +WFSResult WFSSRVGetAttributes(const utf8 *sPathName, WFSFileAttributes *pFa); +WFSResult WFSSRVChangePermissions(const utf8 *sPathName, u32 nFlags); +WFSResult WFSSRVDelete(const utf8 *sPathName); +WFSResult WFSSRVMoveLocal(const utf8 *sSrcPathName, const utf8 *sDstPathName); +WFSResult WFSSRVOpenFile(const utf8 *sPathName, WFSAccess nDesiredAccess, WFSFileHandle *pFh); +WFSResult WFSSRVReadFile(WFSFileHandle fh, void *pFileDataBuffer, u32 nSize); +WFSResult WFSSRVWriteFile(WFSFileHandle fh, const void *pFileData, u32 nSize); +WFSResult WFSSRVCloseFile(WFSFileHandle fh, u8 bTruncateFlag); +WFSResult WFSSRVSearchDirectoryFirst(const utf8 *sPattern, WFSSearchDirectoryHandle *pSdh, WFSFileInfo *pFi); +WFSResult WFSSRVSearchDirectoryNext(WFSSearchDirectoryHandle sdh, WFSFileInfo *pFi); +WFSResult WFSSRVSearchDirectoryClose(WFSSearchDirectoryHandle sdh); +WFSResult WFSSRVDebugSetTitleID(u64 nTID); +u64 WFSSRVDebugGetTitleID(); + + + +// Functions in the WFS API that are NOT in the WFS Server API: + +// void WFSSetAttachDeviceCallback(utf8 *sDeviceNameBuffer, WFSDeviceCallback cbAttachDevice, void *pUserData); +// void WFSGetAttachDeviceCallback(utf8 **psDeviceName, WFSDeviceCallback *pCbAttachDevice, void **ppUserData); +// void WFSSetDetachDeviceCallback(utf8 *sDeviceNameBuffer, WFSDeviceCallback cbDetachDevice, void *pUserData); +// void WFSGetDetachDeviceCallback(utf8 **psDeviceName, WFSDeviceCallback *pCbDetachDevice, void **ppUserData); + +// WFSResult WFSSetCurrentDirectory(const utf8 *sPathName); +// This function is replaced with: +WFSResult WFSSRVValidateDirectory(const utf8 *sPathName); + + + +// WFSResult WFSGetCurrentDirectory(utf8 *sAbsPathNameBuffer, s32 nBufferSize); +// WFSResult WFSSetFilePosition(WFSFileHandle fh, WFSFileSize nFilePosition); +// WFSResult WFSGetFilePosition(WFSFileHandle fh, WFSFileSize *pFilePosition); +// WFSResult WFSGetFileSize(WFSFileHandle fh, WFSFileSize *pFileSize); + + + + +#endif //define __WFS_SERVER_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/_wfssrv_Defs.h b/trunk/firmware/build/libraries/nfs/common/include/client/_wfssrv_Defs.h new file mode 100644 index 0000000..6a8ab45 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/_wfssrv_Defs.h @@ -0,0 +1,382 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFSSrv library API = shim layer in RVL version and RPC + layer in WFSDEV version. + File: wfsdev_Defs.h - Definitions common to WFS client and server + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfssrv_Defs.h,v $ + Revision 1.34 2008/12/03 00:17:36 kondo_masahiro + Added a argument of WFSSrvFlush(). + + Revision 1.33 2008/10/21 10:45:09 kondo_masahiro + Added new function WFSWriteFileAndDiscard + + Revision 1.32 2008/09/29 01:06:26 kondo_masahiro + Added the argument of WFSSrvInit(). + + Revision 1.31 2008/07/18 02:59:44 ueno + Renamed WFSDeletePermissions() -> WFSDeleteAccessListEntry(). + + Revision 1.30 2008/07/17 05:08:41 kondo_masahiro + Added WFSSRV_ATTACH_DETACH + + Revision 1.29 2008/07/15 08:43:53 nakanose_jin + change arg order + + Revision 1.28 2008/07/14 07:15:46 ueno + Implemented WFSGetAccessListAsync(), WFSSetAccessListEntryAsync() and WFSDeletePermissionsAsync(). + + Revision 1.27 2008/07/10 06:12:33 nakanose_jin + add permissions API + + Revision 1.26 2008/05/22 08:05:49 ueno + Added WFSSrvDebugAclTest to run accesslist test. + + Revision 1.25 2008/05/09 14:03:09 nakanose_jin + canceling => reduce settitleid argument + + Revision 1.23 2008/04/19 05:52:03 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.22 2008/04/15 02:47:27 ueno + Added WFSSrvGetPermissionForUser() and WFSSrvSetPermissionForUser(). + + Revision 1.21 2008/03/28 14:14:20 nakanose_jin + chance spec of debug proc + + Revision 1.20 2008/02/20 08:10:10 nakanose_jin + add WFSExecDebugProcedure + + Revision 1.19 2008/02/08 04:42:00 paul + Changed WFSSrvUnmountVolume parameter bForce to WFSBool + + Revision 1.18 2008/02/07 13:02:18 nakanose_jin + WFSUnmountVolume : Add force-close option (but only in detach condition) + + Revision 1.17 2008/01/10 05:33:20 nakanose_jin + validatePathName => validateDirectory + + Revision 1.16 2007/12/25 14:00:36 ueno + Added WFSSrvConnectToServer() to connect to the server again. + + Revision 1.15 2007/12/12 07:51:29 paul + Added WFSSrvGetFileSize + + Revision 1.14 2007/12/10 02:51:36 paul + Added function codes for WFSSRV_SET_HOME_DIRECTORY, WFSSRV_SET_CURRENT_DIRECTORY. (These do not need to be implemented in the actual server, both call WFSSrvValidatePathName) + + Revision 1.13 2007/11/30 09:43:09 nakanose_jin + refine for multi client + + Revision 1.12 2007/11/21 04:17:28 wayne.wong + Many changes that included single request/result RPC messages, bug fixes, code factoring, and English C comment adjustments. + 1. Combined RPC messages into a single request message and single result + message. Except for file reads and writes. + 2. Fixed+factored some Endianess code. + 3. Enabled larger TCP/IP data transfer size. Previous setting was artifically small + to test the code to perform large transfers. + 4. Changed the volume id parameters utf8*->WFSVolumeId for SrvGetVolumeId + and SrvMountDevice. More consistent with the way we send this type at the + RPC layer. + 5. Changed a couple Japanese comments to be compatible with English + comments. In particular, the "//" comment with a backslash at the end of + the line causes the next line of code to be ignored. + 6. Removed Windows-specific debugging output defines for RVL build. + + Revision 1.11 2007/11/16 21:54:26 paul + Fixed WFSSrvCloseFile to pass nNewSize instead of bTruncateFlag + + Revision 1.10 2007/11/16 02:15:57 wayne.wong + Added enumeration and stubs for WFSFlush call. + + Revision 1.9 2007/11/02 00:21:02 paul + started logging changes in the file + Added StartPosition to WFSSrvReadFile, WFSSrvWriteFile + + *---------------------------------------------------------------------------*/ + +#ifndef __WFSSRV_DEFS_H__ +#define __WFSSRV_DEFS_H__ + +#include "wfs_Defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Enumeration of functions. +// Used by the client to specify functions implemented on the server, or +// by the server to specify functions implemented on the client. + +typedef enum { + // server -> client + + WFSSRV_ATTACH_DEVICE, + WFSSRV_DETACH_DEVICE, + + // client -> server + + WFSSRV_INIT, + WFSSRV_EXIT, + + WFSSRV_GET_DEVICE_INFO, + WFSSRV_MOUNT_DEVICE, + WFSSRV_UNMOUNT_VOLUME, + WFSSRV_INITIALIZE_DEVICE, + WFSSRV_GET_VOLUME_ID, + WFSSRV_GET_FREE_SPACE_SIZE, + WFSSRV_FLUSH, + + WFSSRV_CREATE_DIRECTORY, + WFSSRV_SEARCH_DIRECTORY_FIRST, + WFSSRV_SEARCH_DIRECTORY_NEXT, + WFSSRV_SEARCH_DIRECTORY_CLOSE, + + WFSSRV_SET_HOME_DIRECTORY, + WFSSRV_SET_CURRENT_DIRECTORY, + + WFSSRV_VALIDATE_PATH_NAME, + WFSSRV_DELETE, + WFSSRV_MOVE_LOCAL, + WFSSRV_GET_ATTRIBUTES, + WFSSRV_CHANGE_PERMISSIONS, + + WFSSRV_CREATE_AND_OPEN_FILE, + WFSSRV_OPEN_FILE, + WFSSRV_GET_FILE_SIZE, + WFSSRV_CLOSE_FILE, + WFSSRV_READ_FILE, + WFSSRV_WRITE_FILE, + WFSSRV_WRITE_FILE_AND_DISCARD, + + WFSSRV_GET_PERMISSIONS, + WFSSRV_SET_PERMISSIONS, + + WFSSRV_GET_ACL, + WFSSRV_SET_ACL_ENTRY, + WFSSRV_DELETE_ACL_ENTRY, + + WFSSRV_SET_TITLE_ID, + WFSSRV_TEST, + WFSSRV_EXEC_DEBUG, + + WFSSRV_ATTACH_DETACH, + + WFSSRV_DEBUG_ACLTEST // [check] + +} WFSSrvFunc; + + +typedef u16 WFSSrvFileHandle; +typedef u16 WFSSrvSearchDirectoryHandle; + +#ifndef WFSDEV_SERVER + +// The WFSDev server must distinguish between multiple clients. +// This can be done by assigning a ClientId based on the client's IP address, +// which the server learns whenever it receives a request from a client via sockets. + +// Note: ClientId is orthogonal to TitleId. +// There can be multiple clients with the same TitleId. +// The same client could change TitleId while the server is running. + +// The home directory is only stored on the client side. +// The TitleId, however, is determined by a function in IOS. +// (except for the fake debug/wfsdev version) +// +// This allows a system application built on top of wfs to specify the home directory for +// an app prior to launching it. +// + +// Path Names +// The client<->server API uses absolute WFS path names, becuase the server does not know about +// "Current Directory" or "Home Directory". +// The absolute path name does not include the full windows path name, it is a WFS path name. + +// For example: "/vol/ABCDEFG/titles/1234/JAKK/gamesave/save1.bin" +// On windows, this could map to: +// "C:/my_project/my_wfs_device/titles/1234/JAKK/gamesave/save1.bin" +// There would be a file called: +// "C:/my_project/my_wfs_device/.Wfs" which contains: "Volume Name: ABCDEFG" + + +WFSResult WFSSrvInit(void *pWorkSpaceBuffer, u32 nWorkSpaceSize); +// Contact the WFSSrv server so that it can initialize state for this client. + + +WFSResult WFSSrvExit(void); +// Inform the WFSSrv server that this client is terminating. + + +WFSResult WFSSrvInitializeDevice(const WFSDeviceName *pDevName); +// pDevName (IN) pointer to device name struct. +// Server would create a volume (deleting any existing data within the device assigned to this folder). +// The server could have a GUI to allow device attach to be simulated. +// It depends on the usage model but this may not be necessary for game developers, so low priority. +// (Assuming a system app mounts the drive and assigns home directory in advance, so the +// game can access an already-mounted device from the start). + + +WFSResult WFSSrvGetDeviceInfo(const WFSDeviceName *pDevName, WFSDeviceInfo *pDi); +// pDevName (IN) A pointer to a device name struct. +// pDi (OUT) A pointer to a WFSDeviceInfo struct to receive the device information. + + +WFSResult WFSSrvMountDevice(const WFSDeviceName *pDevName, WFSVolumeId *pVolumeIdBuffer); +// pDevName (IN) A pointer to a device name struct. +// pVolumeIdBuffer (OUT) A pointer to a WFSVolumeId buffer + +WFSResult WFSSrvUnmountVolume(const WFSVolumeId *pVolumeId, WFSBool bForce); +// pVolumeId (IN) A pointer to a struct containing a mounted Volume Id. +// bForce (IN) If set to true, forces the volume to be unmounted regardless of open files. +// NOTE: This flag is only valid if the device is currently detached. Un-flushed data will be lost. + +WFSResult WFSSrvGetVolumeId(const WFSDeviceName *pDevName, WFSVolumeId *sVolumeIdBuffer); +// pDevName (IN) A pointer to a device name struct. +// sVolumeIdBuffer (OUT) A pointer to a WFSVolumeId buffer + + +WFSResult WFSSrvGetFreeSpaceSize(const WFSPathName *pAbsPathName, u64 *pSize); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of a file or directory. +// pSize (OUT) A pointer to a u64 to receive the free space size value. + + +WFSResult WFSSrvFlush(const WFSVolumeId *pVolumeId); + + +WFSResult WFSSrvGetAttributes(const WFSPathName *pAbsPathName, WFSFileAttributes *pFa); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of a file or directory. +// pFa (OUT) A pointer to a WFSFileAttributes struct which will be overwritten with the attributes of the specified file or directory. + +WFSResult WFSSrvChangePermissions(const WFSPathName *pAbsPathName, u32 nFlags, u32 nMask); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of a file or directory. +// nFlags (IN) The new permissions flags that are to be set. Should be a combination of the permission flags: WFS_PERM_* +// nMask (IN) A mask to specify which flags to change. + + +WFSResult WFSSrvCreateDirectory(const WFSPathName *pAbsPathName, u32 nFlags, u64 nQuota); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of a file or directory. +// nFlags (IN) Should be a combination of the permission flags: WFS_PERM_*. Note: WFS_FLAG_DIRECTORY will be set +// whether it is included or not. +// nQuota (IN) This parameter that can be used to restrict the total size of the hierarchy beneath the +// new directory. A quota of 0 means there is no size restriction, i.e. the quota is Infinity. + + +WFSResult WFSSrvSearchDirectoryFirst(const WFSPathName *pPattern, WFSSrvSearchDirectoryHandle *pSsdh, WFSFileInfo *pFi); +// pPattern (IN) A pointer to a struct specifying the search pattern as an absolute path name. +// pSsdh (OUT) A pointer to a WFSSrvSearchDirectoryHandle handle which is overwritten by the server. +// pFi (OUT) A pointer to a WFSFileInfo struct which will be overwritten with the details of the + + +WFSResult WFSSrvSearchDirectoryNext(WFSSrvSearchDirectoryHandle ssdh, WFSFileInfo *pFi); +// ssdh (IN) A WFSSrvSearchDirectoryHandle which was created by WFSSrvSearchDirectoryFirst. +// pFi (OUT) A pointer to a WFSFileInfo struct which will be overwritten with the details of the +// next file which matches the search pattern. +// +// If they have read permission on the directory, they can list all files/dirs in that directory. Directory read +// access was already checked by WFSSrvSearchDirectoryFirst. While they can list the directory contents, they may +// not be able to access all contained files/dirs. + + +WFSResult WFSSrvSearchDirectoryClose(WFSSrvSearchDirectoryHandle ssdh); +// ssdh (IN) A WFSSrvSearchDirectoryHandle which was returned by WFSSrvSearchDirectoryFirst. + + +WFSResult WFSSrvValidateDirectory(const WFSPathName *pAbsPathName); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of a file or directory to validate. +// Returns WFS_RESULT_OK if the specified pathname exists, and is accessible to the current title + + +WFSResult WFSSrvDelete(const WFSPathName *pAbsPathName); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of the file or directory to delete. + +WFSResult WFSSrvMoveLocal(const WFSPathName *pSrcAbsPathName, const WFSPathName *pDstAbsPathName); +// pSrcAbsPathName (IN) A pointer to a struct containing the absolute pathname of the source file or directory. +// pDstAbsPathName (IN) A pointer to a struct containing the absolute pathname of the destination file or directory. +// Moves or renames the source file/directory to the destination pathname. This function does not work across volumes. + + +WFSResult WFSSrvCreateAndOpenFile(const WFSPathName *pAbsPathName, u32 nFlags, WFSContentIdx nCidx, WFSFileSize nPreAllocateSize, WFSSrvFileHandle *pSfh); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of the file to create and open. +// nFlags (IN) Should be a combination of the permission flags: WFS_PERM_* +// nCidx (IN) The content idx, used to control access to purchased content. +// nPreAllocateSize (IN) The amount of disk-space to pre-allocate for the file. Hint to the file system. +// pSfh (OUT) A pointer to a server file handle which is overwritten by the server. + +WFSResult WFSSrvOpenFile(const WFSPathName *pAbsPathName, WFSAccess nDesiredAccess, WFSSrvFileHandle *pSfh, WFSFileAttributes *pFa); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of the file to open. +// nDesiredAccess (IN) The kind of access that is required: should be one of the WFS_ACCESS_* options. +// pSfh (OUT) A pointer to a server file handle, which is overwritten by the server. +// pFa (OUT) A pointer to a WFSFileAttributes struct which will be overwritten by the server, + +WFSResult WFSSrvCloseFile(WFSSrvFileHandle sfh, WFSFileSize nNewSize); +// sfh (IN) The server file handle which was returned when the file was opened. +// nNewSize (IN) This value may be set to truncate the size of a file. + +WFSResult WFSSrvGetFileSize(WFSSrvFileHandle sfh, WFSFileSize *pNewSize); +// sfh (IN) The server file handle which was returned when the file was opened. +// pNewSize (OUT) A pointer to a WFSFileSize variable which is overwritten by the current file size. + +s32 WFSSrvReadFile(WFSSrvFileHandle sfh, void *pFileDataBuffer, WFSFileSize nStartPosition, s32 nSize); +// sfh (IN) The server file handle which was returned when the file was opened. +// pFileDataBuffer (OUT) Points to a buffer which will be overwritten with data from the file. +// nSize (IN) The number of bytes to be read. + + +WFSResult WFSSrvWriteFile(WFSSrvFileHandle sfh, const void *pFileData, WFSFileSize nStartPosition, WFSFileSize nSize, WFSBool bDiscard); +// sfh (IN) The server file handle which was returned when the file was opened. +// pFileData (IN) Points to the data to be written to the file. +// nSize (IN) The number of bytes to be written. +// bDiscard (IN) If it is true, the user buffer is used as work buffer. + + +WFSResult WFSSrvSetTitleId(WFSTitleId titleId,WFSGroupId groupId); +// titleId (IN) the title id which is the low 32 bits of the OSTitleId which can be obtained be ESP_GetTitleId() +// groupId (IN) the group id from the TMD, which can be obtained by ES_GetTmd() +// This function informs the server of the title id and group id of the application linked to this instance of the client. + +WFSResult WFSSrvExecDebugProcedure( u32 cmd , void *arg0 , void *arg1 ); +// cmd (IN) special command No. +// arg0,arg1 (IN/OUT) parameters of special command. +// This function let the server do special tasks. + +WFSResult WFSSrvConnectToServer(void); + +WFSResult WFSSrvGetPermissionForUser(const WFSPathName *pAbsPathName, u32 *pFlags, WFSTitleId titleId); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of the file or the directory. +// pFlags (OUT) A pointer to a u32 which will be overwritten with the permissions the specified title id has to +// access or modify the specified file or directory. See wfstypes.h for WFS_PERM* flag definitions. +// titleId (IN) Title id of the application for which permissions are being set. + +WFSResult WFSSrvSetPermissionForUser(const WFSPathName *pAbsPathName, u32 nFlags, u32 nMask, WFSTitleId titleId); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of the file or the directory. +// nFlags (IN) The new permissions flags that are to be set. Should be a combination of the permission flags: WFS_PERM_* (see wfstypes.h) +// nMask (IN) The mask determines which flags will be changed. NewAttributes = (OldAttributes & ~nMask) | (nFlags & nMask) +// titleId (IN) Title id of the application for which permissions are being set. + +WFSResult WFSSrvDeleteAccessListEntry(const WFSPathName *pAbsPathName, WFSTitleId titleId, WFSTitleId entryCreatorId); +WFSResult WFSSrvSetAccessListEntry(const WFSPathName *pAbsPathName, u32 nFlags, u32 nMask, WFSTitleId titleId); +s32 WFSSrvGetAccessList(const WFSPathName *pAbsPathName, WFSAccessListEntry *pAccessList, u32 nMaxElements); + + + +WFSResult WFSSrvSetWorkspace(void *pWorkSpaceBuffer, u32 nWorkSpaceSize); + +#ifdef ACL_TEST +WFSResult WFSSrvDebugAclTest(u32 testNo, void *arg0, void *arg1); +#endif // ACL_TEST + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif //define __WFSSRV_DEFS_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/randomlib.h b/trunk/firmware/build/libraries/nfs/common/include/client/randomlib.h new file mode 100644 index 0000000..7593e6d --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/randomlib.h @@ -0,0 +1,26 @@ +#ifndef _RANDOMLIB_H +#define _RANDOMLIB_H + +#include "revolution.h" + +/* +#if _IOP +#include "types.h" +#else +#include "revolution/types.h" +#endif +*/ + +#include "wfs_Platform.h" + +void RandomInitialise(int ij, int kl); +double RandomUniform(void); +double RandomGaussian(double mean, double stddev); +int RandomInt(int lower, int upper); +double RandomDouble(double lower, double upper); +u32 RandomU32(); + +#define NUM_UNIQUE_RANDOM_SEEDS_U32 0x382C7A42 +void RandomSetSeedU32(u32 nSeed); + +#endif diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/wfs_AsyncUtils.h b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_AsyncUtils.h new file mode 100644 index 0000000..0172a52 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_AsyncUtils.h @@ -0,0 +1,95 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_AsyncUtils.h - mutual exclusion for multi-thread case + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_AsyncUtils.h,v $ + Revision 1.6 2008/04/19 05:52:50 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.5 2007/11/09 01:19:54 paul + *** empty log message *** + + Revision 1.4 2007/11/02 00:25:49 paul + started logging changes in the file + *---------------------------------------------------------------------------*/ + +#ifndef wfs_AsyncUtils_h +#define wfs_AsyncUtils_h + +#include "wfs_PathNames.h" +#include "wfs_Mutex.h" + +#ifdef _DEBUG + #define _DEBUG_ASYNC_UTILS 0 // change to 1 if debug info required +#else + #define _DEBUG_ASYNC_UTILS 0 +#endif + +#define WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(ptr,Type,var) *((Type*)ptr)=var; ptr=(void*)((size_t)pPtr + sizeof(Type)) +#define WFSCLI_WRITE_ASYNC_PARAM(ptr,Type,var) *((Type*)ptr)=var +#define WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(ptr,Type,var) Type var=*((Type*)ptr); ptr=(void*)((size_t)pPtr + sizeof(Type)) +#define WFSCLI_DECLARE_AND_READ_ASYNC_PARAM(ptr,Type,var) Type var=*((Type*)ptr); +#define WFSCLI_READ_ASYNC_PARAM_AND_INC_PTR(ptr,Type,var) var=*((Type*)ptr); ptr=(void*)((size_t)pPtr + sizeof(Type)) +#define WFSCLI_READ_ASYNC_PARAM(ptr,Type,var) var=*((Type*)ptr) + + +typedef struct WFSAsyncParamHdr WFSAsyncParamHdr; +typedef struct WFSAsyncParamHdrAnchor WFSAsyncParamHdrAnchor; +typedef struct WFSAsyncParamHdrLink WFSAsyncParamHdrLink; +typedef struct WFSAsyncParamGlobals WFSAsyncParamGlobals; + +struct WFSAsyncParamHdrLink { + WFSAsyncParamHdr *pNext; + WFSAsyncParamHdr *pPrev; +}; + +struct WFSAsyncParamHdrAnchor { + WFSAsyncParamHdr *pHead; + WFSAsyncParamHdr *pTail; +}; + +struct WFSAsyncParamHdr { + WFSAsyncParamHdrLink l; + u32 nSize; // Size of parameters including this header + void *cb; + void *pUserData; + u8 nFunction; // Values are defined in wfssrv_Defs.h +}; + +struct WFSAsyncGlobals { + WFSAsyncParamHdrAnchor anchor; + WFSThread asyncExecThread; + void *pAsyncExecStack; + WFSMutex mxAccessTheParamQueue; + WFSCond condParamQueueEmpty; + WFSCond condParamQueueNotEmpty; +}; + + +void WFSAsyncUtilsInit(); + +void WFSAsyncUtilsClose(); + +WFSResult WFSPrepareAsyncCall(void **ppPtr, u8 nFunction, void *pUserData, void *cb, size_t nOtherParamSize); + +WFSResult WFSPrepareAsyncCallWithPathName(void **ppPtr, const utf8 *sInPathName, + WFSPathNameType nPathType, u8 nFunction, void *pUserData, void *cb, size_t nOtherParamSize); + +WFSResult WFSPrepareMoveLocalAsyncCall(void **ppPtr, const utf8 *sSrcPathName, const utf8 *sDstPathName, + WFSPathNameType nPathType, u8 nFunction, void *pUserData, void *cb, size_t nOtherParamSize); + +WFSResult WFSPrepareAsyncCallWithDeviceName(void **ppPtr, const utf8 *sDeviceName, + u8 nFunction, void *pUserData, void *cb, size_t nOtherParamSize); + +WFSResult WFSPrepareAsyncCallWithVolumeId(void **ppPtr, const utf8 *sVolumeId, + u8 nFunction, void *pUserData, void *cb, size_t nOtherParamSize); + +#endif //define wfs_AsyncUtils_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Client.h b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Client.h new file mode 100644 index 0000000..d91cca4 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Client.h @@ -0,0 +1,65 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Client.h - Internal definitions for the PPC side of the WFS API + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Client.h,v $ + Revision 1.4 2007/11/02 00:20:34 paul + started logging changes in the file + + *---------------------------------------------------------------------------*/ + +// File created 2007.08.29 + +#ifndef wfs_Client_h +#define wfs_Client_h + +#ifdef _DEBUG + #define _DEBUG_WFS_CLIENT 1 +#else + #define _DEBUG_WFS_CLIENT 0 +#endif + +#include "wfs_Heap.h" +#include "wfs_AsyncUtils.h" +#include "wfscli_Handles.h" +#include "wfssrv_Defs.h" + +typedef struct { + bool bMutexInitialized; + WFSMutex mxAccessDeviceCallbackGlobals; + utf8 *pAttachDeviceNameBuffer; + WFSDeviceCallback cbAttachDevice; + void *pAttachDeviceUserData; + + utf8 *pDetachDeviceNameBuffer; + WFSDeviceCallback cbDetachDevice; + void *pDetachDeviceUserData; +} WFSDeviceCallbackGlobals; + +typedef struct { + bool bLibInitialized; + void *pWorkSpaceBuffer; + WFSHeap heap; + WFSCliHandles hnd; + WFSAsyncGlobals ag; + WFSPathGlobals pg; + WFSDeviceCallbackGlobals dcg; +} WFSClientGlobals; + +typedef struct { + WFSSrvFunc nFunction; + WFSPath pathAbs; +} WFSFuncParams_OnePathName; + +extern WFSClientGlobals wcg; + +#endif //wfs_Client_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Config.h b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Config.h new file mode 100644 index 0000000..18f9bcc --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Config.h @@ -0,0 +1,58 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Config.h - project-wide configuration settings governing resource allocations etc. + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Config.h,v $ + Revision 1.8 2008/11/04 06:07:16 ueno + Changed the maximum number of file handles and search handles to 32. + + Revision 1.7 2008/09/29 01:06:04 kondo_masahiro + Added several macros. + + Revision 1.6 2008/07/09 02:52:33 paul + Increased maximum number of File & Directory Search handles + + Revision 1.5 2008/05/12 20:30:22 paul + Added handle defs + + Revision 1.4 2007/11/05 18:38:42 paul + WFSDEV flag is now defined in makefile / projectfile + + Revision 1.3 2007/11/02 00:25:29 paul + started logging changes in the file + *---------------------------------------------------------------------------*/ + +#ifndef wfs_Config_h +#define wfs_Config_h + + +// Define WFSDEV in the makefile/project settings to compile the WFS DEV version of the client +#ifdef WFSDEV + #define _WFSDEV 1 +#else + #define _WFSDEV 0 +#endif + +// This determines the maximum number of asynchronous calls that can be outstanding before a busy error occurs +//#define WFS_MAX_OUTSTANDING_ASYNC_CALLS 4 +// Now it is determined by the amount of memory the user supplies with WFSInit + +#define WFSCLI_WORK_SPACE_SIZE (40*1024) +#define WFS_ASYNC_EXEC_STACK_SIZE (16*1024) // client common code async handler thread + +// WFSDEV-specific +#define WFSDEV_CALLBACK_THREAD_STACK_SIZE (16*1024) // client thread for server-initiated callbacks; for WFSDEV implementation +#define WFSDEV_MAX_CLIENTS (5) // maximum number of clients that the server can support simultaneously + +#define WFSCLI_FILE_HANDLE_IDX_BITS 5 +#define WFSCLI_SEARCH_DIR_HANDLE_IDX_BITS 5 + +#endif //wfs_Config_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Defs.h b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Defs.h new file mode 100644 index 0000000..112c3d6 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Defs.h @@ -0,0 +1,81 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Defs.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Defs.h,v $ + Revision 1.14 2008/11/05 15:11:45 ueno + Fixed WFS_ROUND_DOWN(). + + Revision 1.13 2008/07/11 05:27:22 kondo_masahiro + Fixed WFS_ROUND_UP / DOWN + + Revision 1.11 2008/04/19 05:52:44 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.10 2007/12/28 07:33:23 nakanose_jin + fix bug + + Revision 1.9 2007/12/26 10:17:44 paul + WFS_RANGE_CHK, WFS_INDEX_COUNT 追加 + + Revision 1.8 2007/11/06 22:44:18 paul + added wfs_Errors.h to list of included headers + + Revision 1.7 2007/11/05 18:39:16 paul + removed unused macro + + Revision 1.6 2007/11/02 00:24:51 paul + started logging changes in the file + +*---------------------------------------------------------------------------*/ + +#ifndef wfs_Defs_h +#define wfs_Defs_h + + +#define _WIN32_WINNT 0x500 + +#include "revolution/wfs.h" +#include "wfs_Platform.h" +#include "wfs_Config.h" +#include "wfs_Errors.h" +#include "wfs_Types.h" + +#if !_IOP +#include +#include +#include +#endif + +#define WFS_ROUND_UP(v,x) (((v)+(x)-1)&-((signed)x)) +#define WFS_ROUND_DOWN(v,x) ((v)&-((signed)x)) + +#define WFS_RANGE_CHK(val,min,max) (((val)>=(min))&&((val)<(max))) +#define WFS_INDEX_COUNT(array) (size_t)(sizeof(array)/sizeof(array[0])) + +#define BYTES2BITS(b) ((b)<<3) + +#ifndef swap_typ + #define swap_typ(Typ,a,b) { Typ t=a; a=b; b=t; } +#endif + +#ifdef _DEBUG + #ifndef _ASSERT + #define _ASSERT(x) ASSERT(x) + #endif +#else + #ifndef _ASSERT + #define _ASSERT(x) + #endif +#endif + + +#endif // wfs_defs_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Errors.h b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Errors.h new file mode 100644 index 0000000..91e0621 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Errors.h @@ -0,0 +1,151 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Error_h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Errors.h,v $ + Revision 1.8 2008/07/11 19:14:01 paul + Updated to match latest wfsError.h + + Revision 1.7 2007/12/04 05:59:11 paul + bug fix + + Revision 1.6 2007/11/21 22:18:13 paul + Added WFS_INTERNAL_RESULT_ALREADY_MOUNTED + + Revision 1.5 2007/11/06 22:44:53 paul + Added macro to do validation checks for NULL pointers passed in + + Revision 1.4 2007/11/02 00:24:24 paul + started logging changes in the file + *---------------------------------------------------------------------------*/ + +#ifndef wfs_Error_h +#define wfs_Error_h + +#define WFSReturnOnError(x) { WFSResult nResult = x; if (nResult < WFS_RESULT_OK) return nResult; } +#define WFSReturnOnInternalError(x) { WFSInternalResult nResult = x; if (nResult < WFS_INTERNAL_RESULT_OK) return nResult; } +#define WFSReturnOnNullParameter(p) { if (p == NULL) return WFS_RESULT_INVALID; } + +typedef enum { + WFS_INTERNAL_RESULT_OK = 0, // Success + + // Errors that are usually detected in the client, and would result in the server not being called: + WFS_INTERNAL_RESULT_BUSY = -1, // The request queue is full. + WFS_INTERNAL_RESULT_OUT_OF_MEMORY = -2, // The client does not have enough memory to complete the requested operation. (May be due to too many outstanding aysnc calls). + WFS_INTERNAL_RESULT_INVALID = -3, // The function parameters were invalid, e.g. File name is too long, Path is too long or too deep. + WFS_INTERNAL_RESULT_ACCESS = -4, // Trying to write to a file which was opened for read-only access, or vice versa. + WFS_INTERNAL_RESULT_LIB_NOT_INITIALIZED = -5, // The WFS client has not been initialized. Please call WFSInit(..) (This error message is omitted from the list of return values). + WFS_INTERNAL_RESULT_LIB_INITIALIZED = -6, // The WFS client has already been initialized. + WFS_INTERNAL_RESULT_FILE_TOO_BIG = -7, // The current write/append request would push the file over the size limit. + WFS_INTERNAL_RESULT_NO_CHANGE_SIZE = -8, // The requested operation would cause the file size to change, but this file has WFS_PERM_NO_CHANGE_SIZE flag set. + + // Errors that cannot usually be detected early, and would be passed via nResult to the Async callbacks: + WFS_INTERNAL_RESULT_MEDIA_ERROR = -9, // The device or media is not attached, or was removed before the requested operation could be completed. + WFS_INTERNAL_RESULT_DEV_UNUSABLE = -10, // Attached device is not accessible, e.g. because it is an unsupported device, or has an unknown format. + WFS_INTERNAL_RESULT_DEV_NOT_INITIALIZED = -11, // Device not formatted, or does not yet contain a Wii volume + WFS_INTERNAL_RESULT_DEV_IN_USE = -12, // Trying to initialize a device which is in use (mounted) by one or more clients. + WFS_INTERNAL_RESULT_VOL_ID_ERROR = -13, // Attempted to mount a device with the same unique ID as an already mounted device (This could happen if the User backs up an entire Wii partition using a PC) + WFS_INTERNAL_RESULT_WRITE_PROTECTED = -14, // Device is physically write protected (e.g. USB Flash memory, SD Card). + WFS_INTERNAL_RESULT_ALREADY_MOUNTED = -15, // The device is already mounted. + + WFS_INTERNAL_RESULT_PERMISSION = -16, // Permission flags do not permit the requested access from this application. + WFS_INTERNAL_RESULT_PERMISSION_CL = -17, // Permission error caused by control level problems. + WFS_INTERNAL_RESULT_ACL_FULL = -18, // The access list is full. + WFS_INTERNAL_RESULT_ACL_ENTRY_NOT_FOUND = -19, // The specified entry does not exist in the access list. + WFS_INTERNAL_RESULT_AUTHENTICATION = -20, // Trying to access content on a different Wii, which does not have the required access rights. + WFS_INTERNAL_RESULT_CORRUPTION = -21, // A corrupted block was encountered which prevented the operation from being completed. + + WFS_INTERNAL_RESULT_DIRECTORY_QUOTA = -22, // One of the ancestor directories would exceed its quota. + + WFS_INTERNAL_RESULT_MAX_HANDLES = -23, // The maximum number of concurrent file handles / search handles are already in use. + WFS_INTERNAL_RESULT_ALREADY_EXISTS = -24, // The file or directory being created already exists. + WFS_INTERNAL_RESULT_NOT_FOUND = -25, // The specified file or directory or device does not exist. + WFS_INTERNAL_RESULT_NOT_EMPTY = -26, // The specified directory cannot be deleted because it is not empty. + WFS_INTERNAL_RESULT_NOT_FILE = -27, // The specified path is directory instead of a file. + WFS_INTERNAL_RESULT_NOT_DIRECTORY = -28, // The specified path is a file instead of a directory + WFS_INTERNAL_RESULT_FILE_OPEN = -39, // The file is open. Cannot delete, move, rename, change permissions of an open file. Cannot open a file more than once unless all opens are WFS_ACCESS_READ. + WFS_INTERNAL_RESULT_LOCKED = -30, // Cannot perform the requested operation since the file or directory is locked by an existing operation. + WFS_INTERNAL_RESULT_RESOURCE_LIMIT_EXCEEDED = -31, // A resource limit prevents this function call. Try smaller values. + + WFS_INTERNAL_RESULT_DIR_ENTRY_FOUND = -40, // The search string was matched and pointed to an entry + WFS_INTERNAL_RESULT_DIR_NODE_STRING_PREFIX = -41, // The search string ended early during comparison with a node sub string. (So this name is a prefix of existing names) + WFS_INTERNAL_RESULT_DIR_CHOICE_PREFIX = -42, // The search string ended at the end of a node sub string, but the node did not have a termination choice. (This name is a prefix of existing names) + WFS_INTERNAL_RESULT_DIR_NODE_STRING_MISMATCH = -43, // A mismatch was encountered while comparing the search string to a sub node prefix string. + WFS_INTERNAL_RESULT_DIR_NODE_CHOICE_NOT_FOUND = -44, // A mismatch was encountered while comparing a character of the search string with a set of choices for that character. + WFS_INTERNAL_RESULT_DIR_BLK_FULL = -45, // Unable to insert the specified string to the radix tree, due to lack of space in the block. + + // These result codes are not errors, but normal return values for the path cache functions + WFS_INTERNAL_RESULT_SRV_END_OF_PATH = -60, // Last part of path name parsed + WFS_INTERNAL_RESULT_SRV_PATH_DEPTH_1 = -61, // Path was of depth 1, such as "/something" + WFS_INTERNAL_RESULT_SRV_PATH_DEV = -62, // Path was "/dev" + WFS_INTERNAL_RESULT_SRV_PATH_VOL = -63, // Path was "/vol" + WFS_INTERNAL_RESULT_SRV_PATH_VOL_ROOT = -64, // Path was a volume root path, such as "/vol/xxxxxxx/" + + WFS_INTERNAL_RESULT_PTREE_ENTRY_FOUND = -70, + WFS_INTERNAL_RESULT_PTREE_ENTRY_NOT_FOUND = -71, + WFS_INTERNAL_RESULT_PTREE_FULL = -72, + + WFS_INTERNAL_RESULT_DEVICE_ERROR = -200, + WFS_INTERNAL_RESULT_DEVICE_INVALID_PARAMETER = -201, + WFS_INTERNAL_RESULT_DEVICE_NOT_FOUND = -202, + + WFS_INTERNAL_RESULT_BCACHE_ERROR = -300, // unspecified error + WFS_INTERNAL_RESULT_BCACHE_RESOURCE_LIMIT = -301, // exhausted resources + WFS_INTERNAL_RESULT_BCACHE_INVALID_PARAMETER = -302, // at least one argument is invalid + WFS_INTERNAL_RESULT_BCACHE_NO_MEMORY = -303, // could not malloc + WFS_INTERNAL_RESULT_BCACHE_NOT_FOUND = -304, // sector is not cached + WFS_INTERNAL_RESULT_BCACHE_MAX_DEVICES = -305, // max devices alreay allocated + WFS_INTERNAL_RESULT_BCACHE_INVALID_DEVICE = -306, // device not found/open + WFS_INTERNAL_RESULT_BCACHE_INVALID_HANDLE = -307, // invalid device handle + WFS_INTERNAL_RESULT_BCACHE_INVALID_VOLUME = -308, // invalid volume ID (not mapped) + WFS_INTERNAL_RESULT_BCACHE_ALREADY_MAPPED = -309, // vol or devH already mapped + WFS_INTERNAL_RESULT_BCACHE_ALLOC = -310, // cannot alloc (no mem, or pmem error) + WFS_INTERNAL_RESULT_BCACHE_PMEM = -311, // cannot read or write to pmem device + + WFS_INTERNAL_RESULT_VOLUME_ERROR = -400, // unspecified volume error + WFS_INTERNAL_RESULT_VOLUME_INVALID_PARAMETER = -401, // at least one argument is invalid + WFS_INTERNAL_RESULT_VOLUME_BCACHE_ALLOC = -402, // cannot allocate a page/block in memory + WFS_INTERNAL_RESULT_VOLUME_BCACHE_CONFIG = -403, // block cache not configured correctly + WFS_INTERNAL_RESULT_VOLUME_ID = -404, // bad volume ID or not initialized + WFS_INTERNAL_RESULT_VOLUME_CORRUPT_MR = -405, // the MR (or its free lists) are corrupted + WFS_INTERNAL_RESULT_VOLUME_AREA_ALLOC = -406, // area allocation cannot be satisfied + WFS_INTERNAL_RESULT_VOLUME_DEVICE_PARAMETER = -407, // parameters incompatible with device + WFS_INTERNAL_RESULT_VOLUME_NOT_MAPPED = -408, // volume is not mapped; invalid volume ID + + WFS_INTERNAL_RESULT_TRANSACTION_ERROR = -500, // unspecified transaction error + WFS_INTERNAL_RESULT_TRANSACTION_INVALID_PARAMETER= -501, + + WFS_INTERNAL_RESULT_ACL_ERROR = -600, // unspecified error + WFS_INTERNAL_RESULT_ACL_INVALID_PARAMETER = -601, // at least one argument is invalid + WFS_INTERNAL_RESULT_ACL_MAX_ENTRIES = -602, // max entries already in the access list. + WFS_INTERNAL_RESULT_ACL_BUFFER_TOO_SMALL = -603, // buffer is too small to store an access list. + WFS_INTERNAL_RESULT_ACL_CACHE = -610, // cannot allocate a cache. + WFS_INTERNAL_RESULT_ACL_FILE = -620, // cannot create, modify or delete the access list file. + WFS_INTERNAL_RESULT_ACL_ACLDIR_INCONSISTENT = -621, // access list files and indexlist are inconsistent. + WFS_INTERNAL_RESULT_ACL_FILENAME = -630, // cannot convert acl filename <=> acl content. + WFS_INTERNAL_RESULT_ACL_NAMEDIR_INCONSISTENT = -631, // access name files and indexlist are inconsistent. + WFS_INTERNAL_RESULT_ACL_HANDLE = -640, // cannot allocate an access list handle. + + WFS_INTERNAL_RESULT_AREA_ERROR = -700, // unspecified area error + WFS_INTERNAL_RESULT_AREA_INVALID_PARAMETER = -701, + WFS_INTERNAL_RESULT_AREA_BCACHE_ALLOC = -702, // cannot allocate a page/block in memory + WFS_INTERNAL_RESULT_AREA_CORRUPT_HDR = -703, // the area header is corrupted + WFS_INTERNAL_RESULT_AREA_VOLUME_NOT_MAPPED = -704, // volume is not mapped; invalid volume ID + WFS_INTERNAL_RESULT_AREA_ALLOC = -705, // area allocation cannot be satisfied + + WFS_INTERNAL_RESULT_NOT_IMPLEMENTED = -1026, // The requested function has not yet been implemented //ToDo: This error should be removed from the final API + WFS_INTERNAL_RESULT_UNKNOWN = -1027, // Unexpected error - could be caused by a bug in the file system. + WFS_INTERNAL_RESULT_FATAL_ERROR = -1028 // May be caused by critical metadata corruption. +} WFSInternalResult; + +#define WFSSetLastError(nErr) (wkg.nLastErr = (nErr)) + +#endif diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Heap.h b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Heap.h new file mode 100644 index 0000000..0e0e3d6 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Heap.h @@ -0,0 +1,73 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Heap.h - memory allocation functions + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Heap.h,v $ + Revision 1.8 2008/04/19 05:52:37 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.7 2007/12/26 04:26:41 paul + changed pAllocator to &allocator + + Revision 1.6 2007/12/26 04:13:56 paul + Changed RVL version of WFSHeap + + Revision 1.5 2007/12/26 00:19:25 paul + Added WFSHeapDestroy() + + Revision 1.4 2007/11/02 00:23:58 paul + started logging changes in the file + *---------------------------------------------------------------------------*/ + +#ifndef wfs_Heap_h +#define wfs_Heap_h + + +#include "wfs_Defs.h" + +#ifdef _DEBUG + #define _DEBUG_HEAP 0 // change to 1 if debug info required +#else + #define _DEBUG_HEAP 0 +#endif + +#if _WIN32 + +typedef HANDLE WFSHeap; + +#elif _TWL + +#define WFS_HEAP_DEFAULT_ALIGNMENT 32 + +typedef OSHeapHandle WFSHeap; + +#elif _RVL + +#include +#define WFS_HEAP_DEFAULT_ALIGNMENT 32 + +typedef struct { + MEMAllocator allocator; + MEMHeapHandle handle; +} WFSHeap; + +#elif _IOP + +#define WFSHeap IOSHeapId + +#endif + +void WFSCreateHeap(WFSHeap *pHeap, void *pBase, size_t nSize); +void *WFSHeapAlloc(WFSHeap *pHeap, size_t nSize); +void WFSHeapFree(WFSHeap *pHeap, void *pAddr); +void WFSHeapDestroy(WFSHeap *pHeap); + +#endif //define wfs_Heap_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Mutex.h b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Mutex.h new file mode 100644 index 0000000..2c25492 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Mutex.h @@ -0,0 +1,179 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Mutex.h - mutual exclusion for multi-thread case + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Mutex.h,v $ + Revision 1.11 2008/04/19 05:52:30 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.10 2007/12/27 01:43:38 ueno + Added WFSIsThreadTerminated() and WFSJoinThread(). + + Revision 1.9 2007/12/25 13:59:47 ueno + Added WFSSuspendThread(). + + Revision 1.8 2007/11/21 04:17:28 wayne.wong + Many changes that included single request/result RPC messages, bug fixes, code factoring, and English C comment adjustments. + 1. Combined RPC messages into a single request message and single result + message. Except for file reads and writes. + 2. Fixed+factored some Endianess code. + 3. Enabled larger TCP/IP data transfer size. Previous setting was artifically small + to test the code to perform large transfers. + 4. Changed the volume id parameters utf8*->WFSVolumeId for SrvGetVolumeId + and SrvMountDevice. More consistent with the way we send this type at the + RPC layer. + 5. Changed a couple Japanese comments to be compatible with English + comments. In particular, the "//" comment with a backslash at the end of + the line causes the next line of code to be ignored. + 6. Removed Windows-specific debugging output defines for RVL build. + + Revision 1.7 2007/11/02 00:23:33 paul + started logging changes in the file + *---------------------------------------------------------------------------*/ + +#ifndef wfs_Mutex_h +#define wfs_Mutex_h + +#include "wfs_Defs.h" + +#ifdef _DEBUG + #define _DEBUG_MUTEX 0 // change to 1 if debug info required +#else + #define _DEBUG_MUTEX 0 +#endif + +#if _WIN32 + +typedef struct { + HANDLE hHandle; +} WFSMutex; + +typedef struct { + HANDLE hAutoResetEvent; + //HANDLE hManualResetEvent; +} WFSCond; + +typedef struct { + HANDLE hThread; +} WFSThread; + +void WFSInitMutex(WFSMutex *mutex); +void WFSLockMutex(WFSMutex *mutex); +bool WFSTryLockMutex(WFSMutex *mutex); +void WFSUnlockMutex(WFSMutex *mutex); + +void WFSInitCond(WFSCond *pCond); +void WFSSignalCond(WFSCond *pCond); +void WFSWaitCond(WFSCond *pCond, WFSMutex* pMx); +void WFSResetCond(WFSCond *pCond); + +typedef LPTHREAD_START_ROUTINE WFSThreadFunc; + +bool WFSCreateThread(WFSThread *thread, + WFSThreadFunc threadFunc, + void* param, + void* stackBase, + u32 stackSize, + OSPriority priority); + +s32 WFSResumeThread(WFSThread *pThread); +void WFSCancelThread(WFSThread *pThread); +void WFSExitThread(void *pVal); +s32 WFSSuspendThread(WFSThread *pThread); +bool WFSIsThreadTerminated(WFSThread *thread); +bool WFSJoinThread(WFSThread *thread, void** val); + +#elif _TWL + +#define WFSMutex OSMutex +#define WFSCond OSEvent +#define WFSThread OSThread + +#define WFSInitMutex osInitMutex +#define WFSLockMutex osLockMutex +#define WFSTryLockMutex osTryLockMutex +#define WFSUnlockMutex osUnlockMutex + +//#define WFSInitCond osInitCond +//#define WFSSignalCond osSignalCond +//#define WFSWaitCond osWaitCond +//#define WFSResetCond(x) // This function does nothing on RVL, only needed for Windows + +typedef void *(*WFSThreadFunc)(void *); + +bool WFSCreateThread(WFSThread *thread, + WFSThreadFunc threadFunc, + void* param, + void* stackBase, + u32 stackSize, + OSPriority priority); + +s32 WFSResumeThread(WFSThread *pThread); +void WFSCancelThread(WFSThread *pThread); +void WFSExitThread(void *pVal); +s32 WFSSuspendThread(WFSThread *pThread); +bool WFSIsThreadTerminated(WFSThread *thread); +bool WFSJoinThread(WFSThread *thread, void** val); + +void WFSInitCond(WFSCond *pCond); +void WFSSignalCond(WFSCond *pCond); +void WFSWaitCond(WFSCond *pCond, WFSMutex* pMx); +void WFSResetCond(WFSCond *pCond); +/* +#define WFSResumeThread OSResumeThread +#define WFSCancelThread OSCancelThread +#define WFSExitThread OSExitThread +#define WFSSuspendThread OSSuspendThread +#define WFSIsThreadTerminated OSIsThreadTerminated +#define WFSJoinThread OSJoinThread +*/ +#elif _RVL + +#define WFSMutex OSMutex +#define WFSCond OSCond +#define WFSThread OSThread + +#define WFSInitMutex OSInitMutex +#define WFSLockMutex OSLockMutex +#define WFSTryLockMutex OSTryLockMutex +#define WFSUnlockMutex OSUnlockMutex + +#define WFSInitCond OSInitCond +#define WFSSignalCond OSSignalCond +#define WFSWaitCond OSWaitCond +#define WFSResetCond(x) // This function does nothing on RVL, only needed for Windows + +typedef void *(*WFSThreadFunc)(void *); + +bool WFSCreateThread(WFSThread *thread, + WFSThreadFunc threadFunc, + void* param, + void* stackBase, + u32 stackSize, + OSPriority priority); + +#define WFSResumeThread OSResumeThread +#define WFSCancelThread OSCancelThread +#define WFSExitThread OSExitThread +#define WFSSuspendThread OSSuspendThread +#define WFSIsThreadTerminated OSIsThreadTerminated +#define WFSJoinThread OSJoinThread + +#elif _IOP + +// dummy +typedef void *WFSMutex; +typedef void *WFSThread; +typedef void *WFSCond; + +#endif + +#endif //define wfs_Mutex_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Names.h b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Names.h new file mode 100644 index 0000000..dc8ab3a --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Names.h @@ -0,0 +1,95 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Names.h - global name types used by the WFS project + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Names.h,v $ + Revision 1.5 2008/02/25 05:32:50 paul + Reverted to previous version - changed defs instead. + + Revision 1.3 2007/11/06 22:43:48 paul + changed include + + Revision 1.2 2007/11/02 00:22:34 paul + started logging changes in the file + + *---------------------------------------------------------------------------*/ + +#ifndef wfs_Names_h +#define wfs_Names_h + +#include "wfs_Defs.h" + + +#if (WFS_MAX_PATH_NAME_SIZE<256) + typedef u8 WFSPathNameLengthType; +#elif (WFS_MAX_PATH_NAME_SIZE<65536) + typedef u16 WFSPathNameLengthType; +#else + typedef u32 WFSPathNameLengthType; +#endif + +typedef struct { + WFSPathNameLengthType nLen; // This is the length of the string not including the NULL terminator + utf8 sStr[WFS_MAX_PATH_NAME_SIZE+1]; +} WFSPathName; + +WFSResult WFSSetPathName(WFSPathName *pPathName, const utf8 *sPathName); + + +#if (WFS_MAX_FILE_NAME_SIZE<256) + typedef u8 WFSFileNameLengthType; +#elif (WFS_MAX_FILE_NAME_SIZE<65536) + typedef u16 WFSFileNameLengthType; +#else + typedef u32 WFSFileNameLengthType; +#endif + +typedef struct { + WFSFileNameLengthType nLen; // This is the length of the string not including the NULL terminator + utf8 sStr[WFS_MAX_FILE_NAME_SIZE+1]; +} WFSFileName; + +WFSResult WFSSetFileName(WFSFileName *pFileName, const utf8 *sFileName); + + +#if (WFS_MAX_DEVICE_NAME_SIZE<256) + typedef u8 WFSDeviceNameLengthType; +#elif (WFS_MAX_DEVICE_NAME_SIZE<65536) + typedef u16 WFSDeviceNameLengthType; +#else + typedef u32 WFSDeviceNameLengthType; +#endif + +typedef struct { + WFSDeviceNameLengthType nLen; // This is the length of the string not including the NULL terminator + utf8 sStr[WFS_MAX_DEVICE_NAME_SIZE+1]; +} WFSDeviceName; + +WFSResult WFSSetDeviceName(WFSDeviceName *pDeviceName, const utf8 *sDeviceName); + + +#if (WFS_MAX_VOLUME_ID_SIZE<256) + typedef u8 WFSVolumeIdLengthType; +#elif (WFS_MAX_VOLUME_ID_SIZE<65536) + typedef u16 WFSVolumeIdLengthType; +#else + typedef u32 WFSVolumeIdLengthType; +#endif + +typedef struct { + WFSVolumeIdLengthType nLen; // This is the length of the string not including the NULL terminator + utf8 sStr[WFS_MAX_VOLUME_ID_SIZE+1]; +} WFSVolumeId; + +WFSResult WFSSetVolumeId(WFSVolumeId *pVolumeId, const utf8 *sVolumeId); + + +#endif //define wfs_Names_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/wfs_PathNames.h b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_PathNames.h new file mode 100644 index 0000000..949fc5e --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_PathNames.h @@ -0,0 +1,79 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_PathNames.h - Functions for concatenating relative and absolute pathnames + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_PathNames.h,v $ + Revision 1.10 2008/08/19 14:05:40 nakanose_jin + smash pathnames bug + + Revision 1.9 2008/04/19 20:44:58 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.8 2007/12/10 02:50:11 paul + Added debug output + + Revision 1.7 2007/11/09 01:20:52 paul + Added a new path name type to allow validation of path name depth for paths ending in directories + + Revision 1.6 2007/11/02 01:09:26 paul + updated path type + + Revision 1.5 2007/11/02 00:20:16 paul + started logging changes in the file + + *---------------------------------------------------------------------------*/ + +// File created by Paul Donnelly on 2007.10.05 + +#ifndef wfs_PathNames_h +#define wfs_PathNames_h + +#ifdef _DEBUG + #define _DEBUG_PATHNAMES 0 // change to 1 locally if debug info required. (should be 0 for checkin) +#else + #define _DEBUG_PATHNAMES 0 +#endif + +#include "wfs_Mutex.h" + +typedef enum { + // Initial states + PATH_TYPE_REL_OR_ABS=0, // Path name can be a relative or absolute file or directory + PATH_TYPE_REL_OR_ABS_DIR, // Path name can be a relative or absolute directory + PATH_TYPE_ABS_DIR_ONLY, // Path name must be an absolute directory + PATH_TYPE_PATTERN // Path name (pattern) can be relative or absolute and may include wild cards in file name part. +} WFSPathNameType; + +typedef struct { + u16 nNumParts; + WFSPathNameLengthType aPart[WFS_MAX_PATH_DEPTH+1]; +} WFSPathPartOffsetArray; + +typedef struct { + WFSPathPartOffsetArray ppoa; + WFSPathName pn; +} WFSPath; + +typedef struct { + WFSMutex mxAccessPathGlobals; + WFSPath pathHome, pathCurrent; +} WFSPathGlobals; + +void WFSPathInit(); + +WFSResult WFSPathResolve(WFSPathName *pPnOutAbs, WFSPathPartOffsetArray *pPpoaOutAbs, const utf8 *sInPathName, WFSPathNameType nPathType); + +WFSResult WFSPathValidate(WFSPath *pPath); + +void WFSPathCopy(WFSPathName *pPnDst, WFSPathPartOffsetArray *pPpoaDst, WFSPathName *pPnSrc, WFSPathPartOffsetArray *pPpoaSrc, bool bAppendSeparator, bool bNullTermination); + +#endif //define wfs_PathNames_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Platform.h b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Platform.h new file mode 100644 index 0000000..ec34a0f --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Platform.h @@ -0,0 +1,161 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Platform.h - low level definitions and types that are primarily platform dependent + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Platform.h,v $ + Revision 1.13 2008/08/28 00:20:35 nakanose_jin + lets standard exception style + + Revision 1.11 2008/08/27 04:50:50 nakanose_jin + add function and defines + + Revision 1.10 2008/07/17 05:56:25 kondo_masahiro + Added #define SNPRINTF + + Revision 1.9 2008/04/24 23:19:15 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.8 2008/04/22 00:59:59 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.6 2007/11/21 04:17:28 wayne.wong + Many changes that included single request/result RPC messages, bug fixes, code factoring, and English C comment adjustments. + 1. Combined RPC messages into a single request message and single result + message. Except for file reads and writes. + 2. Fixed+factored some Endianess code. + 3. Enabled larger TCP/IP data transfer size. Previous setting was artifically small + to test the code to perform large transfers. + 4. Changed the volume id parameters utf8*->WFSVolumeId for SrvGetVolumeId + and SrvMountDevice. More consistent with the way we send this type at the + RPC layer. + 5. Changed a couple Japanese comments to be compatible with English + comments. In particular, the "//" comment with a backslash at the end of + the line causes the next line of code to be ignored. + 6. Removed Windows-specific debugging output defines for RVL build. + + Revision 1.5 2007/11/17 03:05:38 paul + removed #include "WinOSReport.h" from NDEV version + + Revision 1.4 2007/11/05 18:39:52 paul + removed kernel-specific definitions + + Revision 1.3 2007/11/02 00:22:23 paul + started logging changes in the file + +*---------------------------------------------------------------------------*/ + +#ifndef wfs_Platform_h +#define wfs_Platform_h + +#include + +#define TWL 1 +//--twl modified +#if 1 + #define _OSX 0 + #define _WIN32 0 + #define _TWL 1 + #define _RVL 0 + #define _IOP 0 +#else +//--twl modified +#ifdef OSX + #define _OSX 1 + #define _WIN32 0 + #define _RVL 0 + #define _IOP 0 +#else + #ifdef WIN32 + #define _OSX 0 + #define _WIN32 1 + #define _RVL 0 + #define _IOP 0 + #else + #ifdef IOP + #define _OSX 0 + #define _WIN32 0 + #define _RVL 0 + #define _IOP 1 + #else // RVL + #define _OSX 0 + #define _WIN32 0 + #define _RVL 1 + #define _IOP 0 + #endif + #endif +#endif +#endif //twl modified + +#if _WIN32 + #pragma warning(disable:4996) +// #define UNALIGNED __unaligned + #define BYTES_PER_INT 4 + #define BITS_PER_INT 32 + #define BIT_OFFSET_MASK 31 + #define BIT_OFFSET_TO_INT_OFFSET_SHIFT 5 + #define OSReport printf + #include "WinOSReport.h" + #define OSPanic MyOSPanic + #define SNPRINTF _snprintf +#elif _OSX + #define BYTES_PER_INT 4 + #define BITS_PER_INT 32 + #define BIT_OFFSET_MASK 31 + #define BIT_OFFSET_TO_INT_OFFSET_SHIFT 5 + #define OSReport printf + #include "WinOSReport.h" + #define OSPanic MyOSReport + #define SNPRINTF snprintf +//-- twl modified +#elif _TWL + #define BYTES_PER_INT 4 + #define BITS_PER_INT 32 + #define BIT_OFFSET_MASK 31 + #define BIT_OFFSET_TO_INT_OFFSET_SHIFT 5 + #define MyOSReport osTPrintf + #define InitMyOSReport() + #define SNPRINTF OS_SNPrintf + #define STRNLEN( str, maxlen ) stdStrLen(str) +//-- twl modified +#elif _RVL + #define BYTES_PER_INT 4 + #define BITS_PER_INT 32 + #define BIT_OFFSET_MASK 31 + #define BIT_OFFSET_TO_INT_OFFSET_SHIFT 5 + #define max(a,b) (((a)>(b))?(a):(b)) + #define min(a,b) (((a)<(b))?(a):(b)) + #define MyOSReport OSReport + #define InitMyOSReport() + #define SNPRINTF snprintf +#elif _IOP + #define BYTES_PER_INT 4 + #define BITS_PER_INT 32 + #define BIT_OFFSET_MASK 31 + #define BIT_OFFSET_TO_INT_OFFSET_SHIFT 5 + #define max(a,b) (((a)>(b))?(a):(b)) + #define min(a,b) (((a)<(b))?(a):(b)) + #define MyOSReport printf + #define InitMyOSReport() + #define SNPRINTF snprintf +#endif // WIN32 + +#ifndef BIG_ENDIAN + #ifdef WIN32 + #define BIG_ENDIAN 0 + #elif TWL + #define BIG_ENDIAN 0 + #else + #define BIG_ENDIAN 1 + #endif // WIN32 +#endif // BIG_ENDIAN + + +#endif //define wfs_Platform_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Types.h b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Types.h new file mode 100644 index 0000000..5bd6874 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/wfs_Types.h @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Types.h - global types used by the WFS project + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Types.h,v $ + Revision 1.5 2008/04/19 05:52:09 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.4 2007/11/02 23:14:04 paul + *** empty log message *** + + Revision 1.3 2007/11/02 22:35:50 paul + *** empty log message *** + + Revision 1.2 2007/11/02 00:21:35 paul + started logging changes in the file + +*---------------------------------------------------------------------------*/ + +#ifndef wfs_Types_h +#define wfs_Types_h + +//typedef char utf8; + +#include "wfs_Names.h" + +#endif //define wfs_Types_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/client/wfscli_Handles.h b/trunk/firmware/build/libraries/nfs/common/include/client/wfscli_Handles.h new file mode 100644 index 0000000..d2b43ad --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/client/wfscli_Handles.h @@ -0,0 +1,130 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Handles.h - Module for file handles and search directory handles + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfscli_Handles.h,v $ + Revision 1.10 2008/10/07 06:42:05 ueno + Modified WFSCliFileInfoAlloc to set WFSCLI_HANDLE_ALLOCATED in order to indicate the handle is allocated. + + Revision 1.9 2008/07/09 02:51:29 paul + Fixed comments + + Revision 1.8 2008/05/12 20:30:41 paul + Updated handle defs + + Revision 1.7 2007/11/02 00:19:58 paul + started logging changes in the file + +*---------------------------------------------------------------------------*/ + +// File created by Paul Donnelly on 2007.10.06 + + +#ifndef wfs_Handles_h +#define wfs_Handles_h + +#ifdef _DEBUG + #define _DEBUG_WFS_HANDLES 1 +#else + #define _DEBUG_WFS_HANDLES 0 +#endif + +#include "wfs_Defs.h" +#include "wfs_Mutex.h" + +#define WFSCLI_MAX_FILE_HANDLES (1< +#include + +#define NFS_DEVCTL_GET_GEOMETRY 0 +#define NFS_DEVCTL_FORMAT 1 +#define NFS_DEVCTL_REPORT_REMOVE 2 +#define NFS_DEVCTL_CHECKSTATUS 3 +#define NFS_DEVCTL_WARMSTART 4 +#define NFS_DEVCTL_POWER_RESTORE 5 +#define NFS_DEVCTL_POWER_LOSS 6 + + +#endif // __NFS_DRNAND_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/driver_interface/sdmc.h b/trunk/firmware/build/libraries/nfs/common/include/driver_interface/sdmc.h new file mode 100644 index 0000000..42614a7 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/driver_interface/sdmc.h @@ -0,0 +1,91 @@ +/*---------------------------------------------------------------------------* + Project: TWL - SD driver + File: sdmc.h + + Copyright 2006-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: #$ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef __SDMC_H__ +#define __SDMC_H__ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + + +/********************************************* + SDスペック構造体 +*********************************************/ +typedef struct { + u32 csd_ver2_flag; //CSDフォーマットバージョン(SDHCのときは1) + u32 memory_capacity; //data areaのサイズ(512Byte単位) + u32 protected_capacity; //protected areaのサイズ(512Byte単位) + u32 card_capacity; //カード全体のサイズ(512Byte単位) + + u32 adjusted_memory_capacity; //memory_capacityをシリンダ(heads*secptrack)の倍数に調整したサイズ(cylinders*heads*secptrackになる) + + u16 heads; + u16 secptrack; + u16 cylinders; + u16 SC; //sectors per cluster + u16 BU; + u16 RDE; //number of root dir entries(512 fix) + u32 SS; //sector size(512 fix) + u32 RSC; //reserved sector count(1 fix) +// u32 TS; //total sectors + u16 FATBITS; //16 or 32 + u16 SF; //sectors per FAT + u32 SSA; //sectors in system area + u32 NOM; //sectors in master boot record +} SdmcSpec; + + +/*FATパラメータ TODO:SdmcSpecを統合すること*/ +typedef struct { + u32 device_capacity; //デバイス全体のサイズ(512Byte単位) + u32 adjusted_device_capacity; + + u32 memory_capacity; //data areaのサイズ(512Byte単位) + u32 adjusted_memory_capacity; //memory_capacityをシリンダ(heads*secptrack)の倍数に調整したサイズ(cylinders*heads*secptrackになる) + + u16 volume_cylinders; + + u16 heads; + u16 secptrack; + u16 cylinders; + u16 SC; //sectors per cluster + u16 BU; + u16 RDE; //number of root dir entries(512 fix) + u16 padding; + u32 SS; //sector size(512 fix) + u32 RSC; //reserved sector count(1 fix) + u16 FATBITS; //16 or 32 + u16 SF; //sectors per FAT + u32 SSA; //sectors in system area + u32 NOM; //sectors in master boot record + + u32 begin_sect; +} FATSpec; + + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /*__SDMC_H__*/ diff --git a/trunk/firmware/build/libraries/nfs/common/include/msc_error.h b/trunk/firmware/build/libraries/nfs/common/include/msc_error.h new file mode 100644 index 0000000..3df3fec --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/msc_error.h @@ -0,0 +1,29 @@ +/*---------------------------------------------------------------------------* + File: msc_api.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + +*---------------------------------------------------------------------------*/ + +typedef u32 MSCError; + +#define IOS_ERROR_MSC_OK 0 + +#define IOS_ERROR_MSC_DEVICE_DETACH -8001 +#define IOS_ERROR_MSC_COMMAND_FAILED -8002 +#define IOS_ERROR_MSC_PHASE_ERROR -8003 +#define IOS_ERROR_MSC_INVALID_CBW_SIGNATURE -8004 +#define IOS_ERROR_MSC_INVALID_CBW_TAG -8005 + +#define IOS_ERROR_MSC_HASH_INCONSISTENT -8101 + +#if _IOP +IOSError MscCheckCswError(HardDisc *p_hd, IOSError ie); +#endif + diff --git a/trunk/firmware/build/libraries/nfs/common/include/private/wfs_Debug.h b/trunk/firmware/build/libraries/nfs/common/include/private/wfs_Debug.h new file mode 100644 index 0000000..25ba1fd --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/private/wfs_Debug.h @@ -0,0 +1,190 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFS library + File: wfs_Debug.h - debugging routines for WFS implementation + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Debug.h,v $ + Revision 1.16 2008/10/30 06:10:29 kondo_masahiro + Added WFSDEBUG_CMD_AREA_AND_DIR_CHECK_DISK + + Revision 1.15 2008/10/14 03:00:34 nakanose_jin + (none) + + Revision 1.14 2008/09/18 10:25:33 nakanose_jin + add new WFSDEBUG_CMD_* + + Revision 1.13 2008/08/29 01:14:57 kondo_masahiro + Added a flag WFSDEBUG_CMD_KRN_INIT_AREA_SECTORS. + + Revision 1.11 2008/06/26 00:21:30 kondo_masahiro + Added #define WFSDEBUG_CMD_SHIM_WORKSPACE. + + Revision 1.10 2008/05/23 02:00:33 nakanose_jin + add new command + + Revision 1.9 2008/05/10 04:20:22 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.8 2008/05/08 11:40:58 nakanose_jin + move WFSDebugSetTitleID wfsPerm.h => wfs_Debug.h + + Revision 1.7 2008/05/07 13:27:12 nakanose_jin + fix comment + + Revision 1.6 2008/04/25 12:06:38 nakanose_jin + add cmd (0x2) + + Revision 1.5 2008/04/18 07:53:33 nakanose_jin + merging acl + + Revision 1.4 2008/04/03 07:11:05 nakanose_jin + add extern C + + Revision 1.3 2008/03/31 04:24:58 nakanose_jin + add comments + + Revision 1.2 2008/03/31 00:58:52 nakanose_jin + add args for debugproc + + Revision 1.1 2008/03/26 01:11:50 nakanose_jin + WFS Debug functions for tool develpment + + Revision 1.6 2008/02/20 08:10:10 nakanose_jin + add WFSExecDebugProcedure + + Revision 1.5 2007/12/17 13:29:14 nakanose_jin + add debug utility function + + Revision 1.4 2007/11/02 00:25:10 paul + started logging changes in the file + +*---------------------------------------------------------------------------*/ + +#include +// #include "wfs_Defs.h" + +#ifndef __WFS_DEBUG_H__ +#define __WFS_DEBUG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//-------------------------------------------------------------------------------------------------------------- +// WFSDebugSetTitleId +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSDebugSetTitleId(WFSTitleId titleId); +// Arguments: +// ---------- +// titleId .. Title Id is assigned per application. Determines the ownership & access permissions of files. +// A value of WFS_ROOT_ID can be specified for SYSTEM level access to all files. +// groupId .. Group Id determines the GROUP access to files. Usually corresponds to a Company Id. +// +// Return Values: +// -------------- +// Possible return values for WFSDebugSetTitleId: +// WFS_RESULT_OK .. The search handle has been closed successfully. +// WFS_RESULT_INVALID .. The function parameters were invalid. +// +// Description: +// ------------ +// Allows the application to specify it's WFS Title Id, which will be used to determine access permissions to WFS files. +// NOTE: This function is for testing and debugging purposes only, and will be removed from the final API. +// NOTE: This function only affects WFS. It does not change the real Title Id. +// ToDo: This function should be removed before releasing to developers. + +/* + * for debug purpose only. + */ +WFSResult WFSDebugSrvTest(const char* deviceName); +WFSResult WFSDebugCloseServerSocket(void); +WFSResult WFSDebugCloseCallbackSocket(void); + +const char *WFSDebug_GetResultString(WFSResult result); +WFSResult WFSExecDebugProcedure( u32 cmd , void *arg0 , void *arg1 ); +const static u32 WFSDEBUG_CMD_DELETE_DEVICEROOT = 0; +const static u32 WFSDEBUG_CMD_DELETE_PATH = 1; +const static u32 WFSDEBUG_CMD_CLOSE_ALLFILE = 2; +const static u32 WFSDEBUG_CMD_DUMP_PERMISSION = 3; +const static u32 WFSDEBUG_CMD_SET_AUTO_FORMAT_ON_ATTACH = 4; +const static u32 WFSDEBUG_CMD_ATTACH = 5; +const static u32 WFSDEBUG_CMD_ATTACH_WRITE_PROTECTED = 6; +const static u32 WFSDEBUG_CMD_DETACH = 7; +const static u32 WFSDEBUG_CMD_PUSH_PATH = 8; +const static u32 WFSDEBUG_CMD_EXEC_BAT = 9; // +const static u32 WFSDEBUG_CMD_TOUCH = 10; + + +//#define WFSDEBUG_CMD_KRN_INIT_VIRTUAL_DISK 0x10 +#define WFSDEBUG_CMD_KRN_INIT_AREA_SECTORS 0x10 +#define WFSDEBUG_CMD_KRN_INIT_CACHE 0x11 +#define WFSDEBUG_CMD_DIR_CHECK_DNS_EMPTY 0x12 +#define WFSDEBUG_CMD_SHIM_WORKSPACE 0x13 +#define WFSDEBUG_CMD_AREA_AND_DIR_CHECK_DISK 0x14 + +#define WFSDEBUG_CMD_DEVICE_ATTACH_DETACH 0x20 +#define WFSDEBUG_CMD_DEVICE_PSEUDO_DETACH 0x21 +#define WFSDEBUG_CMD_DEVICE_PSEUDO_HASH_INCONSISTENT 0x22 +#define WFSDEBUG_CMD_DEVICE_SET_FLAGS 0x23 + +/* + + WFSDEBUG_CMD_DELETE_DEVICEROOT + brief: 指定パスを削除 + arg0 : ターゲットデバイス名 ( "msc1" 等 ) + arg1 : - + + WFSDEBUG_CMD_DELETE_PATH + brief: 指定パスを削除(マウント中でなくてもよい) + arg0 : ターゲットデバイス名 ( "msc1" 等) + arg1 : ターゲットパス *1 ( "/titles" 等) + + WFSDEBUG_CMD_CLOSE_ALLFILE + brief: オープンされたままのファイルを全て閉じます。 + arg0 : ターゲットボリューム名 + arg1 : - + + WFSDEBUG_CMD_DUMP_PERMISSION + brief: 指定パスのパーミッション情報表示 (マウント中でなくてもよい) + arg0 : ターゲットデバイス名 ( "msc1" 等) + arg1 : ターゲットパス *1 ( "/titles" 等) + + WFSDEBUG_CMD_SET_AUTO_FORMAT_ON_ATTACH + brief: アタッチ時にデバイスが未フォーマットであれば必要なシステム情報を付加する/しない (default:する) + arg0 : true/false + arg1 : - + + WFSDEBUG_CMD_ATTACH + WFSDEBUG_CMD_ATTACH_WRITE_PROTECTED + brief: 指定デバイスをアタッチします。WFSDevAttach.exe [-p] arg0 arg1 と同等です。 + arg0 : ターゲットデバイス名 ( ex. "msc1") + arg1 : 仮想ボリュームルートの物理パス ( ex. "D:\iifstest\msc01" ) + + WFSDEBUG_CMD_DETACH + brief: 指定デバイスをデタッチします。WFSDevAttach.exe -d arg0 と同等です。 + arg0 : ターゲットデバイス名 ( ex. "msc1") + arg1 : - + + WFSDEBUG_CMD_EXEC_BAT + brief: 任意のコマンドを実行。 + 使用に際しては安全上の理由から必要最小限にとどめることを推奨します。 + バッチファイル内の操作で誤って重要ファイルを消したりしないよう重々ご注意下さい。 + arg0 : ターゲット実行ファイル ( 絶対パス指定のみ。ex. "H:\\iifstest\\bin\\ready_testLongPathName.bat" ) + arg1 : ターゲット実行時パス ( 絶対パス指定のみ。指定無し(NULL)でもOK。ex. "H:\\iifstest\\bin" ) + + + *1 : ボリュームルートをルートとする仮想パス +*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // __WFS_DEBUG_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/randomlib.h b/trunk/firmware/build/libraries/nfs/common/include/randomlib.h new file mode 100644 index 0000000..7593e6d --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/randomlib.h @@ -0,0 +1,26 @@ +#ifndef _RANDOMLIB_H +#define _RANDOMLIB_H + +#include "revolution.h" + +/* +#if _IOP +#include "types.h" +#else +#include "revolution/types.h" +#endif +*/ + +#include "wfs_Platform.h" + +void RandomInitialise(int ij, int kl); +double RandomUniform(void); +double RandomGaussian(double mean, double stddev); +int RandomInt(int lower, int upper); +double RandomDouble(double lower, double upper); +u32 RandomU32(); + +#define NUM_UNIQUE_RANDOM_SEEDS_U32 0x382C7A42 +void RandomSetSeedU32(u32 nSeed); + +#endif diff --git a/trunk/firmware/build/libraries/nfs/common/include/revolution.h b/trunk/firmware/build/libraries/nfs/common/include/revolution.h new file mode 100644 index 0000000..066e9de --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/revolution.h @@ -0,0 +1,17 @@ +#ifndef __REVOLUTION_H__ +#define __REVOLUTION_H__ + +#include +#include +#include +//#include +//#include + +typedef u32 OSPriority; + +#define ASSERT SDK_ASSERT + +//typedef BOOL bool; +//typedef BOOL WFSBool; + +#endif // __REVOLUTION_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/revolution/__mem.h b/trunk/firmware/build/libraries/nfs/common/include/revolution/__mem.h new file mode 100644 index 0000000..ddde003 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/revolution/__mem.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------* + Project: MEM library + File: mem.h + Programmers: Takano Makoto + + Copyright 2005 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + *---------------------------------------------------------------------------*/ + +#ifndef __MEM_H__ +#define __MEM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include +#include +#include +#include +#include +#include + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/* __MEM_H__ */ +#endif diff --git a/trunk/firmware/build/libraries/nfs/common/include/revolution/wfs.h b/trunk/firmware/build/libraries/nfs/common/include/revolution/wfs.h new file mode 100644 index 0000000..2429392 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/revolution/wfs.h @@ -0,0 +1,1444 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFS library + File: wfs.h - Provides a standard interface to the Wii file system + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs.h,v $ + Revision 1.104 2008/12/03 00:14:21 kondo_masahiro + Added a argument of WFSFlush(). + + Revision 1.103 2008/10/21 10:46:43 kondo_masahiro + Added new function WFSWriteFileAndDiscard + + Revision 1.102 2008/08/05 02:16:15 paul + removed unused error message WFS_RESULT_DIRECTORY_FULL + + Revision 1.101 2008/07/10 10:27:30 nakanose_jin + bye inheritance & dev_full error + + Revision 1.100 2008/07/02 06:52:43 nakanose_jin + bye inheritance & dev_full error + + Revision 1.99 2008/06/20 18:38:47 paul + Changed comment for WFSCreateDirectory + + Revision 1.98 2008/04/25 17:26:30 paul + Removed WFSExitAsync remnants. Updated nCidx comment. Updated nQuota comment. + + Revision 1.97 2008/04/08 18:19:58 paul + Moved permissions-related declarations to wfsPerm.h. Moved callback definitions to wfsTypes.h. Moved error-related definitions to wfsError.h. + + Revision 1.96 2008/03/31 14:04:02 ueno + Modified WFS_DP_*_EDIT and WFS_DP_INHERIT_DP_* bits to check if permissions are editable, easily. + Added permission masks. + + Revision 1.95 2008/03/26 02:06:19 ueno + Fixed typos. + + Revision 1.94 2008/03/25 09:11:49 ueno + Revised permission flags and permission APIs. + + Revision 1.93 2008/03/25 00:26:21 ueno + Added permission APIs. + + Revision 1.92 2008/02/08 09:50:22 paul + Added WFS_RESULT_DEV_IN_USE + + Revision 1.91 2008/02/08 04:39:05 paul + Changed bForce parameter of WFSUnmountVolume to WFSBool + + Revision 1.90 2008/02/08 01:32:24 nakanose_jin + WFSUnmountVolume : add force-closing option + + Revision 1.89 2008/02/07 13:02:47 nakanose_jin + WFSUnmountVolume : Add force-close option (but only in detach condition) + + Revision 1.88 2008/02/06 01:11:19 paul + Added new error code, WFS_RESULT_NOT_DIRECTORY for WFSSetCurrentDirectory and WFSSetHomeDirectory. + + Revision 1.87 2008/01/28 05:46:02 paul + Clarified the comment about file access permission during WFSCreateAndOpenFile + + Revision 1.86 2008/01/17 07:51:59 ooizumi + Moved several definitions to wfstypes.h. + + Revision 1.85 2008/01/10 09:34:35 nakanose_jin + bye - WFSExitAsync + + Revision 1.84 2007/12/12 19:58:56 paul + Clarified WFSSearchDirectoryFirst spec - handle is not created when an error occurs. + + Revision 1.83 2007/12/12 07:45:08 paul + Added WFSGetFileSizeAsync - WFSGetFileSize is no longer implemented on the client side + + Revision 1.82 2007/12/08 00:01:57 paul + Updated the comment for WFS_RESULT_LIB_NOT_INITIALIZED + + Revision 1.81 2007/11/27 02:58:20 nakanose_jin + add extern "C" + + Revision 1.80 2007/11/22 09:40:05 nakanose_jin + Add WFS_RESULT_NOT_FILE for WFSFileOpen + + Revision 1.79 2007/11/22 01:48:29 paul + Added nFileSize to WFSCloseFileAsync + + Revision 1.78 2007/11/21 22:15:41 paul + Added WFS_RESULT_ALREADY_MOUNTED + + Revision 1.77 2007/11/20 00:16:34 paul + Removed WFS_RESULT_BUSY from WFSGetFilePosition, WFSSetFilePosition, WFSGetFileSize. + + Revision 1.76 2007/11/16 13:12:04 nakanose_jin + modify comment for NOT_FOUND + + Revision 1.75 2007/11/16 02:33:57 paul + Changed error code for WFSMountDevice(). Now, trying to mount the same device twice results in WFS_RESULT_ALREADY_EXISTS error. + + Revision 1.74 2007/11/16 01:29:21 paul + Added WFSFlush() + + Revision 1.73 2007/11/15 23:40:42 paul + Updated device name errors to WFS_RESULT_NOT_FOUND + + Revision 1.72 2007/11/09 01:18:37 paul + Updated validation error checks for several functions + Updated max path depth + + Revision 1.71 2007/11/02 00:34:38 paul + now logging updates. + Changed WFSReadFileAsync, WFSWriteFileAsync to require explicit start position + +*---------------------------------------------------------------------------*/ + +#ifndef __WFS_H__ +#define __WFS_H__ + +// --------------------------------------------------------------------- +// wfs.h - Wii File System (WFS) API +// --------------------------------------------------------------------- + +// Provides a standard interface to the Wii file system + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + + +//------------------------------------------------------------------------------------------------------ +// WFS Path Names +//------------------------------------------------------------------------------------------------------ +// Throughout the WFS API, path names can be absolute, or relative to the CurrentDirectory. +// +// The following conventions are used: +// File names are read and written case-sensitively, but compared case-insensitively. +// File names can use any characters except * ? / +// WFS uses forwards slashes / as directory separators. +// * and ? are used to specify wild card patterns to directory search. +// Non-ascii file names are supported using the multi-byte utf-8 format. +// Path names must be NULL terminated. +// +// File names including . or ~ are possible, except: +// The following names have special meanings, and cannot be used as file names: "~", ".", ".." +// "" or "." refers to the current directory. +// ".." refers to the parent directory. +// "~" refers to a title's home directory. +// +// Path names starting with "/" are absolute. +// Path names starting with "~/" are relative to the title's home directory, +// otherwise they are relative to CurrentDirectory. +// +// All devices have a device name entry in "/dev". If the WFSDevType (obtained via WFSGetDeviceInfo) +// of the device is WFS_DEVTYPE_SD or WFS_DEVTYPE_USB_MSC, the device may or may not have +// a WFS volume. A WFS volume can be created on the device with WFSInitializeDevice. At volume +// creation time, the volume is assigned a (relatively) unique Volume Id. The device's WFS volume +// is made accessible by mounting it. After a volume is mounted, it is accessible as +// "/vol/VolumeId" where VolumeId is the volume's unique Id. The "/vol" directory has an entry for +// each mounted WFS volume. Even with mounted devices, a device name entry for mounted volumes +// remains in "/dev" for that device. +//------------------------------------------------------------------------------------------------------ + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSInit +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSInit(void *pWorkSpaceBuffer, u32 nWorkSpaceSize); +// Arguments: +// ---------- +// pWorkSpaceBuffer .. Points to a workspace buffer that will be used by WFS as workspace. Must be 64 Byte aligned. +// nWorkSpaceSize .. The size of the workspace buffer. Must be >= WFS_MIN_WORK_SPACE_SIZE. +// +// Return Values: +// -------------- +// Possible return values for WFSSetCurrentDirectory: +// WFS_RESULT_OK .. WFS has been successfully initialized +// WFS_RESULT_LIB_ALREADY_INITIALIZED .. WFS library has already been initialized. +// WFS_RESULT_INVALID .. The input parameters are invalid +// +// Description: +// ------------ +// Call this function to initialize the WFS library. +// NOTE: If an attach callback has been registered using WFSSetAttachDeviceCallback, +// it will be called for any existing attached devices during the processing of WFSInit + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSExit +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSExit(); +// Arguments: +// ---------- +// none +// +// Return Values: +// -------------- + +// Possible return values for WFSExit: +// WFS_RESULT_OK .. Successfully mounted the device. VolumeId has been added to the "/vol" directory. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_LIB_NOT_INITIALIZED .. The WFS library has not been initialized. +// +// Description: +// ------------ +// Waits until all outstanding operations have been completed, then closes the library and frees up +// the workspace memory specified in WFSInit. No further WFS calls can be made until the library +// is re-initialized. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSetAttachDeviceCallback +//-------------------------------------------------------------------------------------------------------------- +void WFSSetAttachDeviceCallback(utf8 *sDeviceNameBuffer, WFSDeviceCallback cbAttachDevice, void *pUserData); +// Arguments: +// ---------- +// sDeviceNameBuffer .. A pointer to a buffer of at least WFS_MAX_DEVICE_NAME_SIZE+1 bytes which will be overwritten with the +// NULL terminated device name, and passed to the callback. (output) +// cbAttachDevice .. A pointer to the function to call when a storage device is attached. +// pUserData .. Arbitrary user data that is passed to the callback function. +// +// Return Values: +// -------------- +// None. +// +// Description: +// ------------ +// This function is used to register callback functions for notification of storage devices or +// storage media being attached. +// +// NOTE: Already attached devices can be enumerated by passing "/dev/*" as the search pattern to WFSSearchDirectoryFirst. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetAttachDeviceCallback +//-------------------------------------------------------------------------------------------------------------- +void WFSGetAttachDeviceCallback(utf8 **psDeviceName, WFSDeviceCallback *pCbAttachDevice, void **ppUserData); +// Arguments: +// ---------- +// psDeviceName .. A pointer to a variable to receive the current value of the sDeviceNameBuffer pointer +// that was previously set using WFSSetAttachDeviceCallback. +// pCbAttachDevice .. A pointer to a variable to receive the current callback function pointer. +// ppUserData .. A pointer to a variable to receive the current user data pointer. +// +// Return Values: +// -------------- +// None. +// +// Description: +// ------------ +// This function is used to get information about the existing callback functions for notification of +// storage devices or storage media being attached. The information can be saved and restored later, +// or can be used to implement callback chaining. +// ("Callback chaining" means calling the old callback function from within the new callback function). + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSetDetachDeviceCallback +//-------------------------------------------------------------------------------------------------------------- +void WFSSetDetachDeviceCallback(utf8 *sDeviceNameBuffer, WFSDeviceCallback cbDetachDevice, void *pUserData); +// Arguments: +// ---------- +// sDeviceName .. A pointer to a buffer of at least WFS_MAX_DEVICE_NAME_SIZE+1 bytes, which is overwritten +// with the NULL terminated device name, and passed to the callback. (output) +// cbDetachDevice .. A pointer to the function to call when a storage device is detached. +// pUserData .. Arbitrary user data that is passed to the callback function. +// +// Return Values: +// -------------- +// None. +// +// Description: +// ------------ +// This function is used to register callback functions for notification of storage devices or +// storage media being detached. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetDetachDeviceCallback +//-------------------------------------------------------------------------------------------------------------- +void WFSGetDetachDeviceCallback(utf8 **psDeviceName, WFSDeviceCallback *pCbDetachDevice, void **ppUserData); +// Arguments: +// ---------- +// psDeviceName .. A pointer to a variable to receive the current value of the sDeviceName pointer +// that was previously set using WFSSetDetachDeviceCallback. +// pCbDetachDevice .. A pointer to a variable to receive the current callback function pointer. +// ppUserData .. A pointer to a variable to receive the current user data pointer. +// +// Return Values: +// -------------- +// None. +// +// Description: +// ------------ +// This function is used to get information about the existing callback functions for notification of +// storage devices or storage media being detached. The information can be saved and restored later, +// or can be used to implement callback chaining. +// ("Callback chaining" means calling the old callback function from within the new callback function). + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetDeviceInfo, WFSGetDeviceInfoAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSGetDeviceInfo (const utf8 *sDeviceName, WFSDeviceInfo *pDi); +WFSResult WFSGetDeviceInfoAsync(const utf8 *sDeviceName, WFSDeviceInfo *pDi, void *pUserData, WFSDeviceInfoCallback cb); +// Arguments: +// ---------- +// sDeviceName .. A pointer to the NULL terminated device name. (input) +// pDi .. A pointer to a WFSDeviceInfo struct to receive the requested device information. (output) +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a device callback function. +// +// Return Values: +// -------------- +// Possible return values for WFSGetDeviceInfo: +// WFS_RESULT_OK .. Successfully retrieved the device information. *pDi has been updated. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// Possible immediate return values for WFSGetDeviceInfoAsync: +// WFS_RESULT_OK .. GetDeviceInfo request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid. +// Possible values of nResult passed to WFSGetDeviceInfoAsync callback: +// WFS_RESULT_OK .. Successfully retrieved the device information. *pDi has been updated. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// +// Description: +// ------------ +// These functions return the device information associated with a device name. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSMountDevice, WFSMountDeviceAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSMountDevice (const utf8 *sDeviceName, utf8 *sVolumeIdBuffer); +WFSResult WFSMountDeviceAsync(const utf8 *sDeviceName, utf8 *sVolumeIdBuffer, void *pUserData, WFSDeviceVolumeCallback cb); +// Arguments: +// ---------- +// sDeviceName .. A pointer to the NULL terminated device name. (input) +// sVolumeIdBuffer .. A pointer to a buffer of at least WFS_MAX_VOLUME_ID+1 bytes which will be overwritten with the +// NULL terminated volume id. (output) +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a device callback function. +// +// Return Values: +// -------------- +// Possible return values for WFSMountDevice: +// WFS_RESULT_OK .. Successfully mounted the device. VolumeId has been added to the "/vol" directory. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sDeviceName is too long, sVolumeIdBuffer is NULL. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_DEV_UNUSABLE .. Device is not accessible, e.g. because it is an unsupported device, or has an unknown format. +// WFS_RESULT_DEV_NOT_INITIALIZED .. Device not formatted, or does not yet contain a WFS volume +// WFS_RESULT_VOL_ID_ERROR .. Device has the same Id as an already mounted device. (This could happen if the User backs up an entire WFS volume using a PC) +// WFS_RESULT_ALREADY_MOUNTED .. The device is already mounted. +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// Possible immediate return values for WFSMountDeviceAsync: +// WFS_RESULT_OK .. WFSMountDevice request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sDeviceName is too long, sVolumeIdBuffer is NULL. +// Possible values of nResult passed to WFSMountDeviceAsync callback: +// WFS_RESULT_OK .. Successfully mounted the device. VolumeId has been added to the "/vol" directory. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_DEV_UNUSABLE .. Device is not accessible, e.g. because it is an unsupported device, or has an unknown format. +// WFS_RESULT_DEV_NOT_INITIALIZED .. Device not formatted, or does not yet contain a WFS volume +// WFS_RESULT_VOL_ID_ERROR .. Device has the same Id as an already mounted device. (This could happen if the User backs up an entire WFS volume using a PC) +// WFS_RESULT_ALREADY_MOUNTED .. The device is already mounted. +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName +// +// Description: +// ------------ +// These functions are used to mount a WFS volume. +// The mount point is "/vol/VolumeId" as described in "WFS Path Names". + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSUnmountVolume, WFSUnmountVolumeAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSUnmountVolume (const utf8 *sVolumeId, WFSBool bForce); +WFSResult WFSUnmountVolumeAsync(const utf8 *sVolumeId, WFSBool bForce, void *pUserData, WFSUnmountVolumeCallback cb); +// Arguments: +// ---------- +// sVolumeId .. pointer to a string buffer containing the mounted Volume Id. +// bForce .. If set to TRUE, forces the volume to be unmounted regardless of open files. +// NOTE: This flag is only valid if the device is currently detached. Un-flushed data will be lost. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a device callback function. +// +// Return Values: +// -------------- +// Possible return values for WFSUnmountVolume: +// WFS_RESULT_OK .. Successfully unmounted the device. The Volume Id has been removed from the "/vol" directory. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. sVolumeId is too long, or NULL. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_FILE_OPEN .. The volume cannot be closed because one or more files within it are currently open. +// WFS_RESULT_NOT_FOUND .. No mounted volume exists which matches sVolumeId. +// Possible immediate return values for WFSUnmountVolumeAsync: +// WFS_RESULT_OK .. WFSMountDevice request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. sVolumeId is too long, or NULL. +// Possible values of nResult passed to WFSUnmountVolumeAsync callback: +// WFS_RESULT_OK .. Successfully unmounted the device. The Volume Id has been removed from the "/vol" directory. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_FILE_OPEN .. The volume cannot be closed because one or more files within it are currently open. +// WFS_RESULT_NOT_FOUND .. No mounted volume exists which matches sVolumeId +// +// Description: +// ------------ +// These functions are used to unmount a WFS volume. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSInitializeDevice, WFSInitializeDeviceAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSInitializeDevice (const utf8 *sDeviceName); +WFSResult WFSInitializeDeviceAsync(const utf8 *sDeviceName, void *pUserData, WFSInitializeDeviceCallback cb); +// Arguments: +// ---------- +// sDeviceName .. A pointer to the NULL terminated device name. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a device callback function. +// +// Return Values: +// -------------- +// Possible return values for WFSInitializeDevice: +// WFS_RESULT_OK .. Initialization was successful. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid. e.g. sDeviceName is too long, or NULL. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_DEV_UNUSABLE .. Unable to initialize device. +// WFS_RESULT_DEV_IN_USE .. Trying to initialize a device which is in use (mounted) by one or more clients. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. The device may not be initialized by the calling application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// Possible immediate return values for WFSInitializeDeviceAsync: +// WFS_RESULT_OK .. Initialization request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid. e.g. sDeviceName is too long, or NULL. +// Possible values of nResult passed to WFSInitializeDeviceAsync callback: +// WFS_RESULT_OK .. Initialization was successful. +// WFS_RESULT_DEV_UNUSABLE .. Unable to initialize device. +// WFS_RESULT_DEV_IN_USE .. Trying to initialize a device which is in use (mounted) by one or more clients. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. The device may not be initialized by the calling application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// +// Description: +// ------------ +// These functions can be used to initialize a device (format, and create a WFS volume on the device). +// When the volume is created it is assigned a (relatively) unique Volume Id. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetVolumeId, WFSGetVolumeIdAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSGetVolumeId (const utf8 *sDeviceName, utf8 *sVolumeIdBuffer); +WFSResult WFSGetVolumeIdAsync(const utf8 *sDeviceName, utf8 *sVolumeIdBuffer, void *pUserData, WFSDeviceVolumeCallback cb); +// Arguments: +// ---------- +// sDeviceName .. A pointer to the NULL terminated device name. (input) +// sVolumeIdBuffer .. A pointer to a buffer of at least WFS_MAX_VOLUME_ID+1 bytes which will be overwritten with the volume id. (output) +// pDi .. A pointer to a WFSDeviceInfo struct to receive the requested device information. (output) +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a device callback function. +// +// Return Values: +// -------------- +// Possible return values for WFSGetVolumeId: +// WFS_RESULT_OK .. Successfully retrieved the device information. *sVolumeId has been updated. (In all other cases sVolumeId is unchanged) +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid. e.g. sDeviceName is too long or NULL, sVolumeIdBuffer is NULL. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_DEV_NOT_INITIALIZED .. No WFS volume exists on the device. +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// Possible immediate return values for WFSGetVolumeIdAsync: +// WFS_RESULT_OK .. GetDeviceInfo request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sDeviceName is too long or NULL, sVolumeIdBuffer is NULL. +// Possible values of nResult passed to WFSGetVolumeIdAsync callback: +// WFS_RESULT_OK .. Successfully retrieved the device information. *sVolumeId has been updated. (In all other cases sVolumeId is unchanged) +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_DEV_NOT_INITIALIZED .. No WFS volume exists on the device. +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// +// Description: +// ------------ +// These functions can be used to determine if a volume exists, and if so retrieve the volume id. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetFreeSpaceSize, WFSGetFreeSpaceSizeAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSGetFreeSpaceSize (const utf8 *sPathName, u64 *pSize); +WFSResult WFSGetFreeSpaceSizeAsync(const utf8 *sPathName, void *pUserData, WFSGetFreeSpaceCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of a file or directory. +// See "WFS Path Names" for rules about path names. +// pSize .. A pointer to a u64 to receive the free space size value. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSGetFreeSpaceSizeAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSGetFreeSpaceSize +// WFS_RESULT_OK .. Successfully calculated the free space size. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sPathName is too long, too deep, or NULL; or pSize is NULL. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_PERMISSION .. you have no list permission on this object. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_NOT_FOUND .. The specified path does not exist. +// Possible immediate return values for WFSGetFreeSpaceSizeAsync: +// WFS_RESULT_OK .. GetDeviceInfo request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sPathName is too long, too deep, or NULL. +// Possible values of nResult passed to WFSGetDeviceInfoAsync callback: +// WFS_RESULT_OK .. Successfully calculated the free space size. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_PERMISSION .. you have no list permission on this object. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_NOT_FOUND .. The specified path does not exist. +// +// Description: +// ------------ +// Use this function to calculate the number of bytes free on the device associated with a path name. +// The result also depends on the TitleId of the calling process, since titles would typically have +// a fixed storage quota assigned. +// +// Examples: +// Applying these functions to "/vol/VolumeId/tmp" would return the remaining free space quota +// of the shared tmp directory. +// Applying these functions to "/vol/VolumeId/titles/CompanyId/TitleId", would +// return the remaining free space quota of the title's home directory. +// Applying these functions to "/vol/VolumeId/" would return the sum of the +// free space quotas of the shared tmp directory, and the title's home directory. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSetHomeDirectory, WFSSetHomeDirectoryAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSetHomeDirectory (const utf8 *sAbsPathName); +WFSResult WFSSetHomeDirectoryAsync(const utf8 *sAbsPathName, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sAbsPathName .. absolute path name to a valid directory. +// pUserData .. arbitrary user data that is passed to the callback function. +// cb .. pointer to a callback function to receive the result of WFSCreateDirectoryAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSetHomeDirectory: +// WFS_RESULT_OK .. The directory is valid, and prepared for access. Only in this case is the home directory changed. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. sAbsPathName was invalid: e.g. too long, too deep, or NULL. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. This function is only available to SYSTEM. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to access directory. +// WFS_RESULT_NOT_FOUND .. The specified directory does not exist. +// WFS_RESULT_NOT_DIRECTORY .. The specified path is not a directory. +// Possible immediate return values for WFSSetHomeDirectoryAsync: +// WFS_RESULT_OK .. SetCurrentDirectory request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. sAbsPathName was invalid: e.g. too long, too deep, or NULL. +// Possible values of nResult passed to WFSSetHomeDirectoryAsync callback: +// WFS_RESULT_OK .. The directory is valid, and prepared for access. Only in this case is the home directory changed. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. This function is only available to SYSTEM. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to access directory. +// WFS_RESULT_NOT_FOUND .. The specified directory does not exist. +// WFS_RESULT_NOT_DIRECTORY .. The specified path is not a directory. +// +// Description: +// ------------ +// Sets the internal home directory which can be used at the start of relative path names as ~/ +// This function will check that the specified directory exists. +// This function is intended for use by the application launcher. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSetCurrentDirectory, WFSSetCurrentDirectoryAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSetCurrentDirectory (const utf8 *sPathName); +WFSResult WFSSetCurrentDirectoryAsync(const utf8 *sPathName, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. absolute or relative path name to a valid directory. +// See "WFS Path Names" for rules about path names. +// pUserData .. arbitrary user data that is passed to the callback function. +// cb .. pointer to a callback function to receive the result of WFSCreateDirectoryAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSetCurrentDirectory: +// WFS_RESULT_OK .. The directory is valid, and prepared for access. Only in this case is the current directory changed. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. sPathName was invalid: e.g. too long, too deep, or NULL. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. you have no list permission on this object. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to access directory. +// WFS_RESULT_NOT_FOUND .. The specified directory does not exist. +// WFS_RESULT_NOT_DIRECTORY .. The specified path is not a directory. +// Possible immediate return values for WFSSetCurrentDirectoryAsync: +// WFS_RESULT_OK .. SetCurrentDirectory request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. sPathName was invalid: e.g. too long, too deep, or NULL. +// Possible values of nResult passed to WFSSetCurrentDirectoryAsync callback: +// WFS_RESULT_OK .. The directory is valid, and prepared for access. Only in this case is the current directory changed. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. you have no list permission on this object. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to access directory. +// WFS_RESULT_NOT_FOUND .. The specified directory does not exist. +// WFS_RESULT_NOT_DIRECTORY .. The specified path is not a directory. +// +// Description: +// ------------ +// Sets the internal current directory which is used to resolve relative path names. +// This function will check that the specified directory exists and is accessable to the current application. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetCurrentDirectory +//-------------------------------------------------------------------------------------------------------------- +s32 WFSGetCurrentDirectory(utf8 *sAbsPathNameBuffer, s32 nBufferSize); +// Arguments: +// ---------- +// sAbsPathNameBuffer .. A pointer to a buffer to receive a copy of the absolute path name of the Current Directory. +// nBufferSize .. size of the buffer. +// +// Return Values: +// -------------- +// >0 .. nBufferSize was not large enough. This is the number of bytes required to hold +// the path name of the current directory including the terminating NULL character. +// WFS_RESULT_OK .. The absolute path name of the current directory was copied to the user buffer. +// WFS_RESULT_INVALID .. The input parameters were invalid, e.g. sAbsPathNameBuffer is NULL. +// WFS_RESULT_LIB_NOT_INITIALIZED .. The WFS library has not been initialized. Please call WFSInit(..) +// +// Description: +// ------------ +// Copies the current directory to the buffer pointed to by sAbsPathName. +// nBufferSize should contain the size of the buffer including terminating NULL character. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSCreateDirectory, WFSCreateDirectoryAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSCreateDirectory (const utf8 *sPathName, u32 nFlags, u64 nQuota); +WFSResult WFSCreateDirectoryAsync(const utf8 *sPathName, u32 nFlags, u64 nQuota, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of the directory that is to be created. +// See "WFS Path Names" for rules about path names. +// nFlags .. should be a combination of the permission or wfs flags: WFS_FLAG_* or WFS_PERM_* (see wfsPerm.h) +// Note: WFS_FLAG_DIRECTORY will be set whether it is included or not. +// nQuota .. This parameter can be used to restrict the total size of the hierarchy beneath the new directory. +// The quota includes space for meta-data, so the total usable data size will be less than the quota. +// A quota of 0 means there is no size restriction, i.e. the quota is Infinity. +// Otherwise the quota must be >= WFS_MIN_DIRECTORY_QUOTA. +// The directory will be allocated as a contiguous area if (nFlags & WFS_FLAG_CONTIGUOUS_AREA) && (nQuota >= WFS_MIN_DIRECTORY_QUOTA) +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSCreateDirectoryAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSCreateDirectory: +// WFS_RESULT_OK .. The directory was created. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Path is too deep. (For directories the depth limit is 1 less than for files). +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the parent directory do not permit WRITE access to this application. +// WFS_RESULT_AUTHENTICATION .. Could occur when writing to a directory belonging to another App, whose access key no longer exists. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to create the directory. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_ALREADY_EXISTS .. A directory or file with the same name already exists. +// WFS_RESULT_NOT_FOUND .. Could not find the parent directory specified in the path name. +// Possible immediate return values for WFSCreateDirectoryAsync: +// WFS_RESULT_OK .. CreateDirectory request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Path is too deep. (For directories the depth limit is 1 less than for files). +// Possible values of nResult passed to WFSCreateDirectoryAsync callback: +// WFS_RESULT_OK .. The directory was created. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the parent directory do not permit WRITE access to this application. +// WFS_RESULT_AUTHENTICATION .. Could occur when writing to a directory belonging to another App, whose access key no longer exists. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to create the directory. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_ALREADY_EXISTS .. A directory or file with the same name already exists. +// WFS_RESULT_NOT_FOUND .. Could not find the parent directory specified in the path name. +// +// Description: +// ------------ +// Use these functions to create directories. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSCreateAndOpenFile, WFSCreateAndOpenFileAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSCreateAndOpenFile (const utf8 *sPathName, u32 nFlags, WFSContentIdx nCidx, WFSFileSize nPreAllocateSize, WFSFileHandle *pFh); +WFSResult WFSCreateAndOpenFileAsync(const utf8 *sPathName, u32 nFlags, WFSContentIdx nCidx, WFSFileSize nPreAllocateSize, void *pUserData, WFSFileOpCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of the file that is to be created and opened. +// See "WFS Path Names" for rules about path names. +// nFlags .. should be a combination of the permission flags: WFS_PERM_* (see wfsPerm.h) +// Note: This function will always open the file for writing, even if nFlags==WFS_PERM_OWNER_READ_ONLY. +// The specified permissions only take effect after the file is closed, and opened again. +// nCidx .. The content idx of the file being created. Content idx is the unit of access control for purchased content. +// For game-save or temporary files, set nCidx to 0. Files having nCidx >0 is referred to as "Content". +// nPreAllocateSize .. The amount of disk-space to pre-allocate for the file. This can be used to assist the file system +// with reducing disk fragamentation. If the eventual size is unknown, set nPreAllocateSize to 0. +// nPreAllocateSize can be used in conjunction with the NO_CHANGE_SIZE flag to allocate a fixed size file. +// pFh .. A pointer to a file handle which is passed back by the library. +// The file handle should be used to specify this file in subsequent file operations. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSCreateAndOpenFileAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSCreateAndOpenFile: +// WFS_RESULT_OK .. The file was created. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Filename is too long, Path is too deep. +// WFS_RESULT_MAX_HANDLES .. Maximum number of concurrent file handles already in use. (Too many files open). +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the parent directory do not permit WRITE access to this application. +// WFS_RESULT_AUTHENTICATION .. Could occur when writing to a directory belonging to another App, whose access key no longer exists. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to create the file. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_ALREADY_EXISTS .. A directory or file with the same name already exists. +// WFS_RESULT_NOT_FOUND .. Could not find the parent directory specified in the path name. +// Possible immediate return values for WFSCreateAndOpenFileAsync: +// WFS_RESULT_OK .. CreateAndOpen request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Filename is too long, Path is too deep. +// Possible values of nResult passed to WFSCreateAndOpenFileAsync callback: +// WFS_RESULT_OK .. The file was created. +// WFS_RESULT_MAX_HANDLES .. Maximum number of concurrent file handles already in use. (Too many files open). +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the parent directory do not permit WRITE access to this application. +// WFS_RESULT_AUTHENTICATION .. Could occur when writing to a directory belonging to another App, whose access key no longer exists. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to create the file. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_ALREADY_EXISTS .. A directory or file with the same name already exists. +// WFS_RESULT_NOT_FOUND .. Could not find the parent directory specified in the path name. +// +// Description: +// ------------ +// Use these functions to create and open new files. +// These functions cannot be used to overwrite existing files (or directories). Use WFSDelete first. +// Note: This function will always open the file with WFS_ACCESS_RW access permission, even if +// nFlags==WFS_PERM_OWNER_READ_ONLY. The specified permission flags only take effect after +// the file is closed, and opened again. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetAttributes, WFSGetAttributesAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSGetAttributes (const utf8 *sPathName, WFSFileAttributes *pFa); +WFSResult WFSGetAttributesAsync(const utf8 *sPathName, WFSFileAttributes *pFa, void *pUserData, WFSGetAttributesCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of a file or directory. +// See "WFS Path Names" for rules about path names. +// pFa .. A pointer to a WFSFileAttributes struct which will be overwritten with the details of the specified file or directory. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSGetAttributesAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSGetAttributes: +// WFS_RESULT_OK .. The specified file or directory was found. Details are returned in *pFi. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// Possible immediate return values for WFSGetAttributesAsync: +// WFS_RESULT_OK .. The request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// Possible values of nResult passed to WFSGetAttributesAsync callback: +// WFS_RESULT_OK .. The specified file or directory was found. Details are returned in *pFi. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// +// Description: +// ------------ +// Use these functions to read the attributes of a file or directory. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSDelete, WFSDeleteAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSDelete (const utf8 *sPathName); +WFSResult WFSDeleteAsync(const utf8 *sPathName, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of the file or directory which is to be deleted. +// See "WFS Path Names" for rules about path names. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSChangePermissionsAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSDelete: +// WFS_RESULT_OK .. Target was deleted successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the delete operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the parent directory does not permit WFS_PERM_D_CHANGE access from this application, or permission flags of the target do not allow WFS_PERM_*_DELETE_MOVE access. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory does not exist. +// WFS_RESULT_NOT_EMPTY .. Cannot delete a directory that is not empty. +// WFS_RESULT_FILE_OPEN .. Cannot delete an open file. +// Possible immediate return values for WFSDeleteAsync: +// WFS_RESULT_OK .. Delete request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// Possible values of nResult passed to WFSDeleteAsync callback: +// WFS_RESULT_OK .. Target was deleted successfully +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the delete operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the parent directory does not permit WFS_PERM_D_CHANGE access from this application, or permission flags of the target do not allow WFS_PERM_*_DELETE_MOVE access. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory does not exist. +// WFS_RESULT_NOT_EMPTY .. Cannot delete a directory that is not empty. +// WFS_RESULT_FILE_OPEN .. Cannot delete an open file. +// +// Description: +// ------------ +// Use these functions to delete files or directories. +// To delete a file, it must not be open. To delete a directory, it must be empty. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSMoveLocal, WFSMoveLocalAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSMoveLocal (const utf8 *sSrcPathName, const utf8 *sDstPathName); +WFSResult WFSMoveLocalAsync(const utf8 *sSrcPathName, const utf8 *sDstPathName, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sSrcPathName .. Relative or absolute path to the source file. +// sDstPathName .. Relative or absolute path to the destination file. +// See "WFS Path Names" for rules about path names. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSMoveLocalAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSMoveLocal: +// WFS_RESULT_OK .. Target was moved successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Trying to move between different devices, Trying to move a directory to it's own sub-directory, File name is too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the move operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the source or destination parent directories do not permit WFS_PERM_D_CHANGE access from this application, or permission flags of the target do not allow WFS_PERM_*_DELETE_MOVE access. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_ALREADY_EXISTS .. A directory or file with the same name as the destination path already exists. +// WFS_RESULT_NOT_FOUND .. The specified source file or path does not exist. +// WFS_RESULT_FILE_OPEN .. Cannot move or rename an open file, or a directory hirearchy which contains an open file, or open search handle. +// Possible immediate return values for WFSMoveLocalAsync: +// WFS_RESULT_OK .. Move request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Trying to move between different devices, Trying to move a directory to it's own sub-directory, File name is too long, Path is too deep. +// Possible values of nResult passed to WFSMoveLocalAsync callback: +// WFS_RESULT_INVALID .. After moving sSrcPathName to the new location, it's deepest descendent path name would be too long, or too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the move operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the source or destination parent directories do not permit WFS_PERM_D_CHANGE access from this application, or permission flags of the target do not allow WFS_PERM_*_DELETE_MOVE access. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_ALREADY_EXISTS .. A directory or file with the same name as the destination path already exists. +// WFS_RESULT_NOT_FOUND .. The specified source file or path does not exist. +// WFS_RESULT_FILE_OPEN .. Cannot move or rename an open file, or a directory hirearchy which contains an open file, or open search handle. +// +// Description: +//------------ +// Use these functions to move or rename files or directories within the same volume. +// NOTE 1: These functions cannot be used to move a file from one volume to a different volume. +// NOTE 2: Moving or Renaming a file may cause the number of blocks required to store the directory information to increase, +// therefore errors associated with capacity are possible. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSOpenFile, WFSOpenFileAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSOpenFile (const utf8 *sPathName, WFSAccess nDesiredAccess, WFSFileHandle *pFh); +WFSResult WFSOpenFileAsync(const utf8 *sPathName, WFSAccess nDesiredAccess, void *pUserData, WFSFileOpCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of the file which is to be opened. +// See "WFS Path Names" for rules about path names. +// nDesiredAccess .. The kind of access that is required: should be one of the WFS_ACCESS_* options. +// pFh .. A pointer to a file handle which is passed back by the library. +// The file handle should be used to specify this file in subsequent file operations. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSOpenAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSOpen: +// WFS_RESULT_OK .. File was opened successfuly. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// WFS_RESULT_MAX_HANDLES .. Maximum number of concurrent file handles already in use. (Too many files open). +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the open operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Trying to open a file for write access, but device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the target do not permit requested access from this application (WFS_PERM_*_READ or WFS_PERM_*_WRITE). +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to open the file. +// WFS_RESULT_NOT_FOUND .. The specified file or path does not exist. +// WFS_RESULT_NOT_FILE .. The specified file is a directory. +// WFS_RESULT_FILE_OPEN .. Cannot open a file more than once unless all opens are WFS_ACCESS_READ. +// Possible immediate return values for WFSOpenAsync: +// WFS_RESULT_OK .. Open request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// Possible values of nResult passed to WFSOpenAsync callback: +// WFS_RESULT_OK .. File was opened successfuly. +// WFS_RESULT_MAX_HANDLES .. Maximum number of concurrent file handles already in use. (Too many files open). +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the open operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Trying to open a file for write access, but device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the target do not permit requested access from this application (WFS_PERM_*_READ or WFS_PERM_*_WRITE). +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to open the file. +// WFS_RESULT_NOT_FOUND .. The specified file or path does not exist. +// WFS_RESULT_FILE_OPEN .. Cannot open a file more than once unless all opens are WFS_ACCESS_READ. +// +// Description: +// ------------ +// Use these functions to open files for reading, writing, or both. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSetFilePosition +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSetFilePosition(WFSFileHandle fh, WFSFileSize nFilePosition); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// nFilePosition .. The absolute file position to set. +// +// Return Values: +// -------------- +// Possible return values for WFSSetFilePosition: +// WFS_RESULT_OK .. The file postion has been updated successfully. +// WFS_RESULT_INVALID .. Invalid file handle, or the position specified is beyond the end of the file. +// +// Description: +// ------------ +// This function can be used to set the absolute file position of an opened file (i.e. seek). No Async +// version is provided because this function does not need to access the storage device, and returns quickly. +// The file position is used and updated by WFSReadFile, WFSWriteFile, but not WFSReadFileAsync, WFSWriteFileAsync. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetFilePosition +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSGetFilePosition(WFSFileHandle fh, WFSFileSize *pFilePosition); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// pFilePosition .. A pointer to a variable which will be overwritten with the absolute file position. +// +// Return Values: +// -------------- +// Possible return values for WFSGetFilePosition: +// WFS_RESULT_OK .. Success. *pFilePosition contains the absolute file position. +// WFS_RESULT_INVALID .. Invalid file handle. +// +// Description: +// ------------ +// This function can be used to get the absolute file position of an opened file. No Async version +// is provided because this function does not need to access the storage device, and returns quickly. +// The file position is used and updated by WFSReadFile, WFSWriteFile, but not WFSReadFileAsync, WFSWriteFileAsync. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetFileSize, WFSGetFileSizeAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSGetFileSize (WFSFileHandle fh, WFSFileSize *pFileSize); +WFSResult WFSGetFileSizeAsync(WFSFileHandle fh, void *pUserData, WFSGetFileSizeCallback cb); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// pFileSize .. A pointer to a variable which will be overwritten with the file size (in Bytes). +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSGetFileSizeAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSetFileSize: +// WFS_RESULT_OK .. Success. *pFileSize contains the file size. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. Invalid file handle. +// Possible immediate return values for WFSGetFileSizeAsync: +// WFS_RESULT_OK .. The command was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_INVALID .. Invalid file handle. +// Possible values of nResult passed to WFSGetFileSizeAsync callback: +// WFS_RESULT_OK .. Success. The file size is passed in the nFileSize parameter of the callback. +// +// Description: +// ------------ +// These functions can be used to get the file size of an opened file. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSReadFile, WFSReadFileAsync +//-------------------------------------------------------------------------------------------------------------- +s32 WFSReadFile (WFSFileHandle fh, void *pFileDataBuffer, s32 nSize); +WFSResult WFSReadFileAsync(WFSFileHandle fh, void *pFileDataBuffer, WFSFileSize nStartPosition, s32 nSize, void *pUserData, WFSReadFileCallback cb); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// pFileDataBuffer .. Points to a buffer which will be overwritten with data from the file. +// nStartPosition .. The offset from the start of the file to start reading from. (Async version only). +// nSize .. The number of bytes to be read. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSReadAsync. +// +// Return Values: +// -------------- +// The return value is the number of bytes read, or one of the Error return values: +// Possible return values for WFSRead: +// >=0 .. Number of bytes read (May be less than requested if the end of the file is reached) +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle, pFileDataBuffer is NULL. +// WFS_RESULT_ACCESS .. The file was opened with WFS_ACCESS_WRITE_ONLY. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the read operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while reading the file. +// Possible immediate return values for WFSReadAsync (prior to start of read command): +// WFS_RESULT_OK .. Read request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle, pFileDataBuffer is NULL. +// WFS_RESULT_ACCESS .. The file was opened with WFS_ACCESS_WRITE_ONLY. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media has been removed since the file was opened. +// Possible values of nResult passed to WFSReadAsync callback: +// >=0 .. Number of bytes read (May be less than requested if the end of the file is reached). +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the read operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while reading the file. +// +// Description: +// ------------ +// This function is used to read data from a file that has been opened for reading. +// The file position will be advanced by the number of bytes read. +// Note: WFSReadFile automatically advances a file pointer stored within the library, whereas WFSReadFileAsync does not. +// WFSReadFileAsync requires the start position to be specified in the call. + + +//-------------------------------------------------------------------------------------------------------------- +// WFSWriteFile, WFSWriteFileAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSWriteFile (WFSFileHandle fh, const void *pFileData, WFSFileSize nSize); +WFSResult WFSWriteFileAsync(WFSFileHandle fh, const void *pFileData, WFSFileSize nStartPosition, WFSFileSize nSize, void *pUserData, WFSFileOpCallback cb); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// pFileData .. Points to the data to be written to the file. +// nStartPosition .. The offset from the start of the file to start writing to. (Async version only). +// nSize .. The number of bytes to be written. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSWriteAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSWrite: +// WFS_RESULT_OK .. Write completed successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle, pFileData is NULL. +// WFS_RESULT_ACCESS .. The file was opened with WFS_ACCESS_READ. +// WFS_RESULT_FILE_TOO_BIG .. This write operation would cause the file to go over the file size limit. +// WFS_RESULT_NO_CHANGE_SIZE .. This write operation would cause the file size to increase, but the WFS_PERM_NO_CHANGE_SIZE flag is set. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed since the file was opened +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the write completed. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while writing to the file. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// Possible immediate return values for WFSWriteAsync (prior to start of write command): +// WFS_RESULT_OK .. Write request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle, pFileData is NULL. +// WFS_RESULT_ACCESS .. The file was opened with WFS_ACCESS_READ. +// WFS_RESULT_FILE_TOO_BIG .. This write operation would cause the file to go over the file size limit. +// WFS_RESULT_NO_CHANGE_SIZE .. This write operation would cause the file size to increase, but the WFS_PERM_NO_CHANGE_SIZE flag is set. +// Possible values of nResult passed to WFSWriteAsync callback: +// WFS_RESULT_OK .. Write completed successfully. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the write operation completed. +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the write completed . +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while writing to the file. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// +// Description: +// ------------ +// This function is used to write data to a file that has been opened for writing. +// Data will be overwritten or appended to the file, starting from the current cursor position. +// Note: WFSWriteFile automatically advances a file pointer stored within the library, whereas WFSWriteFileAsync does not. +// WFSWriteFileAsync requires the start position to be specified in the call. + + +//-------------------------------------------------------------------------------------------------------------- +// WFSWriteFileAndDiscardData, WFSWriteFileAndDiscardDataAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSWriteFileAndDiscard (WFSFileHandle fh, const void *pFileData, WFSFileSize nSize); +WFSResult WFSWriteFileAndDiscardAsync(WFSFileHandle fh, const void *pFileData, WFSFileSize nStartPosition, WFSFileSize nSize, void *pUserData, WFSFileOpCallback cb); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// pFileData .. Points to the data to be written to the file. +// nStartPosition .. The offset from the start of the file to start writing to. (Async version only). +// nSize .. The number of bytes to be written. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSWriteAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSWrite: +// WFS_RESULT_OK .. Write completed successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle, pFileData is NULL. +// WFS_RESULT_ACCESS .. The file was opened with WFS_ACCESS_READ. +// WFS_RESULT_FILE_TOO_BIG .. This write operation would cause the file to go over the file size limit. +// WFS_RESULT_NO_CHANGE_SIZE .. This write operation would cause the file size to increase, but the WFS_PERM_NO_CHANGE_SIZE flag is set. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed since the file was opened +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the write completed. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while writing to the file. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// Possible immediate return values for WFSWriteAsync (prior to start of write command): +// WFS_RESULT_OK .. Write request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle, pFileData is NULL. +// WFS_RESULT_ACCESS .. The file was opened with WFS_ACCESS_READ. +// WFS_RESULT_FILE_TOO_BIG .. This write operation would cause the file to go over the file size limit. +// WFS_RESULT_NO_CHANGE_SIZE .. This write operation would cause the file size to increase, but the WFS_PERM_NO_CHANGE_SIZE flag is set. +// Possible values of nResult passed to WFSWriteAsync callback: +// WFS_RESULT_OK .. Write completed successfully. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the write operation completed. +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the write completed . +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while writing to the file. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// +// Description: +// ------------ +// This function is used to write data to a file that has been opened for writing. +// Data will be overwritten or appended to the file, starting from the current cursor position. +// This function is faster than WFSWriteFile. However the data buffer is overwritten by used as the work buffer. +// Note: WFSWriteFile automatically advances a file pointer stored within the library, whereas WFSWriteFileAsync does not. +// WFSWriteFileAsync requires the start position to be specified in the call. + + +//-------------------------------------------------------------------------------------------------------------- +// WFSCloseFile, WFSCloseFileAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSCloseFile (WFSFileHandle fh, WFSBool bTruncateFlag); +WFSResult WFSCloseFileAsync(WFSFileHandle fh, WFSBool bTruncateFlag, WFSFileSize nFileSize, void *pUserData, WFSFileOpCallback cb); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// bTruncateFlag .. If the file was opened for writing and this flag is set to TRUE, the file will be truncated. +// For WFSCloseFile, the current file position becomes the new file size. For WFSCloseFileAsync, nFileSize is used. +// If this flag is FALSE, the file will be closed without truncation. +// nFileSize .. If bTruncateFlag is TRUE, this is the new file size (WFSCloseFileAsync only). +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSCloseAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSClose: +// WFS_RESULT_OK .. Close completed successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. (Can also occur if there are outstanding async read/write operations on this file handle) +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle. +// WFS_RESULT_ACCESS .. Trying to truncate the file, but the file was opened with WFS_ACCESS_READ. +// WFS_RESULT_NO_CHANGE_SIZE .. Trying to truncate the file, but the file has the WFS_PERM_NO_CHANGE_SIZE flag set. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the close completed. +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the close completed. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while closing the file. +// Possible immediate return values for WFSCloseAsync: +// WFS_RESULT_OK .. Close request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle. +// WFS_RESULT_ACCESS .. Trying to truncate the file, but the file was opened with WFS_ACCESS_READ. +// WFS_RESULT_NO_CHANGE_SIZE .. Trying to truncate the file, but the file has the WFS_PERM_NO_CHANGE_SIZE flag set. +// Possible values of nResult passed to WFSCloseAsync callback: +// WFS_RESULT_OK .. Close completed successfully. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the close completed. +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the close completed. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while closing the file. +// +// Description: +// ------------ +// This function is used to close a file. +// If the file was opened for writing, it can be truncated by setting bTruncateFlag=TRUE + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSFlush, WFSFlushAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSFlush (const utf8 *sVolumeId); +WFSResult WFSFlushAsync(const utf8 *sVolumeId, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sVolumeId .. pointer to a string buffer containing the mounted Volume Id. +// +// Return Values: +// -------------- +// Possible return values for WFSFlush: +// WFS_RESULT_OK .. The updates made by the application have been successfully flushed to disk. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the flush completed. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while flushing the data. +// Possible immediate return values for WFSFlushAsync: +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// Possible values of nResult passed to WFSFlushAsync callback: +// WFS_RESULT_OK .. The updates made by the application have been successfully flushed to disk. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the flush completed. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while flushing the data. +// +// Description: +// ------------ +// This function can be used to guarantee that that operations which have previously completed, have been flushed to disk. +// Because this function can take a significant amount of time, indiscriminate use of this function may adversely affect performance. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSearchDirectoryFirst, WFSSearchDirectoryFirstAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSearchDirectoryFirst (const utf8 *sPattern, WFSSearchDirectoryHandle *pSdh, WFSFileInfo *pFi); +WFSResult WFSSearchDirectoryFirstAsync(const utf8 *sPattern, WFSFileInfo *pFi, void *pUserData, WFSSearchDirectoryCallback cb); +// Arguments: +// ---------- +// sPattern .. specifies the search pattern. It can be prefixed by a relative or absolute path specification. +// The file name portion (after the last directory separator) can include the following wildcard +// characters: +// * to match any sequence of 0 or more characters, +// ? to match any single character. +// +// pSdh .. A pointer to a WFSSearchDirectoryHandle which is passed back by the library. +// This handle should be passed to WFSSearchDirectoryNext or WFSSearchDirectoryNextAsync +// to continue the search, or WFSSearchDirectoryClose to finish the search. +// pFi .. A pointer to a WFSFileInfo struct which will be overwritten with the details of the +// first file which matches the search pattern. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSSearchDirectoryFirstAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSearchDirectoryFirst: +// WFS_RESULT_OK .. At least one file exists which matches the pattern. Details of the first file are returned in *pFi. Only in this case is a search directory handle created. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Directory name too long, Path is too deep. +// WFS_RESULT_MAX_HANDLES .. Maximum number of concurrent search handles already in use. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. This application does not have access to the base directory of the search. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while searching the directory. +// WFS_RESULT_NOT_FOUND .. No files were found which matched the search pattern. +// Possible immediate return values for WFSSearchDirectoryFirstAsync: +// WFS_RESULT_OK .. Search request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Directory name too long, Path is too deep. +// Possible values of nResult passed to WFSSearchDirectoryFirstAsync callback: +// WFS_RESULT_OK .. At least one file exists which matches the pattern. Details of the first file are returned in *pFi. Only in this case is a search directory handle created. +// WFS_RESULT_MAX_HANDLES .. Maximum number of concurrent search handles already in use. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. This application does not have access to the base directory of the search. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while searching the directory. +// WFS_RESULT_NOT_FOUND .. No files were found which matched the search pattern. +// +// Description: +// ------------ +// Use these functions to search a directory for files matching a specific pattern. +// These functions can be used to enumerate attached devices, by passing "/dev/*" as the search pattern. // ToDo: Consider how to handle case of attachement/detachment during such device enumeration. +// These functions do not perform recursive searches of sub directories. +// NOTE: Don't forget to call WFSSearchDirectoryClose() when finished with the search. + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSearchDirectoryNext, WFSSearchDirectoryNextAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSearchDirectoryNext (WFSSearchDirectoryHandle sdh, WFSFileInfo *pFi); +WFSResult WFSSearchDirectoryNextAsync(WFSSearchDirectoryHandle sdh, WFSFileInfo *pFi, void *pUserData, WFSSearchDirectoryCallback cb); +// Arguments: +// ---------- +// sdh .. A WFSSearchDirectoryHandle which was created by WFSSearchDirectoryFirst. +// pFi .. A pointer to a WFSFileInfo struct which will be overwritten with the details of the +// next file which matches the search pattern. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSSearchDirectoryNextAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSearchDirectoryNext: +// WFS_RESULT_OK .. Another file/directory was found which matches the search pattern associated with sdh. It's details are returned in *pFi. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sdh is not a valid search handle. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. This application does not have access to the base directory of the search. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while searching the directory. +// WFS_RESULT_NOT_FOUND .. No more files could be found which matched the search pattern. +// Possible immediate return values for WFSSearchDirectoryNextAsync: +// WFS_RESULT_OK .. Search request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sdh is not a valid search handle. +// Possible values of nResult passed to WFSSearchDirectoryNextAsync callback: +// WFS_RESULT_OK .. Another file/directory was found which matches the search pattern associated with sdh. It's details are returned in *pFi. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. This application does not have access to the base directory of the search. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while searching the directory. +// WFS_RESULT_NOT_FOUND .. No more files were found which matched the search pattern. +// +// Description: +// ------------ +// Use these functions to search a directory for the next file matching a previously specified pattern. +// NOTE: Don't forget to call WFSSearchDirectoryClose() when finished with the search. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSearchDirectoryClose, WFSSearchDirectoryCloseAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSearchDirectoryClose (WFSSearchDirectoryHandle sdh); +WFSResult WFSSearchDirectoryCloseAsync(WFSSearchDirectoryHandle sdh, void *pUserData, WFSSearchDirectoryCloseCallback cb); +// Arguments: +// ---------- +// sdh .. A WFSSearchDirectoryHandle which was returned by WFSSearchDirectoryFirst. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSSearchDirectoryCloseAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSearchDirectoryClose: +// WFS_RESULT_OK .. The search handle has been closed successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sdh is not a valid search handle. +// Possible immediate return values for WFSSearchDirectoryCloseAsync: +// WFS_RESULT_OK .. The close search handle request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sdh is not a valid search handle. +// Possible values of nResult passed to WFSSearchDirectoryCloseAsync callback: +// WFS_RESULT_OK .. The search handle has been closed successfully. +// +// Description: +// ------------ +// These functions are used to close a directory search. +// This will free up the memory required to keep track of the search. + + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif //define __WFS_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/revolution/wfsError.h b/trunk/firmware/build/libraries/nfs/common/include/revolution/wfsError.h new file mode 100644 index 0000000..77b4ab3 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/revolution/wfsError.h @@ -0,0 +1,98 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFS library + File: wfserror.h + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfsError.h,v $ + Revision 1.6 2008/09/26 12:04:33 ueno + Changed WFS_RESULT_* to be equal to WFSKRN_RESULT_* to guarantee the casts. + + Revision 1.5 2008/07/11 19:02:21 paul + Removed WFS_RESULT_DIRECTORY_FULL. Fixed comments and reordered slightly. + + Revision 1.4 2008/07/10 07:03:19 nakanose_jin + add permissions API + + Revision 1.3 2008/07/02 06:52:43 nakanose_jin + bye inheritance & dev_full error + + Revision 1.2 2008/06/25 00:58:19 nakanose_jin + add control level error + + Revision 1.1 2008/04/08 18:25:40 paul + Moved error definitions from wfs.h to this header file. + + +*---------------------------------------------------------------------------*/ + +#ifndef __WFS_ERROR_H__ +#define __WFS_ERROR_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + + +// --------------------------------------------------------------------- +// WFS error codes +// --------------------------------------------------------------------- +typedef enum { + WFS_RESULT_OK = 0, // Success + + // Errors that can usually be detected early, and if detected, would result in the Async callback not being called: + WFS_RESULT_BUSY = -1, // Too many requests, try waiting then calling again. + WFS_RESULT_OUT_OF_MEMORY = -2, // The library does not have enough memory to complete the requested operation. (May be due to too many outstanding aysnc calls). + WFS_RESULT_INVALID = -3, // The function parameters were invalid, e.g. File name is too long, Path is too long or too deep. + WFS_RESULT_ACCESS = -4, // Trying to write to a file which was opened for read-only access, or vice versa. + WFS_RESULT_LIB_NOT_INITIALIZED = -5, // The WFS library has not been initialized. Please call WFSInit() (This error is checked in functions that require the library to be initialized, but only in the debug versions). + WFS_RESULT_LIB_ALREADY_INITIALIZED = -6, // The WFS library has already been initialized. + WFS_RESULT_FILE_TOO_BIG = -7, // The current write/append request would push the file over the size limit. + WFS_RESULT_NO_CHANGE_SIZE = -8, // The requested operation would cause the file size to change, but this file has WFS_PERM_NO_CHANGE_SIZE flag set. + + // Errors that cannot usually be detected early, and would be passed via nResult to the Async callbacks: + WFS_RESULT_MEDIA_ERROR = -9, // The device or media is not attached, or was removed before the requested operation could be completed. + WFS_RESULT_DEV_UNUSABLE = -10, // Attached device is not accessible, e.g. because it is an unsupported device, or has an unknown format. + WFS_RESULT_DEV_NOT_INITIALIZED = -11, // Device not formatted, or does not yet contain a WFS volume + WFS_RESULT_DEV_IN_USE = -12, // Trying to initialize a device which is in use (mounted) by one or more clients. + WFS_RESULT_VOL_ID_ERROR = -13, // Attempted to mount a volume with the same unique Id as an already mounted volume (This could happen if the User backs up an entire WFS volume using a PC) + WFS_RESULT_WRITE_PROTECTED = -14, // Device is physically write protected (e.g. USB Flash memory, SD Card) + WFS_RESULT_ALREADY_MOUNTED = -15, // The device is already mounted + + WFS_RESULT_PERMISSION = -16, // Permission flags do not permit the requested access from this application. + WFS_RESULT_PERMISSION_CL = -17, // Permission error caused by control level problems. + WFS_RESULT_ACL_FULL = -18, // The access list is full. + WFS_RESULT_ACL_ENTRY_NOT_FOUND = -19, // The specified entry does not exist in the access list. + WFS_RESULT_AUTHENTICATION = -20, // Trying to access content on a different Wii, which does not have the required access rights. + WFS_RESULT_CORRUPTION = -21, // A corrupted block was encountered which prevented the operation from being completed. + + WFS_RESULT_DIRECTORY_QUOTA = -22, // One of the ancestor directories would exceed its quota. + + WFS_RESULT_MAX_HANDLES = -23, // The maximum number of concurrent file handles / search handles are already in use. + WFS_RESULT_ALREADY_EXISTS = -24, // The file or directory being created already exists. + WFS_RESULT_NOT_FOUND = -25, // The specified file, directory or device does not exist. + WFS_RESULT_NOT_EMPTY = -26, // The specified directory cannot be deleted because it is not empty. + WFS_RESULT_NOT_FILE = -27, // The specified path is directory instead of a file. + WFS_RESULT_NOT_DIRECTORY = -28, // The specified path is a file instead of a directory. + WFS_RESULT_FILE_OPEN = -29, // The file is open. Cannot delete, move, rename, change permissions of an open file. Cannot open a file more than once unless all opens are WFS_ACCESS_READ. + WFS_RESULT_LOCKED = -30, // Cannot perform the requested operation since the file or directory is locked by an existing operation. + WFS_RESULT_RESOURCE_LIMIT_EXCEEDED = -31, // A resource limit prevents this function call. Try smaller values. + + WFS_RESULT_NOT_IMPLEMENTED = -1026, // The requested function has not yet been implemented //ToDo: This error should be removed from the final API + WFS_RESULT_UNKNOWN = -1027, // Unexpected error - could be caused by a bug in the file system. + WFS_RESULT_FATAL_ERROR = -1028 // May be caused by critical metadata corruption. + +} WFSResult; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif //define __WFS_ERROR_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/revolution/wfsPerm.h b/trunk/firmware/build/libraries/nfs/common/include/revolution/wfsPerm.h new file mode 100644 index 0000000..7cd034f --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/revolution/wfsPerm.h @@ -0,0 +1,462 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFS library + File: wfsperm.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfsPerm.h,v $ + Revision 1.20 2008/09/18 10:26:24 nakanose_jin + fix comments + + Revision 1.19 2008/08/29 02:24:46 nakanose_jin + add comments + + Revision 1.18 2008/08/06 04:12:45 nakanose_jin + add PERMISSION_CL,ACL_ENTRY_NOT_FOUND,ACL_FULL comment + + Revision 1.17 2008/07/18 00:33:03 paul + Added descriptions of functions. Rename WFSDeletePermissions() -> WFSDeleteAccessListEntry(). + + Revision 1.16 2008/07/17 05:07:02 kondo_masahiro + inline -> static inline + + Revision 1.15 2008/07/15 08:28:47 nakanose_jin + change define value + + Revision 1.14 2008/07/14 07:22:51 ueno + Renamed WFSSetAccessList() by WFSSetAccessListEntry(). + + Revision 1.13 2008/07/11 09:46:03 ueno + Added async functions. + + Revision 1.12 2008/07/11 09:19:36 ueno + Fixed a typo. + + Revision 1.11 2008/07/10 07:03:18 nakanose_jin + add permissions API + + Revision 1.10 2008/07/02 06:52:43 nakanose_jin + bye inheritance & dev_full error + + Revision 1.9 2008/06/23 02:58:31 nakanose_jin + separate relative from absolute + + Revision 1.8 2008/06/16 18:23:50 ueno + Removed WFSCreateAccessList(). + + Revision 1.7 2008/06/05 14:08:06 ueno + Revised permission APIs. + + Revision 1.6 2008/05/08 11:41:02 nakanose_jin + move WFSDebugSetTitleID wfsPerm.h => wfs_Debug.h + + Revision 1.5 2008/05/07 13:26:55 nakanose_jin + fix ambiguous definision + + Revision 1.4 2008/04/29 01:14:52 ueno + Removed WFS_DEBUG_SYSTEM_PROCESS_ID. + Added WFS_ROOT_ID and WFS_EVERYONE_ID. + + Revision 1.3 2008/04/23 09:21:24 ueno + Revised directory permission (change -> add). + + Revision 1.2 2008/04/18 07:54:12 nakanose_jin + merging acl + + Revision 1.1 2008/04/08 18:27:19 paul + Moved permissions related declarations from wfs.h to this header file. Changed permissions API to support access lists. + + +*---------------------------------------------------------------------------*/ + +#ifndef __WFS_PERM_H__ +#define __WFS_PERM_H__ + +// Permission Flags Which apply to Files only: + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// permissions +#define WFS_PERM_CHANGE_SIZE 0x0001 +#define WFS_PERM_WRITE 0x0002 +#define WFS_PERM_READ 0x0004 +#define WFS_PERM_ADD_OR_DELETE_FILE 0x0008 +#define WFS_PERM_ADD_OR_DELETE_SUBDIR 0x0010 +#define WFS_PERM_LIST 0x0020 +#define WFS_PERM_DELETE_OR_MOVE 0x0040 + +// reserved +#define WFS_PERM_RESERVED0 0x0080 +#define WFS_PERM_RESERVED1 0x0100 +#define WFS_PERM_RESERVED2 0x0200 +#define WFS_PERM_RESERVED3 0x0400 +#define WFS_PERM_RESERVED4 0x0800 + +// control level +/* 古い定義 +#define WFS_PERM_CL0 0x0000 // 0 +#define WFS_PERM_CL_MINUS_1 0x7000 // -1 +#define WFS_PERM_CL_MINUS_2 0x6000 // -2 +#define WFS_PERM_CL_MINUS_3 0x5000 // -3 +#define WFS_PERM_CL_MINUS_4 0x4000 // -4 +#define WFS_PERM_CL_MASK 0x7000 +*/ +#define WFS_PERM_CL_MINUS_0 0xE000 // 0 +#define WFS_PERM_CL_MINUS_1 0xC000 // -1 +#define WFS_PERM_CL_MINUS_2 0xA000 // -2 +#define WFS_PERM_CL_MINUS_3 0x8000 // -3 +#define WFS_PERM_CL_0 0x0000 // 0 (absolute) +#define WFS_PERM_CL_1 0x2000 // 1 (absolute) +#define WFS_PERM_CL_2 0x4000 // 2 (absolute) +#define WFS_PERM_CL_3 0x6000 // 3 (absolute) + +#define WFS_PERM_CL_MASK 0xE000 +#define WFS_PERM_CL_SHIFT 13 +#define WFS_PERM_CL_RELATIVE_BIT 0x8000 + +static inline u32 WFS_PERM_GET_CL_ABSOLUTE(u32 perm) +{ + // ASSERT( 0 == (WFS_PERM_CL_RELATIVE_BIT & perm) ); + return ((perm & WFS_PERM_CL_MASK) >> WFS_PERM_CL_SHIFT); +} + +static inline u32 WFS_PERM_SET_CL_ABSOLUTE(u32 perm , s32 cl) +{ + // ASSERT( (cl >= 0) && (cl <= 3) ); + perm = (perm & ~WFS_PERM_CL_MASK) | (cl << WFS_PERM_CL_SHIFT); + return perm; +} + +static inline u32 WFS_PERM_SET_CL_RELATIVE(u32 perm , s32 cl) +{ + // ASSERT( (cl <= 0) && (cl >= -3) ); + perm = (perm & ~WFS_PERM_CL_MASK) | ((7 + cl) << WFS_PERM_CL_SHIFT); + return perm; +} + + +#define WFS_PERM_DIR_FULL (WFS_PERM_CHANGE_SIZE | WFS_PERM_WRITE | WFS_PERM_READ | \ + WFS_PERM_ADD_OR_DELETE_FILE | WFS_PERM_ADD_OR_DELETE_SUBDIR | \ + WFS_PERM_LIST | WFS_PERM_DELETE_OR_MOVE) +#define WFS_PERM_FILE_FULL (WFS_PERM_CHANGE_SIZE | WFS_PERM_WRITE | WFS_PERM_READ | WFS_PERM_DELETE_OR_MOVE) + +#define WFS_PERM_FULL 0xFFFF // this is special keyword. it will be converted to a appropriate value in internal + +typedef u32 WFSTitleId; +typedef u32 WFSGroupId; + +#define WFS_ROOT_ID 0UL +#define WFS_EVERYONE_ID 0x80000000 + +typedef struct WFSAccessListEntry { + u32 titleId; + u32 entryCreatorId; + u32 permissions; +} WFSAccessListEntry; + +#define WFS_ACL_ENTRY_NET_SIZE (sizeof(u32) + sizeof(u32) + sizeof(u16)) // smaller than sizeof(WFSKrnAccessListEntry). +#define WFS_ACL_MAX_ENTRIES (WFS_MAX_FILE_NAME_SIZE - sizeof(u32)*2)/(WFS_ACL_ENTRY_NET_SIZE*2) + +//-------------------------------------------------------------------------------------------------------------- +// WFSChangePermissions, WFSChangePermissionsAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSChangePermissions (const utf8 *sPathName, u32 nFlags, u32 nMask); +WFSResult WFSChangePermissionsAsync(const utf8 *sPathName, u32 nFlags, u32 nMask, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of the file or directory whose permissions are to be changed. +// See "WFS Path Names" for rules about path names. +// nFlags .. The new permissions flags that are to be set. Should be a combination of the permission flags: WFS_PERM_* +// nMask .. The mask determines which flags will be changed. NewAttributes = (OldAttributes & ~nMask) | (nFlags & nMask) +// NOTE: The mask bits for bits which are never allowed to be changed, such as WFS_FLAG_IS_A_DIRECTORY are automatically set to 0. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSChangePermissionsAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSChangePermissions: +// WFS_RESULT_OK .. The permissions were updated successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. The requested change was not allowed due to the existing permissions settings. +// WFS_RESULT_PERMISSION_CL .. You cant set the requested permission because you dont have a appropriate control level. +// WFS_RESULT_ACL_FULL .. You cant set the requested permission because the target access list is full. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory does not exist. +// WFS_RESULT_RESOURCE_LIMIT_EXCEEDED .. Too much accesslist variations generated , so quota resource are drained. +// Possible immediate return values for WFSChangePermissionsAsync: +// WFS_RESULT_OK .. Change permissions request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// Possible values of nResult passed to WFSChangePermissionsAsync callback: +// WFS_RESULT_OK .. The permissions were updated successfully. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Only the owner of a file or directory can change its permission flags. +// WFS_RESULT_PERMISSION_CL .. You cant set the requested permission because you dont have a appropriate control level. +// WFS_RESULT_ACL_FULL .. You cant set the requested permission because the target access list is full. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory does not exist. +// WFS_RESULT_RESOURCE_LIMIT_EXCEEDED .. Too much accesslist variations generated , so quota resource are drained. +// +// Description: +// ------------ +// These functions can be used to change one's own permissions to access a specified file or directory. +// However the permissions can only be set within the bounds granted by superior users. +// (The purpose is to allow a user to specify a file as read-only, which is common in existing file systems). + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSetPermissionsForUser, WFSSetPermissionsForUserAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSetPermissionsForUser (const utf8 *sPathName, u32 nFlags, u32 nMask, WFSTitleId titleId); +WFSResult WFSSetPermissionsForUserAsync(const utf8 *sPathName, u32 nFlags, u32 nMask, WFSTitleId titleId, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of the file or directory whose permissions are to be changed. +// See "WFS Path Names" for rules about path names. +// nFlags .. The new permissions flags that are to be set. Should be a combination of the permission flags: WFS_PERM_* +// nMask .. The mask determines which flags will be changed. NewAttributes = (OldAttributes & ~nMask) | (nFlags & nMask) +// titleId .. The title id of the application for which permissions are being set. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSSetPermissionsForUserAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSetPermissionsForUser: +// WFS_RESULT_OK .. The permissions were updated successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. The requested change was not allowed due to the existing permissions settings. +// WFS_RESULT_PERMISSION_CL .. You cant set the requested permission because you dont have a appropriate control level. +// WFS_RESULT_ACL_FULL .. You cant set the requested permission because the target access list is full. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_NOT_FOUND .. The specified file or directory does not exist. +// WFS_RESULT_RESOURCE_LIMIT_EXCEEDED .. Too much accesslist variations generated , so quota resource are drained. +// Possible immediate return values for WFSSetPermissionsForUserAsync: +// WFS_RESULT_OK .. Change permissions request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// Possible values of nResult passed to WFSSetPermissionsForUserAsync callback: +// WFS_RESULT_OK .. The permissions were updated successfully. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Only the owner of a file or directory can change its permission flags. +// WFS_RESULT_PERMISSION_CL .. You cant set the requested permission because you dont have a appropriate control level. +// WFS_RESULT_ACL_FULL .. You cant set the requested permission because the target access list is full. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_NOT_FOUND .. The specified file or directory does not exist. +// WFS_RESULT_RESOURCE_LIMIT_EXCEEDED .. Too much accesslist variations generated , so quota resource are drained. +// +// Description: +// ------------ +// Use these functions to specify or change the permissions that a particular title id will have to access or modify the specified file or directory. +// NOTE: The permissions are specified as absolute values. However these are represented on access lists as permissions relative to the granter. +// This function operates in such a way as to only create access list entries when necessary, and remove them if possible. + + + +WFSResult WFSGetPermissionsForUser (const utf8 *sPathName, u32 *pFlags, WFSTitleId titleId); +WFSResult WFSGetPermissionsForUserAsync(const utf8 *sPathName, WFSTitleId titleId, void *pUserData, WFSGetPermissionsForUserCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of a file or directory. +// See "WFS Path Names" for rules about path names. +// pFlags .. A pointer to a u32 which will be overwritten with the permissions the specified title id has to +// access or modify the specified file or directory. +// titleId .. The title id of the application for which permissions are being set. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSGetPermissionsForUserAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSGetPermissionsForUser: +// WFS_RESULT_OK .. The specified file or directory was found. The permissions were calculated and copied to *pFlags. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// Possible immediate return values for WFSGetPermissionsForUserAsync: +// WFS_RESULT_OK .. The request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// Possible values of nResult passed to WFSGetPermissionsForUserAsync callback: +// WFS_RESULT_OK .. The specified file or directory was found and its permissions were calculated and passed as the nFlags parameter. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// +// Description: +// ------------ +// Use these functions to read the permissions of a file or directory for a particular user (title id). +// The permissions values returned are absolute values resulting from inheritance and permissions granted by superior users. + + + +s32 WFSGetAccessList (const utf8 *sPathName, WFSAccessListEntry *pAccessList, u32 nMaxEntries); +WFSResult WFSGetAccessListAsync(const utf8 *sPathName, WFSAccessListEntry *pAccessList, u32 nMaxEntries, void *pUserData, WFSGetAccessListCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of a file or directory. +// See "WFS Path Names" for rules about path names. +// pAccessList .. A pointer to an array of WFSAccessListEntry structs which will be overwritten with the access list entries. +// nMaxEntries .. The maximum number of access list entries that the array can hold. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSGetAccessListAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSGetAccessList: +// >= 0 .. The number of access list entries that were successfully copied to the specified array. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// Possible immediate return values for WFSGetAccessListAsync: +// WFS_RESULT_OK .. The request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// Possible values of nResult passed to WFSGetAccessListAsync callback: +// >= 0 .. The number of access list entries that were successfully copied to the specified array. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// +// Description: +// ------------ +// Use these functions to read the raw access list for a file or directory. +// The raw access list contains only relative values of permissions and control level. (relative to the permission granter) +// The actual permission to access files and directories depends on the absolute values of permissions and control level, +// which are calculated by following inheritance and the permission-granting links back to root. + + + +WFSResult WFSSetAccessListEntry (const utf8 *sPathName, u32 nFlags, u32 nMask, WFSTitleId titleId); +WFSResult WFSSetAccessListEntryAsync(const utf8 *sPathName, u32 nFlags, u32 nMask, WFSTitleId titleId, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of a file or directory. +// See "WFS Path Names" for rules about path names. +// titleId .. The title id of the application for which permissions are being set. +// nFlags .. The new permissions flags that are to be set. Should be a combination of the permission flags: WFS_PERM_* +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSSetAccessListEntryAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSetAccessListEntry: +// WFS_RESULT_OK .. The specified file or directory was found, and the specified access list entry was created or updated. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION_CL .. You cant set the requested permission because you dont have a appropriate control level. +// WFS_RESULT_ACL_FULL .. You cant set the requested permission because the target access list is full. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// WFS_RESULT_RESOURCE_LIMIT_EXCEEDED .. Too much accesslist variations generated , so quota resource are drained. +// Possible immediate return values for WFSSetAccessListEntryAsync: +// WFS_RESULT_OK .. The request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// Possible values of nResult passed to WFSSetAccessListEntryAsync callback: +// WFS_RESULT_OK .. The specified file or directory was found, and the specified access list entry was created or updated. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// +// Description: +// ------------ +// Use these functions to create or update a raw access list entry. +// Raw access list entries contain only relative values of permissions and control level. (relative to the permission granter) +// The actual permission to access files and directories depends on the absolute values of permissions and control level, +// which are calculated by following inheritance and the permission-granting links back to root. +// NOTE: SetPermissionsForUser() can be used to specify permissions using absolute values. + + + +WFSResult WFSDeleteAccessListEntry (const utf8 *sPathName, WFSTitleId titleId , WFSTitleId entryCreatorId); +WFSResult WFSDeleteAccessListEntryAsync(const utf8 *sPathName, WFSTitleId titleId , WFSTitleId entryCreatorId, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of a file or directory. +// See "WFS Path Names" for rules about path names. +// titleId .. The title id of the application for which permissions are being removed. +// entryCreatorId .. The title id of the application which created the access list entry (the permission granter). +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSDeletePermissionsAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSDeletePermissions: +// WFS_RESULT_OK .. The specified file or directory was found. The permissions were calculated and copied to *pFlags. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_ACL_ENTRY_NOT_FOUND .. the target access list entry does not exist. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// Possible immediate return values for WFSDeletePermissionsAsync: +// WFS_RESULT_OK .. The request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// Possible values of nResult passed to WFSDeletePermissionsAsync callback: +// WFS_RESULT_OK .. The specified file or directory was found and its permissions were calculated and passed as the nFlags parameter. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// +// Description: +// ------------ +// Use these functions to delete a specified access list entry. + + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif //define __WFS_PERM_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/revolution/wfstypes.h b/trunk/firmware/build/libraries/nfs/common/include/revolution/wfstypes.h new file mode 100644 index 0000000..957ba6e --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/revolution/wfstypes.h @@ -0,0 +1,209 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFS library + File: wfstypes.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfstypes.h,v $ + Revision 1.13 2008/12/10 06:55:11 kondo_masahiro + Added the new device types WFS_DEVTYPE_USB_MSC_??. + + Revision 1.12 2008/12/03 00:13:29 kondo_masahiro + Added WFS_MAX_WORK_SPACE_SIZE and fixed WFS_MIN_WORK_SPACE_SIZE + + Revision 1.11 2008/10/23 11:16:20 nakanose_jin + Open and Search should give a invalid file handle if he fails to execute. + + Revision 1.10 2008/09/26 09:32:36 kondo_masahiro + Marged with revision 1.8 + + Revision 1.9 2008/09/26 09:29:54 kondo_masahiro + Changed WFS_MIN_WORK_SPACE_SIZE. + + Revision 1.8 2008/07/30 03:57:46 paul + Fixed WFS_FLAG_CONTIGUOUS_AREA comment + + Revision 1.7 2008/07/25 09:46:56 ooizumi + Fixed WFSAccess definition. + + Revision 1.6 2008/07/11 09:46:03 ueno + Added async functions. + + Revision 1.5 2008/06/20 18:35:39 paul + Added WFS_MIN_DIRECTORY_QUOTA, WFS_FLAG_CONTIGUOUS_AREA + + Revision 1.4 2008/04/29 01:14:52 ueno + Removed WFS_DEBUG_SYSTEM_PROCESS_ID. + Added WFS_ROOT_ID and WFS_EVERYONE_ID. + + Revision 1.3 2008/04/08 18:24:30 paul + Moved callbacks and other type definitions from wfs.h into this header file. Moved permissions flags to wfsPerm.h + + Revision 1.2 2008/02/25 05:35:41 paul + Reduced WFS_MAX_FILE_NAME_SIZE and WFS_MAX_PATH_NAME_SIZE to make structs multiples of 32 bytes, and also allow space for a NULL terminator so we dont have to change existing code. + + Revision 1.1 2008/01/17 07:51:43 ooizumi + Moved several definitions from wfs.h. + + +*---------------------------------------------------------------------------*/ + +#ifndef __WFSTYPES_H__ +#define __WFSTYPES_H__ + + +// --------------------------------------------------------------------- +// wfstypes.h - Wii File System (WFS) API +// --------------------------------------------------------------------- + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +// --------------------------------------------------------------------- +// WFS attributes +// --------------------------------------------------------------------- +#define WFS_MAX_FILE_SIZE 4294967295 // ((u32)-1) +#define WFS_MAX_PATH_DEPTH 31 // (ToDo: Directories must keep track of their deepest sub-path, so we can validate directory move requests) + +// The following represent the maximum size of string fields in Bytes, not including the terminating NULL character. +#define WFS_MAX_FILE_NAME_SIZE 254 // Does not include the path, just the file name. +#define WFS_MAX_PATH_NAME_SIZE 509 // (ToDo: Directories must keep track of their longest sub-path, so we can validate directory move/rename requests) +#define WFS_MAX_DEVICE_NAME_SIZE 15 // maximum size of a device name +#define WFS_MAX_VOLUME_ID_SIZE 7 // maximum size of WFS Volume Id string (This is a randomly assigned string of characters, e.g., 1a2b3c4) + +#define WFS_MAX_WORK_SPACE_SIZE ((512+40+40) * 1024) // Used for user data cache, shim layer queueing parameters and async thread stack / queueing async parameters. +#define WFS_MIN_WORK_SPACE_SIZE ((144+40+40) * 1024) +#define WFS_MIN_DIRECTORY_QUOTA (1024 * 1024) +#define WFS_INVALID_HANDLE_VALUE ((u32)-1) + + +typedef char utf8; // ToDo: Perhaps utf8 should be changed to WFSChar? +typedef u32 WFSFileTime; // Time in seconds since 00:00, 1st January, 2000 +typedef u32 WFSFileSize; // Size of file +typedef u32 WFSContentIdx; // Used to identify files which belong to the same unit of purchased content, and control access to them +typedef u8 WFSBool; + + +// --------------------------------------------------------------------- +// WFS devices +// --------------------------------------------------------------------- + +// Possible WFS device states: +// 1. Valid - valid WFS volume exists +// 2. Unusable - bad device +// 3. Unknown format (e.g., FAT12, NTFS, HFS) +// 4. Uninitialized - recognized format (FAT32), but not enough free space for a WFS volume + +// Whenever a compatible device is attached, we check to see if a WFS volume already exists. If not, +// we try to create it automatically. If it is not created, then the device must not have enough space. + +#define WFS_DEVFLAG_UNUSABLE 1 // Device is unusable (e.g. unknown format, unsupported device) +#define WFS_DEVFLAG_WRITE_PROTECTED 2 // Device is physically write protected +#define WFS_DEVFLAG_NOT_INITIALIZED 4 // Device not formatted or does not yet contain a WFS volume +#define WFS_DEVFLAG_NOT_MOUNTED 8 // Device has not yet been mounted + +// ToDo: Can we force this enum to be u8? +typedef enum { + WFS_DEVTYPE_NONE = 0x00, + WFS_DEVTYPE_SD = 0x01, + WFS_DEVTYPE_USB_MSC_10 = 0x02, // MSC device with USB1.0 + WFS_DEVTYPE_USB_MSC_11 = 0x03, // MSC device with USB1.1 + WFS_DEVTYPE_USB_MSC_20 = 0x04, // MSC device with USB2.0 + WFS_DEVTYPE_EXT_SD = 0x05, + WFS_DEVTYPE_NAND = 0x06 +} WFSDevType; + +typedef struct { + u64 nDevTotalCapacity; // Total capacity of underlying device in bytes + u8 nDevType; // One of WFS_DEVTYPE_* + u8 nDevFlags; // Combination of WFS_DEVFLAG_* +} WFSDeviceInfo; + +// ToDo: Should consider the case of users making an exact copy of a WFS volume causing two devices to +// have the same "unique" device Id. This may be an unavoidable problem. +// We can return WFS_RESULT_VOL_ID_ERROR if we attempt to mount a device with the same Id as an existing device. + + +// --------------------------------------------------------------------- +// WFSFileHandle, WFSSearchDirectoryHandle +// --------------------------------------------------------------------- + +typedef u32 WFSFileHandle; +typedef u32 WFSSearchDirectoryHandle; + + +// --------------------------------------------------------------------- +// WFSFileInfo +// --------------------------------------------------------------------- + +typedef struct { + union { + WFSFileSize nFileSize; // Assuming this is a file + u32 nNumEntries; // Assuming this is a directory + }; + u32 nFlags; // Includes the permissions for the requesting user: WFS_PERM* and directory status flag: WFS_FLAG_IS_A_DIRECTORY + WFSContentIdx nCidx; + WFSFileTime timeCreated; + WFSFileTime timeUpdated; +} WFSFileAttributes; + +typedef struct { + WFSFileAttributes attr; + utf8 sFileName[WFS_MAX_FILE_NAME_SIZE+1]; +} WFSFileInfo; + + +// --------------------------------------------------------------------- +// WFS File Attributes +// --------------------------------------------------------------------- + +// The following flags are not stored per-title id, but they are included along with the permissions for the current title id in the nFlags field of WFSFileAttributes +#define WFS_FLAG_IS_A_DIRECTORY 0x80000000 // This flag can not be changed after creation. +#define WFS_FLAG_CONTIGUOUS_AREA 0x40000000 // Specifies that a directory has a contiguous set of blocks allocated to it, and is a self-contained area + + +// --------------------------------------------------------------------- +// WFSAccess +// --------------------------------------------------------------------- +typedef enum { + WFS_ACCESS_READ = 0x01, + WFS_ACCESS_WRITE = 0x02, + WFS_ACCESS_RW = 0x03 // WFS_ACCESS_READ | WFS_ACCESS_WRITE +} WFSAccess; + + +// --------------------------------------------------------------------- +// WFS callback types +// --------------------------------------------------------------------- +typedef void (*WFSResultCallback )(WFSResult nResult, void *pUserData); +typedef void (*WFSDeviceCallback )(const utf8 *sDeviceName, void *pUserData); // For attach/detach callbacks +typedef void (*WFSDeviceInfoCallback )(WFSResult nResult, const utf8 *sDeviceName, WFSDeviceInfo *pDi, void *pUserData); +typedef void (*WFSDeviceVolumeCallback )(WFSResult nResult, const utf8 *sDeviceName, utf8 *sVolumeId, void *pUserData); +typedef void (*WFSUnmountVolumeCallback )(WFSResult nResult, const utf8 *sVolumeId, void *pUserData); +typedef void (*WFSInitializeDeviceCallback)(WFSResult nResult, const utf8 *sDeviceName, void *pUserData); +typedef void (*WFSFileOpCallback )(WFSResult nResult, WFSFileHandle fh, void *pUserData); +typedef void (*WFSGetFileSizeCallback )(WFSResult nResult, u32 nFileSize, WFSFileHandle fh, void *pUserData); +typedef void (*WFSReadFileCallback )(s32 nResultOrNumBytesRead, WFSFileHandle fh, void *pUserData); +typedef void (*WFSGetFreeSpaceCallback )(WFSResult nResult, u64 nSize, void *pUserData); +typedef void (*WFSGetAttributesCallback )(WFSResult nResult, const WFSFileAttributes *pFa, void *pUserData); +typedef void (*WFSSearchDirectoryCallback )(WFSResult nResult, WFSSearchDirectoryHandle sdh, const WFSFileInfo *pFi, void *pUserData); +typedef void (*WFSSearchDirectoryCloseCallback)(WFSResult nResult, WFSSearchDirectoryHandle sdh, void *pUserData); +typedef void (*WFSGetPermissionsForUserCallback)(WFSResult nResult, u32 nFlags, void *pUserData); +typedef void (*WFSGetAccessListCallback )(s32 nResultOrNumAclEntries, void *pUserData); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif //define __WFSTYPES_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Api.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Api.h new file mode 100644 index 0000000..25fc198 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Api.h @@ -0,0 +1,166 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Api.h - global types used by the WFS kernel + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Api.h,v $ + Revision 1.13 2008/12/04 00:42:37 ooizumi + Changed definition name to enable permission. + + Revision 1.12 2008/09/28 23:30:00 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.11 2008/08/29 00:13:19 kondo_masahiro + Removed gPtr and gSize. + + Revision 1.10 2008/07/25 02:54:16 paul + Added TransInfo lists to wkg + + Revision 1.9 2008/07/17 22:43:08 paul + removed SubBlkTracker + + Revision 1.8 2008/07/17 22:14:25 paul + Added rootDirAttr + + Revision 1.7 2008/07/17 04:37:45 kondo_masahiro + Fixed codes for porting IOP. + + Revision 1.6 2008/07/09 01:06:24 paul + Added some definitions to support lists of mounted volumes. Moved block cache memory buffer into wkg. + + Revision 1.5 2008/06/09 18:16:25 paul + added devAttr + + Revision 1.4 2008/05/12 19:19:05 paul + Added SubBlkTracker + + Revision 1.3 2008/05/10 04:00:48 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.2 2008/04/25 17:28:32 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.1 2008/04/22 04:39:07 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.6 2008/04/23 00:55:23 paul + Updated WFSKrnGlobals + + Revision 1.5 2008/04/19 05:50:11 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.4 2008/02/29 02:38:02 kondo_masahiro + Fixed code to accept IOP compiler + + Revision 1.3 2008/02/28 02:38:02 kondo_masahiro + Fixed code to accept PPC compiler + + Revision 1.2 2008/02/27 07:27:11 paul + made areaHdrRoot a global so it could be accessed from debug code in wfskrn_Dir.cpp + + Revision 1.1 2007/12/27 11:40:03 paul + *** empty log message *** + +*---------------------------------------------------------------------------*/ + +#ifndef wfskrn_Api_h +#define wfskrn_Api_h + +#include "revolution/wfs.h" +#include "wfskrn_Config.h" +#include "wfskrn_Defs.h" +#include "wfskrn_Heap.h" +#include "wfskrn_Handles.h" +#include "wfskrn_Area.h" +#include "wfskrn_Bcache.h" +#include "wfskrn_Volume.h" +#include "wfskrn_PathCache.h" +#include "wfskrn_PTree.h" +#include "wfskrn_Device.h" +#include "wfskrn_Volume.h" + + +typedef struct VolumeLink_ { + struct VolumeInfo_ *pNext; + struct VolumeInfo_ *pPrev; +} VolumeLink; + +typedef struct VolumeInfo_ { + VolumeLink vl; + struct DeviceInfo_ *pDevInfo; + VolumeHdr vh; +#if _DEBUG + WFSVolumeId volId; +#endif + AreaInfo rootAreaInfo; + DirEntryAttrHdr rootAttr; + u32 nClientsMountedBy; // A bit vector. Up to 32 clients represented by a bit each. + bool bDetached; +} VolumeInfo; + + +#define WFSKRN_MAX_VOLUMES (WFSKRN_MAX_DEVICES + WFSKRN_MAX_MOUNTED_VOLUMES) +#define WFS_STATIC_MEM_TOTAL_SIZE (WFS_BLK_CACHE_SIZE + WFS_BCACHE_META_DATA_SIZE + WFS_STATIC_HEAP_SIZE + WFS_STATIC_MEM_ALIGNMENT) + +typedef struct { + u8 *pBlkCache; + u8 *pHeapData; + bool bKrnInitialized; + bool bMountedDeviceWasDetached; + WFSKrnHeap heap; + + //WFSKrnStrHashTbl strHTbl; + PathCache pathCache; + PTreeHdr ptreeHdr; + PTreeAllocator ptreeAllocator; + + WFSBlkAdr nRootDirBlkAdr; + + u32 nNumDevices; + DeviceInfo aDevInfo[WFSKRN_MAX_DEVICES]; + VolumeInfo aVolInfo[WFSKRN_MAX_VOLUMES]; + VolumeLink mountedVolListAnchor; + VolumeInfo *pMountedVolListAnchor; // double link list + VolumeInfo *pFreeVolList; // single link list (stack) + + DirEntryAttrHdr rootDirAttr; + DirEntryAttrHdr volDirAttr; + DirEntryAttrHdr devDirAttr; + DirEntryAttrHdr devAttr; + +#if _WIN32 || PERM_TEST + WFSTitleId nDebugTitleId; +#endif + TransInfo aTransInfo[WFSKRN_MAX_ACTIVE_TRANSACTIONS]; + TransInfoLink activeTransListAnchor; + TransInfo *pActiveTransListAnchor; + TransInfo *pTransInfoFreeList; + + WFSKrnHandles hnd; + WFSFileTime time; + + u8 aStaticMem[WFS_STATIC_MEM_TOTAL_SIZE]; // it includes block cache for meta block and heap data. +} WFSKrnGlobals; + + +extern WFSKrnGlobals wkg; + +extern DirItr gDi; + +extern AreaInfo *pAhInit; +extern WFSBlkAdr *pBaInit; + +//extern u8 *gpPtr; // Pointer of vdsk memory +//extern u32 gSize; // Size of vdsk memory + +extern u8 *gpHeapPtr; // Pointer of heap memory +extern u32 gHeapSize; // Size of heap memory + +#endif //define wfskrn_Api_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Area.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Area.h new file mode 100644 index 0000000..2588de4 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Area.h @@ -0,0 +1,328 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Area.h - Module for managing contiguous disk areas + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Area.h,v $ + Revision 1.24 2008/12/18 09:03:37 kondo_masahiro + Fixed function name and process from BCacheSetBlkAdr() to BCacheRemap() + + Revision 1.23 2008/12/17 01:37:42 kondo_masahiro + Added function BCacheSetBlkAdr() + + Revision 1.22 2008/11/26 01:46:19 kondo_masahiro + Fixed arguments of several functions in order to improve access speed. + + Revision 1.21 2008/10/17 08:51:27 kondo_masahiro + Added the new MEDIUM size category (40KB-320KB) + + Revision 1.20 2008/10/14 10:27:44 kondo_masahiro + Added codes to access very large size file data + + Revision 1.19 2008/10/10 02:11:49 kondo_masahiro + Fixed a bug to access large files + + Revision 1.18 2008/10/09 04:15:46 kondo_masahiro + Fixed member of AreaHdr and AreaInfo + + Revision 1.17 2008/10/08 23:20:09 kondo_masahiro + Added codes to access large size file data + + Revision 1.16 2008/09/28 23:30:08 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.15 2008/09/24 07:32:07 ueno + Added AclHdr{} to AreaHdr{} to save configuration of accesslists in a disk. + + Revision 1.14 2008/08/27 09:53:34 paul + Changed information in area header slightly. Added nStride to alloc, free functions + + Revision 1.13 2008/08/14 08:04:16 kondo_masahiro + Removed struct AreaHashHdr. + + Revision 1.12 2008/08/07 10:42:39 ueno + Modified for BTREE_BASED_ALLOCATOR. + + Revision 1.11 2008/08/05 04:17:15 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.10 2008/07/23 04:21:43 ueno + Modified AreaInfo{} for B-tree based allocator. + + Revision 1.9 2008/07/17 04:54:33 kondo_masahiro + Fixed codes for porting IOP. + + Revision 1.8 2008/07/09 01:12:34 paul + Many changes to area structs - to allow directory module to write via block cache, support volume initialization and mounting exisiting volumes. + + Revision 1.14 2008/04/28 20:20:57 wayne.wong + Changed the interface to block alloc slightly to return WFSKrnResult. + + Revision 1.13 2008/04/26 05:51:56 wayne.wong + Fixed prototype name and arg type. + + Revision 1.7 2008/05/10 04:00:48 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.6 2008/04/25 19:15:19 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.4 2008/04/25 06:22:55 ueno + Cleanup. + + Revision 1.3 2008/04/25 04:40:47 ueno + Added support for WFSDEV. + + Revision 1.12 2008/04/26 01:23:55 wayne.wong + Moved area functionality from Volume to Area module. Changed implementation + to support small area sizes for a large mapped number of sectors. Added + block wrapper calls for Area and BCache calls. + + Revision 1.11 2008/04/23 00:38:36 paul + Removed old defs + + Revision 1.10 2008/04/19 05:50:05 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.9 2008/04/18 09:04:48 nakanose_jin + merging acl + + Revision 1.8 2008/04/18 01:58:18 wayne.wong + Created separate Area types for persistent (hdr) and non-persistent (info) types. + Changed function names to be consistent with kernel naming convention. + Defines are included to support the previous naming, but will be deleted in + the future. + + Revision 1.7 2008/03/11 03:18:39 wayne.wong + Added sector information to the area header. + + Revision 1.6 2008/02/28 13:11:58 ueno + Revised to keep accesslist cache and indexlist handle in WFSAreaHdr{}. + + Revision 1.5 2008/02/28 06:37:24 kondo_masahiro + Fixed code to accept PPC compiler + + Revision 1.4 2008/02/27 11:17:16 ueno + Added fields for accesslist development to WFSAreaHdr{}. + + Revision 1.3 2008/02/20 07:10:44 paul + Added WfsAreaFreeBlks function, WFSTransBlkAdr struct + + Revision 1.2 2007/12/27 11:39:22 paul + preliminary API to help me proceed with the Dir module + + Revision 1.1 2007/11/16 05:44:48 paul + first checkin + + +*---------------------------------------------------------------------------*/ + +#ifndef wfs_Area_h +#define wfs_Area_h + +#ifdef _DEBUG + #define _CHECK_BLK_USAGE 0 // change to check for invalid area block and block cache usage + #define _CHECK_BLK_ALLOCATION 0 +#else + #define _CHECK_BLK_USAGE 0 + #define _CHECK_BLK_ALLOCATION 0 +#endif + +#include "wfskrn_Defs.h" +#include "wfskrn_BCache.h" +#include "wfskrn_Permission_AccessList_Type.h" + +///// The flag enables block cache. ///// +#define AREA_ENABLE_BLK_CACHE 1 + +#if AREA_ENABLE_BLK_CACHE + #define BTREE_BASED_ALLOCATOR 1 + #define LIST_BASED_ALLOCATOR 0 + #define SIMPLE_ALLOCATOR 0 +#else + #define BTREE_BASED_ALLOCATOR 0 + #define LIST_BASED_ALLOCATOR 0 + #define SIMPLE_ALLOCATOR 1 +#endif + + +#if BTREE_BASED_ALLOCATOR +#include "wfskrn_FreeBlkAlloc_Type.h" +#endif // BTREE_BASED_ALLOCATOR + +//#define AREA_SECTOR_SIZE 512 +//#define AREA_SECTOR_SIZE_BITS 9 + +#define AREA_PAGE_SIZE (1< (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define BITFIELD_USE_TEMPLATES 0 + +#include "wfskrn_Defs.h" + +//----------------------------------------------------------------------------------------------------------------- + +u32 WfsCalculateFieldSizeInBytes(u32 nVal); +u8 WfsCalculateFieldSizeInBits(u32 nVal); + +#if BITFIELD_USE_TEMPLATES + template unsigned WfsReadBitField (unsigned *aBitArray, int nStartBit); +#endif +unsigned WfsReadBitField(unsigned *aBitArray, int nStartBit, int nNumBits); +// Arguments: +// ---------- +// aBitArray is an array of machine sized unsigned int which are interpreted as a bit array. +// (The first bit of the array is the most significant bit of aBitArray[0]) +// nStartBit is the bit offset in the bit array to start reading from. +// Pre Conditions: 1 <= nNumBits <= BITS_PER_INT +// +// Return Values: +// -------------- +// Returns a machine sized unsigned int whose least significant nNumBits are the extracted bit field. +// +// Description: +// ------------ +// This function reads a bitfield of width nNumBits from a bit array. +// NOTE: It is up to the caller to mask off the least significant nNumBits bits of the return value +// if necessary, using a mask such as ((1< void WfsOverwriteBitField(unsigned *aBitArray, int nStartBit, unsigned nValue); +#endif +void WfsOverwriteBitField(unsigned *aBitArray, int nStartBit, unsigned nValue, int nNumBits, unsigned nMask); +// Arguments: +// ---------- +// aBitArray is an array of machine sized words which are interpreted as a bit array. +// (The first bit of the array is the most significant bit of aBitArray[0]) +// nValue is the value to write. +// nNumBits is the bit width of nValue. +// nStartBit is the bit offset in the bit array to start writing to. +// Pre Conditions: 1 <= nNumBits <= BITS_PER_INT; 0 < nValue < (1< Metadata 3840[B] +#define WFS_STATIC_MEM_ALIGNMENT 512 + +#define WFS_MAX_USER_BLK_CACHE_SIZE (512 * 1024) +#define WFS_MIN_USER_BLK_CACHE_SIZE (144 * 1024) + +// Special in-memory area at the top of WFS to hold "/dev", "/vol" directories +#define WFS_LOG2_PATH_CACHE_SIZE 15 + +#if _WIN32 + #define WFS_LOG2_MAX_AREA_SIZE 29 +#else + #define WFS_LOG2_MAX_AREA_SIZE 34 // Max area size of 16GB +#endif + +#define WFSKRN_MAX_ACTIVE_TRANSACTIONS 4 +#define WFSKRN_MAX_DEVICES 1 +#define WFSKRN_MAX_MOUNTED_VOLUMES 1 +#define WFSKRN_MAX_NUM_AREA_SIZES 10 // at least 5 (64MB, 256MB, 1GB, 4GB, and 16GB) +#define WFSKRN_MIN_AREA_SIZE (2*WFS_MIN_REGION_SIZE) // 64MB = 32MB + 32MB + +#define WFSKRN_FILE_HANDLE_IDX_BITS 5 +#define WFSKRN_SEARCH_DIR_HANDLE_IDX_BITS 5 + +#define WFSKRN_FILE_BUFFER_MEM_ALIGNMENT_SIZE 32 + +// block cache parameters +#define WFSKRN_BCACHE_HASH_TABLE_SIZE 47 // use for 512KB w/ 8KB pages? +#define WFSKRN_BCACHE_HASH_FN(_key) (_key % WFSKRN_BCACHE_HASH_TABLE_SIZE) +#define WFSKRN_BCACHE_HASH_LIST(_key) (gHash[WFSKRN_BCACHE_HASH_FN(_key)]) + +// parameter for CATEGORY VERY LARGE +#define WFSKRN_VERY_LARGE_MAP_NUM_INDIRECT_BLKS 8 + +#define PERMISSION_ENABLED +#define PERM_TEST 1 + +#endif //wfskrn_Config_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Defs.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Defs.h new file mode 100644 index 0000000..30d72a6 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Defs.h @@ -0,0 +1,107 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Defs.h - kernel definitions + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Defs.h,v $ + Revision 1.5 2008/11/05 15:05:44 ueno + Fixed a bug of WFS_ROUND_DOWN(). + + Revision 1.4 2008/10/17 08:51:27 kondo_masahiro + Added the new MEDIUM size category (40KB-320KB) + + Revision 1.3 2008/10/14 10:27:30 kondo_masahiro + Added #define _DEBUG_BREAK_POINT + + Revision 1.2 2008/07/09 01:29:34 paul + Added some macros to convert C definition __DATE__ (object file compilation date) to an integer. + + Revision 1.1 2008/04/22 04:39:07 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.3 2008/04/19 05:49:31 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.2 2007/12/27 11:36:55 paul + *** empty log message *** + + Revision 1.1 2007/11/05 19:03:13 paul + first checkin + +*---------------------------------------------------------------------------*/ + +#ifndef wfskrn_Defs_h +#define wfskrn_Defs_h + + +#define _WIN32_WINNT 0x500 + +#include "revolution/wfs.h" +#include "wfskrn_Platform.h" +#include "wfskrn_Config.h" +#include "wfskrn_Errors.h" +#include "wfskrn_Types.h" + +#if !_IOP +#include +#include +#include +#endif + +#ifndef true + #define true 1 +#endif + +#ifndef false + #define false 0 +#endif + +#define WFS_ROUND_UP(v,x) (((v)+(x)-1)&-((signed)x)) +#define WFS_ROUND_DOWN(v,x) ((v)&-((signed)x)) + +#define WFS_NUM_BITS_REQUIRED(x) \ + (((x)<3)?1:((x)<5)?2:((x)<9)?3:\ + ((x)<0x11)?4:((x)<0x21)?5:((x)<0x41)?6:((x)<0x81)?7:\ + ((x)<0x101)?8:((x)<0x201)?9:((x)<0x401)?10:((x)<0x801)?11:\ + ((x)<0x1001)?12:((x)<0x2001)?13:((x)<0x4001)?14:((x)<0x8001)?15:\ + ((x)<0x10001)?16:((x)<0x20001)?17:((x)<0x40001)?18:((x)<0x80001)?19:\ + ((x)<0x100001)?20:((x)<0x200001)?21:((x)<0x400001)?22:((x)<0x800001)?23:\ + ((x)<0x1000001)?24:((x)<0x2000001)?25:((x)<0x4000001)?26:((x)<0x8000001)?27:\ + ((x)<0x10000001)?28:((x)<0x20000001)?29:((x)<0x40000001)?30:((x)<0x80000001)?31:32) + +#define BYTES2BITS(b) ((b)<<3) + +#define BUILD_YEAR ((((__DATE__[7]-'0')*10+(__DATE__[8]-'0'))*10+(__DATE__[9]-'0'))*10+(__DATE__[10]-'0')) +#define BUILD_MONTH (__DATE__[2]=='n'?0:__DATE__[2]=='b'?1:__DATE__[2]=='r'?(__DATE__[0]=='M'?2:3):__DATE__[2]=='y'?4:__DATE__[2]=='n'?5:__DATE__[2]=='l'?6:__DATE__[2]=='g'?7:__DATE__[2]=='p'?8:__DATE__[2]=='t'?9:__DATE__[2]=='v'?10:11) +#define BUILD_DAY ((__DATE__[4]==' '?0:__DATE__[4]-'0')*10+(__DATE__[5]-'0')) +#define BUILD_DATE (((BUILD_YEAR-2000)*12+BUILD_MONTH)*31+BUILD_DAY) + +#ifndef swap_typ + #define swap_typ(Typ,a,b) { Typ t=a; a=b; b=t; } +#endif + +#ifdef _DEBUG + #ifndef _ASSERT + #define _ASSERT(x) ASSERT(x) + #endif +#else + #ifndef _ASSERT + #define _ASSERT(x) + #endif +#endif + +#ifdef _DEBUG + #define _DEBUG_BREAK_POINT 1 +#else + #define _DEBUG_BREAK_POINT 0 +#endif + + +#endif // wfskrn_Defs_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Device.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Device.h new file mode 100644 index 0000000..41599de --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Device.h @@ -0,0 +1,232 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Device.h - Storage device abstraction. + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Device.h,v $ + Revision 1.14 2008/12/10 06:54:02 kondo_masahiro + Added a argument WFSDevType nDevType in DeviceAttachDetachCallback. + + Revision 1.13 2008/11/26 02:43:58 kondo_masahiro + Added comments of DeviceRead/Write. + + Revision 1.12 2008/11/26 01:46:01 kondo_masahiro + Fixed arguments of several functions in order to improve access speed. + Fixed source code for Win32 version to enable easier debug. + + Revision 1.11 2008/10/09 01:40:14 kondo_masahiro + Fixed name of the function DeviceRead/WriteSingleBlk + + Revision 1.10 2008/10/08 23:20:09 kondo_masahiro + Added codes to access large size file data + + Revision 1.9 2008/10/03 08:37:18 kondo_masahiro + Fixed codes for porting IOP + + Revision 1.8 2008/09/30 02:02:27 ueno + Removed an obsolete define, WFSKRN_SIMULATED_DISK_SIZE. + + Revision 1.7 2008/09/28 23:30:24 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.6 2008/08/29 00:12:36 kondo_masahiro + Added DeviceGetVolumeId. + + Revision 1.5 2008/08/14 08:20:14 kondo_masahiro + Changed WFSKRN_SIMULATED_DISK_PATH + + Revision 1.4 2008/08/14 08:07:27 kondo_masahiro + Changed several APIs in order to access the large size file. + + Revision 1.3 2008/08/05 04:17:29 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.2 2008/07/17 05:07:43 kondo_masahiro + Added codes for IOP + + Revision 1.1 2008/07/09 01:39:12 paul + Merged device definitions from wfskrn_PMem.h and wfskrn_Api.h. + +*---------------------------------------------------------------------------*/ + +#ifndef _WFSKRN_DEVICE_H_ +#define _WFSKRN_DEVICE_H_ + +#if _WIN32 +#include +#include +#endif + +#include "revolution/wfs.h" +#include "wfs_Names.h" +#include "wfskrn_Defs.h" +#include "wfskrn_Config.h" + +#if _WIN32 +#include "msc_error.h" +#elif _TWL +#include "msc_error.h" +#elif _IOP +#include "msc_includes.h" +#endif + +#define DEVICE_EMBEDDED_HASH_DATA 1 // If it is on, the hash data is embedded to the written data. +#define DEVICE_VERIFY_HASH_DATA 1 // If it is on, DeviceRead can outputs error when two hash data discord. +#define DEVICE_DEBUG_PSEUDO_DEVICE_ERROR 1 + +#define DEVICE_IOP_MAX_ASYNC_NUM 2 + +#if _WIN32 + #define IOSError s32 + #define WFSKRN_SIMULATED_DISK_PATH "Y:\\TEMP\\shirait\\WFS_VOL_S\\" + typedef HANDLE DeviceHandle; // Windows handle +#elif _TWL + #define IOSError s32 + typedef u32 DeviceHandle; +#elif _RVL + typedef u32 DeviceHandle; +#elif _IOP + #define DEVICE_IOP_MSC_CHECK(mscfunc) if(mscfunc < IOS_ERROR_OK){ return WFSKRN_RESULT_DEVICE_ERROR; } + typedef HardDisc* DeviceHandle; +#else +#endif //_WIN32 + + +//#define _DEBUG_WFSKRN_DEVICE_ + +#ifdef _DEBUG_WFSKRN_DEVICE_ +#define dbgd(_s) (_s) +#else +#define dbgd(_s) +#endif // _DEBUG_WFSKRN_DEVICE_ + + +typedef struct DeviceHdr_ { + u32 nLog2SectorSize; // 1st field: Base 2 logarithm of the sector size (default = 9 corresponding to 512 byte sectors) + u32 nNumSectors; // 2nd field; capacity of device +} DeviceHdr; + +typedef struct DeviceInfo_ { + DeviceHdr dh; +#if _WIN32 + HANDLE hSimulatedDeviceFile; +#endif + // + bool bInUse; + u32 nSectorSize; + u64 nTotalCapacity; + DeviceHandle nDeviceDevHandle; + struct VolumeInfo_ *pVolInfo; + WFSDeviceName devName; + WFSDevType nDevType; + u8 nFlags; +} DeviceInfo; + + +// Initialize Device library +void DeviceInitLib(); + +#if _IOP +// Regist callback function for attach/detach device +typedef void (*DeviceAttachDetachCallback)(u32 bAttach, u32 nDevIdx, u32 nLog2SectorSize, u32 nTotalSize, WFSDevType nDevType, void *pUserData); +void DeviceAttachDetachRegistCallback(DeviceAttachDetachCallback cbAttach, void *pUserData); +#endif + +WFSKrnResult DeviceRead(DeviceInfo *pDevInfo, u32 nSectorAdr, u8 *pBuffer, u32 nSectors, WFSHashCode *pHash, u32 nLog2HashSectors, u32 nOffsetHashBlks, s32 nHashStride, s32 nHashStridePerMaxLBlks); +// Arguments: +// ---------- +// pDevInfo [IN] .. A pointer of DeviceInfo. +// nSecrorAdr [IN] .. A head sector address of HDD to read. +// pBuffer [OUT] .. A pointer of read buffer. +// nSectors [IN] .. A read sector size of HDD. +// pHash [IN] .. A pointer to compare the hash value. +// nLog2HashSectors [IN] .. A sector size unit for hash value. The hash value is calculated for each the unit. +// nOffsetHashBlks [IN] .. A offset block size for nHashStridePerMaxLBlks. +// nHashStride [IN] .. A stride of hash address for each hash size unit. +// nHashStridePerMaxLBlks [IN] .. A stride of hash address for each 512KB unit. +// +// Description: +// ------------ +// Read nSector from device pDevInfo starting at LBA nSectorAdr into buffer pBuffer. +// nLog2HashSector is the hash size unit. The argument nLog2HashSector must be indicate up to 64KB (~16). +// The hash value is calculated and compared with pHash for each buffer size nLog2HashSector. +// The hash address pHash is added by nHashStride for each buffer size nLog2HashSector. +// After total hash calculation size is reached to the multiples of 512KB, +// The hash address pHash is added by nHashStride and nHashStridePerMaxLBlks for "SIZE_CATEGORY_LARGE". +// For example, When nLog2HashSectors is 16(64KB) and nOffsetHashBlks is 3, +// The hash address up to 5th block are added by nHashStride. (512 / 64 - 3 = 5) +// The hash address of 6th block is added by nHashStride and nHashStridePerMaxLBlks. + +static inline WFSKrnResult DeviceReadSingleBlk(DeviceInfo *pDevInfo, u32 nSectorAdr, u8 *pBuffer, u32 nSectors, WFSHashCode *pHash, u32 nLog2HashSectors){ + dbgd(printf("DeviceRead()\n")); + ASSERT(nSectors <= 1<<(WFS_LOG2_MAX_HASHABLE_BLK_SIZE-pDevInfo->dh.nLog2SectorSize) ); // ~64KB + return DeviceRead(pDevInfo, nSectorAdr, pBuffer, nSectors, pHash, nLog2HashSectors, 0, 0, 0); +} + +WFSKrnResult DeviceWrite(DeviceInfo *pDevInfo, u32 nSectorAdr, u8 *pBuffer, u32 nSectors, WFSHashCode *pHash, u32 nLog2HashSectors, u32 nOffsetHashBlks, s32 nHashStride, s32 nHashStridePerMaxLBlks, bool bDecryption); +// Arguments: +// ---------- +// pDevInfo [IN] .. A pointer of DeviceInfo. +// nSecrorAdr [IN] .. A head sector address of HDD to read. +// pBuffer [IN] .. A pointer of read buffer. +// nSectors [IN] .. A read sector size of HDD. +// pHash [OUT] .. A pointer to store the hash value. +// nLog2HashSectors [IN] .. A sector size unit for hash value. The hash value is calculated for each the unit. +// nOffsetHashBlks [IN] .. A offset block size for nHashStridePerMaxLBlks. +// nHashStride [IN] .. A stride of hash address for each hash size unit. +// nHashStridePerMaxLBlks [IN] .. A stride of hash address for each 512KB unit. +// bDecryption [IN] .. A flag to indicate whether buffer is decrypted after write access or not. +// +// Description: +// ------------ +// Write nSector from device pDevInfo starting at LBA nSectorAdr into buffer pBuffer. +// nLog2HashSector is the hash size unit. The argument nLog2HashSector must be indicate up to 64KB (~16). +// The hash value is calculated and stored to pHash for each buffer size nLog2HashSector. +// The hash address pHash is added by nHashStride for each buffer size nLog2HashSector. +// After total hash calculation size is reached to the multiples of 512KB, +// The hash address pHash is added by nHashStride and nHashStridePerMaxLBlks for "SIZE_CATEGORY_LARGE". +// For example, When nLog2HashSectors is 16(64KB) and nOffsetHashBlks is 3, +// The hash address up to 5th block are added by nHashStride. (512 / 64 - 3 = 5) +// The hash address of 6th block is added by nHashStride and nHashStridePerMaxLBlks. + +static inline WFSKrnResult DeviceWriteSingleBlk(DeviceInfo *pDevInfo, u32 nSectorAdr, u8 *pBuffer, u32 nSectors, WFSHashCode *pHash, u32 nLog2HashSectors, bool bDecryption){ + dbgd(printf("DeviceWrite()\n")); + ASSERT(nSectors <= 1<<(WFS_LOG2_MAX_HASHABLE_BLK_SIZE-pDevInfo->dh.nLog2SectorSize) ); // ~64KB + return DeviceWrite(pDevInfo, nSectorAdr, pBuffer, nSectors, pHash, nLog2HashSectors, 0, 0, 0, bDecryption); +} + +// Get the device info from the device name (from the path cache) +DeviceInfo *DeviceGetDeviceInfo(const WFSDeviceName *pDevName); + +// Get a volume id from the device name even if the device is not mounted. +WFSKrnResult DeviceGetVolumeId(const WFSDeviceName *pDevName, WFSVolumeId *pVolId); + +// Mount a volume +WFSKrnResult DeviceMountVolume(DeviceInfo *pDevInfo); + +// Attach a device - called when user physically attaches a drive +WFSKrnResult DeviceAttach(DeviceInfo *pDevInfo, WFSDevType nDevType, u32 nDevIdx, u32 Log2SectorSize, u32 nNumSectors); + +// Detach a device - called when user physically detaches a drive +WFSKrnResult DeviceDetach(DeviceInfo *pDevInfo); + +//// Debug functions +void DeviceDebugSetPseudoDetachDevice(s32 cnt); +void DeviceDebugSetPseudoHashInconsistent(s32 cnt); +s32 DeviceDebugGetPseudoDetachDevice(); +s32 DeviceDebugGetPseudoHashInconsistent(); + +#if _WIN32 // * Windows version * +#define DeviceOverhead() (2*sizeof(u32)) // overhead for simulating a device +#else +#define DeviceOverhead() 0 +#endif // _WIN32 + +#endif // _WFSKRN_DEVICE_H_ diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Dir.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Dir.h new file mode 100644 index 0000000..c0058df --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Dir.h @@ -0,0 +1,800 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Dir.h - Directory Module + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Dir.h,v $ + Revision 1.28 2008/12/04 00:42:37 ooizumi + Changed definition name to enable permission. + + Revision 1.27 2008/11/19 05:02:53 ooizumi + Fixed typo. + + Revision 1.26 2008/11/18 04:57:11 saito_tomoya + Modified SetBit() and added SetBitArray(). + + Revision 1.25 2008/11/07 08:55:16 kondo_masahiro + Added DirCalculateAttrSubBlkLog2SizeUpdateAllocSize() + + Revision 1.24 2008/11/04 00:25:07 kondo_masahiro + Added DirSbaAllocAndRegistSubBlk() + + Revision 1.23 2008/10/31 09:51:42 ueno + Modified WFSSrvAPIs to return WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED when path cache is short of memory. + + Revision 1.22 2008/10/30 05:09:05 kondo_masahiro + Added DirCheckDisk + + Revision 1.21 2008/10/24 09:02:25 kondo_masahiro + Added decrease block process of DirResize. + + Revision 1.20 2008/10/17 08:51:27 kondo_masahiro + Added the new MEDIUM size category (40KB-320KB) + + Revision 1.19 2008/10/16 09:25:53 ooizumi + Fixed definitions for debug build. + + Revision 1.18 2008/10/14 10:27:44 kondo_masahiro + Added codes to access very large size file data + + Revision 1.17 2008/10/10 02:11:31 kondo_masahiro + Fixed a bug to access large files + + Revision 1.16 2008/10/09 04:15:46 kondo_masahiro + Fixed member of AreaHdr and AreaInfo + + Revision 1.15 2008/10/08 23:20:09 kondo_masahiro + Added codes to access large size file data + + Revision 1.14 2008/10/07 10:30:34 ooizumi + Added nObjCreator to DirEntryAttrHdr. + + Revision 1.13 2008/09/28 23:30:31 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.12 2008/08/27 09:49:46 paul + Started coding for different size categories + + Revision 1.11 2008/08/05 04:17:43 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.10 2008/07/28 22:26:54 paul + Improved updateMap processing. Added DirGetBlk(). + + Revision 1.9 2008/07/25 02:56:12 paul + Changed nTransIdx to *pTransInfo. Changed WFSTransBlkAdr to TransBlkAdr + + Revision 1.8 2008/07/21 22:50:42 paul + Changed name from DirItrPinBlkAndUpdatePtrs() -> DirItrPinBlkAndFixPtrs() + + Revision 1.7 2008/07/17 22:23:52 paul + Changes for update counters + + Revision 1.6 2008/07/09 01:33:13 paul + Added DirItrCloseNoUnpin alternative to DirItrClose to give the option of unpinning the cache block while closing an interator. Made other minor changes. + + Revision 1.5 2008/06/09 18:15:30 paul + No longer storing the non-persistent state: number of open read/write handles per file, within file attributes - moved this info to path cache which is non-persistent. + + Revision 1.4 2008/05/12 19:20:28 paul + Added a list of open directory iterators. + + Revision 1.3 2008/05/10 04:00:48 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.2 2008/04/25 17:28:21 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.14 2008/04/23 01:30:14 paul + Continued updating and documenting Dir API + + Revision 1.13 2008/04/19 05:49:25 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.12 2008/04/18 00:09:02 paul + Changed interface to Dir functions + + Revision 1.11 2008/04/15 18:35:38 paul + Changed definition of DirFind to take separate nMaxBlkDepth and nFlags parameters. + + Revision 1.10 2008/04/05 03:10:40 paul + Many changes for Delete and associated testing. + + Revision 1.9 2008/03/07 01:38:35 paul + added DIR_PREFIX_SEARCH + + Revision 1.8 2008/02/29 02:29:46 paul + Added Delete functions, fixed DirCreateAndInitNewBlk4 parameters + + Revision 1.7 2008/02/28 06:32:42 kondo_masahiro + Fixed code to accept PPC compiler + + Revision 1.5 2008/02/21 04:30:54 paul + reorganization + + Revision 1.4 2008/02/21 01:36:56 paul + moved DIR_MAX_BLK_DEPTH to header file + updated definition for DirFind + + Revision 1.3 2008/02/21 00:11:34 paul + Moved SubBlk allocation out of the dir module making it more generic. Now DirBlkHdr pseudo-inherits from WFSSubBlkAllocHdr, which in turn inherits from WFSMetaDataHdr + + Revision 1.2 2008/02/20 07:46:21 paul + Numerous changes + + Revision 1.1 2007/12/27 11:36:29 paul + still at an early stage of development + + Revision 1.2 2007/11/08 05:29:16 paul + continued with block layout initialization code + + Revision 1.1 2007/11/05 19:03:13 paul + first checkin + +*---------------------------------------------------------------------------*/ + +#ifndef wfskrn_Dir_h +#define wfskrn_Dir_h + +#include "wfskrn_Config.h" +#include "wfskrn_SubBlkAlloc.h" +#include "wfskrn_Trans.h" +#include "wfskrn_PTree.h" + +#ifdef _DEBUG + #define _DEBUG_DIR 1 // change to 1 if debug info required +#else + #define _DEBUG_DIR 0 +#endif + +#define DIR_MAX_BLK_DEPTH 5 +#define DIR_PREFIX_SEARCH ((u32)-2) +#define DIR_PREFIX_SUPPRESSION 0 + +#define DIR_SUB_BLK_TYPE_RADIX_NODE 0x00 +#define DIR_SUB_BLK_TYPE_BLK_PTR 0x01 + +#define DIR_SPLIT_BLK_ADR 0 + +// Flags which are store in the same variable as: WFS_FLAG_IS_A_DIRECTORY, WFS_FLAG_CONTIGUOUS_AREA +#define FILE_SIZE_CATEGORY_VERY_SMALL 0 // Files which fit in the directory leaf block. (up to about 960 bytes - also depends on file name length) +#define FILE_SIZE_CATEGORY_SMALL 1 // Files where the attr block points to between 1 and 5 small blocks. +#define FILE_SIZE_CATEGORY_MEDIUM 2 // Files where the attr block points to between 1 and 5 medium blocks. +#define FILE_SIZE_CATEGORY_LARGE 3 // Files where the attr block points to between 1 and 12 large blocks. +#define FILE_SIZE_CATEGORY_VERY_LARGE 4 // Files where the attr block points to indirect blocks which point to large blocks. + + + +#if _DEBUG_DIR + extern bool bCheckDirBlks; +#endif + +#if _DEBUG_DIR + extern u32 nDirTest; + extern u32 nDirTestBreakPoint; + extern u32 nDirTotalTests; +#endif + +typedef struct { + WFSSubBlkAllocHdr sbah; + u16 nRootOfs; + u16 nNumRecs; // Number of records in the block, not the whole directory +} DirBlkHdr; + +#pragma pack(1) +#define SIZE_OF_DIRSUBBLKHDR 3 +typedef struct { + u8 nStrLen; + u8 nNumEntries; + utf8 aFirstChar[1]; +} _ATTRIBUTE_PACKED DirSubBlkHdr; +#pragma pack() + +typedef struct DirNodeStack_ DirNodeStack; +struct DirNodeStack_ { + DirNodeStack *pParent; + WFSBlkAdr nBlkAdr; + u32 nUpdateCtr; // Compared against counter stored in dir blocks to determine whether the block has been changed since this iterator was last used. + u16 nSubBlkOfs; + u8 nEntryIdx; + u8 nStrIdx; +}; + +typedef struct { + u16 *pOfs; // A pointer to the offset pointer to the node. This would need to be updated if the sub block is relocated. + DirSubBlkHdr *pSubBlkHdr; // A pointer to the sub block containing the node. + u32 nLog2Size; // The base 2 logarithm of the size of the sub block containing the node. + utf8 *pStrPtr; // A string pointer to the current cursor position within the search name. After DirFind(), it points to the first mismatch. + utf8 *pNodeStrPtr; // A string pointer to the current cursor position within the node string. After DirFind(), it points to the first mismatch. + u32 nEntryIdx; // The entry index of the choice within the current node which is closest but <= search name during DirFind(). + DirNodeStack *pDns; // A stack of locators within dir node sub blks recording the path taken through the name radix tree + u32 nDnsDepth; // Number of entries in the DirNodeStack +} DirNodeItr; + +typedef struct { + u32 nSize; + u16 nContentIdx; + u16 nVersion; +} DirFileAttr; + +typedef struct { + WFSBlkAdr nQuota; // Quota in multiples of blocks + WFSBlkAdr nSubDirBlkAdr; +} DirDirAttr; + +typedef struct { + u32 nAccessListIdx; + u32 nAllocSize; + WFSFileTime timeCreated; + WFSFileTime timeUpdated; +#ifdef PERMISSION_ENABLED + WFSTitleId nObjCreator; +#endif + union { + DirFileAttr file; + DirDirAttr dir; + }; + u8 nAttrLog2Size; // Log to the base 2 of the file attributes sub-block + u8 nSizeCategory; // Size category of the file + u8 nNameLen; // Length of the file name + u8 aCaseBitArray[1]; // (variable size) A bit per character of the file name to indicate whether each character is upper or lower case +} DirEntryAttrHdr; + +typedef struct { + struct DirItr_ *pNext; + struct DirItr_ *pPrev; +} DirItrLink; + +typedef struct DirItr_ { + DirItrLink link; + u32 nBlkDepth; // The depth of the block currently pointed to by the iterator. Normally, set to 0 before calling DirFind* functions. + TransBlkAdr tba; // The block currently pointed to by the iterator. Normally, set to the root block of the directory before calling DirFind* functions. + DirEntryAttrHdr *pAttrHdr; // Pointer to the file/dir attributes of the current file. + DirBlkHdr *pBlkHdr; // Pointer to start of block tba.nBlkAdr in memory. (Start of the block is the block header). + u32 nUpdateCtr; // Update counter of the block referenced by tba.nBlkAdr + DirNodeItr dni; + DirNodeStack **ppDnsRootParent; // Pointer to the parent link within the root dir node stack entry - to allow for easy freeing of the whole dir node stack. + WFSFileName name; // Name of the current entry pointed to by the iterator. +} DirItr; // Directory Iterator + +#define MAX_INDIRECT_FILE_DEPTH 3 + +typedef struct { + //TransBlkAdr tba; + //u32 nPos; + u8 *pDataPtr; + u32 nRemainingBlkSize; +} DirFilePos; + +typedef struct { + //TransBlkAdr tba; + //u32 nPos; + WFSFileBlkPtr *pFileBlkPtr; + u32 nRemainingBlkSize; +} DirFilePosMedium; + +WFSKrnResult DirFindFilePos(DirItr *pDi, WFSFileSize nPos, DirFilePos *pFpos, u32 nTransFlags); +WFSKrnResult DirResizeFile(DirItr *pDi, WFSFileSize nNewSize); + +// ToDo: Now that a WFSFileName member has been added to DirItr, I should check for performance problems +// introduced by indiscriminate copies of DirItr structs. Some Dir functions which define a local WFSFileName +// could possibly use the storage space within the DirItr instead (eDirLeafBlkSplit, DirNodeBlkSplit). + +typedef struct { + utf8 aToLower[256]; + utf8 aToUpper[256]; + DirItrLink openDirItrListAnchor; + DirItr *pOpenDirItrListAnchor; + PTreeHdr updateMap; // Maps from nBlkAdr to nUpdateCtr for directory blocks which are referenced by currently open directory iterators + PTreeAllocator updateMapAllocator; +} DirGlobals; + +extern DirGlobals dirGlobals; + +u32 DirLeafGetSubBlkLog2Size_2(u32 nStrLen, u32 nNumEntries); +u32 DirNodeGetSubBlkLog2Size_3(u32 nStrLen, u32 nNumEntries, utf8 cFirstChoice); +u32 DirCalculateAttrSubBlkLog2Size(AreaInfo *pAreaInfo, u32 nAllocSize, u32 nNameLen, u8 *pSizeCategory); +u32 DirCalculateAttrSubBlkLog2SizeDecrease(AreaInfo *pAreaInfo, u32 nAllocSize, u32 nNameLen, u8 *pSizeCategory); +u32 DirCalculateAttrSubBlkLog2SizeUpdateAllocSize(AreaInfo *pAreaInfo, u32 *pAllocSize, u32 nNameLen, u8 *pSizeCategory); +u32 DirCalculateAttrSubBlkLog2SizeDecreaseUpdateAllocSize(AreaInfo *pAreaInfo, u32 *pAllocSize, u32 nNameLen, u8 *pSizeCategory); + +void DirModuleInit(); + +void DirLeafCheckBlk(DirItr *pDi); +void DirNodeCheckBlk(DirItr *pDi); +void DirCheckBlk(DirItr *pDi); + +#define DIR_CHECK_DISK_FOR_DIR_TREE 0 +#define DIR_CHECK_DISK_FOR_ACL_TREE 1 +WFSKrnResult DirCheckDisk(WFSBlkAdr rootBlkAdr, DirItr *pDi, WFSSrvFileHandle fh, u8* pBuffer, u32 bufferSize, u32 nFlag); + +WFSKrnResult DirGetBlk(DirItr *pDi, u32 nTransFlags, DirBlkHdr **ppBlkHdr); + +WFSKrnResult DirCreateAndInitNewBlk4(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, WFSMetaDataFlags nFlags, TransInfo *pTransInfo, DirBlkHdr **ppBlkHdr); +//WFSKrnResult DirCreateAndInitNewBlk(TransBlkAdr *pTba, WFSMetaDataFlags nFlags, DirBlkHdr **ppBlkHdr); +void DirBlkCreateRootNode(DirBlkHdr *pBlkHdr); + +WFSKrnResult DirReGetHashAdr(AreaInfo *pAreaInfo, DirEntryAttrHdr *pAttrHdr, WFSBlkAdr nNewBlkAdr, DirBlkHdr* pNewBlkHdr); + +WFSKrnResult DirSbaAllocAndRegistSubBlk(WFSFileName *pName, DirItr *pDi, u32 nLog2Size, DirEntryAttrHdr **ppNewAttrHdr); + +WFSKrnResult DirFindNameWithoutCaseConversion(DirItr *pDi); + + +WFSKrnResult DirFindName(WFSFileName *pName, DirItr *pDi); +// Arguments: +// ---------- +// pName [IN/OUT] .. A pointer to a WFSFileName struct containing the utf8 name to search for. +// pDi [OUT] .. A pointer to a DirItr struct which will be updated with the search location. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. The name was found. *pDi is overwritten with the contents of the directory iterator. +// WFSKRN_RESULT_NOT_FOUND .. The specified name was not found. +// Other error codes are possible - passed back from lower level functions +// +// Description: +// ------------ +// This function searches for a specific name in the directory, and if a match is found, returns the location of the +// file or sub-directory attributes for the associated entry. +// NOTE: Some parts of the directory iterator structure are allocated dynamically, and must be freed +// by calling DirItrClose() when pDi is no longer needed. + + +WFSKrnResult DirFindRaw(DirItr *pDi); +// Arguments: +// ---------- +// pDi [IN/OUT] .. A pointer to DirItr struct which will be updated with the details of the location. +// pDi->name contains a raw input name to search for (will not be case-converted) +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. The name was found. *ppAttr is overwritten with the contents of the associated attributes block. +// WFSKRN_RESULT_NOT_FOUND .. The specified name was not found. +// Other error codes are possible - passed back from lower level functions +// +// Description: +// ------------ +// This function searches for a specific raw name in the directory, and if a match is found, returns the location of the +// attributes for the associated entry. +// NOTE: This function is provided to support Access-lists, and should not be used for normal directories. +// Some parts of the directory iterator structure are allocated dynamically, and must be freed +// by calling DirItrClose() when pDi is no longer needed. + + +WFSKrnResult DirFindFirstNamePrefixMatch(WFSFileName *pName, DirItr *pDi); +// Arguments: +// ---------- +// pName [IN/OUT] .. A pointer to a WFSFileName struct containing the prefix of the utf8 name to search for. +// pDi [OUT] .. A pointer to a directory iterator struct which stores information about the file location. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. The first name which starts with the prefix was found. *pDi contains the location of the file/dir attributes block. +// WFSKRN_RESULT_NOT_FOUND .. No name was found which starts with the specified prefix. +// Other error codes are possible - passed back from lower level functions +// +// Description: +// ------------ +// This function searches the directory for a name which starts with a specified prefix. If one or more matching names exsit, +// this function returns the location of the first match, and the corresponding entry attributes data in *pDi. +// pDi can be passed to DirFindNext() to find the next entry in the directory. +// NOTE: Some parts of the directory iterator structure are allocated dynamically, and must be freed +// by calling DirItrClose() when pDi is no longer needed. + + +WFSKrnResult DirNextName(WFSFileName *pName, DirItr *pDi); +// Arguments: +// ---------- +// pName [OUT] .. A pointer to a WFSFileName struct containing the file name to search for. +// pDi [IN/OUT] .. A pointer to a directory iterator struct which stores information about the file location. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. A next entry was found. *pName and *pDi were updated. +// WFSKRN_RESULT_NOT_FOUND .. No further entries were found. +// Other error codes are possible - passed back from lower level functions +// +// Description: +// ------------ +// This function increments the directory iterator to the next entry (in lexicographical order) +// The name of the next entry is returned in *pName. The directory location including file attributes is returned in *pDi. +// NOTE: Some parts of the directory iterator structure are allocated dynamically, and must be freed +// by calling DirItrClose() when pDi is no longer needed. + + +WFSKrnResult DirNextRaw(WFSFileName *pName, DirItr *pDi); +// Arguments: +// ---------- +// pName [OUT] .. A pointer to a WFSFileName struct containing the file name to search for. +// pDi [IN/OUT] .. A pointer to a directory iterator struct which stores information about the file location. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. A next entry was found. *pName and *pDi were updated. +// WFSKRN_RESULT_NOT_FOUND .. No further entries were found. +// Other error codes are possible - passed back from lower level functions +// +// Description: +// ------------ +// This function increments the directory iterator to the next entry (in lexicographical order) +// The name of the next entry is returned in *pName. The directory location including file attributes is returned in *pDi. +// NOTE: Some parts of the directory iterator structure are allocated dynamically, and must be freed +// by calling DirItrClose() when pDi is no longer needed. + + +WFSKrnResult DirItrClose(DirItr *pDi); +// Arguments: +// ---------- +// pDi [IN] .. A pointer to a directory iterator struct. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. The directory iterator was successfully closed. +// Other error codes may be possible - passed back from lower level functions +// +// Description: +// ------------ +// This function closes the directory iterator and frees up dynamically allocated resources. +// Includes unpinning the currently referenced block + + +WFSKrnResult DirItrCloseNoUnpin(DirItr *pDi); +// Arguments: +// ---------- +// pDi [IN] .. A pointer to a directory iterator struct. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. The directory iterator was successfully closed. +// Other error codes may be possible - passed back from lower level functions +// +// Description: +// ------------ +// This function closes the directory iterator and frees up dynamically allocated resources. +// Does not include unpinning the currently referenced block + + + +WFSKrnResult DirInsertName(WFSFileName *pName, DirItr *pDi, u32 nAllocSize); +// Arguments: +// ---------- +// pName [IN] .. A pointer to a WFSFileName struct containing a utf-8 name string to insert. +// pDi [OUT] .. A pointer to a directory iterator struct which represents the location within the directory. +// nAllocSize [IN] .. The initial size of the file. When creating sub-directories, use nAllocSize = 0. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. The name was inserted successfully. +// WFSKRN_RESULT_ALREADY_EXISTS .. A conflicting name already exists in the directory. +// Other error codes may be possible - passed back from lower level functions +// +// Description: +// ------------ +// This function inserts a utf-8 name into the directory. The case information for each character is stored, but is ingored +// when comparing with existing names, so the name will conflict with an existing name which differs only in capitalization. + + +WFSKrnResult DirInsertRaw(WFSFileName *pName, DirItr *pDi, u32 nAllocSize); +// Arguments: +// ---------- +// pName [IN] .. A pointer to a WFSFileName struct containing a raw name to insert. (The name can use any 8-bit characters but must be 0 terminated). +// pDi [OUT] .. A pointer to a directory iterator struct. +// nAllocSize [IN] .. The initial size of the file. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. The name was inserted successfully. +// WFSKRN_RESULT_ALREADY_EXISTS .. The same name already exists in the directory. +// Other error codes may be possible - passed back from lower level functions +// +// Description: +// ------------ +// This function inserts a raw string into the directory. No case manipulations are performed, +// so the comparison with existing names is case-sensitive. +// NOTE: This function is provided to support Access-lists, and should not be used for normal directories. + + +WFSKrnResult DirDeleteEntry(DirItr *pDi); +// Arguments: +// ---------- +// pDi [OUT] .. A pointer to a directory iterator struct which is pointing to a particular entry. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. The entry name and its associated attribute data was deleted successfully from the directory. +// Other error codes may be possible - passed back from lower level functions +// +// Description: +// ------------ +// This function deletes an entry from a directory. This includes deleting the attribute data for the file or sub-directory, +// but does not include deleting separate data blocks or meta-data blocks associated with the file or sub-directory. +// One of the DirFind* functions should be used to + + +WFSKrnResult DirDeleteFile(DirItr *pDi); +// Arguments: +// ---------- +// pDi [IN] .. A pointer to a directory iterator struct which is pointing to a particular entry. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. The file was deleted successfully. +// Other error codes may be possible - passed back from lower level functions +// +// Description: +// ------------ +// This function deletes the data blocks and meta-data blocks associated with a file entry, but does not delete +// the entry itself from its parent directory. + + +WFSKrnResult DirDeleteSubDir(DirItr *pDi); +// Arguments: +// ---------- +// pDi [IN] .. A pointer to a directory iterator struct which is pointing to a particular entry. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. The sub directory was deleted successfully. +// WFSKRN_RESULT_NOT_EMPTY .. The sub directory is not empty, and was not deleted. +// Other error codes may be possible - passed back from lower level functions +// +// Description: +// ------------ +// This function deletes the root block associated with a sub-directory entry, but does not delete +// the entry itself from its parent directory. + + +void DirInitDirEntryAttrHdr(DirEntryAttrHdr *pAttrHdr); +void DirInitFileEntryAttrHdr(DirEntryAttrHdr *pAttrHdr); +WFSKrnResult DirItrPinBlkAndFixPtrs(DirItr *pDi, u32 nTransFlags); +WFSKrnResult DirItrMapBlks(DirItr *pDi); +void DirItrUnmapBlks(DirItr *pDi); +WFSKrnResult DirItrCheckMapBlks(DirItr *pDi); +WFSKrnResult DirItrCheckAndUnmapBlks(DirItr *pDi); + +void WFSKrnCopyFileName(WFSFileName *pDst, WFSFileName *pSrc); +void WFSKrnCopyStrAndConvertToLowerCase(utf8 *pDstStr, const utf8 *pSrcStr, u32 nLen); +void WFSKrnCopyFileNameAndConvertToLowerCase(WFSFileName *pDst, WFSFileName *pSrc); +void WFSKrnCopyFileNameAndRestoreCase(utf8 *pDst, WFSFileName *pSrc, u8 *pCaseBitArray); +WFSKrnResult WFSKrnValidateCopyStrAndConvertToLowerCase(utf8 *pDstStr, const utf8 *pSrcStr, u32 nLen, u32 nMaxLen); + +void WFSKrnStoreCaseInformationStr(u8 *pCaseBitArray, const utf8 *pStr, u32 nLen); + +static inline WFSKrnResult DirCreateAndInitNewBlk(TransBlkAdr *pTba, WFSMetaDataFlags nFlags, DirBlkHdr **ppBlkHdr) { + return DirCreateAndInitNewBlk4(pTba->pAreaInfo, pTba->nBlkAdr, nFlags, pTba->pTransInfo, ppBlkHdr); +} + +static inline void WFSKrnStoreCaseInformation(u8 *pCaseBitArray, WFSFileName *pName) { + WFSKrnStoreCaseInformationStr(pCaseBitArray, pName->sStr, pName->nLen); +} + +// Inline Functions for FILE_SIZE_CATEGORY_SMALL // 1 block = 8KB (small block size) +static inline WFSFileBlkPtr *WFSKrnGetFileBlkPtrForCategorySmall(DirEntryAttrHdr *pAttrHdr, u32 nAttrLog2Size, u32 nBlkIdx){ + return (WFSFileBlkPtr *)((size_t)pAttrHdr + (1<nBlkAdr; + fileBlkInfo.pHash = &pFileBlkPtr->hash; + return fileBlkInfo; +} + +static inline WFSFileBlkInfo WFSKrnGetFileBlkInfoForCategorySmallCast(AreaInfo *pAreaInfo, void *pMetaData, u32 nLog2MetaSize, u32 nBlkIdx){ + return WFSKrnGetFileBlkInfoForCategorySmall(pAreaInfo, (DirEntryAttrHdr*)pMetaData, nLog2MetaSize, nBlkIdx); +} + +// Inline Functions for FILE_SIZE_CATEGORY_MEDIUM // 1 block = 64KB (small block size) +#define WFSKrnGetFileBlkPtrForCategoryMedium WFSKrnGetFileBlkPtrForCategorySmall +#define WFSKrnGetFileBlkInfoForCategoryMedium WFSKrnGetFileBlkInfoForCategorySmall +#define WFSKrnGetFileBlkInfoForCategoryMediumCast WFSKrnGetFileBlkInfoForCategorySmallCast + +// Inline Functions for FILE_SIZE_CATEGORY_LARGE // Meddium Block Size = 64KB (Max hash size) +static inline WFSFileLargeBlkPtr *WFSKrnGetFileLargeBlkPtrForCategoryLarge(DirEntryAttrHdr *pAttrHdr, u32 nAttrLog2Size, u32 nLargeBlkIdx){ + return (WFSFileLargeBlkPtr *)( (size_t)pAttrHdr + (1<nBlkAdr+(nMedBlkIdx<nLog2BlksPerMediumBlk); + fileBlkInfo.pHash = &pFileLargeBlkPtr->aHash[nMedBlkIdx]; + return fileBlkInfo; +} + +static inline WFSFileBlkInfo WFSKrnGetFileBlkInfoForCategoryLarge4(AreaInfo *pAreaInfo, DirEntryAttrHdr *pAttrHdr, u32 nAttrLog2Size, u32 nMedBlkIdx){ + return WFSKrnGetFileBlkInfoForCategoryLarge(pAreaInfo, + WFSKrnGetFileLargeBlkPtrForCategoryLarge(pAttrHdr, + nAttrLog2Size, + nMedBlkIdx>>pAreaInfo->nLog2MediumBlkPerLargeBlk), + nMedBlkIdx%(1<nLog2MediumBlkPerLargeBlk)); +} + +static inline WFSFileBlkInfo WFSKrnGetFileBlkInfoForCategoryLargeCast(AreaInfo *pAreaInfo, void *pMetaData, u32 nLog2MetaSize, u32 nMedBlkIdx){ + return WFSKrnGetFileBlkInfoForCategoryLarge4(pAreaInfo, (DirEntryAttrHdr*)pMetaData, nLog2MetaSize, nMedBlkIdx); +} + +// Inline Functions for FILE_SIZE_CATEGORY_VERY_LARGE // Meddium Block Size = 64KB (Max hash size) +static inline WFSBlkAdr *WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(AreaInfo *pAreaInfo, DirEntryAttrHdr *pAttrHdr, u32 nAttrLog2Size, u32 nIndirectBlkIdx){ + return (WFSBlkAdr*)( (size_t)pAttrHdr + (1<nNumLargeBlkPtrsPerBlk; + return WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pAreaInfo, pAttrHdr, nAttrLog2Size, nIndirectBlkIdx); +} + +static inline WFSBlkAdr *WFSKrnGetBlkAdrPtrFromAttrHdrAndMedBlkIdxForCategoryVeryLarge(AreaInfo *pAreaInfo, DirEntryAttrHdr *pAttrHdr, u32 nAttrLog2Size, u32 nMedBlkIdx){ + return WFSKrnGetBlkAdrPtrFromAttrHdrAndLargeBlkIdxForCategoryVeryLarge(pAreaInfo, pAttrHdr, nAttrLog2Size, nMedBlkIdx>>pAreaInfo->nLog2MediumBlkPerLargeBlk); +} + +static inline WFSFileLargeBlkPtr *WFSKrnGetFileLargeBlkPtrFromIndirectBlkForCategoryVeryLarge(u8 *pBlkPtr, u32 nLargeBlkIdx){ + return (WFSFileLargeBlkPtr *)( (size_t)pBlkPtr + sizeof(WFSMetaDataHdr) + (nLargeBlkIdx * sizeof(WFSFileLargeBlkPtr)) ); +} + +static inline WFSFileBlkInfo WFSKrnGetFileBlkInfoFromIndirectBlkForCategoryVeryLarge(AreaInfo *pAreaInfo, u8 *pBlkPtr, u32 nMedBlkIdx){ + return WFSKrnGetFileBlkInfoForCategoryLarge(pAreaInfo, + WFSKrnGetFileLargeBlkPtrFromIndirectBlkForCategoryVeryLarge(pBlkPtr, + nMedBlkIdx>>pAreaInfo->nLog2MediumBlkPerLargeBlk), + nMedBlkIdx%(1<nLog2MediumBlkPerLargeBlk)); +} + +static inline WFSFileBlkInfo WFSKrnGetFileBlkInfoFromIndirectBlkForCategoryVeryLargeCast(AreaInfo *pAreaInfo, void *pMetaData, u32 nLog2MetaSize, u32 nMedBlkIdx){ + return WFSKrnGetFileBlkInfoFromIndirectBlkForCategoryVeryLarge(pAreaInfo, (u8*)pMetaData, nMedBlkIdx); +} + +// Inline Functions for Dir Module +static inline u32 DirLeafGetSubBlkLog2Size(DirSubBlkHdr *pSubBlkHdr) { + return DirLeafGetSubBlkLog2Size_2(pSubBlkHdr->nStrLen, pSubBlkHdr->nNumEntries); +} + +static inline u32 DirNodeGetSubBlkLog2Size(DirSubBlkHdr *pSubBlkHdr) { + return DirNodeGetSubBlkLog2Size_3(pSubBlkHdr->nStrLen, pSubBlkHdr->nNumEntries, pSubBlkHdr->aFirstChar[pSubBlkHdr->nStrLen]); +} + +static inline u16* DirNodeGetOfsTblStartPtr_ote(DirSubBlkHdr *pSubBlkHdr, u16 *pOfsTblEnd) { + if (pSubBlkHdr->aFirstChar[pSubBlkHdr->nStrLen] == 0) { + return &pOfsTblEnd[-(s32)pSubBlkHdr->nNumEntries-1]; + } else { + return &pOfsTblEnd[-(s32)pSubBlkHdr->nNumEntries]; + } +} +static inline u16* DirNodeGetOfsTblStartPtr_l2s(DirSubBlkHdr *pSubBlkHdr, u32 nLog2Size) { + u16 *pOfsTblEnd = (u16*)((u8*)pSubBlkHdr + (1<aFirstChar[pSubBlkHdr->nStrLen] == 0) { + return &pOfsTblEnd[-nIdx-1]; + } else { + return &pOfsTblEnd[-nIdx]; + } +#endif +} + +static inline u16* DirNodeGetIntraBlkOfsPtr_l2s(s32 nIdx, DirSubBlkHdr *pSubBlkHdr, u32 nLog2Size) { + u16 *pOfsTblEnd = (u16*)((u8*)pSubBlkHdr + (1<nNumEntries-1]<<16)); +#else + DirSubBlkHdr *psbh = pSubBlkHdr; // for warning + return ((WFSBlkAdr*)pOfsTblEnd)[-1]; +#endif +}*/ +#if DIR_SPLIT_BLK_ADR + #define DirNodeGetBlkAdr_ote(pSubBlkHdr, pOfsTblEnd) ((WFSBlkAdr)(pOfsTblEnd[-1] + (pOfsTblEnd[-(s32)pSubBlkHdr->nNumEntries-1]<<16))); +#else + #define DirNodeGetBlkAdr_ote(pSubBlkHdr, pOfsTblEnd) ((WFSBlkAdr*)pOfsTblEnd)[-1]; +#endif + + +static inline WFSBlkAdr DirNodeGetBlkAdr_l2s(DirSubBlkHdr *pSubBlkHdr, u32 nLog2Size) { + u16 *pOfsTblEnd = (u16*)((u8*)pSubBlkHdr + (1<nNumEntries-1] = (u16)(nBlkAdr>>16); +#else + DirSubBlkHdr *psbh = pSubBlkHdr; // for warning + ((u32*)pOfsTblEnd)[-1] = nBlkAdr; +#endif +}*/ +#if DIR_SPLIT_BLK_ADR + #define DirNodeSetBlkAdr_ote(nBlkAdr, pSubBlkHdr, pOfsTblEnd) { pOfsTblEnd[-1] = (u16)nBlkAdr; pOfsTblEnd[-(s32)pSubBlkHdr->nNumEntries-1] = (u16)(nBlkAdr>>16); } +#else + #define DirNodeSetBlkAdr_ote(nBlkAdr, pSubBlkHdr, pOfsTblEnd) ((u32*)pOfsTblEnd)[-1] = nBlkAdr; +#endif + + +static inline void DirNodeSetBlkAdr_l2s(WFSBlkAdr nBlkAdr, DirSubBlkHdr *pSubBlkHdr, u32 nLog2Size) { + u16 *pOfsTblEnd = (u16*)((u8*)pSubBlkHdr + (1< _DEBUG_DIR + + Revision 1.1 2008/02/27 09:48:02 paul + *** empty log message *** + + +*---------------------------------------------------------------------------*/ + +#ifndef wfskrn_DirNodeStack_h +#define wfskrn_DirNodeStack_h + +#include "wfskrn_Dir.h" + +#if _DEBUG_DIR + #define _DEBUG_DIR_NODE_STACK 1 // change to 1 if debug info required +#else + #define _DEBUG_DIR_NODE_STACK 0 +#endif + +#if _DEBUG + void DebugCheckNumFreeDnsPoolEntries(char *str); +#endif + +#if _DEBUG_DIR_NODE_STACK + extern bool bCheckDirNodeStack; + void DirNodeStackCheckFreeList(); + WFSKrnResult _DirNodeStackGetEntry (char *sFile, u32 nLine, DirNodeItr *pDni); + WFSKrnResult _DirPushNodeStackEntry(char *sFile, u32 nLine, DirNodeItr *pDni, WFSBlkAdr nBlkAdr); + void _DirNodeStackFree (char *sFile, u32 nLine, DirNodeItr *pDni, DirNodeStack **ppParent); + void _DirPopNodeStackEntry (char *sFile, u32 nLine, DirNodeItr *pDni); + void _DirNodeStackCheckEmpty(); + + #define DirNodeStackGetEntry(pDni) _DirNodeStackGetEntry (_KRN_FILE_, __LINE__, pDni) + #define DirPushNodeStackEntry(pDni,nBlkAdr) _DirPushNodeStackEntry(_KRN_FILE_, __LINE__, pDni, nBlkAdr) + #define DirNodeStackFree(pDni,ppParent) _DirNodeStackFree (_KRN_FILE_, __LINE__, pDni, ppParent) + #define DirPopNodeStackEntry(pDni) _DirPopNodeStackEntry (_KRN_FILE_, __LINE__, pDni) + #define DirNodeStackCheckEmpty _DirNodeStackCheckEmpty(); +#else + WFSKrnResult DirNodeStackGetEntry (DirNodeItr *pDni); + WFSKrnResult DirPushNodeStackEntry(DirNodeItr *pDni, WFSBlkAdr nBlkAdr); + void DirNodeStackFree(DirNodeItr *pDni, DirNodeStack **ppParent); + void DirPopNodeStackEntry(DirNodeItr *pDni); + #define DirNodeStackCheckEmpty +#endif + +WFSKrnResult DirAllocateMoreNodeStackEntries(); + +void DirConstructEntryNameFromNodeStack(WFSFileName *pKey, DirItr *pDi); + + +#endif //wfskrn_DirNodeStack_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_DirRxTree.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_DirRxTree.h new file mode 100644 index 0000000..6c81d55 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_DirRxTree.h @@ -0,0 +1,145 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_DirRxTree.h - Find functions for the Directory Module + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_DirRxTree.h,v $ + Revision 1.4 2008/07/30 21:21:08 paul + Changed the default value of _CHECK_RXT to 0 to improve the speed of the stress test + + Revision 1.3 2008/07/21 22:49:55 paul + Added callback to RxtCheck() + + Revision 1.2 2008/06/09 18:06:12 paul + Rewrote DirRxTree to support PathCache. New version includes parent pointers in each node. + + Revision 1.1 2008/05/10 04:00:23 kondo_masahiro + Initial check-in + +*---------------------------------------------------------------------------*/ + +#ifndef wfskrn_DirRxTree_h +#define wfskrn_DirRxTree_h + +#include "wfskrn_Bitfield.h" +#include "wfskrn_Dir.h" + + +#define RXT_LOG2_RESERVE_SIZE 9 +#define RXT_MIN_LOG2_NODE_SIZE 4 +#define RXT_MAX_LOG2_SIZE 16 + +#if _DEBUG + #define _CHECK_RXT 0 // Set to 1 to enable radix tree and path cache check. However, it makes the test program run a lot slower +#else + #define _CHECK_RXT 0 +#endif + +#pragma pack(1) +typedef struct { + u8 nLog2Size; // The value n such that 2^n is the size of the node + u8 nEntryIdx; // The index of the entry in the parent block which points to this node + u16 nParentOfs; // The offset to the parent of this node + u16 nStrLen; // The length of the prefix string of this node + u8 nNumEntries; // The number of entries in this node + utf8 aFirstChar[1]; // The first character of the variable-size part of the node: format is prefix string followed by choice characters + // The table of u16 offsets to child nodes are stored in reverse order starting from the end of the node +} RxtNodeHdr; +//} _ATTRIBUTE_PACKED RxtNodeHdr; +#pragma pack() + + +typedef struct { + u16 *pOfs; // A pointer to the offset pointer to the node. This would need to be updated if the sub block is relocated. + RxtNodeHdr *pNodeHdr; // A pointer to the sub block containing the node. + utf8 *pStrPtr; // A string pointer to the current cursor position within the search name. After RxtFind(), it points to the first mismatch. + utf8 *pNodeStrPtr; // A string pointer to the current cursor position within the node string. After RxtFind(), it points to the first mismatch. + s32 nEntryIdx; // The entry index of the choice within the current node which is closest but <= search name after RxtFind(). + u32 nDepth; // Current depth of iterator +} RxtItr; + + +typedef struct { + WFSSubBlkAllocHdr sbah; + u16 nRootOfs; + u16 nReserveOfs; // Offset to a sub-block which can be used to guarantee Delete will always succeed + u16 nNumRecs; // Number of records in the block, not the whole directory +} RxtHdr; + + +typedef struct { + u8 nLog2Size; + u8 nEntryIdx; + u16 nParentOfs; +} RxtAttrHdr; + +WFSBool DirBinarySplitSearchChoices(utf8 *aSortedArray, u32 nNumEntries, utf8 cSearchChar, u32 *pEntryIdx); + +void RxtInit (RxtHdr *pRxtHdr, u32 nLog2Size); +WFSKrnResult RxtFind (RxtHdr *pRxtHdr, RxtItr *pRxi, u32 nStrLen); +WFSKrnResult RxtFindNext(RxtHdr *pRxtHdr, RxtItr *pRxi, utf8 cSeparator); +WFSKrnResult RxtInsert (RxtHdr *pRxtHdr, RxtItr *pRxi, u32 nSuffixLen, RxtAttrHdr *pAttrHdr); +WFSKrnResult RxtDeleteNode(RxtHdr *pRxtHdr, RxtItr *pRxi, u32 nEntryIdx, u32 nNodeOfs, RxtNodeHdr *pNodeHdr); +WFSKrnResult RxtDelete (RxtHdr *pRxtHdr, RxtItr *pRxi); +WFSKrnResult RxtNext (RxtHdr *pRxtHdr, RxtItr *pRxi); +WFSKrnResult RxtNextUntilSeparator(RxtHdr *pRxtHdr, RxtItr *pRxi, utf8 cSeparator); + +void RxtGetString(RxtHdr *pRxtHdr, RxtNodeHdr *pNodeHdr, utf8 *sStr, u32 nStrLen); + + +#if _CHECK_RXT + typedef void (*RxtCheckEntry)(u32 nRecIdx, u32 nDepth, utf8 *sPath, void *pPtr); + void RxtCheck(RxtHdr *pRxtHdr, u32 nTotalSize, RxtCheckEntry cbCheckEntry); +#endif + +void RxtTest(); + +// Inline Function Definitions +static inline u32 RxtGetNodeLog2Size_2(u32 nStrLen, u32 nNumEntries) { + //u32 nNumBytesRequired = (u32)&((RxtNodeHdr*)0)->aFirstChar + nStrLen + (nNumEntries*3); + u32 nNumBytesRequired = sizeof(RxtNodeHdr)-1 + nStrLen + (nNumEntries*3); + u32 nLog2Size = WfsCalculateFieldSizeInBits(nNumBytesRequired-1); + if (nLog2Size < SBA_MIN_LOG2_SUB_BLK_SIZE) { + nLog2Size = SBA_MIN_LOG2_SUB_BLK_SIZE; + } + return nLog2Size; +} + +static inline u32 RxtGetNodeLog2Size(RxtNodeHdr *pNodeHdr) { + return RxtGetNodeLog2Size_2(pNodeHdr->nStrLen, pNodeHdr->nNumEntries); +} + +static inline u16 *RxtGetChildOfsPtr_ote(s32 nIdx, u16 *pOfsTblEnd) { + return &pOfsTblEnd[-nIdx]; +} + +static inline u16* RxtGetChildOfsPtr(s32 nIdx, RxtNodeHdr *pNodeHdr) { + u16 *pOfsTblEnd = (u16*)((u8*)pNodeHdr + (1<nLog2Size)); + return RxtGetChildOfsPtr_ote(nIdx, pOfsTblEnd); +} + +static inline u16 RxtGetChildOfs_ote(s32 nIdx, u16 *pOfsTblEnd) { + return *RxtGetChildOfsPtr_ote(nIdx, pOfsTblEnd); +} + +static inline u16 RxtGetChildOfs(s32 nIdx, RxtNodeHdr *pNodeHdr) { + return *RxtGetChildOfsPtr(nIdx, pNodeHdr); +} + +static inline void RxtSetChildOfs_ote(s32 nIdx, u16 nOfs, u16 *pOfsTblEnd) { + *RxtGetChildOfsPtr_ote(nIdx, pOfsTblEnd) = nOfs; +} + +static inline void RxtSetChildOfs(s32 nIdx, u16 nOfs, RxtNodeHdr *pNodeHdr) { + *RxtGetChildOfsPtr(nIdx, pNodeHdr) = nOfs; +} + + +#endif //define wfskrn_DirRxTree_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_EPTree.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_EPTree.h new file mode 100644 index 0000000..a40db97 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_EPTree.h @@ -0,0 +1,71 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_EPTree.h + + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_EPTree.h,v $ + Revision 1.4 2008/12/17 05:08:17 ueno + Cleanup. + + Revision 1.3 2008/12/15 02:40:27 ueno + Added support for multi p-tree. + + Revision 1.1 2008/12/02 04:55:39 ueno + Added EPTree to support multi-PTree. + + +*---------------------------------------------------------------------------*/ + +#ifndef __WFSKRN_EPTREE_H__ +#define __WFSKRN_EPTREE_H__ + +#include "wfskrn_Area.h" +#include "wfskrn_FTree.h" + +#define EPTREEHDR_OFFSET (BLOCK_SIZE - sizeof(EPTreeHdr)) +#define GET_EPTREEHDR(pBlock) ((EPTreeHdr*) ((u8*) (pBlock) + EPTREEHDR_OFFSET)) +#define GET_BLOCK_FROM_EPTREEHDR(eptreeHdr) ((u8*) (eptreeHdr) - EPTREEHDR_OFFSET) + +#define EPTREE_GET_KEY(epti) ((epti)->nKey) +#define EPTREE_GET_DATA(epti) ((epti)->nData) + +typedef struct +{ + PTreeHdr ptreeHdr; // 8 bytes. + WFSBlkAdr addr; + u8 height; // height = 1, 2 ... + u8 padding[11]; + SubBlockAllocatorHeader sbaHdr; // 8 bytes. +} EPTreeHdr; // sizeof(EPTreeHdr) must be 32 bytes. ( == sizeof(FTreeBlock)); + +typedef PTreeItr EPTreeItr; + +#define EPTREE_MAX_HEIGHT 2 + +typedef struct +{ + EPTreeHdr* eptreeHdr[EPTREE_MAX_HEIGHT]; // inherited FBATreeItr + EPTreeItr epti[EPTREE_MAX_HEIGHT]; // inherited FBATreeItr. +} MEPTreeItr; + +EPTreeHdr* EPTreeBlockInit(AreaInfo* area, void* block, WFSBlkAdr addr, u32 offset, u8 height); +EPTreeItr* EPTreeGetLastIter(MEPTreeItr* iter); +WFSKrnResult EPTreeFind(AreaInfo* area, MEPTreeItr* iter, u32 nKey); +WFSKrnResult EPTreePrev(AreaInfo* area, MEPTreeItr* iter); +WFSKrnResult EPTreeNext(AreaInfo* area, MEPTreeItr* iter); +WFSKrnResult EPTreeFirst(AreaInfo* area, MEPTreeItr* iter); +WFSKrnResult EPTreeLast(AreaInfo* area, MEPTreeItr* iter); +WFSKrnResult EPTreeInsert(AreaInfo* area, MEPTreeItr* iter, u32 key, u32 data); // [check] can remove area? +WFSKrnResult EPTreeDelete(AreaInfo* area, MEPTreeItr* iter, u32 key, WFSBlkAdr* freeBlks); +WFSKrnResult EPTreeInit(AreaInfo* area, u32 offset); + +#endif // __WFSKRN_EPTREE_H__ + diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Errors.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Errors.h new file mode 100644 index 0000000..f68d7c2 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Errors.h @@ -0,0 +1,309 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Errors_h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Errors.h,v $ + Revision 1.19 2008/12/15 02:40:27 ueno + Added support for multi p-tree. + + Revision 1.18 2008/11/07 08:54:35 kondo_masahiro + Added WFSKrnExit4/5OnError() + + Revision 1.17 2008/10/30 05:08:19 kondo_masahiro + Added error for DirCheckDisk + + Revision 1.16 2008/09/28 23:30:40 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.15 2008/08/27 10:03:58 paul + added WFSKRN_RESULT_BLK_CACHE_ALLOC_FAILED + + Revision 1.14 2008/08/05 04:17:52 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.13 2008/07/17 22:25:49 paul + Added WFSKRN_RESULT_DIR_ITR_INVALID + Fixed value for WFSKRN_RESULT_FILE_OPEN + + Revision 1.12 2008/07/17 05:11:44 kondo_masahiro + Added WFSKRN_RESULT_DEVICE_HASH_INCONSISTENT + + Revision 1.11 2008/07/17 04:18:24 ueno + Added errors for freeblock allocator. + + Revision 1.10 2008/07/11 18:05:17 paul + Updated to match latest wfsError.h + + Revision 1.9 2008/07/09 01:35:43 paul + Changed some result code names, and added new result codes for PTree. + + Revision 1.8 2008/06/10 20:13:04 kondo_masahiro + Added WFSKrnCommandCountBreak. + + Revision 1.7 2008/06/09 18:05:48 paul + Added support for logging calls to WFSSrv functions. + Added new result codes. + + Revision 1.6 2008/06/05 08:09:18 ueno + Revised permission APIs. + + Revision 1.5 2008/05/28 01:06:13 ueno + Added error codes for AclCheckDisk(). + + Revision 1.4 2008/05/12 19:21:31 paul + Added an error code. + + Revision 1.3 2008/05/10 04:00:48 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.2 2008/04/25 12:07:44 nakanose_jin + add new errors + + Revision 1.13 2008/04/26 01:13:53 wayne.wong + Moved area allocation functionality from Volume to Area module. + Changed error codes appropriately. + + Revision 1.12 2008/04/25 04:35:29 nakanose_jin + add new errors + + Revision 1.11 2008/04/22 23:01:43 paul + Added WFSKRN_RESULT_DEV_IN_USE to match wfsError.h. Added WFSKrnExitOnError + + Revision 1.10 2008/04/18 01:42:46 wayne.wong + Added some area-specific error codes. + + Revision 1.9 2008/04/15 07:40:11 ueno + Added error codes to WFSKrnResult for accesslist. + + Revision 1.8 2008/03/19 07:35:48 wayne.wong + Added and fixed error codes. + + Revision 1.7 2008/03/11 03:09:34 wayne.wong + Added some more BCache and Volume errors. + + Revision 1.6 2008/02/28 06:32:36 kondo_masahiro + Fixed code to accept PPC compiler + + Revision 1.5 2008/02/27 00:46:26 paul + Differentiated names of error functions + + Revision 1.4 2008/02/21 22:25:26 wayne.wong + Added errors for the modules BCache, PMem, Volume, and Transaction. + + Revision 1.3 2008/02/21 01:37:43 paul + split into wfskrn_Errors.h and wfskrn_Errors.cpp + + Revision 1.2 2008/02/20 07:47:52 paul + Updated error codes and added WFSKrnOutputError macro to output error code as a string + + Revision 1.1 2007/12/27 11:35:52 paul + internal error definitions + + *---------------------------------------------------------------------------*/ + +#ifndef wfskrn_Errors_h +#define wfskrn_Errors_h + +#define WFSKrnReturnOnError(x) { WFSKrnResult nResult = x; if (nResult < WFSKRN_RESULT_OK) return nResult; } +#define WFSKrnExitOnError(x) { nResult = x; if (nResult < WFSKRN_RESULT_OK) goto Exit; } +#define WFSKrnExit1OnError(x) { nResult = x; if (nResult < WFSKRN_RESULT_OK) goto Exit1; } +#define WFSKrnExit2OnError(x) { nResult = x; if (nResult < WFSKRN_RESULT_OK) goto Exit2; } +#define WFSKrnExit3OnError(x) { nResult = x; if (nResult < WFSKRN_RESULT_OK) goto Exit3; } +#define WFSKrnExit4OnError(x) { nResult = x; if (nResult < WFSKRN_RESULT_OK) goto Exit4; } +#define WFSKrnExit5OnError(x) { nResult = x; if (nResult < WFSKRN_RESULT_OK) goto Exit5; } + +#define WFSKrnReturnOnNullParameter(p) { if (p == NULL) return WFSKRN_RESULT_INVALID; } + +typedef enum { + WFSKRN_RESULT_OK = 0, // Success + + // Errors that can usually be detected early, and if detected, would result in the Async callback not being called: + WFSKRN_RESULT_BUSY = -1, // Too many requests, try waiting then calling again. + WFSKRN_RESULT_OUT_OF_MEMORY = -2, // The library does not have enough memory to complete the requested operation. (May be due to too many outstanding aysnc calls). + WFSKRN_RESULT_INVALID = -3, // The function parameters were invalid, e.g. File name is too long, Path is too long or too deep. + WFSKRN_RESULT_ACCESS = -4, // Trying to write to a file which was opened for read-only access, or vice versa. + WFSKRN_RESULT_LIB_NOT_INITIALIZED = -5, // The WFS library has not been initialized. Please call WFSInit() (This error is checked in functions that require the library to be initialized, but only in the debug versions). + WFSKRN_RESULT_LIB_ALREADY_INITIALIZED = -6, // The WFS library has already been initialized. + WFSKRN_RESULT_FILE_TOO_BIG = -7, // The current write/append request would push the file over the size limit. + WFSKRN_RESULT_NO_CHANGE_SIZE = -8, // The requested operation would cause the file size to change, but this file has WFS_PERM_NO_CHANGE_SIZE flag set. + + // Errors that cannot usually be detected early, and would be passed via nResult to the Async callbacks: + WFSKRN_RESULT_MEDIA_ERROR = -9, // The device or media is not attached, or was removed before the requested operation could be completed. + WFSKRN_RESULT_DEV_UNUSABLE = -10, // Attached device is not accessible, e.g. because it is an unsupported device, or has an unknown format. + WFSKRN_RESULT_DEV_NOT_INITIALIZED = -11, // Device not formatted, or does not yet contain a WFS volume + WFSKRN_RESULT_DEV_IN_USE = -12, // Trying to initialize a device which is in use (mounted) by one or more clients. + WFSKRN_RESULT_VOL_ID_ERROR = -13, // Attempted to mount a volume with the same unique Id as an already mounted volume (This could happen if the User backs up an entire WFS volume using a PC) + WFSKRN_RESULT_WRITE_PROTECTED = -14, // Device is physically write protected (e.g. USB Flash memory, SD Card) + WFSKRN_RESULT_ALREADY_MOUNTED = -15, // The device is already mounted + + WFSKRN_RESULT_PERMISSION = -16, // Permission flags do not permit the requested access from this application. + WFSKRN_RESULT_PERMISSION_CL = -17, // Permission error caused by control level problems. + WFSKRN_RESULT_ACL_FULL = -18, // The access list is full. + WFSKRN_RESULT_ACL_ENTRY_NOT_FOUND = -19, // The specified entry does not exist in the access list. + WFSKRN_RESULT_AUTHENTICATION = -20, // Trying to access content on a different Wii, which does not have the required access rights. + WFSKRN_RESULT_CORRUPTION = -21, // A corrupted block was encountered which prevented the operation from being completed. + + WFSKRN_RESULT_DIRECTORY_QUOTA = -22, // One of the ancestor directories would exceed its quota. + + WFSKRN_RESULT_MAX_HANDLES = -23, // The maximum number of concurrent file handles / search handles are already in use. + WFSKRN_RESULT_ALREADY_EXISTS = -24, // The file or directory being created already exists. + WFSKRN_RESULT_NOT_FOUND = -25, // The specified file or directory or device does not exist. + WFSKRN_RESULT_NOT_EMPTY = -26, // The specified directory cannot be deleted because it is not empty. + WFSKRN_RESULT_NOT_FILE = -27, // The specified path is directory instead of a file. + WFSKRN_RESULT_NOT_DIRECTORY = -28, // The specified path is a file instead of a directory + WFSKRN_RESULT_FILE_OPEN = -29, // The file is open. Cannot delete, move, rename, change permissions of an open file. Cannot open a file more than once unless all opens are WFS_ACCESS_READ. + WFSKRN_RESULT_LOCKED = -30, // Cannot perform the requested operation since the file or directory is locked by an existing operation. + WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED = -31, // A resource limit prevents this function call. Try smaller values. + + // Directory find results - these can be errors or expected depending on whether we are trying to access an existing file or trying to create a new one: + WFSKRN_RESULT_DIR_ENTRY_FOUND = -40, // The search string was matched and pointed to an entry + WFSKRN_RESULT_DIR_NODE_STRING_PREFIX = -41, // The search string ended early during comparison with a node sub string. (So this name is a prefix of existing names) + WFSKRN_RESULT_DIR_CHOICE_PREFIX = -42, // The search string ended at the end of a node sub string, but the node did not have a termination choice. (This name is a prefix of existing names) + WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH = -43, // A mismatch was encountered while comparing the search string to a sub node prefix string. + WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND = -44, // A mismatch was encountered while comparing a character of the search string with a set of choices for that character. + WFSKRN_RESULT_DIR_BLK_FULL = -45, // Unable to insert the specified string to the radix tree, due to lack of space in the block. + WFSKRN_RESULT_DIR_ITR_INVALID = -46, // One or more blocks referenced by the directory iterator and its node stack have been updated since the iterator was last used. DirFind must be called again. + + // These result codes are not errors, but normal return values for the path cache functions + WFSKRN_RESULT_SRV_END_OF_PATH = -60, // Last part of path name parsed + WFSKRN_RESULT_SRV_PATH_DEPTH_1 = -61, // Path was of depth 1, such as "/something" + WFSKRN_RESULT_SRV_PATH_DEV = -62, // Path was "/dev" + WFSKRN_RESULT_SRV_PATH_VOL = -63, // Path was "/vol" + WFSKRN_RESULT_SRV_PATH_VOL_ROOT = -64, // Path was a volume root path, such as "/vol/xxxxxxx/" + + WFSKRN_RESULT_PTREE_ENTRY_FOUND = -70, + WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND = -71, + WFSKRN_RESULT_PTREE_FULL = -72, + WFSKRN_RESULT_PTREE_EMPTY = -73, + + WFSKRN_RESULT_DEVICE_ERROR = -80, + WFSKRN_RESULT_DEVICE_INVALID_PARAMETER = -81, + WFSKRN_RESULT_DEVICE_NOT_FOUND = -82, + WFSKRN_RESULT_DEVICE_HASH_INCONSISTENT = -83, + + WFSKRN_RESULT_BLK_CACHE_ALLOC_FAILED = -90, + + WFSKRN_RESULT_BCACHE_ERROR = -300, // unspecified error + WFSKRN_RESULT_BCACHE_RESOURCE_LIMIT = -301, // exhausted resources + WFSKRN_RESULT_BCACHE_INVALID_PARAMETER = -302, // at least one argument is invalid + WFSKRN_RESULT_BCACHE_NO_MEMORY = -303, // could not malloc + WFSKRN_RESULT_BCACHE_NOT_FOUND = -304, // sector is not cached + WFSKRN_RESULT_BCACHE_MAX_DEVICES = -305, // max devices alreay allocated + WFSKRN_RESULT_BCACHE_INVALID_DEVICE = -306, // device not found/open + WFSKRN_RESULT_BCACHE_INVALID_HANDLE = -307, // invalid device handle + WFSKRN_RESULT_BCACHE_INVALID_VOLUME = -308, // invalid volume ID (not mapped) + WFSKRN_RESULT_BCACHE_ALREADY_MAPPED = -309, // vol or devH already mapped + WFSKRN_RESULT_BCACHE_ALLOC = -310, // cannot alloc (no mem, or pmem error) + WFSKRN_RESULT_BCACHE_HASH_BLK_NOT_MAPPED = -311, // hash block isn't mapped on cache + + WFSKRN_RESULT_VOLUME_ERROR = -400, // unspecified volume error + WFSKRN_RESULT_VOLUME_INVALID_PARAMETER = -401, // at least one argument is invalid + WFSKRN_RESULT_VOLUME_BCACHE_ALLOC = -402, // cannot allocate a page/block in memory + WFSKRN_RESULT_VOLUME_BCACHE_CONFIG = -403, // block cache not configured correctly + WFSKRN_RESULT_VOLUME_ID = -404, // bad volume ID or not initialized + WFSKRN_RESULT_VOLUME_CORRUPT_MR = -405, // the MR (or its free lists) are corrupted + WFSKRN_RESULT_VOLUME_AREA_ALLOC = -406, // area allocation cannot be satisfied + WFSKRN_RESULT_VOLUME_DEVICE_PARAMETER = -407, // parameters incompatible with device + WFSKRN_RESULT_VOLUME_NOT_MAPPED = -408, // volume is not mapped; invalid volume ID + + WFSKRN_RESULT_TRANSACTION_ERROR = -500, // unspecified transaction error + WFSKRN_RESULT_TRANSACTION_INVALID_PARAMETER= -501, + + WFSKRN_RESULT_ACL_ERROR = -600, // unspecified error + WFSKRN_RESULT_ACL_INVALID_PARAMETER = -601, // at least one argument is invalid + WFSKRN_RESULT_ACL_MAX_ENTRIES = -602, // max entries alreay in the accesslist. + WFSKRN_RESULT_ACL_BUFFER_TOO_SMALL = -603, // buffer is too small to store an accesslist. + WFSKRN_RESULT_ACL_CACHE = -610, // cannot allocate a cache. + WFSKRN_RESULT_ACL_FILE = -620, // cannot create, modify or delete the accesslist file. + WFSKRN_RESULT_ACL_ACLDIR_INCONSISTENT = -621, // accesslist files and indexlist are inconsistent. + WFSKRN_RESULT_ACL_FILENAME = -630, // cannot convert acl filename <=> acl content. + WFSKRN_RESULT_ACL_NAMEDIR_INCONSISTENT = -631, // access name files and indexlist are inconsistent. + WFSKRN_RESULT_ACL_HANDLE = -640, // cannot allocate an accesslist handle. + + WFSKRN_RESULT_AREA_ERROR = -700, // unspecified area error + WFSKRN_RESULT_AREA_INVALID_PARAMETER = -701, + WFSKRN_RESULT_AREA_BCACHE_ALLOC = -702, // cannot allocate a page/block in memory + WFSKRN_RESULT_AREA_CORRUPT_HDR = -703, // the area header is corrupted + WFSKRN_RESULT_AREA_VOLUME_NOT_MAPPED = -704, // volume is not mapped; invalid volume ID + WFSKRN_RESULT_AREA_ALLOC = -705, // area allocation cannot be satisfied + + WFSKRN_RESULT_FTREE_RETRY = -801, // retry insert. + WFSKRN_RESULT_FTREE_SPLIT = -802, // cannot split tree. + WFSKRN_RESULT_FTREE_EMPTY = -803, // no entry in the F-tree. + + WFSKRN_RESULT_CHECKDISK_INCONSISTENT = -901, // bit arrays does not consistent between free block allocator and dir module. + WFSKRN_RESULT_CHECKDISK_INTERNAL_ERROR = -902, // bit arrays can not construct. + + WFSKRN_RESULT_NOT_IMPLEMENTED = -1026, // The requested function has not yet been implemented //ToDo: This error should be removed from the final API + WFSKRN_RESULT_UNKNOWN = -1027, // Unexpected error - could be caused by a bug in the file system. + WFSKRN_RESULT_FATAL_ERROR = -1028 // May be caused by critical metadata corruption. +} WFSKrnResult; + +#define WFSSetLastError(nErr) (wkg.nLastErr = (nErr)) + +const char *WFSKrnGetErrorString( WFSKrnResult nResult ); +WFSKrnResult WFSKrnOutputErrorCode(WFSKrnResult nResult); +WFSKrnResult WFSKrnOutputErrorStr(const char *pStr); +void WFSKrnCommandCountBreak(); + +#if _DEBUG + #define DBG_OUTPUT_TO_LOG_FILE 0 + #define DBG_OUTPUT_TO_SCREEN 0 + #define DBG_OUTPUT_PREFIX "%5d. " + extern u32 nDbgCommandCount; + extern u32 nDbgCommandOutputStart; + extern u32 nDbgCommandOutputEnd; + extern u32 nDbgCommandCountBreak; +#define WFSKrnDbgOutputTest(x) if ((nDbgCommandCount>=nDbgCommandOutputStart)&&(nDbgCommandCount VerifyMemoryBlockFTree + + Revision 1.6 2008/08/09 03:34:29 ueno + Disabled runtime check. + + Revision 1.5 2008/08/09 02:02:02 ueno + Cleanup. + + Revision 1.4 2008/08/08 13:27:22 ueno + Fixed BLOCK_SIZE. + + Revision 1.3 2008/08/07 10:46:50 ueno + Modified for BTREE_BASED_ALLOCATOR (now debugging). + + Revision 1.2 2008/08/02 11:52:10 ueno + Revised the positions of FTreeHdr{} and FBAPTreeHdr{} in 8KB-blocks to protect hash code. + + Revision 1.1 2008/08/01 06:57:39 ueno + Initial Check-in. + +*---------------------------------------------------------------------------*/ + +#ifndef __WFSKRN_FTREE_H__ +#define __WFSKRN_FTREE_H__ + +#include "wfskrn_Area.h" +#if BTREE_BASED_ALLOCATOR + +#define MAX_SUB_TREE 7 + +#include "wfskrn_Defs.h" +#include "wfskrn_Api.h" +#include "wfskrn_Area.h" +#include "wfskrn_Errors.h" +#include "wfskrn_PTree.h" + +#define FTREE_LEAF_FAN_OUT 7 + +#define FTREE_LEAF_APPROPRIATE_NUM 5 // 70% of FTREE_LEAF_FAN_OUT +#define FTREE_NODE_APPROPRIATE_NUM 4 // 70% of PTREE_NODE_FAN_OUT + +enum // treeType +{ + FTREE_TYPE_A = 0, + FTREE_TYPE_B, + FTREE_TYPE_C, + FTREE_TYPE_D, + FTREE_TYPE_E, + FTREE_TYPE_F, + FTREE_TYPE_G, + FTREE_TYPE_END // this is not used. +}; + +#define GET_SUBTREE(header, treeType) (&(header)->tree[(treeType)]) +#define GET_SUBTREE_TYPE(header, fti) ((fti)->subTree - &(header)->tree[0]) + +typedef PTreeNode FTreeNode; + + +/* + [check] should save the number of data. + 4 bits * 7 (remainder 4 bits) + <-----------------------------------> + +---+---+---+---+---+---+---+---+---+ + | x | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + +---+---+---+---+---+---+---+---+---+ +*/ +typedef struct +{ + u32 aKey[FTREE_LEAF_FAN_OUT]; + u32 data; // 4 bits * 7 (remainder 4 bits) +} FTreeLeaf; + +#define LEAF_GET_LEN(leaf, index) ((((leaf)->data) >> (4 * (index))) & 0x0f) +#define FTREE_SBA_OFFSET 24 + +/* + an 8kb-block. + +-------------------------+ A + | | | + | hash code, areaInfo, | | offset + | volumeInfo, etc... | | + | | | + +-------------------------+ V + | | A + | | | + | | | + | | | + | | | + | | | + | | | + | Sub-blocks | | + | | | size + | | | + | | | + | | | + | | | + | | | + | | V + +-------------------------+ A + | | | + +-------------------------+ | FTreeHdr (footer?) + | SubBlockAllocatorHeader | | + +-------------------------+ V +*/ +typedef struct _SubBlockAllocatorHeader +{ + u16 freeBlock; // start address of free blocks. + u16 numBlock; // the number of blocks in this 8kB block. + + u16 offset; + u16 size; +} SubBlockAllocatorHeader; + +typedef struct +{ + PTreeHdr tree[MAX_SUB_TREE]; // 8 bytes * 7 + SubBlockAllocatorHeader sbaHdr; // 8 bytes +} FTreeHdr; // sizeof(FTreeHdr) == sizeof(FTreeBlock) * NUM_HEADER_BLOCK. + +typedef struct +{ + u32 prev; + u32 next; + u16 num; +} FTreeFreeBlock; + +typedef struct +{ + u32 prev; + u32 next; + u16 num; + u8 padding[22]; // sizeof(FTreeBlock) must be 32. +} FTreeBlock; + +typedef struct +{ + PTreeItr ptree; // inherit PTreeItr. + FTreeLeaf* pLeaf; + PTreeHdr* subTree; + WFSBlkAdr splitKey; // [ToDo] should separete FTreeItr. + WFSBlkAdr newChild; // [ToDo] should separete FTreeItr. + WFSBlkAdr newChildSubTreeType; // [ToDo] should separete FTreeItr. +} FTreeItr; + +#define FTREE_GET_KEY(pFti) ((pFti)->ptree.nKey) +#define FTREE_GET_DATA(pFti) ((pFti)->ptree.nData) + +#define PTREE_GET_KEY(pPti) ((pPti)->nKey) +#define PTREE_GET_DATA(pPti) ((pPti)->nData) + +#define FTREE_MASK_LENGTH 0x07FF +#define FTREE_FLAG_BTREE 0x8000 +#define FTREE_BLOCK_SIZE (32) + +#define BLOCK_SIZE (1<nBlkSize as a block size. + +#define FTREE_LOG2_OFS_A 0 +#define FTREE_LOG2_OFS_B 3 +#define FTREE_LOG2_OFS_C 6 +#define FTREE_LOG2_OFS_D 10 +#define FTREE_LOG2_OFS_E 14 +#define FTREE_LOG2_OFS_F 18 +#define FTREE_LOG2_OFS_G 22 +#define FTREE_LOG2_OFS_END 26 + +extern const u32 FTreeBlkLog2Ofs[MAX_SUB_TREE+1]; + +#define SBAHDR_OFFSET (BLOCK_SIZE - sizeof(SubBlockAllocatorHeader)) +#define GET_SBAHDR(pBlock) ((SubBlockAllocatorHeader*) ((u8*) pBlock + SBAHDR_OFFSET)) +#define SET_FREEBLOCK(sbaHdr, pBlock) (sbaHdr->freeBlock = ((FTreeBlock*) (pBlock) - CACHE(sbaHdr))) +#define FREEBLOCK_NUMBER(sbaHdr) (sbaHdr->freeBlock) +#define CACHE(sbaHdr) ((FTreeBlock*) ((u8*) (sbaHdr) - (SBAHDR_OFFSET - (sbaHdr)->offset))) +#define END_OF_CACHE(sbaHdr) ((FTreeBlock*) ((u8*) CACHE(sbaHdr) + (sbaHdr)->size)) +#define GET_FREEBLOCK(sbaHdr) (CACHE(sbaHdr) + (sbaHdr)->freeBlock) +#define MAX_FREEBLOCK(sbaHdr) ((sbaHdr)->size / sizeof(FTreeBlock)) +#define GET_BLOCK_HEAD(treeHdr /* EPTreeHdr or FTreeHdr */) ((FTreeBlock*) ((u8*) &((treeHdr)->sbaHdr) - SBAHDR_OFFSET)) + +#define FTREEHDR_OFFSET (BLOCK_SIZE - sizeof(FTreeHdr)) +#define GET_FTREEHDR(pBlock) ((FTreeHdr*) ((u8*) (pBlock) + FTREEHDR_OFFSET)) +#define GET_SUBBLOCK(ftreeHdr, offset) ((FTreeBlock*) ((u8*) GET_BLOCK_HEAD(ftreeHdr) + (offset))) + +#ifdef _DEBUG +// #define FTREE_RUNTIME_CHECK // for debug. +#endif // _DEBUG + + +#ifdef FTREE_RUNTIME_CHECK +#define WFSKRN_FTREE_RUNTIME_CHECK(x) { \ + if (FBADebugVerbose) \ + { \ + WFSKRN_FTREE_ASSERT(x); \ + } \ + } +#else +#define WFSKRN_FTREE_RUNTIME_CHECK(x) +#endif + +#ifdef _DEBUG +#ifdef WIN32 +#define WFSKRN_FTREE_ASSERT(x) assert(x) +#else // Win32 +#define WFSKRN_FTREE_ASSERT(x) ASSERT(x) +#endif // WIN32 +#else +#define WFSKRN_FTREE_ASSERT(x) +#endif + +typedef struct _FTreeExtent +{ + u32 start; + u32 len; // the unit is 8kB. +} FTreeExtent; + +FTreeHdr* FTreeBlockInit(AreaInfo* area, void* block /* 8kB block */); + +WFSKrnResult FTreeFind(FTreeHdr* header, FTreeItr* iter, u32 nKey, WFSBool strictSearch); + +WFSKrnResult FTreeInsert(AreaInfo* area, FTreeHdr* header, FTreeItr* iter, u32 nKey, u32 nData); +WFSKrnResult FTreeDelete(FTreeHdr* header, FTreeItr* iter, u32 nKey); +WFSKrnResult FTreeModify(FTreeHdr* header, FTreeItr* iter, u32 originalKey, u32 modKey, u32 modData); + +WFSKrnResult FTreeFirst(FTreeHdr* header, FTreeItr* iter); +WFSKrnResult FTreeNext(FTreeHdr* header, FTreeItr* iter); +WFSKrnResult FTreeLast(FTreeHdr* header, FTreeItr* iter); +WFSKrnResult FTreePrev(FTreeHdr* header, FTreeItr* iter); +WFSKrnResult PTreeLast(PTreeHdr *pPTreeHdr, PTreeItr *pPti, PTreeAllocator *pAllocator); +WFSKrnResult PTreePrev(PTreeHdr *pPTreeHdr, PTreeItr *pPti, PTreeAllocator *pAllocator); +PTreeHdr* FTreeSelectSubTree(FTreeHdr* header, WFSBlkAdr unitLen); + +u16 FTreeAllocEntry(void *pBase); +WFSKrnResult FTreeAllocEntries(void *pBase, u16 *pNodeOfs, u32 nNumNodes); +void FTreeFreeEntry(void *pBase, u16 nOfs); + +FTreeBlock* MemoryBlockAlloc(SubBlockAllocatorHeader* header, int numBlocks); +int MemoryBlockFree(SubBlockAllocatorHeader* header, FTreeBlock* block, u32 numBlocks); + +void FTreeSbaInit(AreaInfo* area, void* block, u32 footerSize, u32 offset); + +WFSBool VerifyMemoryBlockFTree(SubBlockAllocatorHeader* header); // [check] debug API. +WFSBool FTreeVerifyTree(FTreeHdr* header); + +#endif // BTREE_BASED_ALLOCATOR +#endif // __WFSKRN_FTREE_H__ + + diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_FreeBlkAlloc.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_FreeBlkAlloc.h new file mode 100644 index 0000000..cad69dd --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_FreeBlkAlloc.h @@ -0,0 +1,184 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_FreeBlkAlloc.h + + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_FreeBlkAlloc.h,v $ + Revision 1.16 2008/12/18 00:32:11 ueno + Removed FBADirtyFtreeBlock(). + + Revision 1.15 2008/12/17 05:08:17 ueno + Cleanup. + + Revision 1.14 2008/12/15 02:40:27 ueno + Added support for multi p-tree. + + Revision 1.13 2008/12/02 04:55:39 ueno + Added EPTree to support multi-PTree. + + Revision 1.11 2008/11/18 04:57:11 saito_tomoya + Modified SetBit() and added SetBitArray(). + + Revision 1.10 2008/11/07 03:01:42 ueno + Fixed FTreeExtentInfo{} for IOP. + + Revision 1.9 2008/10/14 11:25:13 ueno + Disabled runtime check. + + Revision 1.8 2008/09/29 10:19:25 ueno + Revised to support multi-B-tree-based allocator. + + Revision 1.7 2008/08/13 04:14:00 ueno + Modified FreeBlkAlloc() to allocate blocks near nRefBlkAdr. + + Revision 1.6 2008/08/13 00:14:09 paul + Changed type of nStride from u32 to s32 + + Revision 1.5 2008/08/09 03:34:29 ueno + Disabled runtime check. + + Revision 1.4 2008/08/08 13:27:42 ueno + Added UnpinFTreeBlk(). + + Revision 1.3 2008/08/07 10:46:50 ueno + Modified for BTREE_BASED_ALLOCATOR (now debugging). + + Revision 1.2 2008/08/02 11:52:10 ueno + Revised the positions of FTreeHdr{} and FBAPTreeHdr{} in 8KB-blocks to protect hash code. + + Revision 1.1 2008/08/01 06:57:39 ueno + Initial Check-in. + +*---------------------------------------------------------------------------*/ + +#ifndef __WFSKRN_FREEBLKALLOC_H__ +#define __WFSKRN_FREEBLKALLOC_H__ + +#include "wfskrn_Area.h" +#if BTREE_BASED_ALLOCATOR + +#include "wfskrn_FreeBlkAlloc_Type.h" +#include "wfskrn_FTree.h" +#include "wfskrn_EPTree.h" + +#define FBA_ROOT_BLK 0 // default block for p-tree. +#define FBA_INITIAL_FTREE_BLK 1 // default block for f-tree. + +#define GET_FBATREE_HDR(area) (&((area)->ah.freeBlkAllocHdr)) // [check] +#define FBA_SBA_OFFSET (sizeof(AreaHdr) + sizeof(VolumeHdr)) +#define FBA_GET_FTREE_BLK(pIter) ((pIter)->epti[(pIter)->height - 1].nData) + +typedef struct +{ + EPTreeHdr* eptreeHdr[EPTREE_MAX_HEIGHT]; // inherit MEPTreeItr. + EPTreeItr epti[EPTREE_MAX_HEIGHT]; // inherit MEPTreeItr. + FTreeItr fti; + FTreeHdr* ftreeHdr; + WFSBlkAdr ftreeAddr; + + WFSBool isInserted; + u8 height; +} FBATreeItr; + +typedef struct _ExtentStorageHeader +{ + u32 prio; // priority + u32 numPrev; + u32 numNext; +} ExtentStorageHeader; + +typedef struct _ExtentStorageEntry +{ + WFSBlkAdr start; + WFSBlkAdr len; // block len. + u16 treeType; + u16 nNumBlk; +} ExtentStorageEntry; + +typedef struct _FBASingleEntry +{ + ExtentStorageHeader header; + ExtentStorageEntry entry; +} FBASingleEntry; + +typedef struct _RemainderExtents +{ + FTreeExtent head; + FTreeExtent fractionHead; + FTreeExtent tail; + FTreeExtent fractionTail; +} RemainderExtents; + +typedef struct _FTreeExtentInfo +{ + WFSBlkAdr start; + WFSBlkAdr len; // the unit is 8kB. + FBATreeItr iter; + WFSBool alignment; +} FTreeExtentInfo; + +#define FBA_RESULT_KEY(pIter) ((pIter)->fti.ptree.nKey) +#define FBA_RESULT_DATA(pIter) ((pIter)->fti.ptree.nData) + +EPTreeHdr* EpTreeBlockInit(AreaInfo* area, void* block, u32 offset); + +WFSKrnResult FreeBlkInsert(AreaInfo* area, FBATreeItr* iter, WFSBlkAdr nBlkAdr, WFSBlkAdr nNumBlks); +WFSKrnResult FreeBlkDelete(AreaInfo* area, FBATreeItr* iter, WFSBlkAdr nBlkAdr, WFSBlkAdr nNumBlks, u32 nBlkLog2Size); + +WFSKrnResult FreeBlkInit(AreaInfo *pAreaInfo, u32 offset); +WFSKrnResult FreeBlkAlloc(AreaInfo *pAreaInfo, WFSBlkAdr nRefBlkAdr, WFSBlkAdr nNumBlks, WFSBlkAdr *aBlkAdr, s32 nStride, u32 nBlkLog2Size); +WFSKrnResult FreeBlkFree(AreaInfo *pAreaInfo, WFSBlkAdr nNumBlks, WFSBlkAdr *aBlkAdr, s32 nStride, u32 nBlkLog2Size); + +WFSKrnResult FreeBlkFirst(AreaInfo* area, FBATreeItr* iter, u32 nSubTreeBlkLog2Size); +WFSKrnResult FreeBlkLast(AreaInfo* area, FBATreeItr* iter, u32 nSubTreeBlkLog2Size); +WFSKrnResult FreeBlkNext(AreaInfo* area, FBATreeItr* iter); +WFSKrnResult FreeBlkPrev(AreaInfo* area, FBATreeItr* iter); + +WFSKrnResult FreeBlkFind(AreaInfo* area, FBATreeItr* iter, u32 key, u32 nBlkLog2Size); +WFSKrnResult FreeBlkFindStrict(AreaInfo* area, FBATreeItr* iter, u32 nBlkAdr, u32 nBlkLog2Size); + +WFSBlkAdr FreeBlkGetFreeSize(AreaInfo *pAreaInfo); + +WFSBool FreeBlkVerify(AreaInfo* area); +WFSKrnResult FreeBlkCheckDisk(AreaInfo* area, WFSSrvFileHandle fh, u8* pBuffer, u32 bufferSize, u32 size); +u32 FreeBlkGetFreeBlkLen(AreaInfo* area, u32 nBlkLog2SizeOfs); +WFSKrnResult FreeBlkDumpFreeblock(AreaInfo* area); + +void FBAItrOpen(AreaInfo* area, FBATreeItr* iter); +void FBAItrClose(AreaInfo* area, FBATreeItr* iter); + +PTreeHdr* FTreeSelectSubTree(FTreeHdr* header, WFSBlkAdr unitLen); + +void FBAUnpinCache(AreaInfo* area, u32 diskAddr); +void FBAUnpinFTreeBlk(AreaInfo* area, FBATreeItr* iter); +void FBAFreeCache(AreaInfo* area, u32 diskAddr); +WFSKrnResult FBAGetCache(AreaInfo* area, u32 diskAddr, u32 flags, void** cache); + +#ifdef _DEBUG +// #define FBA_DEBUG_VERBOSE +// #define WFSKRN_FBA_RUNTIME_CHECK +#endif // _DEBUG + +#ifdef WFSKRN_FBA_RUNTIME_CHECK +#define FBA_STRICT_ASSERT(x) { \ + if (FBADebugVerbose) \ + { \ + WFSKRN_FTREE_ASSERT(x); \ + } \ + } +#else +#define FBA_STRICT_ASSERT(x) +#endif + +#endif // BTREE_BASED_ALLOCATOR + +#endif // __WFSKRN_FREEBLKALLOC_H__ + diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_FreeBlkAlloc_Type.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_FreeBlkAlloc_Type.h new file mode 100644 index 0000000..dc0418a --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_FreeBlkAlloc_Type.h @@ -0,0 +1,71 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_FreeBlkAlloc.h + + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_FreeBlkAlloc_Type.h,v $ + Revision 1.4 2008/12/02 04:55:39 ueno + Added EPTree to support multi-PTree. + + Revision 1.2 2008/08/09 03:34:29 ueno + Disabled runtime check. + + Revision 1.1 2008/08/07 10:47:29 ueno + Added for BTREE_BASED_ALLOCATOR (now debugging). + + Revision 1.2 2008/08/02 11:52:10 ueno + Revised the positions of FTreeHdr{} and FBAPTreeHdr{} in 8KB-blocks to protect hash code. + + Revision 1.1 2008/08/01 06:57:39 ueno + Initial Check-in. + +*---------------------------------------------------------------------------*/ + +#ifndef __WFSKRN_FREEBLKALLOC_TYPE_H__ +#define __WFSKRN_FREEBLKALLOC_TYPE_H__ + +#include "wfskrn_Area.h" +#if BTREE_BASED_ALLOCATOR + +#define GET_FBATREE_HDR(area) (&((area)->ah.freeBlkAllocHdr)) + +#define GET_EPTREEHDR_FROM_AREAINFO(area) ((EPTreeHdr*) ((u8*) ((area)->pAflh) + GET_FBATREE_HDR(area)->ofsEPtreeHdr)) +// ~ + +/* + root disk block in the area. + +-----------------+ <-- pVolInfo - - - - - - - - -A + | | | + +-----------------+ <-- pAreaHdr (pAreaInfo->ah) | + | | | + A +-----------------+ <-- pAreaInfo->pAflh | + | | | A | + | | | | | + | | | | | pAreaInfo->nBlkSize (4kB or 8kB?) + ofsEPtreeHdr | | | | | + | | | | nSizeRemaining | + | | | | | + V +-----------------+ | | + | EPTreeHdr | | | + +-----------------+ V - - - - - - - - - - - - - - V +*/ + +// FBATreeHdr is stored in a disk. +typedef struct _FBATreeHdr +{ + unsigned totalBlks; // freeblocks and metadata blocks in the Freeblock allocator. + unsigned ofsEPtreeHdr; // offset of FBAPTreeHdr from pAreaInfo->pAflh. + unsigned ptreeHeight; // height of ptree blocks. the min is FBA_PTREE_MIN_HEIGHT. +} FBATreeHdr; + +#endif // BTREE_BASED_ALLOCATOR +#endif // __WFSKRN_FREEBLKALLOC_TYPE_H__ + diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Handles.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Handles.h new file mode 100644 index 0000000..ae537b7 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Handles.h @@ -0,0 +1,136 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Handles.h - Module for file handles and search directory handles + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Handles.h,v $ + Revision 1.6 2008/10/07 06:01:16 ueno + Modified WFSKrnFileInfoAlloc() to set WFSKRN_HANDLE_ALLOCATED in order to indicate the handle is allocated. + + Revision 1.5 2008/07/17 22:27:36 paul + Removed nRootBlkAdr from WFSKrnSearchDirInfo. (Now in PathCacheItr) + + Revision 1.4 2008/06/09 18:12:18 paul + Made changes to support PathCache. Handles now contain a path cache iterator. + + Revision 1.3 2008/05/16 18:53:34 paul + Added nRootBlkAdr to WFSKrnSearchDirInfo + + Revision 1.2 2008/05/10 04:00:48 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.1 2008/04/24 23:21:13 kondo_masahiro + Initial check-in + + Revision 1.1 2008/04/23 00:27:45 paul + Copied and modified from wfscli_Handles.h + +*---------------------------------------------------------------------------*/ + +#ifndef wfskrn_Handles_h +#define wfskrn_Handles_h + +#ifdef _DEBUG + #define _DEBUG_WFSKRN_HANDLES 1 +#else + #define _DEBUG_WFSKRN_HANDLES 0 +#endif + +#include "wfskrn_Defs.h" +#include "wfskrn_Mutex.h" +#include "wfskrn_PathCache.h" + + +#define WFSKRN_MAX_FILE_HANDLES (1< +#define WFS_HEAP_DEFAULT_ALIGNMENT 32 + +typedef struct { + MEMAllocator allocator; + MEMHeapHandle handle; +} WFSKrnHeap; + +#elif _IOP + +#define WFSKrnHeap IOSHeapId + +#endif + +void WFSKrnCreateHeap(WFSKrnHeap *pHeap, void *pBase, size_t nSize); +void *WFSKrnHeapAlloc(WFSKrnHeap *pHeap, size_t nSize); +void WFSKrnHeapFree(WFSKrnHeap *pHeap, void *pAddr); +void WFSKrnHeapDestroy(WFSKrnHeap *pHeap); + +#endif //define wfskrn_Heap_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Mutex.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Mutex.h new file mode 100644 index 0000000..b8e89e4 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Mutex.h @@ -0,0 +1,190 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Mutex.h - mutual exclusion for multi-thread case + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Mutex.h,v $ + Revision 1.2 2008/08/05 04:17:58 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.3 2008/04/19 05:48:44 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.2 2008/02/28 06:32:23 kondo_masahiro + Fixed code to accept PPC compiler + + Revision 1.1 2007/12/27 11:34:29 paul + similar to wfs_Mutex.h, but will eventually have to support IOP + + *---------------------------------------------------------------------------*/ + +#ifndef wfskrn_Mutex_h +#define wfskrn_Mutex_h + +#include "wfskrn_Defs.h" +#define _TWL 1 //twl modified + +#ifdef _DEBUG + #define _DEBUG_WFSKRN_MUTEX 0 // change to 1 if debug info required +#else + #define _DEBUG_WFSKRN_MUTEX 0 +#endif + +#if _WIN32 + +typedef struct { + HANDLE hHandle; +} WFSKrnMutex; + +typedef struct { + HANDLE hAutoResetEvent; + //HANDLE hManualResetEvent; +} WFSKrnCond; + +#define WFSKrnSemaphore HANDLE + +typedef struct { + HANDLE hThread; +} WFSKrnThread; + +void WFSKrnInitMutex(WFSKrnMutex *mutex); +void WFSKrnLockMutex(WFSKrnMutex *mutex); +bool WFSKrnTryLockMutex(WFSKrnMutex *mutex); +void WFSKrnUnlockMutex(WFSKrnMutex *mutex); + +void WFSKrnInitCond(WFSKrnCond *pCond); +void WFSKrnSignalCond(WFSKrnCond *pCond); +void WFSKrnWaitCond(WFSKrnCond *pCond, WFSKrnMutex* pMx); +void WFSKrnResetCond(WFSKrnCond *pCond); + +#define WFSKrnInitSemaphore(pSem, initNum) *pSem = CreateSemaphore(NULL,initNum,1,NULL); +#define WFSKrnSignalSemaphore(pSem) ReleaseSemaphore(*pSem, 1, NULL); +#define WFSKrnWaitSemaphore(pSem) WaitForSingleObject(*pSem, INFINITE); + +s32 WFSKrnResumeThread(WFSKrnThread *pThread); +void WFSKrnCancelThread(WFSKrnThread *pThread); +void WFSKrnExitThread(void *pVal); +s32 WFSKrnSuspendThread(WFSKrnThread *pThread); +bool WFSKrnIsThreadTerminated(WFSKrnThread *thread); +bool WFSKrnJoinThread(WFSKrnThread *thread, void** val); + +//-- twl modified +#elif _TWL +typedef u32 OSPriority; +#define WFSKrnMutex OSMutex +#define WFSKrnCond OSEvent +#define WFSKrnSemaphore OSSemaphore +#define WFSKrnThread OSThread + +#define WFSKrnInitMutex osInitMutex +#define WFSKrnLockMutex osLockMutex +#define WFSKrnTryLockMutex osTryLockMutex +#define WFSKrnUnlockMutex osUnlockMutex + +//#define WFSKrnInitCond osInitCond +//#define WFSKrnSignalCond osSignalCond +//#define WFSKrnWaitCond osWaitCond +//#define WFSKrnResetCond(x) // This function does nothing on RVL, only needed for Windows +void WFSKrnInitCond(WFSCond *pCond); +void WFSKrnSignalCond(WFSCond *pCond); +void WFSKrnWaitCond(WFSCond *pCond, WFSMutex* pMx); +void WFSKrnResetCond(WFSCond *pCond); + +#define WFSKrnInitSemaphore osInitSemaphore +#define WFSKrnSignalSemaphore osSignalSemaphore +#define WFSKrnWaitSemaphore osWaitSemaphore + +#define WFSKrnResumeThread OSResumeThread +#define WFSKrnCancelThread OSCancelThread +#define WFSKrnExitThread OSExitThread +#define WFSKrnSuspendThread OSSuspendThread +#define WFSKrnIsThreadTerminated OSIsThreadTerminated +#define WFSKrnJoinThread OSJoinThread +//-- twl modified + +#elif _RVL + +#define WFSKrnMutex OSMutex +#define WFSKrnCond OSCond +#define WFSKrnSemaphore OSSemaphore +#define WFSKrnThread OSThread + +#define WFSKrnInitMutex OSInitMutex +#define WFSKrnLockMutex OSLockMutex +#define WFSKrnTryLockMutex OSTryLockMutex +#define WFSKrnUnlockMutex OSUnlockMutex + +#define WFSKrnInitCond OSInitCond +#define WFSKrnSignalCond OSSignalCond +#define WFSKrnWaitCond OSWaitCond +#define WFSKrnResetCond(x) // This function does nothing on RVL, only needed for Windows + +#define WFSKrnInitSemaphore OSInitSemaphore +#define WFSKrnSignalSemaphore OSSignalSemaphore +#define WFSKrnWaitSemaphore OSWaitSemaphore + +#define WFSKrnResumeThread OSResumeThread +#define WFSKrnCancelThread OSCancelThread +#define WFSKrnExitThread OSExitThread +#define WFSKrnSuspendThread OSSuspendThread +#define WFSKrnIsThreadTerminated OSIsThreadTerminated +#define WFSKrnJoinThread OSJoinThread + +#elif _IOP + +#define WFSKRN_MUTEX_Q_SIZE 1 +typedef s32 OSPriority; + +typedef struct{ + IOSMessageQueueId mqid; // Message queue + IOSMessage mq[WFSKRN_MUTEX_Q_SIZE]; + s32 count; // lock count + IOSThreadId owner; +} WFSKrnMutex; + +//#define WFSKrnCond + +typedef struct { + IOSThreadId tid; + s32 count; +} WFSKrnThread; + +void WFSKrnInitMutex(WFSKrnMutex *mutex); +void WFSKrnLockMutex(WFSKrnMutex *mutex); +bool WFSKrnTryLockMutex(WFSKrnMutex *mutex); +void WFSKrnUnlockMutex(WFSKrnMutex *mutex); + +//#define WFSKrnInitCond +//#define WFSKrnSignalCond +//#define WFSKrnWaitCond +//#define WFSKrnResetCond + +s32 WFSKrnResumeThread(WFSKrnThread *pThread); +void WFSKrnCancelThread(WFSKrnThread *pThread); +void WFSKrnExitThread(void *pVal); +s32 WFSKrnSuspendThread(WFSKrnThread *pThread); +bool WFSKrnIsThreadTerminated(WFSKrnThread *pThread); +bool WFSKrnJoinThread(WFSKrnThread *pThread, void** val); + +#endif + +typedef void *(*WFSKrnThreadFunc)(void *); + +bool WFSKrnCreateThread(WFSKrnThread *thread, + WFSKrnThreadFunc threadFunc, + void* param, + void* stackBase, + u32 stackSize, + OSPriority priority); + +#endif //define wfskrn_Mutex_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_PTree.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_PTree.h new file mode 100644 index 0000000..03e9e91 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_PTree.h @@ -0,0 +1,106 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_PTree.h + + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_PTree.h,v $ + Revision 1.2 2008/07/17 22:33:39 paul + Added adapter functions to the Sba allocators for updateMap + + Revision 1.1 2008/07/09 01:42:35 paul + u32->u32 mapping optimized B-Tree. (for use by new block allocator, and transaction block re-mapper) + +*---------------------------------------------------------------------------*/ + +#ifndef wfskrn_PTree_h +#define wfskrn_PTree_h + +#ifdef _DEBUG + #define _DEBUG_PTREE 0 // change to 1 if debug info required +#else + #define _DEBUG_PTREE 0 +#endif + + +#include "wfskrn_Defs.h" + + +#define PTREE_LOG2_NODE_SIZE 5 +#define PTREE_NODE_FAN_OUT 6 // (6 * 2 Byte Offset) + (5 * 4 Byte Key) = 32 Bytes +#define PTREE_LEAF_FAN_OUT 4 // 4 * (4 Byte Key + 4 Byte Value) = 32 Bytes +#define PTREE_MAX_HEIGHT 5 + + +// Node Sizes: + +typedef struct { + u32 aKey[PTREE_NODE_FAN_OUT-1]; + u16 aOfs[PTREE_NODE_FAN_OUT]; +} PTreeNode; + +typedef struct { + u32 aKey[PTREE_LEAF_FAN_OUT]; + u32 aData[PTREE_LEAF_FAN_OUT]; +} PTreeLeaf; + +typedef struct { + u16 *pOfs; // A pointer to the offset pointer to the node. This would need to be updated if the sub block is relocated. + PTreeLeaf *pLeaf; + PTreeNode *apNode[PTREE_MAX_HEIGHT-1]; + u32 aEntryIdx[PTREE_MAX_HEIGHT]; + //u32 *apKey[PTREE_MAX_HEIGHT]; + u32 nKey; + u32 nData; +} PTreeItr; + +typedef u16 (*PTreeAllocNodeFunc) (void *pBase); +typedef WFSKrnResult (*PTreeAllocNodesFunc)(void *pBase, u16 *pNodeOfs, u32 nNumNodes); +typedef void (*PTreeFreeNodeFunc) (void *pBase, u16 nOfs); + +typedef struct { + void *pBase; + PTreeAllocNodeFunc fpAllocNode; + PTreeAllocNodesFunc fpAllocNodes; + PTreeFreeNodeFunc fpFreeNode; +} PTreeAllocator; + +// Allocator functions which use SubBlkAlloc module +u16 PTreeAllocNodeFromSba(void *pBase); +WFSKrnResult PTreeAllocNodesFromSba(void *pBase, u16 aNodeOfs[], u32 nNumNodes); +void PTreeFreeNodeToSba(void *pBase, u16 nOfs); + +typedef struct { + u32 nRootHeight; // height of root node (opposite of depth). + u16 nRootOfs; // Offset to the root node of the tree. + u16 nNumRecs; // Number of records in the tree. +} PTreeHdr; + +typedef struct { + u16 nParentOfs; // The offset the to parent of this node + u8 nEntryIdx; // The index of the entry in the parent block which points to this node + u8 nNumEntries; // The number of entries in this node + u32 nLength; +} PTreeAttrHdr; + +void PTreeInit (PTreeHdr *pPTreeHdr, PTreeAllocator *pAllocator); +WFSKrnResult PTreeFind (PTreeHdr *pPTreeHdr, PTreeItr *pPti, u32 nKey, PTreeAllocator *pAllocator); +WFSKrnResult PTreeInsert(PTreeHdr *pPTreeHdr, PTreeItr *pPti, u32 nKey, u32 nData, PTreeAllocator *pAllocator); +WFSKrnResult PTreeDelete(PTreeHdr *pPTreeHdr, PTreeItr *pPti, PTreeAllocator *pAllocator); +WFSKrnResult PTreeFirst (PTreeHdr *pPTreeHdr, PTreeItr *pPti, PTreeAllocator *pAllocator); +WFSKrnResult PTreeNext (PTreeHdr *pPTreeHdr, PTreeItr *pPti, PTreeAllocator *pAllocator); + +WFSKrnResult PTreeInsertOrUpdateRec(PTreeHdr *pPTreeHdr, u32 nKey, u32 nData, PTreeAllocator *pAllocator); + +void PTreeCheck(PTreeHdr *pPTreeHdr, u32 nLog2Size, PTreeAllocator *pAllocator); +void PTreeTest(); + + +#endif //define wfskrn_PTree_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_PathCache.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_PathCache.h new file mode 100644 index 0000000..8fcb96e --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_PathCache.h @@ -0,0 +1,202 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_PathCache.h - Caches recently used path names plus root path names "/dev", "/vol" + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_PathCache.h,v $ + Revision 1.13 2008/12/04 00:42:37 ooizumi + Changed definition name to enable permission. + + Revision 1.12 2008/10/31 09:51:42 ueno + Modified WFSSrvAPIs to return WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED when path cache is short of memory. + + Revision 1.11 2008/10/07 10:30:01 ooizumi + Defined PathCachePerm. + Added nObjCreator to PathCacheData. + + Revision 1.10 2008/07/30 21:25:01 paul + Removed some unused definitions + + Revision 1.9 2008/07/30 06:04:34 ooizumi + Added definitions for permission. + + Revision 1.8 2008/07/21 22:48:35 paul + Added PathCacheCheck() + + Revision 1.7 2008/07/17 22:31:12 paul + Added nRootBlkAdr to PathCacheItr. + + Revision 1.6 2008/07/09 01:46:06 paul + Minor change. + + Revision 1.5 2008/06/23 13:44:04 nakanose_jin + add cast for avoid warning + + Revision 1.4 2008/06/09 18:06:42 paul + Rewrote PathCache to use a radix tree. Now actually provides PathCache functionality. + Also stores a list of open file / directory search paths so that invalid WFSSrv calls can be detected. + + Revision 1.3 2008/05/14 02:14:54 paul + Added some comments + + Revision 1.2 2008/05/12 19:22:12 paul + Made naming more consistent + + Revision 1.1 2008/05/10 04:00:29 kondo_masahiro + Initial check-in + +*---------------------------------------------------------------------------*/ + +#ifndef wfskrn_PathCache_h +#define wfskrn_PathCache_h + +#include "wfskrn_Config.h" +#include "wfskrn_DirRxTree.h" + +#ifdef _DEBUG + #define _DEBUG_PATH_CACHE 0 // change to 1 if debug info required +#else + #define _DEBUG_PATH_CACHE 0 +#endif + +#if _CHECK_RXT + #define _CHECK_PATH_CACHE 1 +#else + #define _CHECK_PATH_CACHE 0 +#endif + +#define WFS_DEVICE_DIRECTORY "/dev" +#define WFS_VOLUME_DIRECTORY "/vol" + + +#define PATH_CACHE_MAX_ENTRIES ((1<pStrPtr, WFS_MAX_PATH_NAME_SIZE); + return PathCacheFind3(pRxi, nStrLen, ppData); +} + +static inline PathCacheEntry *PathCacheFind1(RxtItr *pRxi) { + void *pData; + return PathCacheFind2(pRxi, &pData); +} + +PathCacheEntry *PathCacheIncrementalFindEntry(RxtItr *pRxi, u32 nStrLen, void **ppData); + +void PathCacheDeleteEntry(PathCacheEntry *pEntry); +WFSKrnResult PathCacheDeleteSubTree(PathCacheEntry *pEntry); +WFSKrnResult PathCacheDeleteLru(); + +PathCacheEntry *PathCacheIncrementalInsertAfterCursorEntry(PathCacheEntry *pCursorEntry, RxtItr *pRxi, u32 nPrefixLen, u32 nSuffixLen); +WFSKrnResult PathCacheIncrementalInsertPinnedEntry(PathCacheItr *pPci, u32 nStrLen); +#if _DEBUG_PATH_CACHE + WFSKrnResult PathCacheIncreaseEntryOpenHandleCount(PathCacheItr *pPci, WFSAccess nDesiredAccess, utf8 *sStr); + WFSKrnResult PathCacheDecreaseEntryOpenHandleCount(PathCacheItr *pPci, utf8 *sStr); + void PathCachePinEntry(PathCacheEntry *pEntry, utf8 *sStr); +#else + WFSKrnResult PathCacheIncreaseEntryOpenHandleCount(PathCacheItr *pPci, WFSAccess nDesiredAccess); + WFSKrnResult PathCacheDecreaseEntryOpenHandleCount(PathCacheItr *pPci); + void PathCachePinEntry(PathCacheEntry *pEntry); +#endif + +#if _CHECK_PATH_CACHE + void PathCacheCheck(); +#endif + + +void PathCacheInit(); +void PathCacheTest(); + +WFSKrnResult PathCacheFindParentDir(const WFSPathName *pAbsPathName, utf8 *sLowerCaseStr, PathCacheItr *pPci); +WFSKrnResult PathCacheFindPath (const WFSPathName *pAbsPathName, utf8 *sLowerCaseStr, PathCacheItr *pPci); + +#endif //define wfskrn_PathCache_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission.h new file mode 100644 index 0000000..b85de05 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission.h @@ -0,0 +1,79 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Permission.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission.h,v $ + Revision 1.5 2008/12/18 10:28:33 ooizumi + Fixed macro. + + Revision 1.4 2008/12/04 00:49:49 ooizumi + Removed old codes. + Fixed. + + Revision 1.3 2008/07/31 23:59:09 ooizumi + Fixed permission of special directories.. + + Revision 1.2 2008/07/30 06:04:34 ooizumi + Added definitions for permission. + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.6 2008/02/28 04:36:47 ueno + Cleanup. + + Revision 1.5 2008/02/27 10:05:26 ueno + Revised to use WFSAreaHdr{} to specifiy WFS area. + + Revision 1.4 2008/02/27 04:33:36 ueno + Added root ID and alias permission flags. + + Revision 1.3 2008/02/26 14:12:06 ueno + Added WFSAccessListAddEntry() and WFSAccessListRemoveEntry() to edit accesslist. + + Revision 1.2 2008/02/25 09:44:08 ueno + Added support for accesslist cache. + + Revision 1.1 2008/02/22 05:15:55 ueno + Initial Check-in. + + +*---------------------------------------------------------------------------*/ +#ifndef __WFS_PERMISSION_H__ +#define __WFS_PERMISSION_H__ + +#ifdef _DEBUG + +#ifdef WIN32 +#define WFSKRN_PERM_ASSERT(x) assert(x) +//#define WFSKRN_PERM_REPORT printf +#define WFSKRN_PERM_REPORT +#else // Win32 +#define WFSKRN_PERM_ASSERT(x) SDK_ASSERT(x) +//#define WFSKRN_PERM_REPORT(...) printf(__VA_ARGS__) +#define WFSKRN_PERM_REPORT osTPrintf +#endif // WIN32 + +#else // _DEBUG + +#define WFSKRN_PERM_ASSERT(x) SDK_ASSERT(x) +#define WFSKRN_PERM_REPORT(...) osTPrintf(__VA_ARGS__) +//#define WFSKRN_PERM_ASSERT(x) +//#define WFSKRN_PERM_REPORT(...) + +#endif // _DEBUG + +WFSKrnResult WFSKrnGetInheritedPermissionForUserDi(PathCacheItr* pPci, u32* pFlags, WFSTitleId titleId); +WFSKrnResult WFSKrnGetInheritedPermissionForUserPci(PathCacheItr* pPci, u32* pFlags, WFSTitleId titleId); +WFSKrnResult WFSKrnGetParentInheritedPermissionForUserPci(PathCacheItr* pPci, u32* pFlags, WFSTitleId titleId); +WFSKrnResult WFSKrnSetInheritedPermissionForUser(PathCacheItr* pPci, u32 nFlags, u32 nMask, WFSTitleId entryCreatorId, WFSTitleId titleId); + +#endif // __WFS_PERMISSION_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_AccessList.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_AccessList.h new file mode 100644 index 0000000..13f7f1b --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_AccessList.h @@ -0,0 +1,567 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Permission_AccessList.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission_AccessList.h,v $ + Revision 1.23 2008/09/24 07:32:07 ueno + Added AclHdr{} to AreaHdr{} to save configuration of accesslists in a disk. + + Revision 1.22 2008/08/14 08:02:57 kondo_masahiro + Fixed definition of ACL_GET_CL_RELATIVE() from inline to static inline. + + Revision 1.21 2008/07/23 04:18:07 ueno + Reduced memory size required for accesslist. + + Revision 1.20 2008/07/11 08:10:50 ueno + Fixed control level check. + + Revision 1.19 2008/06/16 18:03:56 ueno + Fixed comment. + + Revision 1.18 2008/06/05 14:04:11 ueno + Modified to reserve accesslist index 0 as the default (empty) accesslist. + + Revision 1.17 2008/06/05 08:44:40 ueno + Cleanup. + + Revision 1.16 2008/06/05 08:09:18 ueno + Revised permission APIs. + + Revision 1.15 2008/06/02 15:09:54 ueno + Revised WFSKrnAccessList{} to reduce the size. + + Revision 1.14 2008/05/29 14:08:13 ueno + Modified _WFSAccessListControlBlock(). + + Revision 1.13 2008/05/28 02:12:57 ueno + Cleanup. + + Revision 1.12 2008/05/23 06:31:52 ueno + Cleanup. + + Revision 1.11 2008/05/19 05:31:53 ueno + Defined accesslist meta-data types. + + Revision 1.10 2008/05/15 13:33:46 ueno + Implemented initialization using directory module. + + Revision 1.9 2008/05/06 02:27:21 ueno + Fixed ifdef. + + Revision 1.8 2008/04/29 06:25:14 ueno + Cleanup. + + Revision 1.7 2008/04/29 01:12:54 ueno + Defined WFS_ROOT_ID and WFS_EVERYONE_ID. + + Revision 1.6 2008/04/25 19:15:14 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.4 2008/04/25 06:22:55 ueno + Cleanup. + + Revision 1.3 2008/04/25 04:40:47 ueno + Added support for WFSDEV. + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.23 2008/04/23 08:59:55 ueno + Replaced WFSAreaHdr by AreaInfo. + Revised directory permission (change -> add). + + Revision 1.22 2008/04/21 06:07:54 ueno + Fixed struct for C99. + + Revision 1.21 2008/04/15 07:35:29 ueno + Fixed error codes. + + Revision 1.20 2008/04/15 06:45:47 ueno + Changed return type to WFSKrnResult. + + Revision 1.19 2008/04/14 13:50:17 ueno + Cleanup. + + Revision 1.18 2008/04/14 03:02:16 ueno + Modified WFSKrnCreateRootAccessList() to create an accesslist only for the root. + Added WFSKrnDebugCreateAccessList() for tests. + + Revision 1.17 2008/04/11 13:20:13 ueno + Removed WFSKrnAccessListSetInstallerPermission(). + + Revision 1.16 2008/04/11 06:16:33 ueno + Defined WFSAclFileHandle. + Cleaned up headers. + + Revision 1.15 2008/04/11 02:52:11 ueno + Renamed WFSKrnCreateAccessList() to make clear the purpose. + + Revision 1.14 2008/04/09 11:31:25 ueno + Changed the maximum number of accesslist handles. + + Revision 1.13 2008/04/07 12:47:17 ueno + Added support for group others. + + Revision 1.12 2008/04/07 09:18:54 ueno + Modified WFSAccessListControlBlock() to keep permissions for the installer. + + Revision 1.11 2008/04/03 09:59:30 ueno + Added manuals of WFS AccessList APIs. + + Revision 1.10 2008/04/03 06:40:35 ueno + Removed WFSKRN_ACCESSLIST_FLAG_CONTENT_DIRECTORY flag. + Cleanup. + + Revision 1.9 2008/04/02 14:15:13 ueno + Revised permission inheritance. + + Revision 1.8 2008/03/31 14:06:49 ueno + Removed WFSKrnAccessListAddUser() and RemoveUser(). + Removed WFSKrnAccessListCan*(). + + Revision 1.7 2008/03/19 10:18:49 ueno + Revised WFSKrnAddUser() and RemoveUser() to specify operator title ID. + + Revision 1.6 2008/03/18 13:42:28 ueno + Added WFSKrnAccessListSetControlLevel(), GetControlLevel() to set/get a control level. + + Revision 1.5 2008/03/14 08:02:48 ueno + Revised API prefixes (WFS -> WFSKrn). + + Revision 1.4 2008/03/12 06:37:34 ueno + Added WFSAccessListCanRead(), Write()... + + Revision 1.3 2008/03/11 12:10:35 ueno + Cleanup. + + Revision 1.2 2008/03/11 11:38:58 ueno + Cleanup. + + Revision 1.1 2008/03/11 11:09:21 ueno + Renamed. + + Revision 1.14 2008/03/11 09:51:51 ueno + Fixed EscapeAccessList() to make a filename from UTF-16 characters (0x3300-0x33ff). + + Revision 1.13 2008/03/11 06:53:02 ueno + Added WFSAccessListSetPermission() and GetPermission(). + + Revision 1.12 2008/03/07 05:43:57 ueno + Cleanup. + + Revision 1.10 2008/03/06 12:26:04 ueno + Revised cache freelist (signgle -> double link list). + + Revision 1.9 2008/03/06 10:46:19 ueno + Cleanup. + + Revision 1.8 2008/02/29 00:47:45 ueno + Changed the attribute of index to inout (WFSAccessListAddEntry() and RemoveEntry()). + + Revision 1.7 2008/02/28 13:11:58 ueno + Revised to keep accesslist cache and indexlist handle in WFSAreaHdr{}. + + Revision 1.6 2008/02/28 04:36:47 ueno + Cleanup. + + Revision 1.5 2008/02/27 10:05:26 ueno + Revised to use WFSAreaHdr{} to specifiy WFS area. + + Revision 1.4 2008/02/27 04:33:36 ueno + Added root ID and alias permission flags. + + Revision 1.3 2008/02/26 14:12:06 ueno + Added WFSAccessListAddEntry() and WFSAccessListRemoveEntry() to edit accesslist. + + Revision 1.2 2008/02/25 09:44:08 ueno + Added support for accesslist cache. + + Revision 1.1 2008/02/22 05:15:55 ueno + Initial Check-in. + + +*---------------------------------------------------------------------------*/ +#ifndef __WFSKRN_PERMISSION_ACCESSLIST_H__ +#define __WFSKRN_PERMISSION_ACCESSLIST_H__ + +#include + +#if !_IOP +#include "wfs_Client.h" +#endif + +#include "wfskrn_Area.h" +#include "wfskrn_Mutex.h" +#include "wfskrn_Permission_Type.h" + +#define WFSKRN_ACCESSLIST_MAX_CONTROL_LEVEL 3 + +#if !_IOP +namespace wfsdev_api{ + struct tagSAreaInfo; +} +#endif + + +#ifndef ROUNDUP32BYTE +#define ROUNDUP32BYTE(val) (((size_t)val+31)&~31) +#endif // ROUNDUP32BYTE + +// +// Accesslist Cache +// + +#define ACL_MAX_MEMORY_BLOCK 254 // [check] +#define ACL_NO_ENTRY 255 // [check] + +typedef struct WFSKrnAccessListEntry +{ + u32 id; // title ID. + u32 ecId; // entry creator's Id. + u32 pm; // permissions and control levels. +} WFSKrnAccessListEntry; + +typedef struct _WFSKrnAccessList WFSKrnAccessList; + +struct _WFSKrnAccessList +{ + u8 num; // number of blocks in this list. + u8 type; // WFSKRN_ACCESSLIST_FREEBLOCK or 0. + u16 ref; // reference count of this cache. + WFSKrnAclHandle handle; // access list handle and WFSKRN_ACCESSLIST_FLAG_* flags + u8 prevFreeCacheBlock; // previous free cache. + u8 nextFreeCacheBlock; // next free cache. + u8 prevBlock; // previous cache. + u8 nextBlock; // next cache. +}; + +// cache list, free cache list. +typedef struct WFSKrnAccessListLinkList +{ + WFSKrnAccessList* head; + WFSKrnAccessList* tail; +} WFSKrnAccessListLinkList; + +#define WFSKRN_ACCESSLIST_FREEBLOCK ((u8) 0x1) // Free memory block. +#define WFSKRN_BLOCKS_IN_LIST(x) (sizeof(WFSKrnAccessList)/sizeof(WFSKrnAccessListBlock) + \ + WFSKrnAccessListGetNum(x) * (sizeof(WFSKrnAccessListEntry)/sizeof(WFSKrnAccessListBlock))) + +typedef struct WFSKrnAccessListBlock +{ + u8 num; // number of blocks in this chunk. + u8 type; // WFSKRN_ACCESSLIST_FREEBLOCK or 0. + u8 reserved; + u8 nextBlock; // the block number of the next chunk. +} WFSKrnAccessListBlock; + +#define ACL_DEFAULT_CACHESIZE (128 * sizeof(WFSKrnAccessListBlock)) + +// +// Accesslist Index +// + +#define ACL_RELATIVE_CL_FLAG 0x8000 +#define ACL_CL_MASK 0x0003 +#define WFS_PERM_RELATIVE_CL_FLAG 0x8000 + +static inline WFSKrnResult ACL_GET_CL_RELATIVE(u32 perm, int* cl) +{ + WFSKrnResult result = WFSKRN_RESULT_INVALID; + if (perm & ACL_RELATIVE_CL_FLAG) + { + u32 val = ((~perm >> WFS_PERM_CL_SHIFT) & ACL_CL_MASK); + *cl = -((int) val); + result = WFSKRN_RESULT_OK; + } + return result; +} + +#define ACL_ENTRY_NET_SIZE (sizeof(u32) + sizeof(u32) + sizeof(u16)) // smaller than sizeof(WFSKrnAccessListEntry). +#define ACL_MAX_ENTRIES (WFS_MAX_FILE_NAME_SIZE - sizeof(u32)*2)/(ACL_ENTRY_NET_SIZE*2) +// flags for accesslist handle +#define ACL_FLAG_DIRECTORY (1<<31) // accesslist for directory. +#define ACL_FLAG_RESERVED0 (1<<30) +#define ACL_FLAG_RESERVED1 (1<<29) +#define ACL_FLAG_RESERVED2 (1<<28) +#define ACL_TYPE_MASK (~0xf0000000) +#define ACL_TYPE(x) ((x)->handle & ~ACL_TYPE_MASK) +#define ACL_INDEX(x) ((x)->handle & ACL_TYPE_MASK) + +#define WFSKRN_ACCESSLIST_GROUP 0x80000000 + +// escape sequence to convert a content of an accesslist to a filename. +#define ESCAPE 0x33 +#define ESCAPED_NULL 0x58 + +// +// Index List +// which manages indices of free and used accesslists. +// +#define WFSKRN_ACCESSLIST_INDEXES_IN_PAGE 16 +#define WFSKRN_ACCESSLIST_INDEXLIST_MAX_PAGE 6 +#define WFSKRN_ACCESSLIST_FREEINDEX 0xffffffff + +typedef struct IndexListHeader +{ + u32 numEntry; +} IndexListHeader; + +typedef struct IndexListEntry +{ + u32 location; +} IndexListEntry; + +// +// Control Block of Accesslists. +// + +#if WFSDEV +namespace wfsdev_api{ + struct tagSAreaInfo; +} +#endif + +#ifndef _struct_WFSAccessListControlBlock_ +#define _struct_WFSAccessListControlBlock_ +typedef struct _WFSAccessListControlBlock WFSAccessListControlBlock; +#endif + +struct _WFSAccessListControlBlock +{ + WFSKrnAccessListBlock* freeBlock; + WFSKrnAccessListBlock* memoryBlock; // heap for accesslist cache. + u32 numBlock; + + WFSKrnAccessListLinkList cache; + WFSKrnAccessListLinkList cacheFreeList; +#ifdef WFSKRN_ACL_USE_MUTEX + WFSKrnMutex mxMutex; +#endif // WFSKRN_ACL_USE_MUTEX + +#if WFSDEV + struct wfsdev_api::tagSAreaInfo *aclWrapper; +#endif + WFSBool initialized; +}; + +// +// APIs +// + +//-------------------------------------------------------------------------------------------------------------- +// WFSKrnAccessListInit +//-------------------------------------------------------------------------------------------------------------- +// Arguments: +// ---------- +// area .. [in] A WFS area. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. success +// WFSKRN_RESULT_ACL_ERROR .. (see wfskrn_Errors.h) +// WFSKRN_RESULT_INVALID +// WFSKRN_RESULT_OUT_OF_MEMORY +// WFSKRN_RESULT_LIB_ALREADY_INITIALIZED +// +// Description: +// ------------ +// This function initializes accesslist cache and accesslist index list. +// WFSAccessListControlBlock{} in area (AreaInfo{}) must be properly initialized before calling this function. +// - Memory blocks for accesslist cache must be set in memoryBlock field of WFSAccessListControlBlock{}. +// - The number of blocks must be set in numBlock field. +// - initialized field must be set to FALSE. +WFSKrnResult WFSKrnAccessListInit(AreaInfo* area); + + +//-------------------------------------------------------------------------------------------------------------- +// WFSKrnAccessListOpen +//-------------------------------------------------------------------------------------------------------------- +// Arguments: +// ---------- +// area .. [in] A WFS area. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. success +// WFSKRN_RESULT_OUT_OF_MEMORY +// WFSKRN_RESULT_LIB_ALREADY_INITIALIZED +// +// Description: +// ------------ +// This function initializes accesslist cache and loads accesslist configuration from the device: +// - the root block for accesslist files. +// - the root block for accesslist namefiles and the index list. +// WFSAccessListControlBlock{} in area (AreaInfo{}) must be properly initialized before calling this function. +// - Memory blocks for accesslist cache must be set in memoryBlock field of WFSAccessListControlBlock{}. +// - The number of blocks must be set in numBlock field. +// - initialized field must be set to FALSE. +WFSKrnResult WFSKrnAccessListOpen(const AreaInfo* area); + + +//-------------------------------------------------------------------------------------------------------------- +// WFSKrnAccessListExit +//-------------------------------------------------------------------------------------------------------------- +// Arguments: +// ---------- +// area .. [in] A WFS area. +// +// Return Values: +// -------------- +// WFS_RESULT_OK .. success +// +// Description: +// ------------ +// This function is not implemented. +// +WFSKrnResult WFSKrnAccessListExit(const AreaInfo* area); + +//-------------------------------------------------------------------------------------------------------------- +// WFSKrnDeletePermissions +//-------------------------------------------------------------------------------------------------------------- +// Arguments: +// ---------- +// area .. [in] A WFS area. +// handle .. [in] Accesslist handle. +// titleId .. [in] Title Id to be deleted. +// entryCreatorId .. [in] Entry creator's Id. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. success +// WFSKRN_RESULT_INVALID +// WFSKRN_RESULT_ACL_ERROR +// WFSKRN_RESULT_ACL_MAX_ENTRIES +// WFSKRN_RESULT_ACL_FILE +// +// Description: +// ------------ +// This function deletes the specified entry in the specified accesslist. + +WFSKrnResult WFSKrnDeletePermissions(const AreaInfo* area, + WFSKrnAclHandle* handle, WFSTitleId entryCreatorId, WFSTitleId titleId); + +// Arguments: +// ---------- +// area .. [in] A WFS area. +// handle .. [in] Accesslist handle. +// pAccessList .. [out] Buffer for an accesslist. +// nMaxElements .. [out] Size of the buffer. +// +// Return Values: +// -------------- +// The number of entries. .. success +// WFSKRN_RESULT_ACL_BUFFER_TOO_SMALL +// +// Description: +// ------------ +// This function gets all entries in the specified accesslist. + +s32 WFSKrnGetAccessList(const AreaInfo* area, + WFSKrnAclHandle handle, WFSAccessListEntry *pAccessList, u32 nMaxElements); + +//-------------------------------------------------------------------------------------------------------------- +// WFSKrnSetAccessList +//-------------------------------------------------------------------------------------------------------------- +// Arguments: +// ---------- +// area .. [in] A WFS area. +// handle .. [inout] Accesslist handle. +// caller .. [in] +// nFlags .. [in] Permissions and control levels to be set. +// nMask .. [in] Mask of permissions. +// entryCreatorId .. [in] Id of the title which created the entry. +// titleId .. [in] Title Id of the entry to be modified. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. success +// WFSKRN_RESULT_INVALID +// WFSKRN_RESULT_ACL_ERROR +// WFSKRN_RESULT_ACL_MAX_ENTRIES +// WFSKRN_RESULT_ACL_FILE +// +// Description: +// ------------ +// This function chnages permissions of the specified entry, or creates a new entry. +WFSKrnResult WFSKrnSetAccessList(const AreaInfo* area, WFSKrnAclHandle* handle, + u32 nFlags, u32 nMask, WFSTitleId entryCreatorId, WFSTitleId titleId); + +//-------------------------------------------------------------------------------------------------------------- +// WFSKrnReleaseAccessList +//-------------------------------------------------------------------------------------------------------------- +// Arguments: +// ---------- +// area .. [in] A WFS area. +// handle .. [in] A handle of accesslist . +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. success +// WFSKRN_RESULT_ACL_ERROR +// WFSKRN_RESULT_ACL_CACHE +// WFSKRN_RESULT_ACL_FILE +// +// Description: +// ------------ +// This function decrements the reference count of the specified accesslist. +// When the count reduces to zero, the accesslist is removed. +// This is called when deleting a file or directory. +WFSKrnResult WFSKrnReleaseAccessList(const AreaInfo* area, WFSKrnAclHandle handle); + +//-------------------------------------------------------------------------------------------------------------- +// WFSKrnAccessListCheckDirectoryPermission +//-------------------------------------------------------------------------------------------------------------- +// Arguments: +// ---------- +// area .. [in] WFS area. +// handle .. [in] A handle of an accesslist for a directory. +// titleId .. [in] Title ID. +// flag .. [in] Permissions to be checked. +// +// Return Values: +// -------------- +// TRUE .. The title has the specified permissions. +// FALSE .. The title does not have the permissions. +// +// Description: +// ------------ +// This function checks if the title has the specified directory permissions. +// +// WFSBool WFSKrnAccessListCheckDirectoryPermission(const AreaInfo* area, WFSKrnAclHandle handle, WFSTitleId titleId, u32 flag); + +//-------------------------------------------------------------------------------------------------------------- +// WFSKrnAccessListCheckDirectoryPermission +//-------------------------------------------------------------------------------------------------------------- +// Arguments: +// ---------- +// area .. [in] WFS area. +// handle .. [in] A handle of an accesslist for a file. +// titleId .. [in] Title ID. +// flag .. [in] Permissions to be checked. +// +// Return Values: +// -------------- +// TRUE .. The title has the specified permissions. +// FALSE .. The title does not have the permissions. +// +// Description: +// ------------ +// This function checks if the title has the specified file permissions. +// WFSBool WFSKrnAccessListCheckFilePermission(const AreaInfo* area, +// WFSKrnAclHandle handle, WFSTitleId titleId, u32 flag); + +// +// Memory block allocator for accesslist cache. +// +WFSKrnAccessListBlock* WFSKrnMemoryBlockAlloc(const AreaInfo* area, int numBlocks); +int WFSKrnMemoryBlockFree(const AreaInfo* area, WFSKrnAccessListBlock* block, u32 numBlocks); + +#endif // __WFSKRN_PERMISSION_ACCESSLIST_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_AccessList_Type.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_AccessList_Type.h new file mode 100644 index 0000000..030ecbe --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_AccessList_Type.h @@ -0,0 +1,29 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Permission_AccessList_Type.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission_AccessList_Type.h,v $ + Revision 1.1 2008/09/24 07:50:34 ueno + Added AclHdr{} to AreaHdr{} to save configuration of accesslists in a disk. + + + +*---------------------------------------------------------------------------*/ +#ifndef __WFSKRN_PERMISSION_ACCESSLIST_TYPE_H__ +#define __WFSKRN_PERMISSION_ACCESSLIST_TYPE_H__ + +typedef struct _AclHdr +{ + WFSBlkAdr aclBlock; + WFSBlkAdr nameBlock; +} AclHdr; + +#endif // __WFSKRN_PERMISSION_ACCESSLIST_TYPE_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_File.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_File.h new file mode 100644 index 0000000..d0f9605 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_File.h @@ -0,0 +1,107 @@ +/*---------------------------------------------------------------------------* + Project: wfskrn + File: wfs_Permission.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission_File.h,v $ + Revision 1.9 2008/07/23 04:18:07 ueno + Reduced memory size required for accesslist. + + Revision 1.8 2008/05/23 06:31:52 ueno + Cleanup. + + Revision 1.7 2008/05/22 06:36:01 ueno + Ported permission APIs to IOP. + + Revision 1.6 2008/05/19 10:12:05 ueno + Revised not to use hardlink. + + Revision 1.5 2008/05/15 13:33:46 ueno + Implemented initialization using directory module. + + Revision 1.4 2008/04/29 06:25:14 ueno + Cleanup. + + Revision 1.3 2008/04/25 06:22:55 ueno + Cleanup. + + Revision 1.2 2008/04/25 01:22:46 ueno + Moved from RVL_SDK to RM_SDK. + + Revision 1.12 2008/04/23 08:59:55 ueno + Replaced WFSAreaHdr by AreaInfo. + Revised directory permission (change -> add). + + Revision 1.11 2008/04/21 06:07:55 ueno + Fixed struct for C99. + + Revision 1.10 2008/04/15 06:45:48 ueno + Changed return type to WFSKrnResult. + + Revision 1.9 2008/04/11 06:16:33 ueno + Defined WFSAclFileHandle. + Cleaned up headers. + + Revision 1.8 2008/03/14 08:02:49 ueno + Revised API prefixes (WFS -> WFSKrn). + + Revision 1.7 2008/03/11 12:10:35 ueno + Cleanup. + + Revision 1.6 2008/02/29 07:28:45 ueno + Added Windows api wrappers. + + Revision 1.5 2008/02/27 13:12:23 ueno + Revised to store a filename of an accesslist in a file (*.name). + + Revision 1.4 2008/02/27 10:05:26 ueno + Revised to use WFSAreaHdr{} to specifiy WFS area. + + Revision 1.3 2008/02/26 14:12:06 ueno + Added WFSAccessListAddEntry() and WFSAccessListRemoveEntry() to edit accesslist. + + Revision 1.2 2008/02/25 09:44:08 ueno + Added support for accesslist cache. + + Revision 1.1 2008/02/22 05:15:56 ueno + Initial Check-in. + + +*---------------------------------------------------------------------------*/ +#ifndef __WFSKRN_PERMISSION_FILE_H__ +#define __WFSKRN_PERMISSION_FILE_H__ + +#include +#include "wfssrv_Defs.h" +#include "wfskrn_Area.h" +#include "wfskrn_Permission_Type.h" + +#ifndef WFSDEV +#define IndexDirInfo(x) (((x)->accessListCb->indexDirInfo)) +#endif // WFSDEV + +int WFSKrnConvertAccessListToFilename(const WFSKrnAccessList* list, utf8* filename, u32 size); +int WFSKrnConvertFilenameToAccessList(const utf8* filename, u32 size, WFSKrnAccessList* list); + +int WFSKrnAccessListIndexListInit(const AreaInfo* area); +int WFSKrnAccessListIndexListExit(const AreaInfo* area); +int WFSKrnAccessListCreateFile(const AreaInfo* area, const utf8* filename, WFSKrnAccessList** list); +WFSKrnResult WFSKrnAccessListDeleteFile(const AreaInfo* area, u32 index); +WFSKrnAccessList* WFSKrnAccessListLookupFile(const AreaInfo* area, u32 index); +WFSKrnResult WFSKrnAccessListSetFileReferenceCount(const AreaInfo* area, u32 index, u32 ref); +WFSKrnResult WFSKrnAccessListGetFileReferenceCount(const AreaInfo* area, u32 index, u32* ref); +int WFSKrnAccessListOpenList(const AreaInfo* area, const utf8* filename, AclFileInfo* aclFile, + WFSBool create, WFSAclFileHandle *pFh); + +int GetAccessListIndex(const AreaInfo* area, WFSAclFileHandle indexListHandle, WFSKrnAclHandle handle, IndexListEntry* entry); +int OpenIndexList(const AreaInfo* area, WFSAclFileHandle* indexListHandle, AclFileInfo* indexListInfo); +int CloseIndexList(const AreaInfo* area, WFSAclFileHandle indexListHandle); + +#endif // __WFSKRN_PERMISSION_FILE_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_Iop.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_Iop.h new file mode 100644 index 0000000..defb492 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_Iop.h @@ -0,0 +1,123 @@ +/*---------------------------------------------------------------------------* + Project: wfsKrn + File: wfs_Permission_Iop.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission_Iop.h,v $ + Revision 1.7 2008/09/24 07:32:07 ueno + Added AclHdr{} to AreaHdr{} to save configuration of accesslists in a disk. + + Revision 1.6 2008/07/23 04:18:07 ueno + Reduced memory size required for accesslist. + + Revision 1.5 2008/05/22 06:36:01 ueno + Ported permission APIs to IOP. + + Revision 1.4 2008/05/19 10:12:05 ueno + Revised not to use hardlink. + + Revision 1.3 2008/05/19 05:31:53 ueno + Defined accesslist meta-data types. + + Revision 1.2 2008/05/15 13:33:46 ueno + Implemented initialization using directory module. + + Revision 1.1 2008/05/06 07:38:27 ueno + Initial Check-in. + + Revision 1.6 2008/04/29 06:25:14 ueno + Cleanup. + + Revision 1.5 2008/04/29 01:12:54 ueno + Defined WFS_ROOT_ID and WFS_EVERYONE_ID. + + Revision 1.4 2008/04/25 06:22:55 ueno + Cleanup. + + Revision 1.3 2008/04/25 04:40:47 ueno + Added support for WFSDEV. + + Revision 1.10 2008/04/23 08:59:55 ueno + Replaced WFSAreaHdr by AreaInfo. + Revised directory permission (change -> add). + + Revision 1.9 2008/04/11 06:16:33 ueno + Defined WFSAclFileHandle. + Cleaned up headers. + + Revision 1.8 2008/04/07 09:17:44 ueno + Modified WFSKrnAccessListDirectoryInit() to return an integer. + + Revision 1.7 2008/04/03 09:59:41 ueno + Cleanup. + + Revision 1.6 2008/03/14 08:02:49 ueno + Revised API prefixes (WFS -> WFSKrn). + + Revision 1.5 2008/02/29 07:28:45 ueno + Added Windows api wrappers. + + Revision 1.4 2008/02/28 13:11:58 ueno + Revised to keep accesslist cache and indexlist handle in WFSAreaHdr{}. + + Revision 1.3 2008/02/27 13:12:24 ueno + Revised to store a filename of an accesslist in a file (*.name). + + Revision 1.2 2008/02/27 10:05:26 ueno + Revised to use WFSAreaHdr{} to specifiy WFS area. + + Revision 1.1 2008/02/22 05:15:56 ueno + Initial Check-in. + + +*---------------------------------------------------------------------------*/ +#ifndef __WFSKRN_PERMISSION_IOP_H__ +#define __WFSKRN_PERMISSION_IOP_H__ + +#include +#include "wfssrv_Defs.h" +#include "wfskrn_Area.h" +#include "wfskrn_Permission_Type.h" + +#define INDEXLIST_FILENAME "index" +#define ACL_NAMEFILE_LEN 14 // including '\0'. + +#define AclBlock(x) (((x)->ah.aclHdr.aclBlock)) +#define NameBlock(x) (((x)->ah.aclHdr.nameBlock)) + +#define ACL_FILEINFO_NAME(aclFileInfo) ((aclFileInfo)->di.name.sStr) + +int CreateNamefile(const AreaInfo* area, WFSKrnAclHandle handle, const AclNameFileHeader* header, const utf8* filename); +int DeleteNamefile(const AreaInfo* area, u32 index); +int ReadNamefile(const AreaInfo* area, WFSKrnAclHandle handle, void* buf, WFSFileSize size, WFSFileSize offset); +int WriteNamefile(const AreaInfo* area, WFSKrnAclHandle handle, const void* buf, WFSFileSize size, WFSFileSize offset); + +int WFSKrnAccessListDirectoryInit(AreaInfo* area); + +int WFSKrnAccessListGetAclFileInfo(const AreaInfo* area, const utf8* filename, u32 type, AclFileInfo* fileInfo); + +int GetAccessListPath(const AreaInfo* area, AclFileInfo* aclFile); + +// +// Wrapper +// + +WFSResult AclGetFileSize(const AreaInfo* area, WFSAclFileHandle fh, WFSFileSize* fileSize); +WFSResult AclWriteFile(const AreaInfo* area, WFSAclFileHandle fh, const void *pFileData, WFSFileSize nSize, WFSFileSize offset); +s32 AclReadFile(const AreaInfo* area, WFSAclFileHandle fh, void *pFileDataBuffer, s32 nSize, WFSFileSize offset); + +WFSResult AclCreateFile(const AreaInfo* area, const AclFileInfo* fileInfo, WFSBool create, WFSAclFileHandle *pFh); +WFSResult AclCloseFile(WFSAclFileHandle fh); + +WFSResult AclDeleteAccessListFile(const AreaInfo* area, const AclFileInfo* aclFile); +WFSResult AclCreateAccessListFile(const AreaInfo* area, const AclFileInfo* aclFile, WFSBool create, WFSAclFileHandle *pFh); +WFSBool AclAccessListAlreadyExist(const AreaInfo* area, const AclFileInfo* aclFile); + +#endif // __WFSKRN_PERMISSION_IOP_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_Private.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_Private.h new file mode 100644 index 0000000..1909042 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_Private.h @@ -0,0 +1,133 @@ +/*---------------------------------------------------------------------------* + Project: wfskrn + File: wfs_Permission_Private.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission_Private.h,v $ + Revision 1.8 2008/06/05 14:04:11 ueno + Modified to reserve accesslist index 0 as the default (empty) accesslist. + + Revision 1.7 2008/06/05 08:09:18 ueno + Revised permission APIs. + + Revision 1.6 2008/05/28 01:06:52 ueno + Added AclCheckDisk() to check acl meta-data. + + Revision 1.5 2008/05/23 06:31:52 ueno + Cleanup. + + Revision 1.4 2008/05/22 06:36:01 ueno + Ported permission APIs to IOP. + + Revision 1.3 2008/04/29 01:12:54 ueno + Defined WFS_ROOT_ID and WFS_EVERYONE_ID. + + Revision 1.2 2008/04/25 01:22:46 ueno + Moved from RVL_SDK to RM_SDK. + + Revision 1.11 2008/04/23 08:59:55 ueno + Replaced WFSAreaHdr by AreaInfo. + Revised directory permission (change -> add). + + Revision 1.10 2008/04/14 03:02:16 ueno + Modified WFSKrnCreateRootAccessList() to create an accesslist only for the root. + Added WFSKrnDebugCreateAccessList() for tests. + + Revision 1.9 2008/04/11 06:16:33 ueno + Defined WFSAclFileHandle. + Cleaned up headers. + + Revision 1.8 2008/04/11 04:54:06 ueno + Added WFSKRN_ACL_USE_MUTEX to switch mutex. + + Revision 1.7 2008/04/09 03:01:27 ueno + Cleanup. + + Revision 1.6 2008/04/08 06:39:41 ueno + Cleanup. + + Revision 1.5 2008/04/01 08:25:10 ueno + Fixed cache reference count. + + Revision 1.4 2008/03/18 13:42:39 ueno + Added a debug function. + + Revision 1.3 2008/03/14 08:02:49 ueno + Revised API prefixes (WFS -> WFSKrn). + + Revision 1.2 2008/03/07 05:31:07 ueno + Modified WFSCreateAccessList() to be able to create an accesslist for directories. + + Revision 1.1 2008/03/06 10:47:12 ueno + New. + + +*---------------------------------------------------------------------------*/ +#ifndef __WFSKRN_PERMISSION_PRIVATE_H__ +#define __WFSKRN_PERMISSION_PRIVATE_H__ + +#include +#include "wfssrv_Defs.h" +#include "wfskrn_Area.h" + +// private APIs +#ifdef WFSDEV +int AclUtf8ToWchar(const utf8* utf8, LPWSTR wchar, u32 bytes); +int AclWcharToUtf8(const LPWSTR wchar, utf8* utf8, u32 bytes); +#endif // WFSDEV + +void WFSKrnAccessListSetNum(WFSKrnAccessList* list, u32 num); +u32 WFSKrnAccessListGetNum(const WFSKrnAccessList* list); + +WFSKrnResult WFSKrnAccessListAlloc(const AreaInfo* area, u32 numEntries, WFSKrnAccessList** list); +int WFSKrnAccessListFree(const AreaInfo* area, WFSKrnAccessList* list); + +int WFSKrnAllocAccessListIndex(const AreaInfo* area, u32 indexFlags, u32* newIndex, u32 num); +int WFSKrnFreeAccessListIndex(const AreaInfo* area, u32 index); + +void WFSKrnAccessListCacheAdd(const AreaInfo* area, WFSKrnAccessList* list); +void WFSKrnAccessListCacheRemove(const AreaInfo* area, WFSKrnAccessList* list); +void WFSKrnAccessListCacheFreeListRemove(const AreaInfo* area, WFSKrnAccessList* list); +WFSKrnAccessList* WFSKrnAccessListLookup(const AreaInfo* area, u32 index); +WFSKrnAccessList* WFSKrnAccessListLookupByIndex(const AreaInfo* area, u32 index); + +// debug functions. +WFSBool VerifyMemoryBlock(const AreaInfo* area); +void PrintMemoryBlock(const AreaInfo* area); +void WFSKrnDebugPrintAccessList(const AreaInfo* area, u32 index); +s32 AclDirList(const AreaInfo* area, WFSBlkAdr block); +WFSKrnResult AclCheckDisk(const AreaInfo* area); + +//-------------------------------------------------------------------------------------------------------------- +// WFSKrnDebugCreateAccessList +//-------------------------------------------------------------------------------------------------------------- +// Arguments: +// ---------- +// area .. [in] A WFS area. +// aclType .. [in] ACL_FLAG_DIRECTORY (directory) or 0 (file). +// titleId .. [in] The first title in the accesslist to be created. +// nFlags .. [in] permissions and control levels (WFS_PERM_*) +// newHandle .. [out] Pointer to the new accesslist handle. +// +// Return Values: +// -------------- +// WFSKRN_RESULT_OK .. success +// WFSKRN_RESULT_INVALID +// WFSKRN_RESULT_ACL_ERROR +// WFSKRN_RESULT_ACL_MAX_ENTRIES +// WFSKRN_RESULT_ACL_FILE +// +// Description: +// ------------ +// This function creates an accesslist. +WFSKrnResult WFSKrnDebugCreateAccessList(const AreaInfo* area, u32 aclType, + WFSTitleId entryCreatorId, WFSTitleId titleId, u32 nFlags, WFSKrnAclHandle* newHandle); + +#endif // __WFSKRN_PERMISSION_PRIVATE_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_Type.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_Type.h new file mode 100644 index 0000000..26c5015 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_Type.h @@ -0,0 +1,137 @@ +/*---------------------------------------------------------------------------* + Project: wfskrn + File: wfs_Permission_Type.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission_Type.h,v $ + Revision 1.12 2008/07/23 04:18:07 ueno + Reduced memory size required for accesslist. + + Revision 1.11 2008/07/23 02:01:51 ueno + Modified to use mutex on Windows. + + Revision 1.10 2008/05/30 08:50:35 ueno + Disabled mutex for IOP. + + Revision 1.9 2008/05/23 06:31:52 ueno + Cleanup. + + Revision 1.8 2008/05/22 06:36:01 ueno + Ported permission APIs to IOP. + + Revision 1.7 2008/05/19 10:12:05 ueno + Revised not to use hardlink. + + Revision 1.6 2008/05/19 05:31:53 ueno + Defined accesslist meta-data types. + + Revision 1.5 2008/05/16 11:16:58 ueno + Implemented permission APIs with directory module. + + Revision 1.4 2008/05/15 13:33:46 ueno + Implemented initialization using directory module. + + Revision 1.3 2008/05/06 02:27:21 ueno + Fixed ifdef. + + Revision 1.2 2008/04/29 06:25:14 ueno + Cleanup. + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.1 2008/04/11 06:16:33 ueno + Defined WFSAclFileHandle. + Cleaned up headers. + + + +*---------------------------------------------------------------------------*/ +#ifndef __WFSKRN_PERMISSION_TYPE_H__ +#define __WFSKRN_PERMISSION_TYPE_H__ + +#include +#include "wfskrn_Dir.h" +#include "wfskrn_Handles.h" +#include "wfskrn_DirFind.h" +#include "wfskrn_DirNodeStack.h" + +// access list handle +typedef u32 WFSKrnAclHandle; + +#if _WIN32 +// The maximum path length of an emulation directory is WFSKRN_MAX_PATH_NAME_SIZE. +#define WFSKRN_ACCESSLIST_MAX_PATH_LEN ((WFS_MAX_PATH_NAME_SIZE+1)*2) +#else +#define WFSKRN_ACCESSLIST_MAX_PATH_LEN (WFS_MAX_PATH_NAME_SIZE+1) +#endif // _WIN32 + +// type of metadata. +#define ACL_TYPE_INDEXLIST 1 +#define ACL_TYPE_NAMEFILE 2 +#define ACL_TYPE_ACLFILE 3 + +typedef struct AclFileInfo +{ + u32 type; // ACL_TYPE_* +#ifdef WFSDEV + utf8 path[WFSKRN_ACCESSLIST_MAX_PATH_LEN]; +#else + DirItr di; +#endif // WIN32 +} AclFileInfo; + +typedef struct AclNameFileHeader +{ + u32 num; // The number of titles in this list. + u32 ref; // The number of files and directories associated with this accesslist. +} AclNameFileHeader; + +// file handle +#ifdef WFSDEV +typedef HANDLE WFSAclFileHandle; +#else // WFSDEV +typedef AclFileInfo* WFSAclFileHandle; +#endif // WFSDEV + +// mutex +// #define WFSKRN_ACL_USE_MUTEX // [check] how to use mutex on IOP? + +#ifdef WFSKRN_ACL_USE_MUTEX +#include "wfskrn_Mutex.h" +#define WFSAclInitMutex(x) WFSKrnInitMutex(x) +#define WFSAclLockMutex(x) WFSKrnLockMutex(x) +#define WFSAclUnlockMutex(x) WFSKrnUnlockMutex(x) +#else +#define WFSAclInitMutex(x) +#define WFSAclLockMutex(x) +#define WFSAclUnlockMutex(x) +#endif + +// print message +#define WFSKRN_ACL_DEBUG + +#ifdef WFSKRN_ACL_DEBUG + +#ifdef WIN32 +#define WFSKRN_ACL_ASSERT(x) assert(x) +#else // Win32 +#define WFSKRN_ACL_ASSERT(x) ASSERT(x) +#endif // WIN32 +#define WFSKRN_ACL_REPORT printf + +#else // WFSKRN_ACL_DEBUG + +#define WFSKRN_ACL_ASSERT(x) +#define WFSKRN_ACL_REPORT + +#endif // WFSKRN_ACL_DEBUG + +#endif // __WFSKRN_PERMISSION_TYPE_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_Win32.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_Win32.h new file mode 100644 index 0000000..853e051 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Permission_Win32.h @@ -0,0 +1,127 @@ +/*---------------------------------------------------------------------------* + Project: wfsKrn + File: wfs_Permission_Win32.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission_Win32.h,v $ + Revision 1.13 2008/09/24 07:32:07 ueno + Added AclHdr{} to AreaHdr{} to save configuration of accesslists in a disk. + + Revision 1.12 2008/05/19 10:12:05 ueno + Revised not to use hardlink. + + Revision 1.11 2008/05/19 05:31:53 ueno + Defined accesslist meta-data types. + + Revision 1.10 2008/05/15 13:33:46 ueno + Implemented initialization using directory module. + + Revision 1.9 2008/05/08 08:08:02 ueno + Revised AclReadFile() and AclWriteFile() to set offset. + + Revision 1.8 2008/05/06 03:16:07 ueno + Added AclGetFileSize() to wrap Windows API.. + + Revision 1.7 2008/05/06 02:27:21 ueno + Fixed ifdef. + + Revision 1.6 2008/04/29 06:25:14 ueno + Cleanup. + + Revision 1.5 2008/04/29 01:12:54 ueno + Defined WFS_ROOT_ID and WFS_EVERYONE_ID. + + Revision 1.4 2008/04/25 06:22:55 ueno + Cleanup. + + Revision 1.3 2008/04/25 04:40:47 ueno + Added support for WFSDEV. + + Revision 1.10 2008/04/23 08:59:55 ueno + Replaced WFSAreaHdr by AreaInfo. + Revised directory permission (change -> add). + + Revision 1.9 2008/04/11 06:16:33 ueno + Defined WFSAclFileHandle. + Cleaned up headers. + + Revision 1.8 2008/04/07 09:17:44 ueno + Modified WFSKrnAccessListDirectoryInit() to return an integer. + + Revision 1.7 2008/04/03 09:59:41 ueno + Cleanup. + + Revision 1.6 2008/03/14 08:02:49 ueno + Revised API prefixes (WFS -> WFSKrn). + + Revision 1.5 2008/02/29 07:28:45 ueno + Added Windows api wrappers. + + Revision 1.4 2008/02/28 13:11:58 ueno + Revised to keep accesslist cache and indexlist handle in WFSAreaHdr{}. + + Revision 1.3 2008/02/27 13:12:24 ueno + Revised to store a filename of an accesslist in a file (*.name). + + Revision 1.2 2008/02/27 10:05:26 ueno + Revised to use WFSAreaHdr{} to specifiy WFS area. + + Revision 1.1 2008/02/22 05:15:56 ueno + Initial Check-in. + + +*---------------------------------------------------------------------------*/ +#ifndef __WFSKRN_PERMISSION_WIN32_H__ +#define __WFSKRN_PERMISSION_WIN32_H__ + +#include +#include "wfs_Client.h" +#include "wfskrn_Area.h" +#include "wfskrn_Permission_Type.h" + +#define LONGPATH_PREFIX L"\\\\?\\" +#define ACCESSLIST_DIR ".WFSAccessLists" +#define ACCESSLIST_DIR_WCHAR L".WFSAccessLists" +#define INDEXLIST_FILENAME ".wfsaccesslist_indexlist" +#define NAMEFILE_DIR "name" +#define NAMEFILE_DIR_WCHAR L"name" + +WFSBool AlreadyExist(const LPWSTR path); +int Utf8ToWcharAccessList(const AreaInfo* area, const utf8* path, LPWSTR wPath, u32 wPathLen); +int EscapeAccessListToWideChar(const char* encoded, LPWSTR wPath, u32 size); +int UnescapeAccessListFromWideChar(const LPWSTR wPath, utf8* encoded, u32 size); + +int CreateNamefile(const AreaInfo* area, WFSKrnAclHandle handle, const AclNameFileHeader* header, const utf8* filename); +int DeleteNamefile(const AreaInfo* area, u32 index); +int ReadNamefile(const AreaInfo* area, WFSKrnAclHandle handle, void* buf, WFSFileSize size, WFSFileSize offset); +int WriteNamefile(const AreaInfo* area, WFSKrnAclHandle handle, const void* buf, WFSFileSize size, WFSFileSize offset); + +int WFSKrnAccessListDirectoryInit(AreaInfo* area); + +int WFSKrnAccessListGetAclFileInfo(const AreaInfo* area, const utf8* filename, u32 type, AclFileInfo* fileInfo); + +int GetAccessListPath(const AreaInfo* area, AclFileInfo* aclFile); + +// +// Wrapper +// + +WFSResult AclGetFileSize(const AreaInfo* area, WFSAclFileHandle fh, WFSFileSize* fileSize); +WFSResult AclWriteFile(const AreaInfo* area, WFSAclFileHandle fh, const void *pFileData, WFSFileSize nSize, WFSFileSize offset); +s32 AclReadFile(const AreaInfo* area, WFSAclFileHandle fh, void *pFileDataBuffer, s32 nSize, WFSFileSize offset); + +WFSResult AclCreateFile(const AreaInfo* area, const AclFileInfo* fileInfo, WFSBool create, WFSAclFileHandle *pFh); +WFSResult AclCloseFile(WFSAclFileHandle fh); + +WFSResult AclDeleteAccessListFile(const AreaInfo* area, const AclFileInfo* aclFile); +WFSResult AclCreateAccessListFile(const AreaInfo* area, const AclFileInfo* aclFile, WFSBool create, WFSAclFileHandle *pFh); +WFSBool AclAccessListAlreadyExist(const AreaInfo* area, const AclFileInfo* aclFile); + +#endif // __WFSKRN_PERMISSION_WIN32_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Platform.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Platform.h new file mode 100644 index 0000000..573c1f1 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Platform.h @@ -0,0 +1,176 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Platform.h - low level definitions and types that are primarily platform dependent + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Platform.h,v $ + Revision 1.6 2008/08/27 04:05:21 nakanose_jin + change ospanic definision + + Revision 1.5 2008/07/14 01:01:11 kondo_masahiro + Removed _STRICMP + + Revision 1.4 2008/06/26 05:37:33 kondo_masahiro + Added function _STRICMP(). + + Revision 1.3 2008/05/10 04:00:48 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.2 2008/04/25 17:26:30 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.4 2008/04/26 05:36:11 paul + Added _ATTRIBUTE_PACKED + + Revision 1.3 2008/04/19 05:47:36 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.2 2008/02/28 06:32:17 kondo_masahiro + Fixed code to accept PPC compiler + + Revision 1.1 2007/11/05 19:03:13 paul + first checkin + +*---------------------------------------------------------------------------*/ + +#ifndef wfskrn_Platform_h +#define wfskrn_Platform_h + +#include + +//--twl modified +#define TWL 1 +#if 1 + #define _OSX 0 + #define _WIN32 0 + #define _TWL 1 + #define _RVL 0 + #define _IOP 0 +#else +//--twl modified +#ifdef OSX + #define _OSX 1 + #define _WIN32 0 + #define _RVL 0 + #define _IOP 0 +#else + #ifdef WIN32 + #define _OSX 0 + #define _WIN32 1 + #define _RVL 0 + #define _IOP 0 + #else + #ifdef IOP + #define _OSX 0 + #define _WIN32 0 + #define _RVL 0 + #define _IOP 1 + #elif RVL + #define _OSX 0 + #define _WIN32 0 + #define _RVL 1 + #define _IOP 0 + #endif + #endif +#endif +#endif //twl modified + +// Although the cache line size depends on the platform, it is fixed to +// the IOP cache line size, since the goal is not to optimize for different +// platforms, but rather to use other platforms as a development aid. +#define WFS_CPU_CACHE_LINE_SIZE (1<<5) + +#if _WIN32 + #pragma warning (3: 4101) + #pragma warning (3: 4189) + #pragma warning(disable:4996) + #define _ATTRIBUTE_PACKED + #define BYTES_PER_INT 4 + #define BITS_PER_INT 32 + #define BIT_OFFSET_MASK 31 + #define BIT_OFFSET_TO_INT_OFFSET_SHIFT 5 + #define MAX max + #define MIN min + //#define OSReport printf + #include "WinOSReport.h" + #define OSPanic MyOSPanic + #define SNPRINTF _snprintf + #define STRNLEN( str, maxlen ) strlen(str) + #define _ATTRIBUTE_PACKED +#elif _OSX + #define BYTES_PER_INT 4 + #define BITS_PER_INT 32 + #define BIT_OFFSET_MASK 31 + #define BIT_OFFSET_TO_INT_OFFSET_SHIFT 5 + //#define OSReport printf + #include "WinOSReport.h" + #define OSPanic MyOSReport + #define SNPRINTF snprintf + #define STRNLEN( str, maxlen ) strlen(str) + #define _ATTRIBUTE_PACKED +//-- twl modified +#elif _TWL + #define BYTES_PER_INT 4 + #define BITS_PER_INT 32 + #define BIT_OFFSET_MASK 31 + #define BIT_OFFSET_TO_INT_OFFSET_SHIFT 5 + #define MAX(a,b) (((a)>(b))?(a):(b)) + #define MIN(a,b) (((a)<(b))?(a):(b)) + #define MyOSReport osTPrintf + #define InitMyOSReport() + #define SNPRINTF OS_SNPrintf + #define STRNLEN( str, maxlen ) stdStrNLen(str, maxlen) + #define _ATTRIBUTE_PACKED +//-- twl modified +#elif _RVL + #pragma warn_unusedarg off + #pragma warn_implicitconv off + #pragma warn_possunwant off + #include + #define BYTES_PER_INT 4 + #define BITS_PER_INT 32 + #define BIT_OFFSET_MASK 31 + #define BIT_OFFSET_TO_INT_OFFSET_SHIFT 5 + #define MAX(a,b) (((a)>(b))?(a):(b)) + #define MIN(a,b) (((a)<(b))?(a):(b)) + #define MyOSReport OSReport + #define InitMyOSReport() + #define SNPRINTF snprintf + #define STRNLEN( str, maxlen ) strlen(str) + #define _ATTRIBUTE_PACKED +#elif _IOP + #define BYTES_PER_INT 4 + #define BITS_PER_INT 32 + #define BIT_OFFSET_MASK 31 + #define BIT_OFFSET_TO_INT_OFFSET_SHIFT 5 + #define MAX(a,b) (((a)>(b))?(a):(b)) + #define MIN(a,b) (((a)<(b))?(a):(b)) + #define MyOSReport printf + #define InitMyOSReport() + #define SNPRINTF snprintf + #define STRNLEN( str, maxlen ) strnlen( str, maxlen ) + #define _ATTRIBUTE_PACKED __attribute__((packed)) +#endif // WIN32 + +#ifndef BIG_ENDIAN + #ifdef WIN32 + #define BIG_ENDIAN 0 + #elif TWL + #define BIG_ENDIAN 0 + #else + #define BIG_ENDIAN 1 + #endif // WIN32 +#endif // BIG_ENDIAN + + +#endif //define wfskrn_Platform_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_SubBlkAlloc.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_SubBlkAlloc.h new file mode 100644 index 0000000..72cc01d --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_SubBlkAlloc.h @@ -0,0 +1,96 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_SubBlkAlloc.h - Memory Managed Blocks, and functions for allocating sub blocks from them + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_SubBlkAlloc.h,v $ + Revision 1.6 2008/09/28 23:30:46 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.5 2008/08/27 10:01:32 paul + Removed nTotalFree from block header + + Revision 1.4 2008/07/14 23:03:11 paul + Changed nOfs to use u16 + + Revision 1.3 2008/06/09 18:11:14 paul + Changed SbaBlkInit() to support blocks with different header sizes + + Revision 1.2 2008/04/25 17:26:24 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.3 2008/04/19 05:47:18 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.2 2008/04/05 03:23:05 paul + Added extra check functions + + Revision 1.1 2008/02/21 00:06:19 paul + *** empty log message *** + +*---------------------------------------------------------------------------*/ + +#ifndef wfskrn_SubBlkAlloc_h +#define wfskrn_SubBlkAlloc_h + + +#include "wfskrn_Defs.h" +#include "wfskrn_Area.h" + +#ifdef _DEBUG + #define _DEBUG_SUB_BLK_ALLOC 0 // change to 1 if debug info required +#else + #define _DEBUG_SUB_BLK_ALLOC 0 +#endif + +#define SBA_MIN_LOG2_SUB_BLK_SIZE 3 +#define SBA_MAX_LOG2_SUB_BLK_SIZE 11 +#define SBA_MAX_LOG2_SUB_BLK_SIZE_FOR_MIDDLE 10 +#define SBA_NUM_SUB_BLK_SIZES (SBA_MAX_LOG2_SUB_BLK_SIZE - SBA_MIN_LOG2_SUB_BLK_SIZE + 1) + +//#define SBA_FREE_SUB_BLK_MAGIC 0xFEDCBAF8 +#define SBA_FREE_SUB_BLK_MAGIC 0xFEDC // NOTE: This magic number is used to mark free sub blocks. It must not represent valid data for any in-use sub blocks using this allocator. + +typedef struct { + WFSIntraBlkOfs nNumFree; + WFSIntraBlkOfs nFirstFree; +} WFSSubBlkList; + +typedef struct { + WFSMetaDataHdr mdh; + WFSSubBlkList aSubBlkList[SBA_NUM_SUB_BLK_SIZES]; +#if _DEBUG_SUB_BLK_ALLOC + WFSIntraBlkOfs nTotalFree; + u16 pad; +#endif +} WFSSubBlkAllocHdr; + +typedef struct { + u16 nMagic; + u16 nNext; + u16 nPrev; + u16 nLog2Size; +} WFSSubBlkFreeHdr; + +void SbaCheckOfs(u16 nOfs); +void SbaRemoveSubBlkFromFreeList(WFSSubBlkAllocHdr *pBlkHdr, u16 nOfs, u32 nLog2Size); +u16 SbaAllocSubBlk(WFSSubBlkAllocHdr *pBlkHdr, u32 nLog2Size); +WFSKrnResult SbaAllocSubBlks(WFSSubBlkAllocHdr *pBlkHdr, u32 nLog2Size, u16 aSubBlkOfs[], u32 nNumSubBlks); +void SbaFreeSubBlk(WFSSubBlkAllocHdr *pBlkHdr, u16 nOfs, u32 nLog2Size); +void SbaReduceSubBlkSize(WFSSubBlkAllocHdr *pBlkHdr, u16 nOfs, u32 nOldLog2Size, u32 nNewLog2Size); +WFSSubBlkAllocHdr *SbaBlkInit(void *pBlk, u32 nLog2BlkSize, u32 nLog2HdrSize); +u32 SbaCountFreeSpace(WFSSubBlkAllocHdr *pBlkHdr); +u32 SbaCheckFreeSpace(WFSSubBlkAllocHdr *pBlkHdr, u32 *aUtilization); + + +#endif //wfskrn_SubBlkAlloc_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Trans.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Trans.h new file mode 100644 index 0000000..b65223f --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Trans.h @@ -0,0 +1,197 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Trans.h - Provides access to blocks for transactions including re-mapping functionality + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Trans.h,v $ + Revision 1.17 2008/12/18 09:03:37 kondo_masahiro + Fixed function name and process from BCacheSetBlkAdr() to BCacheRemap() + + Revision 1.16 2008/12/17 01:37:41 kondo_masahiro + Added function BCacheSetBlkAdr() + + Revision 1.15 2008/11/26 01:44:35 kondo_masahiro + Fixed arguments of several functions in order to improve access speed. + + Revision 1.14 2008/11/05 15:03:40 ueno + Fixed a typo. + + Revision 1.13 2008/11/05 05:55:23 kondo_masahiro + Added TransSetChainId() + + Revision 1.12 2008/10/21 09:50:09 kondo_masahiro + Added new function WFSWriteFileAndDiscard + + Revision 1.11 2008/10/17 08:51:27 kondo_masahiro + Added the new MEDIUM size category (40KB-320KB) + + Revision 1.10 2008/10/14 10:27:44 kondo_masahiro + Added codes to access very large size file data + + Revision 1.9 2008/10/10 02:11:31 kondo_masahiro + Fixed a bug to access large files + + Revision 1.8 2008/10/08 23:20:09 kondo_masahiro + Added codes to access large size file data + + Revision 1.7 2008/10/03 08:37:18 kondo_masahiro + Fixed codes for porting IOP + + Revision 1.6 2008/09/28 23:30:51 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.5 2008/08/27 09:50:04 paul + Started coding to differentiate File/Meta-data blocks + + Revision 1.4 2008/08/06 05:28:46 kondo_masahiro + Added debug flags for hash and detach test. + + Revision 1.3 2008/07/25 02:57:22 paul + Added TransInfo, TansBegin(), TransEnd() + + Revision 1.2 2008/07/17 05:14:51 kondo_masahiro + Fixed codes for porting IOP. + + Revision 1.1 2008/07/09 01:48:14 paul + First checkin of transaction API. Currently has no re-mapping. + +*---------------------------------------------------------------------------*/ + +#ifndef wfs_Trans_h +#define wfs_Trans_h + +#include "wfskrn_Area.h" + + +#define TRANS_FLAG_READ_BLK BCACHE_FLAG_READ // Use this flag unless you are ignoring/overwriting any existing data in the blcok +#define TRANS_FLAG_WRITE_BLK BCACHE_FLAG_DIRTY // Use this flag if you intend to write to the block +#define TRANS_FLAG_RW_BLK (BCACHE_FLAG_READ | BCACHE_FLAG_DIRTY) // Use this flag unless you are ignoring/overwriting any existing data in the blcok + +typedef struct { + struct TransInfo_ *pNext; + struct TransInfo_ *pPrev; +} TransInfoLink; + +typedef struct TransInfo_ { + TransInfoLink link; + WFSTitleId nTitleId; +} TransInfo; + +typedef struct { + AreaInfo *pAreaInfo; // Area info + WFSBlkAdr nBlkAdr; // Block address + TransInfo *pTransInfo; // Transaction info +} TransBlkAdr; + + +void TransModuleInit(); + +TransInfo *TransBegin(); +void TransEnd(TransInfo *pTransInfo); + +WFSKrnResult TransGetBlk5(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo, u32 nFlags, void **ppBlkPtr); +static inline WFSKrnResult TransGetBlk(TransBlkAdr *pTba, u32 nFlags, void **ppBlkPtr) { + return TransGetBlk5(pTba->pAreaInfo, pTba->nBlkAdr, pTba->pTransInfo, nFlags, ppBlkPtr); +} + +WFSKrnResult TransGetAndPinBlk5(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo, u32 nFlags, void **ppBlkPtr); +static inline WFSKrnResult TransGetAndPinBlk(TransBlkAdr *pTba, u32 nFlags, void **ppBlkPtr) { + return TransGetAndPinBlk5(pTba->pAreaInfo, pTba->nBlkAdr, pTba->pTransInfo, nFlags, ppBlkPtr); +} + +WFSKrnResult TransSetChainId4(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo, u32 nChainId); +static inline WFSKrnResult TransSetChainId(TransBlkAdr *pTba, u32 nChainId) { + return TransSetChainId4(pTba->pAreaInfo, pTba->nBlkAdr, pTba->pTransInfo, nChainId); +} + +WFSKrnResult TransGetChainId4(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo, u32 *pChainId); +static inline WFSKrnResult TransGetChainId(TransBlkAdr *pTba, u32 *pChainId) { + return TransGetChainId4(pTba->pAreaInfo, pTba->nBlkAdr, pTba->pTransInfo, pChainId); +} + +WFSKrnResult TransUnpinBlk3(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo); +static inline WFSKrnResult TransUnpinBlk(TransBlkAdr *pTba) { + return TransUnpinBlk3(pTba->pAreaInfo, pTba->nBlkAdr, pTba->pTransInfo); +} + +WFSKrnResult TransDirtyBlk3(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo); +static inline WFSKrnResult TransDirtyBlk(TransBlkAdr *pTba) { + return TransDirtyBlk3(pTba->pAreaInfo, pTba->nBlkAdr, pTba->pTransInfo); +} + +WFSKrnResult TransFreeBlks6(AreaInfo *pAreaInfo, u32 nLog2BlkSize, u32 nNumBlks, WFSBlkAdr *pBlkAdr, s32 nStride, TransInfo *pTransInfo); +static inline WFSKrnResult TransFreeBlks5(AreaInfo *pAreaInfo, u32 nLog2BlkSize, u32 nNumBlks, WFSBlkAdr aBlkAdr[], TransInfo *pTransInfo) { + return TransFreeBlks6(pAreaInfo, nLog2BlkSize, nNumBlks, aBlkAdr, sizeof(WFSBlkAdr), pTransInfo); +} + +WFSKrnResult TransUnpinAndFreeBlks(AreaInfo *pAreaInfo, u32 nLog2BlkSize, u32 nNumBlks, WFSBlkAdr aBlkAdr[], TransInfo *pTransInfo); + +WFSKrnResult TransStoreBlk3(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo); +static inline WFSKrnResult TransStoreBlk(TransBlkAdr *pTba) { + return TransStoreBlk3(pTba->pAreaInfo, pTba->nBlkAdr, pTba->pTransInfo); +} + +WFSKrnResult TransFlushBlk3(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo); +static inline WFSKrnResult TransFlushBlk(TransBlkAdr *pTba) { + return TransFlushBlk3(pTba->pAreaInfo, pTba->nBlkAdr, pTba->pTransInfo); +} + +WFSKrnResult TransGetFileBlk6(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo, u32 nFlags, void **ppBlkPtr, WFSHashCode *pHash); +static inline WFSKrnResult TransGetFileBlk(TransBlkAdr *pTba, u32 nFlags, void **ppBlkPtr, WFSHashCode *pHash) { + return TransGetFileBlk6(pTba->pAreaInfo, pTba->nBlkAdr, pTba->pTransInfo, nFlags, ppBlkPtr, pHash); +} + + +WFSKrnResult TransGetAndPinFileBlk8(AreaInfo *pAreaInfo, WFSBlkAdr nParentBlkAdr, u16 nHashOfs, + WFSBlkAdr nFileBlkAdr, TransInfo *pTransInfo, u32 nFlags, u32 nValidSize, u32 nBCacheGroupId, void **ppBlkPtr); +static inline WFSKrnResult TransGetAndPinFileBlk(TransBlkAdr *pTba, WFSBlkAdr nParentBlkAdr, u16 nHashOfs, WFSBlkAdr nFileBlkAdr, u32 nFlags, u32 nValidSize, void **ppBlkPtr) { + return TransGetAndPinFileBlk8(pTba->pAreaInfo, nParentBlkAdr, nHashOfs, nFileBlkAdr, pTba->pTransInfo, nFlags, nValidSize, BCACHE_GROUP_ID_USERBLK_8K, ppBlkPtr); +} + +static inline WFSKrnResult TransGetAndPinFileMediumBlk(TransBlkAdr *pTba, WFSBlkAdr nParentBlkAdr, u16 nHashOfs, WFSBlkAdr nFileBlkAdr, u32 nFlags, u32 nValidSize, void **ppBlkPtr) { + return TransGetAndPinFileBlk8(pTba->pAreaInfo, nParentBlkAdr, nHashOfs, nFileBlkAdr, pTba->pTransInfo, nFlags, nValidSize, BCACHE_GROUP_ID_USERBLK_64K, ppBlkPtr); +} + +WFSKrnResult TransUnpinFileBlk3(AreaInfo *pAreaInfo, WFSBlkAdr nFileBlkAdr, TransInfo *pTransInfo); +static inline WFSKrnResult TransUnpinFileBlk(TransBlkAdr *pTba, WFSBlkAdr nFileBlkAdr) { + return TransUnpinFileBlk3(pTba->pAreaInfo, nFileBlkAdr, pTba->pTransInfo); +} + +WFSKrnResult TransInvalidate3(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo); + +WFSKrnResult TransSetValidSize4(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo, u32 nValidSize); + +WFSKrnResult TransRemapCache6(AreaInfo *pAreaInfo, WFSBlkAdr nSrcBlkAdr, TransInfo *pTransInfo, WFSBlkAdr nDstBlkAdr, WFSBlkAdr nHashBlkAdr, u32 nHashOfs); + +WFSKrnResult TransReadFileBlks7(u8 *pAlignedPtr, AreaInfo *pAreaInfo, u32 nLog2BlkSize, u32 nSize, WFSFileBlkPtr *pFileBlkPtr, s32 nStride, TransInfo *pTransInfo); +static inline WFSKrnResult TransReadFileBlks(u8 *pAlignedPtr, AreaInfo *pAreaInfo, u32 nSize, WFSFileBlkPtr *pFileBlkPtr, s32 nStride, TransInfo *pTransInfo){ + return TransReadFileBlks7(pAlignedPtr, pAreaInfo, pAreaInfo->ah.nLog2BlkSize, nSize, pFileBlkPtr, nStride, pTransInfo); +} +static inline WFSKrnResult TransReadFileMediumBlks(u8 *pAlignedPtr, AreaInfo *pAreaInfo, u32 nSize, WFSFileBlkPtr *pFileBlkPtr, s32 nStride, TransInfo *pTransInfo){ + return TransReadFileBlks7(pAlignedPtr, pAreaInfo, pAreaInfo->ah.nLog2MediumBlkSize, nSize, pFileBlkPtr, nStride, pTransInfo); +} + +WFSKrnResult TransWriteFileBlks7(u8 *pAlignedPtr, AreaInfo *pAreaInfo, u32 nLog2BlkSize, u32 nSize, WFSFileBlkPtr *pFileBlkPtr, s32 nStride, TransInfo *pTransInfo, bool bDecryption); +static inline WFSKrnResult TransWriteFileBlks(u8 *pAlignedPtr, AreaInfo *pAreaInfo, u32 nSize, WFSFileBlkPtr *pFileBlkPtr, s32 nStride, TransInfo *pTransInfo, bool bDecryption){ + return TransWriteFileBlks7(pAlignedPtr, pAreaInfo, pAreaInfo->ah.nLog2BlkSize, nSize, pFileBlkPtr, nStride, pTransInfo, bDecryption); +} +static inline WFSKrnResult TransWriteFileMediumBlks(u8 *pAlignedPtr, AreaInfo *pAreaInfo, u32 nSize, WFSFileBlkPtr *pFileBlkPtr, s32 nStride, TransInfo *pTransInfo, bool bDecryption){ + return TransWriteFileBlks7(pAlignedPtr, pAreaInfo, pAreaInfo->ah.nLog2MediumBlkSize, nSize, pFileBlkPtr, nStride, pTransInfo, bDecryption); +} + +WFSKrnResult TransReadFileLargeBlks (u8 *pAlignedPtr, AreaInfo *pAreaInfo, u32 nSize, u32 nOffsetBlks, + WFSFileLargeBlkPtr *pFileLargeBlkPtr, s32 nStride, TransInfo *pTransInfo); +WFSKrnResult TransWriteFileLargeBlks(u8 *pAlignedPtr, AreaInfo *pAreaInfo, u32 nSize, u32 nOffsetBlks, + WFSFileLargeBlkPtr *pFileLargeBlkPtr, s32 nStride, TransInfo *pTransInfo, bool bDecryption); + +WFSKrnResult TransTrancateFileBlk(TransBlkAdr *pTba, WFSBlkAdr nParentBlkAdr, u16 nHashOfs, WFSBlkAdr nFileBlkAdr, u32 nOldSize, u32 nNewSize); +WFSKrnResult TransTrancateFileMediumBlk(TransBlkAdr *pTba, WFSBlkAdr nParentBlkAdr, u16 nHashOfs, WFSBlkAdr nFileBlkAdr, u32 nOldSize, u32 nNewSize); + +#endif //wfs_Trans_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Types.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Types.h new file mode 100644 index 0000000..e954dfb --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Types.h @@ -0,0 +1,165 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Types.h - global types used by the WFS kernel + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Types.h,v $ + Revision 1.12 2008/10/24 09:03:09 kondo_masahiro + Added decrease block process of DirResize. + + Revision 1.11 2008/10/17 08:51:27 kondo_masahiro + Added the new MEDIUM size category (40KB-320KB) + + Revision 1.10 2008/10/10 02:11:31 kondo_masahiro + Fixed a bug to access large files + + Revision 1.9 2008/10/08 23:20:09 kondo_masahiro + Added codes to access large size file data + + Revision 1.8 2008/09/28 23:30:56 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.7 2008/08/06 02:24:17 paul + Added WFSFileBlkPtr and DIR_ENTRY_ATTR* defs + + Revision 1.6 2008/07/28 22:30:56 paul + Moved defs related to update counter here + + Revision 1.5 2008/07/25 08:47:53 ooizumi + Added WFSKrnAccess. + + Revision 1.4 2008/07/17 05:15:08 kondo_masahiro + Fixed codes for porting IOP. + + Revision 1.3 2008/07/09 01:52:00 paul + Updated definitions for meta-data flags. + + Revision 1.2 2008/05/10 04:00:48 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.5 2008/04/26 01:25:56 wayne.wong + Added magic number values. + + Revision 1.4 2008/04/05 22:43:54 paul + Added WFSMetaDataFlags to make wfskrn_Volume.h compile + + Revision 1.3 2008/02/21 00:12:44 paul + Added WFSMetaDataHdr + + Revision 1.2 2007/12/27 11:33:28 paul + added various types + + Revision 1.1 2007/11/05 19:03:13 paul + first checkin + +*---------------------------------------------------------------------------*/ + +#ifndef wfskrn_Types_h +#define wfskrn_Types_h + +#include "wfskrn_Defs.h" + +// Magic numbers for WFS block types. Should be the first u32(4B) of a meta-data block (post decryption) +typedef enum { // Flags to identify persistent block types + WFS_MDF_NULL = 0x00000000, + + WFS_MDF_DIR_BLK = 0x80000000, // Directory Block + WFS_MDF_DIR_ROOT_BLK = 0x40000000, // Always combined with WFS_MDF_DIR_BLK or WFS_MDF_FREE_LIST + WFS_MDF_DIR_LEAF_BLK = 0x20000000, // Always combined with WFS_MDF_DIR_BLK or WFS_MDF_FREE_LIST + + WFS_MDF_INDIRECT_BLK = 0x40000000, // Indirect block. (Block of pointers to user data blocks). + WFS_MDF_FREE_LIST_BLK = 0x20000000, // Free List Management (B-tree) block + WFS_MDF_VOLUME_HDR = 0x10000000, // Master Record. Not combined with anything else + WFS_MDF_AREA_HDR = 0x08000000, // Area Header. Not combined with anything else + + WFS_MDF_MAX = 0xffffffff +} WFSMetaDataFlags; + + +#define WFSKRN_MAX_FILE_HANDLES (1<aCaseBitArray) + (WFS_MAX_FILE_NAME_SIZE>>3)) // 28+31 = 59byte +#define DIR_ENTRY_ATTR_MAX_PTR_ARY_SIZE ((1<> WFS_LOG2_SMALL_BLK_SIZE) +#define DIR_ENTRY_ATTR_MAX_MEDIUM_BLK_PTRS (DIR_ENTRY_ATTR_MAX_MEDIUM_SIZE >> WFS_LOG2_MEDIUM_BLK_SIZE) +#define DIR_ENTRY_ATTR_MAX_LARGE_BLK_PTRS (DIR_ENTRY_ATTR_MAX_LARGE_SIZE >> WFS_LOG2_LARGE_BLK_SIZE) + +#define DIR_ENTRY_ATTR_MAX_SMALL_BLK_PTRS_DECREASE (DIR_ENTRY_ATTR_MAX_SMALL_SIZE_DECREASE >> WFS_LOG2_SMALL_BLK_SIZE) +#define DIR_ENTRY_ATTR_MAX_MEDIUM_BLK_PTRS_DECREASE (DIR_ENTRY_ATTR_MAX_MEDIUM_SIZE_DECREASE >> WFS_LOG2_MEDIUM_BLK_SIZE) +#define DIR_ENTRY_ATTR_MAX_LARGE_BLK_PTRS_DECREASE (DIR_ENTRY_ATTR_MAX_LARGE_SIZE_DECREASE >> WFS_LOG2_LARGE_BLK_SIZE) + +// Internal WFSAccess value +typedef enum { + WFS_ACCESS_CHANGE_SIZE = 0x04 +} WFSKrnAccess; + +#endif //define wfskrn_Types_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Utils.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Utils.h new file mode 100644 index 0000000..9832b90 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Utils.h @@ -0,0 +1,29 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Utils.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Utils.h,v $ + Revision 1.1 2008/12/03 00:11:29 kondo_masahiro + Initial check-in. + + +*---------------------------------------------------------------------------*/ + +#ifndef wfskrn_Utils_h +#define wfskrn_Utils_h + +#include "wfskrn_Defs.h" + +void _qsort(void *base, size_t num, size_t size, int (*compare)(const void*, const void*) ); +int CompareBlkAdrForward(const void *pA, const void *pB); +int CompareBlkAdrReverse(const void *pA, const void *pB); + +#endif // wfskrn_Utils_h diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Volume.h b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Volume.h new file mode 100644 index 0000000..36150f1 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfskrn_Volume.h @@ -0,0 +1,73 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Volume.h - handle volume-wide management of area allocation + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Volume.h,v $ + Revision 1.4 2008/07/17 05:21:49 kondo_masahiro + Fixed codes for porting IOP. + + Revision 1.3 2008/07/09 01:54:58 paul + Many changes to Volume API to support mounting in namespace, and mounting root directory from an existing volume. + + Revision 1.2 2008/05/12 19:24:00 paul + Merged in Wayne's previous changes + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.3 2008/04/26 01:26:41 wayne.wong + Moved area allocation functionality from Volume to Area module. + Changed API appropriately. + + Revision 1.2 2008/03/19 07:41:22 wayne.wong + Checkpoint. Added initial alloc/free area functions. + + Revision 1.1 2008/03/11 03:22:09 wayne.wong + Checkpoint. Preliminary version. + + +*---------------------------------------------------------------------------*/ + +#ifndef _WFSKRN_VOLUME_H_ +#define _WFSKRN_VOLUME_H_ + +#include "wfskrn_Device.h" + +#define VOLUME_HDR_BLK_ADR 0 // Absolute block address of the volume header + +typedef struct VolumeHdr_ { + // This is the part of the VolumeInfo struct which gets stored on disk + WFSMetaDataHdr mdh; + u32 nVolId; // Randomly assigned 32 bit identifier + u16 nWfsVersion; // WFS version; major upper 8b, minor lower 8b + u16 nBuildDate; // Build date (in days since 2008.01.01) +} VolumeHdr; + +void VolumeModuleInit(); +struct VolumeInfo_ *VolumeAlloc(); +void VolumeFree(struct VolumeInfo_ *pVolInfo); +void VolumeRemoveFromMountedList(struct VolumeInfo_ *pVolInfo); +void VolumeAddToMountedList(struct VolumeInfo_ *pVolInfo); +void VolumeConvertU32ToVolId(WFSVolumeId *pVolId, u32 nVolId); + +WFSKrnResult VolumeInitRootArea(struct VolumeInfo_ *pVolInfo, u8 nLog2BlkSize); +WFSKrnResult VolumeInit (struct VolumeInfo_ *pVolInfo, u32 nLog2BlkSize, u32 nNumBlks); +WFSKrnResult VolumeUnmount (struct VolumeInfo_ *pVolInfo); + +//#define _DEBUG_WFSKRN_VOLUME_ + +#ifdef _DEBUG_WFSKRN_VOLUME_ +#define dbgv(_s) (_s) +#else +#define dbgv(_s) +#endif // _DEBUG_WFSKRN_VOLUME_ + +#endif // _WFSKRN_VOLUME_H_ diff --git a/trunk/firmware/build/libraries/nfs/common/include/wfssrv_Defs.h b/trunk/firmware/build/libraries/nfs/common/include/wfssrv_Defs.h new file mode 100644 index 0000000..6a8ab45 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/include/wfssrv_Defs.h @@ -0,0 +1,382 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFSSrv library API = shim layer in RVL version and RPC + layer in WFSDEV version. + File: wfsdev_Defs.h - Definitions common to WFS client and server + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfssrv_Defs.h,v $ + Revision 1.34 2008/12/03 00:17:36 kondo_masahiro + Added a argument of WFSSrvFlush(). + + Revision 1.33 2008/10/21 10:45:09 kondo_masahiro + Added new function WFSWriteFileAndDiscard + + Revision 1.32 2008/09/29 01:06:26 kondo_masahiro + Added the argument of WFSSrvInit(). + + Revision 1.31 2008/07/18 02:59:44 ueno + Renamed WFSDeletePermissions() -> WFSDeleteAccessListEntry(). + + Revision 1.30 2008/07/17 05:08:41 kondo_masahiro + Added WFSSRV_ATTACH_DETACH + + Revision 1.29 2008/07/15 08:43:53 nakanose_jin + change arg order + + Revision 1.28 2008/07/14 07:15:46 ueno + Implemented WFSGetAccessListAsync(), WFSSetAccessListEntryAsync() and WFSDeletePermissionsAsync(). + + Revision 1.27 2008/07/10 06:12:33 nakanose_jin + add permissions API + + Revision 1.26 2008/05/22 08:05:49 ueno + Added WFSSrvDebugAclTest to run accesslist test. + + Revision 1.25 2008/05/09 14:03:09 nakanose_jin + canceling => reduce settitleid argument + + Revision 1.23 2008/04/19 05:52:03 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.22 2008/04/15 02:47:27 ueno + Added WFSSrvGetPermissionForUser() and WFSSrvSetPermissionForUser(). + + Revision 1.21 2008/03/28 14:14:20 nakanose_jin + chance spec of debug proc + + Revision 1.20 2008/02/20 08:10:10 nakanose_jin + add WFSExecDebugProcedure + + Revision 1.19 2008/02/08 04:42:00 paul + Changed WFSSrvUnmountVolume parameter bForce to WFSBool + + Revision 1.18 2008/02/07 13:02:18 nakanose_jin + WFSUnmountVolume : Add force-close option (but only in detach condition) + + Revision 1.17 2008/01/10 05:33:20 nakanose_jin + validatePathName => validateDirectory + + Revision 1.16 2007/12/25 14:00:36 ueno + Added WFSSrvConnectToServer() to connect to the server again. + + Revision 1.15 2007/12/12 07:51:29 paul + Added WFSSrvGetFileSize + + Revision 1.14 2007/12/10 02:51:36 paul + Added function codes for WFSSRV_SET_HOME_DIRECTORY, WFSSRV_SET_CURRENT_DIRECTORY. (These do not need to be implemented in the actual server, both call WFSSrvValidatePathName) + + Revision 1.13 2007/11/30 09:43:09 nakanose_jin + refine for multi client + + Revision 1.12 2007/11/21 04:17:28 wayne.wong + Many changes that included single request/result RPC messages, bug fixes, code factoring, and English C comment adjustments. + 1. Combined RPC messages into a single request message and single result + message. Except for file reads and writes. + 2. Fixed+factored some Endianess code. + 3. Enabled larger TCP/IP data transfer size. Previous setting was artifically small + to test the code to perform large transfers. + 4. Changed the volume id parameters utf8*->WFSVolumeId for SrvGetVolumeId + and SrvMountDevice. More consistent with the way we send this type at the + RPC layer. + 5. Changed a couple Japanese comments to be compatible with English + comments. In particular, the "//" comment with a backslash at the end of + the line causes the next line of code to be ignored. + 6. Removed Windows-specific debugging output defines for RVL build. + + Revision 1.11 2007/11/16 21:54:26 paul + Fixed WFSSrvCloseFile to pass nNewSize instead of bTruncateFlag + + Revision 1.10 2007/11/16 02:15:57 wayne.wong + Added enumeration and stubs for WFSFlush call. + + Revision 1.9 2007/11/02 00:21:02 paul + started logging changes in the file + Added StartPosition to WFSSrvReadFile, WFSSrvWriteFile + + *---------------------------------------------------------------------------*/ + +#ifndef __WFSSRV_DEFS_H__ +#define __WFSSRV_DEFS_H__ + +#include "wfs_Defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Enumeration of functions. +// Used by the client to specify functions implemented on the server, or +// by the server to specify functions implemented on the client. + +typedef enum { + // server -> client + + WFSSRV_ATTACH_DEVICE, + WFSSRV_DETACH_DEVICE, + + // client -> server + + WFSSRV_INIT, + WFSSRV_EXIT, + + WFSSRV_GET_DEVICE_INFO, + WFSSRV_MOUNT_DEVICE, + WFSSRV_UNMOUNT_VOLUME, + WFSSRV_INITIALIZE_DEVICE, + WFSSRV_GET_VOLUME_ID, + WFSSRV_GET_FREE_SPACE_SIZE, + WFSSRV_FLUSH, + + WFSSRV_CREATE_DIRECTORY, + WFSSRV_SEARCH_DIRECTORY_FIRST, + WFSSRV_SEARCH_DIRECTORY_NEXT, + WFSSRV_SEARCH_DIRECTORY_CLOSE, + + WFSSRV_SET_HOME_DIRECTORY, + WFSSRV_SET_CURRENT_DIRECTORY, + + WFSSRV_VALIDATE_PATH_NAME, + WFSSRV_DELETE, + WFSSRV_MOVE_LOCAL, + WFSSRV_GET_ATTRIBUTES, + WFSSRV_CHANGE_PERMISSIONS, + + WFSSRV_CREATE_AND_OPEN_FILE, + WFSSRV_OPEN_FILE, + WFSSRV_GET_FILE_SIZE, + WFSSRV_CLOSE_FILE, + WFSSRV_READ_FILE, + WFSSRV_WRITE_FILE, + WFSSRV_WRITE_FILE_AND_DISCARD, + + WFSSRV_GET_PERMISSIONS, + WFSSRV_SET_PERMISSIONS, + + WFSSRV_GET_ACL, + WFSSRV_SET_ACL_ENTRY, + WFSSRV_DELETE_ACL_ENTRY, + + WFSSRV_SET_TITLE_ID, + WFSSRV_TEST, + WFSSRV_EXEC_DEBUG, + + WFSSRV_ATTACH_DETACH, + + WFSSRV_DEBUG_ACLTEST // [check] + +} WFSSrvFunc; + + +typedef u16 WFSSrvFileHandle; +typedef u16 WFSSrvSearchDirectoryHandle; + +#ifndef WFSDEV_SERVER + +// The WFSDev server must distinguish between multiple clients. +// This can be done by assigning a ClientId based on the client's IP address, +// which the server learns whenever it receives a request from a client via sockets. + +// Note: ClientId is orthogonal to TitleId. +// There can be multiple clients with the same TitleId. +// The same client could change TitleId while the server is running. + +// The home directory is only stored on the client side. +// The TitleId, however, is determined by a function in IOS. +// (except for the fake debug/wfsdev version) +// +// This allows a system application built on top of wfs to specify the home directory for +// an app prior to launching it. +// + +// Path Names +// The client<->server API uses absolute WFS path names, becuase the server does not know about +// "Current Directory" or "Home Directory". +// The absolute path name does not include the full windows path name, it is a WFS path name. + +// For example: "/vol/ABCDEFG/titles/1234/JAKK/gamesave/save1.bin" +// On windows, this could map to: +// "C:/my_project/my_wfs_device/titles/1234/JAKK/gamesave/save1.bin" +// There would be a file called: +// "C:/my_project/my_wfs_device/.Wfs" which contains: "Volume Name: ABCDEFG" + + +WFSResult WFSSrvInit(void *pWorkSpaceBuffer, u32 nWorkSpaceSize); +// Contact the WFSSrv server so that it can initialize state for this client. + + +WFSResult WFSSrvExit(void); +// Inform the WFSSrv server that this client is terminating. + + +WFSResult WFSSrvInitializeDevice(const WFSDeviceName *pDevName); +// pDevName (IN) pointer to device name struct. +// Server would create a volume (deleting any existing data within the device assigned to this folder). +// The server could have a GUI to allow device attach to be simulated. +// It depends on the usage model but this may not be necessary for game developers, so low priority. +// (Assuming a system app mounts the drive and assigns home directory in advance, so the +// game can access an already-mounted device from the start). + + +WFSResult WFSSrvGetDeviceInfo(const WFSDeviceName *pDevName, WFSDeviceInfo *pDi); +// pDevName (IN) A pointer to a device name struct. +// pDi (OUT) A pointer to a WFSDeviceInfo struct to receive the device information. + + +WFSResult WFSSrvMountDevice(const WFSDeviceName *pDevName, WFSVolumeId *pVolumeIdBuffer); +// pDevName (IN) A pointer to a device name struct. +// pVolumeIdBuffer (OUT) A pointer to a WFSVolumeId buffer + +WFSResult WFSSrvUnmountVolume(const WFSVolumeId *pVolumeId, WFSBool bForce); +// pVolumeId (IN) A pointer to a struct containing a mounted Volume Id. +// bForce (IN) If set to true, forces the volume to be unmounted regardless of open files. +// NOTE: This flag is only valid if the device is currently detached. Un-flushed data will be lost. + +WFSResult WFSSrvGetVolumeId(const WFSDeviceName *pDevName, WFSVolumeId *sVolumeIdBuffer); +// pDevName (IN) A pointer to a device name struct. +// sVolumeIdBuffer (OUT) A pointer to a WFSVolumeId buffer + + +WFSResult WFSSrvGetFreeSpaceSize(const WFSPathName *pAbsPathName, u64 *pSize); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of a file or directory. +// pSize (OUT) A pointer to a u64 to receive the free space size value. + + +WFSResult WFSSrvFlush(const WFSVolumeId *pVolumeId); + + +WFSResult WFSSrvGetAttributes(const WFSPathName *pAbsPathName, WFSFileAttributes *pFa); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of a file or directory. +// pFa (OUT) A pointer to a WFSFileAttributes struct which will be overwritten with the attributes of the specified file or directory. + +WFSResult WFSSrvChangePermissions(const WFSPathName *pAbsPathName, u32 nFlags, u32 nMask); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of a file or directory. +// nFlags (IN) The new permissions flags that are to be set. Should be a combination of the permission flags: WFS_PERM_* +// nMask (IN) A mask to specify which flags to change. + + +WFSResult WFSSrvCreateDirectory(const WFSPathName *pAbsPathName, u32 nFlags, u64 nQuota); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of a file or directory. +// nFlags (IN) Should be a combination of the permission flags: WFS_PERM_*. Note: WFS_FLAG_DIRECTORY will be set +// whether it is included or not. +// nQuota (IN) This parameter that can be used to restrict the total size of the hierarchy beneath the +// new directory. A quota of 0 means there is no size restriction, i.e. the quota is Infinity. + + +WFSResult WFSSrvSearchDirectoryFirst(const WFSPathName *pPattern, WFSSrvSearchDirectoryHandle *pSsdh, WFSFileInfo *pFi); +// pPattern (IN) A pointer to a struct specifying the search pattern as an absolute path name. +// pSsdh (OUT) A pointer to a WFSSrvSearchDirectoryHandle handle which is overwritten by the server. +// pFi (OUT) A pointer to a WFSFileInfo struct which will be overwritten with the details of the + + +WFSResult WFSSrvSearchDirectoryNext(WFSSrvSearchDirectoryHandle ssdh, WFSFileInfo *pFi); +// ssdh (IN) A WFSSrvSearchDirectoryHandle which was created by WFSSrvSearchDirectoryFirst. +// pFi (OUT) A pointer to a WFSFileInfo struct which will be overwritten with the details of the +// next file which matches the search pattern. +// +// If they have read permission on the directory, they can list all files/dirs in that directory. Directory read +// access was already checked by WFSSrvSearchDirectoryFirst. While they can list the directory contents, they may +// not be able to access all contained files/dirs. + + +WFSResult WFSSrvSearchDirectoryClose(WFSSrvSearchDirectoryHandle ssdh); +// ssdh (IN) A WFSSrvSearchDirectoryHandle which was returned by WFSSrvSearchDirectoryFirst. + + +WFSResult WFSSrvValidateDirectory(const WFSPathName *pAbsPathName); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of a file or directory to validate. +// Returns WFS_RESULT_OK if the specified pathname exists, and is accessible to the current title + + +WFSResult WFSSrvDelete(const WFSPathName *pAbsPathName); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of the file or directory to delete. + +WFSResult WFSSrvMoveLocal(const WFSPathName *pSrcAbsPathName, const WFSPathName *pDstAbsPathName); +// pSrcAbsPathName (IN) A pointer to a struct containing the absolute pathname of the source file or directory. +// pDstAbsPathName (IN) A pointer to a struct containing the absolute pathname of the destination file or directory. +// Moves or renames the source file/directory to the destination pathname. This function does not work across volumes. + + +WFSResult WFSSrvCreateAndOpenFile(const WFSPathName *pAbsPathName, u32 nFlags, WFSContentIdx nCidx, WFSFileSize nPreAllocateSize, WFSSrvFileHandle *pSfh); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of the file to create and open. +// nFlags (IN) Should be a combination of the permission flags: WFS_PERM_* +// nCidx (IN) The content idx, used to control access to purchased content. +// nPreAllocateSize (IN) The amount of disk-space to pre-allocate for the file. Hint to the file system. +// pSfh (OUT) A pointer to a server file handle which is overwritten by the server. + +WFSResult WFSSrvOpenFile(const WFSPathName *pAbsPathName, WFSAccess nDesiredAccess, WFSSrvFileHandle *pSfh, WFSFileAttributes *pFa); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of the file to open. +// nDesiredAccess (IN) The kind of access that is required: should be one of the WFS_ACCESS_* options. +// pSfh (OUT) A pointer to a server file handle, which is overwritten by the server. +// pFa (OUT) A pointer to a WFSFileAttributes struct which will be overwritten by the server, + +WFSResult WFSSrvCloseFile(WFSSrvFileHandle sfh, WFSFileSize nNewSize); +// sfh (IN) The server file handle which was returned when the file was opened. +// nNewSize (IN) This value may be set to truncate the size of a file. + +WFSResult WFSSrvGetFileSize(WFSSrvFileHandle sfh, WFSFileSize *pNewSize); +// sfh (IN) The server file handle which was returned when the file was opened. +// pNewSize (OUT) A pointer to a WFSFileSize variable which is overwritten by the current file size. + +s32 WFSSrvReadFile(WFSSrvFileHandle sfh, void *pFileDataBuffer, WFSFileSize nStartPosition, s32 nSize); +// sfh (IN) The server file handle which was returned when the file was opened. +// pFileDataBuffer (OUT) Points to a buffer which will be overwritten with data from the file. +// nSize (IN) The number of bytes to be read. + + +WFSResult WFSSrvWriteFile(WFSSrvFileHandle sfh, const void *pFileData, WFSFileSize nStartPosition, WFSFileSize nSize, WFSBool bDiscard); +// sfh (IN) The server file handle which was returned when the file was opened. +// pFileData (IN) Points to the data to be written to the file. +// nSize (IN) The number of bytes to be written. +// bDiscard (IN) If it is true, the user buffer is used as work buffer. + + +WFSResult WFSSrvSetTitleId(WFSTitleId titleId,WFSGroupId groupId); +// titleId (IN) the title id which is the low 32 bits of the OSTitleId which can be obtained be ESP_GetTitleId() +// groupId (IN) the group id from the TMD, which can be obtained by ES_GetTmd() +// This function informs the server of the title id and group id of the application linked to this instance of the client. + +WFSResult WFSSrvExecDebugProcedure( u32 cmd , void *arg0 , void *arg1 ); +// cmd (IN) special command No. +// arg0,arg1 (IN/OUT) parameters of special command. +// This function let the server do special tasks. + +WFSResult WFSSrvConnectToServer(void); + +WFSResult WFSSrvGetPermissionForUser(const WFSPathName *pAbsPathName, u32 *pFlags, WFSTitleId titleId); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of the file or the directory. +// pFlags (OUT) A pointer to a u32 which will be overwritten with the permissions the specified title id has to +// access or modify the specified file or directory. See wfstypes.h for WFS_PERM* flag definitions. +// titleId (IN) Title id of the application for which permissions are being set. + +WFSResult WFSSrvSetPermissionForUser(const WFSPathName *pAbsPathName, u32 nFlags, u32 nMask, WFSTitleId titleId); +// pAbsPathName (IN) A pointer to a struct containing the absolute pathname of the file or the directory. +// nFlags (IN) The new permissions flags that are to be set. Should be a combination of the permission flags: WFS_PERM_* (see wfstypes.h) +// nMask (IN) The mask determines which flags will be changed. NewAttributes = (OldAttributes & ~nMask) | (nFlags & nMask) +// titleId (IN) Title id of the application for which permissions are being set. + +WFSResult WFSSrvDeleteAccessListEntry(const WFSPathName *pAbsPathName, WFSTitleId titleId, WFSTitleId entryCreatorId); +WFSResult WFSSrvSetAccessListEntry(const WFSPathName *pAbsPathName, u32 nFlags, u32 nMask, WFSTitleId titleId); +s32 WFSSrvGetAccessList(const WFSPathName *pAbsPathName, WFSAccessListEntry *pAccessList, u32 nMaxElements); + + + +WFSResult WFSSrvSetWorkspace(void *pWorkSpaceBuffer, u32 nWorkSpaceSize); + +#ifdef ACL_TEST +WFSResult WFSSrvDebugAclTest(u32 testNo, void *arg0, void *arg1); +#endif // ACL_TEST + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif //define __WFSSRV_DEFS_H__ diff --git a/trunk/firmware/build/libraries/nfs/common/src/client/WinOSReport.cpp b/trunk/firmware/build/libraries/nfs/common/src/client/WinOSReport.cpp new file mode 100644 index 0000000..ff50ba1 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/client/WinOSReport.cpp @@ -0,0 +1,145 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: WinOSReport.cpp - implementation of WFSDEV higher-level socket + library. + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: WinOSReport.cpp,v $ + Revision 1.9 2008/08/28 00:18:26 nakanose_jin + lets standard exception style + + Revision 1.8 2008/08/27 04:50:52 nakanose_jin + add function and defines + + Revision 1.7 2008/04/19 05:53:32 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.6 2007/11/26 11:25:13 nakanose_jin + deal error on ndev + + Revision 1.5 2007/11/02 01:08:06 paul + now logging changes + +*---------------------------------------------------------------------------*/ + +#if _WIN32 +#include +#endif + +#if !_IOP +#include +#include +#endif + +#include +#include "WinOSReport.h" + +static OSReportCallback userCB=0; + +#if _WIN32 +FILE *fpOSReport; +#endif + +void DebugPrintCallback(const char *pStr) { +#if _WIN32 + //fpOSReport = fopen("OSReport.txt", "a+, ccs=UTF-8"); + //fpOSReport = fopen("OSReport.txt", "a+"); + fprintf(fpOSReport, pStr); + //fclose(fpOSReport); + //OutputDebugString(pStr); +#else + osTPrintf(pStr); +#endif +} + +void DebugPrintCallback2(const char *pStr) { +#if _WIN32 + OutputDebugString(pStr); +#else + osTPrintf(pStr); +#endif +} + +OSReportCallback SetOSReportPrintCallback(OSReportCallback cb) { + OSReportCallback oldCb = userCB; + userCB = cb; + return oldCb; +} + +#pragma warning(disable:4996) + +#if (_MSC_VER) && (_MSC_VER < 1400) +#define VSNPRINTF _vsnprintf +#else +#define VSNPRINTF vsnprintf +#endif + +#define SIZEDUMP 1024 + +static char strdump[SIZEDUMP]; +#include "wfs_Mutex.h" +WFSMutex mxOSReport; + +#if _WIN32 +void InitMyOSReport(void) { + WFSInitMutex(&mxOSReport); +} +#endif + +#if _WIN32 +void MyOSReport(const char *format, ...) { + if (userCB) { + WFSLockMutex(&mxOSReport); + va_list ap; + va_start(ap, format); + VSNPRINTF(strdump, SIZEDUMP, format, ap); + userCB(strdump); + va_end( ap ); + WFSUnlockMutex(&mxOSReport); + } else { + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fflush(stderr); + } +} +#endif + +#if _WIN32 +#include +#endif + +void MyOSPanic(const char* file, int line , const char* msg, ...) { +#if _WIN32 + MyOSReport(" in \"%s\" on line %d.\n", file, line); + if (userCB) { + WFSLockMutex(&mxOSReport); + va_list ap; + va_start(ap, msg); + VSNPRINTF(strdump, SIZEDUMP, msg, ap); + userCB(strdump); + va_end( ap ); + WFSUnlockMutex(&mxOSReport); + } else { + va_list ap; + va_start(ap, msg); + vfprintf(stderr, msg, ap); + va_end(ap); + fflush(stderr); + } + throw std::bad_exception(); + abort(); +#else + osTPanic( "panic"); +#endif +} + diff --git a/trunk/firmware/build/libraries/nfs/common/src/client/randomlib.cpp b/trunk/firmware/build/libraries/nfs/common/src/client/randomlib.cpp new file mode 100644 index 0000000..a4692b6 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/client/randomlib.cpp @@ -0,0 +1,206 @@ +#include +#include "randomlib.h" + +#define FALSE 0 +#define TRUE 1 + +/* + This Random Number Generator is based on the algorithm in a FORTRAN + version published by George Marsaglia and Arif Zaman, Florida State + University; ref.: see original comments below. + At the fhw (Fachhochschule Wiesbaden, W.Germany), Dept. of Computer + Science, we have written sources in further languages (C, Modula-2 + Turbo-Pascal(3.0, 5.0), Basic and Ada) to get exactly the same test + results compared with the original FORTRAN version. + April 1989 + Karl-L. Noell + and Helmut Weber + + This random number generator originally appeared in "Toward a Universal + Random Number Generator" by George Marsaglia and Arif Zaman. + Florida State University Report: FSU-SCRI-87-50 (1987) + It was later modified by F. James and published in "A Review of Pseudo- + random Number Generators" + THIS IS THE BEST KNOWN RANDOM NUMBER GENERATOR AVAILABLE. + (However, a newly discovered technique can yield + a period of 10^600. But that is still in the development stage.) + It passes ALL of the tests for random number generators and has a period + of 2^144, is completely portable (gives bit identical results on all + machines with at least 24-bit mantissas in the floating point + representation). + The algorithm is a combination of a Fibonacci sequence (with lags of 97 + and 33, and operation "subtraction plus one, modulo one") and an + "arithmetic sequence" (using subtraction). + + Use IJ = 1802 & KL = 9373 to test the random number generator. The + subroutine RANMAR should be used to generate 20000 random numbers. + Then display the next six random numbers generated multiplied by 4096*4096 + If the random number generator is working properly, the random numbers + should be: + 6533892.0 14220222.0 7275067.0 + 6172232.0 8354498.0 10633180.0 +*/ + +/* Globals */ +double u[97],c,cd,cm; +int i97,j97; +int test = FALSE; + +/* + This is the initialization routine for the random number generator. + NOTE: The seed variables can have values between: 0 <= IJ <= 31328 + 0 <= KL <= 30081 + The random number sequences created by these two seeds are of sufficient + length to complete an entire calculation with. For example, if sveral + different groups are working on different parts of the same calculation, + each group could be assigned its own IJ seed. This would leave each group + with 30000 choices for the second seed. That is to say, this random + number generator can create 900 million different subsequences -- with + each subsequence having a length of approximately 10^30. +*/ +void RandomInitialise(int ij, int kl) +{ + double s,t; + int ii,i,j,k,l,jj,m; + + /* + Handle the seed range errors + First random number seed must be between 0 and 31328 + Second seed must have a value between 0 and 30081 + */ + if (ij < 0 || ij > 31328 || kl < 0 || kl > 30081) { + ij = 1802; + kl = 9373; + } + + i = (ij / 177) % 177 + 2; + j = (ij % 177) + 2; + k = (kl / 169) % 178 + 1; + l = (kl % 169); + + for (ii=0; ii<97; ii++) { + s = 0.0; + t = 0.5; + for (jj=0; jj<24; jj++) { + m = (((i * j) % 179) * k) % 179; + i = j; + j = k; + k = m; + l = (53 * l + 1) % 169; + if (((l * m % 64)) >= 32) + s += t; + t *= 0.5; + } + u[ii] = s; + } + + c = 362436.0 / 16777216.0; + cd = 7654321.0 / 16777216.0; + cm = 16777213.0 / 16777216.0; + i97 = 97; + j97 = 33; + test = TRUE; +} + +void RandomSetSeedU32(u32 nSeed) { + // Seeds between 0x0 and 0x382C7A41 inclusive are unique + RandomInitialise((int)(nSeed%31329),(int)((nSeed/31329)%30082)); +} + +/* + This is the random number generator proposed by George Marsaglia in + Florida State University Report: FSU-SCRI-87-50 +*/ +double RandomUniform(void) +{ + double uni; + + // Make sure the initialisation routine has been called + if (!test) + RandomInitialise(1802,9373); + + uni = u[i97-1] - u[j97-1]; + if (uni <= 0.0) + uni++; + u[i97-1] = uni; + i97--; + if (i97 == 0) + i97 = 97; + j97--; + if (j97 == 0) + j97 = 97; + c -= cd; + if (c < 0.0) + c += cm; + uni -= c; + if (uni < 0.0) + uni++; + + return(uni); +} + +/* + ALGORITHM 712, COLLECTED ALGORITHMS FROM ACM. + THIS WORK PUBLISHED IN TRANSACTIONS ON MATHEMATICAL SOFTWARE, + VOL. 18, NO. 4, DECEMBER, 1992, PP. 434-435. + The function returns a normally distributed pseudo-random number + with a given mean and standard devaiation. Calls are made to a + function subprogram which must return independent random + numbers uniform in the interval (0,1). + The algorithm uses the ratio of uniforms method of A.J. Kinderman + and J.F. Monahan augmented with quadratic bounding curves. +*/ + +#if !_IOP + +double RandomGaussian(double mean,double stddev) +{ + double q,u,v,x,y; + + // Generate P = (u,v) uniform in rect. enclosing acceptance region + // Make sure that any random numbers <= 0 are rejected, since + // gaussian() requires uniforms > 0, but RandomUniform() delivers >= 0. + do { + u = RandomUniform(); + v = RandomUniform(); + if (u <= 0.0 || v <= 0.0) { + u = 1.0; + v = 1.0; + } + v = 1.7156 * (v - 0.5); + + // Evaluate the quadratic form + x = u - 0.449871; + y = fabs(v) + 0.386595; + q = x * x + y * (0.19600 * y - 0.25472 * x); + + // Accept P if inside inner ellipse + if (q < 0.27597) + break; + + // Reject P if outside outer ellipse, or outside acceptance region + } while ((q > 0.27846) || (v * v > -4.0 * log(u) * u * u)); + + // Return ratio of P's coordinates as the normal deviate + return (mean + stddev * v / u); +} + +#endif + +// Return random integer within a range, lower -> upper INCLUSIVE +int RandomInt(int lower,int upper) +{ + return((int)(RandomUniform() * (upper - lower + 1)) + lower); +} + +u32 RandomU32() { + double rX = RandomUniform(); + double rY = RandomUniform(); + return (u32)((rX * 4294967296.0)+(rY * 65536)); +} + +// Return random float within a range, lower -> upper +double RandomDouble(double lower,double upper) +{ + return((upper - lower) * RandomUniform() + lower); +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/client/wfs_AsyncUtils.cpp b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_AsyncUtils.cpp new file mode 100644 index 0000000..5c1ad4c --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_AsyncUtils.cpp @@ -0,0 +1,708 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_AsyncUtils.cpp + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_AsyncUtils.cpp,v $ + Revision 1.42 2008/12/03 00:17:05 kondo_masahiro + Fixed case WFSSRV_FLUSH. + + Revision 1.41 2008/10/31 05:37:09 ooizumi + Fixed a bug in WFSExecFunction(). + + Revision 1.40 2008/10/23 11:15:28 nakanose_jin + Open and Search should give a invalid file handle if he fails to execute. + + Revision 1.39 2008/10/21 10:45:20 kondo_masahiro + Added new function WFSWriteFileAndDiscard + + Revision 1.38 2008/07/18 02:59:46 ueno + Renamed WFSDeletePermissions() -> WFSDeleteAccessListEntry(). + + Revision 1.37 2008/07/14 07:15:24 ueno + Implemented WFSGetAccessListAsync(), WFSSetAccessListEntryAsync() and WFSDeletePermissionsAsync(). + + Revision 1.36 2008/04/24 04:26:29 nakanose_jin + byebye nPermissions param + + Revision 1.35 2008/04/18 07:45:03 nakanose_jin + merge acl + + Revision 1.34 2008/04/10 13:35:38 ueno + Added WFSSetPermissionsForUser[Async] and WFSGetPermissionsForUser[Async]. + + Revision 1.33 2008/02/25 08:33:20 paul + BOOL -> WFSBool + + Revision 1.32 2008/02/07 13:02:21 nakanose_jin + WFSUnmountVolume : Add force-close option (but only in detach condition) + + Revision 1.31 2008/01/23 00:44:30 ueno + Fixed to copy volume ID only when the result is WFS_RESULT_OK. + + Revision 1.30 2008/01/23 00:07:02 paul + Fixed WFSGetVolumeIdAsync to only overwrite buffer when result==WFS_RESULT_OK + + Revision 1.29 2008/01/10 09:23:26 paul + bugfix for WFSSRV_SET_CURRENT_DIRECTORY, WFSSRV_SET_HOME_DIRECTORY + + Revision 1.28 2008/01/10 05:33:23 nakanose_jin + validatePathName => validateDirectory + + Revision 1.27 2008/01/08 09:49:46 ueno + Modified WFSExecFunction() to support WFSSRV_MOUNT_DEVICE. + + Revision 1.26 2007/12/27 06:02:37 paul + bugfix for WFSSRV_SET_HOME_DIRECTORY, WFSSRV_SET_CURRENT_DIRECTORY + + Revision 1.25 2007/12/27 01:43:19 ueno + Added WFSIsThreadTerminated() and WFSJoinThread(). + + Revision 1.24 2007/12/26 05:43:45 ueno + Fixed WFSAsyncUtilsInit() to create a thread. + Fixed WFSAsyncUtilsClose() to send signal to wake up async thread. + + Revision 1.23 2007/12/25 14:03:50 ueno + Modified to initialize mutex, thread and heap only once. + + Revision 1.22 2007/12/12 19:57:07 paul + Changed WFSSearchDirectoryFirstAsync to not create a search directory handle, and pass sdh=0 to the callback if WFSSrvSearchDirectoryFirst returns an error code. + + Revision 1.21 2007/12/12 07:52:10 paul + Added WFSSRV_GET_FILE_SIZE + + Revision 1.20 2007/12/11 00:10:06 paul + Fixed a bug in WFSWriteFileAsync + + Revision 1.19 2007/12/10 02:48:49 paul + Fixed WFSSetCurrentDirectoryAsync, WFSSetHomeDirectoryAsync + + Revision 1.18 2007/11/21 04:17:45 wayne.wong + Many changes that included single request/result RPC messages, bug fixes, code factoring, and English C comment adjustments. + 1. Combined RPC messages into a single request message and single result + message. Except for file reads and writes. + 2. Fixed+factored some Endianess code. + 3. Enabled larger TCP/IP data transfer size. Previous setting was artifically small + to test the code to perform large transfers. + 4. Changed the volume id parameters utf8*->WFSVolumeId for SrvGetVolumeId + and SrvMountDevice. More consistent with the way we send this type at the + RPC layer. + 5. Changed a couple Japanese comments to be compatible with English + comments. In particular, the "//" comment with a backslash at the end of + the line causes the next line of code to be ignored. + 6. Removed Windows-specific debugging output defines for RVL build. + + Revision 1.17 2007/11/16 21:55:08 paul + Changed WFSSrvCloseFile to pass nNewSize instead of bTruncateFlag + + Revision 1.16 2007/11/16 02:06:40 paul + Added WFSFlush() + + Revision 1.15 2007/11/09 01:17:29 paul + Added sub-directory validation check for WFSMoveLocal + + Revision 1.14 2007/11/02 01:57:40 paul + bugfix + + Revision 1.13 2007/11/02 00:52:21 paul + now logging changes + added nStartPosition to WFSSrvReadFile, WFSSrvWriteFile + +---------------------------------------------------------------------------*/ + +#include "wfs_Client.h" + +#undef dbg +#if _DEBUG_ASYNC_UTILS +#define dbg(s) s +#else +#define dbg(s) +#endif + +static BOOL bMutexInitialized; + +void WFSExecFunction(WFSAsyncParamHdr *pParamHdr); + +void WFSExecFunction(WFSAsyncParamHdr *pParamHdr) { + dbg(MyOSReport("Processing Function: %d\n", pParamHdr->nFunction)); + void *pPtr = (void*)((size_t)pParamHdr + sizeof(WFSAsyncParamHdr)); + WFSResult nResult = WFS_RESULT_OK; + switch(pParamHdr->nFunction) { + case WFSSRV_EXIT: { + //WFSAsyncUtilsClose(); + ((WFSResultCallback)pParamHdr->cb)(nResult, pParamHdr->pUserData); + WFSExitThread(NULL); + break; + } + case WFSSRV_GET_DEVICE_INFO: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, utf8 *, sDeviceName); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSDeviceInfo *, pDi); + WFSDeviceName *pDevName = (WFSDeviceName *)pPtr; + nResult = WFSSrvGetDeviceInfo(pDevName, pDi); + ((WFSDeviceInfoCallback)pParamHdr->cb)(nResult, sDeviceName, pDi, pParamHdr->pUserData); + break; + } + case WFSSRV_MOUNT_DEVICE: { + WFSVolumeId volId; + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, const utf8 *, sDeviceName); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, utf8 *, sVolumeIdBuffer); + WFSDeviceName *pDevName = (WFSDeviceName *)pPtr; + nResult = WFSSrvMountDevice(pDevName, &volId); + if (nResult == WFS_RESULT_OK) + { + strncpy(sVolumeIdBuffer, volId.sStr, WFS_MAX_VOLUME_ID_SIZE+1); + } + ((WFSDeviceVolumeCallback)pParamHdr->cb)(nResult, sDeviceName, sVolumeIdBuffer, pParamHdr->pUserData); + break; + } + case WFSSRV_UNMOUNT_VOLUME: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, const utf8 *, sVolumeId); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSBool, bForce); + WFSVolumeId *pVolumeId = (WFSVolumeId *)pPtr; + nResult = WFSSrvUnmountVolume(pVolumeId, bForce); + ((WFSUnmountVolumeCallback)pParamHdr->cb)(nResult, sVolumeId, pParamHdr->pUserData); + break; + } + case WFSSRV_INITIALIZE_DEVICE: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, const utf8 *, sDeviceName); + WFSDeviceName *pDevName = (WFSDeviceName *)pPtr; + nResult = WFSSrvInitializeDevice(pDevName); + ((WFSInitializeDeviceCallback)pParamHdr->cb)(nResult, sDeviceName, pParamHdr->pUserData); + break; + } + case WFSSRV_GET_VOLUME_ID: { + WFSVolumeId volId; + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, const utf8 *, sDeviceName); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, utf8 *, sVolumeIdBuffer); + WFSDeviceName *pDevName = (WFSDeviceName *)pPtr; + nResult = WFSSrvGetVolumeId(pDevName, &volId); + if (nResult == WFS_RESULT_OK) { + strncpy(sVolumeIdBuffer, volId.sStr, WFS_MAX_VOLUME_ID_SIZE+1); + } + ((WFSDeviceVolumeCallback)pParamHdr->cb)(nResult, sDeviceName, sVolumeIdBuffer, pParamHdr->pUserData); + break; + } + case WFSSRV_GET_FREE_SPACE_SIZE: { + WFSPathName *pAbsPathName = (WFSPathName *)pPtr; + u64 nSize; + nResult = WFSSrvGetFreeSpaceSize(pAbsPathName, &nSize); + ((WFSGetFreeSpaceCallback)pParamHdr->cb)(nResult, nSize, pParamHdr->pUserData); + break; + } + case WFSSRV_SET_HOME_DIRECTORY: { + WFSPathName *pAbsPathName = (WFSPathName *)pPtr; + nResult = WFSSrvValidateDirectory(pAbsPathName); + if (nResult == WFS_RESULT_OK) { + WFSLockMutex(&wcg.pg.mxAccessPathGlobals); + if (pAbsPathName->sStr[pAbsPathName->nLen-1]!='/') { + pAbsPathName->sStr[pAbsPathName->nLen++] ='/'; + pAbsPathName->sStr[pAbsPathName->nLen] =0; + } + WFSPathResolve(&wcg.pg.pathHome.pn, &wcg.pg.pathHome.ppoa, pAbsPathName->sStr, PATH_TYPE_ABS_DIR_ONLY); + WFSUnlockMutex(&wcg.pg.mxAccessPathGlobals); + } + ((WFSResultCallback)pParamHdr->cb)(nResult, pParamHdr->pUserData); + break; + } + case WFSSRV_SET_CURRENT_DIRECTORY: { + WFSPathName *pAbsPathName = (WFSPathName *)pPtr; + nResult = WFSSrvValidateDirectory(pAbsPathName); + if (nResult == WFS_RESULT_OK) { + WFSLockMutex(&wcg.pg.mxAccessPathGlobals); + if (pAbsPathName->sStr[pAbsPathName->nLen-1]!='/') { + pAbsPathName->sStr[pAbsPathName->nLen++] ='/'; + pAbsPathName->sStr[pAbsPathName->nLen] =0; + } + WFSPathResolve(&wcg.pg.pathCurrent.pn, &wcg.pg.pathCurrent.ppoa, pAbsPathName->sStr, PATH_TYPE_ABS_DIR_ONLY); + WFSUnlockMutex(&wcg.pg.mxAccessPathGlobals); + } + ((WFSResultCallback)pParamHdr->cb)(nResult, pParamHdr->pUserData); + break; + } + case WFSSRV_VALIDATE_PATH_NAME: { + WFSPathName *pAbsPathName = (WFSPathName *)pPtr; + nResult = WFSSrvValidateDirectory(pAbsPathName); + ((WFSResultCallback)pParamHdr->cb)(nResult, pParamHdr->pUserData); + break; + } + case WFSSRV_CREATE_DIRECTORY: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, u32, nFlags); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, u64, nQuota); + WFSPathName *pAbsPathName = (WFSPathName *)pPtr; + nResult = WFSSrvCreateDirectory(pAbsPathName, nFlags, nQuota); + ((WFSResultCallback)pParamHdr->cb)(nResult, pParamHdr->pUserData); + break; + } + case WFSSRV_GET_ATTRIBUTES: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSFileAttributes *, pFa); + WFSPathName *pAbsPathName = (WFSPathName *)pPtr; + nResult = WFSSrvGetAttributes(pAbsPathName, pFa); + ((WFSGetAttributesCallback)pParamHdr->cb)(nResult, pFa, pParamHdr->pUserData); + break; + } + case WFSSRV_CHANGE_PERMISSIONS: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, u32, nFlags); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, u32, nMask); + WFSPathName *pAbsPathName = (WFSPathName *)pPtr; + nResult = WFSSrvChangePermissions(pAbsPathName, nFlags, nMask); + ((WFSResultCallback)pParamHdr->cb)(nResult, pParamHdr->pUserData); + break; + } + case WFSSRV_DELETE: { + WFSPathName *pAbsPathName = (WFSPathName *)pPtr; + nResult = WFSSrvDelete(pAbsPathName); + ((WFSResultCallback)pParamHdr->cb)(nResult, pParamHdr->pUserData); + break; + } + case WFSSRV_DELETE_ACL_ENTRY: { + WFSPathName *pAbsPathName; + + // restore arguments. + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSTitleId, titleId); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSTitleId, entryCreatorId); + pAbsPathName = (WFSPathName *)pPtr; + + nResult = WFSSrvDeleteAccessListEntry(pAbsPathName, titleId, entryCreatorId); + ((WFSResultCallback)pParamHdr->cb)(nResult, pParamHdr->pUserData); + break; + } + case WFSSRV_SET_ACL_ENTRY: { + WFSPathName *pAbsPathName; + + // restore arguments. + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, u32, nFlags); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, u32, nMask); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSTitleId, titleId); + pAbsPathName = (WFSPathName *)pPtr; + nResult = WFSSrvSetAccessListEntry(pAbsPathName, nFlags, nMask, titleId); + + ((WFSResultCallback)pParamHdr->cb)(nResult, pParamHdr->pUserData); + break; + } + case WFSSRV_GET_ACL: { + WFSPathName *pAbsPathName; + s32 nResultOrNumAclEntries; + + // restore arguments. + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSAccessListEntry*, pAccessList); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, u32, nMaxElements); + pAbsPathName = (WFSPathName *)pPtr; + nResultOrNumAclEntries = WFSSrvGetAccessList(pAbsPathName, pAccessList, nMaxElements); + + ((WFSGetAccessListCallback)pParamHdr->cb)(nResultOrNumAclEntries, pParamHdr->pUserData); + break; + } + case WFSSRV_MOVE_LOCAL: { + WFSPathName *pSrcAbsPathName = (WFSPathName *)pPtr; + WFSPathName *pDstAbsPathName = (WFSPathName *)((size_t)pPtr + pSrcAbsPathName->nLen + sizeof(WFSPathName) - WFS_MAX_PATH_NAME_SIZE - 1); + nResult = WFSSrvMoveLocal(pSrcAbsPathName, pDstAbsPathName); + ((WFSResultCallback)pParamHdr->cb)(nResult, pParamHdr->pUserData); + break; + } + case WFSSRV_CREATE_AND_OPEN_FILE: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, u32, nFlags); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSContentIdx, nCidx); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, u32, nPreAllocateSize); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSCliFileInfo *, pFi); + WFSSrvFileHandle sfh; + WFSPathName *pAbsPathName = (WFSPathName *)pPtr; + nResult = WFSSrvCreateAndOpenFile(pAbsPathName, nFlags, nCidx, nPreAllocateSize, &sfh); + WFSFileHandle fh; + if (nResult == WFS_RESULT_OK) { + fh = pFi->nHandle |= sfh; + pFi->fa.nFileSize = pFi->nPosition = 0; + pFi->fa.nFlags = nFlags; + pFi->fa.nCidx = nCidx; + pFi->nAccess = WFS_ACCESS_RW; + } else { + WFSCliFileInfoFree(pFi); + fh = NULL; + } + ((WFSFileOpCallback)pParamHdr->cb)(nResult, fh, pParamHdr->pUserData); + break; + } + case WFSSRV_OPEN_FILE: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSAccess, nDesiredAccess); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSCliFileInfo *, pFi); + WFSSrvFileHandle sfh; + WFSPathName *pAbsPathName = (WFSPathName *)pPtr; + nResult = WFSSrvOpenFile(pAbsPathName, nDesiredAccess, &sfh, &pFi->fa); + WFSFileHandle fh; + if (nResult == WFS_RESULT_OK) { + fh = pFi->nHandle |= sfh; + pFi->nPosition = 0; + pFi->nAccess = nDesiredAccess; + } else { + WFSCliFileInfoFree(pFi); // fh = NULL; + fh = WFS_INVALID_HANDLE_VALUE; + } + ((WFSFileOpCallback)pParamHdr->cb)(nResult, fh, pParamHdr->pUserData); + break; + } + case WFSSRV_GET_FILE_SIZE: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM(pPtr, WFSFileHandle, fh); + WFSSrvFileHandle sfh = (WFSSrvFileHandle)fh; + WFSFileSize nFileSize; + nResult = WFSSrvGetFileSize(sfh, &nFileSize); + ((WFSGetFileSizeCallback)pParamHdr->cb)(nResult, nFileSize, fh, pParamHdr->pUserData); + break; + } + case WFSSRV_READ_FILE: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSFileHandle, fh); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, void *, pFileDataBuffer); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSFileSize, nStartPosition); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM(pPtr, s32, nSize); + WFSSrvFileHandle sfh = (WFSSrvFileHandle)fh; + s32 nResultOrNumBytesRead = WFSSrvReadFile(sfh, pFileDataBuffer, nStartPosition, nSize); +#if 0 // This code has been disabled, because we are no longer updating file position after async read/write + if (nResultOrNumBytesRead >= 0) { + WFSCliFileInfo *pFi; + WFSGetCliFileInfo(&pFi, fh); + pFi->nPosition += nResultOrNumBytesRead; + if (pFi->fa.nFileSize < pFi->nPosition) { + pFi->fa.nFileSize = pFi->nPosition; + } + } +#endif + ((WFSReadFileCallback)pParamHdr->cb)(nResultOrNumBytesRead, fh, pParamHdr->pUserData); + break; + } + case WFSSRV_WRITE_FILE: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSFileHandle, fh); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, const void *, pFileData); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSFileSize, nStartPosition); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM(pPtr, WFSFileSize, nSize); + WFSSrvFileHandle sfh = (WFSSrvFileHandle)fh; + nResult = WFSSrvWriteFile(sfh, pFileData, nStartPosition, nSize, FALSE); + if (nResult == WFS_RESULT_OK) { + WFSCliFileInfo *pFi; + WFSGetCliFileInfo(&pFi, fh); + u32 nEndPosition = nStartPosition + nSize; + if (pFi->fa.nFileSize < nEndPosition) { + pFi->fa.nFileSize = nEndPosition; + } + } + ((WFSFileOpCallback)pParamHdr->cb)(nResult, fh, pParamHdr->pUserData); + break; + } + case WFSSRV_WRITE_FILE_AND_DISCARD: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSFileHandle, fh); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, const void *, pFileData); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSFileSize, nStartPosition); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM(pPtr, WFSFileSize, nSize); + WFSSrvFileHandle sfh = (WFSSrvFileHandle)fh; + nResult = WFSSrvWriteFile(sfh, pFileData, nStartPosition, nSize, TRUE); + if (nResult == WFS_RESULT_OK) { + WFSCliFileInfo *pFi; + WFSGetCliFileInfo(&pFi, fh); + u32 nEndPosition = nStartPosition + nSize; + if (pFi->fa.nFileSize < nEndPosition) { + pFi->fa.nFileSize = nEndPosition; + } + } + ((WFSFileOpCallback)pParamHdr->cb)(nResult, fh, pParamHdr->pUserData); + break; + } + case WFSSRV_CLOSE_FILE: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSFileHandle, fh); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM(pPtr, WFSFileSize, nNewSize); + WFSSrvFileHandle sfh = (WFSSrvFileHandle)fh; + nResult = WFSSrvCloseFile(sfh, nNewSize); + if (nResult == WFS_RESULT_OK) { + WFSCliFileInfo *pFi; + WFSGetCliFileInfo(&pFi, fh); + WFSCliFileInfoFree(pFi); + } + ((WFSFileOpCallback)pParamHdr->cb)(nResult, fh, pParamHdr->pUserData); + break; + } + case WFSSRV_FLUSH: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, const utf8 *, sVolumeId); + WFSVolumeId *pVolumeId = (WFSVolumeId *)pPtr; + nResult = WFSSrvFlush(pVolumeId); + ((WFSResultCallback)pParamHdr->cb)(nResult, pParamHdr->pUserData); + break; + } + case WFSSRV_SEARCH_DIRECTORY_FIRST: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSCliSearchDirInfo *, pSdi); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSFileInfo *, pFi); + WFSPathName *pAbsPattern = (WFSPathName *)pPtr; + WFSSrvSearchDirectoryHandle ssdh; + nResult = WFSSrvSearchDirectoryFirst(pAbsPattern, &ssdh, pFi); + pSdi->nHandle |= ssdh; + WFSFileHandle fh = pSdi->nHandle; + if (nResult != WFS_RESULT_OK) { + WFSCliSearchDirInfoFree(pSdi); + fh = WFS_INVALID_HANDLE_VALUE; // fh = 0; + } + ((WFSSearchDirectoryCallback)pParamHdr->cb)(nResult, fh, pFi, pParamHdr->pUserData); + break; + } + case WFSSRV_SEARCH_DIRECTORY_NEXT: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSSearchDirectoryHandle, sdh); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM(pPtr, WFSFileInfo *, pFi); + WFSSrvSearchDirectoryHandle ssdh = (WFSSrvSearchDirectoryHandle)sdh; + nResult = WFSSrvSearchDirectoryNext(ssdh, pFi); + ((WFSSearchDirectoryCallback)pParamHdr->cb)(nResult, sdh, pFi, pParamHdr->pUserData); + break; + } + case WFSSRV_SEARCH_DIRECTORY_CLOSE: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSSearchDirectoryHandle, sdh); + WFSSrvSearchDirectoryHandle ssdh = (WFSSrvSearchDirectoryHandle)sdh; + nResult = WFSSrvSearchDirectoryClose(ssdh); + if (nResult == WFS_RESULT_OK) { + WFSCliSearchDirInfo *pSdi; + WFSGetCliSearchDirInfo(&pSdi, sdh); + WFSCliSearchDirInfoFree(pSdi); + } + ((WFSSearchDirectoryCloseCallback)pParamHdr->cb)(nResult, sdh, pParamHdr->pUserData); + break; + } + case WFSSRV_GET_PERMISSIONS: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSTitleId, titleId); + WFSPathName *pAbsPathName = (WFSPathName *)pPtr; + u32 nFlags; + nResult = WFSSrvGetPermissionForUser(pAbsPathName, &nFlags, titleId); + ((WFSGetPermissionsForUserCallback)pParamHdr->cb)(nResult, nFlags, pParamHdr->pUserData); + break; + } + case WFSSRV_SET_PERMISSIONS: { + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, u32, nFlags); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, u32, nMask); + WFSCLI_DECLARE_AND_READ_ASYNC_PARAM_THEN_INC_PTR(pPtr, WFSTitleId, titleId); + WFSPathName *pAbsPathName = (WFSPathName *)pPtr; + nResult = WFSSrvSetPermissionForUser(pAbsPathName, nFlags, nMask, titleId); + ((WFSResultCallback)pParamHdr->cb)(nResult, pParamHdr->pUserData); + break; + } + } +} + +#if _WIN32 +DWORD WINAPI WFSAsyncExecThread(LPVOID pParam); +#elif _RVL +void *WFSAsyncExecThread(void *pParam); +#elif _TWL +void *WFSAsyncExecThread(void *pParam); +#endif + +#if _WIN32 +DWORD WINAPI WFSAsyncExecThread(LPVOID pParam) +#elif _RVL +void *WFSAsyncExecThread(void *pParam) +#elif _TWL +void *WFSAsyncExecThread(void *pParam) +#endif +{ +#pragma unused(pParam) + + (void)osEnableInterrupts(); + dbg(MyOSReport("Starting WFSAsyncExecThread()\n")); + while(1) { + WFSLockMutex(&wcg.ag.mxAccessTheParamQueue); + while (wcg.ag.anchor.pHead == (WFSAsyncParamHdr*)&wcg.ag.anchor) { + if (wcg.bLibInitialized==false) { + WFSSignalCond(&wcg.ag.condParamQueueEmpty); + return NULL; + } + WFSWaitCond(&wcg.ag.condParamQueueNotEmpty, &wcg.ag.mxAccessTheParamQueue); + } + WFSResetCond(&wcg.ag.condParamQueueNotEmpty); + WFSAsyncParamHdr *pParamHdr = wcg.ag.anchor.pHead; + wcg.ag.anchor.pHead = pParamHdr->l.pNext; + pParamHdr->l.pNext->l.pPrev = (WFSAsyncParamHdr*)&wcg.ag.anchor; + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); + WFSExecFunction(pParamHdr); + WFSHeapFree(&wcg.heap, pParamHdr); + } +} + +void WFSAsyncUtilsInit() { + wcg.ag.anchor.pHead = wcg.ag.anchor.pTail = (WFSAsyncParamHdr*)&wcg.ag.anchor; + if (!bMutexInitialized) + { + bMutexInitialized = true; + WFSInitMutex(&wcg.ag.mxAccessTheParamQueue); + WFSInitCond(&wcg.ag.condParamQueueNotEmpty); + } + wcg.ag.pAsyncExecStack = WFSHeapAlloc(&wcg.heap, WFS_ASYNC_EXEC_STACK_SIZE); + WFSCreateThread(&wcg.ag.asyncExecThread, WFSAsyncExecThread, 0, wcg.ag.pAsyncExecStack, WFS_ASYNC_EXEC_STACK_SIZE, 15); + WFSResumeThread(&wcg.ag.asyncExecThread); +} + +void WFSAsyncUtilsClose() { + WFSLockMutex(&wcg.ag.mxAccessTheParamQueue); + WFSSignalCond(&wcg.ag.condParamQueueNotEmpty); // [check] + if (wcg.ag.anchor.pHead != wcg.ag.anchor.pTail) { + WFSWaitCond(&wcg.ag.condParamQueueEmpty, &wcg.ag.mxAccessTheParamQueue); + } + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); + WFSJoinThread(&wcg.ag.asyncExecThread, NULL); + // Assumes all workspace memory will be deleted, so does not bother to free space + // ToDo: blocking wait for last async to finish +} + +static void WfsPrepareAsyncCallCommon(void **ppPtr, u8 nFunction, void *pUserData, void *cb, size_t nOtherParamSize, u32 nSize, WFSAsyncParamHdr *pParamHdr) { + pParamHdr->nSize = nSize; + pParamHdr->nFunction = nFunction; + pParamHdr->cb = cb; + pParamHdr->pUserData = pUserData; + WFSLockMutex(&wcg.ag.mxAccessTheParamQueue); + if (wcg.ag.anchor.pHead == (WFSAsyncParamHdr*)&wcg.ag.anchor) { + // ParamQueue was previously empty, but will now have an entry added. + // It is OK to signal in advance of actually adding the entry, becuase + // the async execution thread won't be able to proceed until we unlock the mutex. + WFSSignalCond(&wcg.ag.condParamQueueNotEmpty); + } + pParamHdr->l.pNext = (WFSAsyncParamHdr*)&wcg.ag.anchor; + pParamHdr->l.pPrev = wcg.ag.anchor.pTail; + wcg.ag.anchor.pTail->l.pNext = pParamHdr; + wcg.ag.anchor.pTail = pParamHdr; + if (nOtherParamSize==0) { + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); + } + if (ppPtr) { + *ppPtr = (void*)((size_t)pParamHdr + sizeof(WFSAsyncParamHdr)); + } +} + +WFSResult WFSPrepareAsyncCall(void **ppPtr, u8 nFunction, void *pUserData, void *cb, size_t nOtherParamSize) { + // This function allocates memory for storing away parameters of asynchronous function calls which do not include path names. + // If any errors occur, it releases the allocated memory and returns with an error code. + // If no errors occur, the memory remains allocated, and a parameter header entry is added to the async execution ParamQueue. + // If nOtherParamSize is 0, the ParamQueue item is complete, and the access mutex is unlocked. + // otherwise, it is assumed that the calling function will fill out the remaining elements and will unlock the mutex. + size_t nTotalAllocSize = sizeof(WFSAsyncParamHdr) + nOtherParamSize; + WFSAsyncParamHdr *pParamHdr = (WFSAsyncParamHdr *)WFSHeapAlloc(&wcg.heap, nTotalAllocSize); + if (pParamHdr == 0) { + return WFS_RESULT_OUT_OF_MEMORY; + } + WfsPrepareAsyncCallCommon(ppPtr, nFunction, pUserData, cb, nOtherParamSize, nTotalAllocSize, pParamHdr); + return WFS_RESULT_OK; +} + +WFSResult WFSPrepareAsyncCallWithPathName(void **ppPtr, const utf8 *sInPathName, + WFSPathNameType nPathType, u8 nFunction, void *pUserData, void *cb, size_t nOtherParamSize) +{ + // This function allocates memory for storing away parameters of asynchronous function calls, including a pathname parameter. + // It resolves, stores, and validates the specified pathname. + // If any errors occur, it releases the allocated memory and returns with an error code. + // If no errors occur, the memory remains allocated, and a parameter header entry is added to the async execution ParamQueue. + // If nOtherParamSize is 0, the ParamQueue item is complete, and the access mutex is unlocked. + // otherwise, it is assumed that the calling function will fill out the remaining elements and will unlock the mutex. + size_t nOffset = sizeof(WFSAsyncParamHdr) + nOtherParamSize; + size_t nTotalAllocSize = nOffset + sizeof(WFSPathName); + WFSAsyncParamHdr *pParamHdr = (WFSAsyncParamHdr *)WFSHeapAlloc(&wcg.heap, nTotalAllocSize); + if (pParamHdr == 0) { + return WFS_RESULT_OUT_OF_MEMORY; + } + WFSPathPartOffsetArray ppoa; + WFSPathName *pPnAbs = (WFSPathName *)((u8*)pParamHdr + nOffset); + WFSResult nResult = WFSPathResolve(pPnAbs, &ppoa, sInPathName, nPathType); + if (nResult != WFS_RESULT_OK) { + WFSHeapFree(&wcg.heap, pParamHdr); + return nResult; + } + WfsPrepareAsyncCallCommon(ppPtr, nFunction, pUserData, cb, nOtherParamSize, nTotalAllocSize, pParamHdr); + return WFS_RESULT_OK; +} + +WFSResult WFSPrepareMoveLocalAsyncCall(void **ppPtr, const utf8 *sSrcPathName, const utf8 *sDstPathName, + WFSPathNameType nPathType, u8 nFunction, void *pUserData, void *cb, size_t nOtherParamSize) +{ + // This function allocates memory for storing away parameters of asynchronous function calls, including a pathname parameter. + // It resolves, stores, and validates the specified pathname. + // If any errors occur, it releases the allocated memory and returns with an error code. + // If no errors occur, the memory remains allocated, and a parameter header entry is added to the async execution ParamQueue. + // If nOtherParamSize is 0, the ParamQueue item is complete, and the access mutex is unlocked. + // otherwise, it is assumed that the calling function will fill out the remaining elements and will unlock the mutex. + size_t nOffset = sizeof(WFSAsyncParamHdr) + nOtherParamSize; + size_t nTotalAllocSize = nOffset + (2 * sizeof(WFSPathName)); + WFSAsyncParamHdr *pParamHdr = (WFSAsyncParamHdr *)WFSHeapAlloc(&wcg.heap, nTotalAllocSize); + if (pParamHdr == 0) { + return WFS_RESULT_OUT_OF_MEMORY; + } + WFSPathPartOffsetArray ppoa; + WFSPathName *pPnSrcAbs = (WFSPathName *)((u8*)pParamHdr + nOffset); + WFSResult nResult = WFSPathResolve(pPnSrcAbs, &ppoa, sSrcPathName, nPathType); + if (nResult != WFS_RESULT_OK) { + goto Error; + } + nOffset += pPnSrcAbs->nLen + sizeof(WFSPathName) - WFS_MAX_PATH_NAME_SIZE - 1; + WFSPathName *pPnDstAbs = (WFSPathName *)((u8*)pParamHdr + nOffset); + nResult = WFSPathResolve(pPnDstAbs, &ppoa, sDstPathName, nPathType); + if (nResult != WFS_RESULT_OK) { + goto Error; + } + if (strncmp(pPnSrcAbs->sStr, pPnDstAbs->sStr, pPnSrcAbs->nLen)==0) { + if (pPnDstAbs->sStr[pPnSrcAbs->nLen]=='/') { + // trying to move a directory to it's own sub-directory + nResult = WFS_RESULT_INVALID; + goto Error; + } + } + nOffset += pPnDstAbs->nLen + sizeof(WFSPathName) - WFS_MAX_PATH_NAME_SIZE - 1; + WfsPrepareAsyncCallCommon(ppPtr, nFunction, pUserData, cb, nOtherParamSize, nOffset, pParamHdr); + return WFS_RESULT_OK; +Error: + WFSHeapFree(&wcg.heap, pParamHdr); + return nResult; +} + +WFSResult WFSPrepareAsyncCallWithDeviceName(void **ppPtr, const utf8 *sDeviceName, + u8 nFunction, void *pUserData, void *cb, size_t nOtherParamSize) +{ + size_t nDeviceNameOffset = sizeof(WFSAsyncParamHdr) + sizeof(const utf8 *) + nOtherParamSize; + size_t nTotalAllocSize = nDeviceNameOffset + sizeof(WFSDeviceName); + WFSAsyncParamHdr *pParamHdr = (WFSAsyncParamHdr *)WFSHeapAlloc(&wcg.heap, nTotalAllocSize); + if (pParamHdr == 0) { + return WFS_RESULT_OUT_OF_MEMORY; + } + void *pPtr = (void*)((size_t)pParamHdr + sizeof(WFSAsyncParamHdr)); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, const utf8 *, sDeviceName); + WFSDeviceName *pDeviceName = (WFSDeviceName *)((u8*)pParamHdr + nDeviceNameOffset); + WFSResult nResult = WFSSetDeviceName(pDeviceName, sDeviceName); + if (nResult != WFS_RESULT_OK) { + WFSHeapFree(&wcg.heap, pParamHdr); + return nResult; + } + WfsPrepareAsyncCallCommon(ppPtr, nFunction, pUserData, cb, nOtherParamSize, nTotalAllocSize, pParamHdr); + if (ppPtr) { + *ppPtr = (void*)((size_t)*ppPtr + sizeof(const utf8 *)); + } + return WFS_RESULT_OK; +} + +WFSResult WFSPrepareAsyncCallWithVolumeId(void **ppPtr, const utf8 *sVolumeId, + u8 nFunction, void *pUserData, void *cb, size_t nOtherParamSize) +{ + size_t nVolumeIdOffset = sizeof(WFSAsyncParamHdr) + sizeof(const utf8 *) + nOtherParamSize; + size_t nTotalAllocSize = nVolumeIdOffset + sizeof(WFSVolumeId); + WFSAsyncParamHdr *pParamHdr = (WFSAsyncParamHdr *)WFSHeapAlloc(&wcg.heap, nTotalAllocSize); + if (pParamHdr == 0) { + return WFS_RESULT_OUT_OF_MEMORY; + } + void *pPtr = (void*)((size_t)pParamHdr + sizeof(WFSAsyncParamHdr)); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, const utf8 *, sVolumeId); + WFSVolumeId *pVolumeId = (WFSVolumeId *)((u8*)pParamHdr + nVolumeIdOffset); + WFSResult nResult = WFSSetVolumeId(pVolumeId, sVolumeId); + if (nResult != WFS_RESULT_OK) { + WFSHeapFree(&wcg.heap, pParamHdr); + return nResult; + } + WfsPrepareAsyncCallCommon(ppPtr, nFunction, pUserData, cb, nOtherParamSize, nTotalAllocSize, pParamHdr); + if (ppPtr) { + *ppPtr = (void*)((size_t)*ppPtr + sizeof(const utf8 *)); + } + return WFS_RESULT_OK; +} + + diff --git a/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Client_Common.cpp b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Client_Common.cpp new file mode 100644 index 0000000..fffb502 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Client_Common.cpp @@ -0,0 +1,1150 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Client_Common.cpp - PPC side of the WFS API. Common to WFS and WFSDev + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Client_Common.cpp,v $ + Revision 1.74 2008/12/10 04:42:22 kondo_masahiro + Added error handling for srcpath include current or home path. + + Revision 1.73 2008/12/04 00:02:09 kondo_masahiro + Fixed WFSFlushAsync(). + + Revision 1.72 2008/12/03 00:16:38 kondo_masahiro + Fixed WFSFlush(). + + Revision 1.71 2008/10/23 11:15:28 nakanose_jin + Open and Search should give a invalid file handle if he fails to execute. + + Revision 1.70 2008/10/21 10:45:20 kondo_masahiro + Added new function WFSWriteFileAndDiscard + + Revision 1.69 2008/10/21 04:14:55 nakanose_jin + (none) + + Revision 1.68 2008/10/20 02:53:37 ueno + Restored WFSExecDebugProcedure() for WFSDEV. + + Revision 1.67 2008/10/20 00:00:22 ueno + Modified WFSExecDebugProcedure() to support WFSDEBUG_CMD_ATTACH and WFSDEBUG_CMD_DETACH options. + + Revision 1.66 2008/10/14 07:02:41 ueno + Fixed WFSOpenFileAsync() to be able to return an error. + + Revision 1.65 2008/10/14 06:00:39 ueno + Fixed WFSCreateAndOpenFileAsync() and WFSOpenFileAsync() to release client file info when WFSPrepareAsyncCallWithPathName() returns an error. + + Revision 1.64 2008/10/07 06:37:01 ueno + Modified WFSExit() to close all open files. + + Revision 1.63 2008/09/29 01:06:19 kondo_masahiro + Added the argument of WFSSrvInit(). + + Revision 1.62 2008/09/05 02:27:19 ooizumi + Fixed a bug WFSGetCurrentDirectory returns a broken path name. + + Revision 1.61 2008/08/19 14:05:43 nakanose_jin + smash pathnames bug + + Revision 1.60 2008/08/08 05:22:29 nakanose_jin + removed ASSERT and return WFS_RESULT_LIB_NOT_INITIALIZED. + + Revision 1.58 2008/07/18 02:59:46 ueno + Renamed WFSDeletePermissions() -> WFSDeleteAccessListEntry(). + + Revision 1.57 2008/07/15 08:43:57 nakanose_jin + change arg order + + Revision 1.56 2008/07/14 07:15:23 ueno + Implemented WFSGetAccessListAsync(), WFSSetAccessListEntryAsync() and WFSDeletePermissionsAsync(). + + Revision 1.55 2008/07/11 09:20:37 ueno + Fixed a typo. + + Revision 1.54 2008/07/10 06:12:37 nakanose_jin + add permissions API + + Revision 1.52 2008/05/10 04:13:13 kondo_masahiro + Fixed WFSExecDebugProcedure + + Revision 1.51 2008/05/09 14:03:12 nakanose_jin + canceling => reduce settitleid argument + + Revision 1.49 2008/04/24 04:26:29 nakanose_jin + byebye nPermissions param + + Revision 1.48 2008/04/18 07:45:03 nakanose_jin + merge acl + + Revision 1.47 2008/04/10 13:35:38 ueno + Added WFSSetPermissionsForUser[Async] and WFSGetPermissionsForUser[Async]. + + Revision 1.46 2008/04/04 06:43:29 nakanose_jin + link error + + Revision 1.45 2008/03/28 14:14:23 nakanose_jin + chance spec of debug proc + + Revision 1.44 2008/02/25 08:47:32 paul + Fixed WFSUnmountVolumeAsync + + Revision 1.43 2008/02/25 08:34:22 paul + BOOL -> WFSBool + + Revision 1.42 2008/02/20 08:10:13 nakanose_jin + add WFSExecDebugProcedure + + Revision 1.41 2008/02/13 01:49:37 nakanose_jin + WFSGetCurrentDirectory : NULL arg + + Revision 1.40 2008/02/08 05:08:50 paul + Updated WFSUnmountVolumeAsync + + Revision 1.39 2008/02/08 05:07:45 paul + Changed BOOL to WFSBool + + Revision 1.38 2008/02/08 03:29:16 paul + Fixed WFSGetCurrentDirectory to return '/' if current directory is '/' - normally trailing '/' is removed. + + Revision 1.37 2008/02/07 13:02:21 nakanose_jin + WFSUnmountVolume : Add force-close option (but only in detach condition) + + Revision 1.36 2008/01/23 00:44:30 ueno + Fixed to copy volume ID only when the result is WFS_RESULT_OK. + + Revision 1.35 2008/01/23 00:07:18 paul + Fixed WFSGetVolumeId to only overwrite buffer when result==WFS_RESULT_OK + + Revision 1.34 2008/01/10 05:33:23 nakanose_jin + validatePathName => validateDirectory + + Revision 1.33 2008/01/09 10:24:50 paul + Added check for pWorkSpaceBuffer==NULL in WFSInit + + Revision 1.32 2008/01/08 12:17:37 ueno + Fixed. + + Revision 1.31 2007/12/27 01:44:08 ueno + Modified WFSExit() to call WFSSrvExit(). + + Revision 1.30 2007/12/26 07:58:30 ueno + Modified WFSInit() to start connecting WFSDEV server. + + Revision 1.29 2007/12/26 00:39:00 paul + typo: DestroyHeap -> HeapDestroy + + Revision 1.28 2007/12/26 00:37:37 paul + Added WFSHeapDestroy() + + Revision 1.27 2007/12/12 08:13:31 paul + Added WFSSrvGetFileSize + + Revision 1.26 2007/12/12 01:08:10 ueno + Modified WFSInit() to remove network initialization code. + + Revision 1.25 2007/12/10 02:48:49 paul + Fixed WFSSetCurrentDirectoryAsync, WFSSetHomeDirectoryAsync + + Revision 1.24 2007/12/07 23:58:11 paul + Changed lib initialization check. Now it always checks for WFSExit, WFSSetCurrentDirectory. For other functions, only check in debug version. + + Revision 1.23 2007/12/06 20:22:48 paul + Fixed a bug in WFSSearchDirectoryNextAsync(). It was incorrectly allocating a search handle. + + Revision 1.22 2007/11/22 02:36:41 paul + made WFSCloseFileAsync return WFS_RESULT_INVALID if nFileSize is > actual file size + + Revision 1.21 2007/11/22 01:59:58 paul + Added nFileSize to WFSCloseFileAsync + + Revision 1.20 2007/11/21 04:17:45 wayne.wong + Many changes that included single request/result RPC messages, bug fixes, code factoring, and English C comment adjustments. + 1. Combined RPC messages into a single request message and single result + message. Except for file reads and writes. + 2. Fixed+factored some Endianess code. + 3. Enabled larger TCP/IP data transfer size. Previous setting was artifically small + to test the code to perform large transfers. + 4. Changed the volume id parameters utf8*->WFSVolumeId for SrvGetVolumeId + and SrvMountDevice. More consistent with the way we send this type at the + RPC layer. + 5. Changed a couple Japanese comments to be compatible with English + comments. In particular, the "//" comment with a backslash at the end of + the line causes the next line of code to be ignored. + 6. Removed Windows-specific debugging output defines for RVL build. + + Revision 1.19 2007/11/20 19:44:58 paul + Added WFSReturnIfLibNotInitialized to WFSFlush(), WFSFlushAsync() + + Revision 1.18 2007/11/16 21:55:33 paul + Changed WFSSrvCloseFile to pass nNewSize instead of bTruncateFlag + + Revision 1.17 2007/11/16 02:04:32 paul + Added WFSFlush() + Removed previous change by Nakanose-san. (NULL pointer was already being checked by WFSSetDeviceName) + + Revision 1.16 2007/11/15 12:59:01 nakanose_jin + TitleID -> TitleId + add nullpointer check + + Revision 1.15 2007/11/09 01:17:01 paul + Added sub-directory validation check for WFSMoveLocal + Fixed validation of path name depth for paths ending in directories + + Revision 1.14 2007/11/06 22:42:37 paul + Added validation checks for NULL pointers passed in + + Revision 1.13 2007/11/02 01:57:53 paul + bugfix + + Revision 1.12 2007/11/02 00:54:31 paul + now logging changes + Changed WFSReadFileAsync, WFSWriteFileAsync to require explicit start position + + +*---------------------------------------------------------------------------*/ + +// File created by Paul Donnelly on 2007.08.29 + +#include "wfs_Client.h" +#include "wfs_Errors.h" +#include "wfssrv_Defs.h" +#include "wfs_AsyncUtils.h" +#include "private/wfs_Debug.h" + +#define WFSReturnIfLibNotInitialized if (!wcg.bLibInitialized) return WFS_RESULT_LIB_NOT_INITIALIZED; + +WFSClientGlobals wcg ATTRIBUTE_ALIGN(4); + +// ToDo: Check start and end of user-supplied buffers + +WFSResult WFSInit(void *pWorkSpaceBuffer, u32 nWorkSpaceSize) { + if (wcg.bLibInitialized) { + return WFS_RESULT_LIB_ALREADY_INITIALIZED; + } + if ( (pWorkSpaceBuffer==NULL) || ((u32)pWorkSpaceBuffer&0x1ff)||(nWorkSpaceSizeWFS_MAX_WORK_SPACE_SIZE) +#if _RVL + || (((u32)pWorkSpaceBuffer&0xf0000000)!=0x90000000) +#endif + ) { + return WFS_RESULT_INVALID; + } + wcg.pWorkSpaceBuffer = pWorkSpaceBuffer; + WFSCreateHeap(&wcg.heap, pWorkSpaceBuffer, WFSCLI_WORK_SPACE_SIZE); + pWorkSpaceBuffer = (void *)((size_t)pWorkSpaceBuffer + WFSCLI_WORK_SPACE_SIZE); + nWorkSpaceSize -= WFSCLI_WORK_SPACE_SIZE; + WFSPathInit(); + WFSCliInitHandles(); + wcg.bLibInitialized = true; + WFSAsyncUtilsInit(); + WFSReturnOnError(WFSSrvInit(pWorkSpaceBuffer, nWorkSpaceSize)); + return WFS_RESULT_OK; +} + +static WFSResult CloseAllFile(void) +{ +// WFSFileHandle fh; + WFSResult result = WFS_RESULT_OK; + WFSCliFileInfo* pFi; + u32 idx; + for (idx=0; idx < WFSCLI_MAX_FILE_HANDLES; ++idx) + { + pFi = &wcg.hnd.aCliFileInfo[idx]; + if (pFi->nNext == WFSCLI_HANDLE_ALLOCATED) + { + // the handle is open. + WFSFileHandle fh = pFi->nHandle; + result = WFSCloseFile(fh, (WFSBool) FALSE); // [check] should wait file access? + if (result != WFS_RESULT_OK && + result != WFS_RESULT_MEDIA_ERROR) + { + break; + } + } + } + + if (result == WFS_RESULT_MEDIA_ERROR) + { + result = WFS_RESULT_OK; + } + return result; +} + + +WFSResult WFSExit() { + if (!wcg.bLibInitialized) return WFS_RESULT_LIB_NOT_INITIALIZED; + WFSReturnOnError(CloseAllFile()); + WFSReturnOnError(WFSSrvExit()); + wcg.bLibInitialized = false; + WFSAsyncUtilsClose(); + WFSHeapDestroy(&wcg.heap); + return WFS_RESULT_OK; +} + +/* +WFSResult WFSExitAsync(void *pUserData, WFSResultCallback cb) { + if (!wcg.bLibInitialized) return WFS_RESULT_LIB_NOT_INITIALIZED; + wcg.bLibInitialized = false; + return WFSPrepareAsyncCall(NULL, WFSSRV_EXIT, pUserData, cb, 0); +} +*/ + +void WFSSetAttachDeviceCallback(utf8 *sDeviceNameBuffer, WFSDeviceCallback cbAttachDevice, void *pUserData) { + if (!wcg.dcg.bMutexInitialized) { + wcg.dcg.bMutexInitialized = true; + WFSInitMutex(&wcg.dcg.mxAccessDeviceCallbackGlobals); + } + WFSLockMutex(&wcg.dcg.mxAccessDeviceCallbackGlobals); + wcg.dcg.pAttachDeviceNameBuffer = sDeviceNameBuffer; + wcg.dcg.cbAttachDevice = cbAttachDevice; + wcg.dcg.pAttachDeviceUserData = pUserData; + WFSUnlockMutex(&wcg.dcg.mxAccessDeviceCallbackGlobals); +} + +void WFSGetAttachDeviceCallback(utf8 **psDeviceName, WFSDeviceCallback *pCbAttachDevice, void **ppUserData) { + if (!wcg.dcg.bMutexInitialized) { + wcg.dcg.bMutexInitialized = true; + WFSInitMutex(&wcg.dcg.mxAccessDeviceCallbackGlobals); + } + WFSLockMutex(&wcg.dcg.mxAccessDeviceCallbackGlobals); + if (psDeviceName) { *psDeviceName = wcg.dcg.pAttachDeviceNameBuffer; } + if (pCbAttachDevice) { *pCbAttachDevice = wcg.dcg.cbAttachDevice; } + if (ppUserData) { *ppUserData = wcg.dcg.pAttachDeviceUserData; } + WFSUnlockMutex(&wcg.dcg.mxAccessDeviceCallbackGlobals); +} + +void WFSSetDetachDeviceCallback(utf8 *sDeviceNameBuffer, WFSDeviceCallback cbDetachDevice, void *pUserData) { + if (!wcg.dcg.bMutexInitialized) { + wcg.dcg.bMutexInitialized = true; + WFSInitMutex(&wcg.dcg.mxAccessDeviceCallbackGlobals); + } + WFSLockMutex(&wcg.dcg.mxAccessDeviceCallbackGlobals); + wcg.dcg.pDetachDeviceNameBuffer = sDeviceNameBuffer; + wcg.dcg.cbDetachDevice = cbDetachDevice; + wcg.dcg.pDetachDeviceUserData = pUserData; + WFSUnlockMutex(&wcg.dcg.mxAccessDeviceCallbackGlobals); +} + +void WFSGetDetachDeviceCallback(utf8 **psDeviceName, WFSDeviceCallback *pCbDetachDevice, void **ppUserData) { + if (!wcg.dcg.bMutexInitialized) { + wcg.dcg.bMutexInitialized = true; + WFSInitMutex(&wcg.dcg.mxAccessDeviceCallbackGlobals); + } + WFSLockMutex(&wcg.dcg.mxAccessDeviceCallbackGlobals); + if (psDeviceName) { *psDeviceName = wcg.dcg.pDetachDeviceNameBuffer; } + if (pCbDetachDevice) { *pCbDetachDevice = wcg.dcg.cbDetachDevice; } + if (ppUserData) { *ppUserData = wcg.dcg.pDetachDeviceUserData; } + WFSUnlockMutex(&wcg.dcg.mxAccessDeviceCallbackGlobals); +} + + +WFSResult WFSGetDeviceInfo(const utf8 *sDeviceName, WFSDeviceInfo *pDi) { + WFSReturnIfLibNotInitialized; + WFSDeviceName devName; + WFSReturnOnNullParameter(pDi); + WFSReturnOnError(WFSSetDeviceName(&devName, sDeviceName)); + return WFSSrvGetDeviceInfo(&devName, pDi); +} + +WFSResult WFSGetDeviceInfoAsync(const utf8 *sDeviceName, WFSDeviceInfo *pDi, void *pUserData, WFSDeviceInfoCallback cb) { + WFSReturnIfLibNotInitialized; + void *pPtr; + size_t nExtraSize = sizeof(WFSDeviceInfo *); + WFSReturnOnNullParameter(pDi); + WFSReturnOnError(WFSPrepareAsyncCallWithDeviceName(&pPtr, sDeviceName, WFSSRV_GET_DEVICE_INFO, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSDeviceInfo *, pDi); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSMountDevice(const utf8 *sDeviceName, utf8 *sVolumeIdBuffer) { + WFSReturnIfLibNotInitialized; + WFSDeviceName devName; + WFSVolumeId volId; + WFSResult result; + + WFSReturnOnNullParameter(sVolumeIdBuffer); + WFSReturnOnError(WFSSetDeviceName(&devName, sDeviceName)); + result = WFSSrvMountDevice(&devName, &volId); + if (result==WFS_RESULT_OK) { + strncpy(sVolumeIdBuffer, volId.sStr, WFS_MAX_VOLUME_ID_SIZE+1); + } + return result; +} + +WFSResult WFSMountDeviceAsync(const utf8 *sDeviceName, utf8 *sVolumeIdBuffer, void *pUserData, WFSDeviceVolumeCallback cb) { + WFSReturnIfLibNotInitialized; + void *pPtr; + size_t nExtraSize = sizeof(const utf8 *); + WFSReturnOnNullParameter(sVolumeIdBuffer); + WFSReturnOnError(WFSPrepareAsyncCallWithDeviceName(&pPtr, sDeviceName, WFSSRV_MOUNT_DEVICE, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, utf8 *, sVolumeIdBuffer); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSUnmountVolume(const utf8 *sVolumeId, WFSBool bForce) { + WFSReturnIfLibNotInitialized; + WFSVolumeId volumeId; + WFSReturnOnError(WFSSetVolumeId(&volumeId, sVolumeId)); + return WFSSrvUnmountVolume(&volumeId, bForce); +} + +WFSResult WFSUnmountVolumeAsync(const utf8 *sVolumeId, WFSBool bForce, void *pUserData, WFSUnmountVolumeCallback cb) { + WFSReturnIfLibNotInitialized; + void *pPtr; + size_t nExtraSize = sizeof(bForce); + WFSReturnOnError(WFSPrepareAsyncCallWithVolumeId(&pPtr, sVolumeId, WFSSRV_UNMOUNT_VOLUME, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSBool, bForce); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSInitializeDevice(const utf8 *sDeviceName) { + WFSReturnIfLibNotInitialized; + WFSDeviceName devName; + WFSReturnOnError(WFSSetDeviceName(&devName, sDeviceName)); + return WFSSrvInitializeDevice(&devName); +} + +WFSResult WFSInitializeDeviceAsync(const utf8 *sDeviceName, void *pUserData, WFSInitializeDeviceCallback cb) { + WFSReturnIfLibNotInitialized; + return WFSPrepareAsyncCallWithDeviceName(NULL, sDeviceName, WFSSRV_INITIALIZE_DEVICE, pUserData, cb, 0); +} + +WFSResult WFSGetVolumeId(const utf8 *sDeviceName, utf8 *sVolumeIdBuffer) { + WFSReturnIfLibNotInitialized; + WFSDeviceName devName; + WFSVolumeId volId; + WFSResult result; + WFSReturnOnNullParameter(sVolumeIdBuffer); + WFSReturnOnError(WFSSetDeviceName(&devName, sDeviceName)); + result = WFSSrvGetVolumeId(&devName, &volId); + if (result==WFS_RESULT_OK) { + strncpy(sVolumeIdBuffer, volId.sStr, WFS_MAX_VOLUME_ID_SIZE+1); + } + return result; +} + +WFSResult WFSGetVolumeIdAsync(const utf8 *sDeviceName, utf8 *sVolumeIdBuffer, void *pUserData, WFSDeviceVolumeCallback cb) { + WFSReturnIfLibNotInitialized; + void *pPtr; + size_t nExtraSize = sizeof(utf8 *); + WFSReturnOnNullParameter(sVolumeIdBuffer); + WFSReturnOnError(WFSPrepareAsyncCallWithDeviceName(&pPtr, sDeviceName, WFSSRV_GET_VOLUME_ID, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, utf8 *, sVolumeIdBuffer); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSGetFreeSpaceSize(const utf8 *sPathName, u64 *pSize) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pSize); + WFSPathName pathNameAbs; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, NULL, sPathName, PATH_TYPE_REL_OR_ABS)); + return WFSSrvGetFreeSpaceSize(&pathNameAbs, pSize); +} + +WFSResult WFSGetFreeSpaceSizeAsync(const utf8 *sPathName, void *pUserData, WFSGetFreeSpaceCallback cb) { + WFSReturnIfLibNotInitialized; + return WFSPrepareAsyncCallWithPathName(NULL, sPathName, PATH_TYPE_REL_OR_ABS, WFSSRV_GET_FREE_SPACE_SIZE, pUserData, cb, 0); +} + +WFSResult WFSSetHomeDirectory(const utf8 *sAbsPathName) { + WFSReturnIfLibNotInitialized; + WFSPathName pathNameAbs; + WFSPathPartOffsetArray ppoa; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, &ppoa, sAbsPathName, PATH_TYPE_ABS_DIR_ONLY)); + WFSReturnOnError(WFSSrvValidateDirectory(&pathNameAbs)); + WFSLockMutex(&wcg.pg.mxAccessPathGlobals); + WFSPathCopy(&wcg.pg.pathHome.pn, &wcg.pg.pathHome.ppoa, &pathNameAbs, &ppoa, true, true); + WFSUnlockMutex(&wcg.pg.mxAccessPathGlobals); + return WFS_RESULT_OK; +} + +WFSResult WFSSetHomeDirectoryAsync(const utf8 *sAbsPathName, void *pUserData, WFSResultCallback cb) { + WFSReturnIfLibNotInitialized; + return WFSPrepareAsyncCallWithPathName(NULL, sAbsPathName, PATH_TYPE_ABS_DIR_ONLY, WFSSRV_SET_HOME_DIRECTORY, pUserData, cb, 0); +} + +WFSResult WFSSetCurrentDirectory(const utf8 *sPathName) { + if (!wcg.bLibInitialized) return WFS_RESULT_LIB_NOT_INITIALIZED; + WFSPathName pathNameAbs; + WFSPathPartOffsetArray ppoa; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, &ppoa, sPathName, PATH_TYPE_REL_OR_ABS)); + WFSReturnOnError(WFSSrvValidateDirectory(&pathNameAbs)); + WFSLockMutex(&wcg.pg.mxAccessPathGlobals); + WFSPathCopy(&wcg.pg.pathCurrent.pn, &wcg.pg.pathCurrent.ppoa, &pathNameAbs, &ppoa, true, true); + WFSUnlockMutex(&wcg.pg.mxAccessPathGlobals); + return WFS_RESULT_OK; +} + +WFSResult WFSSetCurrentDirectoryAsync(const utf8 *sPathName, void *pUserData, WFSResultCallback cb) { + if (!wcg.bLibInitialized) return WFS_RESULT_LIB_NOT_INITIALIZED; + return WFSPrepareAsyncCallWithPathName(NULL, sPathName, PATH_TYPE_REL_OR_ABS, WFSSRV_SET_CURRENT_DIRECTORY, pUserData, cb, 0); +} + +s32 WFSGetCurrentDirectory(utf8 *sAbsPathNameBuffer, s32 nBufferSize) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(sAbsPathNameBuffer); + WFSLockMutex(&wcg.pg.mxAccessPathGlobals); + if (wcg.pg.pathCurrent.pn.nLen > nBufferSize) { + s32 nLength = wcg.pg.pathCurrent.pn.nLen; // This is enough since we remove the trailing '/' + WFSUnlockMutex(&wcg.pg.mxAccessPathGlobals); + return nLength; + } + memcpy(sAbsPathNameBuffer, wcg.pg.pathCurrent.pn.sStr, wcg.pg.pathCurrent.pn.nLen); + int nPos = wcg.pg.pathCurrent.pn.nLen; + if (wcg.pg.pathCurrent.pn.nLen>1 && sAbsPathNameBuffer[wcg.pg.pathCurrent.pn.nLen-1] == '/') { + --nPos; // Removes the trailing '/' unless it is also the first '/' + } + sAbsPathNameBuffer[nPos]=0; // Ensure the return string is properly terminated + WFSUnlockMutex(&wcg.pg.mxAccessPathGlobals); + return WFS_RESULT_OK; +} + +WFSResult WFSCreateDirectory(const utf8 *sPathName, u32 nFlags, u64 nQuota) { + WFSReturnIfLibNotInitialized; + WFSPathName pathNameAbs; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, NULL, sPathName, PATH_TYPE_REL_OR_ABS_DIR)); + return WFSSrvCreateDirectory(&pathNameAbs, nFlags, nQuota); +} + +WFSResult WFSCreateDirectoryAsync(const utf8 *sPathName, u32 nFlags, u64 nQuota, void *pUserData, WFSResultCallback cb) { + WFSReturnIfLibNotInitialized; + void *pPtr; + size_t nExtraSize = sizeof(nFlags) + sizeof(nQuota); + WFSReturnOnError(WFSPrepareAsyncCallWithPathName(&pPtr, sPathName, PATH_TYPE_REL_OR_ABS_DIR, WFSSRV_CREATE_DIRECTORY, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, u32, nFlags); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, u64, nQuota); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSGetAttributes(const utf8 *sPathName, WFSFileAttributes *pFa) { + WFSReturnIfLibNotInitialized; + WFSPathName pathNameAbs; + WFSReturnOnNullParameter(pFa); + WFSReturnOnError(WFSPathResolve(&pathNameAbs, NULL, sPathName, PATH_TYPE_REL_OR_ABS)); + return WFSSrvGetAttributes(&pathNameAbs, pFa); +} + +WFSResult WFSGetAttributesAsync(const utf8 *sPathName, WFSFileAttributes *pFa, void *pUserData, WFSGetAttributesCallback cb) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFa); + void *pPtr; + size_t nExtraSize = sizeof(WFSFileAttributes *); + WFSReturnOnError(WFSPrepareAsyncCallWithPathName(&pPtr, sPathName, PATH_TYPE_REL_OR_ABS, WFSSRV_GET_ATTRIBUTES, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSFileAttributes *, pFa); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSChangePermissions(const utf8 *sPathName, u32 nFlags, u32 nMask) { + WFSReturnIfLibNotInitialized; + WFSPathName pathNameAbs; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, NULL, sPathName, PATH_TYPE_REL_OR_ABS)); + return WFSSrvChangePermissions(&pathNameAbs, nFlags, nMask); +} + +WFSResult WFSChangePermissionsAsync(const utf8 *sPathName, u32 nFlags, u32 nMask, void *pUserData, WFSResultCallback cb) { + WFSReturnIfLibNotInitialized; + void *pPtr; + size_t nExtraSize = sizeof(nFlags) + sizeof(nMask); + WFSReturnOnError(WFSPrepareAsyncCallWithPathName(&pPtr, sPathName, PATH_TYPE_REL_OR_ABS, WFSSRV_CHANGE_PERMISSIONS, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, u32, nFlags); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, u32, nMask); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSDelete(const utf8 *sPathName) { + WFSReturnIfLibNotInitialized; + WFSPathName pathNameAbs; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, NULL, sPathName, PATH_TYPE_REL_OR_ABS)); + return WFSSrvDelete(&pathNameAbs); +} + +WFSResult WFSDeleteAsync(const utf8 *sPathName, void *pUserData, WFSResultCallback cb) { + WFSReturnIfLibNotInitialized; + return WFSPrepareAsyncCallWithPathName(NULL, sPathName, PATH_TYPE_REL_OR_ABS, WFSSRV_DELETE, pUserData, cb, 0); +} + +WFSResult WFSDeleteAccessListEntry(const utf8 *sPathName, WFSTitleId titleId, WFSTitleId entryCreatorId) { + WFSReturnIfLibNotInitialized; + WFSPathName pathNameAbs; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, NULL, sPathName, PATH_TYPE_REL_OR_ABS)); + return WFSSrvDeleteAccessListEntry(&pathNameAbs,titleId,entryCreatorId); +} + +WFSResult WFSDeleteAccessListEntryAsync(const utf8 *sPathName, WFSTitleId titleId, WFSTitleId entryCreatorId, void *pUserData, WFSResultCallback cb) +{ + WFSReturnIfLibNotInitialized; + void *pPtr; + size_t nExtraSize = sizeof(WFSTitleId) * 2; // entryCreatorId and titleId. + WFSReturnOnError(WFSPrepareAsyncCallWithPathName(&pPtr, sPathName, PATH_TYPE_REL_OR_ABS, + WFSSRV_DELETE_ACL_ENTRY, pUserData, cb, nExtraSize)); + + // save arguments. + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSTitleId, titleId); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSTitleId, entryCreatorId); + + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSMoveLocal(const utf8 *sSrcPathName, const utf8 *sDstPathName) { + WFSReturnIfLibNotInitialized; + WFSPathName pathNameAbsSrc, pathNameAbsDst; + WFSReturnOnError(WFSPathResolve(&pathNameAbsSrc, NULL, sSrcPathName, PATH_TYPE_REL_OR_ABS)); + WFSReturnOnError(WFSPathResolve(&pathNameAbsDst, NULL, sDstPathName, PATH_TYPE_REL_OR_ABS)); + // If moved directory is included to the current directory, invalid error is returned. + if (strncmp(pathNameAbsSrc.sStr, wcg.pg.pathCurrent.pn.sStr, pathNameAbsSrc.nLen)==0) { + return WFS_RESULT_INVALID; + } + // If moved directory is included to the home directory, invalid error is returned. + if (strncmp(pathNameAbsSrc.sStr, wcg.pg.pathCurrent.pn.sStr, pathNameAbsSrc.nLen)==0) { + return WFS_RESULT_INVALID; + } + if (strncmp(pathNameAbsSrc.sStr, pathNameAbsDst.sStr, pathNameAbsSrc.nLen)==0) { + if (pathNameAbsDst.sStr[pathNameAbsSrc.nLen]=='/') { + // trying to move a directory to it's own sub-directory + return WFS_RESULT_INVALID; + } + } + return WFSSrvMoveLocal(&pathNameAbsSrc, &pathNameAbsDst); +} + +WFSResult WFSMoveLocalAsync(const utf8 *sSrcPathName, const utf8 *sDstPathName, void *pUserData, WFSResultCallback cb) { + WFSReturnIfLibNotInitialized; + return WFSPrepareMoveLocalAsyncCall(NULL, sSrcPathName, sDstPathName, PATH_TYPE_REL_OR_ABS, WFSSRV_MOVE_LOCAL, pUserData, cb, 0); +} + +// ToDo: Operations which use file handles should lock the file handles + +WFSResult WFSCreateAndOpenFile(const utf8 *sPathName, u32 nFlags, WFSContentIdx nCidx, WFSFileSize nPreAllocateSize, WFSFileHandle *pFh) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFh); + WFSPathName pathNameAbs; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, NULL, sPathName, PATH_TYPE_REL_OR_ABS)); + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSCliFileInfoAlloc(&pFi)); + WFSSrvFileHandle sfh; + WFSResult nResult = WFSSrvCreateAndOpenFile(&pathNameAbs, nFlags, nCidx, nPreAllocateSize, &sfh); + if (nResult != WFS_RESULT_OK) { + WFSCliFileInfoFree(pFi); + return nResult; + } + *pFh = pFi->nHandle |= sfh; + pFi->fa.nFileSize = 0; + pFi->fa.nFlags = nFlags; + pFi->fa.nCidx = nCidx; + pFi->nAccess = WFS_ACCESS_RW; + pFi->nPosition = 0; + pFi->nPreAllocateSize = nPreAllocateSize; + return WFS_RESULT_OK; +} + +WFSResult WFSCreateAndOpenFileAsync(const utf8 *sPathName, u32 nFlags, WFSContentIdx nCidx, u32 nPreAllocateSize, void *pUserData, WFSFileOpCallback cb) { + WFSResult nResult; + WFSReturnIfLibNotInitialized; + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSCliFileInfoAlloc(&pFi)); + void *pPtr; + size_t nExtraSize = sizeof(nFlags) + sizeof(nCidx) + sizeof(nPreAllocateSize) + sizeof(WFSCliFileInfo *); + nResult = WFSPrepareAsyncCallWithPathName(&pPtr, sPathName, PATH_TYPE_REL_OR_ABS, WFSSRV_CREATE_AND_OPEN_FILE, pUserData, cb, nExtraSize); + if (nResult == WFS_RESULT_OK) + { + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, u32, nFlags); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSContentIdx, nCidx); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, u32, nPreAllocateSize); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSCliFileInfo *, pFi); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + } + else + { + WFSCliFileInfoFree(pFi); + } + return nResult; +} + +WFSResult WFSOpenFile(const utf8 *sPathName, WFSAccess nDesiredAccess, WFSFileHandle *pFh) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFh); + WFSPathName pathNameAbs; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, NULL, sPathName, PATH_TYPE_REL_OR_ABS)); + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSCliFileInfoAlloc(&pFi)); + WFSSrvFileHandle sfh; + WFSResult nResult = WFSSrvOpenFile(&pathNameAbs, nDesiredAccess, &sfh, &pFi->fa); + if (nResult != WFS_RESULT_OK) { + WFSCliFileInfoFree(pFi); + *pFh = WFS_INVALID_HANDLE_VALUE; + return nResult; + } + *pFh = pFi->nHandle |= sfh; + pFi->nAccess = nDesiredAccess; + pFi->nPosition = 0; + return WFS_RESULT_OK; +} + +WFSResult WFSOpenFileAsync(const utf8 *sPathName, WFSAccess nDesiredAccess, void *pUserData, WFSFileOpCallback cb) { + WFSReturnIfLibNotInitialized; + WFSResult nResult; + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSCliFileInfoAlloc(&pFi)); + void *pPtr; + size_t nExtraSize = sizeof(nDesiredAccess) + sizeof(WFSCliFileInfo *); + nResult = WFSPrepareAsyncCallWithPathName(&pPtr, sPathName, PATH_TYPE_REL_OR_ABS, WFSSRV_OPEN_FILE, pUserData, cb, nExtraSize); + if (nResult == WFS_RESULT_OK) + { + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSAccess, nDesiredAccess); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSCliFileInfo *, pFi); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + } + else + { + WFSCliFileInfoFree(pFi); + } + return nResult; +} + +WFSResult WFSSetFilePosition(WFSFileHandle fh, WFSFileSize nFilePosition) { + WFSReturnIfLibNotInitialized; + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSGetCliFileInfo(&pFi, fh)); + if (nFilePosition>pFi->fa.nFileSize) { + return WFS_RESULT_INVALID; + } + pFi->nPosition = nFilePosition; + return WFS_RESULT_OK; +} + +WFSResult WFSGetFilePosition(WFSFileHandle fh, WFSFileSize *pFilePosition) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFilePosition); + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSGetCliFileInfo(&pFi, fh)); + *pFilePosition = pFi->nPosition; + return WFS_RESULT_OK; +} + +WFSResult WFSGetFileSize(WFSFileHandle fh, WFSFileSize *pFileSize) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFileSize); + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSGetCliFileInfo(&pFi, fh)); + WFSSrvFileHandle sfh = (WFSSrvFileHandle)fh; + WFSReturnOnError(WFSSrvGetFileSize(sfh, pFileSize)); + return WFS_RESULT_OK; +} + +WFSResult WFSGetFileSizeAsync(WFSFileHandle fh, void *pUserData, WFSGetFileSizeCallback cb) { + WFSReturnIfLibNotInitialized; + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSGetCliFileInfo(&pFi, fh)); + void *pPtr; + size_t nExtraSize = sizeof(fh); + WFSReturnOnError(WFSPrepareAsyncCall(&pPtr, WFSSRV_GET_FILE_SIZE, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSFileHandle, fh); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +s32 WFSGetAccessList(const utf8 *sPathName, WFSAccessListEntry *pAccessList, u32 nMaxElements) +{ + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pAccessList); + WFSPathName pathNameAbs; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, NULL, sPathName, PATH_TYPE_REL_OR_ABS)); + + s32 nResultOrNumEntries = WFSSrvGetAccessList( &pathNameAbs , pAccessList , nMaxElements ); + if( nResultOrNumEntries >= 0) + { + // 正常終了 + } + return nResultOrNumEntries; +} + + +s32 WFSReadFile(WFSFileHandle fh, void *pFileDataBuffer, s32 nSize) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFileDataBuffer); + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSGetCliFileInfo(&pFi, fh)); + if ((pFi->nAccess & WFS_ACCESS_READ) == 0) { + return WFS_RESULT_ACCESS; + } + WFSSrvFileHandle sfh = (WFSSrvFileHandle)fh; + s32 nResultOrNumBytesRead = WFSSrvReadFile(sfh, pFileDataBuffer, pFi->nPosition, nSize); + if (nResultOrNumBytesRead >= 0) { + pFi->nPosition += nResultOrNumBytesRead; + } + return nResultOrNumBytesRead; +} + +WFSResult WFSReadFileAsync(WFSFileHandle fh, void *pFileDataBuffer, WFSFileSize nStartPosition, s32 nSize, void *pUserData, WFSReadFileCallback cb) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFileDataBuffer); + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSGetCliFileInfo(&pFi, fh)); + if ((pFi->nAccess & WFS_ACCESS_READ) == 0) { + return WFS_RESULT_ACCESS; + } + void *pPtr; + size_t nExtraSize = sizeof(fh) + sizeof(pFileDataBuffer) + sizeof(nStartPosition) + sizeof(nSize); + WFSReturnOnError(WFSPrepareAsyncCall(&pPtr, WFSSRV_READ_FILE, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSFileHandle, fh); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, void *, pFileDataBuffer); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSFileSize, nStartPosition); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, s32, nSize); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSWriteFile(WFSFileHandle fh, const void *pFileData, u32 nSize) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFileData); + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSGetCliFileInfo(&pFi, fh)); + if ((pFi->nAccess & WFS_ACCESS_WRITE) == 0) { + return WFS_RESULT_ACCESS; + } + WFSFileSize nNewPosition = pFi->nPosition + nSize; + if (nNewPosition < pFi->nPosition) { // Detects u32 overflow + return WFS_RESULT_FILE_TOO_BIG; + } + WFSSrvFileHandle sfh = (WFSSrvFileHandle)fh; + WFSResult nResult = WFSSrvWriteFile(sfh, pFileData, pFi->nPosition, nSize, FALSE); + if (nResult == WFS_RESULT_OK) { + pFi->nPosition = nNewPosition; + if (pFi->fa.nFileSize < nNewPosition) { + pFi->fa.nFileSize = nNewPosition; + } + } + return nResult; +} + +WFSResult WFSWriteFileAsync(WFSFileHandle fh, const void *pFileData, WFSFileSize nStartPosition, WFSFileSize nSize, void *pUserData, WFSFileOpCallback cb) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFileData); + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSGetCliFileInfo(&pFi, fh)); + if ((pFi->nAccess & WFS_ACCESS_WRITE) == 0) { + return WFS_RESULT_ACCESS; + } + WFSFileSize nNewPosition = nStartPosition + nSize; + if (nNewPosition < nStartPosition) { // Detects u32 overflow + return WFS_RESULT_FILE_TOO_BIG; + } + void *pPtr; + size_t nExtraSize = sizeof(fh) + sizeof(pFileData) + sizeof(nStartPosition) + sizeof(nSize); + WFSReturnOnError(WFSPrepareAsyncCall(&pPtr, WFSSRV_WRITE_FILE, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSFileHandle, fh); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, const void *, pFileData); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSFileSize, nStartPosition); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSFileSize, nSize); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSWriteFileAndDiscard(WFSFileHandle fh, const void *pFileData, u32 nSize) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFileData); + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSGetCliFileInfo(&pFi, fh)); + if ((pFi->nAccess & WFS_ACCESS_WRITE) == 0) { + return WFS_RESULT_ACCESS; + } + WFSFileSize nNewPosition = pFi->nPosition + nSize; + if (nNewPosition < pFi->nPosition) { // Detects u32 overflow + return WFS_RESULT_FILE_TOO_BIG; + } + WFSSrvFileHandle sfh = (WFSSrvFileHandle)fh; + WFSResult nResult = WFSSrvWriteFile(sfh, pFileData, pFi->nPosition, nSize, TRUE); + if (nResult == WFS_RESULT_OK) { + pFi->nPosition = nNewPosition; + if (pFi->fa.nFileSize < nNewPosition) { + pFi->fa.nFileSize = nNewPosition; + } + } + return nResult; +} + +WFSResult WFSWriteFileAndDiscardAsync(WFSFileHandle fh, const void *pFileData, WFSFileSize nStartPosition, WFSFileSize nSize, void *pUserData, WFSFileOpCallback cb) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFileData); + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSGetCliFileInfo(&pFi, fh)); + if ((pFi->nAccess & WFS_ACCESS_WRITE) == 0) { + return WFS_RESULT_ACCESS; + } + WFSFileSize nNewPosition = nStartPosition + nSize; + if (nNewPosition < nStartPosition) { // Detects u32 overflow + return WFS_RESULT_FILE_TOO_BIG; + } + void *pPtr; + size_t nExtraSize = sizeof(fh) + sizeof(pFileData) + sizeof(nStartPosition) + sizeof(nSize); + WFSReturnOnError(WFSPrepareAsyncCall(&pPtr, WFSSRV_WRITE_FILE_AND_DISCARD, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSFileHandle, fh); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, const void *, pFileData); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSFileSize, nStartPosition); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSFileSize, nSize); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSCloseFile(WFSFileHandle fh, WFSBool bTruncateFlag) { + WFSReturnIfLibNotInitialized; + if (fh==WFS_INVALID_HANDLE_VALUE) { + return WFS_RESULT_INVALID; + } + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSGetCliFileInfo(&pFi, fh)); + WFSSrvFileHandle sfh = (WFSSrvFileHandle)fh; + u32 nNewSize = pFi->fa.nFileSize; + if (bTruncateFlag) { + if (pFi->nAccess & WFS_ACCESS_WRITE) { + nNewSize = pFi->nPosition; + } else { + return WFS_RESULT_ACCESS; + } + } + WFSResult nResult = WFSSrvCloseFile(sfh, nNewSize); + if (nResult == WFS_RESULT_OK) { + WFSCliFileInfoFree(pFi); + } + return nResult; +} + +WFSResult WFSFlush(const utf8 *sVolumeId) { + WFSReturnIfLibNotInitialized; + WFSVolumeId volumeId; + WFSReturnOnError(WFSSetVolumeId(&volumeId, sVolumeId)); + return WFSSrvFlush(&volumeId); +} + +WFSResult WFSFlushAsync(const utf8 *sVolumeId, void *pUserData, WFSResultCallback cb) { + WFSReturnIfLibNotInitialized; + return WFSPrepareAsyncCallWithVolumeId(NULL, sVolumeId, WFSSRV_FLUSH, pUserData, cb, 0); +} + + +WFSResult WFSCloseFileAsync(WFSFileHandle fh, WFSBool bTruncateFlag, WFSFileSize nFileSize, void *pUserData, WFSFileOpCallback cb) { + WFSReturnIfLibNotInitialized; + if (fh==WFS_INVALID_HANDLE_VALUE) { + return WFS_RESULT_INVALID; + } + WFSCliFileInfo *pFi; + WFSReturnOnError(WFSGetCliFileInfo(&pFi, fh)); + u32 nNewSize = pFi->fa.nFileSize; + if (bTruncateFlag) { + if (pFi->nAccess & WFS_ACCESS_WRITE) { + nNewSize = nFileSize; + if (nNewSize > pFi->fa.nFileSize) { + return WFS_RESULT_INVALID; + } + } else { + return WFS_RESULT_ACCESS; + } + } + void *pPtr; + size_t nExtraSize = sizeof(fh) + sizeof(nNewSize); + WFSReturnOnError(WFSPrepareAsyncCall(&pPtr, WFSSRV_CLOSE_FILE, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSFileHandle, fh); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSFileSize, nNewSize); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSSearchDirectoryFirst(const utf8 *sPattern, WFSSearchDirectoryHandle *pSdh, WFSFileInfo *pFi) { + WFSReturnIfLibNotInitialized; + if ((pSdh==NULL)||(pFi==NULL)) { + return WFS_RESULT_INVALID; + } + WFSPathName pathNameAbsPattern; + WFSReturnOnError(WFSPathResolve(&pathNameAbsPattern, NULL, sPattern, PATH_TYPE_PATTERN)); + WFSCliSearchDirInfo *pSdi; + WFSReturnOnError(WFSCliSearchDirInfoAlloc(&pSdi)); + WFSSrvSearchDirectoryHandle ssdh; + WFSResult nResult = WFSSrvSearchDirectoryFirst(&pathNameAbsPattern, &ssdh, pFi); + if (nResult != WFS_RESULT_OK) { + *pSdh = WFS_INVALID_HANDLE_VALUE; + WFSCliSearchDirInfoFree(pSdi); + return nResult; + } + *pSdh = pSdi->nHandle |= ssdh; + return WFS_RESULT_OK; +} + +WFSResult WFSSearchDirectoryFirstAsync(const utf8 *sPattern, WFSFileInfo *pFi, void *pUserData, WFSSearchDirectoryCallback cb) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFi); + WFSCliSearchDirInfo *pSdi; + WFSReturnOnError(WFSCliSearchDirInfoAlloc(&pSdi)); + void *pPtr; + size_t nExtraSize = sizeof(WFSCliSearchDirInfo *) + sizeof(pFi); + WFSReturnOnError(WFSPrepareAsyncCallWithPathName(&pPtr, sPattern, PATH_TYPE_PATTERN, WFSSRV_SEARCH_DIRECTORY_FIRST, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSCliSearchDirInfo *, pSdi); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSFileInfo *, pFi); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSSearchDirectoryNext(WFSSearchDirectoryHandle sdh, WFSFileInfo *pFi) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFi); + WFSCliSearchDirInfo *pSdi; + WFSReturnOnError(WFSGetCliSearchDirInfo(&pSdi, sdh)); + WFSSrvSearchDirectoryHandle ssdh = (WFSSrvSearchDirectoryHandle)sdh; + return WFSSrvSearchDirectoryNext(ssdh, pFi); +} + +WFSResult WFSSearchDirectoryNextAsync(WFSSearchDirectoryHandle sdh, WFSFileInfo *pFi, void *pUserData, WFSSearchDirectoryCallback cb) { + WFSReturnIfLibNotInitialized; + WFSReturnOnNullParameter(pFi); + void *pPtr; + size_t nExtraSize = sizeof(sdh) + sizeof(WFSFileInfo *); + WFSReturnOnError(WFSPrepareAsyncCall(&pPtr, WFSSRV_SEARCH_DIRECTORY_NEXT, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSSearchDirectoryHandle, sdh); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSFileInfo *, pFi); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSSearchDirectoryClose(WFSSearchDirectoryHandle sdh) { + WFSReturnIfLibNotInitialized; + if (sdh==WFS_INVALID_HANDLE_VALUE) { + return WFS_RESULT_INVALID; + } + WFSCliSearchDirInfo *pSdi; + WFSReturnOnError(WFSGetCliSearchDirInfo(&pSdi, sdh)); + WFSSrvSearchDirectoryHandle ssdh = (WFSSrvSearchDirectoryHandle)sdh; + WFSResult nResult = WFSSrvSearchDirectoryClose(ssdh); + if (nResult == WFS_RESULT_OK) { + WFSCliSearchDirInfoFree(pSdi); + } + return nResult; +} + +WFSResult WFSSearchDirectoryCloseAsync(WFSSearchDirectoryHandle sdh, void *pUserData, WFSSearchDirectoryCloseCallback cb) { + WFSReturnIfLibNotInitialized; + if (sdh==WFS_INVALID_HANDLE_VALUE) { + return WFS_RESULT_INVALID; + } + WFSCliSearchDirInfo *pSdi; + WFSReturnOnError(WFSGetCliSearchDirInfo(&pSdi, sdh)); + void *pPtr; + size_t nExtraSize = sizeof(sdh); + WFSReturnOnError(WFSPrepareAsyncCall(&pPtr, WFSSRV_SEARCH_DIRECTORY_CLOSE, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSSearchDirectoryHandle, sdh); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + + +WFSResult WFSGetPermissionsForUser(const utf8 *sPathName, u32 *pFlags, WFSTitleId titleId) +{ + WFSReturnIfLibNotInitialized; + WFSPathName pathNameAbs; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, NULL, sPathName, PATH_TYPE_REL_OR_ABS)); + return WFSSrvGetPermissionForUser(&pathNameAbs, pFlags, titleId); +} + +WFSResult WFSGetPermissionsForUserAsync(const utf8 *sPathName, WFSTitleId titleId, void *pUserData, WFSGetPermissionsForUserCallback cb) +{ + WFSReturnIfLibNotInitialized; + void *pPtr; // for other params. + size_t nExtraSize = sizeof(WFSTitleId); + + WFSReturnOnError(WFSPrepareAsyncCallWithPathName(&pPtr, sPathName, PATH_TYPE_REL_OR_ABS, WFSSRV_GET_PERMISSIONS, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSTitleId, titleId); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSSetPermissionsForUser(const utf8 *sPathName, u32 nFlags, u32 nMask, WFSTitleId titleId) +{ + WFSReturnIfLibNotInitialized; + WFSPathName pathNameAbs; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, NULL, sPathName, PATH_TYPE_REL_OR_ABS)); + return WFSSrvSetPermissionForUser(&pathNameAbs, nFlags, nMask, titleId); +} + +WFSResult WFSSetAccessListEntry(const utf8 *sPathName, u32 nFlags, u32 nMask, WFSTitleId titleId) +{ + WFSReturnIfLibNotInitialized; + WFSPathName pathNameAbs; + WFSReturnOnError(WFSPathResolve(&pathNameAbs, NULL, sPathName, PATH_TYPE_REL_OR_ABS)); + return WFSSrvSetAccessListEntry(&pathNameAbs, nFlags, nMask, titleId); +} + +WFSResult WFSSetAccessListEntryAsync(const utf8 *sPathName, u32 nFlags, u32 nMask, WFSTitleId titleId, void *pUserData, WFSResultCallback cb) +{ + WFSReturnIfLibNotInitialized; + void *pPtr; + size_t nExtraSize = sizeof(u32) * 2 + sizeof(WFSTitleId); // nFlags, nMask and titleId. + WFSReturnOnError(WFSPrepareAsyncCallWithPathName(&pPtr, sPathName, PATH_TYPE_REL_OR_ABS, + WFSSRV_SET_ACL_ENTRY, pUserData, cb, nExtraSize)); + + // save arguments. + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, u32, nFlags); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, u32, nMask); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSTitleId, titleId); + + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSGetAccessListAsync(const utf8 *sPathName, WFSAccessListEntry *pAccessList, u32 nMaxElements, void *pUserData, WFSGetAccessListCallback cb) +{ + WFSReturnIfLibNotInitialized; + void *pPtr; + WFSReturnOnNullParameter(pAccessList); + + size_t nExtraSize = sizeof(WFSAccessListEntry*) + sizeof(u32); // pAccessList and nMaxElements. + + WFSReturnOnError(WFSPrepareAsyncCallWithPathName(&pPtr, sPathName, PATH_TYPE_REL_OR_ABS, WFSSRV_GET_ACL, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, WFSAccessListEntry*, pAccessList); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, u32, nMaxElements); + + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSSetPermissionsForUserAsync(const utf8 *sPathName, u32 nFlags, u32 nMask, + WFSTitleId titleId, void *pUserData, WFSResultCallback cb) +{ + WFSReturnIfLibNotInitialized; + void *pPtr; // for other params. + size_t nExtraSize = sizeof(u32) + sizeof(u32) + sizeof(WFSTitleId); + + WFSReturnOnError(WFSPrepareAsyncCallWithPathName(&pPtr, sPathName, PATH_TYPE_REL_OR_ABS, WFSSRV_SET_PERMISSIONS, pUserData, cb, nExtraSize)); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, u32, nFlags); + WFSCLI_WRITE_ASYNC_PARAM_AND_INC_PTR(pPtr, u32, nMask); + WFSCLI_WRITE_ASYNC_PARAM(pPtr, WFSTitleId, titleId); + WFSUnlockMutex(&wcg.ag.mxAccessTheParamQueue); // Note: This is needed only if (nExtraSize != 0) + return WFS_RESULT_OK; +} + +WFSResult WFSDebugSetTitleId(WFSTitleId titleId); + +WFSResult WFSDebugSetTitleId(WFSTitleId titleId) { + WFSReturnIfLibNotInitialized; + return WFSSrvSetTitleId(titleId,0); +} + +WFSResult WFSExecDebugProcedure( u32 cmd, void *arg0, void *arg1 ) +{ + /*if(cmd != WFSDEBUG_CMD_SHIM_WORKSPACE){ + WFSReturnIfLibNotInitialized; + }*/ + return WFSSrvExecDebugProcedure( cmd , arg0 , arg1 ); +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Debug.cpp b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Debug.cpp new file mode 100644 index 0000000..80d8b41 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Debug.cpp @@ -0,0 +1,170 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFS library + File: wfs_Debug.cpp - implementation of debugging routines for WFS + implementation + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Debug.cpp,v $ + Revision 1.14 2008/12/10 06:55:50 kondo_masahiro + Added the new device types WFS_DEVTYPE_USB_MSC_??. + + Revision 1.13 2008/10/23 11:15:28 nakanose_jin + Open and Search should give a invalid file handle if he fails to execute. + + Revision 1.12 2008/07/15 08:43:57 nakanose_jin + change arg order + + Revision 1.11 2008/06/25 01:00:08 nakanose_jin + add control level error + + Revision 1.10 2008/04/21 04:39:42 nakanose_jin + merging acl + + Revision 1.9 2008/04/18 07:45:03 nakanose_jin + merge acl + + Revision 1.8 2008/03/26 01:18:02 nakanose_jin + move wfs_Debug.h from local to private folder. + + Revision 1.7 2008/02/08 09:52:05 paul + Added WFS_RESULT_DEV_IN_USE + + Revision 1.6 2008/02/07 13:02:21 nakanose_jin + WFSUnmountVolume : Add force-close option (but only in detach condition) + + Revision 1.5 2007/12/26 10:25:51 paul + Changed to use WFS_RANGE_CHK, WFS_INDEX_COUNT from wfs_defs.h, instead of linking jut_utility.cpp + + Revision 1.4 2007/12/17 13:29:17 nakanose_jin + add debug utility function + + Revision 1.3 2007/11/02 00:55:00 paul + now logging changes + +*---------------------------------------------------------------------------*/ + +#include "wfs_Defs.h" +#include "private/wfs_Debug.h" + +// Print to stdout for now via printf's + +void WFSDevTypePrint(WFSDevType devType) { + switch(devType) { + case WFS_DEVTYPE_NONE: + printf("WFS_DEVTYPE_NONE"); + break; + case WFS_DEVTYPE_SD: + printf("WFS_DEVTYPE_SD"); + break; + case WFS_DEVTYPE_USB_MSC_10: + printf("WFS_DEVTYPE_USB_MSC_10"); + break; + case WFS_DEVTYPE_USB_MSC_11: + printf("WFS_DEVTYPE_USB_MSC_11"); + break; + case WFS_DEVTYPE_USB_MSC_20: + printf("WFS_DEVTYPE_USB_MSC_20"); + break; + default: + printf("unknown"); + } +} + +void WFSDevInfoPrint(WFSDeviceInfo *pDevInfo) { + printf("DevTotalCapacity (MB) = %I64u\n", pDevInfo->nDevTotalCapacity/(1024*1024)); + printf("DevType = "); WFSDevTypePrint((WFSDevType)pDevInfo->nDevType); printf("\n"); + printf("DevFlags = 0x%1x\n", pDevInfo->nDevFlags); +} + +void WFSFileAttrPrint(WFSFileAttributes *pFileAttr) { + if (pFileAttr->nFlags & WFS_FLAG_IS_A_DIRECTORY) + printf("NumEntries = %u\n", pFileAttr->nNumEntries); + else + printf("FileSize (MB) = %I64u\n", pFileAttr->nFileSize/(1024*1024)); + + printf("Permissions = 0x%8x\n", pFileAttr->nFlags); + // printf("ContentIdx = %u\n", pFileAttr->nNumEntries); + printf("timeCreated = %u\n", pFileAttr->timeCreated); + printf("timeUpdated = %u\n", pFileAttr->timeUpdated); +} + +void WFSFileInfoPrint(WFSFileInfo *pFileInfo) { + WFSFileAttrPrint(&pFileInfo->attr); + printf("sFilename = %s\n", pFileInfo->sFileName); +} + +static char *_result_strings[] = { + "OK ", + "BUSY ", + "OUT_OF_MEMORY ", + "INVALID ", + "ACCESS ", + "LIB_NOT_INITIAL", + "LIB_ALREADY_INI", + "FILE_TOO_BIG ", + "NO_CHANGE_SIZE ", + "MEDIA_ERROR ", + "DEV_UNUSABLE ", + "DEV_NOT_INITIAL", + "DEV_IN_USE ", + "VOL_ID_ERROR ", + "WRITE_PROTECTED", + "ALREADY_MOUNTED", + "PERMISSION ", + "PERMISSION_CL ", + "ACL_FULL ", + "ACL_NOT_FOUND ", + "AUTHENTICATION ", + "CORRUPTION ", + "DIRECTORY_QUOTA", + "MAX_HANDLES ", + "ALREADY_EXISTS ", + "NOT_FOUND ", + "NOT_EMPTY ", + "NOT_FILE ", + "NOT_DIRECTORY ", + "FILE_OPEN ", + "LOCKED ", + "RESOURCE_LIMIT_", + "" + }; + +static char *_result_strings2[] = { + "NOT_IMPLEMENTED", + "UNKNOWN ", + "FATAL_ERROR " + }; + +/*--------------------------------------------------------------------------*/ +//! \fn iiFSDev_PrintResult(WFSResult result) +//! \par 説明: +//! +//! \param result +//! \return +/*--------------------------------------------------------------------------*/ + +const char * +WFSDebug_GetResultString(WFSResult result) +{ + s32 idx = -1 * (s32)result; + if (WFS_RANGE_CHK(idx , 0 , WFS_INDEX_COUNT(_result_strings))) + { + return _result_strings[idx]; + } + else if (WFS_RANGE_CHK(idx , -WFS_RESULT_NOT_IMPLEMENTED , -WFS_RESULT_NOT_IMPLEMENTED+WFS_INDEX_COUNT(_result_strings2)) ) + { + return _result_strings2[idx+WFS_RESULT_NOT_IMPLEMENTED]; + } + else + { + return "???"; + } +} + diff --git a/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Heap.cpp b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Heap.cpp new file mode 100644 index 0000000..71fcb0b --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Heap.cpp @@ -0,0 +1,119 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Heap.cpp + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Heap.cpp,v $ + Revision 1.8 2007/12/26 04:26:18 paul + changed pAllocator to &allocator + + Revision 1.7 2007/12/26 04:14:14 paul + Changed RVL version of WFSHeap + + Revision 1.6 2007/12/26 00:19:07 paul + Added WFSHeapDestroy() + + Revision 1.5 2007/12/25 14:03:49 ueno + Modified to initialize mutex, thread and heap only once. + + Revision 1.4 2007/11/02 00:55:27 paul + now logging changes + +*---------------------------------------------------------------------------*/ + +#include "wfs_Heap.h" + +#undef dbg +#if _DEBUG_HEAP +#define dbg(s) s +#else +#define dbg(s) +#endif + +#if _WIN32 + +dbg(u32 nSizeAvaliable=0;) + +void WFSCreateHeap(WFSHeap *pHeap, void *pBase, size_t nSize) { + *pHeap = HeapCreate(0, nSize, nSize); + dbg(nSizeAvaliable = nSize); +} + +void *WFSHeapAlloc(WFSHeap *pHeap, size_t nSize) { + void *pAddr = HeapAlloc(*pHeap, 0, nSize); + dbg(nSizeAvaliable -= nSize; + MyOSReport("A:Heap:%d\n", nSizeAvaliable)); + return pAddr; +} + +void WFSHeapFree(WFSHeap *pHeap, void *pAddr) { + dbg(nSizeAvaliable += HeapSize(pHeap, NULL, pAddr); + MyOSReport("F:Heap:%d\n", nSizeAvaliable)); + HeapFree(*pHeap, 0, pAddr); +} + +void WFSHeapDestroy(WFSHeap *pHeap) { + dbg(MyOSReport("WFSHeapDestroy()\n")); + HeapDestroy(*pHeap); +} + +//-- twl modified +#elif _TWL + +void WFSCreateHeap(WFSHeap *pHeap, void *pBase, size_t nSize) { + osTPrintf( "%s needs modify.\n", __FUNCTION__); + //main.cで行っている +} + +void *WFSHeapAlloc(WFSHeap *pHeap, size_t nSize) { +// void *pAddr = OS_AllocFromHeap( OS_ARENA_MAIN_SUBPRIV, *pHeap, nSize); + void *pAddr = osAlloc( nSize); + if( pAddr == NULL) { + osTPrintf( "%s error!\n", __FUNCTION__); + } + return pAddr; +} + +void WFSHeapFree(WFSHeap *pHeap, void *pAddr) { + osFree( pAddr); + // OS_FreeToHeap( OS_ARENA_MAIN_SUBPRIV, *pHeap, pAddr); +} + +void WFSHeapDestroy(WFSHeap *pHeap) { + osTPrintf( "%s needs modify.\n", __FUNCTION__); +// OS_DestroyHeap( OS_ARENA_MAIN_SUBPRIV, *pHeap); +} +//-- twl modified + +#elif _RVL + +void WFSCreateHeap(WFSHeap *pHeap, void *pBase, size_t nSize) { + pHeap->handle = MEMCreateExpHeap(pBase, nSize); + MEMInitAllocatorForExpHeap(&pHeap->allocator, pHeap->handle, WFS_HEAP_DEFAULT_ALIGNMENT); +} + +void *WFSHeapAlloc(WFSHeap *pHeap, size_t nSize) { +// printf("==> %s:%d pHeap: 0x%08x size: %d\n", __FILE__, __LINE__, pHeap->pAllocator, nSize); + void *pAddr = MEMAllocFromAllocator(&pHeap->allocator, nSize); +// printf("==> %s:%d pAddr: 0x%08x\n", __FILE__, __LINE__, pAddr); + return pAddr; +} + +void WFSHeapFree(WFSHeap *pHeap, void *pAddr) { + MEMFreeToAllocator(&pHeap->allocator, pAddr); +} + +void WFSHeapDestroy(WFSHeap *pHeap) { + MEMDestroyExpHeap(pHeap->handle); +} + + +#endif diff --git a/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Mutex.cpp b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Mutex.cpp new file mode 100644 index 0000000..6dd17c5 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Mutex.cpp @@ -0,0 +1,242 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Mutex.cpp + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Mutex.cpp,v $ + Revision 1.9 2008/04/19 05:53:50 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.8 2007/12/27 01:43:19 ueno + Added WFSIsThreadTerminated() and WFSJoinThread(). + + Revision 1.7 2007/12/25 14:01:49 ueno + Added WFSSuspendThread(). + + Revision 1.6 2007/11/02 01:00:36 paul + now logging changes + +*---------------------------------------------------------------------------*/ + +#include "wfs_Mutex.h" + +#undef dbg +#if _DEBUG_MUTEX +#define dbg(s) s +#else +#define dbg(s) +#endif + +#if _WIN32 + +dbg(u32 aSignalCounter[0x2000]); + +void WFSInitMutex(WFSMutex *pMx) { + pMx->hHandle = CreateMutex(NULL, false, NULL); + ReleaseMutex(pMx->hHandle); + dbg(aSignalCounter[(u32)pMx->hHandle&0x1fff]=1; + MyOSReport("InitMutex(%x:%d)\n", pMx->hHandle, aSignalCounter[(u32)pMx->hHandle&0x1fff])); +} + +void WFSLockMutex(WFSMutex *pMx) { + dbg(MyOSReport("Wait(%x:%d)\n", pMx->hHandle, aSignalCounter[(u32)pMx->hHandle&0x1fff])); + WaitForSingleObject(pMx->hHandle, INFINITE); + dbg(aSignalCounter[(u32)pMx->hHandle&0x1fff]--); +} + +bool WFSTryLockMutex(WFSMutex *pMx) { + return (WaitForSingleObject(pMx->hHandle, 0) != WAIT_TIMEOUT); +} + +void WFSUnlockMutex(WFSMutex *pMx) { + dbg(aSignalCounter[(u32)pMx->hHandle&0x1fff]++; + MyOSReport("Release(%x:%d)\n", pMx->hHandle, aSignalCounter[(u32)pMx->hHandle&0x1fff])); + ReleaseMutex(pMx->hHandle); +} + +void WFSInitCond(WFSCond *pCond) { + pCond->hAutoResetEvent = CreateEvent(NULL, false, false, NULL); + dbg(aSignalCounter[(u32)pCond->hAutoResetEvent&0x1fff]=0; + MyOSReport("InitCond(%x:%d)\n", pCond->hAutoResetEvent, aSignalCounter[(u32)pCond->hAutoResetEvent&0x1fff])); + //ResetEvent(pCond->hAutoResetEvent); + //pCond->hManualResetEvent = CreateEvent(NULL, true, false, NULL); +} + +void WFSSignalCond(WFSCond *pCond) { + //PulseEvent(pCond->hAutoResetEvent); + dbg(aSignalCounter[(u32)pCond->hAutoResetEvent&0x1fff]++; + MyOSReport("Signal(%x:%d)\n", pCond->hAutoResetEvent, aSignalCounter[(u32)pCond->hAutoResetEvent&0x1fff])); + SetEvent(pCond->hAutoResetEvent); +} + +void WFSWaitCond(WFSCond *pCond, WFSMutex* pMx) { +#if 1 + dbg(aSignalCounter[(u32)pMx->hHandle&0x1fff]++; + MyOSReport("Signal(%x:%d) And Wait(%x:%d)\n", pMx->hHandle, aSignalCounter[(u32)pMx->hHandle&0x1fff], pCond->hAutoResetEvent, aSignalCounter[(u32)pCond->hAutoResetEvent&0x1fff])); + DWORD nRet = SignalObjectAndWait(pMx->hHandle, pCond->hAutoResetEvent, INFINITE, false); + dbg(aSignalCounter[(u32)pCond->hAutoResetEvent&0x1fff]--); +#else + ReleaseMutex(pMx->hHandle); + WaitForSingleObject(pCond->hAutoResetEvent, INFINITE); +#endif + dbg(MyOSReport("Wait(%x:%d)\n", pMx->hHandle, aSignalCounter[(u32)pMx->hHandle&0x1fff])); + WaitForSingleObject(pMx->hHandle, INFINITE); + dbg(aSignalCounter[(u32)pMx->hHandle&0x1fff]--); +} + +void WFSResetCond(WFSCond *pCond) { + ResetEvent(pCond->hAutoResetEvent); +} + +bool WFSCreateThread(WFSThread *pThread, + WFSThreadFunc threadFunc, + void* param, + void* stackBase, + u32 stackSize, + OSPriority priority) +{ + pThread->hThread = CreateThread(NULL, stackSize, threadFunc, param, CREATE_SUSPENDED, 0); + SetThreadPriority(pThread->hThread, 16-priority); + return true; +} + +s32 WFSResumeThread(WFSThread *pThread) { + return ResumeThread(pThread->hThread); +} + +void WFSCancelThread(WFSThread *pThread) { + // Note: On windows, this does not do any cleanup - should avoid using + TerminateThread(pThread->hThread, 0); +} + +void WFSExitThread(void *pVal) { + ExitThread((DWORD)pVal); +} + +s32 WFSSuspendThread(WFSThread *pThread) +{ + return SuspendThread(pThread->hThread); +} + +bool WFSIsThreadTerminated(WFSThread *pThread) +{ + switch (WaitForSingleObject(pThread->hThread, 0)) + { + case WAIT_TIMEOUT: + return false; + case WAIT_OBJECT_0: // the thread has exited. + case WAIT_ABANDONED: // [check] + case WAIT_FAILED: // the thread does not exist. [check] should check error code? + default: + break; + } + + return true; +} + +bool WFSJoinThread(WFSThread *pThread, void** val) +{ +#pragma unused (val) // exit value is not supported. + switch (WaitForSingleObject(pThread->hThread, INFINITE)) + { + case WAIT_OBJECT_0: + return true; + case WAIT_TIMEOUT: + case WAIT_ABANDONED: + case WAIT_FAILED: + default: + break; + } + return false; +} + + +#elif _RVL + + +bool WFSCreateThread(WFSThread *pThread, + WFSThreadFunc threadFunc, + void* param, + void* stackBase, + u32 stackSize, + OSPriority priority) +{ + return OSCreateThread(pThread, threadFunc, param, (void*)((u32)stackBase+stackSize), stackSize, priority, 0); // joinable +} + + +//-- twl modified +#elif _TWL +typedef void (*MyThreadFunc)(void*); +bool WFSCreateThread(WFSThread *pThread, + WFSThreadFunc threadFunc, + void* param, + void* stackBase, + u32 stackSize, + OSPriority priority) +{ + osCreateThread( pThread, (MyThreadFunc)threadFunc, param, (void*)((u32)stackBase+stackSize), stackSize, priority); + return true; +} + +s32 WFSResumeThread(WFSThread *pThread) { + osWakeupThreadDirect( pThread); +// osTPrintf( "Need TWL modifies.\n"); + return 0; +} + +void WFSCancelThread(WFSThread *pThread) { + osDestroyThread( pThread); +} + +void WFSExitThread(void *pVal) { + osExitThread(); +} + +s32 WFSSuspendThread(WFSThread *pThread) +{ + osTPrintf( "Need TWL modifies.\n"); + return 0; +} + +bool WFSIsThreadTerminated(WFSThread *pThread) +{ + return( osIsThreadTerminated( pThread)); +} + +bool WFSJoinThread(WFSThread *pThread, void** val) +{ +#pragma unused (val) // exit value is not supported. + osJoinThread( pThread); + return true; +} + +void WFSInitCond(WFSCond *pCond) { + osInitEvent( pCond); +} + +void WFSSignalCond(WFSCond *pCond) { + osSignalEvent( pCond, 1); +} + +void WFSWaitCond(WFSCond *pCond, WFSMutex* pMx) { + osUnlockMutex( pMx); + osWaitEventEx( pCond, 1, OS_EVENT_MODE_OR, 1); //イベント待ち後にクリアを伴う +} + +void WFSResetCond(WFSCond *pCond) { + osClearAllEvent( pCond); + return; +} + +//-- twl modified + +#endif diff --git a/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Names.cpp b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Names.cpp new file mode 100644 index 0000000..6eda6c2 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_Names.cpp @@ -0,0 +1,71 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_Names.cpp - Functions for setting and validating name types + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_Names.cpp,v $ + Revision 1.5 2007/11/19 13:28:27 nakanose_jin + bug fix for null pointer check + + Revision 1.4 2007/11/06 22:42:56 paul + Added validation checks for NULL pointers passed in + + Revision 1.3 2007/11/02 01:01:00 paul + now logging changes + +*---------------------------------------------------------------------------*/ + +#include "wfs_Names.h" +#include + +WFSResult WFSSetPathName(WFSPathName *pPathName, const utf8 *sPathName) { + WFSReturnOnNullParameter(sPathName); + u32 nStrLen = strlen(sPathName); + if (nStrLen > WFS_MAX_PATH_NAME_SIZE) { + return WFS_RESULT_INVALID; + } + pPathName->nLen = (WFSPathNameLengthType)nStrLen; + strcpy(pPathName->sStr, sPathName); + return WFS_RESULT_OK; +} + +WFSResult WFSSetFileName(WFSFileName *pFileName, const utf8 *sFileName) { + WFSReturnOnNullParameter(sFileName); + u32 nStrLen = strlen(sFileName); + if (nStrLen > WFS_MAX_FILE_NAME_SIZE) { + return WFS_RESULT_INVALID; + } + pFileName->nLen = (WFSFileNameLengthType)nStrLen; + strcpy(pFileName->sStr, sFileName); + return WFS_RESULT_OK; +} + +WFSResult WFSSetDeviceName(WFSDeviceName *pDeviceName, const utf8 *sDeviceName) { + WFSReturnOnNullParameter(sDeviceName); + u32 nStrLen = strlen(sDeviceName); + if (nStrLen > WFS_MAX_DEVICE_NAME_SIZE) { + return WFS_RESULT_INVALID; + } + pDeviceName->nLen = (WFSDeviceNameLengthType)nStrLen; + strcpy(pDeviceName->sStr, sDeviceName); + return WFS_RESULT_OK; +} + +WFSResult WFSSetVolumeId(WFSVolumeId *pVolumeId, const utf8 *sVolumeId) { + WFSReturnOnNullParameter(sVolumeId); + u32 nStrLen = strlen(sVolumeId); + if (nStrLen > WFS_MAX_VOLUME_ID_SIZE) { + return WFS_RESULT_INVALID; + } + pVolumeId->nLen = (WFSVolumeIdLengthType)nStrLen; + strcpy(pVolumeId->sStr, sVolumeId); + return WFS_RESULT_OK; +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/client/wfs_PathNames.cpp b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_PathNames.cpp new file mode 100644 index 0000000..52802e5 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/client/wfs_PathNames.cpp @@ -0,0 +1,353 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfs_PathNames.cpp - Functions for concatenating relative and absolute path names + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs_PathNames.cpp,v $ + Revision 1.23 2008/08/19 14:12:41 nakanose_jin + bug : relative dir from long path current dir causes buffer-overflow + + Revision 1.22 2008/07/15 02:32:17 paul + Fixed so that single "/" is still accepted + + Revision 1.21 2008/07/09 02:50:34 paul + Changed to ensure absolute paths do not end with a '/' + + Revision 1.20 2008/04/28 18:37:29 paul + Fixed a bug with parsing relative patterns which start with a wildcard character + + Revision 1.19 2008/04/19 05:53:44 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.18 2008/02/29 07:21:55 paul + The previous fix was not adequate. Should be fixed now. + + Revision 1.17 2008/02/29 02:07:16 paul + Fixed a bug where pathnames which ended with a filename that was 1 byte too long were incorrectly accepted. + + Revision 1.16 2008/02/25 05:37:06 paul + Fixed bug in pathname length check + + Revision 1.15 2008/02/13 05:47:08 paul + Changed spec to make empty pathnames "" invalid. Previously it was treated as current directory. + + Revision 1.14 2008/02/07 06:32:06 paul + fixed a problem with filenames such as ~File + + Revision 1.13 2008/02/04 05:44:00 paul + Fixed a bug with checking the length of a directory entry + + Revision 1.12 2008/01/25 04:33:39 paul + Fixed a bug with WFSPathResolve for directories relative to the home directory "~/dir" + + Revision 1.11 2008/01/17 10:18:11 paul + Fixed a bug where characters >=0x80 were being treated as -ve indexes in the table lookup + + Revision 1.10 2007/12/25 14:03:49 ueno + Modified to initialize mutex, thread and heap only once. + + Revision 1.9 2007/12/10 02:49:38 paul + Added debug output + + Revision 1.8 2007/11/09 01:19:32 paul + Added a new start state to allow validation of path name depth for paths ending in directories + + Revision 1.7 2007/11/06 22:43:12 paul + Added validation checks for NULL pointers passed in + + Revision 1.6 2007/11/02 01:06:49 paul + now logging changes + +*---------------------------------------------------------------------------*/ + +// File created by Paul Donnelly on 2007.10.05 + +#include "wfs_Client.h" + +#undef dbg +#if _DEBUG_PATHNAMES +#define dbg(s) s +#else +#define dbg(s) +#endif + +// A Lookup table is used to categorize characters for the purposes of resolving path names. +// It maps a single utf-8 byte to one of the following categories: +#define CHAR_CATEGORY_NORMAL 0 +#define CHAR_CATEGORY_DOT 1 +#define CHAR_CATEGORY_SLASH 2 +#define CHAR_CATEGORY_TILDA 3 +#define CHAR_CATEGORY_NULL 4 +#define CHAR_CATEGORY_BAD 5 +#define NUM_CHAR_CATEGORIES 6 + +// Invalid Utf-8 bytes, control characters, and wildcards are not allowed in path names +utf8 aCharCategory[256] = { + CHAR_CATEGORY_NULL, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, + CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, + CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, + CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, + + CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, + CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, + CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, + CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, + +// ! " # $ % & ' ( ) * + , - . / + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CHAR_CATEGORY_BAD, 0, 0, 0, CHAR_CATEGORY_DOT, CHAR_CATEGORY_SLASH, + +// 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CHAR_CATEGORY_BAD, + +// @ A B C D E F G H I J K L M N O + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +// P Q R S T U V W X Y Z [ \ ] ^ _ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +// ` a b c d e f g h i j k l m n o + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +// p q r s t u v w x y z { | } ~ DEL + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CHAR_CATEGORY_TILDA, CHAR_CATEGORY_BAD, + +// 0x80..0x8F (128..143) + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +// 0x90..0x9F (144..159) + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +// 0xA0..0xAF (160..175) + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +// 0xB0..0xBF (176..191) + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +// 0xC0..0xCF (192..207) + CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +// 0xD0..0xDF (208..223) + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +// 0xE0..0xEF (224..239) + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +// 0xF0..0xFF (240..255) + 0, 0, 0, 0, 0, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, + CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, + CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, CHAR_CATEGORY_BAD, +}; + +// Finite State Machine for resolving and normalizing path names +typedef enum { + // Initial states - see wfs_PathNames.h + STATE_START_REL = PATH_TYPE_REL_OR_ABS, + STATE_START_REL_DIR = PATH_TYPE_REL_OR_ABS_DIR, + STATE_START_ABS_DIR = PATH_TYPE_ABS_DIR_ONLY, + STATE_START_PTN = PATH_TYPE_PATTERN, + + // Mid-parsing states + STATE_START_DOT, + STATE_START_SLASH, + STATE_START_TILDA, + STATE_START_NAME, + STATE_START_WILD, + STATE_TWO_DOTS, + STATE_IGNORE, + STATE_MID, + STATE_DOT, + STATE_TILDA, + STATE_HOME, + STATE_SLASH, + STATE_PARENT, + + // for parsing search patterns including wild-cards + STATE_CHK_WILD, + STATE_WILD, + + // End states (Do not require an entry in the state table, since no further transition is possible) + STATE_END, + STATE_HOME_END, + STATE_NAME_END, + STATE_PARENT_END, + STATE_ERROR +} WFSPathFsmState; + + +u8 aStateMachine[][NUM_CHAR_CATEGORIES] = { + // A-Z . / ~ NULL * ? + { STATE_START_NAME, STATE_START_DOT, STATE_START_SLASH, STATE_START_TILDA, STATE_ERROR, STATE_ERROR }, // STATE_START_REL + { STATE_START_NAME, STATE_START_DOT, STATE_START_SLASH, STATE_START_TILDA, STATE_ERROR, STATE_ERROR }, // STATE_START_REL_DIR + { STATE_ERROR, STATE_ERROR, STATE_START_SLASH, STATE_ERROR, STATE_ERROR, STATE_ERROR }, // STATE_START_ABS_DIR + { STATE_START_NAME, STATE_START_DOT, STATE_START_SLASH, STATE_START_TILDA, STATE_ERROR, STATE_START_WILD}, // STATE_START_PTN + + { STATE_MID, STATE_TWO_DOTS, STATE_IGNORE, STATE_MID, STATE_END, STATE_CHK_WILD }, // STATE_START_DOT + { STATE_MID, STATE_DOT, STATE_IGNORE, STATE_TILDA, STATE_END, STATE_CHK_WILD }, // STATE_START_SLASH + { STATE_START_NAME, STATE_START_NAME, STATE_HOME, STATE_START_NAME, STATE_HOME_END, STATE_CHK_WILD }, // STATE_START_TILDA + { STATE_MID, STATE_MID, STATE_SLASH, STATE_MID, STATE_NAME_END, STATE_CHK_WILD }, // STATE_START_NAME + { STATE_WILD, STATE_WILD, STATE_ERROR, STATE_WILD, STATE_NAME_END, STATE_WILD }, // STATE_START_WILD + { STATE_MID, STATE_MID, STATE_PARENT, STATE_MID, STATE_PARENT_END, STATE_CHK_WILD }, // STATE_TWO_DOTS + { STATE_MID, STATE_DOT, STATE_IGNORE, STATE_TILDA, STATE_END, STATE_CHK_WILD }, // STATE_IGNORE + { STATE_MID, STATE_MID, STATE_SLASH, STATE_MID, STATE_NAME_END, STATE_CHK_WILD }, // STATE_MID + { STATE_MID, STATE_TWO_DOTS, STATE_IGNORE, STATE_MID, STATE_END, STATE_CHK_WILD }, // STATE_DOT + { STATE_MID, STATE_MID, STATE_ERROR, STATE_MID, STATE_ERROR, STATE_CHK_WILD }, // STATE_TILDA + { STATE_MID, STATE_DOT, STATE_IGNORE, STATE_TILDA, STATE_END, STATE_CHK_WILD }, // STATE_HOME + { STATE_MID, STATE_DOT, STATE_IGNORE, STATE_TILDA, STATE_END, STATE_CHK_WILD }, // STATE_SLASH + { STATE_MID, STATE_DOT, STATE_IGNORE, STATE_TILDA, STATE_END, STATE_CHK_WILD }, // STATE_PARENT + { STATE_WILD, STATE_WILD, STATE_ERROR, STATE_WILD, STATE_NAME_END, STATE_WILD }, // STATE_CHK_WILD + { STATE_WILD, STATE_WILD, STATE_ERROR, STATE_WILD, STATE_NAME_END, STATE_WILD }, // STATE_WILD +}; + +static bool bMutexInitialized; + +static void WfsPathClear(WFSPathName *pPn, WFSPathPartOffsetArray *pPpoa) { + pPn->nLen = 1; + pPpoa->nNumParts = 0; + pPpoa->aPart[pPpoa->nNumParts] = pPn->nLen; + pPn->sStr[0] = '/'; + pPn->sStr[1] = 0; +} + +void WFSPathInit() { + if (!bMutexInitialized) + { + bMutexInitialized = true; + WFSInitMutex(&wcg.pg.mxAccessPathGlobals); + } + WfsPathClear(&wcg.pg.pathCurrent.pn, &wcg.pg.pathCurrent.ppoa); + WfsPathClear(&wcg.pg.pathHome.pn, &wcg.pg.pathHome.ppoa); +} + +static void WfsPathParent(WFSPathName *pPn, WFSPathPartOffsetArray *pPpoa) { + if (pPpoa->nNumParts == 0) { + return; + } + pPpoa->nNumParts--; + pPn->nLen = pPpoa->aPart[pPpoa->nNumParts]; + pPn->sStr[pPn->nLen] = 0; +} + +void WFSPathCopy(WFSPathName *pPnDst, WFSPathPartOffsetArray *pPpoaDst, WFSPathName *pPnSrc, WFSPathPartOffsetArray *pPpoaSrc, bool bAppendSeparator, bool bNullTermination) { + pPnDst->nLen = pPnSrc->nLen; + pPpoaDst->nNumParts = pPpoaSrc->nNumParts; + memcpy(pPpoaDst->aPart, pPpoaSrc->aPart, sizeof(pPpoaSrc->aPart[0]) * (pPpoaSrc->nNumParts+1)); + memcpy(pPnDst->sStr, pPnSrc->sStr, sizeof(pPnSrc->sStr[0]) * pPnSrc->nLen); + if ((bAppendSeparator) && (pPnDst->sStr[pPnDst->nLen-1]!='/')) { + pPnDst->sStr[pPnDst->nLen++] = '/'; + pPpoaDst->aPart[pPpoaDst->nNumParts]++; + } + + if (bNullTermination) + { + pPnDst->sStr[pPnDst->nLen] = 0; + } +} + +WFSResult WFSPathResolve(WFSPathName *pPnOutAbs, WFSPathPartOffsetArray *pPpoaOutAbs, const utf8 *sInPathName, WFSPathNameType nPathType) { + // Arguments: + // ---------- + // pOutAbsPath .. The output normalized absolute path name + // sInPathName .. The input path name + // nPathType .. Specifies whether to allow relative or absolute, absolute-only, or patterns + // + // Description: + // ------------ + // Uses a state machine to process input path names or search patterns. + // Relative paths are concatenated to the current directory or home directory. + // The output is a normalized absolute path name or pattern. + // normalized means "../" == "go back one directory" are processed and removed. + // Invalid path names are detected, and cause a WFS_RESULT_INVALID error. + WFSPathPartOffsetArray ppoa; + WFSReturnOnNullParameter(sInPathName); + if (pPpoaOutAbs == NULL) { + pPpoaOutAbs = &ppoa; + } + const utf8 *pParse = sInPathName; + const utf8 *pName = pParse; + s32 nState = (WFSPathFsmState)nPathType; + s32 nDepthLimit = WFS_MAX_PATH_DEPTH; + s32 nLenAdjust = 0; + if ((nPathType==STATE_START_REL_DIR)||(nPathType==STATE_START_ABS_DIR)) { + nDepthLimit--; + } + WFSLockMutex(&wcg.pg.mxAccessPathGlobals); + WfsPathClear(pPnOutAbs, pPpoaOutAbs); + while(nState < STATE_END) { + s32 nCharCategory = aCharCategory[*((u8*)pParse++)]; + nState = aStateMachine[nState][nCharCategory]; + switch(nState) { + case STATE_START_DOT: // ". " + case STATE_START_NAME: // "A " + case STATE_START_WILD: // "* " + WFSPathCopy(pPnOutAbs, pPpoaOutAbs, &wcg.pg.pathCurrent.pn, &wcg.pg.pathCurrent.ppoa, true, false); + break; + case STATE_START_SLASH: // "/ " + WfsPathClear(pPnOutAbs, pPpoaOutAbs); + pName++; + break; + case STATE_HOME: + case STATE_HOME_END: + WFSPathCopy(pPnOutAbs, pPpoaOutAbs, &wcg.pg.pathHome.pn, &wcg.pg.pathHome.ppoa, true, false); + // Falls through + case STATE_IGNORE: + pName = pParse; + break; + case STATE_NAME_END: + nLenAdjust = -1; + // Falls through + case STATE_SLASH: { + s32 nPartLen = pParse - pName; + if (nPartLen>(WFS_MAX_FILE_NAME_SIZE+1)) { + goto Error; + } + s32 nNewLen = pPnOutAbs->nLen + nPartLen + nLenAdjust; + s32 nNewDepth = pPpoaOutAbs->nNumParts+1; + if ((nNewLen>WFS_MAX_PATH_NAME_SIZE)||(nNewDepth>nDepthLimit)) { + goto Error; + } + memcpy(&pPnOutAbs->sStr[pPnOutAbs->nLen], pName, (u32)nPartLen); + pPnOutAbs->nLen = (WFSPathNameLengthType)nNewLen; + pPpoaOutAbs->nNumParts++; + pPpoaOutAbs->aPart[pPpoaOutAbs->nNumParts] = (WFSPathNameLengthType)pPnOutAbs->nLen; + pName = pParse; + break; + } + case STATE_PARENT: + case STATE_PARENT_END: + WfsPathParent(pPnOutAbs, pPpoaOutAbs); + pName = pParse; + break; + case STATE_CHK_WILD: + if (nPathType != PATH_TYPE_PATTERN) { + goto Error; + } + break; + case STATE_ERROR: + goto Error; + case STATE_START_TILDA: case STATE_TILDA: case STATE_DOT: + case STATE_START_REL: case STATE_TWO_DOTS: case STATE_MID: case STATE_END: + case STATE_START_REL_DIR: case STATE_START_ABS_DIR: + break; + } + } + if ((pPnOutAbs->sStr[pPnOutAbs->nLen-1] == '/') && (pPnOutAbs->nLen>1)) { + pPnOutAbs->sStr[--pPnOutAbs->nLen] = 0; + --pPpoaOutAbs->aPart[pPpoaOutAbs->nNumParts]; + } + pPnOutAbs->sStr[pPnOutAbs->nLen] = 0; + WFSUnlockMutex(&wcg.pg.mxAccessPathGlobals); + dbg(MyOSReport("path: %s\n", pPnOutAbs->sStr)); + return WFS_RESULT_OK; +Error: + WFSUnlockMutex(&wcg.pg.mxAccessPathGlobals); + dbg(MyOSReport("path: WFS_RESULT_INVALID\n")); + return WFS_RESULT_INVALID; +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/client/wfscli_Handles.cpp b/trunk/firmware/build/libraries/nfs/common/src/client/wfscli_Handles.cpp new file mode 100644 index 0000000..8067f29 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/client/wfscli_Handles.cpp @@ -0,0 +1,125 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfscli_Handles.cpp - Module for file handles and search directory handles + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfscli_Handles.cpp,v $ + Revision 1.11 2008/10/07 06:41:51 ueno + Modified WFSCliFileInfoAlloc to set WFSCLI_HANDLE_ALLOCATED in order to indicate the handle is allocated. + + Revision 1.10 2008/04/19 05:53:38 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.9 2007/12/25 14:03:49 ueno + Modified to initialize mutex, thread and heap only once. + + Revision 1.8 2007/11/16 02:15:59 wayne.wong + Added enumeration and stubs for WFSFlush call. + + Revision 1.7 2007/11/02 01:07:38 paul + now logging changes + +*---------------------------------------------------------------------------*/ + +// File created by Paul Donnelly on 2007.10.06 + +#include "wfs_Client.h" + +static bool bMutexInitialized; // [check] + +void WFSCliInitHandles() { + if (!bMutexInitialized) + { + bMutexInitialized = true; + WFSInitMutex(&wcg.hnd.mxAccessTheFileInfo); + WFSInitMutex(&wcg.hnd.mxAccessTheSearchDirInfo); + } + wcg.hnd.nFileHandleCounter = 0; + wcg.hnd.nSearchDirHandleCounter = 0; + wcg.hnd.nFirstFreeFileHandle = 0; + wcg.hnd.nFirstFreeSearchDirHandle = 0; + wcg.hnd.nNumUsedFileHandles = 0; + wcg.hnd.nNumUsedSearchDirHandles = 0; + //wcg.hnd.nFirstUsedFileHandle = WFSCLI_MAX_FILE_HANDLES; // A value of WFSCLI_MAX_FILE_HANDLES is the list terminator + //wcg.hnd.nFirstUsedSearchDirHandle = WFSCLI_MAX_SEARCH_DIR_HANDLES; // A value of WFSCLI_MAX_SEARCH_DIR_HANDLES is the list terminator + for(u32 nI=0; nI>16)&(WFSCLI_MAX_FILE_HANDLES-1)]; + return ((*ppFi)->nHandle == fh)?WFS_RESULT_OK:WFS_RESULT_INVALID; +} + +WFSResult WFSGetCliSearchDirInfo(WFSCliSearchDirInfo **ppSdi, WFSSearchDirectoryHandle sdh) { + *ppSdi = &wcg.hnd.aCliSearchDirInfo[(sdh>>16)&(WFSCLI_MAX_SEARCH_DIR_HANDLES-1)]; + return ((*ppSdi)->nHandle == sdh)?WFS_RESULT_OK:WFS_RESULT_INVALID; +} + +WFSResult WFSCliFileInfoAlloc(WFSCliFileInfo **ppFi) { + WFSLockMutex(&wcg.hnd.mxAccessTheFileInfo); + if (wcg.hnd.nFirstFreeFileHandle == WFSCLI_MAX_FILE_HANDLES) { + WFSUnlockMutex(&wcg.hnd.mxAccessTheFileInfo); + return WFS_RESULT_MAX_HANDLES; + } + wcg.hnd.nNumUsedFileHandles++; + u32 nIdx = wcg.hnd.nFirstFreeFileHandle; + wcg.hnd.nFirstFreeFileHandle = wcg.hnd.aCliFileInfo[nIdx].nNext; + wcg.hnd.aCliFileInfo[nIdx].nNext = WFSCLI_HANDLE_ALLOCATED; // this means the handle is open. + *ppFi = &wcg.hnd.aCliFileInfo[nIdx]; + wcg.hnd.aCliFileInfo[nIdx].nHandle = WFSCLI_FILE_HANDLE_TT_FIELD | wcg.hnd.nFileHandleCounter | (nIdx<<16); + wcg.hnd.nFileHandleCounter += WFSCLI_FILE_HANDLE_INC; + wcg.hnd.nFileHandleCounter &= WFSCLI_HANDLE_COUNTER_MASK; + WFSUnlockMutex(&wcg.hnd.mxAccessTheFileInfo); + return WFS_RESULT_OK; +} + +WFSResult WFSCliSearchDirInfoAlloc(WFSCliSearchDirInfo **ppSdi) { + WFSLockMutex(&wcg.hnd.mxAccessTheSearchDirInfo); + if (wcg.hnd.nFirstFreeSearchDirHandle == WFSCLI_MAX_SEARCH_DIR_HANDLES) { + WFSUnlockMutex(&wcg.hnd.mxAccessTheSearchDirInfo); + return WFS_RESULT_MAX_HANDLES; + } + wcg.hnd.nNumUsedSearchDirHandles++; + u32 nIdx = wcg.hnd.nFirstFreeSearchDirHandle; + wcg.hnd.nFirstFreeSearchDirHandle = wcg.hnd.aCliSearchDirInfo[nIdx].nNext; + wcg.hnd.aCliSearchDirInfo[nIdx].nNext = WFSCLI_HANDLE_ALLOCATED; // this means the handle is open. + *ppSdi = &wcg.hnd.aCliSearchDirInfo[nIdx]; + wcg.hnd.aCliSearchDirInfo[nIdx].nHandle = WFSCLI_SEARCH_DIR_HANDLE_TT_FIELD | wcg.hnd.nSearchDirHandleCounter | (nIdx<<16); + wcg.hnd.nSearchDirHandleCounter += WFSCLI_SEARCH_DIR_HANDLE_INC; + wcg.hnd.nSearchDirHandleCounter &= WFSCLI_HANDLE_COUNTER_MASK; + WFSUnlockMutex(&wcg.hnd.mxAccessTheSearchDirInfo); + return WFS_RESULT_OK; +} + +void WFSCliFileInfoFree(WFSCliFileInfo *pFi) { + WFSLockMutex(&wcg.hnd.mxAccessTheFileInfo); + u32 nIdx = (u32)(pFi - wcg.hnd.aCliFileInfo); + pFi->nHandle ^= 0x55555555; // ensures the deleted handle is invalid + pFi->nNext = wcg.hnd.nFirstFreeFileHandle; + wcg.hnd.nNumUsedFileHandles--; + wcg.hnd.nFirstFreeFileHandle = nIdx; + WFSUnlockMutex(&wcg.hnd.mxAccessTheFileInfo); +} + +void WFSCliSearchDirInfoFree(WFSCliSearchDirInfo *pSdi) { + WFSLockMutex(&wcg.hnd.mxAccessTheSearchDirInfo); + u32 nIdx = (u32)(pSdi - wcg.hnd.aCliSearchDirInfo); + pSdi->nHandle ^= 0x55555555; // ensures the deleted handle is invalid + pSdi->nNext = wcg.hnd.nFirstFreeSearchDirHandle; + wcg.hnd.nNumUsedSearchDirHandles--; + wcg.hnd.nFirstFreeSearchDirHandle = nIdx; + WFSUnlockMutex(&wcg.hnd.mxAccessTheSearchDirInfo); +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/driver_interface/drnand.c b/trunk/firmware/build/libraries/nfs/common/src/driver_interface/drnand.c new file mode 100644 index 0000000..c7ba734 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/driver_interface/drnand.c @@ -0,0 +1,203 @@ +/*---------------------------------------------------------------------------* + Project: TWL - rtfs interface for SD Memory Card + File: drnand.h + + Copyright 2006-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: #$ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include +#include + +#define PRINTDEBUG( ...) ((void)0) +/* +#if (SD_DEBUG_PRINT_ON == 1) + #define PRINTDEBUG osTPrintf +#else + #define PRINTDEBUG( ...) ((void)0) +#endif +*/ + +/*---------------------------------------------------------------------------* + 定数 + *---------------------------------------------------------------------------*/ +#define NUM_SD_PAGES +#define SD_PAGE_SIZE + + +/*---------------------------------------------------------------------------* + extern変数 + *---------------------------------------------------------------------------*/ +/*SDメモリカードのスペック構造体*/ +SdmcSpec sdmc_current_spec; + + +/*---------------------------------------------------------------------------* + extern関数 + *---------------------------------------------------------------------------*/ +extern void nandReset( void); +void i_nandCalcSize( void); //TODO:sdmc_current_specを構造体に入れること +BOOL nandCrashBootSectors( u32* buf); + + +/*---------------------------------------------------------------------------* + static変数 + *---------------------------------------------------------------------------*/ +static FATSpec NandFatSpec[4]; //FATパラメータ(パーティション0〜3個別) +static int nand_calculated_fat_params = 0; + + +/*---------------------------------------------------------------------------* + static関数 + *---------------------------------------------------------------------------*/ +BOOL nandFillPartition( int partition_no, u32* buf, u32 blocks); +void i_nandCalcSize( void); + + +#if 1 //アプリケーションでパーティション構成を決めたいとき + +u32 NAND_FAT_PARTITION_COUNT; +u32 NAND_RAW_SECTORS; +u32 NAND_FAT0_SECTORS = 0; +u32 NAND_FAT1_SECTORS; +u32 NAND_FAT2_SECTORS; +u32 NAND_FAT3_SECTORS; + +void nandSetFormatRequest( u16 partition_num, u32* partition_sectors); +void nandSetFormatRequest( u16 partition_num, u32* partition_sectors) +{ + NAND_RAW_SECTORS = partition_sectors[0]; + NAND_FAT0_SECTORS = partition_sectors[1] + NAND_RAW_SECTORS; + NAND_FAT1_SECTORS = partition_sectors[2]; + NAND_FAT2_SECTORS = partition_sectors[3]; + NAND_FAT3_SECTORS = partition_sectors[4]; + NAND_FAT_PARTITION_COUNT = partition_num; +} + +#else //パーティション構成を決め打ちするとき +/* RAW:1MB, FAT0:206MB, FAT1:32.75MB */ +#define NAND_FAT_PARTITION_COUNT (3) +#define NAND_RAW_SECTORS (( 1*1024*1024)/512); +#define NAND_FAT0_SECTORS (((206*1024*1024)/512) + NAND_RAW_SECTORS); //計算上RAWを含めておく +#define NAND_FAT1_SECTORS ((33536*1024)/512); +#define NAND_FAT2_SECTORS (( 1*1024*1024)/512); +#define NAND_FAT3_SECTORS (0); + +#endif + + +/*---------------------------------------------------------------------------* + Name: nandNfsIo + + Description: 上位層からのセクタリード/ライト要求を受ける + + Arguments: driveno : ドライブ番号 + block : 開始ブロック番号 + buffer : + count : ブロック数 + reading : リード要求時にTRUE + + Returns: TRUE/FALSE + *---------------------------------------------------------------------------*/ +BOOL nandNfsIo( int driveno, u32 block, void* buffer, u16 count, BOOL reading) +{ + if( reading) { + PRINTDEBUG( "DEVCTL_IO_READ ... block:%x, count:%x -> buf:%x\n", block, count, buffer); + nandReadSector( buffer, block, count); + }else{ + PRINTDEBUG( "DEVCTL_IO_WRITE ... block:%x, count:%x <- buf:%x\n", block, count, buffer); + nandWriteSector( buffer, block, count); + } + + return TRUE; +} + +/*---------------------------------------------------------------------------* + Name: nandNfsCtrl + + Description: 上位層からのコントロール要求を受ける + + Arguments: driveno : ドライブ番号 + opcode : 要求の種類 + pargs : + + Returns: + Memo : DRIVE_FLAGS_REMOVABLEの場合、ドライバのIO関数を呼ぶ前に + CTRL関数のDEVCTL_CHECK_STATUSが呼ばれる。 + DEVTEST_CHANGED→DEVTEST_NOCHANGEが確認されるとRTFSはセクタ0を + 読みに行き、FATパラメータを取得した上で目的のセクタを読みに行く。 + CTRL関数の前にはDEVCTL_CHECK_STATUSが呼ばれないので、DEVCTL_ + GET_GEOMETRYでは自前で再挿入をチェックする必要がある。 + *---------------------------------------------------------------------------*/ +int nandNfsCtrl( int driveno, int opcode, void* pargs) +{ + switch( opcode) { + case NFS_DEVCTL_GET_GEOMETRY: //formatまたはpartirionするときにRTFSが使うパラメータ + return( 0); + + case NFS_DEVCTL_FORMAT: + PRINTDEBUG( "DEVCTL_FORMAT\n"); + return( 0); + + case NFS_DEVCTL_REPORT_REMOVE: //抜かれたとき + PRINTDEBUG( "DEVCTL_REPORT_REMOVE\n"); + return( 0); + + case NFS_DEVCTL_CHECKSTATUS: //REMOVABLEの場合、毎回R/W前に呼ばれる + PRINTDEBUG( "DEVCTL_CHECKSTATUS\n"); + return(DEVTEST_NOCHANGE); +// } + + case NFS_DEVCTL_WARMSTART: //attachのときしか呼ばれない + PRINTDEBUG( "DEVCTL_WARMSTART\n"); + /*-- NANDのみ初期化 --*/ +// nandReset(); + /*--------------------*/ + return( 0); + + case NFS_DEVCTL_POWER_RESTORE: + PRINTDEBUG( "DEVCTL_POWER_RESTORE\n"); + break; + + case NFS_DEVCTL_POWER_LOSS: + PRINTDEBUG( "DEVCTL_POWER_LOSS\n"); + break; + + default: + PRINTDEBUG( "DEVCTL_unknown\n"); + break; + } + return( 0); +} + +/*---------------------------------------------------------------------------* + Name: i_nandCalcSize + + Description: + + Arguments: + + Returns: None + *---------------------------------------------------------------------------*/ +void i_nandCalcSize( void) +{ + sdmc_current_spec.csd_ver2_flag = 0; + sdmc_current_spec.protected_capacity = (20*256); //20Blocks + sdmc_current_spec.card_capacity = NAND_GUARANTEED_SECTORS; + sdmc_current_spec.memory_capacity = sdmc_current_spec.card_capacity - + sdmc_current_spec.protected_capacity; +} + + +//#endif /*(INCLUDE_SD)*/ diff --git a/trunk/firmware/build/libraries/nfs/common/src/my_wfskrn_Device.cpp b/trunk/firmware/build/libraries/nfs/common/src/my_wfskrn_Device.cpp new file mode 100644 index 0000000..7a11708 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/my_wfskrn_Device.cpp @@ -0,0 +1,545 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Device.cpp - storage device abstraction. + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + +*---------------------------------------------------------------------------*/ + +#include "wfskrn_Device.h" +#include "wfskrn_Api.h" +#include +#include + +//TODO:他で宣言してincludeする +#ifdef __cplusplus +extern "C" { +#endif +BOOL nandNfsIo( int driveno, u32 block, void* buffer, u16 count, BOOL reading); +int nandNfsCtrl( int driveno, int opcode, void* pargs); +#ifdef __cplusplus +} +#endif + + +typedef struct{ + u32 cmd; + s32 status; + WFSHashCode *pHash; + WFSHashCode readHash; +} DeviceMscResourceRequest; + +static DeviceMscResourceRequest gPmrr[DEVICE_IOP_MAX_ASYNC_NUM]; + +#if _WIN32 +char sDevicePathWin32[sizeof(WFSKRN_SIMULATED_DISK_PATH)+WFS_MAX_DEVICE_NAME_SIZE+1] = WFSKRN_SIMULATED_DISK_PATH; + +char *DeviceGetWin32PathName(const utf8 *sDevName) { + memcpy(&sDevicePathWin32[sizeof(WFSKRN_SIMULATED_DISK_PATH)-1], sDevName, WFS_MAX_DEVICE_NAME_SIZE+1); + return sDevicePathWin32; +} + +WFSHashCode aHashDummyData = {0xbeefbeef,0xbeefbeef,0xbeefbeef,0xbeefbeef,0xbeefbeef}; + +#elif _IOP + +static IOSMessageQueueId gMqidPmrr; +static IOSMessage gMqPmrr[DEVICE_IOP_MAX_ASYNC_NUM]; + +static IOSMessageQueueId gMqidIrrFb; +static IOSMessage gMqIrrFb[1]; +static IOSResourceRequest gIrrFuncBlock; + +static DeviceAttachDetachCallback gCbAttach = 0; + +#endif + +static s32 cntDebugPseudoDetachDrive = -1; +static s32 cntDebugPseudoHashInconsistent = -1; + +#define WFS_MAX_DEVICE_PATH (sizeof(WFS_DEVICE_DIRECTORY) + WFS_MAX_DEVICE_NAME_SIZE + 2) + + +// Initialize Device library +// x86 - initialize parameter +void DeviceInitLib() { + dbgd(osTPrintf("DeviceInitLib()\n")); + wkg.nNumDevices = 0; + memset(&wkg.aDevInfo, 0, sizeof(wkg.aDevInfo)); + memset(&gPmrr, 0, sizeof(DeviceMscResourceRequest)*DEVICE_IOP_MAX_ASYNC_NUM); +} + + +void DeviceDebugSetPseudoDetachDevice(s32 cnt) +{ + cntDebugPseudoDetachDrive = cnt; +} + +void DeviceDebugSetPseudoHashInconsistent(s32 cnt) +{ + cntDebugPseudoHashInconsistent = cnt; +} + +s32 DeviceDebugGetPseudoDetachDevice() +{ + return cntDebugPseudoDetachDrive; +} + +s32 DeviceDebugGetPseudoHashInconsistent() +{ + return cntDebugPseudoHashInconsistent; +} + +#if _WIN32 + +static IOSError _WIN32DeviceRead(DeviceInfo *pDevInfo, u32 nSectorAdr, u8 *pData, u16 nSectors, u8 *pHash, u16 nHashSectors, s32 nHashStride) +{ + u64 filePos = (u64)nSectorAdr * pDevInfo->nSectorSize; + filePos += 2 * sizeof(u32); // initial bytes have sector size + dev capacity + LONG posLow = (LONG) filePos & 0xffffffff; + LONG posHigh = filePos >> 32; + SetFilePointer(pDevInfo->hSimulatedDeviceFile, posLow, &posHigh, FILE_BEGIN); + + DWORD numBytes = pDevInfo->nSectorSize * nSectors; + DWORD bytesRead; + if (!ReadFile(pDevInfo->hSimulatedDeviceFile, pData, numBytes, &bytesRead, NULL)) { + dbgd(osTPrintf("DeviceRead: read failed\n")); + return IOS_ERROR_MSC_COMMAND_FAILED; + } + if(pData[0] == 0xaa){ + int a; a=0; + } + if (numBytes != bytesRead) { + dbgd(osTPrintf("DeviceRead: bytes read does not match\n")); + return IOS_ERROR_MSC_COMMAND_FAILED; + } + + s32 nSize = numBytes; + int nNumBlks = 0; + while(nSize>0){ + u8 *pHashPtr = (u8*)pHash+(nNumBlks*nHashStride); + u32 *pHashDummyData32 = (u32*)aHashDummyData; + *pHashDummyData32++ = nSectorAdr+(nNumBlks*nHashSectors); + *pHashDummyData32++ = nSize < (nHashSectors<dh.nLog2SectorSize) ? nSize : (nHashSectors<dh.nLog2SectorSize); + if(memcmp(pHashPtr, (u8*)aHashDummyData, sizeof(WFSHashCode))){ + return IOS_ERROR_MSC_HASH_INCONSISTENT; + } + nSize -= (nHashSectors<dh.nLog2SectorSize); + ++nNumBlks; + } + return IOS_ERROR_MSC_OK; +} + +static IOSError _WIN32DeviceWrite(DeviceInfo *pDevInfo, u32 nSectorAdr, u8 *pData, u16 nSectors, u8 *pHash, u16 nHashSectors, s32 nHashStride, bool bDecryption) +{ + u64 filePos = (u64)nSectorAdr * pDevInfo->nSectorSize; + filePos += sizeof(pDevInfo->dh); // initial bytes have sector size + dev capacity + LONG posLow = (LONG) filePos & 0xffffffff; + LONG posHigh = filePos >> 32; + SetFilePointer(pDevInfo->hSimulatedDeviceFile, posLow, &posHigh, FILE_BEGIN); + + DWORD numBytes = pDevInfo->nSectorSize * nSectors; + DWORD bytesWritten; + s32 nSize = numBytes; + int nNumBlks = 0; + while(nSize>0){ + u8 *pHashPtr = (u8*)pHash+(nNumBlks*nHashStride); + u32 *pHashDummyData32 = (u32*)aHashDummyData; + *pHashDummyData32++ = nSectorAdr+(nNumBlks*nHashSectors); + if(nSectorAdr+(nNumBlks*nHashSectors) == 0x180){ + int a; a=0; + } + *pHashDummyData32++ = nSize < (nHashSectors<dh.nLog2SectorSize) ? nSize : (nHashSectors<dh.nLog2SectorSize); + memcpy(pHashPtr, (u8*)aHashDummyData, sizeof(WFSHashCode)); + nSize -= (nHashSectors<dh.nLog2SectorSize); + ++nNumBlks; + } + if (!WriteFile(pDevInfo->hSimulatedDeviceFile, pData, numBytes, &bytesWritten, NULL)) { + dbgd(osTPrintf("DeviceWrite: write failed\n")); + return IOS_ERROR_MSC_COMMAND_FAILED; + } + if(pData[0] == 0xaa){ + int a; a=0; + } + if (numBytes != bytesWritten) { + dbgd(osTPrintf("DeviceWrite: bytes written does not match\n")); + return IOS_ERROR_MSC_COMMAND_FAILED; + } + if(!bDecryption){ + memset(pData, 0xaa, numBytes); + } + return IOS_ERROR_MSC_OK; +} + +#endif + +// Read nNumSectors sectors from device devHandle starting at LBA nSectorAdr into buffer +// pBuffer. nSectorAdr == LBA. +WFSKrnResult DeviceRead(DeviceInfo *pDevInfo, u32 nSectorAdr, u8 *pBuffer, u32 nSectors, WFSHashCode *pHash, u32 nLog2HashSectors, u32 nOffsetHashBlks, s32 nHashStride, s32 nHashStridePerMaxLBlks) +{ + dbgd(osTPrintf("DeviceRead()\n")); + ASSERT(nLog2HashSectors <= (WFS_LOG2_MAX_HASHABLE_BLK_SIZE-pDevInfo->dh.nLog2SectorSize)); // ~64KB +#if _DEBUG + //osTPrintf("Read: nSectorAdr = 0x%x, pDevInfo->dh.nNumSectors = 0x%x\n", nSectorAdr, pDevInfo->dh.nNumSectors); + if (nSectorAdr >= pDevInfo->dh.nNumSectors) { + WFSKrnOutputErrorStr("Attempted access beyond end of device"); + } +#endif + WFSKrnResult nResult = WFSKRN_RESULT_OK; + DeviceMscResourceRequest *pCurrentReply; + u32 nMaxSectors = 1<<(WFS_LOG2_LARGE_BLK_SIZE-pDevInfo->dh.nLog2SectorSize); + u32 nHashSectors = (1<>nLog2HashSectors)+1 : 0; + u32 nNumLoop = (((nHashSectors<dh.nLog2SectorSize)*(nNumBlks+nOffsetHashBlks)-1)>>WFS_LOG2_LARGE_BLK_SIZE)+1; + u32 nRcvLoop = nNumLoop < DEVICE_IOP_MAX_ASYNC_NUM ? nNumLoop : DEVICE_IOP_MAX_ASYNC_NUM; + int i; + for(i=0;i=nRcvLoop){ +#endif + switch(pCurrentReply->status){ + case IOS_ERROR_MSC_DEVICE_DETACH: + case IOS_ERROR_MSC_COMMAND_FAILED: + case IOS_ERROR_MSC_PHASE_ERROR: + case IOS_ERROR_MSC_INVALID_CBW_SIGNATURE: + case IOS_ERROR_MSC_INVALID_CBW_TAG: + nResult = WFSKRN_RESULT_DEVICE_NOT_FOUND; + break; +#if DEVICE_VERIFY_HASH_DATA + case IOS_ERROR_MSC_HASH_INCONSISTENT: + pDevInfo->nFlags |= WFS_DEVFLAG_NOT_INITIALIZED; + nResult = WFSKRN_RESULT_DEVICE_HASH_INCONSISTENT; + break; +#endif + } +#if DEVICE_DEBUG_PSEUDO_DEVICE_ERROR + if(cntDebugPseudoDetachDrive == 0){ + cntDebugPseudoDetachDrive = -1; + nResult = WFSKRN_RESULT_DEVICE_NOT_FOUND; + } + else if(cntDebugPseudoDetachDrive){ + --cntDebugPseudoDetachDrive; + } +#if DEVICE_VERIFY_HASH_DATA + if(cntDebugPseudoHashInconsistent == 0){ + pDevInfo->nFlags |= WFS_DEVFLAG_NOT_INITIALIZED; + nResult = WFSKRN_RESULT_DEVICE_HASH_INCONSISTENT; + cntDebugPseudoHashInconsistent = -1; + } + else if(cntDebugPseudoHashInconsistent){ + --cntDebugPseudoHashInconsistent; + } +#endif +#endif + } + if(ipHash = pHash; + IOSError ie; +#if _WIN32 + ie = _WIN32DeviceRead(pDevInfo, nSectorAdr, pData, (u16)nSec, (u8*)pCurrentReply->pHash, (u16)(1<status = ie; + } + nSectors -= nSec; + pData += nSec<dh.nLog2SectorSize; + nSectorAdr += nSec; + u32 nBlks = ((nSec-1)>>nLog2HashSectors)+1; + pHash = (WFSHashCode*)((u8*)pHash+nBlks*nHashStride+nHashStridePerMaxLBlks); + nOffsetHashBlks = 0; + } +#if _TWL + } +#endif + return nResult; +} + + +// Write nNumSectors sectors to device devHandle starting at LBA nSectorAdr from buffer +// pBuffer. nSectorAdr == LBA. +WFSKrnResult DeviceWrite(DeviceInfo *pDevInfo, u32 nSectorAdr, u8 *pBuffer, u32 nSectors, WFSHashCode *pHash, u32 nLog2HashSectors, u32 nOffsetHashBlks, s32 nHashStride, s32 nHashStridePerMaxLBlks, bool bDecryption) +{ +#if _DEBUG_BREAK_POINT + if (nSectorAdr==0x28800) { + int a;a=0; + } +#endif + dbgd(osTPrintf("DeviceWrite()\n")); + ASSERT(nLog2HashSectors <= (WFS_LOG2_MAX_HASHABLE_BLK_SIZE-pDevInfo->dh.nLog2SectorSize)); // ~64KB +#if _DEBUG + //osTPrintf("Write: nSectorAdr = 0x%x, pDevInfo->dh.nNumSectors = 0x%x\n", nSectorAdr, pDevInfo->dh.nNumSectors); + if (nSectorAdr >= pDevInfo->dh.nNumSectors) { + WFSKrnOutputErrorStr("Attempted access beyond end of device"); + } +#endif + WFSKrnResult nResult = WFSKRN_RESULT_OK; + DeviceMscResourceRequest *pCurrentReply; + u32 nMaxSectors = 1<<(WFS_LOG2_LARGE_BLK_SIZE-pDevInfo->dh.nLog2SectorSize); + u32 nHashSectors = (1<>nLog2HashSectors)+1 : 0; + u32 nNumLoop = (((nHashSectors<dh.nLog2SectorSize)*(nNumBlks+nOffsetHashBlks)-1)>>WFS_LOG2_LARGE_BLK_SIZE)+1; + u32 nRcvLoop = nNumLoop < DEVICE_IOP_MAX_ASYNC_NUM ? nNumLoop : DEVICE_IOP_MAX_ASYNC_NUM; + int i; + for(i=0;i=1 && i<=nNumLoop ){ +#endif + switch(pCurrentReply->status){ + case IOS_ERROR_MSC_DEVICE_DETACH: + case IOS_ERROR_MSC_COMMAND_FAILED: + case IOS_ERROR_MSC_PHASE_ERROR: + case IOS_ERROR_MSC_INVALID_CBW_SIGNATURE: + case IOS_ERROR_MSC_INVALID_CBW_TAG: + nResult = WFSKRN_RESULT_DEVICE_NOT_FOUND; + } +#if DEVICE_DEBUG_PSEUDO_DEVICE_ERROR + if(cntDebugPseudoDetachDrive == 0){ + nResult = WFSKRN_RESULT_DEVICE_NOT_FOUND; + cntDebugPseudoDetachDrive = -1; + } + else if(cntDebugPseudoDetachDrive){ + --cntDebugPseudoDetachDrive; + } +#endif + } + if(ipHash = pHash; + IOSError ie; +#if _WIN32 + ie = _WIN32DeviceWrite(pDevInfo, nSectorAdr, pData, (u16)nSec, (u8*)pCurrentReply->pHash, (u16)(1<status = ie; + } + nSectors -= nSec; + pData += nSec<dh.nLog2SectorSize; + nSectorAdr += nSec; + u32 nBlks = ((nSec-1)>>nLog2HashSectors)+1; + pHash = (WFSHashCode*)((u8*)pHash+nBlks*nHashStride+nHashStridePerMaxLBlks); + nOffsetHashBlks = 0; + } +#if _TWL + } +#endif + return WFSKRN_RESULT_OK; +} + +DeviceInfo *DeviceGetDeviceInfo(const WFSDeviceName *pDevName) { + dbgd(osTPrintf("DeviceGetDeviceInfo()\n")); + utf8 sDevPath[WFS_MAX_DEVICE_NAME_SIZE + 6]; + void *pDevInfo; + RxtItr rxi; + rxi.pStrPtr = sDevPath; + osSNPrintf(sDevPath, WFS_MAX_DEVICE_NAME_SIZE + 6,"/dev/%s", pDevName->sStr); + if ((!PathCacheFind3(&rxi, pDevName->nLen+5, &pDevInfo)) || + ((DeviceInfo*)pDevInfo < wkg.aDevInfo) || + ((DeviceInfo*)pDevInfo >= &wkg.aDevInfo[WFSKRN_MAX_DEVICES])) + { + return 0; + } + return (DeviceInfo*)pDevInfo; +} + + +WFSKrnResult DeviceGetVolumeId(const WFSDeviceName *pDevName, WFSVolumeId *pVolId) { + dbgd(osTPrintf("DeviceGetVolumeInfo()\n")); + DeviceInfo *pDevInfo = DeviceGetDeviceInfo(pDevName); + if(!pDevInfo || !pDevInfo->bInUse) { + return WFSKRN_RESULT_NOT_FOUND; + } + else if (pDevInfo->nFlags & WFS_DEVFLAG_UNUSABLE) { + return WFSKRN_RESULT_DEV_UNUSABLE; + } + else if (pDevInfo->nFlags & WFS_DEVFLAG_NOT_INITIALIZED) { + return WFSKRN_RESULT_DEV_NOT_INITIALIZED; + } + else if(pDevInfo->pVolInfo){ + VolumeConvertU32ToVolId(pVolId, pDevInfo->pVolInfo->vh.nVolId); + return WFSKRN_RESULT_OK; + } + VolumeInfo tempVolInfo; + tempVolInfo.pDevInfo = pDevInfo; + pDevInfo->pVolInfo = &tempVolInfo; + BCacheEntry* pBce; + WFSKrnResult nResult = BCacheAllocMetaBlk(&tempVolInfo, VOLUME_HDR_BLK_ADR, BCACHE_FLAG_PINNED | BCACHE_FLAG_READ, &pBce); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + VolumeHdr *pVh = (VolumeHdr *)pBce->pBlkPtr; + VolumeConvertU32ToVolId(pVolId, pVh->nVolId); + nResult = BCacheUnpin(&tempVolInfo, VOLUME_HDR_BLK_ADR); + pDevInfo->pVolInfo = 0; + return nResult; +} + + +WFSKrnResult DeviceMountVolume(DeviceInfo *pDevInfo) { + dbgd(osTPrintf("DeviceMountVolume()\n")); + WFSKrnResult nResult = WFSKRN_RESULT_OK; + VolumeInfo tempVolInfo; + tempVolInfo.pDevInfo = pDevInfo; + pDevInfo->pVolInfo = &tempVolInfo; + BCacheEntry* pBce; + nResult = BCacheAllocMetaBlk(&tempVolInfo, VOLUME_HDR_BLK_ADR, BCACHE_FLAG_PINNED | BCACHE_FLAG_READ, &pBce); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + VolumeHdr *pVh = (VolumeHdr *)pBce->pBlkPtr; + tempVolInfo.vh = *(VolumeHdr *)pVh; + BCacheUnpin(&tempVolInfo, VOLUME_HDR_BLK_ADR); + VolumeInfo *pVolInfo = wkg.pMountedVolListAnchor->vl.pNext; + while(pVolInfo != wkg.pMountedVolListAnchor) { + if (pVh->nVolId == pVolInfo->vh.nVolId) { + // The volume Id matches a currently mounted volume + if (pVolInfo->bDetached) { + // ToDo: Check Session ID + pVolInfo->bDetached = false; + pDevInfo->pVolInfo = pVolInfo; + //pDevInfo->nFlags &= ~WFS_DEVFLAG_NOT_MOUNTED; + } else { + nResult = WFSKRN_RESULT_VOL_ID_ERROR; + } + goto Exit; + } + } + BCacheReTag(&tempVolInfo, VOLUME_HDR_BLK_ADR, pVolInfo, VOLUME_HDR_BLK_ADR); + // The volume Id did not match any currently mounted volumes + pVolInfo = pDevInfo->pVolInfo = VolumeAlloc(); + pVolInfo->pDevInfo = pDevInfo; + pVolInfo->vh = tempVolInfo.vh; + VolumeAddToMountedList(pVolInfo); + pVolInfo->rootAreaInfo.pVolInfo = pVolInfo; + pVolInfo->rootAreaInfo.pParent = 0; + pVolInfo->rootAreaInfo.nRelStartBlkAdr = 0; + //pVolInfo->rootAreaInfo.ah.nLog2BlkSize = nLog2BlkSize; + //pVolInfo->rootAreaInfo.ah.nNumBlks = nNumBlks; + nResult = AreaOpen(&pVolInfo->rootAreaInfo); // for debug wfskrn + BCacheUnpin(pVolInfo, VOLUME_HDR_BLK_ADR); // kondo_masahiro 080729 +Exit: + //BCacheUnpin(pVolInfo, VOLUME_HDR_BLK_ADR); + return nResult; +} + + +WFSKrnResult DeviceAttach(DeviceInfo *pDevInfo, WFSDevType nDevType, u32 nDevIdx, u32 nLog2SectorSize, u32 nNumSectors) { + dbgd(osTPrintf("DeviceAttach()\n")); + // Called when user physically attaches a drive + if(pDevInfo->bInUse){ +// return WFSKRN_RESULT_OK; + DeviceDetach(pDevInfo); + } + + nandNfsCtrl( 0, NFS_DEVCTL_WARMSTART, NULL); + + WFSKrnResult nResult = WFSKRN_RESULT_OK; + ++wkg.nNumDevices; + pDevInfo->bInUse = true; + pDevInfo->nDevType = nDevType; + pDevInfo->dh.nLog2SectorSize = nLog2SectorSize; + pDevInfo->nSectorSize = 1<dh.nNumSectors = nNumSectors; + pDevInfo->nTotalCapacity = (u64)nNumSectors * (u64)(pDevInfo->nSectorSize); + WFSPathName path; + switch(nDevType) { + case WFS_DEVTYPE_USB_MSC_10: + osTPrintf("Attach device with USB1.0\n"); + break; + case WFS_DEVTYPE_USB_MSC_11: + osTPrintf("Attach device with USB1.1\n"); + break; + case WFS_DEVTYPE_USB_MSC_20: + osTPrintf("Attach device with USB2.0\n"); + break; + default: + return WFSKRN_RESULT_DEVICE_ERROR; + } + pDevInfo->devName.nLen = 5; + osSNPrintf(pDevInfo->devName.sStr, pDevInfo->devName.nLen+1, "msc%02d", nDevIdx+1); + path.nLen = sizeof(WFS_MAX_DEVICE_PATH)+1+ pDevInfo->devName.nLen; + osSNPrintf(path.sStr, WFS_MAX_DEVICE_PATH, WFS_DEVICE_DIRECTORY"/%s", pDevInfo->devName.sStr); + PathCacheEntry *pEntry = PathCacheInsertAfterCursorEntry2(wkg.pathCache.pPinAnchor, path.sStr); + pEntry->pcd.pData = pDevInfo; +#if _IOP + if(__p_hd[nDevIdx]->state < HARDDISC_STATUS_IDLE){ + return WFSKRN_RESULT_DEVICE_ERROR; + } + pDevInfo->nDeviceDevHandle = __p_hd[nDevIdx]; +#endif + if (wkg.bMountedDeviceWasDetached) { + DeviceMountVolume(pDevInfo); + } else { + pDevInfo->pVolInfo = 0; + //pDevInfo->nFlags = WFS_DEVFLAG_NOT_MOUNTED; + } + return nResult; +} + + +WFSKrnResult DeviceDetach(DeviceInfo *pDevInfo) { + dbgd(osTPrintf("DeviceDetach()\n")); + if(!pDevInfo->bInUse){ + return WFSKRN_RESULT_OK; + } + // Called when user physically detaches a drive + utf8 sDevicePathWfs[WFS_MAX_DEVICE_PATH]; + osSNPrintf(sDevicePathWfs, WFS_MAX_DEVICE_PATH, WFS_DEVICE_DIRECTORY"/%s", pDevInfo->devName.sStr); + WFSPathName path; + path.nLen = sizeof(WFS_MAX_DEVICE_PATH)+1+ pDevInfo->devName.nLen; + PathCacheItr pci; + WFSKrnResult nResult = WFSKRN_RESULT_OK; + WFSKrnExitOnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, sDevicePathWfs, path.nLen, WFS_MAX_FILE_NAME_SIZE)); + WFSKrnExitOnError(PathCacheFindPath(&path, path.sStr, &pci)); + PathCacheDeleteEntry(pci.pEntry); +#if _DEBUG + WFSDeviceName devName; + //WFSSetDeviceName(&devName, pDevInfo->devName.sStr); + devName.nLen = STRNLEN(pDevInfo->devName.sStr, WFS_MAX_DEVICE_NAME_SIZE); + strncpy(devName.sStr, pDevInfo->devName.sStr, WFS_MAX_DEVICE_NAME_SIZE); + DeviceInfo *pFoundDevInfo = DeviceGetDeviceInfo(&devName); + if (pFoundDevInfo != 0) { + WFSKrnOutputErrorStr("Delete failed"); + } +#endif + pDevInfo->bInUse = false; + VolumeInfo *pVolInfo = pDevInfo->pVolInfo; + if (pVolInfo){ + if (pVolInfo->nClientsMountedBy) { + wkg.bMountedDeviceWasDetached = true; + pVolInfo->bDetached = true; + } else { + VolumeRemoveFromMountedList(pDevInfo->pVolInfo); + VolumeFree(pDevInfo->pVolInfo); + pDevInfo->pVolInfo = 0; + } + } + --wkg.nNumDevices; +Exit: + return nResult; +} + diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Api.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Api.cpp new file mode 100644 index 0000000..0120037 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Api.cpp @@ -0,0 +1,3530 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Api.cpp - server side of the WFS API for WFSDEV + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Api.cpp,v $ + Revision 1.112 2008/12/18 09:44:36 ooizumi + Fixed a typo in WFSSrvCreateDirectory(). + + Revision 1.111 2008/12/15 02:40:07 ueno + Added support for multi p-tree. + + Revision 1.110 2008/12/10 06:50:36 kondo_masahiro + Added a argument WFSDevType nDevType in WfsKrnAttachDetachCallback. + + Revision 1.109 2008/12/05 06:02:08 ooizumi + Added ifdef not to enable permission check in WFSSrvInitializeDevice(). + + Revision 1.108 2008/12/04 00:45:55 ooizumi + Modified WFSSrvInitializeDevice() to return PERMISSION error if caller is not ROOT. + Changed definition name to enable permission. + Modified error messages. + + Revision 1.107 2008/12/03 00:09:48 kondo_masahiro + Fixed WFSSrvFlush(). + + Revision 1.106 2008/12/01 10:05:42 kondo_masahiro + Fixed error handling in WFSSrvCreateDirectory. + + Revision 1.105 2008/11/28 06:48:10 kondo_masahiro + Fixed a bug around file edit in WFSSrvWriteFile. + + Revision 1.104 2008/11/28 04:43:21 kondo_masahiro + Fixed a bug around file edit in WFSSrvWriteFile. + + Revision 1.103 2008/11/28 04:38:16 kondo_masahiro + Fixed a bug around file edit in WFSSrvWriteFile. + + Revision 1.102 2008/11/28 04:33:42 kondo_masahiro + Fixed a bug around file edit in WFSSrvWriteFile. + + Revision 1.101 2008/11/27 08:55:41 saito_tomoya + Modified to invalidate BCache after check disk. + + Revision 1.100 2008/11/26 01:44:16 kondo_masahiro + Fixed WFSSrvRead/Write in order to improve access speed. + + Revision 1.99 2008/11/18 07:35:45 kondo_masahiro + Fixed WFSSrvMoveLocal() + + Revision 1.98 2008/11/18 04:53:46 saito_tomoya + Modified WFSSrvCheckDisk() to use a bit array file. + + Revision 1.97 2008/11/17 04:45:46 kondo_masahiro + Fixed WFSSrvMoveLocal() + + Revision 1.96 2008/11/14 06:51:19 ueno + Fixed a typo. + + Revision 1.94 2008/11/12 13:30:20 ueno + Modified WFSSrvMoveLocal(), Delete() and CreateDirectory() to return WFSKRN_RESULT_PERMISSION when they modify system paths (/, /dev, /vol). + + Revision 1.93 2008/11/12 09:08:12 kondo_masahiro + Removed the debug print. + + Revision 1.92 2008/11/12 04:24:12 kondo_masahiro + Fixed the codes that work buffer for buffer rotation method is obtained from stack. + + Revision 1.91 2008/11/12 01:45:27 kondo_masahiro + Comment out the contents of WFSSrvCheckDisk(). + + Revision 1.90 2008/11/10 01:40:10 ooizumi + Added permission check sequence to MoveLocal(). + + Revision 1.89 2008/11/10 01:00:24 ueno + Added a workaround to WFSSrvMoveLocal(). + + Revision 1.88 2008/11/07 08:52:21 kondo_masahiro + Fixed WFSSrvMoveLocal() + + Revision 1.87 2008/11/07 04:22:45 ueno + Fixed AdjustMemorySizeForBCache(). + + Revision 1.86 2008/11/05 16:48:37 ueno + Fixed. + + Revision 1.85 2008/11/05 15:08:20 ueno + Modified DirItrMapBlks() to roll back the update map in case of error. + + Revision 1.84 2008/11/05 09:58:50 kondo_masahiro + Fixed WFSMoveLocal() + + Revision 1.83 2008/11/05 05:54:51 kondo_masahiro + Added Chainning system for indirect block in WFSWriteFile() + + Revision 1.82 2008/11/05 05:49:46 ooizumi + Fixed WFSSrvMoveLocal() to insert a directory entry which has not cached yet to PathCache. + + Revision 1.81 2008/11/04 00:23:13 kondo_masahiro + Added WFSSrvMoveLocal() + + Revision 1.80 2008/10/31 09:51:11 ueno + Modified WFSSrvAPIs to return WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED when path cache is short of memory. + + Revision 1.79 2008/10/30 06:34:18 kondo_masahiro + Fixed WFSSrvCheckDisk + + Revision 1.78 2008/10/30 05:06:03 kondo_masahiro + Added WFSSrvCheckDisk + + Revision 1.77 2008/10/27 13:46:11 ueno + Modified WFSSrvInit() to enable attach/detach callbacks when to reinitialize WFS. + + Revision 1.76 2008/10/21 11:34:11 ueno + Modified WFSSrvGetFreeSpaceSize() to return WFSKRN_RESULT_INVALID for virtual paths. + + Revision 1.75 2008/10/21 09:49:37 kondo_masahiro + Added new function WFSWriteFileAndDiscard + + Revision 1.74 2008/10/20 09:27:58 ueno + Added casts for porting IOP. + + Revision 1.73 2008/10/20 05:17:16 ueno + Modified WFSSrvExecDebugProcedure() to support WFSDEBUG_CMD_ATTACH and WFSDEBUG_CMD_DETACH options. + + Revision 1.72 2008/10/17 08:50:48 kondo_masahiro + Added the new MEDIUM size category (40KB-320KB) + + Revision 1.71 2008/10/17 05:34:15 ooizumi + Fixed to update pKfi->attr in WFSSrvOpenFile() and WFSSrvWriteFile(). + + Revision 1.70 2008/10/16 09:32:22 ooizumi + Fixed definitions for debug build. + Fixed a bug failed to handle invalid nPos value error in WFSSrvReadFile() and + WFSSrcWriteFile(). + + Revision 1.69 2008/10/15 03:51:46 ooizumi + Fixed a bug in WFSSrvReadFile(). + + Revision 1.68 2008/10/15 00:14:44 kondo_masahiro + Fixed a bug about 4GB-1 + + Revision 1.67 2008/10/14 10:26:24 kondo_masahiro + Added codes to access very large size file data + + Revision 1.66 2008/10/14 10:23:28 ooizumi + Fixed permission APIs to return WFSKRN_RESULT_PERMISSION error when + the path which has no area info was specified. + + Revision 1.65 2008/10/14 08:53:45 ooizumi + Fixed WFSSrvReadFile(). + + Revision 1.64 2008/10/14 06:15:37 ueno + Fixed WFSSrvReadFile to return WFSKRN_RESULT_INVALID when the specified position exceeds the end of the file. + + Revision 1.63 2008/10/14 04:15:41 ooizumi + Modified WFSSrvSearchDirectoryFirst() to convert WFSKRN_RESULT_NOT_DIRECTORY + to WFSKRN_RESULT_NOT_FOUND. + + Revision 1.62 2008/10/14 03:23:15 ooizumi + Fixed WFSSrvUnmountVolume() to check bForce. + Fixed WFSSrvGetVolumeId() to convert device name string to lower case. + + Revision 1.61 2008/10/13 07:25:26 ueno + Fixed WFSSrvUnmountVolume() to return WFSKRN_RESULT_FILE_OPEN when 0 < pEntry->pcd.nOpenHandleCount. + + Revision 1.60 2008/10/10 10:53:33 ooizumi + Fixed a bug WFSSearchDirectry() fails to search path cache entries. + + Revision 1.59 2008/10/10 04:50:35 ueno + Fixed WFSSrvCloseFile() to reduce pin count in case of permission error. + + Revision 1.58 2008/10/10 04:45:41 ooizumi + Modified to return not implemented error when searching path caching directries. + + Revision 1.57 2008/10/10 02:11:19 kondo_masahiro + Fixed a bug to access large files + + Revision 1.56 2008/10/10 01:19:46 ooizumi + Fixed debug code in WFSSrvOpenFile(). + + Revision 1.55 2008/10/09 07:18:24 ooizumi + Modified WFSSrvCreateAndOpenFile() to check nFlags. + + Revision 1.54 2008/10/09 07:02:18 ooizumi + Fixed a bug in WFSSrvCreateDirectry() and WFSSrvCreateAndOpenFile(). + + Revision 1.53 2008/10/09 05:45:45 ooizumi + Fixed to consider WFS_FLAG_CONTIGUOUS_AREA flag, but contiguous area is not yet implemented. + + Revision 1.52 2008/10/09 04:16:53 kondo_masahiro + Fixed member of AreaHdr and AreaInfo + + Revision 1.51 2008/10/09 03:27:25 ooizumi + Implemented permission check sequence in WFSSrvValidateDirectory. + + Revision 1.50 2008/10/08 23:19:54 kondo_masahiro + Added codes to access large size file data + + Revision 1.49 2008/10/08 13:18:42 ueno + Added AdjustMemorySizeForBCache() to adjust user data cache. + + Revision 1.48 2008/10/07 11:22:38 ueno + Implemented WFSSrvGetFreeSpaceSize(). + Fixed content index and timeUpdated in WFSSrvGetFreeSpaceSize(). + Modified WFSSrvCreateDirectory() to check nFlags. + + Revision 1.47 2008/10/07 11:02:58 ooizumi + Fixed to call WFSKrnDbgOutputInit first in WFSKrnInit. + + Revision 1.46 2008/10/07 10:41:56 ooizumi + Several updates for permission functions. + + Revision 1.45 2008/10/07 05:55:36 ueno + Added a workaround for PathCacheDecreaseEntryOpenHandleCount(). + + Revision 1.44 2008/10/03 08:37:56 kondo_masahiro + Fixed codes for porting IOP + + Revision 1.43 2008/10/03 02:08:23 ueno + Modified UnmountAllVolume() to call Srv APIs. + Added a workaround for WFSSrvSearchDirectoryNext(). + + Revision 1.42 2008/10/02 11:02:22 ueno + Modified WFSSrvUnmountVolume() to return WFS_RESULT_FILE_OPEN when the volume has open files. + + Revision 1.41 2008/10/02 08:27:35 ueno + Modified WFSSrvExit() to unmount all volumes. + + Revision 1.40 2008/09/30 02:01:19 ueno + Modified to support large disk ( < 32TB). + + Revision 1.39 2008/09/29 10:19:36 ueno + Revised to support multi-B-tree-based allocator. + + Revision 1.38 2008/09/28 23:31:11 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.37 2008/09/26 11:06:24 ueno + Fixed WFSSrvGetDeviceInfo() to work well even when the device is not mounted. + + Revision 1.36 2008/09/26 07:39:25 ooizumi + Supported to search "/ *", "/dev/ *" and "/vol/ *". + + Revision 1.35 2008/09/05 02:05:00 ooizumi + Fixed to always update pKfi->attr.file.nSize in WFSSrvWriteFile. + + Revision 1.34 2008/09/01 01:57:05 kondo_masahiro + Minor fixed for IOP compiler. + + Revision 1.33 2008/08/29 00:08:12 kondo_masahiro + Fixed WFSSrvGetVolumeId and WFSSrvExecDebugProcedure. + + Revision 1.32 2008/08/27 23:11:12 ooizumi + Fixed. + + Revision 1.31 2008/08/27 23:10:20 ooizumi + Fixed broken lines. + + Revision 1.30 2008/08/27 23:02:55 ooizumi + Fixed newline to CR+LF(Windows format). + + Revision 1.29 2008/08/27 09:36:15 paul + Started coding for different size categories + + Revision 1.28 2008/08/27 04:13:46 nakanose_jin + add assert + + Revision 1.27 2008/08/22 06:38:22 nakanose_jin + kill warning + + Revision 1.26 2008/08/19 03:22:38 ooizumi + Fixed not to free allocated info buffer before calling TransEnd. + + Revision 1.25 2008/08/07 09:10:34 ooizumi + Implemented WFSSrvGetPermisson and WFSSrvSetPermission. + Fixed a bug WFS_PERM_CHANGE_SIZE doesn't effect in WFSSrvWriteFile. + Fixed a bug in WFSSrvWriteFile TransUnpinBlk is not called when DirResizeFile is failed. + Fixed build errors. + + Revision 1.24 2008/08/05 04:07:58 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.23 2008/08/04 22:49:36 paul + Fixed a bug in WFSSrvCloseFile() which caused an error when _CHECK_BLK_USAGE = 0. + + Revision 1.22 2008/07/31 23:59:19 ooizumi + Fixed permission of special directories.. + + Revision 1.21 2008/07/30 21:14:58 paul + Minor changes (debug output) + + Revision 1.20 2008/07/30 06:11:57 ooizumi + Implemented initial version of permission functions. + + Revision 1.19 2008/07/29 22:50:54 ooizumi + Modified to call TransBegin and TransEnd. + Fixed several bugs. + + Revision 1.18 2008/07/28 21:45:37 paul + Improved updateMap processing - should be more correct, and no longer needs a global update counter. + Fixed a bug in WFSSrvDelete() + + Revision 1.17 2008/07/25 02:51:28 paul + Changed from nTransIdx to *pTransInfo + + Revision 1.16 2008/07/21 22:46:05 paul + Fixed bugs in WFSSrvCloseFile(), WFSSrvWriteFile() + Changed name from DirItrPinBlkAndUpdatePtrs() -> DirItrPinBlkAndFixPtrs() + + Revision 1.15 2008/07/18 02:10:00 ueno + Rename WFSDeletePermissions() -> WFSDeleteAccessListEntry(). + + Revision 1.14 2008/07/17 22:44:41 paul + Fixed reading and writing small files via block cache. Changes to support updateMap (not completely finished yet). + + Revision 1.13 2008/07/17 05:30:21 kondo_masahiro + Fixed codes for porting IOP. + + Revision 1.12 2008/07/15 07:44:18 nakanose_jin + change arg order + + Revision 1.11 2008/07/14 06:27:51 ueno + Changed WFSSrvSetAccessList() to WFSSrvSetAccessListEntry(). + + Revision 1.10 2008/07/14 00:39:22 ueno + Added WFSSrvDeletePermissions(), WFSSrvGetAccessList() and WFSSrvSetAccessList(). + + Revision 1.9 2008/07/08 23:39:05 paul + Many changes - to support accessing a real drive via the block cache, and integrate the device & volume mount/unmount + + Revision 1.8 2008/06/09 18:03:00 paul + Many changes including supporting new Path Cache. + + Revision 1.7 2008/05/22 07:57:25 ueno + Fixed debug flag. + + Revision 1.6 2008/05/19 14:11:55 ueno + Added WFSSrvDebugGetRootAreaInfo() for accesslist tests. + + Revision 1.5 2008/05/16 18:51:31 paul + Changed WFSSrvSearchDirectoryNext so that it still works while adding/deleting files in the directory. + + Revision 1.4 2008/05/12 19:05:15 paul + Changed names of PathCache defs + + Revision 1.3 2008/05/10 03:59:43 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.2 2008/04/25 17:29:34 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.16 2008/04/23 00:23:31 paul + Fixed a bug with pattern matcher + + Revision 1.15 2008/04/23 00:09:07 paul + Updated WFSSrv calls to be closer to the real implementation + + Revision 1.14 2008/04/19 05:51:31 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.13 2008/04/18 00:08:33 paul + Changed interface to Dir functions + + Revision 1.12 2008/04/15 18:36:59 paul + Changed definition of DirFind. + + Revision 1.11 2008/04/15 00:27:04 ueno + Added WFSSrvGetPermissionForUser() and WFSSrvSetPermissionForUser(). + + Revision 1.10 2008/04/08 18:43:35 paul + Changed WFS_PERM_OWNER_RW to WFS_PERM_F_ALL + + Revision 1.9 2008/04/04 21:07:20 paul + Moved flag settings into WFSSrvCreateDirectory() instead of at call site. + + Revision 1.8 2008/04/03 23:46:01 kondo_masahiro + change spec of debug proc + + Revision 1.7 2008/03/07 01:33:51 paul + Changed WFSSrvGetVolumeId temporary implementation to use wkg.areHdrRoot + Changed DirFind spec to use DIR_PREFIX_SEARCH for wildcard support. + + Revision 1.6 2008/02/28 06:30:42 kondo_masahiro + Fixed code to accept PPC compiler + + Revision 1.5 2008/02/27 07:26:52 paul + made areaHdrRoot a global so it could be accessed from debug code in wfskrn_Dir.cpp + + Revision 1.4 2008/02/27 00:41:33 paul + Added WFSSrvExecDebugProcedure + + Revision 1.2 2007/12/27 12:06:17 paul + *** empty log message *** + + Revision 1.1 2007/12/27 11:17:20 paul + mostly dummy functions for now.. only what I needed to start working on Dir module + + Revision 1.7 2007/11/02 00:16:30 paul + started logging changes in the file + Added StartPosition to WFSSrvReadFile, WFSSrvWriteFile + +*---------------------------------------------------------------------------*/ + +#undef _KRN_FILE_ +#define _KRN_FILE_ "Api" + +#include "wfskrn_Config.h" +#include "wfskrn_Api.h" +#include "wfskrn_Handles.h" +#include "wfskrn_DirFind.h" +#include "wfskrn_DirNodeStack.h" +#include "wfskrn_DirRxTree.h" +#include "wfskrn_PathCache.h" +#include "wfskrn_PTree.h" +#include "wfskrn_Trans.h" +#ifdef PERMISSION_ENABLED +#include "wfskrn_Permission.h" +#include "wfskrn_Permission_AccessList.h" +#endif +#include "wfskrn_FreeBlkAlloc.h" +WFSKrnResult AreaPinFreeListHdr(AreaInfo *pAreaInfo, u32 nFlags, AreaFreeListHdr **ppAflh); +void AreaUnpinFreeListHdr(AreaInfo *pAreaInfo); + +#include "randomlib.h" + +#if _WIN32 +#include "wfs_Client.h" +#endif + +WFSKrnGlobals wkg ATTRIBUTE_ALIGN(512); + +DirItr gDi; + +AreaInfo *pAhInit; +WFSBlkAdr *pBaInit; + +//u8 *gpPtr = 0; // Pointer of vdsk memory +//u32 gSize = 0; // Size of vdsk memory + +//u32 gNumSectors = 0; // Size of dsk memory + +//u8 *gpCachePtr = 0; // Pointer of cache memory +//u32 gCacheSize = 0; // Size of cache memory + +u8 *gpHeapPtr = 0; // Pointer of heap memory +u32 gHeapSize = 0; // Size of heap memory + +//////////////////////////////////////////// +#define MAX_ALLOC_NUM_SECTORS_FOR_LIST_ALLOCATOR (32*1024*2) // for LIST_BASED_ALLOCATOR (32MB) +//////////////////////////////////////////// + +// #define MAX_ALLOC_NUM_SECTORS (1024*1024*2) +#define MAX_ALLOC_NUM_SECTORS (1024*1024*2*8/32) + +#define TEST_LOG2_SECTOR_SIZE 9 + +#define CHECKDISKFILENAME "TestCheckBitArrayFile" + +u32 WfsKrnGetCurrentClient() { + // Return client index (0..31) + return 0; // ToDo: Support multiple clients. +} + +// Arc file - IOP. + + +static void WfsKrnAttachDetachCallback(u32 bAttach, u32 nDevIdx, u32 nLog2SectorSize, u32 nNumSectors, WFSDevType nDevType, void *pUserData){ + //MyOSReport("WfsKrnAttachDetachCallback(), bAttach = %d, nDevIdx = %d\n", bAttach, nDevIdx); + + WFSKrnResult nResult; + if(nDevIdx < 0 || nDevIdx >= WFSKRN_MAX_DEVICES){ + WFSKrnOutputErrorStr("Error: WfsKrnAttachDetachCallback(), nDevIdx is incorrect.\n"); + return; + } + if(bAttach){ + DeviceInfo *pDevInfo = &wkg.aDevInfo[nDevIdx]; +#if !BTREE_BASED_ALLOCATOR + u32 nMaxSectors = MAX_ALLOC_NUM_SECTORS_FOR_LIST_ALLOCATOR; + if(nNumSectors > nMaxSectors){ + nNumSectors = nMaxSectors; + } +#endif + //osTPrintf("nLog2SectorSize = %d, nTotalSize>>nLog2SectorSize = %d\n", nLog2SectorSize, nNumSectors); + nResult = DeviceAttach(pDevInfo, nDevType, nDevIdx, nLog2SectorSize, nNumSectors); + if (nResult != WFSKRN_RESULT_OK) + { + WFSKrnOutputErrorStr("Device not found.\n"); + return; + } + + pDevInfo->pVolInfo = 0; + //PathCacheDebugOutput(); +#if _WIN32 + // return callback + if(wcg.dcg.pAttachDeviceNameBuffer){ + strcpy(wcg.dcg.pAttachDeviceNameBuffer, pDevInfo->devName.sStr); + } + if(wcg.dcg.cbAttachDevice){ + (*wcg.dcg.cbAttachDevice)(pDevInfo->devName.sStr, wcg.dcg.pAttachDeviceUserData); + } +#endif + } + else{ + DeviceInfo *pDevInfo = &wkg.aDevInfo[nDevIdx]; + DeviceDetach(pDevInfo); + //PathCacheDebugOutput(); +#if _WIN32 + // return callback + if(wcg.dcg.pDetachDeviceNameBuffer){ + strcpy(wcg.dcg.pDetachDeviceNameBuffer, pDevInfo->devName.sStr); + } + if(wcg.dcg.cbDetachDevice){ + (*wcg.dcg.cbDetachDevice)(pDevInfo->devName.sStr, wcg.dcg.pDetachDeviceUserData); + } +#endif + } +} + +static WFSResult AdjustMemorySizeForBCache(u32* nWorkSpaceSize, u32* nBCacheMeta, u32* nBlkUser64K, u32* nBlkUser8K) +{ + u32 nBCacheMax = WFS_BCACHE_META_DATA_SIZE / (sizeof(BCacheEntry) + 2 * sizeof(BCacheListNode)); + *nBCacheMeta = WFS_BLK_CACHE_SIZE / (1<pcd.pData = (void*) 0; + + entry = PathCacheInsertAfterCursorEntry2(wkg.pathCache.pPinAnchor, (utf8*)"/dev"); + if (!entry) + { + return WFS_RESULT_RESOURCE_LIMIT_EXCEEDED; + } + entry->pcd.pData = (void*)WFSKRN_RESULT_SRV_PATH_DEV; + + entry = PathCacheInsertAfterCursorEntry2(wkg.pathCache.pPinAnchor, (utf8*)"/vol"); + if (!entry) + { + return WFS_RESULT_RESOURCE_LIMIT_EXCEEDED; + } + entry->pcd.pData = (void*)WFSKRN_RESULT_SRV_PATH_VOL; + + return WFS_RESULT_OK; +} + +WFSResult WFSKrnInit(void *pWorkSpaceBuffer, u32 nWorkSpaceSize) +{ +#if _DEBUG + WFSKrnDbgOutputInit("CommandLog.txt"); +#endif + u32 nBCacheMeta; + u32 nBlkUser64K; + u32 nBlkUser8K; + + WFSResult nResult = AdjustMemorySizeForBCache(&nWorkSpaceSize, &nBCacheMeta, &nBlkUser64K, &nBlkUser8K); + if (nResult != WFS_RESULT_OK) + { + return nResult; + } + + //MyOSReport("pWorkSpaceBuffer = 0x%x, nWorkSpaceSize = %d\n", pWorkSpaceBuffer, nWorkSpaceSize); + TransModuleInit(); + WFSKrnInitHandles(); + wkg.time = 0; +// wkg.pBlkCache = (u8*)(((size_t)wkg.aStaticMem + WFS_STATIC_MEM_ALIGNMENT-1)&-WFS_STATIC_MEM_ALIGNMENT); + wkg.pBlkCache = (u8*)(((size_t)wkg.aStaticMem + WFS_STATIC_MEM_ALIGNMENT-1)&~(WFS_STATIC_MEM_ALIGNMENT-1)); + + // Prepare block cache meta data for all blocks. + size_t nMemSize = (nBCacheMeta + nBlkUser64K + nBlkUser8K) * (sizeof(BCacheEntry) + 2 * sizeof(BCacheListNode)); + if (nMemSize > WFS_BCACHE_META_DATA_SIZE) { + WFSKrnOutputErrorStr("BCache MetaData Size too small"); + } + u8 *pBlkCacheMetaData = (u8*)((size_t)wkg.pBlkCache+WFS_BLK_CACHE_SIZE); + BCacheInit(WFS_LOG2_SMALL_BLK_SIZE, pBlkCacheMetaData, nMemSize); + + // Prepare the block cache for meta data blocks on the memory for IOP. + if (BCacheGroupInit(BCACHE_GROUP_ID_METABLK, wkg.pBlkCache, WFS_BLK_CACHE_SIZE, WFS_LOG2_SMALL_BLK_SIZE)) { + return WFS_RESULT_INVALID; + } + + // Prepare the block cache for user data blocks on the memory used by PPC. + // 8KB blocks + if (BCacheGroupInit(BCACHE_GROUP_ID_USERBLK_8K, (u8*)pWorkSpaceBuffer, nBlkUser8K * (1<= WFS_MIN_WORK_SPACE_SIZE && nWorkSpaceSize <= WFS_MAX_WORK_SPACE_SIZE); + nResult = WFSKrnInit(pWorkSpaceBuffer, nWorkSpaceSize); + } +#if _WIN32 + //PTreeTest(); + //PathCacheTest(); + WfsKrnAttachDetachCallback(true, 0, TEST_LOG2_SECTOR_SIZE, MAX_ALLOC_NUM_SECTORS, WFS_DEVTYPE_USB_MSC_20, 0); +#elif _TWL + WfsKrnAttachDetachCallback(true, 0, TEST_LOG2_SECTOR_SIZE, MAX_ALLOC_NUM_SECTORS, WFS_DEVTYPE_USB_MSC_20, 0); +#elif _IOP + DeviceAttachDetachRegistCallback(WfsKrnAttachDetachCallback, 0); +#endif + + return nResult; +} + + +static WFSResult UnmountAllVolume(void) +{ + WFSResult result; + WFSFileInfo wfi; + WFSVolumeId volumeId; + WFSPathName pathNameAbsPattern; + WFSSrvSearchDirectoryHandle ssdh; + + osSNPrintf(pathNameAbsPattern.sStr, WFS_MAX_VOLUME_ID_SIZE, "/vol/*"); + pathNameAbsPattern.nLen = STRNLEN(pathNameAbsPattern.sStr, WFS_MAX_PATH_NAME_SIZE); + + result = WFSSrvSearchDirectoryFirst(&pathNameAbsPattern, &ssdh, &wfi); + while (result == WFS_RESULT_OK) + { + volumeId.nLen = STRNLEN(wfi.sFileName, WFS_MAX_VOLUME_ID_SIZE); + ASSERT(volumeId.nLen == WFS_MAX_VOLUME_ID_SIZE); + memmove(volumeId.sStr, wfi.sFileName, volumeId.nLen+1); + result = WFSSrvUnmountVolume(&volumeId, (WFSBool) TRUE); + if (result != WFS_RESULT_OK) + { + goto UNMOUNTALL_RESULT; + } + break; // [check] workaround (WFSSrvSearchDirectoryNext() returns exception now). + // result = WFSSrvSearchDirectoryNext(ssdh, &wfi); // [check] must call next(). + } + + if (result == WFS_RESULT_NOT_FOUND) + { + result = WFS_RESULT_OK; + } + +UNMOUNTALL_RESULT: + WFSSrvSearchDirectoryClose(ssdh); // [check] always can call close()? + return result; +} + + +WFSResult WFSSrvExit(void) { + WFSResult result = UnmountAllVolume(); +#if _DEBUG + ++nDbgCommandCount; + if (result == WFS_RESULT_OK) + { + WFSKrnDbgOutputTest(WFSKrnDbgOutput1("Exit() WFS_RESULT_OK\n")); + } +#endif + return result; +} + + +/*u32 WFSKrnCreateTransIdx() { + static bool bFirstTime = true; + static u32 nTransIdx = 0; + static WFSKrnMutex mx; + if (bFirstTime) { + bFirstTime = false; + WFSKrnInitMutex(&mx); + } + WFSKrnLockMutex(&mx); + ++nTransIdx; + WFSKrnUnlockMutex(&mx); + return nTransIdx; +}*/ + + +WFSResult WFSSrvInitializeDevice(const WFSDeviceName *pDevName) { + WFSKrnResult nResult; + TransBlkAdr tba; + tba.pTransInfo = TransBegin(); +#ifdef PERMISSION_ENABLED + // ToDo: Now we cannot access from NDEV by ROOT. It is need to implement SetTitleId on WFSKRN. + if(tba.pTransInfo->nTitleId != WFS_ROOT_ID) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit; + } +#endif + DeviceInfo *pDevInfo = DeviceGetDeviceInfo(pDevName); + if (pDevInfo == 0) { + nResult = WFSKRN_RESULT_NOT_FOUND; + goto Exit; + } + if (pDevInfo->nFlags & WFS_DEVFLAG_UNUSABLE) { + nResult = WFSKRN_RESULT_DEV_UNUSABLE; + goto Exit; + } + if (pDevInfo->nFlags & WFS_DEVFLAG_WRITE_PROTECTED) { + nResult = WFSKRN_RESULT_WRITE_PROTECTED; + goto Exit; + } + VolumeInfo *pVolInfo; + if (pDevInfo->pVolInfo == 0) { + pDevInfo->pVolInfo = VolumeAlloc(); + VolumeAddToMountedList(pDevInfo->pVolInfo); + pVolInfo = pDevInfo->pVolInfo; + pVolInfo->nClientsMountedBy = 0; + pVolInfo->pDevInfo = pDevInfo; + } else { + pVolInfo = pDevInfo->pVolInfo; + if (pVolInfo->nClientsMountedBy) { + nResult = WFSKRN_RESULT_DEV_IN_USE; + goto Exit; + } + } + nResult = VolumeInit(pVolInfo, WFS_LOG2_SMALL_BLK_SIZE, (pDevInfo->dh.nNumSectors>>WFS_LOG2_SMALL_BLK_SIZE) * pDevInfo->nSectorSize); + if (nResult != WFSKRN_RESULT_OK) { + goto Exit; + } + tba.pAreaInfo = &pVolInfo->rootAreaInfo; + tba.nBlkAdr = pVolInfo->rootAreaInfo.ah.nRootBlkAdr; + DirBlkHdr *pBlkHdr; + nResult = DirCreateAndInitNewBlk(&tba, (WFSMetaDataFlags)(WFS_MDF_DIR_LEAF_BLK | WFS_MDF_DIR_ROOT_BLK), &pBlkHdr); // Map + if (nResult != WFSKRN_RESULT_OK) { + goto Exit; + } + DirBlkCreateRootNode(pBlkHdr); + TransUnpinBlk(&tba); + VolumeUnmount(pVolInfo); + pDevInfo->nFlags &= ~WFS_DEVFLAG_NOT_INITIALIZED; + nResult = WFSKRN_RESULT_OK; +Exit: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput3("InitializeDevice(\"%s\") WFS_RESULT_%s\n", pDevName->sStr, WFSKrnGetErrorString(nResult))); +#endif + TransEnd(tba.pTransInfo); + return (WFSResult)nResult; +} + + +WFSResult WFSSrvGetDeviceInfo(const WFSDeviceName *pDevName, WFSDeviceInfo *pDi) { + WFSKrnResult nResult = WFSKRN_RESULT_OK; + DeviceInfo *pDevInfo = DeviceGetDeviceInfo(pDevName); + if (pDevInfo == 0) { + nResult = WFSKRN_RESULT_NOT_FOUND; + goto Exit; + } + pDi->nDevFlags = pDevInfo->nFlags; + if (0 == (pDevInfo->nFlags & WFS_DEVFLAG_NOT_INITIALIZED)) { + VolumeInfo *pVolInfo = pDevInfo->pVolInfo; + if (!pVolInfo || (0 == (pVolInfo->nClientsMountedBy & (1<nDevFlags |= WFS_DEVFLAG_NOT_MOUNTED; + } + } + pDi->nDevType = pDevInfo->nDevType; + pDi->nDevTotalCapacity = pDevInfo->nTotalCapacity; +Exit: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput2("GetDeviceInfo(\"%s\", pDi) WFS_RESULT_OK\n", pDevName->sStr)); +#endif + return (WFSResult) nResult; +} + + +WFSResult WFSSrvMountDevice(const WFSDeviceName *pDevName, WFSVolumeId *pVolumeIdBuffer) { + WFSKrnResult nResult = WFSKRN_RESULT_OK; + DeviceInfo *pDevInfo = DeviceGetDeviceInfo(pDevName); + if (pDevInfo == 0) { + nResult = WFSKRN_RESULT_NOT_FOUND; + goto Exit; + } + if (pDevInfo->nFlags & WFS_DEVFLAG_UNUSABLE) { + nResult = WFSKRN_RESULT_DEV_UNUSABLE; + goto Exit; + } + if (pDevInfo->nFlags & WFS_DEVFLAG_NOT_INITIALIZED) { + nResult = WFSKRN_RESULT_DEV_NOT_INITIALIZED; + goto Exit; + } + VolumeInfo *pVolInfo = pDevInfo->pVolInfo; + u32 nClientBit = 1<nClientsMountedBy & nClientBit) { + nResult = WFSKRN_RESULT_ALREADY_MOUNTED; + goto Exit; + } + } else { + nResult = DeviceMountVolume(pDevInfo); + if (nResult != WFSKRN_RESULT_OK) { + goto Exit; + } + pVolInfo = pDevInfo->pVolInfo; + } + WFSVolumeId volId; + VolumeConvertU32ToVolId(&volId, pVolInfo->vh.nVolId); + memcpy(pVolumeIdBuffer->sStr, volId.sStr, volId.nLen+1); +#if _DEBUG + pVolInfo->volId = volId; +#endif + pVolInfo->nClientsMountedBy |= nClientBit; + if (pVolInfo->nClientsMountedBy == nClientBit) { + utf8 sVolPath[WFS_MAX_VOLUME_ID_SIZE + 6]; + osSNPrintf(sVolPath, WFS_MAX_VOLUME_ID_SIZE + 6, "/vol/%s", volId.sStr); + PathCacheEntry *pEntry = PathCacheInsertAfterCursorEntry2(wkg.pathCache.pPinAnchor, sVolPath); + if (pEntry) + { + pEntry->pcd.pData = pVolInfo; + DirInitDirEntryAttrHdr(&pVolInfo->rootAttr); + } + else + { + nResult = WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED; + } + } +Exit: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput2("MountDevice(\"%s\", vid) ", pDevName->sStr); + if (nResult == WFSKRN_RESULT_OK) { + WFSKrnDbgOutput2("vid=%s ", pVolumeIdBuffer->sStr); + } + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString(nResult)); + ); +#endif + return (WFSResult)nResult; +} + + +WFSResult WFSSrvUnmountVolume(const WFSVolumeId *pVolumeId, WFSBool bForce) { + WFSKrnResult nResult = WFSKRN_RESULT_OK; + utf8 sVolPath[WFS_MAX_VOLUME_ID_SIZE + 6]; + osSNPrintf(sVolPath, WFS_MAX_VOLUME_ID_SIZE + 6, "/vol/%s", pVolumeId->sStr); + VolumeInfo *pVolInfo; + RxtItr rxi; + rxi.pStrPtr = sVolPath; + PathCacheEntry *pEntry = PathCacheFind2(&rxi, (void **)&pVolInfo); + if (!pEntry) { + nResult = WFSKRN_RESULT_NOT_FOUND; + goto Exit; + } + if (0 < pEntry->pcd.nOpenHandleCount && + (!bForce || pVolInfo->pDevInfo->bInUse)) // Todo : the root entry will have to be unpined. + { +#if _DEBUG + PathCacheDebugOutput(); +#endif + nResult = WFSKRN_RESULT_FILE_OPEN; + goto Exit; + } + u32 nClientBit = 1<nClientsMountedBy & nClientBit)) { + nResult = WFSKRN_RESULT_NOT_FOUND; + goto Exit; + } + pVolInfo->nClientsMountedBy &= ~nClientBit; + if (pVolInfo->nClientsMountedBy == 0) { + nResult = PathCacheDeleteSubTree(pEntry); + VolumeUnmount(pVolInfo); + // ToDo: For better test reproducibility, it may be good to detect special case of no devices mounted - then re-initialize path cache + } +Exit: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput4("UnmountVolume(\"%s\", bForce=%d) WFS_RESULT_%s\n", pVolumeId->sStr, (int)bForce, WFSKrnGetErrorString(nResult))); +#endif + return (WFSResult)nResult; +} + + +WFSResult WFSSrvGetVolumeId(const WFSDeviceName *pDevName, WFSVolumeId *pVolumeIdBuffer) { +/* + WFSKrnResult nResult = WFSKRN_RESULT_OK; + DeviceInfo *pDevInfo = DeviceGetDeviceInfo(pDevName); + if (pDevInfo == 0) { + nResult = WFSKRN_RESULT_NOT_FOUND; + goto Exit; + } + if (pDevInfo->nFlags & WFS_DEVFLAG_UNUSABLE) { + nResult = WFSKRN_RESULT_DEV_UNUSABLE; + goto Exit; + } + if (pDevInfo->nFlags & WFS_DEVFLAG_NOT_INITIALIZED) { + nResult = WFSKRN_RESULT_DEV_NOT_INITIALIZED; + goto Exit; + } + WFSVolumeId volId; + VolumeInfo *pVolInfo = pDevInfo->pVolInfo; + ASSERT(pVolInfo); + VolumeConvertU32ToVolId(&volId, pVolInfo->vh.nVolId); + //memcpy(pVolumeIdBuffer, volId.sStr, volId.nLen+1); + *pVolumeIdBuffer = volId; +Exit: +*/ + WFSKrnResult nResult = WFSKRN_RESULT_OK; + WFSDeviceName devName; + WFSKrnExitOnError(WFSKrnValidateCopyStrAndConvertToLowerCase(devName.sStr, pDevName->sStr, pDevName->nLen, WFS_MAX_DEVICE_NAME_SIZE)); + devName.nLen = pDevName->nLen; + WFSKrnExitOnError(DeviceGetVolumeId(&devName, pVolumeIdBuffer)); +Exit: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput2("GetVolumeId(\"%s\", vid) ", pDevName->sStr); + if (nResult == WFSKRN_RESULT_OK) { + WFSKrnDbgOutput2("vid=%s ", pVolumeIdBuffer->sStr); + } + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString(nResult)); + ); +#endif + return (WFSResult)nResult; +} + + +WFSResult WFSSrvGetFreeSpaceSize(const WFSPathName *pAbsPathName, u64 *pSize) { + WFSKrnResult nResult = WFSKRN_RESULT_INVALID; + + WFSPathName path; + WFSKrnExit2OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + PathCacheItr pci; + pci.di.tba.pTransInfo = TransBegin(); + WFSKrnExit1OnError(PathCacheFindPath(pAbsPathName, path.sStr, &pci)); +#ifdef PERMISSION_ENABLED + // [check] permissions. NYI. + /* + u32 permissions; + WFSKrnExit1OnError(WFSKrnGetInheritedPermissionForUserDi(&pci, &permissions, pci.di.tba.pTransInfo->nTitleId)); + if((permissions & WFS_PERM_DELETE_OR_MOVE) == 0) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } + */ +#endif + AreaInfo *pAreaInfo = pci.di.tba.pAreaInfo; + if (pAreaInfo) + { + nResult = AreaPinFreeListHdr(pAreaInfo, BCACHE_FLAG_READ | BCACHE_FLAG_DIRTY, &pAreaInfo->pAflh); + if (nResult == WFSKRN_RESULT_OK) + { + u32 numBlk = FreeBlkGetFreeSize(pAreaInfo); + *pSize = (u64) pAreaInfo->nBlkSize * numBlk; + AreaUnpinFreeListHdr(pAreaInfo); + } + } + else + { + nResult = WFSKRN_RESULT_INVALID; + } +Exit1: + DirItrClose(&pci.di); + TransEnd(pci.di.tba.pTransInfo); +Exit2: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput3("WFSSrvGetFreeSpaceSize(\"%s\", pSize) WFS_RESULT_%s\n", pAbsPathName->sStr, WFSKrnGetErrorString(nResult))); +#endif + return (WFSResult)nResult; +} + + +WFSResult WFSSrvGetAttributes(const WFSPathName *pAbsPathName, WFSFileAttributes *pFa) { +#if _DEBUG_BREAK_POINT + if (nDbgCommandCount == 144761) { + int a;a=0; + } +#endif + WFSKrnResult nResult = WFSKRN_RESULT_OK; + WFSPathName path; + WFSKrnExit2OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + PathCacheItr pci; + pci.di.tba.pTransInfo = TransBegin(); + WFSKrnExit1OnError(PathCacheFindPath(pAbsPathName, path.sStr, &pci)); +#ifdef PERMISSION_ENABLED + // Check the permission of parent dir and specified entry + u32 parentPermissions; + u32 permissions; + WFSKrnExit1OnError(WFSKrnGetInheritedPermissionForUserDi(&pci, &permissions, pci.di.tba.pTransInfo->nTitleId)); + if((pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) == 0 || !(permissions & WFS_PERM_LIST)) + { + WFSKrnExit1OnError(WFSKrnGetParentInheritedPermissionForUserPci(&pci, &parentPermissions, pci.di.tba.pTransInfo->nTitleId)); + if(!(parentPermissions & WFS_PERM_LIST)) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } + } +#endif + +#ifdef PERMISSION_ENABLED + // Get inherited permissions + pFa->nFlags = permissions | + (pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) | (pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_CONTIGUOUS_AREA); +#else + pFa->nFlags = (pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY); // ToDo: Get permission bits for current user +#endif + if (pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) { + pFa->nNumEntries = 0; // ToDo: Remove NumEntries parameter from WFS API + pFa->nCidx = 0; // A directory does not have a content index. + } else { + pFa->nFileSize = pci.di.pAttrHdr->file.nSize; + pFa->nCidx = pci.di.pAttrHdr->file.nContentIdx; + } + pFa->timeCreated = pci.di.pAttrHdr->timeCreated; + pFa->timeUpdated = pci.di.pAttrHdr->timeUpdated; +Exit1: + DirItrClose(&pci.di); + if(pci.di.tba.pTransInfo == 0 || pci.di.tba.pTransInfo->link.pNext == 0){ + int a; a=0; + } + TransEnd(pci.di.tba.pTransInfo); +Exit2: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput3("GetAttributes(\"%s\", pFa) WFS_RESULT_%s\n", pAbsPathName->sStr, WFSKrnGetErrorString(nResult))); +#endif + return (WFSResult)nResult; +} + + +WFSResult WFSSrvChangePermissions(const WFSPathName *pAbsPathName, u32 nFlags, u32 nMask) { +/* WFSPathName *papn; papn = (WFSPathName*)pAbsPathName; // for warning +#if _IOP + pAh = (AreaInfo*)((u32)pAh & 0x7fffffff); + pBa = (WFSBlkAdr*)((u32)pBa & 0x7fffffff); +#endif + //osTPrintf("pAreaInfo = 0x%x, pBlkAdr = 0x%x\n",pAh, pBa); + /////////////////////////////////////// + WfsInitRootArea(0, pAh, gpPtr, gSize); // for debug wfskrn + WfsAreaAllocBlks(pAh, 0, 1, pBa, sizeof(WFSBlkAdr)); + /////////////////////////////////////// +#if _IOP + IOS_FlushDCache(pBa, sizeof(WFSBlkAdr)); +#endif*/ +#ifdef PERMISSION_ENABLED + WFSKrnResult nResult = WFSKRN_RESULT_OK; + WFSPathName path; + WFSKrnExit2OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + PathCacheItr pci; + pci.di.tba.pTransInfo = TransBegin(); + WFSKrnExit1OnError(PathCacheFindPath(pAbsPathName, path.sStr, &pci)); + if (!pci.di.tba.pAreaInfo) + { + // no one can set permission to the entry which has no area info. + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } + WFSKrnExit1OnError(DirGetBlk(&pci.di, TRANS_FLAG_RW_BLK, 0)); + WFSKrnExit1OnError(WFSKrnSetInheritedPermissionForUser(&pci, nFlags, nMask, pci.di.tba.pTransInfo->nTitleId, pci.di.tba.pTransInfo->nTitleId)); + if (*pci.rxi.pStrPtr==0) { // The pEntry refers to the object (rather than the parent dir) + // Update acl index data in path cache tree + pci.pEntry->pcd.nAccessListIdx = pci.di.pAttrHdr->nAccessListIdx; + } +Exit1: + DirItrClose(&pci.di); + TransEnd(pci.di.tba.pTransInfo); +Exit2: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput3("ChangePermission(\"%s\", nFlags, nMask) WFS_RESULT_%s\n", pAbsPathName->sStr, WFSKrnGetErrorString(nResult))); +#endif + return (WFSResult)nResult; +#else + osTPrintf("WFSSrvChangePermissionForUser()\n"); + return WFS_RESULT_OK; +#endif +} + + +WFSResult WFSSrvCreateDirectory(const WFSPathName *pAbsPathName, u32 nFlags, u64 nQuota) { +#if _DEBUG_BREAK_POINT + static int c=0;++c;if(c>=144759){ + int a; a=0; + } +#endif + WFSKrnResult nResult=WFSKRN_RESULT_OK; + PathCacheItr pci; + WFSPathName path; + if (nFlags & ~(WFS_FLAG_CONTIGUOUS_AREA | WFS_PERM_FULL)) + { + nResult = WFSKRN_RESULT_INVALID; + goto Exit4; + } + WFSKrnExit4OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + pci.di.tba.pTransInfo = TransBegin(); + nResult = PathCacheFindParentDir(pAbsPathName, path.sStr, &pci); + switch(nResult) { + case WFSKRN_RESULT_OK: + case WFSKRN_RESULT_SRV_PATH_VOL_ROOT: + break; + case WFSKRN_RESULT_SRV_PATH_DEPTH_1: + case WFSKRN_RESULT_SRV_PATH_DEV: + case WFSKRN_RESULT_SRV_PATH_VOL: + nResult = PathCacheFindPath(pAbsPathName, path.sStr, &pci); + switch(nResult) + { + case WFSKRN_RESULT_NOT_FOUND: + break; + case WFSKRN_RESULT_OK: + nResult = WFSKRN_RESULT_ALREADY_EXISTS; + default: + goto Exit3; + } + break; + default: + goto Exit3; + } +#ifdef PERMISSION_ENABLED + // Check the permission of parent dir and specified entry + u32 permissions; + WFSKrnExit3OnError(WFSKrnGetInheritedPermissionForUserPci(&pci, &permissions, pci.di.tba.pTransInfo->nTitleId)); + if(!(permissions & WFS_PERM_ADD_OR_DELETE_SUBDIR)) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit3; + } +#else // PERMISSION_ENABLED + if(pci.di.tba.pAreaInfo == NULL) + { + // system path. + osTPrintf("WFSSrvCreateDirectory(): system path\n"); + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit3; + } +#endif // PERMISSION_ENABLED + WFSBlkAdr nSubDirBlkAdr; + // ToDo: Create sub area when WFS_FLAG_CONTIGUOUS_AREA is specified. + WFSKrnExit3OnError(AreaAllocBlks(pci.di.tba.pAreaInfo, pci.di.tba.nBlkAdr, pci.di.tba.pAreaInfo->ah.nLog2BlkSize, 1, &nSubDirBlkAdr, sizeof(WFSBlkAdr))); + WFSKrnExit2OnError(DirInsertRaw(&pci.di.name, &pci.di, 0)); + WFSKrnStoreCaseInformationStr(pci.di.pAttrHdr->aCaseBitArray, pci.pRawNameStart, pci.di.name.nLen); + // Mark the file as open-for-writing +#ifdef PERMISSION_ENABLED + // Get the correct Access List Idx + pci.di.pAttrHdr->nAccessListIdx = WFS_FLAG_IS_A_DIRECTORY | (nFlags & WFS_FLAG_CONTIGUOUS_AREA); // the default is also the empty accesslist. + pci.di.pAttrHdr->nObjCreator = pci.di.tba.pTransInfo->nTitleId; + WFSKrnExit1OnError(WFSKrnSetInheritedPermissionForUser(&pci, nFlags, WFS_PERM_FULL, pci.di.tba.pTransInfo->nTitleId, pci.di.tba.pTransInfo->nTitleId)); +#else + // ToDo: Add the calls to get the correct Access List Idx + pci.di.pAttrHdr->nAccessListIdx = WFS_FLAG_IS_A_DIRECTORY | nFlags; +#endif + pci.di.pAttrHdr->dir.nQuota = (WFSBlkAdr)(nQuota/pci.di.tba.pAreaInfo->nBlkSize); + pci.di.pAttrHdr->dir.nSubDirBlkAdr = nSubDirBlkAdr; + pci.di.pAttrHdr->timeCreated = ++wkg.time; + pci.di.pAttrHdr->timeUpdated = wkg.time; + TransUnpinBlk(&pci.di.tba); + pci.di.tba.nBlkAdr = nSubDirBlkAdr; + WFSKrnExit1OnError(DirCreateAndInitNewBlk(&pci.di.tba, (WFSMetaDataFlags)(WFS_MDF_DIR_LEAF_BLK | WFS_MDF_DIR_ROOT_BLK), &pci.di.pBlkHdr)); + DirBlkCreateRootNode(pci.di.pBlkHdr); + goto Exit3; +Exit1: + DirItrClose(&pci.di); + if( PathCacheFindPath(pAbsPathName, path.sStr, &pci) != WFSKRN_RESULT_OK) { + goto Exit2; + } + if( *pci.rxi.pStrPtr == 0) { + PathCacheDeleteSubTree(pci.pEntry); + } + DirDeleteEntry(&pci.di); +Exit2: + AreaFreeBlks(pci.di.tba.pAreaInfo, pci.di.tba.pAreaInfo->ah.nLog2BlkSize, 1, &nSubDirBlkAdr, sizeof(WFSBlkAdr)); +Exit3: + DirItrClose(&pci.di); + TransEnd(pci.di.tba.pTransInfo); +Exit4: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput5("CreateDirectory(\"%s\", f=%x, q=%I64d) WFS_RESULT_%s\n", pAbsPathName->sStr, nFlags, nQuota, WFSKrnGetErrorString(nResult))); +#endif + return (WFSResult)nResult; +} + + +#define MAX_SEARCH_HANDLE 16 + +typedef struct{ + WFSSrvSearchDirectoryHandle sdh; + WFSFileName filename; +}SearchBuf; + +//static SearchBuf gSb[MAX_SEARCH_HANDLE]; + + +void WFSKrnNormalizePattern(utf8 *sPattern) { + utf8 *sTo = sPattern; + while(*sPattern) { + *sTo = *sPattern; + if (*sPattern == '*') { + // Convert substrings containing N '*' and M '?' characters only, to a string of M '?' characters followed by a single '*'. + do { + if (*sPattern == '?') { + *sTo++ = '?'; + } + ++sPattern; + } while ((*sPattern=='*')||(*sPattern=='?')); + *sTo = '*'; + } else { + ++sPattern; + } + ++sTo; + } + *sTo = 0; +} + + +bool WFSKrnNameMatchesPattern(utf8 *sName, utf8 *sPattern) { + while ((*sPattern != '*') && (*sPattern != 0)) { + if (*sPattern != *sName) { + if ((*sPattern != '?') || (*sName == 0)) { + return false; + } + } + ++sPattern; + ++sName; + } + if (*sPattern == 0) { + return (*sName == 0); + } + // Skip the '*' char + ++sPattern; + // The corresponding sequence from sName can be any string of 0 or more characters + do { + while ((*sName != 0) && (*sName != *sPattern)) { + ++sName; + } + if (*sName==0) { + return (*sPattern == 0); + } + if (WFSKrnNameMatchesPattern(sName, sPattern)) { + return true; + } + ++sName; + } while (*sName != 0); + return false; +} + +void WfsKrnGetAttrPtr(void *pData, DirEntryAttrHdr **ppAttrHdr) { + if (((s32)pData == WFSKRN_RESULT_SRV_PATH_DEV) || + ((s32)pData == WFSKRN_RESULT_SRV_PATH_VOL)) + { + *ppAttrHdr = &wkg.devDirAttr; + } else if (((DeviceInfo*)pData >= wkg.aDevInfo)&&((DeviceInfo*)pData < &wkg.aDevInfo[WFSKRN_MAX_DEVICES])) { + *ppAttrHdr = &wkg.devAttr; + } else if (((VolumeInfo*)pData >= wkg.aVolInfo)&&((VolumeInfo*)pData < &wkg.aVolInfo[WFSKRN_MAX_VOLUMES])) { + *ppAttrHdr = &((VolumeInfo*)pData)->rootAttr; + } +} + +WFSKrnResult WFSKrnSearchDirectoryCommon(WFSKrnResult nResult, WFSKrnSearchDirInfo *pSdi, WFSFileInfo *pFi, utf8 *sName, utf8 *sPattern) { + while(1) { + switch(nResult) { + case WFSKRN_RESULT_OK: + case WFSKRN_RESULT_DIR_ENTRY_FOUND: + case WFSKRN_RESULT_DIR_NODE_STRING_PREFIX: + case WFSKRN_RESULT_DIR_CHOICE_PREFIX: + if (WFSKrnNameMatchesPattern(sName, sPattern)) { + if (pSdi->pci.di.tba.pAreaInfo) { + WFSKrnCopyFileNameAndRestoreCase(pFi->sFileName, &pSdi->pci.di.name, pSdi->pci.di.pAttrHdr->aCaseBitArray); + } else { + void *pData; + pSdi->pci.rxi.pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + RxtGetChildOfs(1, pSdi->pci.rxi.pNodeHdr)); + pData = ((PathCacheEntry *)pSdi->pci.rxi.pNodeHdr)->pcd.pData; + WfsKrnGetAttrPtr(pData, &pSdi->pci.di.pAttrHdr); + pSdi->pci.di.name.nLen = pSdi->pci.rxi.pStrPtr - pSdi->pci.di.name.sStr; + + memcpy(pFi->sFileName, pSdi->pci.di.name.sStr, pSdi->pci.di.name.nLen); + pFi->sFileName[pSdi->pci.di.name.nLen] = 0; + } + DirEntryAttrHdr *pAttrHdr = pSdi->pci.di.pAttrHdr; + pFi->attr.nCidx = pAttrHdr->file.nContentIdx; +#ifdef PERMISSION_ENABLED + // Get inherited permissions + WFSKrnReturnOnError(WFSKrnGetInheritedPermissionForUserDi(&pSdi->pci, &pFi->attr.nFlags, pSdi->pci.di.tba.pTransInfo->nTitleId)); + pFi->attr.nFlags |= (pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) | (pAttrHdr->nAccessListIdx & WFS_FLAG_CONTIGUOUS_AREA); +#else + pFi->attr.nFlags = pAttrHdr->nAccessListIdx; // ToDo: Get permission bits for current user +#endif + if (pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) { + pFi->attr.nNumEntries = 0; // ToDo: Remove NumEntries parameter from WFS API + } else { + pFi->attr.nFileSize = pAttrHdr->file.nSize; + } + pFi->attr.timeCreated = pAttrHdr->timeCreated; + pFi->attr.timeUpdated = pAttrHdr->timeUpdated; +#if _DEBUG_DIR + pFi->attr.timeCreated = pSdi->pci.di.tba.nBlkAdr; +#endif + return WFSKRN_RESULT_OK; + } + if (pSdi->pci.di.tba.pAreaInfo) + { + nResult = DirNextRaw(&pSdi->pci.di.name, &pSdi->pci.di); + } + else + { + nResult = RxtNext(wkg.pathCache.pRxtHdr, &pSdi->pci.rxi); + } + continue; + case WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH: + case WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND: + return WFSKRN_RESULT_NOT_FOUND; + default: + return nResult; + } + } +} + +WFSResult WFSSrvSearchDirectoryFirst(const WFSPathName *pAbsPattern, WFSSrvSearchDirectoryHandle *pSsdh, WFSFileInfo *pFi) { +#if _DEBUG_BREAK_POINT + if (nDbgCommandCount >= 9390) { + int a;a=0; + } +#endif + WFSKrnResult nResult; + WFSPathName path; + WFSKrnExit3OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPattern->sStr, pAbsPattern->nLen, WFS_MAX_PATH_NAME_SIZE)); + WFSKrnSearchDirInfo *pSdi; + WFSKrnExit3OnError(WFSKrnSearchDirInfoAlloc(&pSdi)); + pSdi->pci.di.tba.pTransInfo = TransBegin(); + *pSsdh = pSdi->nHandle; + nResult = PathCacheFindParentDir(pAbsPattern, path.sStr, &pSdi->pci); + switch(nResult) { + case WFSKRN_RESULT_OK: + case WFSKRN_RESULT_SRV_PATH_DEPTH_1: + case WFSKRN_RESULT_SRV_PATH_DEV: + case WFSKRN_RESULT_SRV_PATH_VOL: + case WFSKRN_RESULT_SRV_PATH_VOL_ROOT: + break; + case WFSKRN_RESULT_NOT_DIRECTORY: + nResult = WFSKRN_RESULT_NOT_FOUND; + default: + goto Exit2; + } +#ifdef PERMISSION_ENABLED + // Check the permission of parent dir + u32 permissions; + WFSKrnExit2OnError(WFSKrnGetInheritedPermissionForUserPci(&pSdi->pci, &permissions, pSdi->pci.di.tba.pTransInfo->nTitleId)); + if(!(permissions & WFS_PERM_LIST)) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit2; + } +#endif + //pPci->pEntry = PathCacheIncrementalInsertAfterCursorEntry(wkg.pathCache.pPinAnchor, &pPci->rxi, nPrefixLen, nSuffixLen); +#if _DEBUG + memcpy(pSdi->pathDebug.sStr, path.sStr, pAbsPattern->nLen); pSdi->pathDebug.sStr[pAbsPattern->nLen]=0; +#endif +#if _DEBUG_PATH_CACHE + PathCachePinEntry(pSdi->pci.pEntry, path.sStr); + PathCacheIncreaseEntryOpenHandleCount(&pSdi->pci, WFS_ACCESS_READ, path.sStr); +#else + PathCachePinEntry(pSdi->pci.pEntry); + PathCacheIncreaseEntryOpenHandleCount(&pSdi->pci, WFS_ACCESS_READ); +#endif + WFSKrnCopyStrAndConvertToLowerCase(pSdi->pattern.sStr, pSdi->pci.pRawNameStart, pSdi->pci.di.name.nLen); + pSdi->pattern.nLen = pSdi->pci.di.name.nLen; + WFSKrnNormalizePattern(pSdi->pattern.sStr); + utf8 *pDstPtr=pSdi->pci.di.name.sStr; + utf8 *pSrcPtr=pSdi->pattern.sStr; + utf8 *pSrcEnd=&pSrcPtr[pSdi->pattern.nLen]; + for(; pSrcPtrpci.di.tba.pAreaInfo == 0) { + void *pData; + s32 nStrLen = pSdi->pci.pNameEnd - pSdi->pci.rxi.pStrPtr; + if (nStrLen == 0) { + // special code for root '/' dir. + pSdi->pci.di.pAttrHdr = &wkg.rootDirAttr; + nResult = WFSKRN_RESULT_OK; + } else { + PathCacheIncrementalFindEntry(&pSdi->pci.rxi, 1, &pData); + pSdi->pci.rxi.pStrPtr = pSdi->pci.di.name.sStr; + nResult = RxtNextUntilSeparator(wkg.pathCache.pRxtHdr, &pSdi->pci.rxi, '/'); + if (nResult != WFSKRN_RESULT_OK) { + goto Exit1; + } + pDstPtr = pSdi->pci.di.name.sStr; + pSrcPtr = pSdi->pattern.sStr; + } + } else { + pSdi->pci.di.nBlkDepth = 0; +#if _DEBUG_BREAK_POINT + if (pSdi->pci.di.tba.nBlkAdr != pSdi->pci.nRootBlkAdr) { + int a;a=0; + } +#endif + //pSdi->nRootBlkAdr = pSdi->pci.di.tba.nBlkAdr; + nResult = DirFind(&pSdi->pci.di.name, &pSdi->pci.di, DIR_MAX_BLK_DEPTH, DIR_FIND_MODE_PREFIX_SEARCH); + } + nResult = WFSKrnSearchDirectoryCommon(nResult, pSdi, pFi, pDstPtr, pSrcPtr); + if (nResult == WFSKRN_RESULT_OK) { + if (pSdi->pci.di.tba.pAreaInfo) { + TransUnpinBlk(&pSdi->pci.di.tba); + } + TransEnd(pSdi->pci.di.tba.pTransInfo); + } else { + if (pSdi->pci.di.tba.pAreaInfo) + { + DirItrClose(&pSdi->pci.di); + } +Exit1: + #if _DEBUG_PATH_CACHE + PathCacheDecreaseEntryOpenHandleCount(&pSdi->pci, path.sStr); + #else + PathCacheDecreaseEntryOpenHandleCount(&pSdi->pci); + #endif +Exit2: + TransEnd(pSdi->pci.di.tba.pTransInfo); + WFSKrnSearchDirInfoFree(pSdi); + } +Exit3: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput2("SearchDirectoryFirst(\"%s\", pSsdh, pFi) ", pAbsPattern->sStr); + if (nResult == WFSKRN_RESULT_OK) { + WFSKrnDbgOutput3("sdh=%04x fn=\"%s\" ", *pSsdh, pFi->sFileName); + } + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString(nResult)); + ); +#endif + return (WFSResult)nResult; +} + +WFSResult WFSSrvSearchDirectoryNext(WFSSrvSearchDirectoryHandle ssdh, WFSFileInfo *pFi) { +#if _DEBUG_BREAK_POINT + static int c=0; ++c; if (c>=0x7d68) { + int a; a=0; + } +#endif + WFSKrnResult nResult; + WFSKrnSearchDirInfo *pSdi; + WFSKrnExitOnError(WFSKrnGetSearchDirInfo(&pSdi, ssdh)); + //nResult = DirNextRaw(&pSdi->pci.di.name, &pSdi->pci.di); // This is unsafe since the directory may have changed + // DirFindNext is slower than DirNextRaw becuase it starts from the root block of the directory every time. + // ToDo: Add code to determine when it is necessary to use DirFindNext + pSdi->pci.di.tba.pTransInfo = TransBegin(); + DirItrCloseNoUnpin(&pSdi->pci.di); + pSdi->pci.di.tba.nBlkAdr = pSdi->pci.nRootBlkAdr; + // ToDo: Add code for special dirs they have no DirItr. + if (pSdi->pci.di.tba.pAreaInfo == 0) { + s32 nStrLen = pSdi->pci.pNameEnd - pSdi->pci.rxi.pStrPtr; + if (nStrLen == 0) { + // special code for root '/' dir. + nResult = WFSKRN_RESULT_NOT_FOUND; + TransEnd(pSdi->pci.di.tba.pTransInfo); + goto Exit; + } else { + // To make pSdi->pci.rxi.pNodeHdr to point RxtAttrHdr. + pSdi->pci.rxi.pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + pSdi->pci.rxi.pNodeHdr->nParentOfs); + pSdi->pci.rxi.pStrPtr = pSdi->pci.di.name.sStr; + nResult = RxtFindNext(wkg.pathCache.pRxtHdr, &pSdi->pci.rxi, '/'); + if (nResult != WFSKRN_RESULT_OK) { + TransEnd(pSdi->pci.di.tba.pTransInfo); + goto Exit; + } + } + } else { + nResult = DirFindNext(&pSdi->pci.di.name, &pSdi->pci.di); + } + nResult = WFSKrnSearchDirectoryCommon(nResult, pSdi, pFi, pSdi->pci.di.name.sStr, pSdi->pattern.sStr); + if (pSdi->pci.di.tba.pAreaInfo) { + TransUnpinBlk(&pSdi->pci.di.tba); + } + TransEnd(pSdi->pci.di.tba.pTransInfo); +Exit: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput2("SearchDirectoryNext(sdh=%04x, pFi) ", ssdh); + if (nResult == WFSKRN_RESULT_OK) { + WFSKrnDbgOutput2("fn=\"%s\" ", pFi->sFileName); + } + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString(nResult)); + ); +#endif + return (WFSResult)nResult; +} + + +WFSResult WFSSrvSearchDirectoryClose(WFSSrvSearchDirectoryHandle ssdh) { +#if _DEBUG_BREAK_POINT + if (nDbgCommandCount == 34840) { + int a;a=0; + } +#endif + WFSKrnResult nResult = WFSKRN_RESULT_OK; + WFSKrnSearchDirInfo *pSdi; + WFSKrnExitOnError(WFSKrnGetSearchDirInfo(&pSdi, ssdh)); + pSdi->pci.di.tba.pTransInfo = TransBegin(); + DirItrCloseNoUnpin(&pSdi->pci.di); +#if _DEBUG_PATH_CACHE + PathCacheDecreaseEntryOpenHandleCount(&pSdi->pci, pSdi->pathDebug.sStr); +#else + PathCacheDecreaseEntryOpenHandleCount(&pSdi->pci); +#endif + TransEnd(pSdi->pci.di.tba.pTransInfo); + WFSKrnSearchDirInfoFree(pSdi); +Exit: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput3("SearchDirectoryClose(sdh=%04x, pFi) WFS_RESULT_%s\n", ssdh, WFSKrnGetErrorString(nResult))); +#endif + return WFS_RESULT_OK; +} + + +WFSResult WFSSrvValidateDirectory(const WFSPathName *pAbsPathName) { +#if _DEBUG_BREAK_POINT + if (nDbgCommandCount == 15) { + int a;a=0; + } +#endif + WFSKrnResult nResult; + WFSPathName path; + WFSKrnExit2OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + PathCacheItr pci; + pci.di.tba.pTransInfo = TransBegin(); + WFSKrnExit1OnError(PathCacheFindPath(pAbsPathName, path.sStr, &pci)); + if ((pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY)==0) { + nResult = WFSKRN_RESULT_NOT_DIRECTORY; + goto Exit1; + } +#ifdef PERMISSION_ENABLED + u32 permissions; + WFSKrnExit1OnError(WFSKrnGetInheritedPermissionForUserDi(&pci, &permissions, pci.di.tba.pTransInfo->nTitleId)); + if((permissions & WFS_PERM_LIST) == 0) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } +#endif +Exit1: + DirItrClose(&pci.di); + TransEnd(pci.di.tba.pTransInfo); +Exit2: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput3("ValidateDirectory(\"%s\") WFS_RESULT_%s\n", pAbsPathName->sStr, WFSKrnGetErrorString(nResult))); +#endif + return (WFSResult)nResult; +} + + +WFSResult WFSSrvDelete(const WFSPathName *pAbsPathName) { +#if _DEBUG_BREAK_POINT + if (nDbgCommandCount == 940958) { + int a;a=0; + } +#endif + WFSKrnResult nResult; + PathCacheItr pci; + pci.di.tba.pTransInfo = TransBegin(); + WFSPathName path; + WFSKrnExit2OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + WFSKrnExit1OnError(PathCacheFindPath(pAbsPathName, path.sStr, &pci)); +#ifdef PERMISSION_ENABLED + u32 permissions; + u32 parentPermissions; + WFSKrnExit1OnError(WFSKrnGetInheritedPermissionForUserDi(&pci, &permissions, pci.di.tba.pTransInfo->nTitleId)); + if((permissions & WFS_PERM_DELETE_OR_MOVE) == 0) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } + WFSKrnExit1OnError(WFSKrnGetParentInheritedPermissionForUserPci(&pci, &parentPermissions, pci.di.tba.pTransInfo->nTitleId)); + if(pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) + { + if((parentPermissions & WFS_PERM_ADD_OR_DELETE_SUBDIR) == 0) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } + } + else + { + if((parentPermissions & WFS_PERM_ADD_OR_DELETE_FILE) == 0) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } + } +#else // PERMISSION_ENABLED + if(pci.di.tba.pAreaInfo == NULL) + { + // system path. + osTPrintf("WFSSrvDelete(): system path\n"); + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } +#endif // PERMISSION_ENABLED + + if (*pci.rxi.pStrPtr==0) { // The pEntry refers to the object (rather than the parent dir) + if (pci.pEntry->pcd.nOpenHandleCount) { + nResult = WFSKRN_RESULT_FILE_OPEN; + goto Exit1; + } + } +#ifdef PERMISSION_ENABLED + AreaInfo* area = pci.di.tba.pAreaInfo; + WFSKrnAclHandle handle = pci.di.pAttrHdr->nAccessListIdx; +#endif + if (pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) { + WFSKrnExit1OnError(DirDeleteSubDir(&pci.di)); + } else { + WFSKrnExit1OnError(DirDeleteFile(&pci.di)); + } +#ifdef PERMISSION_ENABLED + WFSKrnExit1OnError(WFSKrnReleaseAccessList(area, handle)); +#endif + if (*pci.rxi.pStrPtr==0) { // The pEntry refers to the object (rather than the parent dir) + WFSKrnExit1OnError(PathCacheDeleteSubTree(pci.pEntry)); + } + nResult = DirDeleteEntry(&pci.di); +Exit1: + DirItrClose(&pci.di); +Exit2: + TransEnd(pci.di.tba.pTransInfo); +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput3("Delete(\"%s\") WFS_RESULT_%s\n", pAbsPathName->sStr, WFSKrnGetErrorString(nResult))); +#endif + return (WFSResult)nResult; +} + + +WFSResult WFSSrvMoveLocal(const WFSPathName *pSrcAbsPathName, const WFSPathName *pDstAbsPathName) { +#if _DEBUG_BREAK_POINT + if (nDbgCommandCount == 0x75c8) { + int a;a=0; + } +#endif + WFSKrnResult nResult; + WFSPathName path; + PathCacheItr pci; + pci.di.tba.pTransInfo = TransBegin(); + + WFSKrnExit5OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pSrcAbsPathName->sStr, pSrcAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + WFSKrnExit4OnError(PathCacheFindPath(pSrcAbsPathName, path.sStr, &pci)); +#ifdef PERMISSION_ENABLED + u32 permissions; + u32 parentPermissions; + WFSKrnExit4OnError(WFSKrnGetInheritedPermissionForUserDi(&pci, &permissions, pci.di.tba.pTransInfo->nTitleId)); + if((permissions & WFS_PERM_DELETE_OR_MOVE) == 0) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit4; + } + WFSKrnExit4OnError(WFSKrnGetParentInheritedPermissionForUserPci(&pci, &parentPermissions, pci.di.tba.pTransInfo->nTitleId)); + if(!(parentPermissions & ((pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) ? WFS_PERM_ADD_OR_DELETE_SUBDIR : WFS_PERM_ADD_OR_DELETE_FILE))) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit4; + } +#else // PERMISSION_ENABLED + if(pci.di.tba.pAreaInfo == NULL) + { + // system path. + osTPrintf("WFSSrvMoveLocal(): system path\n"); + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit4; + } +#endif + if (*pci.rxi.pStrPtr==0) { // The pEntry refers to the object (rather than the parent dir) + if (pci.pEntry->pcd.nOpenHandleCount) { + nResult = WFSKRN_RESULT_FILE_OPEN; + goto Exit4; + } + } + else + { + // When the entry is directory and it has not cached yet, it is need to cache + // to calculate the sum of children's OpenHandleCount. + if (pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) + { + pci.pEntry = PathCacheIncrementalInsertAfterCursorEntry(wkg.pathCache.pMruAnchor, &pci.rxi, pci.rxi.pStrPtr - path.sStr, pci.pNameEnd - pci.rxi.pStrPtr); + if (pci.pEntry->pcd.nOpenHandleCount) { + nResult = WFSKRN_RESULT_FILE_OPEN; + goto Exit4; + } + } + // The file entry doesn't have children. No need to calculate. + } + + WFSBlkAdr nBlkAdrTmp; + void *pBlkPtrTmp; + AreaInfo *pAreaInfo = pci.di.tba.pAreaInfo; + WFSKrnExit4OnError(AreaAllocBlks(pAreaInfo, pci.di.tba.nBlkAdr, pAreaInfo->ah.nLog2BlkSize, 1, &nBlkAdrTmp, sizeof(WFSBlkAdr))); + WFSKrnExit3OnError(TransGetAndPinBlk5(pAreaInfo, nBlkAdrTmp, pci.di.tba.pTransInfo, 0, &pBlkPtrTmp)); + + memcpy(pBlkPtrTmp, pci.di.pAttrHdr, (1<nAttrLog2Size)); + DirEntryAttrHdr *pSrcAttrHdr = (DirEntryAttrHdr*)pBlkPtrTmp; + + // Todo : Fixed bug for PathCacheRecursiveDelete() in cmp2_test_case3. + if (*pci.rxi.pStrPtr==0){ + WFSKrnExit3OnError(PathCacheDeleteSubTree(pci.pEntry)); + } + WFSKrnExit3OnError(DirDeleteEntry(&pci.di)); + + DirItrClose(&pci.di); + + WFSKrnExit2OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pDstAbsPathName->sStr, pDstAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + nResult = PathCacheFindParentDir(pDstAbsPathName, path.sStr, &pci); + switch(nResult) { + case WFSKRN_RESULT_OK: + case WFSKRN_RESULT_SRV_PATH_VOL_ROOT: + break; + case WFSKRN_RESULT_SRV_PATH_DEPTH_1: + case WFSKRN_RESULT_SRV_PATH_DEV: + case WFSKRN_RESULT_SRV_PATH_VOL: + nResult = WFSKRN_RESULT_INVALID; + default: + goto Exit1; + } +#ifdef PERMISSION_ENABLED + // Check the permission of parent dir and specified entry + WFSKrnExit2OnError(WFSKrnGetInheritedPermissionForUserPci(&pci, &permissions, pci.di.tba.pTransInfo->nTitleId)); + if(!(permissions & ((pSrcAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) ? WFS_PERM_ADD_OR_DELETE_SUBDIR : WFS_PERM_ADD_OR_DELETE_FILE))) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } +#endif + if (pSrcAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY){ + // Process for moving directory . + u8 nSizeCategory; + u32 nAllocSize = 0; + u8 nAttrLog2Size = (u8)DirCalculateAttrSubBlkLog2SizeUpdateAllocSize(pAreaInfo, &nAllocSize, pci.di.name.nLen, &nSizeCategory); +#if _DEBUG + if(nSizeCategory != FILE_SIZE_CATEGORY_VERY_SMALL){ + WFSKrnExit1OnError(WFSKRN_RESULT_FATAL_ERROR); + } +#endif + WFSKrnExit1OnError(DirSbaAllocAndRegistSubBlk(&pci.di.name, &pci.di, nAttrLog2Size, &pci.di.pAttrHdr)); + memcpy((u8*)pci.di.pAttrHdr , (u8*)pSrcAttrHdr, sizeof(DirEntryAttrHdr)); + pci.di.pAttrHdr->nAttrLog2Size = nAttrLog2Size; + pci.di.pAttrHdr->nAllocSize = nAllocSize; + pci.di.pAttrHdr->nNameLen = pci.di.name.nLen; + WFSKrnStoreCaseInformationStr(pci.di.pAttrHdr->aCaseBitArray, pci.pRawNameStart, pci.di.name.nLen); + } else { + // Process for moving file. + // + // When the max sub block size of FILE_SIZE_CATEGORY_VERY_SMALL can not be record as new file name, + // the src file resize by DirResizeFile and size category change to FILE_SIZE_CATEGORY_SMALL. + if (pSrcAttrHdr->nSizeCategory == FILE_SIZE_CATEGORY_VERY_SMALL && pSrcAttrHdr->nAttrLog2Size == SBA_MAX_LOG2_SUB_BLK_SIZE) { + u32 nNewAllocSize = (1<aCaseBitArray) + ((pci.di.name.nLen+7)>>3)); + if (nNewAllocSize < pSrcAttrHdr->file.nSize){ + DirEntryAttrHdr *pNewSrcAttrHdr = (DirEntryAttrHdr*)((size_t)pBlkPtrTmp + (1<aCaseBitArray) + ((pSrcAttrHdr->nNameLen+7)>>3))); + pNewSrcAttrHdr->nAllocSize = pAreaInfo->nBlkSize; + pNewSrcAttrHdr->nAttrLog2Size = (u8)DirCalculateAttrSubBlkLog2Size(pAreaInfo, pNewSrcAttrHdr->nAllocSize, pNewSrcAttrHdr->nNameLen, &pNewSrcAttrHdr->nSizeCategory); + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pNewSrcAttrHdr, pNewSrcAttrHdr->nAttrLog2Size, 0); + memset((void*)pFileBlkPtr, 0, sizeof(WFSFileBlkPtr)); + WFSKrnExit1OnError(AreaAllocBlks(pAreaInfo, pci.di.tba.nBlkAdr, pAreaInfo->ah.nLog2BlkSize, 1, (WFSBlkAdr*)pFileBlkPtr, -(s32)sizeof(WFSFileBlkPtr))); + void *pBlkPtr; + u32 nValidSize = WFS_ROUND_UP(pSrcAttrHdr->file.nSize, pAreaInfo->pVolInfo->pDevInfo->dh.nLog2SectorSize); + u16 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pBlkPtrTmp; + nResult = TransGetAndPinFileBlk(&pci.di.tba, nBlkAdrTmp, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_WRITE_BLK, nValidSize, &pBlkPtr); + if(nResult < WFSKRN_RESULT_OK){ + TransUnpinBlk3(pAreaInfo, pFileBlkPtr->nBlkAdr, pci.di.tba.pTransInfo); + AreaFreeBlks(pAreaInfo, pAreaInfo->ah.nLog2BlkSize, 1, (WFSBlkAdr*)pFileBlkPtr, -(s32)sizeof(WFSFileBlkPtr)); + goto Exit1; + } + memcpy(pBlkPtr, &pSrcAttrHdr->aCaseBitArray[(pSrcAttrHdr->nNameLen+7)>>3], pSrcAttrHdr->file.nSize); + WFSKrnExit1OnError(TransStoreBlk3(pAreaInfo, pFileBlkPtr->nBlkAdr, pci.di.tba.pTransInfo)); + WFSKrnExit1OnError(TransUnpinBlk3(pAreaInfo, pFileBlkPtr->nBlkAdr, pci.di.tba.pTransInfo)); + pSrcAttrHdr = pNewSrcAttrHdr; + } else if (nNewAllocSize < pSrcAttrHdr->nAllocSize){ + pSrcAttrHdr->nAllocSize = nNewAllocSize; + } + } + u8 nSizeCategory; + u8 nAttrLog2Size = (u8)DirCalculateAttrSubBlkLog2Size(pAreaInfo, pSrcAttrHdr->nAllocSize, pci.di.name.nLen, &nSizeCategory); + if(nSizeCategory != pSrcAttrHdr->nSizeCategory){ + nAttrLog2Size = (u8)DirCalculateAttrSubBlkLog2SizeDecrease(pAreaInfo, pSrcAttrHdr->nAllocSize, pci.di.name.nLen, &nSizeCategory); +#if _DEBUG + if(nSizeCategory != pSrcAttrHdr->nSizeCategory){ + WFSKrnExit1OnError(WFSKRN_RESULT_FATAL_ERROR); + } +#endif + } + // Alloc the new sub block and copy from src attributes to the new sub block. + WFSKrnExit1OnError(DirSbaAllocAndRegistSubBlk(&pci.di.name, &pci.di, nAttrLog2Size, &pci.di.pAttrHdr)); + memcpy((u8*)pci.di.pAttrHdr , (u8*)pSrcAttrHdr, sizeof(DirEntryAttrHdr)); + switch(nSizeCategory) + { + case FILE_SIZE_CATEGORY_VERY_SMALL:{ + u32 nCopySize = pSrcAttrHdr->file.nSize; + memcpy(&pci.di.pAttrHdr->aCaseBitArray[(pci.di.name.nLen+7)>>3], &pSrcAttrHdr->aCaseBitArray[(pSrcAttrHdr->nNameLen+7)>>3], nCopySize); + break; + } + case FILE_SIZE_CATEGORY_SMALL:{ + u32 nCopySize = (pSrcAttrHdr->nAllocSize>>pAreaInfo->ah.nLog2BlkSize)*sizeof(WFSFileBlkPtr); + memcpy((u8*)pci.di.pAttrHdr+(1<nAttrLog2Size)-nCopySize, nCopySize); + break; + } + case FILE_SIZE_CATEGORY_MEDIUM:{ + u32 nCopySize = (pSrcAttrHdr->nAllocSize>>pAreaInfo->ah.nLog2MediumBlkSize)*sizeof(WFSFileBlkPtr); + memcpy((u8*)pci.di.pAttrHdr+(1<nAttrLog2Size)-nCopySize, nCopySize); + break; + } + case FILE_SIZE_CATEGORY_LARGE:{ + u32 nCopySize = (pSrcAttrHdr->nAllocSize>>pAreaInfo->ah.nLog2LargeBlkSize)*sizeof(WFSFileLargeBlkPtr); + memcpy((u8*)pci.di.pAttrHdr+(1<nAttrLog2Size)-nCopySize, nCopySize); + break; + } + case FILE_SIZE_CATEGORY_VERY_LARGE:{ + u32 nCopySize = (((pSrcAttrHdr->nAllocSize>>pAreaInfo->ah.nLog2LargeBlkSize)-1)/pAreaInfo->nNumLargeBlkPtrsPerBlk+1)*sizeof(WFSBlkAdr); + memcpy((u8*)pci.di.pAttrHdr+(1<nAttrLog2Size)-nCopySize, nCopySize); + break; + } + } + pci.di.pAttrHdr->nAttrLog2Size = nAttrLog2Size; + pci.di.pAttrHdr->nNameLen = pci.di.name.nLen; + WFSKrnStoreCaseInformationStr(pci.di.pAttrHdr->aCaseBitArray, pci.pRawNameStart, pci.di.name.nLen); + WFSKrnExit3OnError(DirReGetHashAdr(pci.di.tba.pAreaInfo, pci.di.pAttrHdr, pci.di.tba.nBlkAdr, pci.di.pBlkHdr)); + } + goto Exit3; + +Exit1:; + DirItrClose(&pci.di); +Exit2:; + WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pSrcAbsPathName->sStr, pSrcAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE); + switch(PathCacheFindParentDir(pSrcAbsPathName, path.sStr, &pci)) { + case WFSKRN_RESULT_OK: + case WFSKRN_RESULT_SRV_PATH_VOL_ROOT: + break; + default: + goto Exit3; + } + DirSbaAllocAndRegistSubBlk(&pci.di.name, &pci.di, pSrcAttrHdr->nAttrLog2Size, &pci.di.pAttrHdr); + memcpy(pci.di.pAttrHdr, pSrcAttrHdr, (1<nAttrLog2Size)); +Exit3:; + TransUnpinBlk3(pAreaInfo, nBlkAdrTmp, pci.di.tba.pTransInfo); + AreaFreeBlks(pAreaInfo, pAreaInfo->ah.nLog2BlkSize, 1, &nBlkAdrTmp, sizeof(WFSBlkAdr)); +Exit4:; + DirItrClose(&pci.di); +Exit5:; + TransEnd(pci.di.tba.pTransInfo); +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput4("MoveLocal(\"%s\", \"%s\") WFS_RESULT_%s\n", pSrcAbsPathName->sStr, pDstAbsPathName->sStr, WFSKrnGetErrorString(nResult))); +#endif + return (WFSResult)nResult; +} + + +WFSResult WFSSrvCreateAndOpenFile(const WFSPathName *pAbsPathName, u32 nFlags, WFSContentIdx nCidx, WFSFileSize nPreAllocateSize, WFSSrvFileHandle *pSfh) { +#if _DEBUG_BREAK_POINT + if (nDbgCommandCount == 15529) { + int a;a=0; + } +#endif + WFSKrnResult nResult; + WFSPathName path; + if (nFlags & ~(WFS_PERM_FULL)) + { + nResult = WFSKRN_RESULT_INVALID; + goto Exit3; + } + WFSKrnExit3OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + WFSKrnFileInfo *pKfi; + WFSKrnExit3OnError(WFSKrnFileInfoAlloc(&pKfi)); + pKfi->pci.di.tba.pTransInfo = TransBegin(); + nResult = PathCacheFindParentDir(pAbsPathName, path.sStr, &pKfi->pci); + switch(nResult) { + case WFSKRN_RESULT_OK: + case WFSKRN_RESULT_SRV_PATH_VOL_ROOT: + break; + case WFSKRN_RESULT_SRV_PATH_DEPTH_1: + case WFSKRN_RESULT_SRV_PATH_DEV: + case WFSKRN_RESULT_SRV_PATH_VOL: + nResult = PathCacheFindPath(pAbsPathName, path.sStr, &pKfi->pci); + switch(nResult) + { + case WFSKRN_RESULT_NOT_FOUND: + break; + case WFSKRN_RESULT_OK: + nResult = WFSKRN_RESULT_ALREADY_EXISTS; + default: + goto Exit2; + } + break; + default: + goto Exit2; + } +#ifdef PERMISSION_ENABLED + // Check the permission of parent dir and specified entry + u32 permissions; + WFSKrnExit2OnError(WFSKrnGetInheritedPermissionForUserPci(&pKfi->pci, &permissions, pKfi->pci.di.tba.pTransInfo->nTitleId)); + if(!(permissions & WFS_PERM_ADD_OR_DELETE_FILE)) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit2; + } +#endif + WFSKrnExit1OnError(DirInsertRaw(&pKfi->pci.di.name, &pKfi->pci.di, nPreAllocateSize)); + nResult = PathCacheIncrementalInsertPinnedEntry(&pKfi->pci, pAbsPathName->nLen); + if (nResult == WFSKRN_RESULT_OK) + { +#if _DEBUG + memcpy(pKfi->pathDebug.sStr, path.sStr, pAbsPathName->nLen); pKfi->pathDebug.sStr[pAbsPathName->nLen]=0; +#endif +#if _DEBUG_PATH_CACHE + nResult = PathCacheIncreaseEntryOpenHandleCount(&pKfi->pci, WFS_ACCESS_RW, path.sStr); +#else + nResult = PathCacheIncreaseEntryOpenHandleCount(&pKfi->pci, WFS_ACCESS_RW); +#endif + WFSKrnStoreCaseInformationStr(pKfi->pci.di.pAttrHdr->aCaseBitArray, pKfi->pci.pRawNameStart, pKfi->pci.di.name.nLen); + // Mark the file as open-for-writing +#ifdef PERMISSION_ENABLED + // Get the correct Access List Idx + pKfi->pci.di.pAttrHdr->nAccessListIdx = 0; // the default is also the empty accesslist. + pKfi->pci.di.pAttrHdr->nObjCreator = pKfi->pci.di.tba.pTransInfo->nTitleId; + WFSKrnExit1OnError(WFSKrnSetInheritedPermissionForUser(&pKfi->pci, nFlags, WFS_PERM_FULL, pKfi->pci.di.tba.pTransInfo->nTitleId, pKfi->pci.di.tba.pTransInfo->nTitleId)); +#else + // ToDo: Add the calls to get the correct Access List Idx + pKfi->pci.di.pAttrHdr->nAccessListIdx = 1;// | WFSKRN_FILE_OPEN_FOR_WRITE_FLAG; +#endif + pKfi->pci.di.pAttrHdr->file.nSize = 0; + pKfi->pci.di.pAttrHdr->file.nContentIdx = nCidx; + pKfi->pci.di.pAttrHdr->file.nVersion = 0; + pKfi->pci.di.pAttrHdr->timeCreated = ++wkg.time; + pKfi->pci.di.pAttrHdr->timeUpdated = wkg.time; + pKfi->attr = *pKfi->pci.di.pAttrHdr; + pKfi->nAccess = WFS_ACCESS_RW | WFS_ACCESS_CHANGE_SIZE; // Allowed read, write and change size access. + *pSfh = pKfi->nHandle; + + nResult = DirItrMapBlks(&pKfi->pci.di); + if (nResult == WFSKRN_RESULT_OK) + { + TransUnpinBlk(&pKfi->pci.di.tba); + TransEnd(pKfi->pci.di.tba.pTransInfo); + goto Exit3; + } + + // ToDo: Need to decrease entry open handle when failed to set permission for user. +#if _DEBUG_PATH_CACHE + PathCacheDecreaseEntryOpenHandleCount(&pKfi->pci, pKfi->pathDebug.sStr); +#else + PathCacheDecreaseEntryOpenHandleCount(&pKfi->pci); +#endif + } + +Exit1: + DirItrClose(&pKfi->pci.di); +Exit2: + TransEnd(pKfi->pci.di.tba.pTransInfo); + WFSKrnFileInfoFree(pKfi); +Exit3: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput5("CreateAndOpenFile(\"%s\", f=%x, c=%x, s=%u, ) ", pAbsPathName->sStr, nFlags, nCidx, nPreAllocateSize); + if (nResult == WFSKRN_RESULT_OK) { + WFSKrnDbgOutput2("fh=%04x ", *pSfh); + } + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString(nResult)); + ); +#endif + if(nResult < WFSKRN_RESULT_OK){ + int a; a=0; + } + return (WFSResult)nResult; +} + + +WFSResult WFSSrvOpenFile(const WFSPathName *pAbsPathName, WFSAccess nDesiredAccess, WFSSrvFileHandle *pSfh, WFSFileAttributes *pFa) { +#if _DEBUG_BREAK_POINT + if (nDbgCommandCount==2047) { + int a;a=0; + } +#endif + WFSKrnResult nResult = WFSKRN_RESULT_OK; + WFSPathName path; + if ((nDesiredAccessWFS_ACCESS_RW)) { + nResult = WFSKRN_RESULT_INVALID; + goto Exit2; + } + WFSKrnExit2OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + WFSKrnFileInfo *pKfi; + WFSKrnExit2OnError(WFSKrnFileInfoAlloc(&pKfi)); + pKfi->pci.di.tba.pTransInfo = TransBegin(); + WFSKrnExit1OnError(PathCacheFindPath(pAbsPathName, path.sStr, &pKfi->pci)); + if (pKfi->pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) { + nResult = WFSKRN_RESULT_NOT_FILE; + goto Exit1; + } +#ifdef PERMISSION_ENABLED + // Check permission + u32 flags; + switch(nDesiredAccess) + { + case WFS_ACCESS_READ: + flags = WFS_PERM_READ; + break; + case WFS_ACCESS_WRITE: + flags = WFS_PERM_WRITE; + break; + case WFS_ACCESS_RW: + flags = WFS_PERM_READ | WFS_PERM_WRITE; + break; + default: + nResult = WFSKRN_RESULT_INVALID; + goto Exit1; + } + u32 permissions; + WFSKrnExit1OnError(WFSKrnGetInheritedPermissionForUserDi(&pKfi->pci, &permissions, pKfi->pci.di.tba.pTransInfo->nTitleId)); + if(((permissions & WFS_PERM_FILE_FULL) | flags) != (permissions & WFS_PERM_FILE_FULL)) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } +#else // PERMISSION_ENABLED + if (pKfi->pci.di.tba.pAreaInfo == NULL) + { + // system path. + osTPrintf("WFSSrvOpenFile(): system path\n"); + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } +#endif // PERMISSION_ENABLED + nResult = PathCacheIncrementalInsertPinnedEntry(&pKfi->pci, pAbsPathName->nLen); + if (nResult != WFSKRN_RESULT_OK) + { + goto Exit1; + } + +#if _DEBUG + memcpy(pKfi->pathDebug.sStr, path.sStr, pAbsPathName->nLen); pKfi->pathDebug.sStr[pAbsPathName->nLen]=0; +#endif +#if _DEBUG_PATH_CACHE + WFSKrnExit1OnError(PathCacheIncreaseEntryOpenHandleCount(&pKfi->pci, nDesiredAccess, path.sStr)); +#else + WFSKrnExit1OnError(PathCacheIncreaseEntryOpenHandleCount(&pKfi->pci, nDesiredAccess)); +#endif + DirEntryAttrHdr *pAttrHdr = pKfi->pci.di.pAttrHdr; + pFa->nCidx = pAttrHdr->file.nContentIdx; +#ifdef PERMISSION_ENABLED + pFa->nFlags = permissions & WFS_PERM_FILE_FULL; +#else + pFa->nFlags = pAttrHdr->nAccessListIdx; // ToDo: Get permission bits for current user +#endif + if (pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) { + pFa->nNumEntries = 0; // ToDo: Remove NumEntries parameter from WFS API + } else { + pFa->nFileSize = pAttrHdr->file.nSize; + } + pFa->timeCreated = pAttrHdr->timeCreated; + pFa->timeCreated = pAttrHdr->timeUpdated; + // Update attributes in pKfi->attr. + pKfi->attr = *pKfi->pci.di.pAttrHdr; + *pSfh = pKfi->nHandle; +#ifdef PERMISSION_ENABLED + pKfi->nAccess = nDesiredAccess | ((permissions & WFS_PERM_CHANGE_SIZE) ? WFS_ACCESS_CHANGE_SIZE : 0); +#else + pKfi->nAccess = nDesiredAccess; +#endif + //pKfi->fpos.nPos = 0; + nResult = DirItrMapBlks(&pKfi->pci.di); + if (nResult == WFSKRN_RESULT_OK) + { + TransUnpinBlk(&pKfi->pci.di.tba); + TransEnd(pKfi->pci.di.tba.pTransInfo); + goto Exit2; + } + + // decrease entry open handle when failed to set permission for user. +#if _DEBUG_PATH_CACHE + PathCacheDecreaseEntryOpenHandleCount(&pKfi->pci, pKfi->pathDebug.sStr); +#else + PathCacheDecreaseEntryOpenHandleCount(&pKfi->pci); +#endif + +Exit1:; + DirItrClose(&pKfi->pci.di); + TransEnd(pKfi->pci.di.tba.pTransInfo); + WFSKrnFileInfoFree(pKfi); +Exit2:; +#if _DEBUG + #if ((DBG_OUTPUT_TO_LOG_FILE && _WIN32) || DBG_OUTPUT_TO_SCREEN) + char *aDA[4]={"?","R","W","RW"}; + if(nDesiredAccess>3) + nDesiredAccess = (WFSAccess)0; + #endif + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput3("OpenFile(\"%s\", %s, pSfh, pFa) ", pAbsPathName->sStr, aDA[nDesiredAccess]); + if (nResult == WFSKRN_RESULT_OK) { + WFSKrnDbgOutput2("fh=%04x ", *pSfh); + } + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString(nResult)); + ); +#endif + return (WFSResult)nResult; +} + + +static inline WFSKrnResult DirItrUpdateAndPinBlk(DirItr* di, WFSBlkAdr nRootBlkAdr, int transFlag) +{ + WFSKrnResult result = DirItrCheckMapBlks(di); + if (result == WFSKRN_RESULT_OK) + { + result = DirItrPinBlkAndFixPtrs(di, transFlag); + return result; + } + + DirItrUnmapBlks(di); + DirItrCloseNoUnpin(di); + di->nBlkDepth = 0; + di->tba.nBlkAdr = nRootBlkAdr; + + result = DirFind(&di->name, di, DIR_MAX_BLK_DEPTH, DIR_FIND_MODE_NORMAL); + if (result == WFSKRN_RESULT_DIR_ENTRY_FOUND) + { + if (transFlag == TRANS_FLAG_RW_BLK) + { + result = DirGetBlk(di, TRANS_FLAG_RW_BLK, 0); + if (result != WFSKRN_RESULT_OK) + { + return result; + } + } + result = DirItrMapBlks(di); + } + else + { + WFSKrnOutputErrorCode(result); + ASSERT(result == WFSKRN_RESULT_DIR_ENTRY_FOUND); + } + return result; +} + + +WFSResult WFSSrvCloseFile(WFSSrvFileHandle sfh, WFSFileSize nNewSize) { +#if _DEBUG_BREAK_POINT + if (nDbgCommandCount==15531) { + int a;a=0; + } +#endif + WFSKrnFileInfo *pKfi; + WFSKrnResult nResult; + WFSKrnExit2OnError(WFSKrnGetFileInfo(&pKfi, sfh)); + pKfi->pci.di.tba.pTransInfo = TransBegin(); + + nResult = DirItrUpdateAndPinBlk(&pKfi->pci.di, pKfi->pci.nRootBlkAdr, TRANS_FLAG_READ_BLK); + if (nResult != WFSKRN_RESULT_OK) + { + goto Exit1; + } + if (nResult == WFSKRN_RESULT_OK) + { + DirEntryAttrHdr *pAttrHdr = pKfi->pci.di.pAttrHdr; + if (nNewSize != pAttrHdr->file.nSize) { + if ((pKfi->nAccess & WFS_ACCESS_WRITE) == 0) { + nResult = WFSKRN_RESULT_ACCESS; + goto Exit1; + } +#ifdef PERMISSION_ENABLED + if ((pKfi->nAccess & WFS_ACCESS_CHANGE_SIZE) == 0) { + TransEnd(pKfi->pci.di.tba.pTransInfo); + TransUnpinBlk(&pKfi->pci.di.tba); + return WFS_RESULT_NO_CHANGE_SIZE; + } +#endif + WFSKrnExit1OnError( DirGetBlk(&pKfi->pci.di, TRANS_FLAG_RW_BLK, 0) ); + DirResizeFile(&pKfi->pci.di, nNewSize); + } + DirItrUnmapBlks(&pKfi->pci.di); + DirItrClose(&pKfi->pci.di); + } + + if (nResult != WFSKRN_RESULT_MEDIA_ERROR) // [check] workaround. + // PathCacheDecreaseEntryOpenHandleCount() throws exception when the device is unmounted. + { +#if _DEBUG_PATH_CACHE + PathCacheDecreaseEntryOpenHandleCount(&pKfi->pci, pKfi->pathDebug.sStr); +#else + PathCacheDecreaseEntryOpenHandleCount(&pKfi->pci); +#endif + } + TransEnd(pKfi->pci.di.tba.pTransInfo); + WFSKrnFileInfoFree(pKfi); + goto Exit2; +Exit1: + TransEnd(pKfi->pci.di.tba.pTransInfo); +Exit2: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput4("CloseFile(fh=%04x, ns=%u) WFS_RESULT_%s\n", sfh, nNewSize, WFSKrnGetErrorString(nResult))); +#endif + return (WFSResult)nResult; + +} + + +WFSResult WFSSrvGetFileSize(WFSSrvFileHandle sfh, WFSFileSize *pSize) { + WFSKrnFileInfo *pKfi; + WFSKrnResult nResult; + WFSKrnExitOnError(WFSKrnGetFileInfo(&pKfi, sfh)); + pKfi->pci.di.tba.pTransInfo = TransBegin(); + *pSize = pKfi->attr.file.nSize; + TransEnd(pKfi->pci.di.tba.pTransInfo); +Exit: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput4("GetFileSize(fh=%04x, s=%u) WFS_RESULT_%s\n", sfh, *pSize, WFSKrnGetErrorString(nResult))); +#endif + return (WFSResult)nResult; +} + + +//static u8 aTempBuffer[WFS_STATIC_MEM_ALIGNMENT]; //__attribute__((aligned(32))); + +void RotateBuffer(u8 *pBuffer, u32 nSize, s32 nRotationOffset, bool check) { +#if _DEBUG + if ((nRotationOffset > WFS_STATIC_MEM_ALIGNMENT) || (nRotationOffset < -WFS_STATIC_MEM_ALIGNMENT)) { + WFSKrnOutputErrorStr("Rotation Invalid"); + } +#endif + u8 aTempBuffer[WFS_STATIC_MEM_ALIGNMENT]; + if (nRotationOffset > 0) { + memcpy(aTempBuffer, pBuffer, nRotationOffset); + memmove(pBuffer, pBuffer+nRotationOffset, nSize-nRotationOffset); + memcpy(pBuffer+nSize-nRotationOffset, aTempBuffer, nRotationOffset); + } else { + nRotationOffset = -nRotationOffset; + memcpy(aTempBuffer, pBuffer+nSize-nRotationOffset, nRotationOffset); + memmove(pBuffer+nRotationOffset, pBuffer, nSize-nRotationOffset); + memcpy(pBuffer, aTempBuffer, nRotationOffset); + //nRotationOffset = -nRotationOffset; + } + /* + if(check){ + int i; + for(i=1;inAttrLog2Size, nBlkIdx); + return TransReadFileBlks(pBuffer, pAreaInfo, nSize, pFileBlkPtr, -(signed)sizeof(*pFileBlkPtr), pTransInfo); +} + +static inline WFSKrnResult WfsSrvTransReadFileBlksForCategoryMedium(AreaInfo *pAreaInfo, void *pMetaData, u8 *pBuffer, u32 nBlkIdx, u32 nSize, TransInfo *pTransInfo){ + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium((DirEntryAttrHdr*)pMetaData, ((DirEntryAttrHdr*)pMetaData)->nAttrLog2Size, nBlkIdx); + return TransReadFileMediumBlks(pBuffer, pAreaInfo, nSize, pFileBlkPtr, -(signed)sizeof(*pFileBlkPtr), pTransInfo); +} + +static inline WFSKrnResult WfsSrvTransReadFileBlksForCategoryLarge(AreaInfo *pAreaInfo, void *pMetaData, u8 *pBuffer, u32 nBlkIdx, u32 nSize, TransInfo *pTransInfo){ + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrForCategoryLarge((DirEntryAttrHdr*)pMetaData, ((DirEntryAttrHdr*)pMetaData)->nAttrLog2Size, + nBlkIdx>>pAreaInfo->nLog2MediumBlkPerLargeBlk); + return TransReadFileLargeBlks(pBuffer, pAreaInfo, nSize, nBlkIdx%(1<nLog2MediumBlkPerLargeBlk), + pFileLargeBlkPtr, -(signed)sizeof(*pFileLargeBlkPtr), pTransInfo); +} + +static inline WFSKrnResult WfsSrvTransReadFileBlksForCategoryVeryLarge(AreaInfo *pAreaInfo, void *pMetaData, u8 *pBuffer, u32 nBlkIdx, u32 nSize, TransInfo *pTransInfo){ + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrFromIndirectBlkForCategoryVeryLarge((u8*)pMetaData, nBlkIdx>>pAreaInfo->nLog2MediumBlkPerLargeBlk); + return TransReadFileLargeBlks(pBuffer, pAreaInfo, nSize, nBlkIdx%(1<nLog2MediumBlkPerLargeBlk), + pFileLargeBlkPtr, (s32)sizeof(*pFileLargeBlkPtr), pTransInfo); +} + +s32 WFSSrvReadFile(WFSSrvFileHandle sfh, void *pBuffer, WFSFileSize nPos, s32 nSize) { +#if _DEBUG_BREAK_POINT + if (nDbgCommandCount == 0x12e) { + int a;a=0; + } + #if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } + #endif +#endif +#if _DEBUG + #if ((DBG_OUTPUT_TO_LOG_FILE && _WIN32) || DBG_OUTPUT_TO_SCREEN) + WFSFileSize nInPos = nPos; + s32 nInSize = nSize; + #endif +#endif + //if((size_t)pBuffer%WFSKRN_FILE_BUFFER_MEM_ALIGNMENT_SIZE){ + // return WFS_RESULT_INVALID; + //} + WFSKrnResult nResult = WFSKRN_RESULT_OK; + s32 nReadSize=0; + WFSKrnFileInfo *pKfi; + WFSKrnExit3OnError(WFSKrnGetFileInfo(&pKfi, sfh)); + TransInfo *pTransInfo = pKfi->pci.di.tba.pTransInfo = TransBegin(); + if ((pKfi->nAccess & WFS_ACCESS_READ) == 0) { + nResult = (WFSKrnResult)WFS_RESULT_ACCESS; + goto Exit2; + } + nResult = DirItrUpdateAndPinBlk(&pKfi->pci.di, pKfi->pci.nRootBlkAdr, TRANS_FLAG_READ_BLK); + if (nResult != WFSKRN_RESULT_OK) + { + goto Exit1; + } + + //if(!memcmp(pKfi->pci.di.name.sStr,"araucarian",pKfi->pci.di.name.nLen)){ + // int a; a=0; + //} + + DirEntryAttrHdr *pAttrHdr = pKfi->pci.di.pAttrHdr; + if (nPos > pAttrHdr->file.nSize){ + nResult = WFSKRN_RESULT_INVALID; + goto Exit1; + } + u64 nNewPos = (u64)nPos + (u64)nSize; + if (nNewPos > pAttrHdr->file.nSize){ + nNewPos = pAttrHdr->file.nSize; + nSize = pAttrHdr->file.nSize - nPos; + } + nReadSize = nSize; + + // Cases: + // 1. Read a small block to a 512 Byte aligned memory address - direct read possible + // 2. Read a large block, or a set of 64KB pieces from a large block to a 512 Byte aligned memory address - direct read possible + // 3. Read a portion of a small block to a memory address (whether aligned or not) - must read to block cache first and copy + // 4. Read a portion of a 64KB piece to a memory address (whether aligned or not) - read to an internal 64KB buffer first + // Note: If a block is already in cache, use it regardless of the transfer size. + // ToDo: It may be necessasry to make the block cache support allocating either 8KB or 64KB chunks, which would imply it + // needs to implement garbage collection as well. + + // ToDo: The root directory of the sub-area should store its hash code in its parent directory + // ToDo: Hash-code initialization vector should be based on relative block address within the area XOR some intrinsic property of area like its size. + AreaInfo *pAreaInfo = pKfi->pci.di.tba.pAreaInfo; + TransBlkAdr *pTba = &pKfi->pci.di.tba; + if(!nSize){ + nResult = WFSKRN_RESULT_OK; + goto Exit1; + } + + u32 nLog2UnitBlkSize = 0; + WFSBlkAdr *pParentBlkAdr = 0; + WFSFileBlkInfo (*pFuncWFSKrnGetFileBlkInfo)(AreaInfo *pAreaInfo, void *pMetaData, u32 nLog2MetaSize, u32 nBlkIdx) = 0; + WFSKrnResult (*pFuncWfsSrvTransGetAndPinFileBlk)(TransBlkAdr *pTba, WFSBlkAdr nParentBlkAdr, u16 nHashOfs, WFSBlkAdr nFileBlkAdr, u32 nFlags, u32 nValidSize, void **ppBlkPtr) = 0; + WFSKrnResult (*pFuncWfsSrvTransReadFileBlks)(AreaInfo *pAreaInfo, void *pMetaData, u8 *pBuffer, u32 nBlkIdx, u32 nNumBlks, TransInfo *pTransInfo) = 0; + // for VERY_LARGE + u32 nNumIndirectBlks = 0; + s32 nIndirectIdx = 0; + u8* pIndirectBlkPtr[WFSKRN_VERY_LARGE_MAP_NUM_INDIRECT_BLKS]; + + switch(pAttrHdr->nSizeCategory) { + case FILE_SIZE_CATEGORY_VERY_SMALL: { + u8 *pFileDataPtr = &pAttrHdr->aCaseBitArray[(pAttrHdr->nNameLen+7)>>3] + nPos; + memcpy(pBuffer, pFileDataPtr, nSize); + nSize = 0; + break; + } + case FILE_SIZE_CATEGORY_SMALL: { + nLog2UnitBlkSize = pAreaInfo->ah.nLog2BlkSize; + pFuncWFSKrnGetFileBlkInfo = WFSKrnGetFileBlkInfoForCategorySmallCast; + pFuncWfsSrvTransGetAndPinFileBlk = TransGetAndPinFileBlk; + pFuncWfsSrvTransReadFileBlks = WfsSrvTransReadFileBlksForCategorySmall; + pParentBlkAdr = &pTba->nBlkAdr; + break; + } + case FILE_SIZE_CATEGORY_MEDIUM: { + nLog2UnitBlkSize = pAreaInfo->ah.nLog2MediumBlkSize; + pFuncWFSKrnGetFileBlkInfo = WFSKrnGetFileBlkInfoForCategoryMediumCast; + pFuncWfsSrvTransGetAndPinFileBlk = TransGetAndPinFileMediumBlk; + pFuncWfsSrvTransReadFileBlks = WfsSrvTransReadFileBlksForCategoryMedium; + pParentBlkAdr = &pTba->nBlkAdr; + break; + } + case FILE_SIZE_CATEGORY_LARGE: { + nLog2UnitBlkSize = pAreaInfo->ah.nLog2MediumBlkSize; + pFuncWFSKrnGetFileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLargeCast; + pFuncWfsSrvTransGetAndPinFileBlk = TransGetAndPinFileMediumBlk; + pFuncWfsSrvTransReadFileBlks = WfsSrvTransReadFileBlksForCategoryLarge; + pParentBlkAdr = &pTba->nBlkAdr; + break; + } + case FILE_SIZE_CATEGORY_VERY_LARGE: { + nLog2UnitBlkSize = pAreaInfo->ah.nLog2MediumBlkSize; + pFuncWFSKrnGetFileBlkInfo = WFSKrnGetFileBlkInfoFromIndirectBlkForCategoryVeryLargeCast; + pFuncWfsSrvTransGetAndPinFileBlk = TransGetAndPinFileMediumBlk; + pFuncWfsSrvTransReadFileBlks = WfsSrvTransReadFileBlksForCategoryVeryLarge; + pParentBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndLargeBlkIdxForCategoryVeryLarge(pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, nPos>>pAreaInfo->ah.nLog2LargeBlkSize); + nNumIndirectBlks = (nSize+nPos%(pAreaInfo->nNumLargeBlkPtrsPerBlk<ah.nLog2LargeBlkSize)-1)/(pAreaInfo->nNumLargeBlkPtrsPerBlk<ah.nLog2LargeBlkSize)+1; + break; + } + } + + while(nSize > 0){ + void *pMetaData; + void *pParentBlkPtr; + u32 nLog2MetaSize; + u32 nAccessSize, nAccessPos; + + if(pAttrHdr->nSizeCategory == FILE_SIZE_CATEGORY_VERY_LARGE){ + if(!(nIndirectIdx&(WFSKRN_VERY_LARGE_MAP_NUM_INDIRECT_BLKS-1))){ + for(nIndirectIdx=0;nIndirectIdxah.nLog2BlkSize; + pParentBlkPtr = pMetaData; + nAccessPos = nPos%(pAreaInfo->nNumLargeBlkPtrsPerBlk<ah.nLog2LargeBlkSize); + nAccessSize = (pAreaInfo->nNumLargeBlkPtrsPerBlk<ah.nLog2LargeBlkSize) - nAccessPos; + if(nAccessSize > nSize) { + nAccessSize = nSize; + nSize = 0; + } else { + nSize -= nAccessSize; + } + } else { + pMetaData = (void*)pAttrHdr; + nLog2MetaSize = pAttrHdr->nAttrLog2Size; + pParentBlkPtr = pKfi->pci.di.pBlkHdr; + nAccessSize = nSize; + nAccessPos = nPos; + nSize = 0; + } + + u8 *pBlkPtr; + u32 nBlkMask = (1<> nLog2UnitBlkSize; + u32 nStartOfs = nAccessPos & nBlkMask; + u32 nStartBlkFraction = (-(signed)nAccessPos) & nBlkMask; + s32 nEndBlkIdx = (nAccessPos + nAccessSize - 1) >> nLog2UnitBlkSize; + u32 nEndOfs = (nAccessPos + nAccessSize) & nBlkMask; + u32 nEndBlkFraction = 0; + s32 nMaxBlkIdx = pAttrHdr->file.nSize ? ((pAttrHdr->file.nSize - 1) >> nLog2UnitBlkSize) : 0; + s32 nBufferRotationOfs = ((u32)pBuffer + nStartBlkFraction) & (WFS_STATIC_MEM_ALIGNMENT-1); + if (nBufferRotationOfs > nStartBlkFraction) { + nBufferRotationOfs = nBufferRotationOfs - WFS_STATIC_MEM_ALIGNMENT; + } + // If nStartOfs is not 0, nStartBlk is accessed path through block cache. + if(nStartOfs){ + WFSFileBlkInfo fileBlkInfo = pFuncWFSKrnGetFileBlkInfo(pAreaInfo, pMetaData, nLog2MetaSize, nStartBlkIdx); + u16 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pParentBlkPtr; + if( !pAttrHdr->file.nSize || (nStartBlkIdx == nMaxBlkIdx && pAttrHdr->file.nSize&((1<file.nSize&((1<pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + ++nStartBlkIdx; + } + u32 nDirectReadSize = 0; + u32 nEnableByteRotation = 0; + // If nEndOfs is not 0, nEndBlk is accessed path through block cache. (just ready parameters) + if ((nStartBlkIdx <= nEndBlkIdx) && nEndOfs){ + if(!(nEndOfs&((1<pAreaInfo->pVolInfo->pDevInfo->dh.nLog2SectorSize)-1)) && (nBufferRotationOfs >= 0) && (nPos+nAccessSize == pAttrHdr->file.nSize) ){ + nDirectReadSize += nEndOfs; + --nEndBlkIdx; + } else { + nEndBlkFraction += nEndOfs; + nEnableByteRotation += nEndOfs; + --nEndBlkIdx; + } + } + // If nEndOfs and nStartBlkFraction is smaller than nBufferRotationOfs, the extra block is read. (just ready parameters) + while ((nStartBlkIdx <= nEndBlkIdx) && (nBufferRotationOfs < 0) && (nEnableByteRotation < -nBufferRotationOfs)){ + nEnableByteRotation += 1<nBlkAdr, &pFileBlkPtr->hash); + if (nBufferRotationOfs) { + RotateBuffer((u8*)pBuffer, nAccessSize, -nBufferRotationOfs, false); + } + } + // Read end block(s) + //osTPrintf("nSize = %d, nEndBlkFraction = %d\n", nSize, nEndBlkFraction); + void *pBufferEndBlk = (void*)((size_t)pBuffer + nAccessSize - nEndBlkFraction); + while(nEndBlkFraction){ + ++nEndBlkIdx; + WFSFileBlkInfo fileBlkInfo = pFuncWFSKrnGetFileBlkInfo(pAreaInfo, pMetaData, nLog2MetaSize, nEndBlkIdx); + u16 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pParentBlkPtr; + if( !pAttrHdr->file.nSize || (nEndBlkIdx == nMaxBlkIdx && pAttrHdr->file.nSize&((1<file.nSize&((1< (1<nBlkAdr, pBlkPtr); + WFSKrnExit1OnError(TransUnpinBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + } + + if(pAttrHdr->nSizeCategory == FILE_SIZE_CATEGORY_VERY_LARGE){ + WFSKrnExit1OnError(TransUnpinBlk3(pAreaInfo, *pParentBlkAdr, pTransInfo)); + pParentBlkAdr = &pParentBlkAdr[-1]; + ++nIndirectIdx; + } + nPos += nAccessSize; + pBuffer = (void*)((size_t)pBuffer + nAccessSize); + } + +Exit1: + TransUnpinBlk(&pKfi->pci.di.tba); +Exit2: + TransEnd(pKfi->pci.di.tba.pTransInfo); +Exit3: + if(nResult < 0) + { + nReadSize = (s32)nResult; + } +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput4("ReadFile(fh=%04x, pBuf, p=%u, s=%d) ", sfh, nInPos, nInSize); + if (nReadSize >= 0) { + WFSKrnDbgOutput2("return %d\n", nReadSize); + } else { + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString((WFSKrnResult)nReadSize)); + } + ); +#endif + return nReadSize; +} + + +static inline WFSKrnResult WfsSrvTransWriteFileBlksForCategorySmall(AreaInfo *pAreaInfo, void *pMetaData, u8 *pBuffer, u32 nBlkIdx, u32 nSize, TransInfo *pTransInfo, bool bDecryption){ + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall((DirEntryAttrHdr*)pMetaData, ((DirEntryAttrHdr*)pMetaData)->nAttrLog2Size, nBlkIdx); + return TransWriteFileBlks(pBuffer, pAreaInfo, nSize, pFileBlkPtr, -(signed)sizeof(*pFileBlkPtr), pTransInfo, bDecryption); +} + +static inline WFSKrnResult WfsSrvTransWriteFileBlksForCategoryMedium(AreaInfo *pAreaInfo, void *pMetaData, u8 *pBuffer, u32 nBlkIdx, u32 nSize, TransInfo *pTransInfo, bool bDecryption){ + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium((DirEntryAttrHdr*)pMetaData, ((DirEntryAttrHdr*)pMetaData)->nAttrLog2Size, nBlkIdx); + return TransWriteFileMediumBlks(pBuffer, pAreaInfo, nSize, pFileBlkPtr, -(signed)sizeof(*pFileBlkPtr), pTransInfo, bDecryption); +} + +static inline WFSKrnResult WfsSrvTransWriteFileBlksForCategoryLarge(AreaInfo *pAreaInfo, void *pMetaData, u8 *pBuffer, u32 nBlkIdx, u32 nSize, TransInfo *pTransInfo, bool bDecryption){ + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrForCategoryLarge((DirEntryAttrHdr*)pMetaData, ((DirEntryAttrHdr*)pMetaData)->nAttrLog2Size, nBlkIdx>>pAreaInfo->nLog2MediumBlkPerLargeBlk); + return TransWriteFileLargeBlks(pBuffer, pAreaInfo, nSize, nBlkIdx%(1<nLog2MediumBlkPerLargeBlk), + pFileLargeBlkPtr, -(signed)sizeof(*pFileLargeBlkPtr), pTransInfo, bDecryption); +} + +static inline WFSKrnResult WfsSrvTransWriteFileBlksForCategoryVeryLarge(AreaInfo *pAreaInfo, void *pMetaData, u8 *pBuffer, u32 nBlkIdx, u32 nSize, TransInfo *pTransInfo, bool bDecryption){ + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrFromIndirectBlkForCategoryVeryLarge((u8*)pMetaData, nBlkIdx>>pAreaInfo->nLog2MediumBlkPerLargeBlk); + return TransWriteFileLargeBlks(pBuffer, pAreaInfo, nSize, nBlkIdx%(1<nLog2MediumBlkPerLargeBlk), + pFileLargeBlkPtr, (s32)sizeof(*pFileLargeBlkPtr), pTransInfo, bDecryption); +} + + +static u32 nGlobalChainId = 0; + + +WFSResult WFSSrvWriteFile(WFSSrvFileHandle sfh, const void *pBuffer, WFSFileSize nPos, WFSFileSize nSize, WFSBool bDiscard) { +#if _DEBUG_BREAK_POINT + static int c = 0; c++; if (c == 0x2866) { //839702 + int a;a=0; + } +#endif +#if _DEBUG + #if ((DBG_OUTPUT_TO_LOG_FILE && _WIN32) || DBG_OUTPUT_TO_SCREEN) + WFSFileSize nInPos = nPos; + s32 nInSize = nSize; + #endif +#endif + //if((size_t)pBuffer%WFSKRN_FILE_BUFFER_MEM_ALIGNMENT_SIZE){ + // return WFS_RESULT_INVALID; + //} + WFSKrnResult nResult = WFSKRN_RESULT_UNKNOWN; + WFSKrnFileInfo *pKfi; + WFSKrnExit3OnError(WFSKrnGetFileInfo(&pKfi, sfh)); + TransInfo *pTransInfo = pKfi->pci.di.tba.pTransInfo = TransBegin(); + if ((pKfi->nAccess & WFS_ACCESS_WRITE) == 0) { + nResult = (WFSKrnResult)WFS_RESULT_ACCESS; + goto Exit2; + } + nResult = DirItrUpdateAndPinBlk(&pKfi->pci.di, pKfi->pci.nRootBlkAdr, TRANS_FLAG_RW_BLK); + if (nResult != WFSKRN_RESULT_OK) + { + goto Exit2; + } + DirEntryAttrHdr *pAttrHdr = pKfi->pci.di.pAttrHdr; + TransBlkAdr *pTba = &pKfi->pci.di.tba; + AreaInfo *pAreaInfo = pKfi->pci.di.tba.pAreaInfo; + + if (nPos > pAttrHdr->file.nSize){ + nResult = WFSKRN_RESULT_INVALID; + goto Exit1; + } + if(!nSize){ + nResult = WFSKRN_RESULT_OK; + goto Exit1; + } + if (pAttrHdr->file.nSize < (u64) nPos) + { + nResult = WFSKRN_RESULT_INVALID; + goto Exit1; + } + u32 nOldSize = pKfi->pci.di.pAttrHdr->file.nSize; + u64 nNewSize = (u64)nPos + (u64)nSize; + if(nNewSize>>WFS_LOG2_MAX_FILE_SIZE){ + nNewSize = (u32)-1; + nSize = nNewSize - nPos; + } else if (nOldSize > nNewSize){ + nNewSize = nOldSize; + } +#ifdef PERMISSION_ENABLED + if (nNewSize > pAttrHdr->file.nSize) + { + if((pKfi->nAccess & WFS_ACCESS_CHANGE_SIZE) == 0) + { + nResult = (WFSKrnResult)WFS_RESULT_NO_CHANGE_SIZE; + goto Exit1; + } + } +#endif +#if _DEBUG_BREAK_POINT + if (nNewSize == 0xfde71){ + int a; a=0; + } +#endif + osTPrintf( "nNewSize:0x%x, nAllocSize:0x%x\n", nNewSize, pKfi->pci.di.pAttrHdr->nAllocSize); + if (nNewSize > pKfi->pci.di.pAttrHdr->nAllocSize){ + WFSKrnExit1OnError(DirResizeFile(&pKfi->pci.di, nNewSize)); + pAttrHdr = pKfi->pci.di.pAttrHdr; + } + + u32 nLog2UnitBlkSize = 0; + WFSBlkAdr *pParentBlkAdr = 0; + WFSFileBlkInfo (*pFuncWFSKrnGetFileBlkInfo)(AreaInfo *pAreaInfo, void *pMetaData, u32 nLog2MetaSize, u32 nBlkIdx) = 0; + WFSKrnResult (*pFuncWfsSrvTransGetAndPinFileBlk)(TransBlkAdr *pTba, WFSBlkAdr nParentBlkAdr, u16 nHashOfs, WFSBlkAdr nFileBlkAdr, u32 nFlags, u32 nValidSize, void **ppBlkPtr) = 0; + WFSKrnResult (*pFuncWfsSrvTransWriteFileBlks)(AreaInfo *pAreaInfo, void *pMetaData, u8 *pBuffer, u32 nBlkIdx, u32 nNumBlks, TransInfo *pTransInfo, bool bDecryption) = 0; + // for VERY_LARGE + u32 nNumIndirectBlks = 0; + s32 nIndirectIdx = 0; + u8* pIndirectBlkPtr[WFSKRN_VERY_LARGE_MAP_NUM_INDIRECT_BLKS]; + u32 nChainId = 0; + + switch(pAttrHdr->nSizeCategory) { + case FILE_SIZE_CATEGORY_VERY_SMALL: { + u8 *pFileDataPtr = &pAttrHdr->aCaseBitArray[(pAttrHdr->nNameLen+7)>>3] + nPos; + memcpy(pFileDataPtr, pBuffer, nSize); + nPos += nSize; + nSize = 0; + break; + } + case FILE_SIZE_CATEGORY_SMALL: { + nLog2UnitBlkSize = pAreaInfo->ah.nLog2BlkSize; + pFuncWFSKrnGetFileBlkInfo = WFSKrnGetFileBlkInfoForCategorySmallCast; + pFuncWfsSrvTransGetAndPinFileBlk = TransGetAndPinFileBlk; + pFuncWfsSrvTransWriteFileBlks = WfsSrvTransWriteFileBlksForCategorySmall; + pParentBlkAdr = &pTba->nBlkAdr; + break; + } + case FILE_SIZE_CATEGORY_MEDIUM: { + nLog2UnitBlkSize = pAreaInfo->ah.nLog2MediumBlkSize; + pFuncWFSKrnGetFileBlkInfo = WFSKrnGetFileBlkInfoForCategoryMediumCast; + pFuncWfsSrvTransGetAndPinFileBlk = TransGetAndPinFileMediumBlk; + pFuncWfsSrvTransWriteFileBlks = WfsSrvTransWriteFileBlksForCategoryMedium; + pParentBlkAdr = &pTba->nBlkAdr; + break; + } + case FILE_SIZE_CATEGORY_LARGE: { + nLog2UnitBlkSize = pAreaInfo->ah.nLog2MediumBlkSize; + pFuncWFSKrnGetFileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLargeCast; + pFuncWfsSrvTransGetAndPinFileBlk = TransGetAndPinFileMediumBlk; + pFuncWfsSrvTransWriteFileBlks = WfsSrvTransWriteFileBlksForCategoryLarge; + pParentBlkAdr = &pTba->nBlkAdr; + break; + } + case FILE_SIZE_CATEGORY_VERY_LARGE: { + nLog2UnitBlkSize = pAreaInfo->ah.nLog2MediumBlkSize; + pFuncWFSKrnGetFileBlkInfo = WFSKrnGetFileBlkInfoFromIndirectBlkForCategoryVeryLargeCast; + pFuncWfsSrvTransGetAndPinFileBlk = TransGetAndPinFileMediumBlk; + pFuncWfsSrvTransWriteFileBlks = WfsSrvTransWriteFileBlksForCategoryVeryLarge; + pParentBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndLargeBlkIdxForCategoryVeryLarge(pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, nPos>>pAreaInfo->ah.nLog2LargeBlkSize); + nNumIndirectBlks = (nSize+nPos%(pAreaInfo->nNumLargeBlkPtrsPerBlk<ah.nLog2LargeBlkSize)-1)/(pAreaInfo->nNumLargeBlkPtrsPerBlk<ah.nLog2LargeBlkSize)+1; + if(TransGetChainId4(pAreaInfo, pParentBlkAdr[0], pTransInfo, &nChainId) < WFSKRN_RESULT_OK || nChainId == 0){ + ++nGlobalChainId; + if(!nGlobalChainId){ nGlobalChainId = 1;} + nChainId = nGlobalChainId; + } + break; + } + } + + while(nSize > 0){ + void *pMetaData; + void *pHashBlkPtr; + u32 nLog2MetaSize; + u32 nAccessSize, nAccessPos; + + if(pAttrHdr->nSizeCategory == FILE_SIZE_CATEGORY_VERY_LARGE){ + if(!(nIndirectIdx&(WFSKRN_VERY_LARGE_MAP_NUM_INDIRECT_BLKS-1))){ + for(nIndirectIdx=0;nIndirectIdxah.nLog2BlkSize; + pHashBlkPtr = pMetaData; + nAccessPos = nPos%(pAreaInfo->nNumLargeBlkPtrsPerBlk<ah.nLog2LargeBlkSize); + nAccessSize = (pAreaInfo->nNumLargeBlkPtrsPerBlk<ah.nLog2LargeBlkSize) - nAccessPos; + if(nAccessSize > nSize) { + nAccessSize = nSize; + nSize = 0; + } else { + nSize -= nAccessSize; + } + } else { + pMetaData = (void*)pAttrHdr; + nLog2MetaSize = pAttrHdr->nAttrLog2Size; + pHashBlkPtr = pKfi->pci.di.pBlkHdr; + nAccessSize = nSize; + nAccessPos = nPos; + nSize = 0; + } + + u8 *pBlkPtr; + u32 nBlkMask = (1<> nLog2UnitBlkSize; + u32 nStartOfs = nAccessPos & nBlkMask; + u32 nStartBlkFraction = (-(signed)nAccessPos) & nBlkMask; + s32 nEndBlkIdx = (nAccessPos + nAccessSize - 1) >> nLog2UnitBlkSize; + u32 nEndOfs = (nAccessPos + nAccessSize) & nBlkMask; + u32 nEndBlkFraction = 0; + s32 nOldMaxBlkIdx = nOldSize ? ((nOldSize - 1) >> nLog2UnitBlkSize) : 0; + s32 nNewMaxBlkIdx = nNewSize ? ((nNewSize - 1) >> nLog2UnitBlkSize) : 0; + s32 nBufferRotationOfs = ((u32)pBuffer + nStartBlkFraction) & (WFS_STATIC_MEM_ALIGNMENT-1); + if (nBufferRotationOfs > nStartBlkFraction) { + nBufferRotationOfs = nBufferRotationOfs - WFS_STATIC_MEM_ALIGNMENT; + } + // If nStartOfs is not 0, nStartBlk is accessed path through block cache. + if(nStartOfs){ + WFSFileBlkInfo fileBlkInfo = pFuncWFSKrnGetFileBlkInfo(pAreaInfo, pMetaData, nLog2MetaSize, nStartBlkIdx); + u16 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pHashBlkPtr; + u32 nValidSize; + if(nStartBlkIdx < nOldMaxBlkIdx){ + nValidSize = 1<pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo, nValidSize)); + if (bDiscard){ + WFSKrnExit1OnError(TransUnpinBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + WFSKrnExit1OnError(TransFlushBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + } else { + WFSKrnExit1OnError(TransStoreBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + WFSKrnExit1OnError(TransUnpinBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + } + ++nStartBlkIdx; + } + u32 nDirectWriteSize = 0; + u32 nEnableByteRotation = 0; + // If nEndOfs is not 0, nEndBlk is accessed path through block cache. (just ready parameters) + if ((nStartBlkIdx <= nEndBlkIdx) && nEndOfs){ + if(!(nEndOfs&((1<pAreaInfo->pVolInfo->pDevInfo->dh.nLog2SectorSize)-1)) && (nBufferRotationOfs >= 0) && (nPos+nAccessSize == nNewSize) ){ + nDirectWriteSize += nEndOfs; + --nEndBlkIdx; + } else { + nEndBlkFraction += nEndOfs; + nEnableByteRotation += nEndOfs; + --nEndBlkIdx; + } + } + // If nEndOfs and nStartBlkFraction is smaller than nBufferRotationOfs, the extra block is read. (just ready parameters) + while ((nStartBlkIdx <= nEndBlkIdx) && (nBufferRotationOfs < 0) && (nEnableByteRotation < -nBufferRotationOfs)){ + nEnableByteRotation += 1<nBlkAdr, &pFileBlkPtr->hash); + if (nBufferRotationOfs) { + RotateBuffer((u8*)pBuffer, nAccessSize, -nBufferRotationOfs, false); + } + } + // Write end block(s) + //osTPrintf("nSize = %d, nEndBlkFraction = %d\n", nSize, nEndBlkFraction); + void* pBufferEndBlk = (void*)((size_t)pBuffer + nAccessSize - nEndBlkFraction); + while(nEndBlkFraction){ + ++nEndBlkIdx; + WFSFileBlkInfo fileBlkInfo = pFuncWFSKrnGetFileBlkInfo(pAreaInfo, pMetaData, nLog2MetaSize, nEndBlkIdx); + u16 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pHashBlkPtr; + //osTPrintf("nHashOfs = %d, nBlkAdr = %d, pBlkPtr = 0x%x\n", nHashOfs, pFileBlkPtr->nBlkAdr, pBlkPtr); + u32 nValidSize; + if(nEndBlkIdx < nOldMaxBlkIdx){ + nValidSize = 1< (1<pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo, nValidSize)); + if(bDiscard){ + WFSKrnExit1OnError(TransUnpinBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + WFSKrnExit1OnError(TransFlushBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + } else { + WFSKrnExit1OnError(TransStoreBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + WFSKrnExit1OnError(TransUnpinBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + } + } + + if(pAttrHdr->nSizeCategory == FILE_SIZE_CATEGORY_VERY_LARGE){ + WFSKrnExit1OnError(TransUnpinBlk3(pAreaInfo, *pParentBlkAdr, pTransInfo)); + pParentBlkAdr = &pParentBlkAdr[-1]; + ++nIndirectIdx; + } + nPos += nAccessSize; + pBuffer = (void*)((size_t)pBuffer + nAccessSize); + } + + //nPos += nSize; + if (pKfi->pci.di.pAttrHdr->file.nSize < nPos) { + pKfi->pci.di.pAttrHdr->file.nSize = nPos; + } + // Update attributes in pKfi->attr. + pKfi->attr = *pKfi->pci.di.pAttrHdr; +Exit1: + TransUnpinBlk(pTba); +Exit2: + TransEnd(pKfi->pci.di.tba.pTransInfo); +Exit3: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput4("WriteFile(fh=%04x, pBuf, p=%u, s=%u) ", sfh, nInPos, nInSize); + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString((WFSKrnResult)nResult)); + ); +#endif + return (WFSResult)nResult; +} + + +WFSResult WFSSrvFlush(const WFSVolumeId *pVolumeId){ + + WFSKrnResult nResult = WFSKRN_RESULT_OK; + utf8 sVolPath[WFS_MAX_VOLUME_ID_SIZE + 6]; + osSNPrintf(sVolPath, WFS_MAX_VOLUME_ID_SIZE + 6, "/vol/%s", pVolumeId->sStr); + VolumeInfo *pVolInfo; + RxtItr rxi; + rxi.pStrPtr = sVolPath; + PathCacheEntry *pEntry = PathCacheFind2(&rxi, (void **)&pVolInfo); + if (!pEntry) { + nResult = WFSKRN_RESULT_NOT_FOUND; + goto Exit; + } + nResult = BCacheStoreVolume(pVolInfo); +Exit: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest(WFSKrnDbgOutputCmdNum; WFSKrnDbgOutput3("Flush(\"%s\") WFS_RESULT_%s\n", pVolumeId->sStr, WFSKrnGetErrorString(nResult))); +#endif + return (WFSResult)nResult; +} + + +WFSResult WFSSrvSetTitleId(WFSTitleId titleId, WFSGroupId groupId) { +#if _WIN32 || PERM_TEST + wkg.nDebugTitleId = titleId; +#endif + return WFS_RESULT_OK; +} + + +static WFSResult WFSSrvCheckDisk(WFSSrvFileHandle* pfh, utf8 *pDevName){ + + WFSDeviceName devName; + strncpy(devName.sStr, pDevName, WFS_MAX_DEVICE_NAME_SIZE); + devName.nLen = STRNLEN(devName.sStr, WFS_MAX_DEVICE_NAME_SIZE); + DeviceInfo *pDevInfo = DeviceGetDeviceInfo(&devName); + AreaInfo *pAreaInfo = &pDevInfo->pVolInfo->rootAreaInfo; + u32 nSize = pAreaInfo->ah.nNumBlks / 8; + + WFSSrvFileHandle fh; + WFSFileAttributes fa; + WFSPathName bitArrayFilePath; + + WFSVolumeId volId; + VolumeConvertU32ToVolId(&volId, pAreaInfo->pVolInfo->vh.nVolId); + osSNPrintf((char*)bitArrayFilePath.sStr, WFS_MAX_PATH_NAME_SIZE, "/vol/%s/%s", volId.sStr, CHECKDISKFILENAME); + bitArrayFilePath.nLen = STRNLEN(bitArrayFilePath.sStr, WFS_MAX_PATH_NAME_SIZE); + + + // Open bit array file + // todo: check empty area size + // todo: case: the number of blocks is not product of 8 + WFSResult result = WFSSrvCreateAndOpenFile(&bitArrayFilePath, WFS_PERM_FULL, 0, nSize, &fh); + if(result != WFS_RESULT_OK){ + if(result == WFS_RESULT_ALREADY_EXISTS){ + result = WFSSrvOpenFile(&bitArrayFilePath, WFS_ACCESS_RW, &fh, &fa); + if(result != WFS_RESULT_OK){ + osTPrintf("WFSSrvCheckDisk: failed to open file (already exists) %d\n", result); + return (WFSResult)WFSKRN_RESULT_CHECKDISK_INTERNAL_ERROR; + } + } + osTPrintf("WFSSrvCheckDisk: failed to open file %d\n", result); + return (WFSResult)WFSKRN_RESULT_CHECKDISK_INTERNAL_ERROR; + } + + //osTPrintf("fh %d\n", fh); + //osTPrintf("nSize: %d\n", nSize); + //osTPrintf("nNumBlks: %d\n", pAreaInfo->ah.nNumBlks); + + u8* pBuffer; + WFSKrnResult krnResult = WFSKRN_RESULT_OK; + + // Alloc and pin + WFSBlkAdr blkAdr; + krnResult = AreaAllocBlks(pAreaInfo, 0, 16, 1, &blkAdr, 0); // reserve 64KB block x 1 + if (krnResult != WFSKRN_RESULT_OK){ + osTPrintf("WFSSrvCheckDisk: failed to alloc a block.\n"); + krnResult = (WFSKrnResult)WFSKRN_RESULT_CHECKDISK_INTERNAL_ERROR; + goto CLOSEFILE; + } + krnResult = TransGetAndPinFileBlk8(pAreaInfo, blkAdr, 0, blkAdr, NULL, (BCACHE_FLAG_DIRTY | BCACHE_FLAG_PINNED), 1<ah.nLog2MediumBlkSize, BCACHE_GROUP_ID_USERBLK_64K, (void**)&pBuffer); + if (krnResult != WFSKRN_RESULT_OK){ + osTPrintf("WFSSrvCheckDisk: failed to pin the block.\n"); + + krnResult = (WFSKrnResult)WFSKRN_RESULT_CHECKDISK_INTERNAL_ERROR; + goto UNPINBLOCK; + } + + u32 bufferSize = 64*1024; // BCACHE_GROUP_ID_USERBLK_64K + u8* pBuffer512 = pBuffer; + + // clear bit array file + // todo: error handling + memset(pBuffer512, 0, bufferSize); + int nPos; + for(nPos=0; nPos nSize ) writeSize = nSize - nPos; + WFSSrvWriteFile(fh, pBuffer512, nPos, writeSize, false); + } + + // set 1 for blkAdr itself (USERBLK_64K -> 8KB block x 8 -> 1byte) + pBuffer512[0] |= (u8) (0xff << (blkAdr % 8)); + pBuffer512[1] |= (u8)~(0xff << (blkAdr % 8)); + u32 writeSize = 1; + if(blkAdr % 8 != 0) writeSize = 2; + WFSSrvWriteFile(fh, pBuffer512, blkAdr/8, writeSize, false); + + + //osTPrintf("LINE: %d\n", __LINE__); + // Check disk for Free block allocator + krnResult = AreaPinFreeListHdr(pAreaInfo, BCACHE_FLAG_READ , &pAreaInfo->pAflh); + WFSKRN_FTREE_ASSERT(krnResult == WFSKRN_RESULT_OK); + krnResult = FreeBlkCheckDisk(pAreaInfo, fh, pBuffer512, bufferSize, nSize); + if (krnResult != WFSKRN_RESULT_OK){ + osTPrintf("Error : FreeBlkCheckDisk()\n"); + } + AreaUnpinFreeListHdr(pAreaInfo); + + PathCacheItr pci; + WFSPathName path, path1; + osSNPrintf((char*)path1.sStr, WFS_MAX_PATH_NAME_SIZE, "/vol/%s", volId.sStr); + strncpy(path.sStr, path1.sStr, WFS_MAX_PATH_NAME_SIZE); + path.nLen = STRNLEN(path.sStr, WFS_MAX_PATH_NAME_SIZE); + PathCacheFindPath(&path, path1.sStr, &pci); + //osTPrintf("LINE: %d\n", __LINE__); + + // Check disk for access list + krnResult = DirCheckDisk(pAreaInfo->ah.aclHdr.aclBlock, &pci.di, fh, pBuffer512, bufferSize, DIR_CHECK_DISK_FOR_ACL_TREE); + if (krnResult != WFSKRN_RESULT_OK){ + osTPrintf("WFSSrvCheckDisk: failed at acl1\n"); + krnResult = (WFSKrnResult)WFSKRN_RESULT_CHECKDISK_INTERNAL_ERROR; + goto UNPINBLOCK; + } + krnResult = DirCheckDisk(pAreaInfo->ah.aclHdr.nameBlock, &pci.di, fh, pBuffer512, bufferSize, DIR_CHECK_DISK_FOR_ACL_TREE); + if (krnResult != WFSKRN_RESULT_OK){ + osTPrintf("WFSSrvCheckDisk: failed at acl2 \n"); + krnResult = (WFSKrnResult)WFSKRN_RESULT_CHECKDISK_INTERNAL_ERROR; + goto UNPINBLOCK; + } + //osTPrintf("LINE: %d\n", __LINE__); + // Check disk for dir module + krnResult = DirCheckDisk(pAreaInfo->ah.nRootBlkAdr, &pci.di, fh, pBuffer512, bufferSize, DIR_CHECK_DISK_FOR_DIR_TREE); + if (krnResult != WFSKRN_RESULT_OK){ + osTPrintf("WFSSrvCheckDisk: failed at dir module \n"); + krnResult = (WFSKrnResult)WFSKRN_RESULT_CHECKDISK_INTERNAL_ERROR; + goto UNPINBLOCK; + } + + //osTPrintf("LINE: %d\n", __LINE__); + // check if the content of the bit array file is all 1(0xff) + memset(pBuffer512 + bufferSize/2, 0xff, bufferSize/2); + for(nPos=0; nPos nSize) verifySize = nSize - nPos; // + WFSSrvReadFile(fh, pBuffer512, nPos, verifySize); + if(memcmp(pBuffer512, pBuffer512+bufferSize/2, verifySize) != 0){ + // file system error! + osTPrintf("Error : Check disk verify : Buffer = %d\n", nPos); + krnResult = WFSKRN_RESULT_CHECKDISK_INCONSISTENT; + } + } + +UNPINBLOCK: + TransUnpinAndFreeBlks(pAreaInfo, 16, 1, &blkAdr, NULL); + TransInvalidate3(pAreaInfo, blkAdr, NULL); + +CLOSEFILE: + WFSSrvCloseFile(fh, nSize); + WFSSrvDelete(&bitArrayFilePath); + + return (WFSResult)krnResult; + +} + +/* +WFSResult WFSSrvCacheDeleteAll(u32 nDevIdx) { + WFSKrnResult nResult = WFSKRN_RESULT_OK; + utf8 sVolPath[WFS_MAX_VOLUME_ID_SIZE + 6]; + DeviceInfo *pDevInfo = &wkg.aDevInfo[nDevIdx]; + WFSVolumeId VolumeId; + VolumeConvertU32ToVolId(&VolumeId, pDevInfo->pVolInfo->vh.nVolId); + osSNPrintf(sVolPath, WFS_MAX_VOLUME_ID_SIZE + 6, "/vol/%s", VolumeId.sStr); + VolumeInfo *pVolInfo; + RxtItr rxi; + rxi.pStrPtr = sVolPath; + PathCacheEntry *pEntry = PathCacheFind2(&rxi, (void **)&pVolInfo); + if (!pEntry) { + nResult = WFSKRN_RESULT_NOT_FOUND; + goto Exit; + } + if (0 < pEntry->pcd.nOpenHandleCount && pVolInfo->pDevInfo->bInUse) { +#if _DEBUG + PathCacheDebugOutput(); +#endif + nResult = WFSKRN_RESULT_FILE_OPEN; + goto Exit; + } + nResult = PathCacheDeleteSubTree(pEntry); + pEntry = PathCacheInsertAfterCursorEntry2(wkg.pathCache.pPinAnchor, sVolPath); + if (pEntry){ + pEntry->pcd.pData = pVolInfo; + } +Exit:; + return (WFSResult)nResult; +} +*/ + +#include + +WFSResult WFSSrvExecDebugProcedure(u32 cmd , void *arg0 , void *arg1) { + WFSResult nResult = WFS_RESULT_OK; + + // convert. + switch (cmd) + { + case ((int) WFSDEBUG_CMD_ATTACH): + cmd = WFSDEBUG_CMD_DEVICE_ATTACH_DETACH; + arg0 = (void*) TRUE; + arg1 = (void*) 0; // [check] + break; + case ((int) WFSDEBUG_CMD_DETACH): + cmd = WFSDEBUG_CMD_DEVICE_ATTACH_DETACH; + arg0 = (void*) FALSE; + arg1 = (void*) 0; // [check] + break; + case ((int) WFSDEBUG_CMD_ATTACH_WRITE_PROTECTED): + case ((int) WFSDEBUG_CMD_DELETE_DEVICEROOT): + case ((int) WFSDEBUG_CMD_DELETE_PATH): + case ((int) WFSDEBUG_CMD_CLOSE_ALLFILE): + case ((int) WFSDEBUG_CMD_DUMP_PERMISSION): + case ((int) WFSDEBUG_CMD_SET_AUTO_FORMAT_ON_ATTACH): + case ((int) WFSDEBUG_CMD_PUSH_PATH): + case ((int) WFSDEBUG_CMD_EXEC_BAT): + case ((int) WFSDEBUG_CMD_TOUCH): + // default: + return WFS_RESULT_NOT_IMPLEMENTED; + } + + switch (cmd) { +/* + case WFSDEBUG_CMD_KRN_INIT_VIRTUAL_DISK: +#if !_IOP + gpPtr = (u8*)arg0; +#else + gpPtr = (u8*)((u32)arg0 & 0x7fffffff); +#endif + gSize = (u32)arg1; + break; +*/ +// case WFSDEBUG_CMD_KRN_INIT_AREA_SECTORS: +// gNumSectors = (u32)arg0; +// break; + +/* + case WFSDEBUG_CMD_KRN_INIT_CACHE: +#if !_IOP + gpCachePtr = (u8*)arg0; +#else + gpCachePtr = (u8*)((u32)arg0 & 0x7fffffff); +#endif + gCacheSize = (u32)arg1; + break; +*/ + + case WFSDEBUG_CMD_DIR_CHECK_DNS_EMPTY: + DirNodeStackCheckEmpty; + break; +/* + case WFSDEBUG_CMD_PATH_CACHE_DELETE_ALL:{ + u32 nDevIdx = (u32) arg0; + nResult = WFSSrvCacheDeleteAll(nDevIdx); + break; + } +*/ + case WFSDEBUG_CMD_DEVICE_ATTACH_DETACH: + { + u32 bAttach = (u32) arg0; + u32 nDevIdx = (u32) arg1; + DeviceInfo *pDevInfo = &wkg.aDevInfo[nDevIdx]; + if (bAttach && pDevInfo->bInUse) + { + nResult = WFS_RESULT_DEV_IN_USE; + } + else if (!bAttach && !pDevInfo->bInUse) + { + nResult = WFS_RESULT_MEDIA_ERROR; + } + else + { + WfsKrnAttachDetachCallback(bAttach, nDevIdx, TEST_LOG2_SECTOR_SIZE, MAX_ALLOC_NUM_SECTORS, WFS_DEVTYPE_USB_MSC_20, 0); + } + } + break; + + case WFSDEBUG_CMD_DEVICE_PSEUDO_DETACH: + DeviceDebugSetPseudoDetachDevice((s32)arg0); + break; + + case WFSDEBUG_CMD_DEVICE_PSEUDO_HASH_INCONSISTENT: + DeviceDebugSetPseudoHashInconsistent((s32)arg0); + break; + + case WFSDEBUG_CMD_DEVICE_SET_FLAGS: +#if !_IOP + DeviceGetDeviceInfo((WFSDeviceName*)arg0)->nFlags = (u32)arg1; +#else + DeviceGetDeviceInfo((WFSDeviceName*)((u32)arg0 & 0x7fffffff))->nFlags = (u32)arg1; +#endif + break; + case WFSDEBUG_CMD_AREA_AND_DIR_CHECK_DISK:{ + WFSSrvFileHandle* pfh = (WFSSrvFileHandle*)arg0; +#if !_IOP + //u8* pCheckDiskArray = (u8*)arg0; + utf8* pDevString = (utf8*)arg1; +#else + //u8* pCheckDiskArray = (u8*)((u32)arg0&0x7fffffff); + utf8* pDevString = (utf8*)((u32)arg1&0x7fffffff); +#endif + nResult = (WFSResult)WFSSrvCheckDisk(pfh, pDevString); + break; + } + } + return nResult; +} + + +WFSResult WFSSrvConnectToServer(void) { + osTPrintf("WFSSrvConnectToServer()\n"); + return WFS_RESULT_OK; +} + + +WFSResult WFSSrvGetPermissionForUser(const WFSPathName *pAbsPathName, u32 *pFlags, WFSTitleId titleId) { +#ifdef PERMISSION_ENABLED + WFSKrnResult nResult = WFSKRN_RESULT_OK; + WFSPathName path; + WFSKrnExit2OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + PathCacheItr pci; + pci.di.tba.pTransInfo = TransBegin(); + WFSKrnExit1OnError(PathCacheFindPath(pAbsPathName, path.sStr, &pci)); + // Check the permission of parent dir and specified entry for executor + u32 parentPermissions; + u32 permissions; + WFSKrnExit1OnError(WFSKrnGetInheritedPermissionForUserDi(&pci, &permissions, pci.di.tba.pTransInfo->nTitleId)); + if((pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) == 0 || !(permissions & WFS_PERM_LIST)) + { + WFSKrnExit1OnError(WFSKrnGetParentInheritedPermissionForUserPci(&pci, &parentPermissions, pci.di.tba.pTransInfo->nTitleId)); + if(!(parentPermissions & WFS_PERM_LIST)) + { + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } + } + // Get inherited permissions for user + WFSKrnExit1OnError(WFSKrnGetInheritedPermissionForUserDi(&pci, pFlags, titleId)); +Exit1: + DirItrClose(&pci.di); + TransEnd(pci.di.tba.pTransInfo); +Exit2: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput4("GetPermissionForUser(\"%s\", pf=%x, t=%x) ", pAbsPathName->sStr, pFlags, titleId); + if (nResult == WFSKRN_RESULT_OK) { + WFSKrnDbgOutput2("f=%x ", *pFlags); + } + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString(nResult)); + ); +#endif + return (WFSResult)nResult; +#else + osTPrintf("WFSSrvGetPermissionForUser()\n"); + return WFS_RESULT_OK; // dummy +#endif +} + + +WFSResult WFSSrvSetPermissionForUser(const WFSPathName *pAbsPathName, u32 nFlags, u32 nMask, WFSTitleId titleId) { +#ifdef PERMISSION_ENABLED + WFSKrnResult nResult = WFSKRN_RESULT_OK; + WFSPathName path; + WFSKrnExit2OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + PathCacheItr pci; + pci.di.tba.pTransInfo = TransBegin(); + WFSKrnExit1OnError(PathCacheFindPath(pAbsPathName, path.sStr, &pci)); + if (!pci.di.tba.pAreaInfo) + { + // no one can set permission to the entry which has no area info. + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } + WFSKrnExit1OnError(DirGetBlk(&pci.di, TRANS_FLAG_RW_BLK, 0)); + WFSKrnExit1OnError(WFSKrnSetInheritedPermissionForUser(&pci, nFlags, nMask, pci.di.tba.pTransInfo->nTitleId, titleId)); + if (*pci.rxi.pStrPtr==0) { // The pEntry refers to the object (rather than the parent dir) + // Update acl index data in path cache tree + pci.pEntry->pcd.nAccessListIdx = pci.di.pAttrHdr->nAccessListIdx; + } +Exit1: + DirItrClose(&pci.di); + TransEnd(pci.di.tba.pTransInfo); +Exit2: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput5("SetPermissionForUser(\"%s\", f=%x, m=%x, t=%x) ", pAbsPathName->sStr, nFlags, nMask, titleId); + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString(nResult)); + ); +#endif + return (WFSResult)nResult; +#else + osTPrintf("WFSSrvSetPermissionForUser()\n"); + return WFS_RESULT_OK; // dummy +#endif +} + +WFSResult WFSSrvDeleteAccessListEntry(const WFSPathName *pAbsPathName, WFSTitleId titleId, WFSTitleId entryCreatorId) +{ +#ifdef PERMISSION_ENABLED + WFSKrnResult nResult = WFSKRN_RESULT_OK; + WFSPathName path; + WFSKrnExit2OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + PathCacheItr pci; + pci.di.tba.pTransInfo = TransBegin(); + WFSKrnExit1OnError(PathCacheFindPath(pAbsPathName, path.sStr, &pci)); + if (!pci.di.tba.pAreaInfo) + { + // no one can set permission to the entry which has no area info. + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } + WFSKrnExit1OnError(DirGetBlk(&pci.di, TRANS_FLAG_RW_BLK, 0)); + WFSKrnExit1OnError(WFSKrnDeletePermissions(pci.di.tba.pAreaInfo, &(pci.di.pAttrHdr->nAccessListIdx), entryCreatorId, titleId)); + if (*pci.rxi.pStrPtr==0) { // The pEntry refers to the object (rather than the parent dir) + // Update acl index data in path cache tree + pci.pEntry->pcd.nAccessListIdx = pci.di.pAttrHdr->nAccessListIdx; + } +Exit1: + DirItrClose(&pci.di); + TransEnd(pci.di.tba.pTransInfo); +Exit2: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput4("DeleteAccessListEntry(\"%s\", t=%x, ec=%x) ", pAbsPathName->sStr, titleId, entryCreatorId); + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString(nResult)); + ); +#endif + return (WFSResult)nResult; +#else + osTPrintf("WFSSrvDeleteAccessListEntry()\n"); + return WFS_RESULT_NOT_IMPLEMENTED; // dummy +#endif +} + +s32 WFSSrvGetAccessList(const WFSPathName *pAbsPathName, WFSAccessListEntry *pAccessList, u32 nMaxElements) +{ +#ifdef PERMISSION_ENABLED + WFSKrnResult nResult = WFSKRN_RESULT_OK; + WFSPathName path; + WFSKrnExit2OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + PathCacheItr pci; + pci.di.tba.pTransInfo = TransBegin(); + WFSKrnExit1OnError(PathCacheFindPath(pAbsPathName, path.sStr, &pci)); + WFSKrnExit1OnError((WFSKrnResult)WFSKrnGetAccessList(pci.di.tba.pAreaInfo, pci.di.pAttrHdr->nAccessListIdx, pAccessList, nMaxElements)); +Exit1: + DirItrClose(&pci.di); + TransEnd(pci.di.tba.pTransInfo); +Exit2: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput4("GetAccessList(\"%s\", pal=%x, me=%x) ", pAbsPathName->sStr, pAccessList, nMaxElements); + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString(nResult)); + ); +#endif + return (s32)nResult; +#else + osTPrintf("WFSSrvGetAccessList()\n"); + return WFS_RESULT_NOT_IMPLEMENTED; // dummy +#endif +} + +WFSResult WFSSrvSetAccessListEntry(const WFSPathName *pAbsPathName, u32 nFlags, u32 nMask, WFSTitleId titleId) +{ +#ifdef PERMISSION_ENABLED + WFSKrnResult nResult = WFSKRN_RESULT_OK; + WFSPathName path; + WFSKrnExit2OnError(WFSKrnValidateCopyStrAndConvertToLowerCase(path.sStr, pAbsPathName->sStr, pAbsPathName->nLen, WFS_MAX_PATH_NAME_SIZE)); + PathCacheItr pci; + pci.di.tba.pTransInfo = TransBegin(); + WFSKrnExit1OnError(PathCacheFindPath(pAbsPathName, path.sStr, &pci)); + if (!pci.di.tba.pAreaInfo) + { + // no one can set permission to the entry which has no area info. + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit1; + } + WFSKrnExit1OnError(DirGetBlk(&pci.di, TRANS_FLAG_RW_BLK, 0)); + if((pci.di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) == 0) + { + nMask = nMask & (WFS_PERM_CL_MASK | WFS_PERM_FILE_FULL); + } + else + { + nMask = nMask & (WFS_PERM_CL_MASK | WFS_PERM_DIR_FULL); + } + WFSKrnExit1OnError(WFSKrnSetAccessList(pci.di.tba.pAreaInfo, &(pci.di.pAttrHdr->nAccessListIdx), nFlags, nMask, pci.di.tba.pTransInfo->nTitleId, titleId)); + if (*pci.rxi.pStrPtr==0) { // The pEntry refers to the object (rather than the parent dir) + // Update acl index data in path cache tree + pci.pEntry->pcd.nAccessListIdx = pci.di.pAttrHdr->nAccessListIdx; + } +Exit1: + DirItrClose(&pci.di); + TransEnd(pci.di.tba.pTransInfo); +Exit2: +#if _DEBUG + ++nDbgCommandCount; + WFSKrnDbgOutputTest( + WFSKrnDbgOutputCmdNum; + WFSKrnDbgOutput5("SetAccessListEntry(\"%s\", f=%x, m=%x, t=%x) ", pAbsPathName->sStr, nFlags, nMask, titleId); + WFSKrnDbgOutput2("WFS_RESULT_%s\n", WFSKrnGetErrorString(nResult)); + ); +#endif + return (WFSResult)nResult; +#else + osTPrintf("WFSSrvSetAccessList()\n"); + return WFS_RESULT_NOT_IMPLEMENTED; // dummy +#endif +} + +#ifdef _DEBUG +#if (defined(ACL_TEST) || defined(FBA_TEST)) +void* WFSSrvDebugGetRootAreaInfo(void) +{ + return &wkg.aDevInfo[0].pVolInfo->rootAreaInfo; +} +#endif +#endif // _DEBUG + diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Area.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Area.cpp new file mode 100644 index 0000000..dd58c2e --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Area.cpp @@ -0,0 +1,1276 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Area.cpp - Module for managing contiguous disk areas + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Area.cpp,v $ + Revision 1.27 2008/12/18 09:03:10 kondo_masahiro + Fixed function name and process from BCacheSetBlkAdr() to BCacheRemap() + + Revision 1.26 2008/12/17 01:37:27 kondo_masahiro + Added function BCacheSetBlkAdr() + + Revision 1.25 2008/11/26 01:43:38 kondo_masahiro + Fixed arguments of several functions in order to improve access speed. + + Revision 1.24 2008/10/31 09:51:11 ueno + Modified WFSSrvAPIs to return WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED when path cache is short of memory. + + Revision 1.23 2008/10/17 08:50:48 kondo_masahiro + Added the new MEDIUM size category (40KB-320KB) + + Revision 1.22 2008/10/14 10:27:14 kondo_masahiro + Added #define _DEBUG_BREAK_POINT + + Revision 1.21 2008/10/10 02:11:19 kondo_masahiro + Fixed a bug to access large files + + Revision 1.20 2008/10/09 04:16:53 kondo_masahiro + Fixed member of AreaHdr and AreaInfo + + Revision 1.19 2008/10/08 23:19:54 kondo_masahiro + Added codes to access large size file data + + Revision 1.18 2008/10/03 08:37:56 kondo_masahiro + Fixed codes for porting IOP + + Revision 1.17 2008/09/29 01:58:57 ueno + Modified to call BCacheInvalidateBlks() in FreeBlkFree() to invalidate caches of user data. + + Revision 1.16 2008/09/28 23:31:16 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.15 2008/09/24 07:33:21 ueno + Added AclHdr{} to AreaHdr{} to save configuration of accesslists in a disk. + + Revision 1.14 2008/08/27 23:23:28 ooizumi + Fixed newline to CR+LF(Windows format). + + Revision 1.13 2008/08/27 09:41:24 paul + Added stride to alloc, free functions + + Revision 1.12 2008/08/16 04:35:31 ueno + Fixed hardcoding. + + Revision 1.11 2008/08/15 03:36:20 ueno + Fixed stride. + + Revision 1.10 2008/08/14 08:11:40 kondo_masahiro + Removed struct AreaHashHdr. + + Revision 1.9 2008/08/09 03:17:51 ueno + Modified AreaFreeBlks() to call FreeBlkFree() if BTREE_BASED_ALLOCATOR == 1. + + Revision 1.8 2008/08/08 13:31:34 ueno + Added comment. + + Revision 1.7 2008/08/07 10:46:33 ueno + Modified for BTREE_BASED_ALLOCATOR (now debugging). + + Revision 1.6 2008/08/05 04:07:51 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.5 2008/07/23 04:14:52 ueno + Modified to initialize accesslist in AreaOpen(). + + Revision 1.4 2008/07/17 05:31:06 kondo_masahiro + Added codes for debug. + + Revision 1.3 2008/07/08 23:48:25 paul + Many Changes - made the block cache and associated allocator work on blocks instead of sectors. Removed handle-to-pointer mapping code - now using pointers to static structs instead of device or volume handles. Fixed some bugs in the list-based allocator. + + Revision 1.2 2008/05/12 19:05:44 paul + Merged in Wayne's previous changes + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.12 2008/04/28 20:20:26 wayne.wong + Changed the interface to block alloc slightly to return WFSKrnResult. + + Revision 1.11 2008/04/26 05:53:49 wayne.wong + Small fix. Function name. + + Revision 1.10 2008/04/26 01:24:41 wayne.wong + Moved area functionality from Volume to Area module. Changed implementation + to support small area sizes for a large mapped number of sectors. Added + block wrapper calls for Area and BCache calls. + + Revision 1.9 2008/04/18 01:58:44 wayne.wong + Created separate Area types for persistent (hdr) and non-persistent (info) types. + Changed function names to be consistent with kernel naming convention. + Defines are included to support the previous naming, but will be deleted in + the future. + + Revision 1.7 2008/04/03 23:39:00 kondo_masahiro + change spec of debug proc + + Revision 1.6 2008/02/28 07:01:41 kondo_masahiro + Fixed code to accept PPC compiler + + Revision 1.4 2008/02/27 00:27:17 paul + increased block cache size to run bigger tests + + Revision 1.3 2008/02/20 08:09:25 paul + Added some more temporary code for block alloc/free in order to proceed with wfskrn_Dir. + + Revision 1.2 2007/12/27 11:00:05 paul + Added various functions - still only a preliminary API to allow me to progress with + directory implementation + + Revision 1.1 2007/11/16 05:45:15 paul + first checkin + *---------------------------------------------------------------------------*/ + +#include "wfskrn_Api.h" +#include "wfskrn_Area.h" +#include "wfskrn_Bcache.h" +#include "wfskrn_Volume.h" +#include "wfskrn_Permission_AccessList.h" + +#if BTREE_BASED_ALLOCATOR +#include "wfskrn_FreeBlkAlloc.h" +#endif // BTREE_BASED_ALLOCATOR + +#if SIMPLE_ALLOCATOR +void *AreaGetPhysicalBlk(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr) { + return &pAreaInfo->ah.pPtr[(nBlkAdr-1) * pAreaInfo->nBlkSize]; +} +#endif + + +WFSKrnResult AreaPinFreeListHdr(AreaInfo *pAreaInfo, u32 nFlags, AreaFreeListHdr **ppAflh) { + WFSBlkAdr nAbsStartBlkAdr = pAreaInfo->nAbsStartBlkAdr; + BCacheEntry *pBce; + WFSKrnResult nResult = BCacheAllocMetaBlk(pAreaInfo->pVolInfo, nAbsStartBlkAdr, BCACHE_FLAG_PINNED | nFlags, &pBce); + if (nResult == WFSKRN_RESULT_OK) { + u8* pBlkPtr = pBce->pBlkPtr; + if (nAbsStartBlkAdr == 0) { + pBlkPtr += sizeof(VolumeHdr); + } + *ppAflh = (AreaFreeListHdr *)(pBlkPtr + sizeof(AreaHdr)); + } + else{ + *ppAflh = NULL; + } + return nResult; +} + +void AreaUnpinFreeListHdr(AreaInfo *pAreaInfo) { + BCacheUnpin(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr); +} + + +WFSKrnResult AreaAllocBlks(AreaInfo *pAreaInfo, WFSBlkAdr nRefBlkAdr, u32 nLog2BlkSize, u32 nNumBlks, WFSBlkAdr *pBlkAdr, s32 nStride) { + // This function allocates the requested number of physical blocks or fails. + // nRefBlkAdr (IN) A reference block which we wish to allocate close to. + // nNumBlks (IN) Number of blocks to allocate. + // aBlkAdr (OUT) Array to pass back the index of allocated blocks. + + // In the final version, this function should try to allocate sequentially, close to + // the specified reference block address. (These two goals may be conflicting, so a + // heuristic approach is needed). + // The list of allocated block addresses should be written to the specified array. + + // The current version + // Re-mapping is not implemented in this function, it should be a separate function. + // ToDo: For now, assumes small blocks. May need to add a flag to specify large/small blocks. + //WFSBlkAdr nrba = nRefBlkAdr; // for warning + +#if _DEBUG_BREAK_POINT + if(nRefBlkAdr == 463){ + int a; a=0; + } +#endif + + dbga(OS_TPrintf("AreaAllocBlks()\n")); + WFSKrnResult nResult = AreaPinFreeListHdr(pAreaInfo, BCACHE_FLAG_READ | BCACHE_FLAG_DIRTY, &pAreaInfo->pAflh); + if(nResult < WFSKRN_RESULT_OK){ + goto Done; + } +/* + if(pAreaInfo->pVolInfo->pDevInfo->nFlags & WFS_DEVFLAG_UNUSABLE){ // device detached + nResult = WFSKRN_RESULT_MEDIA_ERROR; + goto Done; + } + else if(pAreaInfo->pVolInfo->pDevInfo->nFlags & WFS_DEVFLAG_NOT_INITIALIZED){ // hash error + nResult = WFSKRN_RESULT_CORRUPTION; + goto Done; + } + */ +#if BTREE_BASED_ALLOCATOR + + nResult = FreeBlkAlloc(pAreaInfo, nRefBlkAdr, nNumBlks, pBlkAdr, nStride, nLog2BlkSize); // [check] hard-coding. + + +#elif LIST_BASED_ALLOCATOR + u32 nI; + for(nI=0; nIaBlkAllocState[*pBlkAdr>>5]>>(*pBlkAdr&31))&1; + if (nAllocState == 1) { + WFSKrnOutputErrorStr("Block already allocated!"); + } + pAreaInfo->aBlkAllocState[*pBlkAdr>>5] |= (1<<(*pBlkAdr&31)); + #endif //_CHECK_BLK_ALLOCATION + pBlkAdr = (WFSBlkAdr *)((u8*)pBlkAdr + nStride); + } +#else //SIMPLE_ALLOCATOR + if (pAreaInfo->ah.nNumFreeBlks < nNumBlks) { + return WFSKRN_RESULT_DIRECTORY_QUOTA; + } + pAreaInfo->ah.nNumFreeBlks -= nNumBlks; + u32 nI; + for(nI=0; nIah.nFirstFreeBlkAdr; + WFSBlkAdr *pNextFreeBlock = (WFSBlkAdr *)AreaGetPhysicalBlk(pAreaInfo, *pBlkAdr); + pAreaInfo->ah.nFirstFreeBlkAdr = *pNextFreeBlock; + pBlkAdr = (WFSBlkAdr *)((u8*)pBlkAdr + nStride); + } +#endif //BTREE_BASED_ALLOCATOR/LIST_BASED_ALLOCATOR/SIMPLE_ALLOCATOR +Done: + AreaUnpinFreeListHdr(pAreaInfo); + return nResult; +} + +WFSKrnResult AreaFreeBlks(AreaInfo *pAreaInfo, u32 nLog2BlkSize, u32 nNumBlks, WFSBlkAdr *pBlkAdr, s32 nStride) { + // This function frees the physical blocks passed in. + dbga(OS_TPrintf("AreaFreeBlks()\n")); + WFSKrnResult nResult = AreaPinFreeListHdr(pAreaInfo, BCACHE_FLAG_READ | BCACHE_FLAG_DIRTY, &pAreaInfo->pAflh); + if(nResult < WFSKRN_RESULT_OK){ + goto Done; + } + /* + if(pAreaInfo->pVolInfo->pDevInfo->nFlags & WFS_DEVFLAG_UNUSABLE){ // device detached + nResult = WFSKRN_RESULT_MEDIA_ERROR; + goto Done; + } + else if(pAreaInfo->pVolInfo->pDevInfo->nFlags & WFS_DEVFLAG_NOT_INITIALIZED){ // hash error + nResult = WFSKRN_RESULT_CORRUPTION; + goto Done; + } + */ +#if BTREE_BASED_ALLOCATOR + nResult = FreeBlkFree(pAreaInfo, nNumBlks, pBlkAdr, nStride, nLog2BlkSize); +#elif LIST_BASED_ALLOCATOR + AreaInfo subAreaInfo; + subAreaInfo.pVolInfo = pAreaInfo->pVolInfo; + u32 nI; + for (nI=0; nIaBlkAllocState[*pBlkAdr>>5]>>(*pBlkAdr&31))&1; + if (nAllocState == 0) { + WFSKrnOutputErrorStr("Block already free!"); + } + pAreaInfo->aBlkAllocState[*pBlkAdr>>5] &= ~(1<<(*pBlkAdr&31)); + #endif //_CHECK_BLK_ALLOCATION + subAreaInfo.nRelStartBlkAdr = *pBlkAdr; // * pAreaInfo->pAflh->aFreeList[0].nAreaSize; + nResult = AreaFreeSubArea(pAreaInfo, &subAreaInfo); + #if _DEBUG + if (nResult != WFSKRN_RESULT_OK) { + return nResult; + //WFSKrnOutputErrorCode(nResult); + } + #endif + pBlkAdr = (WFSBlkAdr *)((u8*)pBlkAdr + nStride); + } +#else //SIMPLE_ALLOCATOR + pAreaInfo->ah.nNumFreeBlks += nNumBlks; + u32 nI; + for(nI=0; nIah.nFirstFreeBlkAdr; + pAreaInfo->ah.nFirstFreeBlkAdr = *pBlkAdr; + pBlkAdr = (WFSBlkAdr *)((u8*)pBlkAdr + nStride); + } +#endif //BTREE_BASED_ALLOCATOR/LIST_BASED_ALLOCATOR/SIMPLE_ALLOCATOR +Done:; + AreaUnpinFreeListHdr(pAreaInfo); + return nResult; +} + + +WFSKrnResult AreaInvalidateBlks(AreaInfo *pAreaInfo, u32 nNumBlks, WFSBlkAdr *pBlkAdr, s32 nStride) +{ + WFSKrnResult nResult = WFSKRN_RESULT_UNKNOWN; + int nI; + for(nI=0;nInNumEntriesInFirstBlk) { + nBlkAdr = 0; + *pOfs = sizeof(AreaHdr) + sizeof(AreaFreeListHdr) + (nAreaEntryIdx * sizeof(AreaEntry)); + if (pAreaInfo->nAbsStartBlkAdr == VOLUME_HDR_BLK_ADR) { + *pOfs += sizeof(VolumeHdr); + } + } else { + nAreaEntryIdx -= pAreaInfo->nNumEntriesInFirstBlk; + nBlkAdr = (nAreaEntryIdx / pAreaInfo->nNumEntriesPerBlk) + 1; + *pOfs = ((nAreaEntryIdx % pAreaInfo->nNumEntriesPerBlk) * sizeof(AreaEntry)) + sizeof(WFSMetaDataHdr); + //nBlkAdr = (nAreaEntryIdx / pAreaInfo->nNumEntriesPerBlk) + 1; + //*pOfs = (nAreaEntryIdx % pAreaInfo->nNumEntriesPerBlk) * sizeof(AreaEntry); + } + return nBlkAdr; + } + + + // Loads the specified entry into memory, and returns a pointer to it. + // Otherise NULL is returned to indicate an error. Assumes the device+volume is + // already mapped. No checks here if nAreaEntryIdx is within bounds. + // Also assumes that we don't need to pin the page (i.e., no one else is going + // to access the BCache before the caller is done. + static + WFSKrnResult _AreaEntryMap(AreaInfo *pAreaInfo, AreaEntryIdx nAreaEntryIdx, u32 nFlags, AreaEntry** ppAe) { + dbga(OS_TPrintf("_AreaEntryMap()\n")); + static int c=0; ++c; +#if _DEBUG_BREAK_POINT + if(c>=43) { + int a;a=0; + } +#endif + u32 nOfs; + u32 nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + AreaEntryBlkAdr(pAreaInfo, nAreaEntryIdx, &nOfs); + //u32 nFlags = (bModify?BCACHE_FLAG_DIRTY:0) | BCACHE_FLAG_READ; // no pin; assumes no interruptions to caller + if (!nAbsBlkAdr){ + nFlags &= ~BCACHE_FLAG_PINNED; + } + BCacheEntry *pBce; + //u8 *pBlkPtr; + WFSKrnResult nResult = BCacheAllocMetaData(pAreaInfo->pVolInfo, nAbsBlkAdr, nFlags, &pBce); + + #if _DEBUG + if (!pBce->pBlkPtr || nResult < WFSKRN_RESULT_OK) { + *ppAe = NULL; + return nResult; + } + if (nOfs > (pAreaInfo->nBlkSize - sizeof(AreaEntry))) { + *ppAe = NULL; + return WFSKRN_RESULT_AREA_BCACHE_ALLOC; + } + #endif + //pBlkPtr += nOfs; + //return (AreaEntry*)pBlkPtr; + *ppAe = (AreaEntry*)(pBce->pBlkPtr + nOfs); + return WFSKRN_RESULT_OK; + } + + + static + WFSKrnResult _AreaEntryUnpin(AreaInfo *pAreaInfo, AreaEntryIdx nAreaEntryIdx){ + dbga(OS_TPrintf("_AreaEntryUnmap()\n")); + u32 nOfs; + u32 nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + AreaEntryBlkAdr(pAreaInfo, nAreaEntryIdx, &nOfs); + if (!nAbsBlkAdr){ + return WFSKRN_RESULT_OK; + } + return BCacheUnpin(pAreaInfo->pVolInfo, nAbsBlkAdr); + } + + + static + u32 AreaEntryGetPinCount(AreaInfo *pAreaInfo, AreaEntryIdx nAreaEntryIdx){ + dbga(OS_TPrintf("_AreaEntryGetPinCount()\n")); + u32 nOfs; + u32 nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + AreaEntryBlkAdr(pAreaInfo, nAreaEntryIdx, &nOfs); + return BCacheGetPinCount(pAreaInfo->pVolInfo, nAbsBlkAdr); + } + + + static + u32 _AreaGetAbsBlkAdr(AreaInfo *pAreaInfo, AreaEntryIdx nAreaEntryIdx) { + dbga(OS_TPrintf("_AreaGetAbsBlkAdr()\n")); + u32 nOfs; + return pAreaInfo->nAbsStartBlkAdr + AreaEntryBlkAdr(pAreaInfo, nAreaEntryIdx, &nOfs); + } + + + // Add to the head of the free list. Assumes area header should be already be in-core memory. + // Its page should be marked dirty if a successful add. No checks on if the entry is already + // in another (or this) list. + static + WFSKrnResult _AreaListAdd(AreaInfo *pAreaInfo, u32 nFreeListIdx, AreaEntryIdx nAreaEntryIdx) { + dbga(OS_TPrintf("_AreaListAdd()\n")); + AreaEntry *pEntry; + WFSKrnResult nResult = _AreaEntryMap(pAreaInfo, nAreaEntryIdx, BCACHE_FLAG_READ | BCACHE_FLAG_DIRTY | BCACHE_FLAG_PINNED, &pEntry); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + AreaList *pList = &(pAreaInfo->pAflh->aFreeList[nFreeListIdx]); + if (pList->nLen > 0) { // link to rest of list? + AreaEntry *pNextEntry; + nResult = _AreaEntryMap(pAreaInfo, pList->nHeadIdx, BCACHE_FLAG_READ | BCACHE_FLAG_DIRTY, &pNextEntry); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + pNextEntry->nPrevIdx = nAreaEntryIdx; + pEntry->nNextIdx = pList->nHeadIdx; + } else { // else, just attach as head + pEntry->nNextIdx = AREA_NULL; + } + pEntry->nPrevIdx = AREA_NULL; + pList->nHeadIdx = nAreaEntryIdx; + ++pList->nLen; + nResult = _AreaEntryUnpin(pAreaInfo, nAreaEntryIdx); + return WFSKRN_RESULT_OK; + } + + + // Delete entry from the free list. Assumes volume's MR should be already be in-core memory. + // Its page should be marked dirty if a successful delete. + static + WFSKrnResult _AreaListDelete(AreaInfo *pAreaInfo, u32 nFreeListIdx, AreaEntryIdx nAreaEntryIdx) { + dbga(OS_TPrintf("_AreaListDelete()\n")); +#if _DEBUG_BREAK_POINT + static int c=0; ++c; if (c>=3) { + int a;a=0; + } +#endif + AreaEntry *pEntry; + WFSKrnResult nResult = _AreaEntryMap(pAreaInfo, nAreaEntryIdx, BCACHE_FLAG_READ | BCACHE_FLAG_DIRTY | BCACHE_FLAG_PINNED, &pEntry); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + if (pEntry->nSizeIdx != nFreeListIdx) { + return WFSKRN_RESULT_AREA_CORRUPT_HDR; + } + + AreaList *pList = &(pAreaInfo->pAflh->aFreeList[nFreeListIdx]); + if (pList->nHeadIdx == nAreaEntryIdx) { + pList->nHeadIdx = pEntry->nNextIdx; + } + if (pEntry->nNextIdx != AREA_NULL) { + AreaEntry *pNextEntry; + nResult = _AreaEntryMap(pAreaInfo, pEntry->nNextIdx, BCACHE_FLAG_READ | BCACHE_FLAG_DIRTY, &pNextEntry); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + pNextEntry->nPrevIdx = pEntry->nPrevIdx; + } + if (pEntry->nPrevIdx != AREA_NULL) { + AreaEntry *pPrevEntry; + nResult = _AreaEntryMap(pAreaInfo, pEntry->nPrevIdx, BCACHE_FLAG_READ | BCACHE_FLAG_DIRTY, &pPrevEntry); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + pPrevEntry->nNextIdx = pEntry->nNextIdx; + } + pEntry->nPrevIdx = AREA_NULL; + pEntry->nNextIdx = AREA_NULL; + --pList->nLen; + nResult = _AreaEntryUnpin(pAreaInfo, nAreaEntryIdx); + return nResult; + } + + + static + void _AreaListPrint(AreaInfo *pAreaInfo, AreaEntryIdx start) { + dbga(OS_TPrintf("_AreaListPrint()\n")); + AreaEntryIdx index = start; + while (AREA_NULL != index) { + AreaEntry *pEntry; + WFSKrnResult nResult = _AreaEntryMap(pAreaInfo, index, BCACHE_FLAG_READ, &pEntry); + if (pEntry && nResult >= WFSKRN_RESULT_OK) { + OS_TPrintf("\t%d: attr=0x%02x, next=%d, prev=%d\n", index, pEntry->nAttributes, pEntry->nNextIdx, pEntry->nPrevIdx); + index = pEntry->nNextIdx; + } else { + OS_TPrintf("ERROR: cannot allocate page (%d)\n", nResult); + break; + } + } + } + + + // Check that freelists are consistent. Print out the free list. + static + WFSKrnResult _AreaFreelistCheck(AreaInfo *pAreaInfo) { + dbga(OS_TPrintf("_AreaFreelistCheck()\n")); +#if _DEBUG_BREAK_POINT + static int c=0; ++c; if (c>=3) { + int a;a=0; + } +#endif + //u8 *pMem = (u8*)BCacheAlloc(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr, BCACHE_FLAG_READ); //true, false, false); + // OS_TPrintf("\nvolume 0x%8x\n", pVolInfo); + u32 nSizeIdx; + for (nSizeIdx=0; nSizeIdxpAflh->aFreeList[nSizeIdx]; + // OS_TPrintf("list %2d, length=%d, head=%d\n", nSizeIdx, pList->nLen, pList->nHeadIdx); + if (pList->nLen > 0) { + u32 nNumEntries = 0; + AreaEntryIdx nEntryIdx = pList->nHeadIdx; + while (AREA_NULL != nEntryIdx) { + nNumEntries++; + AreaEntry *pEntry; + WFSKrnReturnOnError(_AreaEntryMap(pAreaInfo, nEntryIdx, BCACHE_FLAG_READ, &pEntry)); + if (pEntry) { + nEntryIdx = pEntry->nNextIdx; + if (pEntry->nAttributes & AREA_ALLOCATED) { + WFSKrnOutputErrorStr("non-free block on free list"); + return WFSKRN_RESULT_AREA_CORRUPT_HDR; + } + } else { + break; + } + } + if (nNumEntries != pList->nLen) { + OS_TPrintf("ERROR: incorrect length. %d != %d\n", nNumEntries, pList->nLen); + _AreaListPrint(pAreaInfo, pList->nHeadIdx); + WFSKrnOutputErrorCode(WFSKRN_RESULT_AREA_CORRUPT_HDR); + return WFSKRN_RESULT_AREA_CORRUPT_HDR; + } + } else if (pList->nHeadIdx != AREA_NULL) { + OS_TPrintf("ERROR: incorrect head. head=%d, len=%d\n", pList->nHeadIdx, pList->nLen); + _AreaListPrint(pAreaInfo, pList->nHeadIdx); + WFSKrnOutputErrorCode(WFSKRN_RESULT_AREA_CORRUPT_HDR); + return WFSKRN_RESULT_AREA_CORRUPT_HDR; + } + } + return WFSKRN_RESULT_OK; + } + + + WFSKrnResult AreaFreelistPrint(AreaInfo *pAreaInfo) { + return _AreaFreelistCheck(pAreaInfo); + } + + + // Allocate an sub-area. Assumes nSizeIdx < gnNumAreaSizes. Check above here? + static + WFSKrnResult _AreaAllocate(AreaInfo *pAreaInfo, u32 nSizeIdx, AreaEntryIdx *pEntryIndex, u32 nFlags) { + dbga(OS_TPrintf("_AreaAllocate()\n")); +#if _DEBUG_BREAK_POINT + static int c=0;++c;if(c>=6){ + int a;a=0; + } +#endif + AreaEntryIdx freeIndex; // entry of free area to return + WFSKrnResult nResult; + if (pAreaInfo->pAflh->aFreeList[nSizeIdx].nLen > 0) { // area available? + freeIndex = pAreaInfo->pAflh->aFreeList[nSizeIdx].nHeadIdx; + nResult = _AreaListDelete(pAreaInfo, nSizeIdx, freeIndex); + if (WFSKRN_RESULT_OK != nResult) { + return nResult; + } + } else { // else, try to split a large free sub-area + if (nSizeIdx < (gnNumAreaSizes-1)) {// try to allocate from larger free list? + nResult = _AreaAllocate(pAreaInfo, nSizeIdx+1, &freeIndex, nFlags); + if (WFSKRN_RESULT_OK == nResult) { // split larger area into n smaller ones + *pEntryIndex = freeIndex; // first child is returned + AreaList *pList = &pAreaInfo->pAflh->aFreeList[nSizeIdx]; + u32 nNumSiblings = pAreaInfo->pAflh->aFreeList[nSizeIdx+1].nAreaSize/pList->nAreaSize; + u32 nStride = pList->nAreaSize/pAreaInfo->pAflh->aFreeList[0].nAreaSize; + AreaEntryIdx nSiblingIdx; + u32 nS; + for (nS=1, nSiblingIdx=*pEntryIndex+nStride; nSnSizeIdx = nSizeIdx; + pAreaEntry->nAttributes = AREA_START; + _AreaListAdd(pAreaInfo, nSizeIdx, nSiblingIdx); + } + } else { + return nResult; + } + } else { + return WFSKRN_RESULT_DIRECTORY_QUOTA; + //return WFSKRN_RESULT_AREA_ALLOC; + } + } + + // Wayne - calling routine will initialize the area's header? + *pEntryIndex = freeIndex; + AreaEntry *pAreaEntry; + nResult = _AreaEntryMap(pAreaInfo, freeIndex, BCACHE_FLAG_READ | BCACHE_FLAG_DIRTY, &pAreaEntry); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + + pAreaEntry->nSizeIdx = nSizeIdx; + pAreaEntry->nAttributes = (0==freeIndex) ? AREA_OVERHEAD : AREA_EMPTY; + pAreaEntry->nAttributes |= AREA_ALLOCATED | AREA_START; + pAreaEntry->nNextIdx = AREA_NULL; + pAreaEntry->nPrevIdx = AREA_NULL; + return WFSKRN_RESULT_OK; + } + + + // Recursive core routine to free a volume area. Coalesce into a larger area if + // possible. The larger area Assumes that *pAreaEntry is not currently on any free list. + // + // Assumes this call is not interrupted by another user of the BCache (i.e., no need to + // pin pages). + static + WFSKrnResult _AreaFree(AreaInfo *pAreaInfo, s16 nSizeIdx, AreaEntryIdx nEntryIdx) { + dbga(OS_TPrintf("_AreaFree()\n")); +#if _DEBUG_BREAK_POINT + static int c=0;++c;if (c>=6){ + int a;a=0; + } +#endif + // try to coalesce aggressively + AreaList *pList = &pAreaInfo->pAflh->aFreeList[nSizeIdx]; + + // Wayne - can we move pDevInfo and pAreaEntry above to eliminate multiple calls? + AreaEntry *pAreaEntry; + WFSKrnResult nResult = _AreaEntryMap(pAreaInfo, nEntryIdx, BCACHE_FLAG_READ | BCACHE_FLAG_DIRTY, &pAreaEntry); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + // Wayne - need to pin pAreaEntry? + + if ((nSizeIdx < (gnNumAreaSizes-1)) && // larger area freelist exists? + (pList->nAreaSize < (pAreaInfo->ah.nNumBlks>>1))) { // larger area possible? + u32 nLargerSize = pAreaInfo->pAflh->aFreeList[nSizeIdx+1].nAreaSize; + u32 nStride = pList->nAreaSize / pAreaInfo->pAflh->aFreeList[0].nAreaSize; + u32 nNumSiblings = nLargerSize / pList->nAreaSize; + AreaEntryIdx nFirstSiblingIdx = nEntryIdx - (nEntryIdx % (nLargerSize/pAreaInfo->pAflh->aFreeList[0].nAreaSize)); + AreaEntryIdx nSiblingIdx; + u32 nS; + for (nS=0, nSiblingIdx=nFirstSiblingIdx; nS= pAreaInfo->ah.nMaxNumAreas) break; + if (nSiblingIdx != nEntryIdx) { + AreaEntry *pSiblingEntry; + nResult = _AreaEntryMap(pAreaInfo, nSiblingIdx, BCACHE_FLAG_READ, &pSiblingEntry); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + if ((pSiblingEntry->nAttributes & AREA_START) && // start of an area + (pSiblingEntry->nSizeIdx == nSizeIdx)) { // and same size + if (pSiblingEntry->nAttributes & AREA_ALLOCATED) break; + } else { + break; + } + } + nSiblingIdx += nStride; + } + + if (nS==nNumSiblings) { // all siblings are free? + for (nS=0, nSiblingIdx=nFirstSiblingIdx; nSnAttributes &= ~AREA_ALLOCATED; + } else { + pSiblingEntry->nAttributes = AREA_EMPTY; + } + // Wayne - anything with AREA_FIRST? or only on allocations? + } + return _AreaFree(pAreaInfo, nSizeIdx+1, nFirstSiblingIdx); + //nResult = _AreaFree(pAreaInfo, nSizeIdx+1, nFirstSiblingIdx); + //if (WFSKRN_RESULT_OK != nResult) return nResult; + } + } + + // not able to coalesce + nResult = _AreaListAdd(pAreaInfo, nSizeIdx, nEntryIdx); + pAreaEntry->nAttributes &= ~AREA_ALLOCATED; + pAreaEntry->nSizeIdx = nSizeIdx; + return nResult; + } + + + // Allocate an area large enough to fit the desired request. Actual number of free + // sectors in the area may be less due to overhead (e.g., first area on disk has + // the volume header and entry table. The area's header should tell the actual + // usable starting nSector and the ending nSector. + // + // Actually, current hack is to allocate an initial area covering the overhead. + // Thus, all subsequent request should be no overhead. + WFSKrnResult AreaAllocSubArea(AreaInfo *pAreaInfo, WFSBlkAdr nNumBlks, AreaInfo *pSubAreaInfo, u32 nFlags) { + dbga(OS_TPrintf("AreaAllocSubArea()\n")); +#if _DEBUG_BREAK_POINT + static int c=0;++c; if(c>=3){ + int a;a=0; + } +#endif + VolumeInfo *pVolInfo = pAreaInfo->pVolInfo; + //DeviceInfo *pDevInfo = pVolInfo->pDevInfo; + //u8 *pMem = (u8*)BCacheAlloc(pVolInfo, pAreaInfo->nAbsStartBlkAdr, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); //true, true, false); + //AreaInfo *pAreaInfo = (pAreaInfo->nAbsStartBlkAdr==VOLUME_HDR_BLK_ADR) ? (AreaHdr*)(pMem + sizeof(VolumeHdr)) : (AreaHdr*)pMem; + WFSKrnResult nResult = WFSKRN_RESULT_OK; + u32 nSizeIdx = 0; + while ((nSizeIdx < gnNumAreaSizes) && // find matching area size + (nNumBlks > pAreaInfo->pAflh->aFreeList[nSizeIdx].nAreaSize)) { + ++nSizeIdx; + } + if (nSizeIdx < gnNumAreaSizes) { + AreaEntryIdx nEntryIdx; + nResult = _AreaAllocate(pAreaInfo, nSizeIdx, &nEntryIdx, nFlags); + u32 nNumBlksAllocated = pAreaInfo->pAflh->aFreeList[nSizeIdx].nAreaSize; + if (WFSKRN_RESULT_OK == nResult) { + pSubAreaInfo->pParent = pAreaInfo; + pSubAreaInfo->pVolInfo = pVolInfo; + pSubAreaInfo->nRelStartBlkAdr = (WFSBlkAdr)nEntryIdx;// * pAreaInfo->pAflh->aFreeList[0].nAreaSize; + pSubAreaInfo->ah.nNumBlks = nNumBlks; + //pSubAreaInfo->nNumSectorsPerSmallBlk = pAreaInfo->pAflh->aFreeList[0].nAreaSize; + } + // Free up any unused portion of the area just allocated + while(nSizeIdx > 0) { + --nSizeIdx; + while((nNumBlksAllocated - nNumBlks) >= pAreaInfo->pAflh->aFreeList[nSizeIdx].nAreaSize) { + nNumBlksAllocated -= pAreaInfo->pAflh->aFreeList[nSizeIdx].nAreaSize; + _AreaFree(pAreaInfo, nSizeIdx, nEntryIdx + nNumBlksAllocated); + } + } + } else { + nResult = WFSKRN_RESULT_AREA_INVALID_PARAMETER; // no area large enough + } + if (WFSKRN_RESULT_OK == nResult) { + BCacheDirty(pVolInfo, pAreaInfo->nAbsStartBlkAdr); + //nResult = BCacheUnpin(pVolInfo, pAreaInfo->nAbsStartBlkAdr); + } else { + //BCacheUnpin(pVolInfo, pAreaInfo->nAbsStartBlkAdr); + } + WFSKrnReturnOnError(_AreaFreelistCheck(pAreaInfo)); + return nResult; + } + + + WFSKrnResult AreaFreeSubArea(AreaInfo *pAreaInfo, AreaInfo *pSubAreaInfo) { + dbga(OS_TPrintf("AreaFreeSubArea()\n")); +#if _DEBUG_BREAK_POINT + static int c=0; ++c; if (c>=831) { + int a;a=0; + } +#endif + WFSKrnReturnOnError(_AreaFreelistCheck(pAreaInfo)); + //VolumeInfo *pVolInfo = pAreaInfo->pVolInfo; + //DeviceInfo *pDevInfo = pVolInfo->pDevInfo; + //u8 *pMem = (u8*)BCacheAlloc(pVolInfo, pAreaInfo->nAbsStartBlkAdr, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED | BCACHE_FLAG_DIRTY); //true, true, true); + //if (!pMem) return WFSKRN_RESULT_AREA_BCACHE_ALLOC; + //AreaInfo *pAreaInfo = (pAreaInfo->pParent==NULL) ? (AreaHdr*)(pMem + sizeof(VolumeHdr)) : (AreaHdr*)pMem; + AreaEntryIdx nEntryIdx = pSubAreaInfo->nRelStartBlkAdr / pAreaInfo->pAflh->aFreeList[0].nAreaSize; + AreaEntry *pAreaEntry; + WFSKrnResult nResult = _AreaEntryMap(pAreaInfo, nEntryIdx, BCACHE_FLAG_READ | BCACHE_FLAG_DIRTY, &pAreaEntry); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + //WFSKrnReturnOnError(_AreaFreelistCheck(pAreaInfo)); + nResult = _AreaFree(pAreaInfo, pAreaEntry->nSizeIdx, nEntryIdx); + WFSKrnReturnOnError(_AreaFreelistCheck(pAreaInfo)); + //nResult = _AreaEntryUnpin(pAreaInfo, nEntryIdx); + //Done: + //BCacheUnpin(pVolInfo, pAreaInfo->nAbsStartBlkAdr); + return nResult; + } + + +#else //SIMPLE_ALLOCATOR + +#endif //LIST_BASED_ALLOCATOR + + +WFSKrnResult AreaBlkStore(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr) { + dbga(OS_TPrintf("AreaBlkStore()\n")); + return BCacheStore(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr + nBlkAdr); +} + + +WFSKrnResult AreaBlkFlush(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr) { + dbga(OS_TPrintf("AreaBlkFlush()\n")); +#if _CHECK_BLK_USAGE + u8 *pPtr; + AreaBlkGetPtr(pAreaInfo, nBlkAdr, (void **)&pPtr); +#endif + WFSKrnResult nResult = BCacheFlush(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr + nBlkAdr); +#if _CHECK_BLK_USAGE + memset(pPtr, 0xff, AREA_PAGE_SIZE); +#endif + return nResult; +} + + +WFSKrnResult AreaBlkInvalidate(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr){ + dbga(OS_TPrintf("AreaBlkFlush()\n")); +#if _CHECK_BLK_USAGE + u8 *pPtr; + AreaBlkGetPtr(pAreaInfo, nBlkAdr, (void **)&pPtr); +#endif + dbga(OS_TPrintf("AreaBlkFlush()\n")); + WFSKrnResult nResult = BCacheInvalidate(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr + nBlkAdr); +#if _CHECK_BLK_USAGE + memset(pPtr, 0xff, AREA_PAGE_SIZE); +#endif + return nResult; +} + + +WFSKrnResult AreaBlkDirty(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr) { + dbga(OS_TPrintf("AreaBlkDirty()\n")); + return BCacheDirty(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr + nBlkAdr); +} + + +WFSKrnResult AreaBlkPin(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr) { + dbga(OS_TPrintf("AreaBlkPin()\n")); + return BCachePin(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr + nBlkAdr); +} + + +WFSKrnResult AreaBlkUnpin(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr) { + dbga(OS_TPrintf("AreaBlkUnpin()\n")); + WFSKrnResult nResult = BCacheUnpin(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr + nBlkAdr); +#if _CHECK_BLK_USAGE +// if nPinCount become 0, the cache data is crashed. (for debug) + if(!BCacheGetPinCount(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr + nBlkAdr)){ + AreaBlkFlush(pAreaInfo, nBlkAdr); + } +#endif + return nResult; +} + + +u32 AreaBlkGetPinCount(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr){ + dbga(OS_TPrintf("AreaBlkUnpin()\n")); + return BCacheGetPinCount(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr + nBlkAdr); +} + + +WFSKrnResult AreaBlkGetPtr(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, void** ppPtr){ + dbga(OS_TPrintf("AreaBlkGetPtr()\n")); + u8 *pMem = (u8*)BCachePointer(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr + nBlkAdr ); + if((s32)pMem < WFSKRN_RESULT_OK){ + return WFSKRN_RESULT_AREA_INVALID_PARAMETER; + } + *ppPtr = pMem; + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult AreaBlkSetValidSize(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, u32 nValidSize){ + dbga(OS_TPrintf("AreaBlkSetValidSize()\n")); + return BCacheSetValidSize(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr + nBlkAdr, nValidSize); +} + + +WFSKrnResult AreaBlkRemapCache(AreaInfo *pAreaInfo, WFSBlkAdr nSrcBlkAdr, WFSBlkAdr nDstBlkAdr, WFSBlkAdr nHashBlkAdr, u32 nHashOfs){ + dbga(OS_TPrintf("AreaBlkSetBlkAdr()\n")); + return BCacheRemap(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr + nSrcBlkAdr, pAreaInfo->nAbsStartBlkAdr + nDstBlkAdr, + pAreaInfo->nAbsStartBlkAdr + nHashBlkAdr, nHashOfs); +} + + +WFSKrnResult AreaInitAllocator(AreaInfo *pAreaInfo, u32 nSizeRemaining) { + dbga(OS_TPrintf("AreaInitAllocator()\n")); + // This function initializes the block and sub-area allocation data structures within a new area + // Arguments: + // pAreaInfo [IN/OUT] .. The area whose free block allocator we wish to initilize + // pRootBlkPtr [IN] .. A pointer to the root block of the area in memory (block cache) + WFSKrnResult nResult = WFSKRN_RESULT_OK; +#if BTREE_BASED_ALLOCATOR + + nResult = FreeBlkInit(pAreaInfo, pAreaInfo->nBlkSize - nSizeRemaining); + +#elif LIST_BASED_ALLOCATOR + u32 *aAreaSizes = gaAllocationSizes; + #if _DEBUG + if ((gnNumAreaSizes==0) || (gnNumAreaSizes>WFSKRN_MAX_NUM_AREA_SIZES)) { + return WFSKRN_RESULT_AREA_INVALID_PARAMETER; + } + // Check that larger areas are an integral multiples of the smaller + s32 nSizeIdx; + for (nSizeIdx=1; nSizeIdxnNumEntriesInFirstBlk = nSizeRemaining / sizeof(AreaEntry); + pAreaInfo->nNumEntriesPerBlk = (pAreaInfo->nBlkSize-sizeof(WFSMetaDataHdr)) / sizeof(AreaEntry); + //pAreaInfo->nNumEntriesPerBlk = (pAreaInfo->nBlkSize) / sizeof(AreaEntry); + pAreaInfo->ah.nMaxNumAreas = pAreaInfo->ah.nNumBlks / aAreaSizes[0]; + pAreaInfo->ah.nDataStartBlkAdr = pAreaInfo->nRelStartBlkAdr; + pAreaInfo->ah.nDataStartBlkAdr += ((pAreaInfo->ah.nMaxNumAreas * sizeof(AreaEntry)) + (pAreaInfo->nBlkSize<<1) -nSizeRemaining-1) >> pAreaInfo->ah.nLog2BlkSize; + + u32 nNumUnclaimedBlks = pAreaInfo->ah.nNumBlks; + AreaEntryIdx nEntryIdx = 0; + //u32 sectorNum = pAreaInfo->nRelStartBlkAdr; + for (nSizeIdx=gnNumAreaSizes-1; nSizeIdx>=0; nSizeIdx--) { + pAreaInfo->pAflh->aFreeList[nSizeIdx].nAreaSize = aAreaSizes[nSizeIdx]; + pAreaInfo->pAflh->aFreeList[nSizeIdx].nHeadIdx = AREA_NULL; + u32 nEntryStride = aAreaSizes[nSizeIdx]/aAreaSizes[0]; // # entries between areas + u32 nNumAreas = 0; // # areas of this size created + while (aAreaSizes[nSizeIdx] <= nNumUnclaimedBlks) { + nNumUnclaimedBlks -= aAreaSizes[nSizeIdx]; + AreaEntry *pEntry; + WFSKrnResult nResult = _AreaEntryMap(pAreaInfo, nEntryIdx, BCACHE_FLAG_DIRTY, &pEntry); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + pEntry->nSizeIdx = nSizeIdx; + pEntry->nAttributes = AREA_START; + ++nNumAreas; + if (nNumAreas == 1) { + pAreaInfo->pAflh->aFreeList[nSizeIdx].nHeadIdx = nEntryIdx; // 1st is start of free list + pEntry->nPrevIdx = AREA_NULL; + } else { + pEntry->nPrevIdx = nEntryIdx - nEntryStride; + } + pEntry->nNextIdx = (aAreaSizes[nSizeIdx] <= nNumUnclaimedBlks) ? nEntryIdx+nEntryStride : AREA_NULL; + nEntryIdx += nEntryStride; + } + pAreaInfo->pAflh->aFreeList[nSizeIdx].nLen = nNumAreas; + } + //// The blocks are mapped to the bcache once because the blocks have to be written the hash data. + //// The hash data is written when BCacheFlushVolume() will be called. + u32 nAbsBlkAdr = _AreaGetAbsBlkAdr(pAreaInfo, nEntryIdx-1)+1; + u32 nBlkAdr; + for(nBlkAdr=0;nBlkAdrpVolInfo, nBlkAdr, BCACHE_FLAG_DIRTY, 0); + if (nResult < WFSKRN_RESULT_OK) { + return nResult; + } + } + //BCacheUnpin(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr); + AreaInfo subAreaInfo; // sub area allocated for pAreaHdr header + nResult = AreaAllocSubArea(pAreaInfo, pAreaInfo->ah.nDataStartBlkAdr, &subAreaInfo, BCACHE_FLAG_DIRTY); + +#else //SIMPLE_ALLOCATOR + + pAreaInfo->ah.pPtr = gpPtr; + + pAreaInfo->ah.nFirstFreeBlkAdr = 1; + pAreaInfo->ah.nNumFreeBlks = pAreaInfo->ah.nNumBlks-1; + u32 nI; + for(nI=1; nIah.nNumFreeBlks; nI++) { + WFSBlkAdr *pNextFreeBlock = (WFSBlkAdr *)AreaGetPhysicalBlk(pAreaInfo, nI); + *pNextFreeBlock = nI+1; + } + WFSBlkAdr *pNextFreeBlock = (WFSBlkAdr *)AreaGetPhysicalBlk(pAreaInfo, nI); + *pNextFreeBlock = 0; + +#endif +#if LIST_BASED_ALLOCATOR +Done: +#endif + return nResult; +} + + +void AreaInfoInit(AreaInfo *pAreaInfo) { + dbga(OS_TPrintf("AreaInfoInit()\n")); + // This function initializes the AreaInfo from the header on disk + pAreaInfo->nBlkSize = (u32)(1<ah.nLog2BlkSize); + pAreaInfo->nMediumBlkSize = (u32)(1<ah.nLog2MediumBlkSize); + pAreaInfo->nLargeBlkSize = (u32)(1<ah.nLog2LargeBlkSize); + pAreaInfo->nLog2BlksPerMediumBlk = (u32)(pAreaInfo->ah.nLog2MediumBlkSize-pAreaInfo->ah.nLog2BlkSize); + pAreaInfo->nLog2BlksPerLargeBlk = (u32)(pAreaInfo->ah.nLog2LargeBlkSize-pAreaInfo->ah.nLog2BlkSize); + pAreaInfo->nLog2MediumBlkPerLargeBlk = (u32)(pAreaInfo->ah.nLog2LargeBlkSize-pAreaInfo->ah.nLog2MediumBlkSize); + pAreaInfo->nLargeBlkPtrSize = sizeof(WFSBlkAdr) + (sizeof(WFSHashCode) << pAreaInfo->nLog2MediumBlkPerLargeBlk); + //pAreaInfo->nMaxMediumBlkPtrsPerAttrSubBlk = DIR_ENTRY_ATTR_MAX_PTR_ARY_SIZE / pAreaInfo->nLargeBlkPtrSize; + //pAreaInfo->nMaxLargeBlkPtrsPerAttrSubBlk = DIR_ENTRY_ATTR_MAX_PTR_ARY_SIZE / pAreaInfo->nLargeBlkPtrSize; + pAreaInfo->nNumLargeBlkPtrsPerBlk = (pAreaInfo->nBlkSize - sizeof(WFSMetaDataHdr)) / pAreaInfo->nLargeBlkPtrSize; + pAreaInfo->nNumMediumBlkPtrsPerBlk = pAreaInfo->nNumLargeBlkPtrsPerBlk<nLog2MediumBlkPerLargeBlk; +} + + +static WFSKrnResult FreeAclCache(AreaInfo *pAreaInfo) +{ + WFSKrnHeapFree(&wkg.heap, pAreaInfo->accessListCb); // release acl control block and acl cache. + pAreaInfo->accessListCb = 0; + return WFSKRN_RESULT_OK; +} + + +static WFSKrnResult AllocAclCache(AreaInfo *pAreaInfo) +{ + WFSKrnResult result = WFSKRN_RESULT_OUT_OF_MEMORY; + WFSAccessListControlBlock* cb; + u32 cbSize = ROUNDUP32BYTE(sizeof(WFSAccessListControlBlock)); + u32 aclCacheSize = ACL_DEFAULT_CACHESIZE; + + // Accesslist cache must be able to contain 3 accesslists, at least. + u32 minBlocks = 3 * (WFS_ACL_MAX_ENTRIES + sizeof(WFSKrnAccessList) / sizeof(WFSKrnAccessListBlock)); + + cb = (WFSAccessListControlBlock*) WFSKrnHeapAlloc(&wkg.heap, cbSize + aclCacheSize); + if (cb) + { + cb->memoryBlock = (WFSKrnAccessListBlock*) ((u8*) cb + cbSize); + cb->numBlock = aclCacheSize / sizeof(WFSKrnAccessListBlock); + cb->initialized = (WFSBool) FALSE; + pAreaInfo->accessListCb = cb; + + if (minBlocks <= cb->numBlock) + { + result = WFSKRN_RESULT_OK; + } + else + { + WFSKrnHeapFree(&wkg.heap, pAreaInfo->accessListCb); // release acl control block and acl cache. + } + } + + return result; +} + + +static WFSKrnResult AclInit(AreaInfo *pAreaInfo) +{ + WFSKrnResult result = AllocAclCache(pAreaInfo); + if (result == WFSKRN_RESULT_OK) + { + result = WFSKrnAccessListInit(pAreaInfo); + } + return result; +} + + +WFSKrnResult AreaInit(AreaInfo *pAreaInfo) { + dbga(OS_TPrintf("AreaInit()\n")); + // Arguments: + // pAreaInfo [IN/OUT] .. Pointer to area info struct for the new area to create. + // Input parameters used (remainder is output): + // pAreaInfo->pVolInfo [IN] .. Points to the volume struct of the area. + // pAreaInfo->pParent [IN] .. Points to the parent area. If this is NULL, then there is no parent (pAreaInfo is the root area) + // pAreaInfo->nRelStartBlkAdr [IN] .. Specifies the location of the new area within the parent area + // pAreaInfo->ah.nLog2BlkSize [IN] .. Log to the base 2 of the block size for this area (small block or meta data blocks) + // pAreaInfo->ah.nNumBlks [IN] .. Number of blocks in the area. Should be a power of 2. + // Synopsis: + // This function can be called to initialize a new area + WFSKrnResult nResult = WFSKRN_RESULT_OK; + VolumeInfo *pVolInfo = pAreaInfo->pVolInfo; + AreaInfo *pParent = pAreaInfo->pParent; + pAreaInfo->nAbsStartBlkAdr = pAreaInfo->nRelStartBlkAdr; + if (pParent) { + pAreaInfo->nAbsStartBlkAdr += pParent->nAbsStartBlkAdr; + } + WFSBlkAdr nAbsStartBlkAdr = pAreaInfo->nAbsStartBlkAdr; +#if _DEBUG + // check size area lies within the bounds of its parent + if (pParent) { + if ((nAbsStartBlkAdr + pAreaInfo->ah.nNumBlks) > (pParent->nAbsStartBlkAdr + pParent->ah.nNumBlks)) { + return WFSKRN_RESULT_AREA_INVALID_PARAMETER; + } + } else { + DeviceInfo *pDevInfo = pVolInfo->pDevInfo; + if (((nAbsStartBlkAdr + pAreaInfo->ah.nNumBlks)<<(pDevInfo->dh.nLog2SectorSize - pAreaInfo->ah.nLog2BlkSize)) > pDevInfo->dh.nNumSectors) { + return WFSKRN_RESULT_AREA_INVALID_PARAMETER; + } + } +#endif + pAreaInfo->ah.nFlags = WFS_MDF_AREA_HDR; + pAreaInfo->ah.nLog2MediumBlkSize = WFS_LOG2_MEDIUM_BLK_SIZE; + pAreaInfo->ah.nLog2LargeBlkSize = WFS_LOG2_LARGE_BLK_SIZE; + + AreaInfoInit(pAreaInfo); + BCacheEntry *pBce; + nResult = BCacheAllocMetaBlk(pVolInfo, nAbsStartBlkAdr, BCACHE_FLAG_PINNED | BCACHE_FLAG_DIRTY, &pBce); + if (nResult < WFSKRN_RESULT_OK) { + return nResult; + } + u8 *pBlkPtr = pBce->pBlkPtr; + u32 nSizeRemaining = pAreaInfo->nBlkSize - sizeof(AreaHdr); + if (pAreaInfo->nAbsStartBlkAdr == VOLUME_HDR_BLK_ADR) { + pBlkPtr += sizeof(VolumeHdr); + nSizeRemaining -= sizeof(VolumeHdr); + } + pAreaInfo->pAflh = (AreaFreeListHdr *)(pBlkPtr + sizeof(AreaHdr)); +#if _CHECK_BLK_ALLOCATION + pAreaInfo->aBlkAllocState = (u32*)WFSKrnHeapAlloc(&wkg.heap, ((pAreaInfo->ah.nNumBlks+31)&-32)>>3); + memset(pAreaInfo->aBlkAllocState, 0, pAreaInfo->ah.nNumBlks>>3); +#endif + /* + root disk block + +------------------+ <-- pVolInfo - - - - - - - - -A + | | | + +------------------+ <-- pAreaHdr (pAreaInfo->ah) | + | | | + +------------------+ <-- pAreaInfo->pAflh | + | | A | + | | | | + | | | | pAreaInfo->nBlkSize + | | | | + | | | nSizeRemaining | + | | | | + | | | | + | | | | + +------------------+ V - - - - - - - - - - - - - - V + */ + nResult = AreaInitAllocator(pAreaInfo, nSizeRemaining); + if (nResult != WFSKRN_RESULT_OK) { + goto Exit; + } +#if _DEBUG + bcg.bSkipCheckPin = true; +#endif + nResult = AreaAllocBlks(pAreaInfo, 0, pAreaInfo->ah.nLog2BlkSize, 1, &pAreaInfo->ah.nRootBlkAdr, sizeof(WFSBlkAdr)); +#if _DEBUG + bcg.bSkipCheckPin = false; +#endif + if (nResult != WFSKRN_RESULT_OK) { + goto Exit; + } + + nResult = AclInit(pAreaInfo); + if (nResult != WFSKRN_RESULT_OK) { + goto Exit; + } + *((AreaHdr *)pBlkPtr) = pAreaInfo->ah; + +Exit: + BCacheUnpin(pVolInfo, nAbsStartBlkAdr); + if (nResult == WFSKRN_RESULT_OK) + { + BCacheFlushVolume(pAreaInfo->pVolInfo); // write out all. Needed? or close flushes? + } + return nResult; +} + + +WFSKrnResult AreaOpen(AreaInfo *pAreaInfo) { + dbga(OS_TPrintf("AreaOpen()\n")); + WFSKrnResult nResult = WFSKRN_RESULT_OK; + VolumeInfo *pVolInfo = pAreaInfo->pVolInfo; + AreaInfo *pParent = pAreaInfo->pParent; + pAreaInfo->nAbsStartBlkAdr = pAreaInfo->nRelStartBlkAdr; + if (pParent) { + pAreaInfo->nAbsStartBlkAdr += pParent->nAbsStartBlkAdr; + } + WFSBlkAdr nAbsStartBlkAdr = pAreaInfo->nAbsStartBlkAdr; +#if _DEBUG + // check size area lies within the bounds of its parent + if (pParent) { + if ((nAbsStartBlkAdr + pAreaInfo->ah.nNumBlks) > (pParent->nAbsStartBlkAdr + pParent->ah.nNumBlks)) { + return WFSKRN_RESULT_AREA_INVALID_PARAMETER; + } + } else { + DeviceInfo *pDevInfo = pVolInfo->pDevInfo; + if (((nAbsStartBlkAdr + pAreaInfo->ah.nNumBlks)<<(pDevInfo->dh.nLog2SectorSize - pAreaInfo->ah.nLog2BlkSize)) > pDevInfo->dh.nNumSectors) { + return WFSKRN_RESULT_AREA_INVALID_PARAMETER; + } + } +#endif + BCacheEntry *pBce; + nResult = BCacheAllocMetaBlk(pVolInfo, nAbsStartBlkAdr, BCACHE_FLAG_PINNED | BCACHE_FLAG_READ, &pBce); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + u8 *pBlkPtr = pBce->pBlkPtr; + +#if BTREE_BASED_ALLOCATOR + if (pAreaInfo->nAbsStartBlkAdr == VOLUME_HDR_BLK_ADR) { + pBlkPtr += sizeof(VolumeHdr); + } + + AreaHdr *pSrcAreaHdr = (AreaHdr*)pBlkPtr; + pAreaInfo->ah = *pSrcAreaHdr; + pAreaInfo->pAflh = (AreaFreeListHdr *)(pBlkPtr + sizeof(AreaHdr)); + AreaInfoInit(pAreaInfo); // [check] init again? + +#elif LIST_BASED_ALLOCATOR + + s32 nSizeRemaining = -(signed)(sizeof(AreaHdr) + sizeof(AreaFreeListHdr)); + if (pAreaInfo->nAbsStartBlkAdr == VOLUME_HDR_BLK_ADR) { + pBlkPtr += sizeof(VolumeHdr); + nSizeRemaining -= sizeof(VolumeHdr); + } + AreaHdr *pSrcAreaHdr = (AreaHdr*)pBlkPtr; + pAreaInfo->ah = *pSrcAreaHdr; + pAreaInfo->pAflh = (AreaFreeListHdr *)(pBlkPtr + sizeof(AreaHdr)); + AreaInfoInit(pAreaInfo); + nSizeRemaining += pAreaInfo->nBlkSize; + pAreaInfo->nNumEntriesInFirstBlk = nSizeRemaining / sizeof(AreaEntry); + pAreaInfo->nNumEntriesPerBlk = (pAreaInfo->nBlkSize-sizeof(WFSMetaDataHdr)) / sizeof(AreaEntry); + //pAreaInfo->nNumEntriesPerBlk = (pAreaInfo->nBlkSize) / sizeof(AreaEntry); + +#else //SIMPLE_ALLOCATOR + +#endif + +#if _CHECK_BLK_ALLOCATION + pAreaInfo->aBlkAllocState = (u32*)WFSKrnHeapAlloc(&wkg.heap, ((pAreaInfo->ah.nNumBlks+31)&-32)>>3); + memset(pAreaInfo->aBlkAllocState, 0, pAreaInfo->ah.nNumBlks>>3); +#endif + //nResult = AreaInitAllocator(pAreaInfo, pBlkPtr); + if (nResult != WFSKRN_RESULT_OK) { + goto Exit; + } + BCacheUnpin(pVolInfo, nAbsStartBlkAdr); + + // load accesslist config. + nResult = AllocAclCache(pAreaInfo); + if (nResult == WFSKRN_RESULT_OK) + { + nResult = WFSKrnAccessListOpen(pAreaInfo); + } + if (nResult != WFSKRN_RESULT_OK) { + goto Exit; + } + + BCacheFlushVolume(pAreaInfo->pVolInfo); // write out all. Needed? or close flushes? +Exit: + return nResult; +} + + +void AreaClose(AreaInfo *pAreaInfo) { + dbga(OS_TPrintf("AreaClose()\n")); + FreeAclCache(pAreaInfo); +#if _CHECK_BLK_ALLOCATION + WFSKrnHeapFree(&wkg.heap, pAreaInfo->aBlkAllocState); +#endif +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_BCache.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_BCache.cpp new file mode 100644 index 0000000..bddf9f3 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_BCache.cpp @@ -0,0 +1,1463 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_BCache.cpp - disk block cache library. + Intended for metadata block caching only. + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_BCache.cpp,v $ + Revision 1.27 2008/12/22 08:56:12 ueno + Avoided null reference. + + Revision 1.26 2008/12/18 09:03:10 kondo_masahiro + Fixed function name and process from BCacheSetBlkAdr() to BCacheRemap() + + Revision 1.25 2008/12/17 01:37:27 kondo_masahiro + Added function BCacheSetBlkAdr() + + Revision 1.24 2008/12/10 08:20:08 ueno + Added BCacheDumpPinCount() for debug. + + Revision 1.23 2008/12/03 00:08:59 kondo_masahiro + Added WFSBCacheStoreVolume and removed WFSBCacheFlushAll. + + Revision 1.22 2008/11/26 01:43:24 kondo_masahiro + Fixed arguments of several functions in order to improve access speed. + + Revision 1.21 2008/11/05 16:48:37 ueno + Fixed. + + Revision 1.20 2008/11/05 05:53:40 kondo_masahiro + Added ChainId + + Revision 1.19 2008/10/16 09:30:39 ooizumi + Fixed definitions for debug build. + + Revision 1.18 2008/10/14 10:27:14 kondo_masahiro + Added #define _DEBUG_BREAK_POINT + + Revision 1.17 2008/10/09 01:41:13 kondo_masahiro + Fixed name of the function DeviceRead/WriteSingleBlk + + Revision 1.16 2008/10/08 23:59:27 ueno + Modified BCacheAlloc() to return WFSKRN_RESULT_MEDIA_ERROR when the volume is unmounted. + + Revision 1.15 2008/10/08 23:19:54 kondo_masahiro + Added codes to access large size file data + + Revision 1.14 2008/10/07 05:56:41 ueno + Modified BCacheAlloc() to return WFSKRN_RESULT_MEDIA_ERROR when the volume is unmounted. + + Revision 1.13 2008/10/03 08:37:56 kondo_masahiro + Fixed codes for porting IOP + + Revision 1.12 2008/09/29 10:19:36 ueno + Revised to support multi-B-tree-based allocator. + + Revision 1.11 2008/09/28 23:31:21 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.10 2008/09/04 03:31:07 kondo_masahiro + Fixed error handling + + Revision 1.9 2008/08/14 08:10:57 kondo_masahiro + Fixed functions related on DeviceRead / Write. + + Revision 1.8 2008/08/08 13:32:28 ueno + Added BCacheCheck2() to check freeblock allocator. + + Revision 1.7 2008/08/05 04:07:46 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.6 2008/07/28 21:47:22 paul + Removed "Increment update counter" section. This is now specific to Dir blocks. + + Revision 1.5 2008/07/17 22:45:10 paul + Change for updateMap + + Revision 1.4 2008/07/17 05:31:15 kondo_masahiro + Added codes for debug. + + Revision 1.3 2008/07/09 00:18:45 paul + Changed to use pointer to static volume struct as tag instead of handle. Removed handle mapping code. Moved globals to a single struct. Removed some of the less useful parameter checking. Added more stringent usage checks in debug builds. + + Revision 1.2 2008/05/12 19:06:39 paul + Merged in Wayne's previous changes + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.8 2008/04/26 01:28:08 wayne.wong + Moved BCache paramers to wfskrn_config.h. Changed type prefix. + + Revision 1.7 2008/03/19 07:42:26 wayne.wong + Fixed a bug with nAbsBlkAdr tag matching at page granularity. + + Revision 1.6 2008/03/11 03:15:53 wayne.wong + Added a call to map a device without knowing the volume's ID. Here, the + device is assumed to have been initialized with a volume and the volume's + header is read. + + Revision 1.5 2008/02/22 00:40:51 wayne.wong + Change BCache module's prefix for functions and types. Added some new functions. + + Revision 1.4 2008/02/20 08:01:39 paul + Changed wfsKrnResult to WFSKrnResult, wfsDevice to Device. + + Revision 1.3 2008/02/05 03:10:52 wayne.wong + Small fixes. + + Revision 1.2 2008/01/30 03:55:49 wayne.wong + Multiple fixes. Checkpoint. + + Revision 1.1 2008/01/18 06:13:50 wayne.wong + Initial version. + +*---------------------------------------------------------------------------*/ + + +// #define _DEBUG_WFSKRN_PMEM_ 1 +// #define _DEBUG_WFSKRN_BCACHE 1 + +#include "wfskrn_Api.h" +#include "wfskrn_BCache.h" +#include "wfskrn_Config.h" +#include "wfskrn_Device.h" +#include "wfskrn_Volume.h" +#include "wfskrn_Area.h" +#include "wfskrn_Utils.h" + +// moved to wfskrn_Config.h + +BCacheGlobals bcg ATTRIBUTE_ALIGN(512); + +#define PAGE_NUMBER_CE(_ce_addr) (_ce_addr - pGroup->pBCacheTable) + +#define BCACHE_CACHE_ENTRY_INVALIDATE(_pCE) { \ + _pCE->nAbsBlkAdr = 0; \ + _pCE->pVolInfo = 0; \ + _pCE->pDevInfo = 0; \ + _pCE->nState = BCACHE_FLAG_INVALID; \ + } + + +#if !DEVICE_EMBEDDED_HASH_DATA +static WFSHashCode hashData; +#endif + + +// internal BCacheList functions +static BCacheListNode *BCacheListNodeAlloc(BCacheGroup *pGroup) { + if (pGroup->bclFree.nLen > 0) { + BCacheListNode *pNode = pGroup->bclFree.pHead; + pGroup->bclFree.pHead = pNode->pNext; + --pGroup->bclFree.nLen; + return pNode; + } + return NULL; +} + + +static void BCacheListNodeFree(BCacheGroup *pGroup, BCacheListNode *pNode) { + pNode->pNext = pGroup->bclFree.pHead; + pGroup->bclFree.pHead = pNode; + ++pGroup->bclFree.nLen; +} + + +static WFSKrnResult BCacheListNodeInit(BCacheGroup *pGroup, u32 numPages) { + dbgb(osTPrintf("BCacheListNodeInit()\n")); + // bcg.pBclNodes = (BCacheListNode*)malloc(2*numPages * sizeof(BCacheListNode)); + pGroup->pBclNodes = (BCacheListNode*)bcg.pHeap; + bcg.pHeap += 2*numPages * sizeof(BCacheListNode); + bcg.nHeapSize -= 2*numPages * sizeof(BCacheListNode); + if (!pGroup->pBclNodes) return WFSKRN_RESULT_BCACHE_NO_MEMORY; + pGroup->bclFree.pHead = NULL; + pGroup->bclFree.pTail = NULL; + u32 nI; + for (nI=0; nI<(2*numPages); nI++) { // need to add to list and hash table + BCacheListNodeFree(pGroup, &pGroup->pBclNodes[nI]); + } + return WFSKRN_RESULT_OK; +} + + +static void BCacheListInit(BCacheList *pList) { + dbgb(osTPrintf("BCacheListInit()\n")); + pList->pHead = NULL; + pList->pTail = NULL; + pList->nLen = 0; +} + + +// A match is found if the nVolumeId and nAbsBlkAdr are the same. +static BCacheEntry* BCacheListFind(BCacheList *pList, VolumeInfo *pVolInfo, WFSBlkAdr nAbsBlkAdr) { + dbgb(osTPrintf("BCacheListFind()\n")); + BCacheListNode *c = pList->pHead; + while (NULL != c) { + BCacheEntry *pBce = (BCacheEntry*)c->pData; + if ((pVolInfo == pBce->pVolInfo) && (pBce->nAbsBlkAdr == nAbsBlkAdr)) { + return pBce; + } + c = c->pNext; + } + return NULL; +} + + +// Add a BCacheEntry to the head of the list. Be careful to not add an entry to the same list +// more than once. +static BCacheEntry* BCacheListAddToHead(BCacheList *pList, BCacheEntry *pBce) { + dbgb(osTPrintf("BCacheListAddToHead()\n")); + BCacheListNode *n = BCacheListNodeAlloc(pBce->pGroup); + if (!n) return NULL; + n->pData = (void*)pBce; + + BCacheListNode *c = pList->pHead; + if (c != NULL) { + c->pPrev = n; + n->pNext = c; + } else { + n->pNext = NULL; + pList->pTail = n; + } + n->pPrev = NULL; + pList->pHead = n; + pList->nLen++; + return pBce; +} + + +// Add a BCacheEntry to the tail of the list. Be careful to not add an empty to the same list +// more than once! +static BCacheEntry* BCacheListAddToTail(BCacheList *pList, BCacheEntry *pBce) { + dbgb(osTPrintf("BCacheListAddToTail()\n")); + BCacheListNode *n = BCacheListNodeAlloc(pBce->pGroup); + if (!n) return NULL; + n->pData = (void*)pBce; + + BCacheListNode *c = pList->pTail; + if (c != NULL) { + c->pNext = n; + n->pPrev = c; + } else { + n->pPrev = NULL; + pList->pHead = n; + } + n->pNext = NULL; + pList->pTail = n; + pList->nLen++; + return pBce; +} + + +// Returns a pointer to the entry if the delete was successful. Otherwise, the +// entry was not found. +static BCacheEntry* BCacheListDelete(BCacheList *pList, BCacheEntry *pBce) { + dbgb(osTPrintf("BCacheListDelete()\n")); + BCacheListNode *c = pList->pHead; + while (NULL != c) { + BCacheEntry *currCE = (BCacheEntry*)c->pData; + if (pBce == currCE) { + if (pList->pHead == c) { + pList->pHead = c->pNext; + } else { + (c->pPrev)->pNext = c->pNext; + } + if (pList->pTail == c) { + pList->pTail = c->pPrev; + } else { + (c->pNext)->pPrev = c->pPrev; + } + pList->nLen--; + BCacheListNodeFree(pBce->pGroup, c); + return pBce; + } + c = c->pNext; + } + return NULL; +} + + +static BCacheEntry* BCacheNodeDelete(BCacheList *pList, BCacheListNode *pNode) { + dbgb(osTPrintf("BCacheNodeDelete()\n")); + if (NULL != pNode) { + BCacheEntry *pBce = (BCacheEntry*)pNode->pData; + if (pList->pHead == pNode) { + pList->pHead = pNode->pNext; + } else { + (pNode->pPrev)->pNext = pNode->pNext; + } + if (pList->pTail == pNode) { + pList->pTail = pNode->pPrev; + } else { + (pNode->pNext)->pPrev = pNode->pPrev; + } + pList->nLen--; + BCacheListNodeFree(pBce->pGroup, pNode); + return pBce; + } + return NULL; +} + + +// Returns a pointer to the entry if the move was successful +static BCacheEntry* BCacheListMoveToHead(BCacheList *pList, BCacheEntry *pBce) { + dbgb(osTPrintf("BCacheListMoveToHead()\n")); + if ((BCacheEntry*)pList->pHead->pData == pBce) return pBce; + if (!BCacheListDelete(pList, pBce)) return NULL; + return BCacheListAddToHead(pList, pBce); +} + + +// Returns a pointer to the entry if the move was successful +static BCacheEntry* BCacheListMoveToTail(BCacheList *pList, BCacheEntry *pBce) { + dbgb(osTPrintf("BCacheListMoveToTail()\n")); + if ((BCacheEntry*)pList->pTail->pData == pBce) return pBce; + if (!BCacheListDelete(pList, pBce)) return NULL; + return BCacheListAddToTail(pList, pBce); +} + + +static void BCacheListPrint(BCacheList *pList) { + dbgb(osTPrintf("BCacheListPrint()\n")); + u32 cnt = 0; + BCacheListNode *c = pList->pHead; + //osTPrintf("\nlist 0x%08x\n", pList); + while (NULL != c) { + BCacheEntry *pBce = (BCacheEntry*)c->pData; + //osTPrintf("%d: 0x%08x, nAbsBlkAdr=%d\n", cnt, pBce, pBce->nAbsBlkAdr); + cnt++; + c = c->pNext; + } +} + + +// Exposed BCache functions + +// Calculate the number of bytes need to support the cache geometry. +u32 BCacheMetadataMemSize(u32 nMemCacheSize, u32 nBlkSize) { + dbgb(osTPrintf("BCacheMetadataMemSize()\n")); + u32 frames = nMemCacheSize/nBlkSize; + u32 result = frames*sizeof(BCacheEntry); // page table + result += 2*frames * sizeof(BCacheListNode); + return result; +} + + +WFSKrnResult BCacheInit(u32 nLog2UnitBlkSize, u8 *pMem, u32 nMemSize) +{ + dbgb(osTPrintf("BCacheInitMetadata()\n")); + bcg.pHeap = pMem; + bcg.nHeapSize = nMemSize; + bcg.nNumGroups = 0; + bcg.nLog2UnitBlkSize = nLog2UnitBlkSize; + bcg.nUnitBlkSize = 1<pBCache = 0; + } + // init hash table + for (nI=0; nIpBCache) || + (bcg.pHeap == NULL) || (pMemCache == NULL) || (nMemCacheSize==0) || (nLog2BlkSize==0) || + ((u32)bcg.pHeap & 0x3) || ((u32)pMemCache & 0x1ff) || + (bcg.nHeapSize < BCacheMetadataMemSize(nMemCacheSize, 1<pBCache = pMemCache; + pGroup->nLog2BlkSize = nLog2BlkSize; + pGroup->nBlkSize = 1<nNumBlks = nMemCacheSize>>nLog2BlkSize; + + BCacheListNodeInit(pGroup, pGroup->nNumBlks); + + BCacheListInit(&pGroup->bclInvalid); + BCacheListInit(&pGroup->bclLru); + BCacheListInit(&pGroup->bclPinned); + + // init cache table + pGroup->pBCacheTable = (BCacheEntry*) bcg.pHeap; + bcg.pHeap += pGroup->nNumBlks*sizeof(BCacheEntry); + bcg.nHeapSize -= pGroup->nNumBlks*sizeof(BCacheEntry); + + if (!pGroup->pBCacheTable) return WFSKRN_RESULT_BCACHE_ERROR; + dbgb(osTPrintf("bcg.pBCacheTable @ 0x%08x\n", bcg.pBCacheTable)); + int nI; + for (nI=0; nInNumBlks; nI++) { // initialize pages and link together + BCacheEntry *pBce = &pGroup->pBCacheTable[nI]; + BCACHE_CACHE_ENTRY_INVALIDATE(pBce); + pBce->pGroup = pGroup; + pBce->pHash = 0; + BCacheListAddToTail(&pGroup->bclInvalid, pBce); + } + + ++bcg.nNumGroups; + + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult BCacheGetState(BCacheGroup *pGroup) { + dbgb(osTPrintf("BCacheGetState()\n")); + pGroup->pMemCache = pGroup->pBCache; + pGroup->nMemCacheSize = pGroup->nNumBlks * pGroup->nBlkSize; + pGroup->nBlkSize = pGroup->nBlkSize; + pGroup->nNumMapped = pGroup->bclLru.nLen + pGroup->bclPinned.nLen; + pGroup->nNumInvalid = pGroup->bclInvalid.nLen; + pGroup->nNumPinned = pGroup->bclPinned.nLen; + return WFSKRN_RESULT_OK; +} + + +// Allocate a page in the cache. +static +WFSKrnResult BCacheAllocBlk(BCacheGroup *pGroup, u8 **ppBlkPtr, BCacheEntry** ppBce) { + dbgb(osTPrintf("BCacheAllocBlk()\n")); + // find a victim list + *ppBce = NULL; + BCacheList *pList; + if (pGroup->bclInvalid.pHead) { // if invalid blocks available + pList = &pGroup->bclInvalid; + } else if (pGroup->bclLru.pHead) { // else, try a non-pinned LRU page + pList = &pGroup->bclLru; + } else { // otherwise, no free page available + return WFSKRN_RESULT_BCACHE_RESOURCE_LIMIT; + } + + BCacheEntry *pBce = (BCacheEntry*) pList->pHead->pData; // victim is head of invalid or LRU list + u8 *pBlkPtr = pGroup->pBCache + (pGroup->nBlkSize * PAGE_NUMBER_CE(pBce)); +#if _DEBUG_BREAK_POINT + if(pBce->nAbsBlkAdr == 0x1c5d){ + int a; a=0; + } +#endif + if (pBce->nState & BCACHE_FLAG_DIRTY) { + DeviceInfo *pDevInfo = pBce->pDevInfo; + WFSKrnResult nResult = DeviceWriteSingleBlk(pDevInfo, pBce->nAbsBlkAdr<<(bcg.nLog2UnitBlkSize-pDevInfo->dh.nLog2SectorSize), + pBlkPtr, pBce->nValidSize>>pDevInfo->dh.nLog2SectorSize, + pBce->pHash, pGroup->nLog2BlkSize-pDevInfo->dh.nLog2SectorSize, false); + if(nResult < WFSKRN_RESULT_OK) { + return WFSKRN_RESULT_MEDIA_ERROR; + } + if(pBce->nAbsBlkAdr != pBce->nHashBlkAdr){ + nResult = BCacheDirty(pDevInfo->pVolInfo, pBce->nHashBlkAdr); + nResult = BCacheUnpin(pDevInfo->pVolInfo, pBce->nHashBlkAdr); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + } + pBce->nState &= ~BCACHE_FLAG_DIRTY; // make clean; just in case we don't really replace + + if(pBce->nChainId && pList == &pGroup->bclLru){ + BCacheEntry *pBceWrite = pBce; + while(1){ + WFSBlkAdr nBlkAdrTmp = pBceWrite->nAbsBlkAdr + (1<<(pGroup->nLog2BlkSize-bcg.nLog2UnitBlkSize)); + pBceWrite = BCacheListFind(&pGroup->bclLru, pBceWrite->pDevInfo->pVolInfo, nBlkAdrTmp); + if(pBceWrite == NULL || pBceWrite->nChainId != pBce->nChainId){ + break; + } + pBceWrite->nChainId = 0; + nResult = BCacheStore(pBceWrite->pDevInfo->pVolInfo, nBlkAdrTmp); + if(nResult < WFSKRN_RESULT_OK) { + return WFSKRN_RESULT_MEDIA_ERROR; + } + } + } + } + if (pList == &pGroup->bclLru) { // if mapped, remove mapping + BCacheListDelete(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(pBce->nAbsBlkAdr)], pBce); + } + if (!BCacheListDelete(pList, pBce)){ // remove victim entry from its list; if fail, return NULL + return WFSKRN_RESULT_BCACHE_ERROR; + } + + pBce->nState = BCACHE_FLAG_INVALID; // make clean; just in case we don't really replace + pBce->pHash = 0; + pBce->nChainId = 0; + + if (ppBlkPtr) *ppBlkPtr = pBlkPtr; + *ppBce = pBce; + return WFSKRN_RESULT_OK; +} + + +#if _CHECK_BLK_USAGE +u32 BCacheCalcCheckSum(u8 *pBuffer, u32 nSize) { + dbgb(osTPrintf("BCacheCalcCheckSum()\n")); + // pBuffer should be 16 byte aligned address, and nSize should be a multiple of 16 bytes + u32 *pPtr = (u32*)pBuffer; + u32 *pPtrEnd = (u32*)((u8*)pBuffer + nSize); + u32 nCheckSum = 0x12345678; + while(pPtr>3); + nCheckSum += *pPtr++; + nCheckSum ^= *pPtr++ + (nCheckSum*0x8020); + } + return nCheckSum; +} +#endif + + +void BCacheReTag(VolumeInfo *pOldVolInfo, WFSBlkAdr nOldAbsBlkAdr, VolumeInfo *pNewVolInfo, WFSBlkAdr nNewAbsBlkAdr) { + dbgb(osTPrintf("BCacheReTag()\n")); + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nOldAbsBlkAdr)], pOldVolInfo, nOldAbsBlkAdr); + if (!pBce) { + // Doesn't exist in the cache, so nothing to re-tag + return; + } + if (WFSKRN_BCACHE_HASH_FN(nOldAbsBlkAdr) == WFSKRN_BCACHE_HASH_FN(nOldAbsBlkAdr)) { + pBce->nAbsBlkAdr = nNewAbsBlkAdr; + pBce->pVolInfo = pNewVolInfo; + } else { + // Cache entry needs to be moved to a new hash table address + // ToDo: This branch has not yet been tested + BCacheListDelete(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nOldAbsBlkAdr)], pBce); + BCacheListAddToHead(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nNewAbsBlkAdr)], pBce); + } +} + + +static +WFSKrnResult BCacheSetHashPtrToEntry(struct VolumeInfo_ *pVolInfo, BCacheEntry *pBce, WFSBlkAdr nHashBlkAdr, u32 nHashOfs) +{ +#if DEVICE_EMBEDDED_HASH_DATA + BCacheEntry *pBceHash; + if (nHashBlkAdr == pBce->nAbsBlkAdr){ + pBceHash = pBce; + } else { + pBceHash = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nHashBlkAdr)], pVolInfo, nHashBlkAdr); + if (!pBceHash){ // nHashBlkAdr have to exist on the block cache. + return WFSKRN_RESULT_BCACHE_HASH_BLK_NOT_MAPPED; + } + pBceHash->nState |= BCACHE_FLAG_DIRTY; + } + if(pBce->nHashBlkAdr != nHashBlkAdr && pBce->nState & BCACHE_FLAG_DIRTY){ + BCacheUnpin(pVolInfo, pBce->nHashBlkAdr); + BCachePin(pVolInfo, nHashBlkAdr); + } + pBce->pHash = (WFSHashCode*)(pBceHash->pBlkPtr+nHashOfs); + pBce->nHashBlkAdr = nHashBlkAdr; +#elif + pBce->pHash = &hashData; +#endif + return WFSKRN_RESULT_OK; +} + + +// nAbsBlkAdr and nHashBlkAdr have to be mapped to use this function +WFSKrnResult BCacheSetHash(struct VolumeInfo_ *pVolInfo, WFSBlkAdr nAbsBlkAdr, WFSBlkAdr nHashBlkAdr, u32 nHashOfs) +{ + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + if (!pBce) { + return WFSKRN_RESULT_BCACHE_NOT_FOUND; + } + return BCacheSetHashPtrToEntry(pVolInfo, pBce, nHashBlkAdr, nHashOfs); +} + + +WFSKrnResult BCacheSetValidSize(struct VolumeInfo_ *pVolInfo, WFSBlkAdr nAbsBlkAdr, u32 nValidSize) +{ + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + if (!pBce) { + return WFSKRN_RESULT_BCACHE_NOT_FOUND; + } + if (nValidSize > pBce->pGroup->nBlkSize){ + return WFSKRN_RESULT_INVALID; + } + pBce->nValidSize = WFS_ROUND_UP(nValidSize,pVolInfo->pDevInfo->nSectorSize); + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult BCacheSetChainId(struct VolumeInfo_ *pVolInfo, WFSBlkAdr nAbsBlkAdr, u32 nChainId) +{ + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + if (!pBce) { + return WFSKRN_RESULT_BCACHE_NOT_FOUND; + } + pBce->nChainId = nChainId; + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult BCacheGetChainId(struct VolumeInfo_ *pVolInfo, WFSBlkAdr nAbsBlkAdr, u32 *pChainId) +{ + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + if (!pBce) { + return WFSKRN_RESULT_BCACHE_NOT_FOUND; + } + *pChainId = pBce->nChainId; + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult BCacheRemap(struct VolumeInfo_ *pVolInfo, WFSBlkAdr nSrcAbsBlkAdr, WFSBlkAdr nDstAbsBlkAdr, WFSBlkAdr nHashAbsBlkAdr, u32 nHashOfs) +{ + BCacheList *pHMapList = &bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nSrcAbsBlkAdr)]; + BCacheEntry *pBce = BCacheListFind(pHMapList, pVolInfo, nSrcAbsBlkAdr); + if (!pBce) { + return WFSKRN_RESULT_BCACHE_NOT_FOUND; + } + if (!BCacheListDelete(pHMapList, pBce)) + { + return WFSKRN_RESULT_BCACHE_ERROR; + } + pBce->nAbsBlkAdr = nDstAbsBlkAdr; + if ( (!BCacheListAddToHead(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nDstAbsBlkAdr)], pBce)) || + (BCacheDirty(pVolInfo, nDstAbsBlkAdr) != WFSKRN_RESULT_OK) || + (BCacheSetHash(pVolInfo, nDstAbsBlkAdr, nHashAbsBlkAdr, nHashOfs) != WFSKRN_RESULT_OK) ) + { + return WFSKRN_RESULT_BCACHE_ERROR; + } + return WFSKRN_RESULT_OK; +} + + +// Alloc a page. A page is mapped memory <-> persistent memory. +// (Wayne - make sure that we do not double-map, map a page already mapped? +// or is that checked above here?) For now, we check if it's already +// mapped/cached here. If so, return that page. +// nHashBlkAdr have to be mapped previously or nHashBlkAdr have to be indicated the same value as nAbsBlkAdr. +WFSKrnResult BCacheAlloc(struct VolumeInfo_ *pVolInfo, WFSBlkAdr nAbsBlkAdr, u32 nFlags, u32 nValidSize, u32 nBCacheGroupId, + WFSBlkAdr nHashBlkAdr, u32 nHashOfs, BCacheEntry** ppBce) +{ + if (!pVolInfo){ + return WFSKRN_RESULT_MEDIA_ERROR; + } + DeviceInfo *pDevInfo = pVolInfo->pDevInfo; + if (!pDevInfo){ + return WFSKRN_RESULT_MEDIA_ERROR; + } + if (nValidSize > (1< 0x10000000){ + int a; a=0; + } +#endif + WFSKrnResult nResult = WFSKRN_RESULT_UNKNOWN; + dbgb(osTPrintf("BCacheAlloc()\n")); + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + BCacheGroup *pGroup; + if (pBce) { // if already cached + if(&bcg.aGroup[nBCacheGroupId] != pBce->pGroup){ + WFSKrnOutputErrorStr("BCacheAllocMetaData: GroupIds do not correspond.\n"); + } + pGroup = pBce->pGroup; + if (nFlags & BCACHE_FLAG_PINNED) { + if(!pBce->nPinCount) { // need to move to pinned list? + BCacheListDelete(&pGroup->bclLru, pBce); + BCacheListAddToHead(&pGroup->bclPinned, pBce); + } +#if _DEBUG +#if !BTREE_BASED_ALLOCATOR + else{ + if (bcg.bSkipCheckPin == false) { + WFSKrnOutputErrorStr("BCacheAllocMetaData: PinCount should be 0 or 1.\n"); + } + } +#endif +#endif + ++pBce->nPinCount; +#if _CHECK_BLK_USAGE + pBce->nDbgCommandCount = nDbgCommandCount+1; +#endif + } + pBce->pBlkPtr = pGroup->pBCache + (pGroup->nBlkSize * PAGE_NUMBER_CE(pBce)); +#if _CHECK_BLK_USAGE + if ((pBce->nState & BCACHE_FLAG_DIRTY)==0) { + u32 nCheckSum = BCacheCalcCheckSum((u8*)pBlkPtr, pGroup->nBlkSize); + if (nCheckSum != pBce->nCheckSum) { + // This is not necessarily a bug because some of Wayne's allocator code marks dirty just before calling Unpin. + // The directory code should always mark the block dirty in advance though. + MyOSReport("Warning: Change detected to block that is not marked dirty. nAbsBlkAdr=%d\n", nAbsBlkAdr); + //WFSKrnOutputErrorStr("Checksum mismatch"); + } + } +#endif + nResult = BCacheSetHashPtrToEntry(pVolInfo, pBce, nHashBlkAdr, nHashOfs); + pBce->nValidSize = WFS_ROUND_UP(nValidSize, pDevInfo->dh.nLog2SectorSize); // round up secter byte + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + goto Done; + } + + u8 *pBlkPtr; + pGroup = &bcg.aGroup[nBCacheGroupId]; + nResult = BCacheAllocBlk(pGroup, (u8**)&pBlkPtr, &pBce); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + pBce->pBlkPtr = pBlkPtr; + pBce->nAbsBlkAdr = nAbsBlkAdr; + pBce->pVolInfo = pVolInfo; + pBce->pDevInfo = pDevInfo; + pBce->nState = BCACHE_FLAG_VALID; + pBce->nValidSize = WFS_ROUND_UP(nValidSize, 1<dh.nLog2SectorSize); // round up secter byte + pBce->nChainId = 0; + + nResult = BCacheSetHashPtrToEntry(pVolInfo, pBce, nHashBlkAdr, nHashOfs); + if(nResult < WFSKRN_RESULT_OK){ + BCacheListAddToHead(&pGroup->bclInvalid, pBce); + return nResult; + } + + if (nFlags & BCACHE_FLAG_READ) { // intend to read existing value of page + // Check hash data have been recorded. + u32 nHashOfs = 0; + if(pBce->nAbsBlkAdr != pBce->nHashBlkAdr){ + for(; nHashOfspHash+nHashOfs) != 0 ){ + break; + } + } + } + if(nHashOfs != sizeof(WFSHashCode) && pBce->nValidSize){ + nResult = DeviceReadSingleBlk(pDevInfo, nAbsBlkAdr<<(bcg.nLog2UnitBlkSize-pDevInfo->dh.nLog2SectorSize), (u8*)pBce->pBlkPtr, + pBce->nValidSize>>pDevInfo->dh.nLog2SectorSize, pBce->pHash, pGroup->nLog2BlkSize-pDevInfo->dh.nLog2SectorSize); + } + /* + if(nAbsBlkAdr == 6402 && pBce->nValidSize == 8192){ + int a; a=0; + } + static int c=0; c++; + if(c > 10950){ + osTPrintf("c=%d ,nAbsBlkAdr = %d, nValidSize = %d\n", c, nAbsBlkAdr, pBce->nValidSize); + } + if(c == 11001){ + int a; a=0; + } + */ + if(nResult < WFSKRN_RESULT_OK){ + pBce->nState = BCACHE_FLAG_INVALID; + pBce->nValidSize = nValidSize; + BCacheListAddToHead(&pGroup->bclInvalid, pBce); + switch(nResult){ + case WFSKRN_RESULT_DEVICE_HASH_INCONSISTENT: + osTPrintf("Hash Error: nAbsBlkAdr = %d, nValidSize = %d\n", nAbsBlkAdr, pBce->nValidSize); + return WFSKRN_RESULT_CORRUPTION; + case WFSKRN_RESULT_DEVICE_NOT_FOUND: + default: + return WFSKRN_RESULT_MEDIA_ERROR; + //return WFSKRN_RESULT_BCACHE_ERROR; + } + } +#if _CHECK_BLK_USAGE + pBce->nCheckSum = BCacheCalcCheckSum((u8*)pBlkPtr, pGroup->nBlkSize); + } else { + pBce->nCheckSum = 0; +#endif + } + + if (nFlags & BCACHE_FLAG_PINNED) { +#if _CHECK_BLK_USAGE + pBce->nDbgCommandCount = nDbgCommandCount+1; +#endif + pBce->nPinCount = 1; + BCacheListAddToHead(&pGroup->bclPinned, pBce); + } else { + pBce->nPinCount = 0; + BCacheListAddToTail(&pGroup->bclLru, pBce); // add as MRU + } + BCacheListAddToHead(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pBce); + dbgb(osTPrintf("BCacheAlloc(0x%08x, %C%C%C) -> 0x%08x\n", + pVolInfo, nAbsBlkAdr, (nFlags&BCACHE_FLAG_READ)?'R':'-', (nFlags&BCACHE_FLAG_PINNED)?'P':'-', (nFlags&BCACHE_FLAG_DIRTY)?'D':'-')); +Done:; + if(nAbsBlkAdr != nHashBlkAdr && !(pBce->nState & BCACHE_FLAG_DIRTY) && (nFlags & BCACHE_FLAG_DIRTY)){ + nResult = BCachePin(pVolInfo, nHashBlkAdr); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + } + pBce->nState |= nFlags & BCACHE_FLAG_DIRTY; + if(ppBce){ + *ppBce = pBce; + } +#if _DEBUG_BREAK_POINT + if(nAbsBlkAdr == 5693){ + int a; a=0; + } +#endif + return nResult; +} + + +void* BCacheFind(VolumeInfo *pVolInfo, WFSBlkAdr nAbsBlkAdr) { + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + if (!pBce) return NULL; + BCacheGroup *pGroup = pBce->pGroup; + u8 *pBlkPtr = pGroup->pBCache + (pGroup->nBlkSize * PAGE_NUMBER_CE(pBce)); + return pBlkPtr; +} + + +// Write page to disk, mark as clean, and if non-pinned, move to head of LRU list since +// it is now clean. +WFSKrnResult BCacheStore(VolumeInfo *pVolInfo, WFSBlkAdr nAbsBlkAdr) { + dbgb(osTPrintf("BCacheStore()\n")); + DeviceInfo *pDevInfo = pVolInfo->pDevInfo; + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + if (!pBce) return WFSKRN_RESULT_BCACHE_NOT_FOUND; + if (!(pBce->nState & BCACHE_FLAG_VALID)) return WFSKRN_RESULT_BCACHE_ERROR; + BCacheGroup *pGroup = pBce->pGroup; + if (pBce->nState & BCACHE_FLAG_DIRTY) { + u8 *pBlkPtr = pGroup->pBCache + (pGroup->nBlkSize * PAGE_NUMBER_CE(pBce)); + WFSKrnResult nResult = DeviceWriteSingleBlk(pDevInfo, pBce->nAbsBlkAdr<<(bcg.nLog2UnitBlkSize-pDevInfo->dh.nLog2SectorSize), pBlkPtr, + pBce->nValidSize>>pDevInfo->dh.nLog2SectorSize, pBce->pHash, pGroup->nLog2BlkSize-pDevInfo->dh.nLog2SectorSize, true); + if(nResult < WFSKRN_RESULT_OK) { + return WFSKRN_RESULT_MEDIA_ERROR; + } + if(pBce->nAbsBlkAdr != pBce->nHashBlkAdr){ + nResult = BCacheDirty(pDevInfo->pVolInfo, pBce->nHashBlkAdr); + nResult = BCacheUnpin(pDevInfo->pVolInfo, pBce->nHashBlkAdr); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + } + pBce->nState &= ~BCACHE_FLAG_DIRTY; // make clean; just in case we don't really replace + if (!pBce->nPinCount){ + BCacheListMoveToHead(&pGroup->bclLru, pBce); + } + dbgb(osTPrintf("BCacheStore(0x%08x, %d)\n", pVolInfo, nAbsBlkAdr)); + } +#if _CHECK_BLK_USAGE + else { + u8 *pBlkPtr = pGroup->pBCache + (pGroup->nBlkSize * PAGE_NUMBER_CE(pBce)); + if (pBce->nCheckSum != BCacheCalcCheckSum(pBlkPtr, pGroup->nBlkSize)) { + WFSKrnOutputErrorStr("Block contents changed, but was not marked dirty\n"); + } + } +#endif + return WFSKRN_RESULT_OK; +} + + +// Write page to disk, invalidate, and move to head of invalid list. Applies to both +// non-pinned and pinned pages. Illegal for invalid pages. +WFSKrnResult BCacheFlush(VolumeInfo *pVolInfo, WFSBlkAdr nAbsBlkAdr) { + dbgb(osTPrintf("BCacheFlush()\n")); + WFSKrnResult nResult = WFSKRN_RESULT_OK; + DeviceInfo *pDevInfo = pVolInfo->pDevInfo; + BCacheList *pHMapList = &bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)]; + BCacheEntry *pBce = BCacheListFind(pHMapList, pVolInfo, nAbsBlkAdr); + if (!pBce) return WFSKRN_RESULT_BCACHE_NOT_FOUND; + if (!(pBce->nState & BCACHE_FLAG_VALID)) return WFSKRN_RESULT_BCACHE_ERROR; + if (pBce->nPinCount){ + osTPrintf("BCacheFlush: The pinned block can not be flushed."); + } + BCacheGroup *pGroup = pBce->pGroup; + if (pBce->nState & BCACHE_FLAG_DIRTY) { // if writeback needed + u8 *pBlkPtr = pGroup->pBCache + (pGroup->nBlkSize * PAGE_NUMBER_CE(pBce)); + nResult = DeviceWriteSingleBlk(pDevInfo, pBce->nAbsBlkAdr<<(bcg.nLog2UnitBlkSize-pDevInfo->dh.nLog2SectorSize), pBlkPtr, + pBce->nValidSize>>pDevInfo->dh.nLog2SectorSize, pBce->pHash, pGroup->nLog2BlkSize-pDevInfo->dh.nLog2SectorSize, false); + if(nResult < WFSKRN_RESULT_OK) { + return WFSKRN_RESULT_MEDIA_ERROR; + } + if(pBce->nAbsBlkAdr != pBce->nHashBlkAdr){ + nResult = BCacheDirty(pDevInfo->pVolInfo, pBce->nHashBlkAdr); + nResult = BCacheUnpin(pDevInfo->pVolInfo, pBce->nHashBlkAdr); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + } + pBce->nState &= ~BCACHE_FLAG_DIRTY; + if (!pBce->nPinCount) BCacheListMoveToHead(&pGroup->bclLru, pBce); + } + BCacheList *pList = pBce->nPinCount ? &pGroup->bclPinned : &pGroup->bclLru; + if (!BCacheListDelete(pList, pBce)) return WFSKRN_RESULT_BCACHE_ERROR; + if (!BCacheListDelete(pHMapList, pBce)) return WFSKRN_RESULT_BCACHE_ERROR; + BCACHE_CACHE_ENTRY_INVALIDATE(pBce); + BCacheListAddToHead(&pGroup->bclInvalid, pBce); + return nResult; +} + + + +WFSKrnResult BCacheStoreVolume(VolumeInfo *pVolInfo) { + dbgb(osTPrintf("BCacheStoreVolume()\n")); + +#if WFS_BLK_CACHE_SIZE >= WFS_MAX_USER_BLK_CACHE_SIZE + WFSBlkAdr aStoreBlkAdr[WFS_BLK_CACHE_SIZE>>WFS_LOG2_SMALL_BLK_SIZE]; +#else + WFSBlkAdr aStoreBlkAdr[WFS_MAX_USER_BLK_CACHE_SIZE>>WFS_LOG2_SMALL_BLK_SIZE]; +#endif + u32 nNumStoreBlks = 0; + + // Make list to store flushed block address for user cache. + BCacheGroup *pGroup = 0; + BCacheList *pList = 0; + int nI,nJ; + for(nI=0;nIbclPinned; + break; + case 2: + pGroup = &bcg.aGroup[BCACHE_GROUP_ID_USERBLK_64K]; + pList = (BCacheList*)&pGroup->bclPinned; + break; + case 4: + pGroup = &bcg.aGroup[BCACHE_GROUP_ID_METABLK]; + pList = (BCacheList*)&pGroup->bclPinned; + break; + case 1: + case 3: + case 5: + pList = (BCacheList*)&pGroup->bclLru; + break; + } + BCacheListNode *pBln = pList->pHead; + for(nJ=0;nJnLen;nJ++){ + BCacheEntry* pBce = (BCacheEntry*)pBln->pData; + if(pVolInfo == pBce->pVolInfo){ + if(pBce->nState & BCACHE_FLAG_DIRTY){ + aStoreBlkAdr[nNumStoreBlks++] = pBce->nAbsBlkAdr; + } + } + pBln = pBln->pNext; + } + if (nI == 3 || nI == 5){ + if(nNumStoreBlks){ + _qsort((void*)aStoreBlkAdr, nNumStoreBlks, sizeof(WFSBlkAdr), CompareBlkAdrForward); + for(nJ=0;nJ= WFS_MAX_USER_BLK_CACHE_SIZE + WFSBlkAdr aFlushBlkAdr[WFS_BLK_CACHE_SIZE>>WFS_LOG2_SMALL_BLK_SIZE]; + WFSBlkAdr aInvalidBlkAdr[WFS_BLK_CACHE_SIZE>>WFS_LOG2_SMALL_BLK_SIZE]; +#else + WFSBlkAdr aFlushBlkAdr[WFS_MAX_USER_BLK_CACHE_SIZE>>WFS_LOG2_SMALL_BLK_SIZE]; + WFSBlkAdr aInvalidBlkAdr[WFS_MAX_USER_BLK_CACHE_SIZE>>WFS_LOG2_SMALL_BLK_SIZE]; +#endif + u32 nNumFlushBlks = 0; + u32 nNumInvalidBlks = 0; + + // Make list to store flushed block address for user cache. + BCacheGroup *pGroup = 0; + BCacheList *pList = 0; + int nI,nJ; + for(nI=0;nIbclPinned; + break; + case 2: + pGroup = &bcg.aGroup[BCACHE_GROUP_ID_USERBLK_64K]; + pList = (BCacheList*)&pGroup->bclPinned; + break; + case 4: + pGroup = &bcg.aGroup[BCACHE_GROUP_ID_METABLK]; + pList = (BCacheList*)&pGroup->bclPinned; + break; + case 1: + case 3: + case 5: + pList = (BCacheList*)&pGroup->bclLru; + break; + } + BCacheListNode *pBln = pList->pHead; + for(nJ=0;nJnLen;nJ++){ + BCacheEntry* pBce = (BCacheEntry*)pBln->pData; + if(pVolInfo == pBce->pVolInfo){ + if(pBce->nState & BCACHE_FLAG_DIRTY){ + aFlushBlkAdr[nNumFlushBlks++] = pBce->nAbsBlkAdr; + } else if (!pBce->nPinCount){ + aInvalidBlkAdr[nNumInvalidBlks++] = pBce->nAbsBlkAdr; + } + } + pBln = pBln->pNext; + } + if (nI == 3 || nI == 5){ + if(nNumFlushBlks){ + _qsort((void*)aFlushBlkAdr, nNumFlushBlks, sizeof(WFSBlkAdr), CompareBlkAdrForward); + for(nJ=0;nJnPinCount){ + osTPrintf("BCacheInvalidate: The pinned block can not be invalidated.\n"); + } + //BCacheList *pList = (pBce->nState & BCACHE_FLAG_PINNED) ? &bcg.bclPinned : &bcg.bclLru; + BCacheGroup *pGroup = pBce->pGroup; + BCacheList *pList = pBce->nPinCount ? &pGroup->bclPinned : &pGroup->bclLru; + if (pBce->nState & BCACHE_FLAG_DIRTY && pBce->nAbsBlkAdr != pBce->nHashBlkAdr) { + WFSKrnReturnOnError(BCacheUnpin(pVolInfo, pBce->nHashBlkAdr)); + } + if (!BCacheListDelete(pList, pBce)) return WFSKRN_RESULT_BCACHE_ERROR; + if (!BCacheListDelete(pHMapList, pBce)) return WFSKRN_RESULT_BCACHE_ERROR; + BCACHE_CACHE_ENTRY_INVALIDATE(pBce); + BCacheListAddToHead(&pGroup->bclInvalid, pBce); + return WFSKRN_RESULT_OK; +} + + +// Invalidate blocks. The function search the indicated block in the cache lists. +WFSKrnResult BCacheInvalidateBlks (struct VolumeInfo_ *pVolInfo, WFSBlkAdr nAbsBlkAdr, u32 nNumBlks){ + dbgb(osTPrintf("BCacheInvalidateBlks()\n")); + s32 nI; + u32 InvalidBlks = 0; + for (nI=bcg.nNumGroups-1;nI>=0;nI--){ + BCacheGroup *pGroup = &bcg.aGroup[nI]; + BCacheList *pList = &pGroup->bclLru; + BCacheListNode *pNode = pList->pHead; + while (NULL != pNode) + { + BCacheEntry *pBce = (BCacheEntry*)pNode->pData; + if (!pBce) + { + return WFSKRN_RESULT_OK; + } + + if (pVolInfo == pBce->pVolInfo && pBce->nAbsBlkAdr >= nAbsBlkAdr && pBce->nAbsBlkAdr < nAbsBlkAdr+nNumBlks) + { + if (pBce->nPinCount){ + osTPrintf("BCacheInvalidateBlks: The pinned block can not be invalidated.\n"); + } + if (pBce->nState & BCACHE_FLAG_DIRTY && pBce->nAbsBlkAdr != pBce->nHashBlkAdr) { + WFSKrnReturnOnError(BCacheUnpin(pVolInfo, pBce->nHashBlkAdr)); + } + BCacheListNode *pNodeNext = pNode->pNext; + if (!BCacheNodeDelete(pList, pNode)) return WFSKRN_RESULT_BCACHE_ERROR; + BCacheList *pHMapList = &bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(pBce->nAbsBlkAdr)]; + if (!BCacheListDelete(pHMapList, pBce)) return WFSKRN_RESULT_BCACHE_ERROR; + BCACHE_CACHE_ENTRY_INVALIDATE(pBce); + BCacheListAddToHead(&pGroup->bclInvalid, pBce); + ++InvalidBlks; + if (InvalidBlks == nNumBlks) return WFSKRN_RESULT_OK; + pNode = pNodeNext; + } + else{ + pNode = pNode->pNext; + } + } +#if _DEBUG + pList = &pGroup->bclPinned; + pNode = pList->pHead; + while (NULL != pNode) { + BCacheEntry *pBce = (BCacheEntry*)pNode->pData; + if (pVolInfo == pBce->pVolInfo && pBce->nAbsBlkAdr >= nAbsBlkAdr && pBce->nAbsBlkAdr < nAbsBlkAdr+nNumBlks) { + osTPrintf("BCacheInvalidateBlks.\n"); + } + pNode = pNode->pNext; + } +#endif + } + return WFSKRN_RESULT_OK; +} + + +// If valid and non-pinned, make MRU. No-op for pinned block. +WFSKrnResult BCacheTouch(VolumeInfo *pVolInfo, WFSBlkAdr nAbsBlkAdr) { + dbgb(osTPrintf("BCacheTouch()\n")); + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + if (!pBce) return WFSKRN_RESULT_BCACHE_NOT_FOUND; + if (!(pBce->nState & BCACHE_FLAG_VALID)) return WFSKRN_RESULT_BCACHE_ERROR; + BCacheGroup *pGroup = pBce->pGroup; + if (!pBce->nPinCount) { + if (BCacheListMoveToHead(&pGroup->bclLru, pBce)) { + return WFSKRN_RESULT_OK; + } else { + return WFSKRN_RESULT_BCACHE_ERROR; + } + } + return WFSKRN_RESULT_OK; +} + + +// Make dirty. Illegal for non-valid pages. Make MRU or not? +WFSKrnResult BCacheDirty(VolumeInfo *pVolInfo, WFSBlkAdr nAbsBlkAdr) { + dbgb(osTPrintf("BCacheDirty()\n")); + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + if (!pBce) return WFSKRN_RESULT_BCACHE_NOT_FOUND; + if (!(pBce->nState & BCACHE_FLAG_VALID)) return WFSKRN_RESULT_BCACHE_ERROR; + pBce->nState |= BCACHE_FLAG_DIRTY; + if(pBce->nAbsBlkAdr != pBce->nHashBlkAdr){ + WFSKrnResult nResult = BCacheAllocMetaBlk(pVolInfo, pBce->nHashBlkAdr, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED | BCACHE_FLAG_DIRTY, 0); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + } + return WFSKRN_RESULT_OK; +} + + +// Pin a block in memory. Move it from the LRU/MRU list to the pinned list. +WFSKrnResult BCachePin(VolumeInfo *pVolInfo, WFSBlkAdr nAbsBlkAdr) { + dbgb(osTPrintf("BCachePin()\n")); + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + if (!pBce) return WFSKRN_RESULT_BCACHE_NOT_FOUND; + if (!(pBce->nState & BCACHE_FLAG_VALID)) return WFSKRN_RESULT_BCACHE_ERROR; + if (!pBce->nPinCount) { + BCacheGroup *pGroup = pBce->pGroup; + if (!BCacheListDelete(&pGroup->bclLru, pBce)) return WFSKRN_RESULT_BCACHE_ERROR; + if (!BCacheListAddToHead(&pGroup->bclPinned, pBce)) return WFSKRN_RESULT_BCACHE_ERROR; + } + //else{ + // WFSKrnOutputErrorStr("BCacheUnpin: PinCount have to be 0 or 1.\n"); + //} + ++pBce->nPinCount; +#if _DEBUG_BREAK_POINT + if(nAbsBlkAdr == 5693){ + int a; a=0; + } +#endif + return WFSKRN_RESULT_OK; +} + + +// Unpin a block in memory; can be replaced. Make MRU. +WFSKrnResult BCacheUnpin(VolumeInfo *pVolInfo, WFSBlkAdr nAbsBlkAdr) { + dbgb(osTPrintf("BCacheUnpin()\n")); + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + if (!pBce) return WFSKRN_RESULT_BCACHE_NOT_FOUND; + if (!(pBce->nState & BCACHE_FLAG_VALID)) return WFSKRN_RESULT_BCACHE_ERROR; + + if(!pBce->nPinCount){ + WFSKrnOutputErrorStr("BCacheUnpin: PinCount cannot be reduced.\n"); + } else if (pBce->nPinCount == 1) { + BCacheGroup *pGroup = pBce->pGroup; + if (!BCacheListDelete(&pGroup->bclPinned, pBce)) return WFSKRN_RESULT_BCACHE_ERROR; + if (!BCacheListAddToTail(&pGroup->bclLru, pBce)) return WFSKRN_RESULT_BCACHE_ERROR; + } + --pBce->nPinCount; +#if _DEBUG_BREAK_POINT + if(nAbsBlkAdr == 5693){ + int a; a=0; + } +#endif + return WFSKRN_RESULT_OK; +} + + +u32 BCacheGetPinCount(VolumeInfo *pVolInfo, WFSBlkAdr nAbsBlkAdr) { + dbgb(osTPrintf("BCacheGetPinCount()\n")); + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + if (!pBce) return (u32)WFSKRN_RESULT_BCACHE_NOT_FOUND; + if (!(pBce->nState & BCACHE_FLAG_VALID)) return (u32)WFSKRN_RESULT_BCACHE_ERROR; + return pBce->nPinCount; +} + + +// Check to see that the BCache is consistent. +// - check the lists' lengths and pages belong +WFSKrnResult BCacheCheck(void) { + dbgb(osTPrintf("BCacheCheck()\n")); + // check LRU list + u32 nI; + for (nI=0;nIbclLru.pHead; + while (pListNode != NULL) { + BCacheEntry *pBce = (BCacheEntry*) pListNode->pData; + if (!(pBce->nState & BCACHE_FLAG_VALID)) { + dbgb(osTPrintf("BCacheCheck: invalid block (%d) in LRU list\n", PAGE_NUMBER_CE(pBce))); + return WFSKRN_RESULT_BCACHE_ERROR; + } + if (pBce->nPinCount) { + dbgb(osTPrintf("BCacheCheck: pinned block (%d) in LRU list\n", PAGE_NUMBER_CE(pBce))); + return WFSKRN_RESULT_BCACHE_ERROR; + } + pListNode = pListNode->pNext; + nLen++; + } + if (pGroup->bclLru.nLen != nLen) { + dbgb(osTPrintf("BCacheCheck: LRU list length inconsistent, %d != %d\n", bcg.bclLru.nLen, nLen)); + return WFSKRN_RESULT_BCACHE_ERROR; + } + + // check pinned list + nLen = 0; + pListNode = pGroup->bclPinned.pHead; + while (pListNode != NULL) { + BCacheEntry *pBce = (BCacheEntry*) pListNode->pData; + if (!(pBce->nState & BCACHE_FLAG_VALID)) { + dbgb(osTPrintf("BCacheCheck: invalid block (%d) in pinned list\n", PAGE_NUMBER_CE(pBce))); + return WFSKRN_RESULT_BCACHE_ERROR; + } + if (!pBce->nPinCount) { + dbgb(osTPrintf("BCacheCheck: non-pinned block (%d) in pinned list\n", PAGE_NUMBER_CE(pBce))); + return WFSKRN_RESULT_BCACHE_ERROR; + } + pListNode = pListNode->pNext; + nLen++; + } + if (pGroup->bclPinned.nLen != nLen) { + dbgb(osTPrintf("BCacheCheck: pinned list length inconsistent, %d != %d\n", bcg.bclPinned.nLen, nLen)); + return WFSKRN_RESULT_BCACHE_ERROR; + } + + // check invalid list + nLen = 0; + pListNode = pGroup->bclInvalid.pHead; + while (pListNode != NULL) { + BCacheEntry *pBce = (BCacheEntry*) pListNode->pData; + if (pBce->nState & BCACHE_FLAG_VALID) { + dbgb(osTPrintf("BCacheCheck: valid block (%d) in invalid list\n", PAGE_NUMBER_CE(pBce))); + return WFSKRN_RESULT_BCACHE_ERROR; + } + pListNode = pListNode->pNext; + nLen++; + } + if (pGroup->bclInvalid.nLen != nLen) { + dbgb(osTPrintf("BCacheCheck: invalid list length inconsistent, %d != %d\n", bcg.bclInvalid.nLen, nLen)); + return WFSKRN_RESULT_BCACHE_ERROR; + } + + if (pGroup->nNumBlks != (pGroup->bclLru.nLen + pGroup->bclPinned.nLen + pGroup->bclInvalid.nLen)) { + dbgb(osTPrintf("BCacheCheck: missing a block, %d != %d+%d+%d\n", + pGroup->nNumBlks, pGroup->bclLru.nLen, pGroup->bclPinned.nLen, pGroup->bclInvalid.nLen)); + } + } + return WFSKRN_RESULT_OK; +} + + +void* BCachePointer(VolumeInfo *pVolInfo, WFSBlkAdr nAbsBlkAdr) { + dbgb(osTPrintf("BCachePointer()\n")); + BCacheEntry *pBce = BCacheListFind(&bcg.aHashTbl[WFSKRN_BCACHE_HASH_FN(nAbsBlkAdr)], pVolInfo, nAbsBlkAdr); + if (!pBce) { // if already cached + return (void *)WFSKRN_RESULT_BCACHE_NOT_FOUND; + } + BCacheGroup *pGroup = pBce->pGroup; + return pGroup->pBCache + (pGroup->nBlkSize * PAGE_NUMBER_CE(pBce)); +} + +// This must be called at the end of a test program. +// In addition to BCacheCheck(), +// BCacheCheck2() checks if all caches are unpinned. +WFSKrnResult BCacheCheck2(void) +{ + dbgb(osTPrintf("BCacheCheck2()\n")); + // check LRU list + u32 nI; + for (nI=0;nIbclLru.pHead; + while (pListNode != NULL) { + BCacheEntry *pBce = (BCacheEntry*) pListNode->pData; + if (!(pBce->nState & BCACHE_FLAG_VALID)) { + dbgb(osTPrintf("BCacheCheck2: invalid block (%d) in LRU list\n", PAGE_NUMBER_CE(pBce))); + return WFSKRN_RESULT_BCACHE_ERROR; + } + if (pBce->nPinCount) { + dbgb(osTPrintf("BCacheCheck2: pinned block (%d) in LRU list\n", PAGE_NUMBER_CE(pBce))); + return WFSKRN_RESULT_BCACHE_ERROR; + } + if (pBce->nPinCount) + { + osTPrintf("BCacheCheck2: blk %u in LRU list: unexpectedly pinned. (%u)\n", + pBce->nAbsBlkAdr, pBce->nPinCount); + return WFSKRN_RESULT_BCACHE_ERROR; + } + pListNode = pListNode->pNext; + nLen++; + } + if (pGroup->bclLru.nLen != nLen) { + dbgb(osTPrintf("BCacheCheck2: LRU list length inconsistent, %d != %d\n", pGroup->bclLru.nLen, nLen)); + return WFSKRN_RESULT_BCACHE_ERROR; + } + + // check pinned list + nLen = 0; + pListNode = pGroup->bclPinned.pHead; + if (pListNode) + { + pinned = (WFSBool) TRUE; + } + + while (pListNode != NULL) { + BCacheEntry *pBce = (BCacheEntry*) pListNode->pData; + if (!(pBce->nState & BCACHE_FLAG_VALID)) { + dbgb(osTPrintf("BCacheCheck2: invalid block (%d) in pinned list\n", PAGE_NUMBER_CE(pBce))); + return WFSKRN_RESULT_BCACHE_ERROR; + } + if (!pBce->nPinCount) { + dbgb(osTPrintf("BCacheCheck2: non-pinned block (%d) in pinned list\n", PAGE_NUMBER_CE(pBce))); + return WFSKRN_RESULT_BCACHE_ERROR; + } + if (pBce->nPinCount) + { + osTPrintf("BCacheCheck2: blk %u in pinned list: unexpectedly pinned. (%u)\n", + pBce->nAbsBlkAdr, pBce->nPinCount); + // return WFSKRN_RESULT_BCACHE_ERROR; + } + pListNode = pListNode->pNext; + nLen++; + } + if (pinned) + { + return WFSKRN_RESULT_BCACHE_ERROR; + } + + if (pGroup->bclPinned.nLen != nLen) { + dbgb(osTPrintf("BCacheCheck2: pinned list length inconsistent, %d != %d\n", pGroup->bclPinned.nLen, nLen)); + return WFSKRN_RESULT_BCACHE_ERROR; + } + + // check invalid list + nLen = 0; + pListNode = pGroup->bclInvalid.pHead; + while (pListNode != NULL) { + BCacheEntry *pBce = (BCacheEntry*) pListNode->pData; + if (pBce->nState & BCACHE_FLAG_VALID) { + dbgb(osTPrintf("BCacheCheck2: valid block (%d) in invalid list\n", PAGE_NUMBER_CE(pBce))); + return WFSKRN_RESULT_BCACHE_ERROR; + } + /* [check] Should pBce->nPinCount be zero? + if (pBce->nPinCount) + { + osTPrintf("BCacheCheck2: blk %u in invalid list: unexpectedly pinned. (%u)\n", + pBce->nAbsBlkAdr, pBce->nPinCount); + // return WFSKRN_RESULT_BCACHE_ERROR; + } + */ + pListNode = pListNode->pNext; + nLen++; + } + if (pGroup->bclInvalid.nLen != nLen) { + dbgb(osTPrintf("BCacheCheck2: invalid list length inconsistent, %d != %d\n", pGroup->bclInvalid.nLen, nLen)); + return WFSKRN_RESULT_BCACHE_ERROR; + } + + if (pGroup->nNumBlks != (pGroup->bclLru.nLen + pGroup->bclPinned.nLen + pGroup->bclInvalid.nLen)) { + dbgb(osTPrintf("BCacheCheck2: missing a block, %d != %d+%d+%d\n", + pGroup->nNumBlks, pGroup->bclLru.nLen, pGroup->bclPinned.nLen, pGroup->bclInvalid.nLen)); + } + } + return WFSKRN_RESULT_OK; +} + +static u32 GetTotalPinCount() +{ + u32 totalPinCount = 0; + BCacheGroup* pGroup; + BCacheListNode* pListNode; + BCacheEntry* pBce; + + int index; + for (index = 0; index < bcg.nNumGroups; ++index) + { + pGroup = &bcg.aGroup[index]; + pListNode = pGroup->bclPinned.pHead; + + while (pListNode != NULL) + { + pBce = (BCacheEntry*) pListNode->pData; + totalPinCount += pBce->nPinCount; + pListNode = pListNode->pNext; + } + } + + return totalPinCount; +} + +// stop pin count check. +u32 BCacheSkipCheckPin(void) +{ + u32 totalPinCount = GetTotalPinCount(); +#if _DEBUG + bcg.bSkipCheckPin = true; +#endif + return totalPinCount; +} + +// restart pin count check. +WFSKrnResult BCacheStopSkipCheckPin(u32 initialPinCount) +{ + u32 totalPinCount = GetTotalPinCount(); +#if _DEBUG + bcg.bSkipCheckPin = false; +#endif + if (totalPinCount == initialPinCount) + { + return WFSKRN_RESULT_OK; + } + BCacheDumpPinCount(); + return WFSKRN_RESULT_FATAL_ERROR; // Pin counts are inconsistent. +} + +u32 BCacheDumpPinCount(void) +{ + u32 totalPinCount = 0; + BCacheGroup* pGroup; + BCacheListNode* pListNode; + BCacheEntry* pBce; + + int index; + for (index = 0; index < bcg.nNumGroups; ++index) + { + pGroup = &bcg.aGroup[index]; + pListNode = pGroup->bclPinned.pHead; + + while (pListNode != NULL) + { + pBce = (BCacheEntry*) pListNode->pData; + osTPrintf("Addr %d, PC %d\n", pBce->nAbsBlkAdr, pBce->nPinCount); + totalPinCount += pBce->nPinCount; + pListNode = pListNode->pNext; + } + } + return totalPinCount; +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_BitField.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_BitField.cpp new file mode 100644 index 0000000..4651b49 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_BitField.cpp @@ -0,0 +1,477 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_BitField.cpp - functions for manipulating bitfields within bit arrays + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_BitField.cpp,v $ + Revision 1.4 2008/12/22 08:57:15 ueno + Fixed WfsSetBitField() when 32 < nNumBits. + + Revision 1.3 2008/07/17 22:45:41 paul + fixed a performance problem + + Revision 1.2 2008/05/10 03:59:43 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.4 2008/04/19 05:51:14 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.3 2008/04/04 20:54:35 paul + Added WfsSetBitField, WfsTestAndSetBitField (used by dir check code to map coverage of used and free parts of block) + + Revision 1.2 2008/02/28 06:32:02 kondo_masahiro + Fixed code to accept PPC compiler + + Revision 1.1 2007/12/27 11:14:47 paul + Most of this is not used at the moment.. but I'll leave it here for now + + *---------------------------------------------------------------------------*/ + +#include "wfskrn_BitField.h" +#include "wfskrn_Platform.h" + +#ifdef _DEBUG + #define _BITFIELD_NUM_TESTS 10000 +#else + #define _BITFIELD_NUM_TESTS 10000 +#endif + +#define BITFIELD_MASK ((1<=16; nVal>>=4) { + nRet+=4; + } + return (u8)( nRet + aBitTbl[nVal] ); +} + +unsigned WfsReadBitField(unsigned *aBitArray, int nStartBit, int nNumBits) { + // Masking should be performed by the caller + unsigned *pBitArray = &aBitArray[nStartBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + int nShift=BITS_PER_INT-(nStartBit&BIT_OFFSET_MASK)-nNumBits; + if (nShift>0) { + return (pBitArray[0]>>nShift); + } else { + if (nShift==0) { + return pBitArray[0]; + } else { + return pBitArray[1]>>(BITS_PER_INT+nShift) | pBitArray[0]<<(-nShift); + } + } +} + + +#if BITFIELD_USE_TEMPLATES +template +unsigned WfsReadBitField (unsigned *aBitArray, int nStartBit) { + unsigned *pBitArray = &aBitArray[nStartBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + int nShift=BITS_PER_INT-(nStartBit&BIT_OFFSET_MASK)-nNumBits; + if (nShift>0) { + return (pBitArray[0]>>nShift) & BITFIELD_MASK; + } else { + if (nShift==0) { + return pBitArray[0] & BITFIELD_MASK; + } else { + return (pBitArray[1]>>(BITS_PER_INT+nShift) | pBitArray[0]<<(-nShift)) & BITFIELD_MASK; + } + } +} +#endif //BITFIELD_USE_TEMPLATES + + +void WfsOverwriteBitField(unsigned *aBitArray, int nStartBit, unsigned nValue, int nNumBits, unsigned nMask) { + unsigned *pBitArray = &aBitArray[nStartBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + int nShift=BITS_PER_INT-(nStartBit&BIT_OFFSET_MASK)-nNumBits; + if (nShift>0) + pBitArray[0] = (pBitArray[0]&~(nMask<>nS1)) | (nValue>>nS1); + int nS2 = BITS_PER_INT+nShift; + pBitArray[1] = (pBitArray[1]&~(nMask< +void WfsOverwriteBitField(unsigned *aBitArray, int nStartBit, int nValue) { + unsigned *pBitArray = &aBitArray[nStartBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + int nShift=BITS_PER_INT-(nStartBit&BIT_OFFSET_MASK)-nNumBits; + if (nShift>0) + pBitArray[0] = (pBitArray[0]&~(BITFIELD_MASK<>nS1)) | (nValue>>nS1); + int nS2 = BITS_PER_INT+nShift; + pBitArray[1] = (pBitArray[1]&~(BITFIELD_MASK<>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned *pCopyTo = &aBitArray[(nBitArrayLength+nNumBits)>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned *pStart = &aBitArray[nBitPos>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned nOldStartWord = *pStart; + unsigned nStartShift = (u32)(nBitPos&BIT_OFFSET_MASK); + unsigned nStartMask = ((unsigned)-1) >> nStartShift; + // Insert right side of value + s32 nValueShift = (s32)(BITS_PER_INT - nStartShift); + *pStart &= nStartMask; + if (nStartShift) { + *pStart |= (nValue<= nShiftLeft) { + if (nTrailingBits > nShiftLeft) { + *pCopyTo = *pCopyFrom< pStart) { + *pCopyTo-- = (pCopyFrom[-1]<>nNumBits); + pCopyFrom--; + } + *pCopyTo-- = pCopyFrom[0]>>nNumBits; + } else { + // Need a special case for no shift right, becuase shift left by 32 does nothing + if ((nBitArrayLength & BIT_OFFSET_MASK)==0) { + pCopyTo--; + pCopyFrom--; + } + while(pCopyFrom >= pStart) { + *pCopyTo-- = *pCopyFrom--; + } + *pCopyTo = 0; + } + // Insert left side of value + *pStart |= nOldStartWord & ~nStartMask; + nValueShift -= nNumBits; + if (nValueShift > 0) { + *pStart |= nValue<>-nValueShift; + } +} + +void WfsBitArrayDeleteBitField(unsigned *aBitArray, int nBitArrayLength, int nBitPos, int nNumBits) { + unsigned *pCopyStart = &aBitArray[ nBitPos >>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned nOldCopyStart = *pCopyStart & ~(((unsigned)-1)>>(nBitPos&BIT_OFFSET_MASK)); + unsigned nFromBit = (u32)(nBitPos+nNumBits); + unsigned *pCopyFrom = &aBitArray[nFromBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned *pCopyTo = pCopyStart; + unsigned *pCopyEnd = &aBitArray[(nBitArrayLength-nNumBits)>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned nShiftLeft = (u32)(nNumBits & BIT_OFFSET_MASK); + unsigned nShiftRight = BITS_PER_INT - nShiftLeft; + *pCopyFrom &= (((unsigned)-1) >> (nFromBit&BIT_OFFSET_MASK)); + if (pCopyTo == pCopyFrom) { + while(pCopyTo <= pCopyEnd) { + pCopyTo[0] = (pCopyTo[0]<>nShiftRight); + pCopyTo++; + } + } else { + if (nShiftLeft) { + if ((((pCopyFrom-pCopyTo)*BITS_PER_INT) + nShiftLeft) > nNumBits) { + *pCopyTo++ = pCopyFrom[0]>>nShiftRight; + } + while(pCopyTo <= pCopyEnd) { + pCopyTo[0] = (pCopyFrom[0]<>nShiftRight); + pCopyTo++; pCopyFrom++; + } + } else { + while(pCopyTo <= pCopyEnd) { + *pCopyTo++ = *pCopyFrom++; + } + } + } + *pCopyStart |= nOldCopyStart; +} + +void WfsSetBitField(unsigned *aBitArray, int nStartBit, int nNumBits) { + unsigned *pBitArray = &aBitArray[nStartBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned nEndBit = (unsigned)(nStartBit + nNumBits - 1); + unsigned *pEnd = &aBitArray[nEndBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned nLeftShift = nStartBit&BIT_OFFSET_MASK; + unsigned nRightShift= (nEndBit&BIT_OFFSET_MASK)^BIT_OFFSET_MASK; + if (pBitArray == pEnd) { + *pBitArray |= (((unsigned)-1)<>nRightShift); + } else { + *pBitArray |= ((u32)-1)<= BITS_PER_INT) { + *(++pBitArray) = ((u32)-1); + nNumBits -= BITS_PER_INT; + } + *(++pBitArray) |= ((u32)-1)>>nRightShift; + } +} + +unsigned WfsTestAndSetBitField(unsigned *aBitArray, int nStartBit, int nNumBits) { + unsigned *pBitArray = &aBitArray[nStartBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned nEndBit = (unsigned)(nStartBit + nNumBits - 1); + unsigned *pEnd = &aBitArray[nEndBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned nLeftShift = nStartBit&BIT_OFFSET_MASK; + unsigned nRightShift= (nEndBit&BIT_OFFSET_MASK)^BIT_OFFSET_MASK; + unsigned nTest; + if (pBitArray == pEnd) { + nTest = *pBitArray & (((unsigned)-1)<>nRightShift); + *pBitArray |= (((unsigned)-1)<>nRightShift); + } else { + nTest = *pBitArray & (((u32)-1)<>nRightShift); + *pBitArray |= ((u32)-1)>>nRightShift; + } + return nTest; +} + +void WfsBitFieldCopy(unsigned *aDstBitArray, int nDstOffset, unsigned *aSrcBitArray, int nSrcOffset, int nCopyLength) { + unsigned *pDstStart = &aDstBitArray[ nDstOffset>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned *pSrcStart = &aSrcBitArray[ nSrcOffset>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned nDstEndBit = (u32)(nDstOffset + nCopyLength - 1); + unsigned *pDstEnd = &aDstBitArray[nDstEndBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]; + unsigned nOldDstStart = *pDstStart; + unsigned nOldDstEnd = *pDstEnd; + int nShift = (nDstOffset&BIT_OFFSET_MASK) - (nSrcOffset&BIT_OFFSET_MASK); + unsigned nShiftRight = (u32)(nShift & BIT_OFFSET_MASK); + unsigned nShiftLeft = BITS_PER_INT - nShiftRight; + if (nShift<0) { + if (pDstStart <= pSrcStart) { + unsigned *pDst = pDstStart; + unsigned *pSrc = pSrcStart; + while(pDst <= pDstEnd) { + pDst[0] = (pSrc[0]<>nShiftRight); + pDst++; pSrc++; + } + } else { + unsigned *pDst = pDstEnd; + unsigned *pSrc = pSrcStart+(pDstEnd-pDstStart); + while(pDst >= pDstStart) { + pDst[0] = (pSrc[0]<>nShiftRight); + pDst--; pSrc--; + } + } + } else if (nShift>0) { + if (pDstStart < pSrcStart) { + unsigned *pDst = pDstStart; + unsigned *pSrc = pSrcStart; + while(pDst <= pDstEnd) { + pDst[0] = (pSrc[-1]<>nShiftRight); + pDst++; pSrc++; + } + } else { + unsigned *pDst = pDstEnd; + unsigned *pSrc = pSrcStart+(pDstEnd-pDstStart); + while(pDst >= pDstStart) { + pDst[0] = (pSrc[-1]<>nShiftRight); + pDst--; pSrc--; + } + } + } else { + if (pDstStart < pSrcStart) { + unsigned *pDst = pDstStart; + unsigned *pSrc = pSrcStart; + while(pDst <= pDstEnd) { + *pDst++ = *pSrc++; + } + } else { + unsigned *pDst = pDstEnd; + unsigned *pSrc = pSrcStart+(pDstEnd-pDstStart); + while(pDst >= pDstStart) { + *pDst-- = *pSrc--; + } + } + } + unsigned nDstStartMask = (((unsigned)-1) >>(nDstOffset&BIT_OFFSET_MASK)); + unsigned nDstEndMask = ((((unsigned)-1)>>1)>>(nDstEndBit&BIT_OFFSET_MASK)); + *pDstStart = (*pDstStart & nDstStartMask) | (nOldDstStart & ~nDstStartMask); + *pDstEnd = (*pDstEnd & ~nDstEndMask ) | (nOldDstEnd & nDstEndMask); +} + + +#define BitMask(b) (1<<(BIT_OFFSET_MASK-((b)&BIT_OFFSET_MASK))) +#include "randomlib.h" + +void WfsTestBitFieldModule() { +#if _BITFIELD_NUM_TESTS + int nDstOffset, nSrcOffset, nCopyLength; + unsigned aOldBitArray[8]; + unsigned aNewBitArray[8]; + + s32 nRandomSeed; +#ifdef WIN32 + LARGE_INTEGER sysClock; + QueryPerformanceCounter(&sysClock); + nRandomSeed = ((u32*)&sysClock)[0] ^ ((u32*)&sysClock)[1]; +#else + nRandomSeed = 0x1; +#endif + RandomSetSeedU32((u32)nRandomSeed); + osTPrintf("nRandomSeed=0x%08x\n", nRandomSeed); + + osTPrintf("WfsBitArrayInsertBitField() Test\n"); + int nTest; + for(nTest=1; nTest<=_BITFIELD_NUM_TESTS; nTest++) { + //for(unsigned nI=0; nI<8; nI++) { aOldBitArray[nI] = 0xFFFFFFFF; } //RandomU32(); } + unsigned nI; + for(nI=0; nI<8; nI++) { aOldBitArray[nI] = RandomU32(); } + int nNumBits = RandomInt(1, 32); + int nBitArrayLength = RandomInt(0, 256-nNumBits); + int nInsertBit = RandomInt(0, nBitArrayLength); + unsigned nValue = RandomU32(); + nValue >>= (32-nNumBits); + aOldBitArray[(nBitArrayLength-1)>>BIT_OFFSET_TO_INT_OFFSET_SHIFT] |= BitMask(nBitArrayLength); + int nBit; + for(nBit=nBitArrayLength; nBit<256; nBit++) { + aOldBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT] &= ~BitMask(nBit); + } + for(nI=0; nI<8; nI++) { aNewBitArray[nI] = aOldBitArray[nI]; } //RandomU32(); } + WfsBitArrayInsertBitField(aNewBitArray, nBitArrayLength, nInsertBit, nNumBits, nValue); + for(nBit=0; nBit>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit)) != + (aNewBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit))) { + osTPrintf("ERROR! Test:%d Mismatch before insertion point at bit %02X\n", nTest, nBit); + goto Error; + } + } + for(; nBit>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit))==0) ^ + ((nValue&(1<<(nNumBits-1-(nBit-nInsertBit))))==0)) { + osTPrintf("ERROR! Test:%d Mismatch in inserted Value at bit %02X:%02x\n", nTest, nBit, nNumBits-1-(nBit-nInsertBit)); + goto Error; + } + } + for(; nBit<256; nBit++) { + if (((aOldBitArray[(nBit-nNumBits)>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit-nNumBits))==0) ^ + ((aNewBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit))==0)) { + osTPrintf("ERROR! Test:%d Mismatch after insertion point at bit %02x:%02x\n(aOldBitArray[%d] & %08x = %08x)\n(aNewBitArray[%d] & %08x = %08x)\n", + nTest, nBit, nBit-nNumBits, + (nBit-nNumBits)>>BIT_OFFSET_TO_INT_OFFSET_SHIFT, BitMask(nBit-nNumBits), + (aOldBitArray[(nBit-nNumBits)>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit-nNumBits)), + nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT, BitMask(nBit), + (aNewBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit))); + goto Error; + } + } + } + + osTPrintf("WfsDeleteBitField() Test\n"); + for(nTest=1; nTest<=_BITFIELD_NUM_TESTS; nTest++) { + unsigned nI; + for(nI=0; nI<8; nI++) { aOldBitArray[nI] = RandomU32(); } + int nBitArrayLength = RandomInt(0, 256); + int nDeleteStartBit = RandomInt(0, nBitArrayLength-1); + int nDeleteNumBits = RandomInt(1, 96); + if (nDeleteNumBits >(nBitArrayLength-nDeleteStartBit)) { + nDeleteNumBits = nBitArrayLength-nDeleteStartBit; + } + int nBit; + for(nBit=nBitArrayLength; nBit<256; nBit++) { + aOldBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT] &= ~BitMask(nBit); + } + for(nI=0; nI<8; nI++) { aNewBitArray[nI] = aOldBitArray[nI]; } + WfsBitArrayDeleteBitField(aNewBitArray, nBitArrayLength, nDeleteStartBit, nDeleteNumBits); + for(nBit=0; nBit>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit)) != + (aNewBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit))) { + osTPrintf("ERROR! Test:%d Mismatch at bit %02X\n", nTest, nBit); + goto Error; + } + } + nBit += nDeleteNumBits; + for(; nBit>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit-nDeleteNumBits))==0) ^ + ((aOldBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit))==0)) { + osTPrintf("ERROR! Test:%d Mismatch between bits %02x:%02x\n(aOldBitArray[%d] & %08x = %08x)\n(aNewBitArray[%d] & %08x = %08x)\n", + nTest, nBit, nBit-nDeleteNumBits, + (nBit-nDeleteNumBits)>>BIT_OFFSET_TO_INT_OFFSET_SHIFT, BitMask(nBit-nDeleteNumBits), + (aOldBitArray[(nBit-nDeleteNumBits)>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit-nDeleteNumBits)), + nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT, BitMask(nBit), + (aNewBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit))); + goto Error; + } + } + } + + osTPrintf("WfsBitFieldCopy() Test\n"); + for(nTest=1; nTest<=_BITFIELD_NUM_TESTS; nTest++) { + unsigned nI; + for(nI=0; nI<8; nI++) { aOldBitArray[nI] = RandomU32(); } + nDstOffset = RandomInt(0, 255); + nSrcOffset = RandomInt(0, 255); + int nMaxLength = 256 - max(nSrcOffset, nDstOffset); + nCopyLength = RandomInt(1, nMaxLength); + int nBit; + /*for(nBit=nBitArrayLength; nBit<256; nBit++) { + aOldBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT] &= ~BitMask(nBit); + }*/ + for(nI=0; nI<8; nI++) { aNewBitArray[nI] = aOldBitArray[nI]; } + WfsBitFieldCopy(aNewBitArray, nDstOffset, aNewBitArray, nSrcOffset, nCopyLength); + for(nBit=0; nBit>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit)) != + (aNewBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit))) { + osTPrintf("ERROR! Test:%d Mismatch at bit %02X\n", nTest, nBit); + goto WfsBitFieldCopyError; + } + } + for(; nBit>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nSrcBit))==0) ^ + ((aNewBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit))==0)) { + osTPrintf("ERROR! Test:%d Mismatch at bit %02X\n", nTest, nBit); + goto WfsBitFieldCopyError; + } + } + for(; nBit<256; nBit++) { + if ((aOldBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit)) != + (aNewBitArray[nBit>>BIT_OFFSET_TO_INT_OFFSET_SHIFT]&BitMask(nBit))) { + osTPrintf("ERROR! Test:%d Mismatch at bit %02X\n", nTest, nBit); + goto WfsBitFieldCopyError; + } + } + } + return; +WfsBitFieldCopyError:; + osTPrintf("WfsBitFieldCopy(New, nDstOffset=%02x, Src, nSrcOffset=%02x, nCopyLength=%02x)\n", nDstOffset, nSrcOffset, nCopyLength); + goto Error; +Error:; + unsigned nI; + osTPrintf("Old: "); for(nI=0; nI<8; nI++) { osTPrintf("%08x", aOldBitArray[nI]); } osTPrintf("\n"); + osTPrintf("New: "); for(nI=0; nI<8; nI++) { osTPrintf("%08x", aNewBitArray[nI]); } osTPrintf("\n"); + osTPrintf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f \n"); + osTPrintf(" 048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c048c\n"); +#endif +} + +// nStartBit = 9 +// nBitArrayLength = 45 +// nNumGapBits = 18 +// nBitArrayLength - nNumGapBits = 36 +// pStart = &aBitArray[0] +// pCopyTo = &aBitArray[1] +// pCopyFrom = &aBitArray[1] diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Dir.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Dir.cpp new file mode 100644 index 0000000..1922bda --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Dir.cpp @@ -0,0 +1,4439 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Dir.cpp + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Dir.cpp,v $ + Revision 1.43 2008/12/03 00:07:34 kondo_masahiro + Removed a function _qsort(). + + Revision 1.42 2008/11/26 01:41:34 kondo_masahiro + Fixed arguments of several functions in order to improve access speed. + + Revision 1.41 2008/11/10 02:18:37 kondo_masahiro + Fixed DirResize() + + Revision 1.40 2008/11/05 04:45:32 kondo_masahiro + Fixed the end of line made to newline. + + Revision 1.39 2008/11/04 00:21:44 kondo_masahiro + Added DirSbaAllocAndRegistSubBlk() + + Revision 1.38 2008/10/30 05:01:36 kondo_masahiro + Fixed DirResize for decrease size + + Revision 1.37 2008/10/30 04:32:42 ueno + Modified for release build. + + Revision 1.36 2008/10/24 04:54:32 kondo_masahiro + Added decrease block process of DirResize. + + Revision 1.35 2008/10/21 09:49:36 kondo_masahiro + Added new function WFSWriteFileAndDiscard + + Revision 1.34 2008/10/17 08:53:52 kondo_masahiro + Added the new MEDIUM size category (40KB-320KB) and fixed a bug about accessing 4GB-2. + + Revision 1.33 2008/10/16 09:30:39 ooizumi + Fixed definitions for debug build. + + Revision 1.32 2008/10/15 00:14:51 kondo_masahiro + Fixed a bug about 4GB-1 + + Revision 1.31 2008/10/14 12:10:59 kondo_masahiro + Fixed a bug in DirResize + + Revision 1.30 2008/10/14 10:26:24 kondo_masahiro + Added codes to access very large size file data + + Revision 1.29 2008/10/10 04:07:01 kondo_masahiro + Fixed a bug in DirResize + + Revision 1.28 2008/10/10 02:11:19 kondo_masahiro + Fixed a bug to access large files + + Revision 1.27 2008/10/10 01:20:37 kondo_masahiro + Fixed a bug in DirResize + + Revision 1.26 2008/10/09 10:58:53 ueno + Commented out debug code. + + Revision 1.25 2008/10/09 04:16:53 kondo_masahiro + Fixed member of AreaHdr and AreaInfo + + Revision 1.24 2008/10/08 23:19:54 kondo_masahiro + Added codes to access large size file data + + Revision 1.23 2008/10/08 08:33:44 ueno + Moved debug code to be able to test access list directory. + + Revision 1.22 2008/10/03 08:37:56 kondo_masahiro + Fixed codes for porting IOP + + Revision 1.21 2008/09/28 23:31:51 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.20 2008/09/02 07:04:45 kondo_masahiro + added qsort for IOP compiler. + + Revision 1.19 2008/08/27 23:23:28 ooizumi + Fixed newline to CR+LF(Windows format). + + Revision 1.18 2008/08/27 09:37:02 paul + Started coding for different size categories + + Revision 1.17 2008/08/26 08:04:01 ooizumi + Fixed a bug in DirReinitBlk. The update counter value must be kept even after re-initialization. + + Revision 1.16 2008/08/05 04:07:27 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.15 2008/07/29 19:00:08 paul + Fixed a bug in DirNodeBlkSplit() + + Revision 1.14 2008/07/28 21:52:49 paul + Improved updateMap processing. Added DirGetBlk() and DirUnpinAndFreeBlk(). + + Revision 1.13 2008/07/25 02:51:28 paul + Changed from nTransIdx to *pTransInfo + + Revision 1.12 2008/07/17 22:46:40 paul + Fixed DirResizeFile() to use block cache. + + Revision 1.11 2008/07/17 05:32:08 kondo_masahiro + Fixed codes for porting IOP. + + Revision 1.10 2008/07/09 00:29:35 paul + Changes to make directory code work with block cache. + + Revision 1.9 2008/06/09 17:29:06 paul + Minor changes + + Revision 1.8 2008/05/27 18:43:55 paul + Made utf8 variable definitions more consistent, and use (unsigned) for comparisons + + Revision 1.7 2008/05/20 00:06:11 paul + Fixed a bug in DirResizeFile + + Revision 1.6 2008/05/19 17:07:26 paul + Fixed bugs in DirLeafSplit, DirResizeFile + + Revision 1.5 2008/05/17 04:14:07 paul + Fixed a bug in DirLeafCompact / DirNodeCompact + + Revision 1.4 2008/05/12 19:08:51 paul + Replaced some calls to DirNodeStackFree with calls to DirItrClose + + Revision 1.3 2008/05/10 03:59:44 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.2 2008/04/25 17:29:42 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.21 2008/04/22 21:06:23 paul + Changed API to some functions a little, and moved DirFind* to a separate file + + Revision 1.20 2008/04/19 05:51:03 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.19 2008/04/18 02:10:59 paul + Fixed DirNext to update pName->nLen + + Revision 1.18 2008/04/18 01:31:27 paul + Removed wfskrn_Permission.h + + Revision 1.17 2008/04/18 00:08:22 paul + Changed interface to Dir functions + + Revision 1.16 2008/04/15 22:19:55 paul + Implemented the resize-in-place case for sub nodes of Leaf blocks in DirDelete. Fixed a bug in DirLeafCompact. + + Revision 1.15 2008/04/15 18:33:53 paul + Changed the method for finding an internal node in DirFind: Insead of using splitter name search, use normal name search, but stop as soon as the requested depth is reached. Changed DirDelete to use this method and fixed a bug in DirDelete. Changed DirLeafCompact to match DirNodeCompact and provide the functionality to resize one node and delete another node while compacting - this is needed to guarantee DirLeafMergeSubBlkWithItsSingleChild always works provided the result can fit within a block. + + Revision 1.14 2008/04/14 17:07:40 paul + Added block splitting to DirDelete when necessary. Cleaned up DirFind, and ensured it calculates correct nStrIdx during node traversal so that DirConstructEntryNameFromNodeStack can be used on splitters. + + Revision 1.13 2008/04/09 18:20:20 paul + Added DirNodeCompact and cleaned up DirLeafCompact + + Revision 1.12 2008/04/08 00:22:33 paul + Implemented some unfinished cases for Delete + + Revision 1.11 2008/04/04 23:46:18 paul + Implemented Delete. There are some unfinished cases, but it is mostly complete. + + Revision 1.10 2008/03/07 01:36:52 paul + Changed DirFind to have a special mode for prefix searches (used to implement wildcard pattern search) DIR_PREFIX_SEARCH. + + Revision 1.9 2008/02/28 06:31:56 kondo_masahiro + Fixed code to accept PPC compiler + + Revision 1.8 2008/02/27 09:39:34 paul + Removed unnecessary params from DirFindNext. Added a stub for DirDelete + + Revision 1.7 2008/02/27 07:25:15 paul + Added code to check intra block offsets, fixed a bug in DirFind + + Revision 1.6 2008/02/27 00:36:22 paul + Many bug-fixes + + Revision 1.5 2008/02/21 04:31:58 paul + Moved DirNodeStack functions to wfskr_DirNodeStack.cpp + + Revision 1.4 2008/02/21 00:48:26 paul + Moved test code to wfskrn_DirTest.cpp + + Revision 1.3 2008/02/21 00:14:38 paul + Moved SubBlk allocation code from this file to wfskrn_SubBlkAlloc.cpp, and made it more generic so it could be used for multiple metadata block types + + Revision 1.2 2008/02/20 08:04:38 paul + Many changes. Currently debugging multi-block insert code + + Revision 1.1 2007/12/27 11:20:03 paul + still at an early stage of development. Allows filenames to be added to a single leaf block. Now working on DirLeafBlkSplit() function. + + *---------------------------------------------------------------------------*/ + +#undef _KRN_FILE_ +#define _KRN_FILE_ "Dir" + +#include "wfskrn_Dir.h" +#include "wfskrn_DirRxTree.h" +#include "wfskrn_DirFind.h" +#include "wfskrn_DirNodeStack.h" +#include "wfskrn_Area.h" +#include "wfskrn_BitField.h" +#include "wfskrn_Heap.h" +#include "wfskrn_Api.h" +#include "wfskrn_Permission_AccessList.h" +#include "wfskrn_Mutex.h" +#include "wfskrn_Utils.h" + +#undef dbg +#if _DEBUG_DIR + #define dbg(s) s +#else + #define dbg(s) +#endif + +#if _DEBUG_DIR + #if !_WIN32 + u32 nDirTest = 0; + u32 nDirTestBreakPoint = 0; + #endif +#endif + + +#define DIR_MAX_SPLIT_BLK_ALLOC ((DIR_MAX_BLK_DEPTH-1)*2) + +// Algorithm: Macro-structure is a B-Tree, with a node per disk-block. Uses a Radix Tree (Trie) within each block. +// * Leaf blocks contain a lexicographically sorted list of string key fields, and associated file records. +// Only leaf blocks can contain file records. +// * Internal node blocks contain a lexicographically sorted list of string splitter fields, and point to leaf blocks. +// In both leaf nodes and internal nodes, the sorted lists of strings are represented as radix trees. +// +// Algorithm for inserting names into the directory: +// * Traverse 0 or more internal nodes comparing against splitters to determine the correct leaf node for insertion. +// * Traverse the leaf node to determine the correct point of insertion. +// * Perform the insertion to the leaf node, splitting it first if neccessary. +// If a split is required: +// * copy the first half and second half of the leaf respectively to two new nodes, then delete the original leaf. +// * Add a splitter to the parent node, or create a new parent node if none exists. +// * If adding the splitter causes the parent node to become full, then split it first and repeat recursively. +// * Internal nodes are not split on the way down like some B-Tree algorithms. +// since it is not easy to determine when a split would be required due to variable sized nodes. +// 2. Deleting names from a directory: +// * +// +// In order to be able to insert an internal node, we need be able to get to the node. + +// ToDo: We need a fast way to determine the longest filename, and the longest sub-path of any of directory. +// This should be stored in each directory and updated as needed. +// If a filename is shortened, or a file is deleted, we need a way to update its parent directory and +// all ancestor directories if necessary - we'd like to find the next longest sub-path quickly. +// - is it necessary to update all parent directories? +// Needs more thought.. + +u32 DirLeafGetSubBlkLog2Size_2(u32 nStrLen, u32 nNumEntries) { + u32 nNumBytesRequired = sizeof(DirSubBlkHdr)-1 + nStrLen + (nNumEntries*3); + u32 nLog2Size = WfsCalculateFieldSizeInBits(nNumBytesRequired-1); + if (nLog2Size < SBA_MIN_LOG2_SUB_BLK_SIZE) { + nLog2Size = SBA_MIN_LOG2_SUB_BLK_SIZE; + } + return nLog2Size; +} + + +u32 DirNodeGetSubBlkLog2Size_3(u32 nStrLen, u32 nNumEntries, utf8 cFirstChoice) { + u32 nNumBytesRequired = sizeof(DirSubBlkHdr)-1 + nStrLen + (nNumEntries*3); + if (cFirstChoice == 0) { + // Nodes require 2 extra bytes for nodes containing a 0 (string terminator) choice. + // This is because the pointer for the 0 case is a 4 byte Block pointer instead of a 2-byte intra-block pointer. + nNumBytesRequired += sizeof(WFSBlkAdr) - sizeof(WFSIntraBlkOfs); + } + u32 nLog2Size = WfsCalculateFieldSizeInBits(nNumBytesRequired-1); + if (nLog2Size < SBA_MIN_LOG2_SUB_BLK_SIZE) { + nLog2Size = SBA_MIN_LOG2_SUB_BLK_SIZE; + } + return nLog2Size; +} + + +// Indirect blocks contain pointers to large (512KB) data blocks, plus 8 sets of hash codes per 512KB block. +// So the amount of data per pointer to 512KB block is: 4 byte Pointer + (8 * 20 byte hash code) == 164 bytes. +// Each 8KB Block can contain: (49 * 164) + 156 == 8192 bytes. (The header must be at least 24 Bytes, which is true). +// A max size 4GB file == 2048 * 512KB. +// So it takes 8192/49 == 168 indirect blocks of 8KB each to cover 4GB. + +u32 DirCalculateAttrSubBlkLog2Size(AreaInfo *pAreaInfo, u32 nAllocSize, u32 nNameLen, u8 *pSizeCategory) { + // This function calculates the size of the attribute sub-block necessary to store a file of the given size + // There are 4 size categories: 0B <= Small <= 964B < Medium <= 320KB < Large <= 2560KB < Very Large < 4GB + + // Arguments: + // pAreaInfo [In] .. A pointer to the AreaInfo struct for the area which contains/will contain the file + // nAllocSize [In] .. The size of the file upon which to base the calculations + // nNameLen [In] .. The Length of the file name in bytes + // pSizeCategory [Out] .. A pointer to a u32 variable which will be overwritten with flags indicating the block size & indirection level of the file + // Returns the log base 2 of the size of the sub-block needed to store the file attributes. + + //u32 nTotalSize = sizeof(DirEntryAttrHdr)-1 + (((nNameLen+31)>>5)<<2); // A bit per character of the name to represent upper/lower case + u32 nTotalSize = (u32)(&((DirEntryAttrHdr*)0)->aCaseBitArray) + ((nNameLen+7)>>3); // A bit per character of the name to represent upper/lower case + if (nAllocSize <= (1<nBlkSize - 1)>>pAreaInfo->ah.nLog2BlkSize; + // Note: This calculation needs to work with maximum file size = 4294967295 + u32 nNumSmallBlks = ((nAllocSize-1)>>pAreaInfo->ah.nLog2BlkSize)+1; + if (nNumSmallBlks >= (1 << (WFS_LOG2_MAX_FILE_SIZE-pAreaInfo->ah.nLog2BlkSize))){ + nNumSmallBlks = 1 << (WFS_LOG2_MAX_FILE_SIZE-pAreaInfo->ah.nLog2BlkSize); + } + if (nNumSmallBlks <= DIR_ENTRY_ATTR_MAX_SMALL_BLK_PTRS) { + *pSizeCategory = FILE_SIZE_CATEGORY_SMALL; + nTotalSize += nNumSmallBlks * (sizeof(WFSBlkAdr) + sizeof(WFSHashCode)); + } else { + u32 nNumMediumBlks = ((nNumSmallBlks - 1) >> pAreaInfo->nLog2BlksPerMediumBlk) + 1; + if(nNumMediumBlks <= DIR_ENTRY_ATTR_MAX_MEDIUM_BLK_PTRS){ + *pSizeCategory = FILE_SIZE_CATEGORY_MEDIUM; + nTotalSize += nNumMediumBlks * (sizeof(WFSBlkAdr) + sizeof(WFSHashCode)); + } else { + u32 nNumLargeBlks = ((nNumMediumBlks - 1) >> pAreaInfo->nLog2MediumBlkPerLargeBlk) + 1; + //u32 nNumLargeBlks = ((nNumSmallBlks - 1) >> pAreaInfo->nLog2BlksPerLargeBlk) + 1; + if (nNumLargeBlks <= DIR_ENTRY_ATTR_MAX_LARGE_BLK_PTRS) { + *pSizeCategory = FILE_SIZE_CATEGORY_LARGE; + nTotalSize += nNumLargeBlks * pAreaInfo->nLargeBlkPtrSize; // (sizeof(WFSBlkAdr) + (sizeof(WFSHashCode) * pAreaInfo->nNumHashCodesPerLargeBlk)); + } else { + *pSizeCategory = FILE_SIZE_CATEGORY_VERY_LARGE; + u32 nNumIndirectBlks = (nNumLargeBlks - 1) / pAreaInfo->nNumLargeBlkPtrsPerBlk + 1; + nTotalSize += nNumIndirectBlks * sizeof(WFSBlkAdr); + } + } + } + } + u32 nLog2Size = WfsCalculateFieldSizeInBits(nTotalSize-1); + if (nLog2Size < SBA_MIN_LOG2_SUB_BLK_SIZE) { + nLog2Size = SBA_MIN_LOG2_SUB_BLK_SIZE; + } + return nLog2Size; +} + + +u32 DirCalculateAttrSubBlkLog2SizeUpdateAllocSize(AreaInfo *pAreaInfo, u32 *pAllocSize, u32 nNameLen, u8 *pSizeCategory) { + // This version of the function updates *pAllocSize. + // On entry, *pAllocSize is the minimum number of bytes that must be allocated. + // On exit, *pAllocSize is the maximum number of bytes that can be used without re-allocation. + // (This can be larger than the requested amount because we only allocate power-of-2 chunks within the block, + // or whole numbers of blocks outside the block). + u32 nAttrHdrSize = (u32)(&((DirEntryAttrHdr*)0)->aCaseBitArray) + ((nNameLen+7)>>3); // A bit per character of the name to represent upper/lower case + if (*pAllocSize <= (1<>pAreaInfo->ah.nLog2BlkSize)+1; + if (nNumSmallBlks <= DIR_ENTRY_ATTR_MAX_SMALL_BLK_PTRS) { + *pSizeCategory = FILE_SIZE_CATEGORY_SMALL; + nAttrHdrSize += nNumSmallBlks * (sizeof(WFSBlkAdr) + sizeof(WFSHashCode)); + *pAllocSize = nNumSmallBlks << pAreaInfo->ah.nLog2BlkSize; + } else { + u32 nNumMediumBlks = ((nNumSmallBlks - 1) >> pAreaInfo->nLog2BlksPerMediumBlk) + 1; + if(nNumMediumBlks <= DIR_ENTRY_ATTR_MAX_MEDIUM_BLK_PTRS){ + *pSizeCategory = FILE_SIZE_CATEGORY_MEDIUM; + nAttrHdrSize += nNumMediumBlks * (sizeof(WFSBlkAdr) + sizeof(WFSHashCode)); + *pAllocSize = nNumMediumBlks << pAreaInfo->ah.nLog2MediumBlkSize; + } else { + u32 nNumLargeBlks = ((nNumMediumBlks - 1) >> pAreaInfo->nLog2MediumBlkPerLargeBlk) + 1; + //u32 nNumLargeBlks = ((nNumSmallBlks - 1) >> pAreaInfo->nLog2BlksPerLargeBlk) + 1; + if (nNumLargeBlks <= DIR_ENTRY_ATTR_MAX_LARGE_BLK_PTRS) { + *pSizeCategory = FILE_SIZE_CATEGORY_LARGE; + nAttrHdrSize += nNumLargeBlks * pAreaInfo->nLargeBlkPtrSize; // (sizeof(WFSBlkAdr) + pAreaInfo->nNumHashCodesPerLargeBlk*sizeof(WFSHashCode)); + } else { + *pSizeCategory = FILE_SIZE_CATEGORY_VERY_LARGE; + u32 nNumIndirectBlks = (nNumLargeBlks - 1) / pAreaInfo->nNumLargeBlkPtrsPerBlk + 1; + nAttrHdrSize += nNumIndirectBlks * sizeof(WFSBlkAdr); + } + if (nNumLargeBlks >= 1<<(WFS_LOG2_MAX_FILE_SIZE-WFS_LOG2_LARGE_BLK_SIZE)){ + *pAllocSize = (u32)-1; + } else { + *pAllocSize = nNumLargeBlks * pAreaInfo->nLargeBlkSize; + } + } + } + u32 nLog2Size = WfsCalculateFieldSizeInBits(nAttrHdrSize-1); + if (nLog2Size < SBA_MIN_LOG2_SUB_BLK_SIZE) { + nLog2Size = SBA_MIN_LOG2_SUB_BLK_SIZE; + } + return nLog2Size; +} + + +u32 DirCalculateAttrSubBlkLog2SizeDecrease(AreaInfo *pAreaInfo, u32 nAllocSize, u32 nNameLen, u8 *pSizeCategory) { + // This function calculates the size of the attribute sub-block necessary to store a file of the given size + // There are 4 size categories: 0B <= Small <= 964B < Medium <= 320KB < Large <= 2560KB < Very Large < 4GB + + // Arguments: + // pAreaInfo [In] .. A pointer to the AreaInfo struct for the area which contains/will contain the file + // nAllocSize [In] .. The size of the file upon which to base the calculations + // nNameLen [In] .. The Length of the file name in bytes + // pSizeCategory [Out] .. A pointer to a u32 variable which will be overwritten with flags indicating the block size & indirection level of the file + // Returns the log base 2 of the size of the sub-block needed to store the file attributes. + + u32 nTotalSize = (u32)(&((DirEntryAttrHdr*)0)->aCaseBitArray) + ((nNameLen+7)>>3); // A bit per character of the name to represent upper/lower case + u32 nNumSmallBlks = nAllocSize ? ((nAllocSize-1)>>pAreaInfo->ah.nLog2BlkSize)+1 : 1; + if (nNumSmallBlks >= (1 << (WFS_LOG2_MAX_FILE_SIZE-pAreaInfo->ah.nLog2BlkSize))){ + nNumSmallBlks = 1 << (WFS_LOG2_MAX_FILE_SIZE-pAreaInfo->ah.nLog2BlkSize); + } + if (nNumSmallBlks <= DIR_ENTRY_ATTR_MAX_SMALL_BLK_PTRS_DECREASE) { + *pSizeCategory = FILE_SIZE_CATEGORY_SMALL; + nTotalSize += nNumSmallBlks * (sizeof(WFSBlkAdr) + sizeof(WFSHashCode)); + } else { + u32 nNumMediumBlks = ((nNumSmallBlks - 1) >> pAreaInfo->nLog2BlksPerMediumBlk) + 1; + if(nNumMediumBlks <= DIR_ENTRY_ATTR_MAX_MEDIUM_BLK_PTRS_DECREASE){ + *pSizeCategory = FILE_SIZE_CATEGORY_MEDIUM; + nTotalSize += nNumMediumBlks * (sizeof(WFSBlkAdr) + sizeof(WFSHashCode)); + } else { + u32 nNumLargeBlks = ((nNumMediumBlks - 1) >> pAreaInfo->nLog2MediumBlkPerLargeBlk) + 1; + //u32 nNumLargeBlks = ((nNumSmallBlks - 1) >> pAreaInfo->nLog2BlksPerLargeBlk) + 1; + if (nNumLargeBlks <= DIR_ENTRY_ATTR_MAX_LARGE_BLK_PTRS_DECREASE) { + *pSizeCategory = FILE_SIZE_CATEGORY_LARGE; + nTotalSize += nNumLargeBlks * pAreaInfo->nLargeBlkPtrSize; // (sizeof(WFSBlkAdr) + (sizeof(WFSHashCode) * pAreaInfo->nNumHashCodesPerLargeBlk)); + } else { + *pSizeCategory = FILE_SIZE_CATEGORY_VERY_LARGE; + u32 nNumIndirectBlks = (nNumLargeBlks - 1) / pAreaInfo->nNumLargeBlkPtrsPerBlk + 1; + nTotalSize += nNumIndirectBlks * sizeof(WFSBlkAdr); + } + } + } + u32 nLog2Size = WfsCalculateFieldSizeInBits(nTotalSize-1); + if (nLog2Size < SBA_MIN_LOG2_SUB_BLK_SIZE) { + nLog2Size = SBA_MIN_LOG2_SUB_BLK_SIZE; + } + return nLog2Size; +} + + +u32 DirCalculateAttrSubBlkLog2SizeDecreaseUpdateAllocSize(AreaInfo *pAreaInfo, u32 *pAllocSize, u32 nNameLen, u8 *pSizeCategory) { + // This version of the function updates *pAllocSize. + // On entry, *pAllocSize is the minimum number of bytes that must be allocated. + // On exit, *pAllocSize is the maximum number of bytes that can be used without re-allocation. + // (This can be larger than the requested amount because we only allocate power-of-2 chunks within the block, + // or whole numbers of blocks outside the block). + + u32 nAttrHdrSize = (u32)(&((DirEntryAttrHdr*)0)->aCaseBitArray) + ((nNameLen+7)>>3); // A bit per character of the name to represent upper/lower case + u32 nNumSmallBlks = *pAllocSize ? ((*pAllocSize-1)>>pAreaInfo->ah.nLog2BlkSize)+1 : 1; + if (nNumSmallBlks <= DIR_ENTRY_ATTR_MAX_SMALL_BLK_PTRS_DECREASE) { + *pSizeCategory = FILE_SIZE_CATEGORY_SMALL; + nAttrHdrSize += nNumSmallBlks * (sizeof(WFSBlkAdr) + sizeof(WFSHashCode)); + *pAllocSize = nNumSmallBlks << pAreaInfo->ah.nLog2BlkSize; + } else { + u32 nNumMediumBlks = ((nNumSmallBlks - 1) >> pAreaInfo->nLog2BlksPerMediumBlk) + 1; + if(nNumMediumBlks <= DIR_ENTRY_ATTR_MAX_MEDIUM_BLK_PTRS_DECREASE){ + *pSizeCategory = FILE_SIZE_CATEGORY_MEDIUM; + nAttrHdrSize += nNumMediumBlks * (sizeof(WFSBlkAdr) + sizeof(WFSHashCode)); + *pAllocSize = nNumMediumBlks << pAreaInfo->ah.nLog2MediumBlkSize; + } else { + u32 nNumLargeBlks = ((nNumMediumBlks - 1) >> pAreaInfo->nLog2MediumBlkPerLargeBlk) + 1; + //u32 nNumLargeBlks = ((nNumSmallBlks - 1) >> pAreaInfo->nLog2BlksPerLargeBlk) + 1; + if (nNumLargeBlks <= DIR_ENTRY_ATTR_MAX_LARGE_BLK_PTRS_DECREASE) { + *pSizeCategory = FILE_SIZE_CATEGORY_LARGE; + nAttrHdrSize += nNumLargeBlks * pAreaInfo->nLargeBlkPtrSize; // (sizeof(WFSBlkAdr) + pAreaInfo->nNumHashCodesPerLargeBlk*sizeof(WFSHashCode)); + } else { + *pSizeCategory = FILE_SIZE_CATEGORY_VERY_LARGE; + u32 nNumIndirectBlks = (nNumLargeBlks - 1) / pAreaInfo->nNumLargeBlkPtrsPerBlk + 1; + nAttrHdrSize += nNumIndirectBlks * sizeof(WFSBlkAdr); + } + if (nNumLargeBlks >= 1<<(WFS_LOG2_MAX_FILE_SIZE-WFS_LOG2_LARGE_BLK_SIZE)){ + *pAllocSize = (u32)-1; + } else { + *pAllocSize = nNumLargeBlks * pAreaInfo->nLargeBlkSize; + } + } + } + u32 nLog2Size = WfsCalculateFieldSizeInBits(nAttrHdrSize-1); + if (nLog2Size < SBA_MIN_LOG2_SUB_BLK_SIZE) { + nLog2Size = SBA_MIN_LOG2_SUB_BLK_SIZE; + } + return nLog2Size; +} + + +WFSKrnResult DirFindFilePos(DirItr *pDi, WFSFileSize nPos, DirFilePos *pFPos, u32 nTransFlags) { + // This function calculates the block and offset within that block corresponding to a file offset + DirEntryAttrHdr *pAttrHdr = pDi->pAttrHdr; + //pDi->tba = pDi->tba; + //pFPos->nPos = nPos; + //AreaInfo *pAreaInfo = pDi->tba.pAreaInfo; + + u32 nAttrHdrSize = (u32)(&((DirEntryAttrHdr*)0)->aCaseBitArray) + ((pAttrHdr->nNameLen+7)>>3); + + //nTransFlags |= BCACHE_FLAG_PINNED; + + switch(pAttrHdr->nSizeCategory) { + case FILE_SIZE_CATEGORY_VERY_SMALL: { + if (pAttrHdr->file.nSize <= (1<pDataPtr = &pAttrHdr->aCaseBitArray[(pAttrHdr->nNameLen+7)>>3] + nPos; + pFPos->nRemainingBlkSize = (1<dni.nLog2Size) - (pFPos->pDataPtr - (u8*)pAttrHdr); + } + break; + } + case FILE_SIZE_CATEGORY_SMALL: { + AreaInfo *pAreaInfo = pDi->tba.pAreaInfo; + u32 nMaxBlkNum = pAttrHdr->file.nSize>>pAreaInfo->ah.nLog2BlkSize; + u32 nPosBlkNum = nPos>>pAreaInfo->ah.nLog2BlkSize; + u32 nPosBlkOfs = nPos%pAreaInfo->nBlkSize; + u8 *pDataBlk; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pAttrHdr, pAttrHdr->nAttrLog2Size, nPosBlkNum); + u16 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + u32 nValidSize = (nMaxBlkNum == nPosBlkNum) ? WFS_ROUND_UP(nPos, pAreaInfo->pVolInfo->pDevInfo->nSectorSize) : pAreaInfo->nBlkSize; + WFSKrnReturnOnError(TransGetAndPinFileBlk(&pDi->tba, pDi->tba.nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, nTransFlags, nValidSize, (void**)&pDataBlk)); + pFPos->pDataPtr = pDataBlk + nPosBlkOfs; + pFPos->nRemainingBlkSize = pAreaInfo->nBlkSize - nPosBlkOfs; + WFSKrnReturnOnError(TransUnpinBlk3(pDi->tba.pAreaInfo, pFileBlkPtr->nBlkAdr, pDi->tba.pTransInfo)); + break; + } + case FILE_SIZE_CATEGORY_MEDIUM: { + AreaInfo *pAreaInfo = pDi->tba.pAreaInfo; + u32 nMaxMedBlkIdx = pAttrHdr->file.nSize>>pAreaInfo->ah.nLog2MediumBlkSize; + u32 nMedBlkIdx = nPos>>pAreaInfo->ah.nLog2MediumBlkSize; + u32 nMedBlkOfs = nPos%pAreaInfo->nMediumBlkSize; + u8 *pDataBlk; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pAttrHdr, pAttrHdr->nAttrLog2Size, nMedBlkIdx); + u16 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + u32 nValidSize = (nMaxMedBlkIdx == nMedBlkIdx) ? WFS_ROUND_UP(nPos, pAreaInfo->pVolInfo->pDevInfo->nSectorSize) : pAreaInfo->nMediumBlkSize; + WFSKrnReturnOnError(TransGetAndPinFileMediumBlk(&pDi->tba, pDi->tba.nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, nTransFlags, nValidSize, (void**)&pDataBlk)); + pFPos->pDataPtr = pDataBlk + nMedBlkOfs; + pFPos->nRemainingBlkSize = pAreaInfo->nMediumBlkSize - nMedBlkOfs; + WFSKrnReturnOnError(TransUnpinBlk3(pDi->tba.pAreaInfo, pFileBlkPtr->nBlkAdr, pDi->tba.pTransInfo)); + break; + } + case FILE_SIZE_CATEGORY_LARGE: { + AreaInfo *pAreaInfo = pDi->tba.pAreaInfo; + u32 nMaxMedBlkIdx = pAttrHdr->file.nSize>>pAreaInfo->ah.nLog2MediumBlkSize; + u32 nMedBlkIdx = nPos>>pAreaInfo->ah.nLog2MediumBlkSize; + u32 nMedBlkOfs = nPos%pAreaInfo->nMediumBlkSize; + u8 *pDataBlk; + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge4(pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, nMedBlkIdx); + u16 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pDi->pBlkHdr; + u32 nValidSize = (nMaxMedBlkIdx == nMedBlkIdx) ? WFS_ROUND_UP(nPos, pAreaInfo->pVolInfo->pDevInfo->nSectorSize) : pAreaInfo->nMediumBlkSize; + WFSKrnReturnOnError(TransGetAndPinFileMediumBlk(&pDi->tba, pDi->tba.nBlkAdr, nHashOfs, fileBlkInfo.nBlkAdr, nTransFlags, nValidSize, (void**)&pDataBlk)); + pFPos->pDataPtr = pDataBlk + nMedBlkOfs; + pFPos->nRemainingBlkSize = pAreaInfo->nMediumBlkSize - nMedBlkOfs; + WFSKrnReturnOnError(TransUnpinBlk3(pDi->tba.pAreaInfo, fileBlkInfo.nBlkAdr, pDi->tba.pTransInfo)); + break; + } + case FILE_SIZE_CATEGORY_VERY_LARGE: { + AreaInfo *pAreaInfo = pDi->tba.pAreaInfo; + u32 nMaxMedBlkIdx = pAttrHdr->file.nSize>>pAreaInfo->ah.nLog2MediumBlkSize; + u32 nMedBlkIdx = nPos>>pAreaInfo->ah.nLog2MediumBlkSize; // 64KB + u32 nMedBlkLocalIdx = nMedBlkIdx%pAreaInfo->nNumMediumBlkPtrsPerBlk; + u32 nMedBlkOfs = nPos%pAreaInfo->nMediumBlkSize; + u8 *pIndirectBlk, *pDataBlk; + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndMedBlkIdxForCategoryVeryLarge(pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, nMedBlkIdx); + WFSKrnReturnOnError(TransGetAndPinBlk5(pDi->tba.pAreaInfo, *pIndirectBlkAdr, pDi->tba.pTransInfo, TRANS_FLAG_READ_BLK, (void**)&pIndirectBlk)); + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoFromIndirectBlkForCategoryVeryLarge(pAreaInfo, pIndirectBlk, nMedBlkLocalIdx); + u16 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pDi->pBlkHdr; + u32 nValidSize = (nMaxMedBlkIdx == nMedBlkIdx) ? WFS_ROUND_UP(nPos, pAreaInfo->pVolInfo->pDevInfo->nSectorSize) : pAreaInfo->nMediumBlkSize; + WFSKrnReturnOnError(TransGetAndPinFileMediumBlk(&pDi->tba, pDi->tba.nBlkAdr, nHashOfs, fileBlkInfo.nBlkAdr, nTransFlags, nValidSize, (void**)&pDataBlk)); + pFPos->pDataPtr = pDataBlk + nMedBlkOfs; + pFPos->nRemainingBlkSize = pAreaInfo->nMediumBlkSize - nMedBlkOfs; + WFSKrnReturnOnError(TransUnpinBlk3(pDi->tba.pAreaInfo, fileBlkInfo.nBlkAdr, pDi->tba.pTransInfo)); + WFSKrnReturnOnError(TransUnpinBlk3(pDi->tba.pAreaInfo, *pIndirectBlkAdr, pDi->tba.pTransInfo)); + break; + } + } +#if _DEBUG_DIR + if (pFPos->nRemainingBlkSize > pDi->tba.pAreaInfo->nBlkSize) { + WFSKrnOutputErrorStr("File Pos Error"); + } +#endif + return WFSKRN_RESULT_OK; +} + +static inline void DirNodeUpdateParentOfsPtr(DirItr *pDi, u16 nNewOfs) { + DirNodeStack *pDns = pDi->dni.pDns; + DirNodeStack *pDnsParent = pDns->pParent; + pDns->nSubBlkOfs = nNewOfs; + if (pDnsParent->nBlkAdr != pDns->nBlkAdr) { + pDi->pBlkHdr->nRootOfs = nNewOfs; + return; + } + DirSubBlkHdr *pSubBlkHdr = (DirSubBlkHdr *)((u8*)pDi->pBlkHdr + pDnsParent->nSubBlkOfs); + DirNodeSetIntraBlkOfs(pDnsParent->nEntryIdx, nNewOfs, pSubBlkHdr); +} + +static inline void DirLeafUpdateParentOfsPtr(DirItr *pDi, u16 nNewOfs) { + DirNodeStack *pDns = pDi->dni.pDns; + DirNodeStack *pDnsParent = pDns->pParent; + pDns->nSubBlkOfs = nNewOfs; + if (pDnsParent->nBlkAdr != pDns->nBlkAdr) { + pDi->pBlkHdr->nRootOfs = nNewOfs; + return; + } + DirSubBlkHdr *pSubBlkHdr = (DirSubBlkHdr *)((u8*)pDi->pBlkHdr + pDnsParent->nSubBlkOfs); + DirLeafSetIntraBlkOfs(pDnsParent->nEntryIdx, nNewOfs, pSubBlkHdr); +} + +inline WFSKrnResult DirUnpinAndFreeBlk(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo) { + // See "Update Counter & Update Map Operations" + PTreeItr pti; + WFSBlkAdr nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + nBlkAdr; + WFSKrnResult nResult = PTreeFind(&dirGlobals.updateMap, &pti, nAbsBlkAdr, &dirGlobals.updateMapAllocator); + if (nResult == WFSKRN_RESULT_PTREE_ENTRY_FOUND) { + u32 *pData = &pti.pLeaf->aData[pti.aEntryIdx[0]]; + *pData = (*pData & ~WFS_MDF_DIR_COUNTER_MASK) | ((*pData + 1) & WFS_MDF_DIR_COUNTER_MASK); + } + return TransUnpinAndFreeBlks(pAreaInfo, pAreaInfo->ah.nLog2BlkSize, 1, &nBlkAdr, pTransInfo); +} + +WFSKrnResult DirGetBlk(DirItr *pDi, u32 nTransFlags, DirBlkHdr **ppBlkHdr) { + // Opens a directory block for modification. + // See "Update Counter & Update Map Operations" + DirBlkHdr *pBlkHdr; + WFSKrnReturnOnError(TransGetBlk(&pDi->tba, nTransFlags, (void**)&pBlkHdr)); + pDi->pBlkHdr = pBlkHdr; + if(ppBlkHdr){ + *ppBlkHdr = pBlkHdr; + } + if (nTransFlags & TRANS_FLAG_WRITE_BLK) { + pDi->nUpdateCtr = (pBlkHdr->sbah.mdh.nFlags + 1) & WFS_MDF_DIR_COUNTER_MASK; + pBlkHdr->sbah.mdh.nFlags = (WFSMetaDataFlags)((pBlkHdr->sbah.mdh.nFlags & ~WFS_MDF_DIR_COUNTER_MASK) | pDi->nUpdateCtr); + PTreeItr pti; + WFSBlkAdr nAbsBlkAdr = pDi->tba.pAreaInfo->nAbsStartBlkAdr + pDi->tba.nBlkAdr; + WFSKrnResult nResult = PTreeFind(&dirGlobals.updateMap, &pti, nAbsBlkAdr, &dirGlobals.updateMapAllocator); + if (nResult == WFSKRN_RESULT_PTREE_ENTRY_FOUND) { + u32 *pData = &pti.pLeaf->aData[pti.aEntryIdx[0]]; + *pData = (*pData & ~WFS_MDF_DIR_COUNTER_MASK) | (pDi->nUpdateCtr & WFS_MDF_DIR_COUNTER_MASK); + } + } else { + pDi->nUpdateCtr = pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_COUNTER_MASK; + } + return WFSKRN_RESULT_OK; +} + +inline void DirReinitBlk(AreaInfo *pAreaInfo, DirBlkHdr *pBlkHdr, WFSMetaDataFlags nFlags) { + u32 nLog2BlkSize = pAreaInfo->ah.nLog2BlkSize; + u32 nUpdateCtr = pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_COUNTER_MASK; + SbaBlkInit(pBlkHdr, nLog2BlkSize, WFS_NUM_BITS_REQUIRED(sizeof(DirBlkHdr))); + pBlkHdr->sbah.mdh.nFlags = (WFSMetaDataFlags)((WFS_MDF_DIR_BLK | nFlags) | nUpdateCtr); +} + +WFSKrnResult DirCreateAndInitNewBlk4(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, WFSMetaDataFlags nFlags, TransInfo *pTransInfo, DirBlkHdr **ppBlkHdr) { + WFSKrnReturnOnError(TransGetAndPinBlk5(pAreaInfo, nBlkAdr, pTransInfo, TRANS_FLAG_WRITE_BLK, (void**)ppBlkHdr)); + DirBlkHdr *pBlkHdr = *ppBlkHdr; + DirReinitBlk(pAreaInfo, pBlkHdr, nFlags); + PTreeItr pti; + WFSBlkAdr nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + nBlkAdr; +#if _DEBUG + WFSKrnResult nResult = PTreeFind(&dirGlobals.updateMap, &pti, nAbsBlkAdr, &dirGlobals.updateMapAllocator); +#else + PTreeFind(&dirGlobals.updateMap, &pti, nAbsBlkAdr, &dirGlobals.updateMapAllocator); // [check] error handling. +#endif + pBlkHdr->sbah.mdh.nFlags = (WFSMetaDataFlags)(pBlkHdr->sbah.mdh.nFlags & ~WFS_MDF_DIR_COUNTER_MASK); +#if _DEBUG + if (nResult == WFSKRN_RESULT_PTREE_ENTRY_FOUND) +#endif + { + pBlkHdr->sbah.mdh.nFlags = (WFSMetaDataFlags)(pBlkHdr->sbah.mdh.nFlags | (pti.nData & WFS_MDF_DIR_COUNTER_MASK)); + } + return WFSKRN_RESULT_OK; +} + +void DirBlkCreateRootNode(DirBlkHdr *pBlkHdr) { + pBlkHdr->nRootOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, SBA_MIN_LOG2_SUB_BLK_SIZE); + DirSubBlkHdr *pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + pBlkHdr->nRootOfs); + pSubBlkHdr->nStrLen = 0; + pSubBlkHdr->nNumEntries = 0; + pSubBlkHdr->aFirstChar[0] = (utf8)0xC1; // invalid utf8 character - to help debug +} + +extern u32 nDebugNumChecks; +WFSKrnResult DirNextRaw(WFSFileName *pName, DirItr *pDi) { + // ToDo: Make this function more compatible with DirFind +#if _DEBUG_DIR_NODE_STACK + bool bOldCheckDirNodeStack = bCheckDirNodeStack; + bCheckDirNodeStack = false; +#endif + WFSKrnResult nResult; + DirNodeItr dni = pDi->dni; + DirBlkHdr *pBlkHdr = pDi->pBlkHdr; + u32 nSubBlkStrLen; + u16 nOfs = 0; + + while(1) { + if (pDi->tba.nBlkAdr != dni.pDns->nBlkAdr) { + TransUnpinBlk(&pDi->tba); + pDi->tba.nBlkAdr = dni.pDns->nBlkAdr; + nResult = DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, &pBlkHdr); + if(nResult < WFSKRN_RESULT_OK){ + goto Done; + } + } + /* + // [check] This debug code will throw exception when pDi is the root directory(?), + // because dni.pDns->pParent is not initialized. + if(dni.pDns->pParent){ + if(dni.pDns != dni.pDns->pParent && dni.pDns->nBlkAdr == dni.pDns->pParent->nBlkAdr && dni.pDns->nSubBlkOfs == dni.pDns->pParent->nSubBlkOfs){ + int a; a=0; + } + } + */ + dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + dni.pDns->nSubBlkOfs); + if (dni.nDnsDepth<=1) { + pDi->dni = dni; + nResult = WFSKRN_RESULT_NOT_FOUND; + goto Done; + } + if (dni.pDns->nEntryIdx < dni.pSubBlkHdr->nNumEntries) { + break; + } + DirPopNodeStackEntry(&dni); + } + u32 nStrIdx = dni.pDns->nStrIdx; + dni.pStrPtr = &pName->sStr[nStrIdx]; + *dni.pStrPtr++ = dni.pSubBlkHdr->aFirstChar[dni.pSubBlkHdr->nStrLen + dni.pDns->nEntryIdx]; + ++dni.pDns->nEntryIdx; + u16 *pOfsTblEnd; + + if (pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK) { + nOfs = DirLeafGetIntraBlkOfs(dni.pDns->nEntryIdx, dni.pSubBlkHdr); + dbg(SbaCheckOfs(nOfs)); + } else { + // traverse internal nodes + dni.nLog2Size = DirNodeGetSubBlkLog2Size(dni.pSubBlkHdr); + u16 *pOfsTblEnd = (u16*)((u8*)dni.pSubBlkHdr + (1<nEntryIdx, dni.pSubBlkHdr, pOfsTblEnd); + dbg(SbaCheckOfs(nOfs)); + while(1) { + dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOfs); + dni.nLog2Size = DirNodeGetSubBlkLog2Size(dni.pSubBlkHdr); + pOfsTblEnd = (u16*)((u8*)dni.pSubBlkHdr + (1<nBlkAdr = pDi->tba.nBlkAdr; + dni.pDns->nSubBlkOfs = nOfs; + dni.pDns->nEntryIdx = 1; + nStrIdx += dni.pSubBlkHdr->nStrLen + 1; + dni.pDns->nStrIdx = (u8)nStrIdx; + if (dni.pSubBlkHdr->aFirstChar[dni.pSubBlkHdr->nStrLen] == 0) { + // We have found the end of the splitter. Change block. + WFSBlkAdr nNewBlkAdr = DirNodeGetBlkAdr_ote(dni.pSubBlkHdr, pOfsTblEnd); + TransUnpinBlk(&pDi->tba); + pDi->tba.nBlkAdr = nNewBlkAdr; + WFSKrnReturnOnError( DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, &pBlkHdr) ); + nOfs = pBlkHdr->nRootOfs; + if (pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK) { +#if (DIR_PREFIX_SUPPRESSION==0) + nStrIdx=0; +#endif + dni.pStrPtr = &pName->sStr[nStrIdx]; + break; + } + } else { + nOfs = DirNodeGetIntraBlkOfs_ote(1, dni.pSubBlkHdr, pOfsTblEnd); + dbg(SbaCheckOfs(nOfs)); + } + } + nStrIdx--; + } + + // traverse leaf node + while(1) { + dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOfs); + nSubBlkStrLen = dni.pSubBlkHdr->nStrLen; + nStrIdx += nSubBlkStrLen + 1; + //utf8 *pSubBlkStrPtr = dni.pSubBlkHdr->aFirstChar; + dni.pNodeStrPtr = dni.pSubBlkHdr->aFirstChar; + while(nSubBlkStrLen--) { + *dni.pStrPtr++ = *dni.pNodeStrPtr++; + } + if (dni.pSubBlkHdr->nNumEntries > 1) { + WFSKrnReturnOnError(DirNodeStackGetEntry(&dni)); + dni.pDns->nBlkAdr = pDi->tba.nBlkAdr; + dni.pDns->nSubBlkOfs = nOfs; + dni.pDns->nEntryIdx = 1; + dni.pDns->nStrIdx = (u8)nStrIdx; + } + utf8 cFirstChoice = *dni.pNodeStrPtr++; + *dni.pStrPtr++ = cFirstChoice; + dni.nLog2Size = DirLeafGetSubBlkLog2Size(dni.pSubBlkHdr); + pOfsTblEnd = (u16*)((u8*)dni.pSubBlkHdr + (1<nLen = dni.pStrPtr - pName->sStr - 1; + pDi->dni = dni; + pDi->pBlkHdr = pBlkHdr; + pDi->dni.pOfs = DirLeafGetIntraBlkOfsPtr_ote(1, pOfsTblEnd); + dbg(SbaCheckOfs(nOfs)); + pDi->pAttrHdr = (DirEntryAttrHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = pDi->pAttrHdr->nAttrLog2Size; + nResult = WFSKRN_RESULT_OK; + goto Done; + } +#if _DEBUG_DIR + if ((nDirTest >= nDirTestBreakPoint) && (pDi->dni.pDns->nSubBlkOfs == 256)) { + int a; a=0; + } +#endif + nOfs = DirLeafGetIntraBlkOfs_ote(dni.pDns->nEntryIdx, pOfsTblEnd); + dbg(SbaCheckOfs(nOfs)); + } +Done: +#if _DEBUG_DIR_NODE_STACK + bCheckDirNodeStack = bOldCheckDirNodeStack; +#endif + return nResult; +} + +static +u16 DirNodePrependStringToSubBlk(DirBlkHdr *pBlkHdr, u16 nOldOfs, const utf8 *pStr, u8 nStrLen, utf8 cJoinChar) { + // A non-Node node is not allowed to end up with exactly 1 child. This function can be used to merge it with the child. + // This function prepends the string pStr followed by cJoinChar to the start of the node specified by pBlkHdr and nOldOfs. + // This function reallocates the node if it grows beyond its existing size. + // It returns the resultant offset address of the updated node, or 0 if allocation fails. + DirSubBlkHdr *pOldSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOldOfs); + u32 nOldLog2Size = DirNodeGetSubBlkLog2Size(pOldSubBlkHdr); + u32 nNewStrLen = (u32)(pOldSubBlkHdr->nStrLen + nStrLen + 1); + u32 nNewLog2Size = DirNodeGetSubBlkLog2Size_3(nNewStrLen, pOldSubBlkHdr->nNumEntries, pOldSubBlkHdr->aFirstChar[pOldSubBlkHdr->nStrLen]); + if (nNewLog2Size == nOldLog2Size) { + memmove(&pOldSubBlkHdr->aFirstChar[nStrLen+1], pOldSubBlkHdr->aFirstChar, (u32)(pOldSubBlkHdr->nStrLen + pOldSubBlkHdr->nNumEntries)); + memcpy(pOldSubBlkHdr->aFirstChar, pStr, nStrLen); + pOldSubBlkHdr->aFirstChar[nStrLen] = cJoinChar; + pOldSubBlkHdr->nStrLen = (u8)nNewStrLen; + return nOldOfs; + } + // The merged node will require more space than the original, so it must be reallocated + u32 nNewNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNewLog2Size); + if (nNewNodeOfs == 0) { + // Could not allocate a larger block + return 0; + } + DirSubBlkHdr *pNewSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nNewNodeOfs); + memcpy(pNewSubBlkHdr->aFirstChar, pStr, nStrLen); // copy includes the terminator + pNewSubBlkHdr->aFirstChar[nStrLen] = cJoinChar; + s32 nNumEntries = pNewSubBlkHdr->nNumEntries = pOldSubBlkHdr->nNumEntries; + memmove(&pNewSubBlkHdr->aFirstChar[nStrLen+1], pOldSubBlkHdr->aFirstChar, (u32)(pOldSubBlkHdr->nStrLen + nNumEntries)); + pNewSubBlkHdr->nStrLen = (u8)nNewStrLen; + u16 *pSrcStart = DirNodeGetIntraBlkOfsPtr_l2s(nNumEntries, pOldSubBlkHdr, nOldLog2Size); + u8 *pSrcEnd = (u8*)pOldSubBlkHdr + (1<nStrLen + nStrLen + 1); + u32 nNewLog2Size = DirLeafGetSubBlkLog2Size_2(nNewStrLen, pOldSubBlkHdr->nNumEntries); + if (nNewLog2Size == nOldLog2Size) { + memmove(&pOldSubBlkHdr->aFirstChar[nStrLen+1], pOldSubBlkHdr->aFirstChar, (u32)(pOldSubBlkHdr->nStrLen + pOldSubBlkHdr->nNumEntries)); + memcpy(pOldSubBlkHdr->aFirstChar, pStr, nStrLen); + pOldSubBlkHdr->aFirstChar[nStrLen] = cJoinChar; + pOldSubBlkHdr->nStrLen = (u8)nNewStrLen; + return (u16)nOldOfs; + } + // The merged node will require more space than the original, so it must be reallocated + u32 nNewNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNewLog2Size); + if (nNewNodeOfs == 0) { + // Could not allocate a larger block + return 0; + } + DirSubBlkHdr *pNewSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nNewNodeOfs); + memcpy(pNewSubBlkHdr->aFirstChar, pStr, nStrLen); // copy includes the terminator + pNewSubBlkHdr->aFirstChar[nStrLen] = cJoinChar; + s32 nNumEntries = pNewSubBlkHdr->nNumEntries = pOldSubBlkHdr->nNumEntries; + memmove(&pNewSubBlkHdr->aFirstChar[nStrLen+1], pOldSubBlkHdr->aFirstChar, (u32)(pOldSubBlkHdr->nStrLen + nNumEntries)); + pNewSubBlkHdr->nStrLen = (u8)nNewStrLen; + u16 *pNewOfsTblEnd = (u16*)((u8*)pNewSubBlkHdr + (1<dni.nDnsDepth; + u32 nDnsDepth = nDnsDepthStart; + while(--nDnsDepth) { + if (pDns->nBlkAdr != nBlkAdr) { + nDnsDepthStart -= nDnsDepth; + break; + } + pDns = pDns->pParent; + } + diSrc.dni.nDnsDepth = 1; + + // Allocate new blocks + WFSKrnReturnOnError(AreaAllocBlks(diSrc.tba.pAreaInfo, nBlkAdr, diSrc.tba.pAreaInfo->ah.nLog2BlkSize, 1, &diDst.tba.nBlkAdr, sizeof(WFSBlkAdr))); + nResult = DirCreateAndInitNewBlk4(diSrc.tba.pAreaInfo, diDst.tba.nBlkAdr, diSrc.pBlkHdr->sbah.mdh.nFlags, diSrc.tba.pTransInfo, &diDst.pBlkHdr); + if(nResult < WFSKRN_RESULT_OK){ + AreaFreeBlks(diSrc.tba.pAreaInfo, diSrc.tba.pAreaInfo->ah.nLog2BlkSize, 1, &diDst.tba.nBlkAdr, sizeof(WFSBlkAdr)); + return nResult; + } + // Initialize a stack frame for traversing the destination block + diDst.dni.nDnsDepth = 0; + nResult = DirNodeStackGetEntry(&diDst.dni); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + diDst.ppDnsRootParent = &diDst.dni.pDns->pParent; + diSrc.dni.nEntryIdx = 1; + diSrc.dni.pOfs = &diSrc.pBlkHdr->nRootOfs; + dbg(SbaCheckOfs(*diSrc.dni.pOfs)); + nResult = DirPushNodeStackEntry(&diSrc.dni, nBlkAdr); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + diSrc.dni.pDns->nStrIdx = 0; // ToDo: This value can be initialized to 0 because prefix-suppression is not implemented + u16 nSrcLeafOfs = diSrc.dni.pDns->nSubBlkOfs; // = diSrc.pBlkHdr->nRootOfs; + utf8 *pChoiceChar; + u32 nRecIdx=0; + diDst.dni.pOfs = &diDst.pBlkHdr->nRootOfs; + u32 nSrcLeafStartDepth = diSrc.dni.nDnsDepth; + + // Perform a depth-first traversal of the block, until the middle leaf sub-block is found. + while(1) { + diSrc.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)diSrc.pBlkHdr + nSrcLeafOfs); + diSrc.dni.nLog2Size = DirLeafGetSubBlkLog2Size(diSrc.dni.pSubBlkHdr); + // Copy over the whole Leaf from the original block + nResult = DirNodeStackGetEntry(&diDst.dni); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + u32 nCopySize = 1<nSubBlkOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)diDst.pBlkHdr, diSrc.dni.nLog2Size); + if (*diDst.dni.pOfs == 0) { + WFSKrnOutputErrorStr("Could not allocate sub block"); + } + } + diDst.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)diDst.pBlkHdr + *diDst.dni.pOfs); + + // Fix up the ofs pointers on the stack + pDns = pDnsCheckStart; + nDnsDepth = nDnsDepthStart; + while(--nDnsDepth) { + if (pDns->nBlkAdr != nBlkAdr) { + break; + } + if (pDns->nSubBlkOfs == nSrcLeafOfs) { + pDns->nSubBlkOfs = *diDst.dni.pOfs; + --nDnsDepthStart; + } + pDns = pDns->pParent; + } + + memcpy(diDst.dni.pSubBlkHdr, diSrc.dni.pSubBlkHdr, nCopySize); + diDst.dni.pDns->nEntryIdx = 1; + u16 *pSrcNodeOfsTblEnd = (u16*)((u8*)diSrc.dni.pSubBlkHdr + (1<nEntryIdx = 1; + pChoiceChar = &diSrc.dni.pSubBlkHdr->aFirstChar[diSrc.dni.pSubBlkHdr->nStrLen]; + + nSubBlkStrLen = diSrc.dni.pSubBlkHdr->nStrLen; + nStrIdx += nSubBlkStrLen; + diSrc.dni.pDns->nStrIdx = (u8)nStrIdx; +#if _DEBUG_DIR + //utf8 *pSubBlkStrPtr = diSrc.dni.pSubBlkHdr->aFirstChar; + diSrc.dni.pNodeStrPtr = diSrc.dni.pSubBlkHdr->aFirstChar; + while(nSubBlkStrLen--) { + *diSrc.dni.pStrPtr++ = *diSrc.dni.pNodeStrPtr++; + } +#endif + if (*pChoiceChar == 0) { + // String terminator char indicates this is a record, so increment our record count +#if _DEBUG_DIR + *diSrc.dni.pStrPtr = 0; + ++pChoiceChar; +#endif + // Copy file attributes to new block + u32 nAttrOfs = pSrcNodeOfsTblEnd[-1]; + dbg(SbaCheckOfs(nAttrOfs)); + DirEntryAttrHdr *pAttrHdr = (DirEntryAttrHdr *)((u8*)diSrc.pBlkHdr + nAttrOfs); + u16 *pDstNodeOfsTblEnd; + if (nSrcLeafOfs == nSkipOfs) { + pDstNodeOfsTblEnd = (u16*)((u8*)diSrc.dni.pSubBlkHdr + (1<nAttrLog2Size); + DirEntryAttrHdr *pDstAttrHdr = (DirEntryAttrHdr *)((u8*)diDst.pBlkHdr + pDstNodeOfsTblEnd[-1]); + memcpy(pDstAttrHdr, pAttrHdr, (u32)(1<nAttrLog2Size)); + ++nRecIdx; + ++diSrc.dni.pDns->nEntryIdx; + ++diDst.dni.pDns->nEntryIdx; + } + while(diSrc.dni.pDns->nEntryIdx > diSrc.dni.pSubBlkHdr->nNumEntries) { + if (diSrc.dni.nDnsDepth == nSrcLeafStartDepth) { + // We reached the top of the stack, so this should be the last record + DirPopNodeStackEntry(&diSrc.dni); + diDst.pBlkHdr->nRootOfs = diDst.dni.pDns->nSubBlkOfs; + DirNodeStackFree(&diDst.dni, diDst.ppDnsRootParent); + diDst.pBlkHdr->nNumRecs = nRecIdx; + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + *pTempBlkAdr = diDst.tba.nBlkAdr; + *ppTempBlkHdr = diDst.pBlkHdr; + return WFSKRN_RESULT_OK; + } + DirPopNodeStackEntry(&diDst.dni); + DirPopNodeStackEntry(&diSrc.dni); +#if _DEBUG_DIR + diSrc.dni.pStrPtr += diSrc.dni.pDns->nStrIdx - nStrIdx; +#endif + nStrIdx = diSrc.dni.pDns->nStrIdx; + diSrc.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)diSrc.pBlkHdr + diSrc.dni.pDns->nSubBlkOfs); + ++diDst.dni.pDns->nEntryIdx; + ++diSrc.dni.pDns->nEntryIdx; + } +#if _DEBUG_DIR + pChoiceChar = &diSrc.dni.pSubBlkHdr->aFirstChar[diSrc.dni.pSubBlkHdr->nStrLen + diSrc.dni.pDns->nEntryIdx-1]; + *diSrc.dni.pStrPtr = *pChoiceChar; +#endif + ++nStrIdx; + diSrc.dni.nLog2Size = DirLeafGetSubBlkLog2Size(diSrc.dni.pSubBlkHdr); + pSrcNodeOfsTblEnd = (u16*)((u8*)diSrc.dni.pSubBlkHdr + (1<nSubBlkOfs); + if (diSrc.dni.pDns->nSubBlkOfs == nSkipOfs) { + diDst.dni.pOfs = DirLeafGetIntraBlkOfsPtr_l2s(diSrc.dni.pDns->nEntryIdx, diSrc.dni.pSubBlkHdr, diSrc.dni.nLog2Size); + } else { + diDst.dni.pOfs = DirLeafGetIntraBlkOfsPtr_l2s(diSrc.dni.pDns->nEntryIdx, diDst.dni.pSubBlkHdr, diSrc.dni.nLog2Size); + } + } + nSrcLeafOfs = DirLeafGetIntraBlkOfs_ote(diSrc.dni.pDns->nEntryIdx, pSrcNodeOfsTblEnd); + dbg(SbaCheckOfs(nSrcLeafOfs)); + nResult = DirNodeStackGetEntry(&diSrc.dni); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + diSrc.dni.pDns->nBlkAdr = nBlkAdr; + diSrc.dni.pDns->nSubBlkOfs = nSrcLeafOfs; +#if _DEBUG_DIR + ++diSrc.dni.pStrPtr; +#endif + } +Error: + TransUnpinAndFreeBlks(diSrc.tba.pAreaInfo, diSrc.tba.pAreaInfo->ah.nLog2BlkSize, DIR_MAX_SPLIT_BLK_ALLOC, &diDst.tba.nBlkAdr, diSrc.tba.pTransInfo); + return nResult; +} + + +static +WFSKrnResult DirNodeCompact(DirItr *pDi, u16 nResizeOfs, u16 nNewLog2Size, u16 nSkipOfs, WFSBlkAdr *pTempBlkAdr, DirBlkHdr **ppTempBlkHdr) { + // This function can be used when a node block is nearly full + // It compacts the specified node block by temporarily copying to a new block. + // While the copy is being performed, optionally the sub block at offset nResizeOfs can be resized to nNewLog2Size, + // and an optional sub block can be skipped (nSkipOfs) + // This function returns the allocated temporary block in *pTempBlkAdr, *ppTempBlkHdr + WFSKrnResult nResult; + DirItr diSrc=*pDi, diDst; +#if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } + WFSFileName name; + diSrc.dni.pStrPtr = name.sStr; +#endif + u32 nStrIdx=0, nSubBlkStrLen; + + WFSBlkAdr nBlkAdr = diSrc.tba.nBlkAdr; + + DirNodeStack *pDnsCheckStart = diSrc.dni.pDns; + DirNodeStack *pDns = pDnsCheckStart; + u32 nDnsDepthStart = pDi->dni.nDnsDepth; + u32 nDnsDepth = nDnsDepthStart; + while(--nDnsDepth) { + if (pDns->nBlkAdr != nBlkAdr) { + nDnsDepthStart -= nDnsDepth; + break; + } + pDns = pDns->pParent; + } + diSrc.dni.nDnsDepth = 1; + + // Allocate new blocks + WFSKrnReturnOnError(AreaAllocBlks(diSrc.tba.pAreaInfo, nBlkAdr, diSrc.tba.pAreaInfo->ah.nLog2BlkSize, 1, &diDst.tba.nBlkAdr, sizeof(WFSBlkAdr))); + nResult = DirCreateAndInitNewBlk4(diSrc.tba.pAreaInfo, diDst.tba.nBlkAdr, diSrc.pBlkHdr->sbah.mdh.nFlags, diSrc.tba.pTransInfo, &diDst.pBlkHdr); + if(nResult < WFSKRN_RESULT_OK){ + AreaFreeBlks(diSrc.tba.pAreaInfo, diSrc.tba.pAreaInfo->ah.nLog2BlkSize, 1, &diDst.tba.nBlkAdr, sizeof(WFSBlkAdr)); + return nResult; + } + // Initialize a stack frame for traversing the destination block + diDst.dni.nDnsDepth = 0; + nResult = DirNodeStackGetEntry(&diDst.dni); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + diDst.ppDnsRootParent = &diDst.dni.pDns->pParent; + diSrc.dni.nEntryIdx = 1; + diSrc.dni.pOfs = &diSrc.pBlkHdr->nRootOfs; + dbg(SbaCheckOfs(*diSrc.dni.pOfs)); + nResult = DirPushNodeStackEntry(&diSrc.dni, nBlkAdr); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + diSrc.dni.pDns->nStrIdx = 0; // ToDo: This value can be initialized to 0 because prefix-suppression is not implemented + u16 nSrcNodeOfs = diSrc.dni.pDns->nSubBlkOfs; // = diSrc.pBlkHdr->nRootOfs; + utf8 *pChoiceChar; + u32 nRecIdx=0; + diDst.dni.pOfs = &diDst.pBlkHdr->nRootOfs; + u32 nSrcLeafStartDepth = diSrc.dni.nDnsDepth; + + // Perform a depth-first traversal of the block, until the middle leaf sub-block is found. + while(1) { + diSrc.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)diSrc.pBlkHdr + nSrcNodeOfs); + diSrc.dni.nLog2Size = DirNodeGetSubBlkLog2Size(diSrc.dni.pSubBlkHdr); + // Copy over the whole node from the original block + nResult = DirNodeStackGetEntry(&diDst.dni); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + u32 nCopySize = 1<nSubBlkOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)diDst.pBlkHdr, diSrc.dni.nLog2Size); + if (*diDst.dni.pOfs == 0) { + WFSKrnOutputErrorStr("Could not allocate sub block"); + } + } + diDst.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)diDst.pBlkHdr + *diDst.dni.pOfs); + + // Fix up the ofs pointers on the stack + pDns = pDnsCheckStart; + nDnsDepth = nDnsDepthStart; + while(--nDnsDepth) { + if (pDns->nBlkAdr != nBlkAdr) { + break; + } + if (pDns->nSubBlkOfs == nSrcNodeOfs) { + pDns->nSubBlkOfs = *diDst.dni.pOfs; + --nDnsDepthStart; + } + pDns = pDns->pParent; + } + + memcpy(diDst.dni.pSubBlkHdr, diSrc.dni.pSubBlkHdr, nCopySize); + diDst.dni.pDns->nEntryIdx = 1; + u16 *pSrcNodeOfsTblEnd = (u16*)((u8*)diSrc.dni.pSubBlkHdr + (1<nEntryIdx = 1; + pChoiceChar = &diSrc.dni.pSubBlkHdr->aFirstChar[diSrc.dni.pSubBlkHdr->nStrLen]; + + nSubBlkStrLen = diSrc.dni.pSubBlkHdr->nStrLen; + nStrIdx += nSubBlkStrLen; + diSrc.dni.pDns->nStrIdx = (u8)nStrIdx; +#if _DEBUG_DIR + //utf8 *pSubBlkStrPtr = diSrc.dni.pSubBlkHdr->aFirstChar; + diSrc.dni.pNodeStrPtr = diSrc.dni.pSubBlkHdr->aFirstChar; + while(nSubBlkStrLen--) { + *diSrc.dni.pStrPtr++ = *diSrc.dni.pNodeStrPtr++; + } +#endif + if (*pChoiceChar == 0) { + // String terminator char indicates this is a record, so increment our record count +#if _DEBUG_DIR + *diSrc.dni.pStrPtr = 0; + ++pChoiceChar; +#endif + ++nRecIdx; + ++diSrc.dni.pDns->nEntryIdx; + ++diDst.dni.pDns->nEntryIdx; + } + while(diSrc.dni.pDns->nEntryIdx > diSrc.dni.pSubBlkHdr->nNumEntries) { + if (diSrc.dni.nDnsDepth == nSrcLeafStartDepth) { + // We reached the top of the stack, so this should be the last record + DirPopNodeStackEntry(&diSrc.dni); + diDst.pBlkHdr->nRootOfs = diDst.dni.pDns->nSubBlkOfs; + DirNodeStackFree(&diDst.dni, diDst.ppDnsRootParent); + diDst.pBlkHdr->nNumRecs = nRecIdx; + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + *pTempBlkAdr = diDst.tba.nBlkAdr; + *ppTempBlkHdr = diDst.pBlkHdr; + return WFSKRN_RESULT_OK; + } + DirPopNodeStackEntry(&diDst.dni); + DirPopNodeStackEntry(&diSrc.dni); +#if _DEBUG_DIR + diSrc.dni.pStrPtr += diSrc.dni.pDns->nStrIdx - nStrIdx; +#endif + nStrIdx = diSrc.dni.pDns->nStrIdx; + diSrc.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)diSrc.pBlkHdr + diSrc.dni.pDns->nSubBlkOfs); + ++diDst.dni.pDns->nEntryIdx; + ++diSrc.dni.pDns->nEntryIdx; + } +#if _DEBUG_DIR + pChoiceChar = &diSrc.dni.pSubBlkHdr->aFirstChar[diSrc.dni.pSubBlkHdr->nStrLen + diSrc.dni.pDns->nEntryIdx-1]; + *diSrc.dni.pStrPtr = *pChoiceChar; +#endif + ++nStrIdx; + diSrc.dni.nLog2Size = DirNodeGetSubBlkLog2Size(diSrc.dni.pSubBlkHdr); + pSrcNodeOfsTblEnd = (u16*)((u8*)diSrc.dni.pSubBlkHdr + (1<nSubBlkOfs); + if (diSrc.dni.pDns->nSubBlkOfs == nSkipOfs) { + diDst.dni.pOfs = DirNodeGetIntraBlkOfsPtr_l2s(diSrc.dni.pDns->nEntryIdx, diSrc.dni.pSubBlkHdr, diSrc.dni.nLog2Size); + } else { + diDst.dni.pOfs = DirNodeGetIntraBlkOfsPtr_l2s(diSrc.dni.pDns->nEntryIdx, diDst.dni.pSubBlkHdr, diSrc.dni.nLog2Size); + } + } + nSrcNodeOfs = DirNodeGetIntraBlkOfs_ote(diSrc.dni.pDns->nEntryIdx, diSrc.dni.pSubBlkHdr, pSrcNodeOfsTblEnd); + dbg(SbaCheckOfs(nSrcNodeOfs)); + nResult = DirNodeStackGetEntry(&diSrc.dni); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + diSrc.dni.pDns->nBlkAdr = nBlkAdr; + diSrc.dni.pDns->nSubBlkOfs = nSrcNodeOfs; +#if _DEBUG_DIR + ++diSrc.dni.pStrPtr; +#endif + } +Error: + TransUnpinAndFreeBlks(diSrc.tba.pAreaInfo, diSrc.tba.pAreaInfo->ah.nLog2BlkSize, DIR_MAX_SPLIT_BLK_ALLOC, &diDst.tba.nBlkAdr, diSrc.tba.pTransInfo); + return nResult; +} + +static +WFSKrnResult DirNodeBlkSplit(DirItr *pDiSrc, WFSBlkAdr *aBlkAdr, u32 *pFirstBlockToFree); + +static +u16 DirNodeMergeSubBlkWithItsSingleChild(DirItr *pDi, DirBlkHdr *pBlkHdr, u16 nOldOfs) { +#if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } +#endif + // A non-leaf node of the radix tree is not allowed to end up with exactly 1 child. This function can be used to merge it with the child. + DirSubBlkHdr *pOldSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOldOfs); + u32 nOldLog2Size = DirNodeGetSubBlkLog2Size(pOldSubBlkHdr); + u16 *pOldNodeOfsTblEnd = (u16*)((u8*)pOldSubBlkHdr + (1<nStrLen + pOldChildHdr->nStrLen + 1); + u32 nNewNodeLog2Size = DirNodeGetSubBlkLog2Size_3(nNewStrLen, pOldChildHdr->nNumEntries, pOldChildHdr->aFirstChar[pOldChildHdr->nStrLen]); + if (nOldChildLog2Size == nNewNodeLog2Size) { + memmove(&pOldChildHdr->aFirstChar[pOldSubBlkHdr->nStrLen+1], pOldChildHdr->aFirstChar, (u32)(pOldChildHdr->nStrLen + pOldChildHdr->nNumEntries)); + memcpy(pOldChildHdr->aFirstChar, pOldSubBlkHdr->aFirstChar, (u32)(pOldSubBlkHdr->nStrLen+1)); + pOldChildHdr->nStrLen = (u8)nNewStrLen; + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nOldOfs, nOldLog2Size); + return (u16)nOldChildOfs; + } + // The merged node will require more space than the original, so it must be reallocated + u32 nNewChildNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNewNodeLog2Size); + if (nNewChildNodeOfs == 0) { + // Could not allocate a larger block + if (pDi == 0) { + return 0; + } + // This section was added for the delete function - compact node and update node stack + WFSBlkAdr nTempBlkAdr; + DirBlkHdr *pTempBlkHdr; + WFSKrnReturnOnError(DirNodeCompact(pDi, nOldOfs, nNewNodeLog2Size, nOldChildOfs, &nTempBlkAdr, &pTempBlkHdr)); + nNewChildNodeOfs = pDi->dni.pDns->nSubBlkOfs; + DirSubBlkHdr *pNewSubBlkHdr = (DirSubBlkHdr *)((u8*)pTempBlkHdr + nNewChildNodeOfs); + memcpy(pNewSubBlkHdr->aFirstChar, pOldSubBlkHdr->aFirstChar, (u32)(pOldSubBlkHdr->nStrLen+1)); + memcpy(pNewSubBlkHdr->aFirstChar +pOldSubBlkHdr->nStrLen+1, pOldChildHdr->aFirstChar, (u32)(pOldChildHdr->nStrLen + pOldChildHdr->nNumEntries)); + pNewSubBlkHdr->nStrLen = (u8)nNewStrLen; + pNewSubBlkHdr->nNumEntries = pOldChildHdr->nNumEntries; + s32 nNumEntries = (s32)pOldChildHdr->nNumEntries; + u16 *pSrcStart = DirNodeGetIntraBlkOfsPtr_l2s(nNumEntries, pOldChildHdr, nOldChildLog2Size); + u8 *pSrcEnd = (u8*)pOldChildHdr + (1<tba.pAreaInfo->nBlkSize); + DirUnpinAndFreeBlk(pDi->tba.pAreaInfo, nTempBlkAdr, pDi->tba.pTransInfo); + return nNewChildNodeOfs; + } + DirSubBlkHdr *pNewSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nNewChildNodeOfs); + memcpy(pNewSubBlkHdr->aFirstChar, pOldSubBlkHdr->aFirstChar, (u32)(pOldSubBlkHdr->nStrLen+1)); + memcpy(pNewSubBlkHdr->aFirstChar +pOldSubBlkHdr->nStrLen+1, pOldChildHdr->aFirstChar, (u32)(pOldChildHdr->nStrLen + pOldChildHdr->nNumEntries)); + pNewSubBlkHdr->nStrLen = (u8)nNewStrLen; + pNewSubBlkHdr->nNumEntries = pOldChildHdr->nNumEntries; + s32 nNumEntries = (s32)pOldChildHdr->nNumEntries; + u16 *pSrcStart = DirNodeGetIntraBlkOfsPtr_l2s(nNumEntries, pOldChildHdr, nOldChildLog2Size); + u8 *pSrcEnd = (u8*)pOldChildHdr + (1<nStrLen + pOldChildHdr->nStrLen + 1); + u32 nNewNodeLog2Size = DirLeafGetSubBlkLog2Size_2(nNewStrLen, pOldChildHdr->nNumEntries); + if (nOldChildLog2Size == nNewNodeLog2Size) { + memmove(&pOldChildHdr->aFirstChar[pOldSubBlkHdr->nStrLen+1], pOldChildHdr->aFirstChar, (u32)(pOldChildHdr->nStrLen + pOldChildHdr->nNumEntries)); + memcpy(pOldChildHdr->aFirstChar, pOldSubBlkHdr->aFirstChar, (u32)(pOldSubBlkHdr->nStrLen+1)); + pOldChildHdr->nStrLen = (u8)nNewStrLen; + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nOldOfs, nOldLog2Size); + return (u16)nOldChildOfs; + } + // The merged node will require more space than the original, so it must be reallocated + u32 nNewChildNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNewNodeLog2Size); + if (nNewChildNodeOfs == 0) { + // Could not allocate a larger block + if (pDi == 0) { + return 0; + } + // This section was added for the delete function - compact leaf and update node stack + WFSBlkAdr nTempBlkAdr; + DirBlkHdr *pTempBlkHdr; + WFSKrnReturnOnError(DirLeafCompact(pDi, nOldOfs, nNewNodeLog2Size, nOldChildOfs, &nTempBlkAdr, &pTempBlkHdr)); + nNewChildNodeOfs = pDi->dni.pDns->nSubBlkOfs; + DirSubBlkHdr *pNewSubBlkHdr = (DirSubBlkHdr *)((u8*)pTempBlkHdr + nNewChildNodeOfs); + memcpy(pNewSubBlkHdr->aFirstChar, pOldSubBlkHdr->aFirstChar, (u32)(pOldSubBlkHdr->nStrLen+1)); + memcpy(pNewSubBlkHdr->aFirstChar +pOldSubBlkHdr->nStrLen+1, pOldChildHdr->aFirstChar, (u32)(pOldChildHdr->nStrLen + pOldChildHdr->nNumEntries)); + pNewSubBlkHdr->nStrLen = (u8)nNewStrLen; + pNewSubBlkHdr->nNumEntries = pOldChildHdr->nNumEntries; + s32 nNumEntries = (s32)pOldChildHdr->nNumEntries; + u16 *pSrcStart = DirLeafGetIntraBlkOfsPtr_l2s(nNumEntries, pOldChildHdr, nOldChildLog2Size); + u8 *pSrcEnd = (u8*)pOldChildHdr + (1<tba.pAreaInfo->nBlkSize); + DirUnpinAndFreeBlk(pDi->tba.pAreaInfo, nTempBlkAdr, pDi->tba.pTransInfo); + return nNewChildNodeOfs; + } + DirSubBlkHdr *pNewSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nNewChildNodeOfs); + memcpy(pNewSubBlkHdr->aFirstChar, pOldSubBlkHdr->aFirstChar, (u32)(pOldSubBlkHdr->nStrLen+1)); + memcpy(pNewSubBlkHdr->aFirstChar +pOldSubBlkHdr->nStrLen+1, pOldChildHdr->aFirstChar, (u32)(pOldChildHdr->nStrLen + pOldChildHdr->nNumEntries)); + pNewSubBlkHdr->nStrLen = (u8)nNewStrLen; + pNewSubBlkHdr->nNumEntries = pOldChildHdr->nNumEntries; + u16 *pNewChildOfsTblEnd = (u16*)((u8*)pNewSubBlkHdr + (1<nNumEntries; + memcpy(&pNewChildOfsTblEnd[-nNumEntries], &pOldChildOfsTblEnd[-nNumEntries], sizeof(u16) * nNumEntries); + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nOldChildOfs, nOldChildLog2Size); + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nOldOfs, nOldLog2Size); + return (u16)nNewChildNodeOfs; +} + +static +u16 DirNodeDeleteSubBlkTail(DirBlkHdr *pBlkHdr, u16 nOldOfs, u32 nNewNumEntries) { + // Delete the latter portion of the input node so that it contains nNewNumEntries + // This function will reallocate the node if its size changes, or merge the node with its child + // if it would otherwise become an illegal non-terminated node with a single child. + // It returns the offset to the resultant node. + DirSubBlkHdr *pOldSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOldOfs); + if (nNewNumEntries==1) { + utf8 *pOldChoiceChar = &pOldSubBlkHdr->aFirstChar[pOldSubBlkHdr->nStrLen]; + if (*pOldChoiceChar != 0) { + // This node would end up as a non-Node node with exactly 1 choice, which is illegal. + // It must be merged with its child. + return DirNodeMergeSubBlkWithItsSingleChild(0, pBlkHdr, nOldOfs); + } + } + u32 nOldLog2Size = DirNodeGetSubBlkLog2Size(pOldSubBlkHdr); + u16 *pSrcStart = DirNodeGetIntraBlkOfsPtr_l2s((s32)nNewNumEntries, pOldSubBlkHdr, nOldLog2Size); + pOldSubBlkHdr->nNumEntries = (u8)nNewNumEntries; + u32 nNewLog2Size = DirNodeGetSubBlkLog2Size(pOldSubBlkHdr); + if (nNewLog2Size == nOldLog2Size) { + // If the block size does not change there is no need to do anything further. + // (because nNumEntries has already been updated, and we are removing entries from the end of the list of choices). + return nOldOfs; + } + // The deletion forces the node to change size. Try to allocate a free node of the new size. + u32 nNewNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNewLog2Size); + //u16 *pOldNodeOfsTblEnd = (u16*)((u8*)pOldSubBlkHdr + (1<nStrLen + nNewNumEntries + sizeof(DirSubBlkHdr)-1; + memcpy(pNewNodeHdr, pOldSubBlkHdr, nCopySize); + u16 *pDstStart = DirNodeGetIntraBlkOfsPtr_ote((s32)nNewNumEntries, pNewNodeHdr, pNewNodeOfsTblEnd); + memcpy(pDstStart, pSrcStart, (u32)((u8*)pNewNodeOfsTblEnd - (u8*)pDstStart)); + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nOldOfs, nOldLog2Size); + return (u16)nNewNodeOfs; +} + +static +u16 DirLeafDeleteSubBlkTail(DirBlkHdr *pBlkHdr, u16 nOldOfs, u32 nNewNumEntries) { + // Delete the latter portion of the input node so that it contains nNewNumEntries + // This function will reallocate the node if its size changes, or merge the node with its child + // if it would otherwise become an illegal non-terminated node with a single child. + // It returns the offset to the resultant node. + DirSubBlkHdr *pOldSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOldOfs); + if (nNewNumEntries==1) { + utf8 *pOldChoiceChar = &pOldSubBlkHdr->aFirstChar[pOldSubBlkHdr->nStrLen]; + if (*pOldChoiceChar != 0) { + // This node would end up as a non-leaf node with exactly 1 choice, which is illegal. + // It must be merged with its child. + return DirLeafMergeSubBlkWithItsSingleChild(0, pBlkHdr, nOldOfs); + } + } + u32 nOldLog2Size = DirLeafGetSubBlkLog2Size(pOldSubBlkHdr); + pOldSubBlkHdr->nNumEntries = (u8)nNewNumEntries; + u32 nNewLog2Size = DirLeafGetSubBlkLog2Size(pOldSubBlkHdr); + if (nNewLog2Size == nOldLog2Size) { + // If the block size does not change there is no need to do anything further. + // (because nNumEntries has already been updated, and we are removing entries from the end of the list of choices). + return (u16)nOldOfs; + } + // The deletion forces the node to change size. Try to allocate a free node of the new size. + u32 nNewNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNewLog2Size); + u16 *pOldNodeOfsTblEnd = (u16*)((u8*)pOldSubBlkHdr + (1<nStrLen + nNewNumEntries + sizeof(DirSubBlkHdr)-1; + memcpy(pNewNodeHdr, pOldSubBlkHdr, nCopySize); + memcpy(&pNewNodeOfsTblEnd[-(s32)nNewNumEntries], &pOldNodeOfsTblEnd[-(s32)nNewNumEntries], sizeof(u16) * nNewNumEntries); + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nOldOfs, nOldLog2Size); + return (u16)nNewNodeOfs; +} + +static +u16 DirNodeCopySubBlkTail(DirBlkHdr *pSrcBlkHdr, u16 nSrcOfs, DirBlkHdr *pDstBlkHdr, u32 nNewNumEntries, u16 nDstChildOfs, bool bCopyPtrTbl) { + // This function copies the last nNewNumEntries of a node, to a new node. nNewNumEntries must be >= 1. + // pSrcBlkHdr is the block containing the source node. nSrcOfs is the offset from the start of the block. + // The new node is created in pDstBlkHdr, which can be the same or different from pSrcBlkHdr. + // This function returns the offset of the new node within pDstBlkHdr, or 0 if it could not be created. + // If the nNewNumEntries == 1, and the sub block is non-leaf, it will be merged with the node at offset nDstChildOfs. + DirSubBlkHdr *pSrcSubBlkHdr = (DirSubBlkHdr *)((u8*)pSrcBlkHdr + nSrcOfs); + if (nNewNumEntries==1) { + utf8 *pSrcChoiceChar = &pSrcSubBlkHdr->aFirstChar[pSrcSubBlkHdr->nStrLen + pSrcSubBlkHdr->nNumEntries - 1]; + if (*pSrcChoiceChar != 0) { + // This node would end up as a non-leaf node with exactly 1 choice, which is illegal. + // It must be merged with its child. + return DirNodePrependStringToSubBlk(pDstBlkHdr, nDstChildOfs, pSrcSubBlkHdr->aFirstChar, pSrcSubBlkHdr->nStrLen, *pSrcChoiceChar); + } + } + u32 nDstLog2Size = DirNodeGetSubBlkLog2Size_3(pSrcSubBlkHdr->nStrLen, nNewNumEntries, 1); + u32 nDstNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pDstBlkHdr, nDstLog2Size); + if (nDstNodeOfs == 0) { + return 0; + } + DirSubBlkHdr *pDstSubBlkHdr = (DirSubBlkHdr *)((u8*)pDstBlkHdr + nDstNodeOfs); + u32 nCopySize = pSrcSubBlkHdr->nStrLen + sizeof(DirSubBlkHdr)-1; + memcpy(pDstSubBlkHdr, pSrcSubBlkHdr, nCopySize); + u32 nEntryIdx = pSrcSubBlkHdr->nNumEntries - nNewNumEntries; + memcpy((u8*)pDstSubBlkHdr + nCopySize, (u8*)pSrcSubBlkHdr + nCopySize + nEntryIdx, nNewNumEntries); + pDstSubBlkHdr->nNumEntries = (u8)nNewNumEntries; + u16 *pDstOfsTblEnd = (u16*)((u8*)pDstSubBlkHdr + (1<nNumEntries, pSrcSubBlkHdr); + memcpy(&pDstOfsTblEnd[-(s32)nNewNumEntries], pSrcStart, sizeof(u16) * nNewNumEntries); + } + pDstOfsTblEnd[-1] = nDstChildOfs; + return (u16)nDstNodeOfs; +} + +static +u16 DirLeafCopySubBlkTail(DirBlkHdr *pSrcBlkHdr, u16 nSrcOfs, DirBlkHdr *pDstBlkHdr, u32 nNewNumEntries, u16 nDstChildOfs, bool bCopyPtrTbl) { + // This function copies the last nNewNumEntries of a node, to a new node. nNewNumEntries must be >= 1. + // pSrcBlkHdr is the block containing the source node. nSrcOfs is the offset from the start of the block. + // The new node is created in pDstBlkHdr, which can be the same or different from pSrcBlkHdr. + // This function returns the offset of the new node within pDstBlkHdr, or 0 if it could not be created. + // If the nNewNumEntries == 1, and the node is non-leaf, it will be merged with the node at offset nDstChildOfs. + DirSubBlkHdr *pSrcSubBlkHdr = (DirSubBlkHdr *)((u8*)pSrcBlkHdr + nSrcOfs); + if (nNewNumEntries==1) { + utf8 *pSrcChoiceChar = &pSrcSubBlkHdr->aFirstChar[pSrcSubBlkHdr->nStrLen + pSrcSubBlkHdr->nNumEntries - 1]; + if (*pSrcChoiceChar != 0) { + // This node would end up as a non-leaf node with exactly 1 choice, which is illegal. + // It must be merged with its child. + return DirLeafPrependStringToSubBlk(pDstBlkHdr, nDstChildOfs, pSrcSubBlkHdr->aFirstChar, pSrcSubBlkHdr->nStrLen, *pSrcChoiceChar); + } + } + u32 nDstLog2Size = DirLeafGetSubBlkLog2Size_2(pSrcSubBlkHdr->nStrLen, nNewNumEntries); + u32 nDstNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pDstBlkHdr, nDstLog2Size); + if (nDstNodeOfs == 0) { + return 0; + } + DirSubBlkHdr *pDstSubBlkHdr = (DirSubBlkHdr *)((u8*)pDstBlkHdr + nDstNodeOfs); + u32 nCopySize = pSrcSubBlkHdr->nStrLen + sizeof(DirSubBlkHdr)-1; + memcpy(pDstSubBlkHdr, pSrcSubBlkHdr, nCopySize); + u32 nEntryIdx = pSrcSubBlkHdr->nNumEntries - nNewNumEntries; + memcpy((u8*)pDstSubBlkHdr + nCopySize, (u8*)pSrcSubBlkHdr + nCopySize + nEntryIdx, nNewNumEntries); + pDstSubBlkHdr->nNumEntries = (u8)nNewNumEntries; + u16 *pDstOfsTblEnd = (u16*)((u8*)pDstSubBlkHdr + (1<nNumEntries, pSrcSubBlkHdr); + memcpy(&pDstOfsTblEnd[-(s32)nNewNumEntries], pSrcStart, sizeof(u16) * nNewNumEntries); + } + pDstOfsTblEnd[-1] = nDstChildOfs; + return (u16)nDstNodeOfs; +} + +u16 DirNodeDeleteSubBlkHead(DirBlkHdr *pBlkHdr, u16 nOfs, u32 nEntryIdx) { + // This function deletes entries from the start of a sub block leaving the last nNewNumEntries. + // pBlkHdr is the block containing the sub block. nOldOfs is the offset from the start of the block. + // This function returns the offset of the new node within pBlkHdr, or 0 if it could not be created. + // If the nNewNumEntries == 1, and the sub block is non-leaf, the node will be merged with its single child. + DirSubBlkHdr *pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOfs); + u32 nLog2Size = DirNodeGetSubBlkLog2Size(pSubBlkHdr); + //u16 *pOfsTblEnd = (u16*)((u8*)pSubBlkHdr + (1<nNumEntries, pSubBlkHdr, pExistingNodeOfsTblEnd); + u16 *pSrcEnd = DirNodeGetIntraBlkOfsPtr_ote(nEntryIdx, pSubBlkHdr, pExistingNodeOfsTblEnd); + utf8 *pSrc = &pSubBlkHdr->aFirstChar[pSubBlkHdr->nStrLen + nEntryIdx]; + memmove(pSrc-1, pSrc, pSubBlkHdr->nNumEntries - nEntryIdx); + --pSubBlkHdr->nNumEntries; + u16 nNewLog2Size = DirNodeGetSubBlkLog2Size(pSubBlkHdr); + if (nNewLog2Size != nLog2Size) { + nNewOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNewLog2Size); + if (nNewOfs == 0) { + // Could not allocate a new block, so resize in place - ToDo: Test this case more + u16 *pDstStart = DirNodeGetIntraBlkOfsPtr_l2s(pSubBlkHdr->nNumEntries, pSubBlkHdr, nNewLog2Size); + u32 nCopySize2 = (u8*)pSrcEnd - (u8*)pSrcStart; + memmove(pDstStart, pSrcStart, nCopySize2); + SbaReduceSubBlkSize((WFSSubBlkAllocHdr*)pBlkHdr, nOfs, nLog2Size, nNewLog2Size); + nNewOfs = nOfs; + } else { + // Delete offset pointer while copying to a new sub block + DirSubBlkHdr *pUpdatedNodeHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nNewOfs); + u32 nCopySize1 = sizeof(DirSubBlkHdr)-1 + pSubBlkHdr->nStrLen + pSubBlkHdr->nNumEntries; + memcpy(pUpdatedNodeHdr, pSubBlkHdr, nCopySize1); + u16 *pDstStart = DirNodeGetIntraBlkOfsPtr_l2s(pSubBlkHdr->nNumEntries, pUpdatedNodeHdr, nNewLog2Size); + u32 nCopySize2 = (u8*)pSrcEnd - (u8*)pSrcStart; + memcpy(pDstStart, pSrcStart, nCopySize2); + // Update parent to point to the new node. Parent may be the nRootOfs of the block + SbaFreeSubBlk((WFSSubBlkAllocHdr*)pBlkHdr, nOfs, nLog2Size); + pSubBlkHdr = pUpdatedNodeHdr; + } + } else { + // Delete entry from existing node + u16 *pDstStart = DirNodeGetIntraBlkOfsPtr_l2s(pSubBlkHdr->nNumEntries, pSubBlkHdr, nNewLog2Size); + u32 nCopySize2 = (u8*)pSrcEnd - (u8*)pSrcStart; + memmove(pDstStart, pSrcStart, nCopySize2); + nNewOfs = nOfs; + } + if ((pSubBlkHdr->nNumEntries==1) && (pSubBlkHdr->aFirstChar[pSubBlkHdr->nStrLen] != 0)) { + utf8 *pChoiceChar = &pSubBlkHdr->aFirstChar[pSubBlkHdr->nStrLen]; + if (*pChoiceChar != 0) { + // This node would end up as a non-leaf node with exactly 1 choice, which is illegal. + // It must be merged with its child. + u16 nNewChildOfs = DirNodeGetIntraBlkOfs_l2s(pSubBlkHdr->nNumEntries, pSubBlkHdr, nNewLog2Size); + nOfs = nNewOfs; + nNewOfs = DirNodePrependStringToSubBlk(pBlkHdr, nNewChildOfs, pSubBlkHdr->aFirstChar, pSubBlkHdr->nStrLen, *pChoiceChar); + SbaFreeSubBlk((WFSSubBlkAllocHdr*)pBlkHdr, nOfs, nNewLog2Size); + } + } + return nNewOfs; +} + +WFSKrnResult DirNodeSubBlkSplitPrefixString(DirBlkHdr *pBlkHdr, DirSubBlkHdr *pSubBlkHdr, u32 nOfs, u32 nNewStrLen, utf8 nNewChoiceChar) { + // This function splits a sub block into two pieces by adding a choice at some point along the prefix string + // ToDo: Implement this function - to remove a common case from insert and delete to node blocks. + return WFSKRN_RESULT_OK; +} + +static +WFSKrnResult DirNodeInsertEntry(WFSFileName *pName, DirItr *pDi, WFSBlkAdr *aBlkAdr, u32 *pFirstBlockToFree) { +#if _DEBUG_BREAK_POINT + static int c;++c;if(c>=3){ + int a;a=0; + } +#endif + // This function adds a splitter to a parent node when a leaf is split. + // pDi->tba.nBlkAdr contains the block address of the parent node to which the splitter entry is being inserted. + // aBlkAdr contains the block addresses of: 0..Left Child, 1..Right Child, 2+..Reserved incase further splits needed +#if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } +#endif + if (pDi->nBlkDepth) { + --pDi->nBlkDepth; + } +//Retry: + WFSBlkAdr nBlkAdr = pDi->tba.nBlkAdr; + DirBlkHdr *pBlkHdr = pDi->pBlkHdr; + u32 nStrLen = pName->nLen; + if (pBlkHdr->nNumRecs==0) { + // The parent block is currently enpty. Add the first record. + // Create root node with minimum possible key (NULL key), and add pointer to left node + u32 nRootNodeLog2Size = DirNodeGetSubBlkLog2Size_3(0, 2, 0); + pBlkHdr->nRootOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nRootNodeLog2Size); + DirSubBlkHdr *pRootSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + pBlkHdr->nRootOfs); + pRootSubBlkHdr->nStrLen = 0; + pRootSubBlkHdr->nNumEntries = 2; + pRootSubBlkHdr->aFirstChar[0]=0; + pRootSubBlkHdr->aFirstChar[1]=pName->sStr[0]; + u16 *pRootOfsTblEnd = (u16 *)((u8*)pRootSubBlkHdr + (1<nStrLen = (u8)nStrLen; + pNodeSubBlkHdr->nNumEntries = 1; + memcpy(pNodeSubBlkHdr->aFirstChar, pName->sStr+1, nStrLen+1); + DirNodeSetBlkAdr_l2s(aBlkAdr[1], pNodeSubBlkHdr, nNodeLog2Size); + pBlkHdr->nNumRecs = 2; + ++pDi->nBlkDepth; + TransUnpinBlk(&pDi->tba); + return WFSKRN_RESULT_OK; + } + + // Insert the new name into the parent node block. + // First determine the insertion point. + DirNodeItr dni = pDi->dni; + dbg(u32 nChildBlkAdr = dni.pDns->nBlkAdr); + //if (pDi->tba.nBlkAdr != dni.pDns->nBlkAdr) { + while (pDi->tba.nBlkAdr != dni.pDns->nBlkAdr) { + //do { + DirPopNodeStackEntry(&dni); + //} while(pDi->tba.nBlkAdr != dni.pDns->nBlkAdr); + } + dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + dni.pDns->nSubBlkOfs); + dbg(if (DirNodeGetBlkAdr(dni.pSubBlkHdr) != nChildBlkAdr) { + WFSKrnOutputErrorStr("BlkAdr doesn't match child!\n"); + }) + DirNodeSetBlkAdr(aBlkAdr[0], dni.pSubBlkHdr); // Update the address of the left hand child block + while(dni.nDnsDepth > 2) { + if (dni.pDns->pParent->nBlkAdr != pDi->tba.nBlkAdr) { + break; + } + DirPopNodeStackEntry(&dni); + } + + dni.pStrPtr = pName->sStr; + u32 nSubBlkStrLen, nStrIdx=0; + //utf8 *pSubBlkStrPtr, + utf8 *pStrEnd = pName->sStr + pName->nLen; + utf8 cSearchChar; + WFSKrnResult nResult; + + dni.pOfs = &pBlkHdr->nRootOfs; + dbg(SbaCheckOfs(*dni.pOfs)); + dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *dni.pOfs); + dni.nLog2Size = DirNodeGetSubBlkLog2Size(dni.pSubBlkHdr); + while(1) { + nSubBlkStrLen = dni.pSubBlkHdr->nStrLen; + nStrIdx += nSubBlkStrLen + 1; + dni.pNodeStrPtr = dni.pSubBlkHdr->aFirstChar; + if ((pStrEnd - dni.pStrPtr) < nSubBlkStrLen) { + while(*dni.pStrPtr == *dni.pNodeStrPtr) { + ++dni.pStrPtr; ++dni.pNodeStrPtr; + } + nSubBlkStrLen -= (dni.pNodeStrPtr - dni.pSubBlkHdr->aFirstChar); + nResult = WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH; + break; + } + while((nSubBlkStrLen) && (*dni.pStrPtr == *dni.pNodeStrPtr)) { + ++dni.pStrPtr; ++dni.pNodeStrPtr; --nSubBlkStrLen; + } + if (nSubBlkStrLen) { + nResult = WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH; + break; + } + // matched all the characters from the prefix. dni.pNodeStrPtr should now be pointing to the array of choices following the prefix. + cSearchChar = *dni.pStrPtr; + if (!DirBinarySplitSearchChoices(dni.pNodeStrPtr, dni.pSubBlkHdr->nNumEntries, cSearchChar, &dni.nEntryIdx)) { + nResult = WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND; + break; + } + //if (dni.pSubBlkHdr->nNumEntries > 1) { + if(dni.pDns->nBlkAdr != nBlkAdr || dni.pDns->nSubBlkOfs != *dni.pOfs){ + WFSKrnReturnOnError(DirPushNodeStackEntry(&dni, nBlkAdr)); + } else { + dni.pDns->nEntryIdx = (u8)dni.nEntryIdx; + } + dni.pDns->nStrIdx = nStrIdx; + //} + // Found the search character. + //++nStrIdx; + if (cSearchChar==0) { + // We matched a 0 .. which means we have found the filename + nResult = WFSKRN_RESULT_DIR_ENTRY_FOUND; + break; + } + dni.pOfs = DirNodeGetIntraBlkOfsPtr_l2s((s32)dni.nEntryIdx, dni.pSubBlkHdr, dni.nLog2Size); + dbg(SbaCheckOfs(*dni.pOfs)); + dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *dni.pOfs); + dni.nLog2Size = DirNodeGetSubBlkLog2Size(dni.pSubBlkHdr); + ++dni.pStrPtr; + } + +Retry:; + u32 nNumMatching = (u32)(dni.pNodeStrPtr - dni.pSubBlkHdr->aFirstChar); + u32 nNodeNumLeft = dni.pSubBlkHdr->nStrLen - nNumMatching; + u32 nSuffixLen = (u32)(pName->nLen - (dni.pStrPtr - pName->sStr)); + u16 nNameSubBlkLog2Size = 0; + u16 nNameSubBlkOfs = 0; + u16 nChoiceNodeSubBlkLog2Size; + u16 nChoiceNodeSubBlkOfs; + u16 *pNodeOfsTblEnd; + u16 *pExistingNodeOfsTblEnd = (u16*)((u8*)dni.pSubBlkHdr + (1<dni = dni; + *pFirstBlockToFree += 2; + WFSKrnReturnOnError(DirNodeBlkSplit(pDi, &aBlkAdr[2], pFirstBlockToFree)); + while(pDi->dni.nDnsDepth > 2) { + DirPopNodeStackEntry(&pDi->dni); + } + pDi->tba.nBlkAdr = pDi->dni.pDns->nBlkAdr; + DirItrCloseNoUnpin(pDi); + u32 nFindMaxDepth = pDi->nBlkDepth; + pDi->nBlkDepth = 0; + DirFind(pName, pDi, nFindMaxDepth, DIR_FIND_MODE_NORMAL); + nBlkAdr = pDi->tba.nBlkAdr; + WFSKrnReturnOnError( DirGetBlk(pDi, TRANS_FLAG_RW_BLK, &pBlkHdr) ); + dni = pDi->dni; + dni.nLog2Size = DirNodeGetSubBlkLog2Size(dni.pSubBlkHdr); + dbg(if (*dni.pOfs != ((u8*)dni.pSubBlkHdr - (u8*)pDi->pBlkHdr)) { + WFSKrnOutputErrorStr("Ofs mismatch error!"); + }) + goto Retry; + } + DirSubBlkHdr *pNameSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nNameSubBlkOfs); + pNameSubBlkHdr->nNumEntries = 1; + pNameSubBlkHdr->nStrLen = (u8)(nSuffixLen-1); + memcpy(pNameSubBlkHdr->aFirstChar, &dni.pStrPtr[1], nSuffixLen); // includes copying the NULL terminator + DirNodeSetBlkAdr(aBlkAdr[1], pNameSubBlkHdr); + } else { + //nNameSubBlkOfs = nAttrOfs; + } + + utf8 cNameChar = dni.pStrPtr[0]; + if (nNodeNumLeft == 0) { + // Add a new option to the existing node + u16 nUpdatedNodeOfs; + u32 nUpdatedNodeLog2Size; + if (cNameChar) { + nUpdatedNodeLog2Size = DirNodeGetSubBlkLog2Size_3(dni.pSubBlkHdr->nStrLen, (u32)(dni.pSubBlkHdr->nNumEntries+1), dni.pSubBlkHdr->aFirstChar[dni.pSubBlkHdr->nStrLen]); + } else { + nUpdatedNodeLog2Size = DirNodeGetSubBlkLog2Size_3(dni.pSubBlkHdr->nStrLen, (u32)(dni.pSubBlkHdr->nNumEntries+1), 0); + } + if (nUpdatedNodeLog2Size != dni.nLog2Size) { + // The node needs to be copied to a larger sub block + nUpdatedNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nUpdatedNodeLog2Size); + if (nUpdatedNodeOfs == 0) { + // Allocation failed, so undo any changes so far, split the block, and try again + if (nSuffixLen) { + // Undo the allocation of the name sub block + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNameSubBlkOfs, nNameSubBlkLog2Size); + } + goto NameNotAllocated; + } + DirSubBlkHdr *pUpdatedNodeHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nUpdatedNodeOfs); + u16 *pUpdatedNodeOfsTblEnd = (u16*)((u8*)pUpdatedNodeHdr + (1<nStrLen + dni.nEntryIdx; + memcpy(pUpdatedNodeHdr, dni.pSubBlkHdr, nCopySize1); + u8 *pDst = &((u8*)pUpdatedNodeHdr)[nCopySize1]; + *pDst++ = (u8)dni.pStrPtr[0]; + s32 nCopySize2 = (s32)(dni.pSubBlkHdr->nNumEntries - dni.nEntryIdx); + memcpy(pDst, &((u8*)dni.pSubBlkHdr)[nCopySize1], (u32)nCopySize2); + ++pUpdatedNodeHdr->nNumEntries; + // Copy the table of child offset pointers from the old block to the new block while inserting the new offset + u16 *pDstStart = DirNodeGetOfsTblStartPtr_ote(pUpdatedNodeHdr, pUpdatedNodeOfsTblEnd); + u16 *pSrcStart = DirNodeGetOfsTblStartPtr_ote(dni.pSubBlkHdr, pExistingNodeOfsTblEnd); + u16 *pSrcEnd = DirNodeGetIntraBlkOfsPtr_ote((s32)dni.nEntryIdx, dni.pSubBlkHdr, pExistingNodeOfsTblEnd); + memcpy(pDstStart, pSrcStart, (u32)((u8*)pSrcEnd-(u8*)pSrcStart)); + pDstStart += (pSrcEnd-pSrcStart); + if (cNameChar) { + *pDstStart++ = nNameSubBlkOfs; + memcpy(pDstStart, pSrcEnd, (u32)((u8*)pExistingNodeOfsTblEnd-(u8*)pSrcEnd)); + } else { + // case where new choice is 0 + *((u32*)pDstStart) = aBlkAdr[1]; + } + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, *dni.pOfs, dni.nLog2Size); + *dni.pOfs = nUpdatedNodeOfs; // Update the parent pointer + } else { + // The new option can be added without changing the size of the node + utf8 *pCharInsertPoint = dni.pSubBlkHdr->aFirstChar + dni.pSubBlkHdr->nStrLen + dni.nEntryIdx; + s32 nCopySize = (s32)(dni.pSubBlkHdr->nNumEntries - dni.nEntryIdx); + u16 *pSrcStart = DirNodeGetOfsTblStartPtr_ote(dni.pSubBlkHdr, pExistingNodeOfsTblEnd); + memmove(pCharInsertPoint+1, pCharInsertPoint, (u32)(nCopySize)); + pCharInsertPoint[0] = dni.pStrPtr[0]; + if (cNameChar) { + u16 *pOfsInsertPoint = DirNodeGetIntraBlkOfsPtr_ote((s32)dni.nEntryIdx, dni.pSubBlkHdr, pExistingNodeOfsTblEnd); + memmove(pSrcStart-1, pSrcStart, (u32)((u8*)pOfsInsertPoint-(u8*)pSrcStart)); + ++dni.pSubBlkHdr->nNumEntries; + pOfsInsertPoint[-1] = nNameSubBlkOfs; + } else { + memmove(pSrcStart-2, pSrcStart, (u32)((u8*)pExistingNodeOfsTblEnd-(u8*)pSrcStart)); + ((u32*)pExistingNodeOfsTblEnd)[-1] = aBlkAdr[1]; + ++dni.pSubBlkHdr->nNumEntries; + } + } + } else { + // Replace the start of the existing node with a new 2-choice node + // and update the existing node to contain only the end of the string, + // resizing the node if its size drops to a smaller power-of-2 allocation size. + // (note: the resize is compulsory due to the algorithms used elsewhere). + // + // First, try to allocate a sub block for the new 2-choice node. + utf8 cNodeChar = dni.pSubBlkHdr->aFirstChar[nNumMatching]; + nChoiceNodeSubBlkLog2Size = (u16)DirNodeGetSubBlkLog2Size_3(nNumMatching, 2, (s8)cNameChar); + nChoiceNodeSubBlkOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nChoiceNodeSubBlkLog2Size); + if (nChoiceNodeSubBlkOfs == 0) { + // Allocation failed, so undo any changes so far, split the block, and try again + if (nSuffixLen) { + // Undo the allocation of the name sub block + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNameSubBlkOfs, nNameSubBlkLog2Size); + } + goto NameNotAllocated; + } + DirSubBlkHdr *pChoiceNodeHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nChoiceNodeSubBlkOfs); + pNodeOfsTblEnd = (u16*)((u8*)pChoiceNodeHdr + (1<nNumEntries = 2; + pChoiceNodeHdr->nStrLen = (u8)nNumMatching; + memcpy(pChoiceNodeHdr->aFirstChar, dni.pSubBlkHdr->aFirstChar, nNumMatching); + + // Now, update the existing node + u16 nUpdatedNodeOfs; + u32 nUpdatedNodeLog2Size = DirNodeGetSubBlkLog2Size_3(nNodeNumLeft-1, dni.pSubBlkHdr->nNumEntries, dni.pSubBlkHdr->aFirstChar[dni.pSubBlkHdr->nStrLen]); + DirSubBlkHdr *pUpdatedNodeHdr; + if (nUpdatedNodeLog2Size != dni.nLog2Size) { + // The existing node should be reduced in size. + // First try to allocate a new smaller sub block. + // If this is not possible, then resize in place. + nUpdatedNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nUpdatedNodeLog2Size); + u32 nOldNodeOfs = (u16)((u8*)dni.pSubBlkHdr - (u8*)pBlkHdr); + if (nUpdatedNodeOfs == 0) { + // allocation failed, so resize in place + // shift/copy the end of the string and the following choices backwards over the start of the string + pUpdatedNodeHdr = dni.pSubBlkHdr; + nUpdatedNodeOfs = (u16)nOldNodeOfs; + pUpdatedNodeHdr->nStrLen = (u8)(nNodeNumLeft-1); // Needs to be done first so that pDstStart calculation is correct + memmove(pUpdatedNodeHdr->aFirstChar, &pUpdatedNodeHdr->aFirstChar[nNumMatching+1], nNodeNumLeft + pUpdatedNodeHdr->nNumEntries); + // shift over the table of pointers at the end of the sub block + u16 *pDstStart = DirNodeGetOfsTblStartPtr_l2s(pUpdatedNodeHdr, nUpdatedNodeLog2Size); + u16 *pSrcStart = DirNodeGetOfsTblStartPtr_ote(dni.pSubBlkHdr, pExistingNodeOfsTblEnd); + memmove(pDstStart, pSrcStart, (u32)((u8*)pExistingNodeOfsTblEnd-(u8*)pSrcStart)); + SbaReduceSubBlkSize((WFSSubBlkAllocHdr *)pBlkHdr, nUpdatedNodeOfs, dni.nLog2Size, nUpdatedNodeLog2Size); + } else { + // copy the end of the node to the new node, and free the old node + pUpdatedNodeHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nUpdatedNodeOfs); + *dni.pOfs = nUpdatedNodeOfs; // Update the parent pointer + pUpdatedNodeHdr->nNumEntries = dni.pSubBlkHdr->nNumEntries; + pUpdatedNodeHdr->nStrLen = (u8)(nNodeNumLeft-1); // Needs to be done first so that pDstStart calculation is correct + memcpy(pUpdatedNodeHdr->aFirstChar, &dni.pSubBlkHdr->aFirstChar[nNumMatching+1], nNodeNumLeft + pUpdatedNodeHdr->nNumEntries - 1); + u16 *pDstStart = DirNodeGetOfsTblStartPtr_l2s(pUpdatedNodeHdr, nUpdatedNodeLog2Size); + u16 *pSrcStart = DirNodeGetOfsTblStartPtr_ote(dni.pSubBlkHdr, pExistingNodeOfsTblEnd); + memcpy(pDstStart, pSrcStart, (u32)((u8*)pExistingNodeOfsTblEnd-(u8*)pSrcStart)); + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nOldNodeOfs, dni.nLog2Size); + } + } else { + // the sub block remains the same size + pUpdatedNodeHdr = dni.pSubBlkHdr; + nUpdatedNodeOfs = (u16)((u8*)pUpdatedNodeHdr - (u8*)pBlkHdr); + dbg(SbaCheckOfs(nUpdatedNodeOfs)); + // Remove characters from the start of the string + memmove(pUpdatedNodeHdr->aFirstChar, &pUpdatedNodeHdr->aFirstChar[nNumMatching+1], nNodeNumLeft + pUpdatedNodeHdr->nNumEntries - 1); + } + pUpdatedNodeHdr->nStrLen = (u8)(nNodeNumLeft-1); + *dni.pOfs = nChoiceNodeSubBlkOfs; + dbg(SbaCheckOfs(*dni.pOfs)); + + if ((unsigned)cNodeChar < (unsigned)cNameChar) { + pChoiceNodeHdr->aFirstChar[nNumMatching] = cNodeChar; + pChoiceNodeHdr->aFirstChar[nNumMatching+1] = cNameChar; + pNodeOfsTblEnd[-1] = nUpdatedNodeOfs; + pNodeOfsTblEnd[-2] = nNameSubBlkOfs; + } else { + pChoiceNodeHdr->aFirstChar[nNumMatching] = cNameChar; + pChoiceNodeHdr->aFirstChar[nNumMatching+1] = cNodeChar; + if (cNameChar==0) { + ((u32*)pNodeOfsTblEnd)[-1] = aBlkAdr[1]; + pNodeOfsTblEnd[-3] = nUpdatedNodeOfs; + } else { + pNodeOfsTblEnd[-1] = nNameSubBlkOfs; + pNodeOfsTblEnd[-2] = nUpdatedNodeOfs; + } + } + } + ++pDi->nBlkDepth; + ++pBlkHdr->nNumRecs; + pDi->dni = dni; // To ensure dir node stack gets freed properly later + dbg(DirNodeCheckBlk(pDi)); + TransUnpinBlk(&pDi->tba); + return WFSKRN_RESULT_OK; +} + +WFSKrnResult DirNodeRenameFirstRec(DirBlkHdr *pBlkHdr) { +#if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } +#endif + //DirItr di; + DirNodeItr dni; + dni.nDnsDepth = 0; + WFSKrnReturnOnError(DirNodeStackGetEntry(&dni)); + DirNodeStack **ppDnsRootParent = &dni.pDns->pParent; + u32 nOfs = pBlkHdr->nRootOfs; + u16 *pOfsTblEnd; + WFSBlkAdr nChildBlkAdr; + while(1) { + dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOfs); + dni.nLog2Size = DirNodeGetSubBlkLog2Size(dni.pSubBlkHdr); + pOfsTblEnd = (u16*)((u8*)dni.pSubBlkHdr + (1<nSubBlkOfs = nOfs; + if (dni.pSubBlkHdr->aFirstChar[dni.pSubBlkHdr->nStrLen] == 0) { + // We have found the end of the splitter. Record the child block for later. + nChildBlkAdr = DirNodeGetBlkAdr_ote(dni.pSubBlkHdr, pOfsTblEnd); + break; + } + nOfs = DirNodeGetIntraBlkOfs_ote(1, dni.pSubBlkHdr, pOfsTblEnd); + } + if (dni.nDnsDepth <= 1) { + WFSKrnOutputErrorStr("Error! First rec already NULL"); + } + if (dni.pSubBlkHdr->nNumEntries == 1) { + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nOfs, dni.nLog2Size); + DirPopNodeStackEntry(&dni); + } + u16 nDstChildOfs = 0; + if (dni.nDnsDepth>1) { + nOfs = dni.pDns->nSubBlkOfs; + dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOfs); + dni.nLog2Size = DirNodeGetSubBlkLog2Size(dni.pSubBlkHdr); + nDstChildOfs = DirNodeDeleteSubBlkHead(pBlkHdr, nOfs, 1); + } + if (dni.nDnsDepth>2) { + DirPopNodeStackEntry(&dni); + nOfs = dni.pDns->nSubBlkOfs; + dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOfs); + dni.nLog2Size = DirNodeGetSubBlkLog2Size(dni.pSubBlkHdr); + pOfsTblEnd = (u16*)((u8*)dni.pSubBlkHdr + (1<2) { + DirPopNodeStackEntry(&dni); + } + dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + dni.pDns->nSubBlkOfs); + } else { + pBlkHdr->nRootOfs = nDstChildOfs; + dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + pBlkHdr->nRootOfs); + } + // Insert "" element into root sub block + u32 nUpdatedNodeLog2Size; + dni.nLog2Size = DirNodeGetSubBlkLog2Size(dni.pSubBlkHdr); + u16 *pExistingNodeOfsTblEnd = (u16*)((u8*)dni.pSubBlkHdr + (1<nStrLen != 0) { + // Handle the case where the root sub block has a prefix - requires a new parent sub-node to be added + //DirNodeSubBlkSplitPrefixString(pBlkHdr, dni.pSubBlkHdr, nOfs, 1, 0); + utf8 cChoiceChar = dni.pSubBlkHdr->aFirstChar[0]; + nUpdatedNodeLog2Size = DirNodeGetSubBlkLog2Size_3(dni.pSubBlkHdr->nStrLen-1, dni.pSubBlkHdr->nNumEntries, dni.pSubBlkHdr->aFirstChar[dni.pSubBlkHdr->nStrLen]); + if (nUpdatedNodeLog2Size != dni.nLog2Size) { + // allocate a new sub block + u32 nUpdatedNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nUpdatedNodeLog2Size); + if (nUpdatedNodeOfs == 0) { + return WFSKRN_RESULT_FATAL_ERROR; + } + DirSubBlkHdr *pUpdatedNodeHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nUpdatedNodeOfs); + pUpdatedNodeHdr->nStrLen = dni.pSubBlkHdr->nStrLen - 1; + pUpdatedNodeHdr->nNumEntries = dni.pSubBlkHdr->nNumEntries; + u32 nCopySize1 = pUpdatedNodeHdr->nStrLen + pUpdatedNodeHdr->nNumEntries; + memcpy(pUpdatedNodeHdr->aFirstChar, &dni.pSubBlkHdr->aFirstChar[1], nCopySize1); + u16 *pUpdatedNodeOfsTblEnd = (u16*)((u8*)pUpdatedNodeHdr + (1<nRootOfs, dni.nLog2Size); + pBlkHdr->nRootOfs = nUpdatedNodeOfs; + } else { + dni.pSubBlkHdr->nStrLen--; + u32 nCopySize1 = dni.pSubBlkHdr->nStrLen + dni.pSubBlkHdr->nNumEntries; + memmove(dni.pSubBlkHdr->aFirstChar, &dni.pSubBlkHdr->aFirstChar[1], nCopySize1); + } + + u32 nNewRootNodeLog2Size = DirNodeGetSubBlkLog2Size_3(0, 2, 0); + u16 nNewRootNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNewRootNodeLog2Size); + if (nNewRootNodeOfs == 0) { + return WFSKRN_RESULT_FATAL_ERROR; + } + DirSubBlkHdr *pNewRootNodeHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nNewRootNodeOfs); + pNewRootNodeHdr->nStrLen = 0; + pNewRootNodeHdr->nNumEntries = 2; + pNewRootNodeHdr->aFirstChar[0] = 0; + pNewRootNodeHdr->aFirstChar[1] = cChoiceChar; + u16 *pNewRootOfsTblEnd = (u16*)((u8*)pNewRootNodeHdr + (1<nRootOfs; + pBlkHdr->nRootOfs = nNewRootNodeOfs; + } else { + // case where there is no prefix string in the root sub block + nUpdatedNodeLog2Size = DirNodeGetSubBlkLog2Size_3(dni.pSubBlkHdr->nStrLen, dni.pSubBlkHdr->nNumEntries+1, 0); + if (nUpdatedNodeLog2Size != dni.nLog2Size) { + u32 nUpdatedNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nUpdatedNodeLog2Size); + if (nUpdatedNodeOfs == 0) { + return WFSKRN_RESULT_FATAL_ERROR; + } + DirSubBlkHdr *pUpdatedNodeHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nUpdatedNodeOfs); + u32 nCopySize1 = sizeof(DirSubBlkHdr)-1 + dni.pSubBlkHdr->nStrLen; + memcpy(pUpdatedNodeHdr, dni.pSubBlkHdr, nCopySize1); + ++pUpdatedNodeHdr->nNumEntries; + memcpy((u8*)pUpdatedNodeHdr + nCopySize1 + 1, &dni.pSubBlkHdr->aFirstChar[dni.pSubBlkHdr->nStrLen], dni.pSubBlkHdr->nNumEntries); + pUpdatedNodeHdr->aFirstChar[pUpdatedNodeHdr->nStrLen] = 0; + u16 *pUpdatedNodeOfsTblEnd = (u16*)((u8*)pUpdatedNodeHdr + (1<nRootOfs, dni.nLog2Size); + pBlkHdr->nRootOfs = nUpdatedNodeOfs; + } else { + // Insert new entry without moving sub block + utf8 *pSrc = &dni.pSubBlkHdr->aFirstChar[dni.pSubBlkHdr->nStrLen]; + memmove(pSrc+1, pSrc, dni.pSubBlkHdr->nNumEntries); + u16 *pSrcStart = DirNodeGetOfsTblStartPtr_ote(dni.pSubBlkHdr, pExistingNodeOfsTblEnd); + *pSrc = 0; + ++dni.pSubBlkHdr->nNumEntries; + memmove(pSrcStart-2, pSrcStart, (u8*)pExistingNodeOfsTblEnd - (u8*)pSrcStart); + ((u32*)pExistingNodeOfsTblEnd)[-1] = nChildBlkAdr; + } + } + //dbg(DirNodeCheckBlk(&di)); + DirNodeStackFree(&dni, ppDnsRootParent); + return WFSKRN_RESULT_OK; +} + +u32 nNumNodeBlkSplits=0; +WFSKrnResult DirNodeBlkSplit(DirItr *pDiSrc, WFSBlkAdr *aDstBlkAdr, u32 *pFirstBlockToFree) { + // Split the specified node block into two pieces, at its mid point. + // Copy the first half of the records to new block 1 + // Copy the first half of the records to new block 2 + // Delete the original block and rename new block 2 to be this block + ++nNumNodeBlkSplits; + WFSKrnResult result; + DirItr diSrc=*pDiSrc, diDst; +#if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } + WFSFileName name; + diSrc.dni.pStrPtr = name.sStr; +#endif + u32 nStrIdx=0, nSubBlkStrLen; + + WFSBlkAdr nBlkAdr = diSrc.tba.nBlkAdr; + WFSBlkAdr nParentBlkAdr = 0; + while(diSrc.dni.nDnsDepth > 1) { + if (diSrc.dni.pDns->nBlkAdr != nBlkAdr) { + nParentBlkAdr = diSrc.dni.pDns->nBlkAdr; + break; + } + DirPopNodeStackEntry(&diSrc.dni); + } + DirBlkHdr *pLeftBlkHdr; + DirBlkHdr *pRightBlkHdr; + result = DirCreateAndInitNewBlk4(diSrc.tba.pAreaInfo, aDstBlkAdr[0], WFS_MDF_NULL, diSrc.tba.pTransInfo, &pLeftBlkHdr); + if(result < WFSKRN_RESULT_OK){ + return result; + } + result = DirCreateAndInitNewBlk4(diSrc.tba.pAreaInfo, aDstBlkAdr[1], WFS_MDF_NULL, diSrc.tba.pTransInfo, &pRightBlkHdr); + if(result < WFSKRN_RESULT_OK){ + TransUnpinAndFreeBlks(diSrc.tba.pAreaInfo, diSrc.tba.pAreaInfo->ah.nLog2BlkSize, 1, aDstBlkAdr, diSrc.tba.pTransInfo); + return result; + } + diDst.pBlkHdr = pLeftBlkHdr; + // Initialize a stack frame for traversing the destination block + diDst.dni.nDnsDepth = 0; + WFSKrnReturnOnError(DirNodeStackGetEntry(&diDst.dni)); + diDst.ppDnsRootParent = &diDst.dni.pDns->pParent; + + diSrc.dni.nEntryIdx = 1; + diSrc.dni.pOfs = &diSrc.pBlkHdr->nRootOfs; + dbg(SbaCheckOfs(*diSrc.dni.pOfs)); + WFSKrnReturnOnError(DirPushNodeStackEntry(&diSrc.dni, nBlkAdr)); + diSrc.dni.pDns->nStrIdx = 0; // ToDo: This value can be initialized to 0 because prefix-suppression is not implemented + u16 nSrcNodeOfs = diSrc.dni.pDns->nSubBlkOfs; // = diSrc.pBlkHdr->nRootOfs; + dbg(SbaCheckOfs(nSrcNodeOfs)); + utf8 *pChoiceChar; + u32 nRecIdx=0; + u32 nHalfNumRecs = (u32)(diSrc.pBlkHdr->nNumRecs>>1); + diDst.dni.pOfs = &diDst.pBlkHdr->nRootOfs; + s32 nSplitPointDnsDepth=-1; + u32 nCopied = 1; + u16 nLeftChildOfs = 0; + WFSFileName parentKey; + u32 nSrcNodeStartDepth = diSrc.dni.nDnsDepth; + + // Perform a depth-first traversal of the block, until the middle Node sub-block is found. + while(1) { + diSrc.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)diSrc.pBlkHdr + nSrcNodeOfs); + diSrc.dni.nLog2Size = DirNodeGetSubBlkLog2Size(diSrc.dni.pSubBlkHdr); + // Copy over the whole node from the original block + WFSKrnReturnOnError(DirNodeStackGetEntry(&diDst.dni)); + *diDst.dni.pOfs = diDst.dni.pDns->nSubBlkOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)diDst.pBlkHdr, diSrc.dni.nLog2Size); + diDst.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)diDst.pBlkHdr + *diDst.dni.pOfs); + memcpy(diDst.dni.pSubBlkHdr, diSrc.dni.pSubBlkHdr, (u32)(1<nEntryIdx = 1; + //u16 *pSrcNodeOfsTblEnd = (u16*)((u8*)diSrc.dni.pSubBlkHdr + (1<nEntryIdx = 1; + pChoiceChar = &diSrc.dni.pSubBlkHdr->aFirstChar[diSrc.dni.pSubBlkHdr->nStrLen]; + nSubBlkStrLen = diSrc.dni.pSubBlkHdr->nStrLen; + nStrIdx += nSubBlkStrLen; + diSrc.dni.pDns->nStrIdx = (u8)nStrIdx; +#if _DEBUG_DIR + utf8 *pSubBlkStrPtr = diSrc.dni.pSubBlkHdr->aFirstChar; + while(nSubBlkStrLen--) { + *diSrc.dni.pStrPtr++ = *pSubBlkStrPtr++; + } +#endif + if (*pChoiceChar == 0) { + // String terminator char indicates this is a record, so increment our record count +#if _DEBUG_DIR + *diSrc.dni.pStrPtr = 0; + //MyOSReport("%d. %s\n", nRecIdx, name.sStr); + ++pChoiceChar; +#endif + ++nRecIdx; + if (nRecIdx==nHalfNumRecs+1) { + DirConstructEntryNameFromNodeStack(&parentKey, &diSrc); +#if _DEBUG_DIR + if (strncmp(parentKey.sStr, name.sStr, WFS_MAX_FILE_NAME_SIZE)) { + WFSKrnOutputErrorStr("Error constructing entry name from stack\n"); + } +#endif + // No Shortening for splitters // ToDo: Shortening can be implemented if we ensure the first splitter of all blocks is "" + //parentKey.nLen -= diSrc.dni.pSubBlkHdr->nStrLen; + //parentKey.sStr[parentKey.nLen] = 0; // This shortens the name to the minimum splitter + } + ++diSrc.dni.pDns->nEntryIdx; + ++diDst.dni.pDns->nEntryIdx; + } + while(diSrc.dni.pDns->nEntryIdx > diSrc.dni.pSubBlkHdr->nNumEntries) { + if (diSrc.dni.nDnsDepth == nSrcNodeStartDepth) { + // We reached the top of the stack, so this should be the last record + pLeftBlkHdr->nRootOfs = nLeftChildOfs; + pRightBlkHdr->nRootOfs = diDst.dni.pDns->nSubBlkOfs; + DirNodeStackFree(&diDst.dni, diDst.ppDnsRootParent); + pLeftBlkHdr->nNumRecs = (u16)nHalfNumRecs; + pRightBlkHdr->nNumRecs = (u16)(diSrc.pBlkHdr->nNumRecs - nHalfNumRecs); + if (diSrc.pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_ROOT_BLK) { + nParentBlkAdr = nBlkAdr; + DirReinitBlk(diSrc.tba.pAreaInfo, diSrc.pBlkHdr, (WFSMetaDataFlags)WFS_MDF_DIR_ROOT_BLK); + } else { + DirUnpinAndFreeBlk(diSrc.tba.pAreaInfo, nBlkAdr, diSrc.tba.pTransInfo); + diSrc.tba.nBlkAdr = nParentBlkAdr; +#if _CHECK_BLK_USAGE // for debug + if(DeviceDebugGetPseudoDetachDevice() == 0){ + DeviceDebugSetPseudoDetachDevice(1); + } + if(DeviceDebugGetPseudoHashInconsistent() == 0){ + DeviceDebugSetPseudoHashInconsistent(1); + } +#endif + WFSKrnReturnOnError( DirGetBlk(&diSrc, TRANS_FLAG_RW_BLK | BCACHE_FLAG_PINNED, 0) ); // must be debug + } + TransUnpinBlk3(diSrc.tba.pAreaInfo, aDstBlkAdr[0], diSrc.tba.pTransInfo); + WFSKrnReturnOnError(DirNodeInsertEntry(&parentKey, &diSrc, aDstBlkAdr, pFirstBlockToFree)); + *pDiSrc=diSrc; + WFSKrnResult result = DirNodeRenameFirstRec(pRightBlkHdr); + TransUnpinBlk3(diSrc.tba.pAreaInfo, aDstBlkAdr[1], diSrc.tba.pTransInfo); + return result; + } + u16 nDstChildOfs = diDst.dni.pDns->nSubBlkOfs; + DirPopNodeStackEntry(&diDst.dni); + DirPopNodeStackEntry(&diSrc.dni); +#if _DEBUG_DIR + diSrc.dni.pStrPtr += diSrc.dni.pDns->nStrIdx - nStrIdx; +#endif + nStrIdx = diSrc.dni.pDns->nStrIdx; + diSrc.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)diSrc.pBlkHdr + diSrc.dni.pDns->nSubBlkOfs); + if (nSplitPointDnsDepth >= (s32)diSrc.dni.nDnsDepth) { + // This is a node which straddles the left and right halves of the source block. + // At this point it has already been copied in whole to the left block. + // We need to move part of it to the right block, and remove unused entries from the left block. + nSplitPointDnsDepth = (s32)(diSrc.dni.nDnsDepth-1); + u32 nRightNumEntries = (u32)(diSrc.dni.pSubBlkHdr->nNumEntries - diSrc.dni.pDns->nEntryIdx + 1); + u32 nLeftNumEntries = diSrc.dni.pDns->nEntryIdx - nCopied; + u16 nLeftOfs = diDst.dni.pDns->nSubBlkOfs; + nDstChildOfs = diDst.dni.pDns->nSubBlkOfs = DirNodeCopySubBlkTail(pLeftBlkHdr, nLeftOfs, pRightBlkHdr, nRightNumEntries, nDstChildOfs, false); + dbg(SbaCheckOfs(nDstChildOfs)); + if (nCopied==0) { + DirSubBlkHdr *pLeftSubBlkHdr = (DirSubBlkHdr *)((u8*)pLeftBlkHdr + nLeftOfs); + diSrc.dni.nLog2Size = DirNodeGetSubBlkLog2Size(diSrc.dni.pSubBlkHdr); + DirNodeSetIntraBlkOfs_l2s(diSrc.dni.pDns->nEntryIdx, nLeftChildOfs, pLeftSubBlkHdr, diSrc.dni.nLog2Size); + } + nLeftChildOfs = DirNodeDeleteSubBlkTail(pLeftBlkHdr, nLeftOfs, nLeftNumEntries); + dbg(if (nLeftChildOfs == 0) { + // This is not expected to happen since the newly split block should have plenty of free space + WFSKrnOutputErrorStr("Fatal Error!\n"); + }) + diDst.dni.pDns->nEntryIdx = 1; + nCopied = 0; + } + ++diDst.dni.pDns->nEntryIdx; + ++diSrc.dni.pDns->nEntryIdx; + } + if ((nRecIdx==nHalfNumRecs)&&(nSplitPointDnsDepth<0)) { + // We have found the middle record of the Node block. + // This code should only be executed once during the loop + nSplitPointDnsDepth = (s32)diSrc.dni.nDnsDepth; + diDst.pBlkHdr = pRightBlkHdr; + } +#if _DEBUG_DIR + pChoiceChar = &diSrc.dni.pSubBlkHdr->aFirstChar[diSrc.dni.pSubBlkHdr->nStrLen + diSrc.dni.pDns->nEntryIdx-1]; + *diSrc.dni.pStrPtr = *pChoiceChar; +#endif + ++nStrIdx; + diSrc.dni.nLog2Size = DirNodeGetSubBlkLog2Size(diSrc.dni.pSubBlkHdr); + { + // Calculate the correct address for diDst.dni.pOfs + if ((nRecIdx < nHalfNumRecs) || (nSplitPointDnsDepth >= diSrc.dni.nDnsDepth)) { + diDst.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pLeftBlkHdr + diDst.dni.pDns->nSubBlkOfs); + diDst.dni.pOfs = DirNodeGetIntraBlkOfsPtr_l2s(diSrc.dni.pDns->nEntryIdx, diDst.dni.pSubBlkHdr, diSrc.dni.nLog2Size); + dbg(SbaCheckOfs(*diDst.dni.pOfs)); + } else { + diDst.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pRightBlkHdr + diDst.dni.pDns->nSubBlkOfs); + diDst.dni.nLog2Size = DirNodeGetSubBlkLog2Size(diDst.dni.pSubBlkHdr); + diDst.dni.pOfs = DirNodeGetIntraBlkOfsPtr_l2s(diDst.dni.pDns->nEntryIdx, diDst.dni.pSubBlkHdr, diDst.dni.nLog2Size); + } + } + nSrcNodeOfs = DirNodeGetIntraBlkOfs_l2s(diSrc.dni.pDns->nEntryIdx, diSrc.dni.pSubBlkHdr, diSrc.dni.nLog2Size); + dbg(SbaCheckOfs(nSrcNodeOfs)); + WFSKrnReturnOnError(DirNodeStackGetEntry(&diSrc.dni)); + diSrc.dni.pDns->nBlkAdr = nBlkAdr; + diSrc.dni.pDns->nSubBlkOfs = nSrcNodeOfs; +#if _DEBUG_DIR + ++diSrc.dni.pStrPtr; +#endif + } +} + +WFSKrnResult DirReGetHashAdr(AreaInfo *pAreaInfo, DirEntryAttrHdr *pAttrHdr, WFSBlkAdr nNewBlkAdr, DirBlkHdr* pNewBlkHdr){ + WFSKrnResult nResult = WFSKRN_RESULT_UNKNOWN; + switch(pAttrHdr->nSizeCategory) { + case FILE_SIZE_CATEGORY_SMALL:{ + u32 nNumFileBlks = ((pAttrHdr->nAllocSize-1)>>pAreaInfo->ah.nLog2BlkSize)+1; + u32 nI; + for(nI=0;nInAttrLog2Size, nI); + u32 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pNewBlkHdr; + nResult = BCacheSetHash(pAreaInfo->pVolInfo, pFileBlkPtr->nBlkAdr, nNewBlkAdr, nHashOfs); + if (nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND) { + return nResult; + } + } + break; + } + case FILE_SIZE_CATEGORY_MEDIUM:{ + u32 nNumFileMediumBlks = ((pAttrHdr->nAllocSize-1)>>pAreaInfo->ah.nLog2MediumBlkSize)+1; + u32 nI; + for(nI=0;nInAttrLog2Size, nI); + u32 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pNewBlkHdr; + nResult = BCacheSetHash(pAreaInfo->pVolInfo, pFileBlkPtr->nBlkAdr, nNewBlkAdr, nHashOfs); + if (nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND) { + return nResult; + } + } + break; + } + case FILE_SIZE_CATEGORY_LARGE: { + u32 nNumBlks = ((pAttrHdr->nAllocSize-1)>>pAreaInfo->ah.nLog2MediumBlkSize)+1; + WFSFileLargeBlkPtr *pFileLargeBlkPtr = 0; + u32 nI; + for(nI=0;nInLog2MediumBlkPerLargeBlk))){ + pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrForCategoryLarge(pAttrHdr, pAttrHdr->nAttrLog2Size, nI>>pAreaInfo->nLog2MediumBlkPerLargeBlk); + } + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge(pAreaInfo, pFileLargeBlkPtr, nI%(1<nLog2MediumBlkPerLargeBlk)); + u32 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pNewBlkHdr; + nResult = BCacheSetHash(pAreaInfo->pVolInfo, fileBlkInfo.nBlkAdr, nNewBlkAdr, nHashOfs); + if (nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND) { + return nResult; + } + } + } + default: + break; + } + return WFSKRN_RESULT_OK; +} + + +u32 nNumLeafBlkSplits = 0; +static +WFSKrnResult DirLeafBlkSplit(DirItr *pDiSrc) { + // Split the specified leaf block into two pieces, at its mid point. + // Copy the first half of the records to new block 1 + // Copy the first half of the records to new block 2 + // Delete the original block and rename new block 2 to be this block + dbg(DirLeafCheckBlk(pDiSrc)); + DirItr diSrc=*pDiSrc, diDst; +#if _DEBUG_DIR + ++nNumLeafBlkSplits; + if (nNumLeafBlkSplits==3086) { + int a;a=0; + } + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } + WFSFileName name; + diSrc.dni.pStrPtr = name.sStr; +#endif + WFSKrnResult nResult; + u32 nStrIdx=0, nSubBlkStrLen; + // Allocate new blocks + WFSBlkAdr nBlkAdr = diSrc.tba.nBlkAdr; + WFSBlkAdr aDstBlkAdr[DIR_MAX_SPLIT_BLK_ALLOC]; + WFSKrnReturnOnError(AreaAllocBlks(diSrc.tba.pAreaInfo, nBlkAdr, diSrc.tba.pAreaInfo->ah.nLog2BlkSize, DIR_MAX_SPLIT_BLK_ALLOC, aDstBlkAdr, sizeof(WFSBlkAdr))); + WFSBlkAdr nParentBlkAdr = 0; + while(diSrc.dni.nDnsDepth > 1) { + if (diSrc.dni.pDns->nBlkAdr != nBlkAdr) { + nParentBlkAdr = diSrc.dni.pDns->nBlkAdr; + break; + } + DirPopNodeStackEntry(&diSrc.dni); + } + DirBlkHdr *pLeftBlkHdr; + DirBlkHdr *pRightBlkHdr; + nResult = DirCreateAndInitNewBlk4(diSrc.tba.pAreaInfo, aDstBlkAdr[0], WFS_MDF_DIR_LEAF_BLK, diSrc.tba.pTransInfo, &pLeftBlkHdr); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + nResult = DirCreateAndInitNewBlk4(diSrc.tba.pAreaInfo, aDstBlkAdr[1], WFS_MDF_DIR_LEAF_BLK, diSrc.tba.pTransInfo, &pRightBlkHdr); + if(nResult < WFSKRN_RESULT_OK){ + TransUnpinAndFreeBlks(diSrc.tba.pAreaInfo, diSrc.tba.pAreaInfo->ah.nLog2BlkSize, 1, aDstBlkAdr, diSrc.tba.pTransInfo); + return nResult; + } +#if _DEBUG_BREAK_POINT + if(aDstBlkAdr[0] == 6370 || aDstBlkAdr[1] == 6370){ + int a; a=0; + } +#endif + WFSBlkAdr nCurrentDstBlkAdr = aDstBlkAdr[0]; + diDst.pBlkHdr = pLeftBlkHdr; + // Initialize a stack frame for traversing the destination block + diDst.dni.nDnsDepth = 0; + nResult = DirNodeStackGetEntry(&diDst.dni); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + diDst.ppDnsRootParent = &diDst.dni.pDns->pParent; + diSrc.dni.nEntryIdx = 1; + diSrc.dni.pOfs = &diSrc.pBlkHdr->nRootOfs; + dbg(SbaCheckOfs(*diSrc.dni.pOfs)); + nResult = DirPushNodeStackEntry(&diSrc.dni, nBlkAdr); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + diSrc.dni.pDns->nStrIdx = 0; // ToDo: This value can be initialized to 0 because prefix-suppression is not implemented + u16 nSrcNodeOfs = diSrc.dni.pDns->nSubBlkOfs; // = diSrc.pBlkHdr->nRootOfs; + utf8 *pChoiceChar; + u32 nRecIdx=0; + u32 nHalfNumRecs = (u32)(diSrc.pBlkHdr->nNumRecs>>1); + diDst.dni.pOfs = &diDst.pBlkHdr->nRootOfs; + //dbg(SbaCheckOfs(*diDst.dni.pOfs)); + s32 nSplitPointDnsDepth=-1; + u32 nCopied = 1; + u16 nLeftChildOfs = 0; + WFSFileName parentKey; + u32 nSrcLeafStartDepth = diSrc.dni.nDnsDepth; + + // Perform a depth-first traversal of the block, until the middle leaf sub-block is found. + while(1) { + diSrc.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)diSrc.pBlkHdr + nSrcNodeOfs); + diSrc.dni.nLog2Size = DirLeafGetSubBlkLog2Size(diSrc.dni.pSubBlkHdr); + // Copy over the whole node from the original block + nResult = DirNodeStackGetEntry(&diDst.dni); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + *diDst.dni.pOfs = diDst.dni.pDns->nSubBlkOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)diDst.pBlkHdr, diSrc.dni.nLog2Size); + diDst.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)diDst.pBlkHdr + *diDst.dni.pOfs); + memcpy(diDst.dni.pSubBlkHdr, diSrc.dni.pSubBlkHdr, (u32)(1<nEntryIdx = 1; + u16 *pSrcNodeOfsTblEnd = (u16*)((u8*)diSrc.dni.pSubBlkHdr + (1<nEntryIdx = 1; + pChoiceChar = &diSrc.dni.pSubBlkHdr->aFirstChar[diSrc.dni.pSubBlkHdr->nStrLen]; + + nSubBlkStrLen = diSrc.dni.pSubBlkHdr->nStrLen; + nStrIdx += nSubBlkStrLen; + diSrc.dni.pDns->nStrIdx = (u8)nStrIdx; +#if _DEBUG_DIR + utf8 *pSubBlkStrPtr = diSrc.dni.pSubBlkHdr->aFirstChar; + while(nSubBlkStrLen--) { + *diSrc.dni.pStrPtr++ = *pSubBlkStrPtr++; + } +#endif + if (*pChoiceChar == 0) { + // String terminator char indicates this is a record, so increment our record count +#if _DEBUG_DIR + *diSrc.dni.pStrPtr = 0; + ++pChoiceChar; +#endif + // Copy file attributes to new block + u32 nAttrOfs = pSrcNodeOfsTblEnd[-1]; + dbg(SbaCheckOfs(nAttrOfs)); + DirEntryAttrHdr *pAttrHdr = (DirEntryAttrHdr *)((u8*)diSrc.pBlkHdr + nAttrOfs); + u16 *pDstNodeOfsTblEnd = (u16*)((u8*)diDst.dni.pSubBlkHdr + (1<nAttrLog2Size); + DirEntryAttrHdr *pDstAttrHdr = (DirEntryAttrHdr *)((u8*)diDst.pBlkHdr + pDstNodeOfsTblEnd[-1]); + memcpy(pDstAttrHdr, pAttrHdr, (u32)(1<nAttrLog2Size)); + // Update to the new hash pointer in file attributes + nResult = DirReGetHashAdr(diSrc.tba.pAreaInfo, pDstAttrHdr, nCurrentDstBlkAdr, diDst.pBlkHdr); + if (nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND) { + goto Error; + } + ++nRecIdx; + if (nRecIdx==nHalfNumRecs+1) { + DirConstructEntryNameFromNodeStack(&parentKey, &diSrc); +#if _DEBUG_DIR + if (strncmp(parentKey.sStr, name.sStr, WFS_MAX_FILE_NAME_SIZE)) { + WFSKrnOutputErrorStr("Error constructing entry name from stack\n"); + }; +#endif + parentKey.nLen -= diSrc.dni.pSubBlkHdr->nStrLen; + parentKey.sStr[parentKey.nLen] = 0; // This shortens the name to the minimum splitter. ToDo: Can be shortened more in many cases + } + ++diSrc.dni.pDns->nEntryIdx; + ++diDst.dni.pDns->nEntryIdx; + } + while(diSrc.dni.pDns->nEntryIdx > diSrc.dni.pSubBlkHdr->nNumEntries) { + if (diSrc.dni.nDnsDepth == nSrcLeafStartDepth) { + // We reached the top of the stack, so this should be the last record + pLeftBlkHdr->nRootOfs = nLeftChildOfs; + pRightBlkHdr->nRootOfs = diDst.dni.pDns->nSubBlkOfs; + DirNodeStackFree(&diDst.dni, diDst.ppDnsRootParent); + pLeftBlkHdr->nNumRecs = (u16)nHalfNumRecs; + pRightBlkHdr->nNumRecs = (u16)(diSrc.pBlkHdr->nNumRecs - nHalfNumRecs); + TransUnpinBlk3(diSrc.tba.pAreaInfo, aDstBlkAdr[0], diSrc.tba.pTransInfo); + TransUnpinBlk3(diSrc.tba.pAreaInfo, aDstBlkAdr[1], diSrc.tba.pTransInfo); + if (diSrc.pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_ROOT_BLK) { + nParentBlkAdr = nBlkAdr; + DirReinitBlk(diSrc.tba.pAreaInfo, diSrc.pBlkHdr, WFS_MDF_DIR_ROOT_BLK); + } else { + DirUnpinAndFreeBlk(diSrc.tba.pAreaInfo, nBlkAdr, diSrc.tba.pTransInfo); + diSrc.tba.nBlkAdr = nParentBlkAdr; +#if _CHECK_BLK_USAGE // for debug + if(DeviceDebugGetPseudoDetachDevice() == 0){ + DeviceDebugSetPseudoDetachDevice(1); + } + if(DeviceDebugGetPseudoHashInconsistent() == 0){ + DeviceDebugSetPseudoHashInconsistent(1); + } +#endif + nResult = DirGetBlk(&diSrc, TRANS_FLAG_RW_BLK | BCACHE_FLAG_PINNED, 0); // must be debug + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + } + *pDiSrc=diSrc; + u32 nFirstBlockToFree = 2; + nResult = DirNodeInsertEntry(&parentKey, pDiSrc, aDstBlkAdr, &nFirstBlockToFree); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + nResult = TransFreeBlks5(diSrc.tba.pAreaInfo, diSrc.tba.pAreaInfo->ah.nLog2BlkSize, DIR_MAX_SPLIT_BLK_ALLOC-nFirstBlockToFree, &aDstBlkAdr[nFirstBlockToFree], diSrc.tba.pTransInfo); + if (nResult != WFSKRN_RESULT_OK) { + WFSKrnOutputErrorCode(nResult); + } + return WFSKRN_RESULT_OK; + } + u16 nDstChildOfs = diDst.dni.pDns->nSubBlkOfs; + DirPopNodeStackEntry(&diDst.dni); + DirPopNodeStackEntry(&diSrc.dni); +#if _DEBUG_DIR + diSrc.dni.pStrPtr += diSrc.dni.pDns->nStrIdx - nStrIdx; +#endif + nStrIdx = diSrc.dni.pDns->nStrIdx; + diSrc.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)diSrc.pBlkHdr + diSrc.dni.pDns->nSubBlkOfs); + if (nSplitPointDnsDepth >= (s32)diSrc.dni.nDnsDepth) { + // This is a node which straddles the left and right halves of the source block. + // At this point it has already been copied in whole to the left block. + // We need to move part of it to the right block, and remove unused entries from the left block. + nSplitPointDnsDepth = (s32)(diSrc.dni.nDnsDepth-1); + u32 nRightNumEntries = (u32)(diSrc.dni.pSubBlkHdr->nNumEntries - diSrc.dni.pDns->nEntryIdx + 1); + u32 nLeftNumEntries = diSrc.dni.pDns->nEntryIdx - nCopied; + u16 nLeftOfs = diDst.dni.pDns->nSubBlkOfs; + nDstChildOfs = diDst.dni.pDns->nSubBlkOfs = DirLeafCopySubBlkTail(pLeftBlkHdr, nLeftOfs, pRightBlkHdr, nRightNumEntries, nDstChildOfs, false); + dbg(SbaCheckOfs(nDstChildOfs)); + if (nCopied==0) { + DirSubBlkHdr *pLeftSubBlkHdr = (DirSubBlkHdr *)((u8*)pLeftBlkHdr + nLeftOfs); + diSrc.dni.nLog2Size = DirLeafGetSubBlkLog2Size(diSrc.dni.pSubBlkHdr); + DirLeafSetIntraBlkOfs_l2s(diSrc.dni.pDns->nEntryIdx, nLeftChildOfs, pLeftSubBlkHdr, diSrc.dni.nLog2Size); + } + nLeftChildOfs = DirLeafDeleteSubBlkTail(pLeftBlkHdr, nLeftOfs, nLeftNumEntries); + dbg(if (nLeftChildOfs == 0) { + // This is not expected to happen since the newly split block should have plenty of free space + WFSKrnOutputErrorStr("Fatal Error!\n"); + }) + diDst.dni.pDns->nEntryIdx = 1; + nCopied = 0; + } + ++diDst.dni.pDns->nEntryIdx; + ++diSrc.dni.pDns->nEntryIdx; + } + if ((nRecIdx==nHalfNumRecs)&&(nSplitPointDnsDepth<0)) { + // We have found the middle record of the leaf block. + // This code should only be executed once during the loop + nSplitPointDnsDepth = (s32)diSrc.dni.nDnsDepth; + nCurrentDstBlkAdr = aDstBlkAdr[1]; + diDst.pBlkHdr = pRightBlkHdr; + } +#if _DEBUG_DIR + pChoiceChar = &diSrc.dni.pSubBlkHdr->aFirstChar[diSrc.dni.pSubBlkHdr->nStrLen + diSrc.dni.pDns->nEntryIdx-1]; + *diSrc.dni.pStrPtr = *pChoiceChar; +#endif + ++nStrIdx; + diSrc.dni.nLog2Size = DirLeafGetSubBlkLog2Size(diSrc.dni.pSubBlkHdr); + pSrcNodeOfsTblEnd = (u16*)((u8*)diSrc.dni.pSubBlkHdr + (1<= diSrc.dni.nDnsDepth)) { + diDst.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pLeftBlkHdr + diDst.dni.pDns->nSubBlkOfs); + diDst.dni.pOfs = DirLeafGetIntraBlkOfsPtr_l2s(diSrc.dni.pDns->nEntryIdx, diDst.dni.pSubBlkHdr, diSrc.dni.nLog2Size); + dbg(SbaCheckOfs(*diDst.dni.pOfs)); + } else { + diDst.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pRightBlkHdr + diDst.dni.pDns->nSubBlkOfs); + diDst.dni.nLog2Size = DirLeafGetSubBlkLog2Size(diDst.dni.pSubBlkHdr); + diDst.dni.pOfs = DirLeafGetIntraBlkOfsPtr_l2s(diDst.dni.pDns->nEntryIdx, diDst.dni.pSubBlkHdr, diDst.dni.nLog2Size); + //dbg(SbaCheckOfs(*diDst.dni.pOfs)); + } + } + nSrcNodeOfs = pSrcNodeOfsTblEnd[-(s32)diSrc.dni.pDns->nEntryIdx]; + dbg(SbaCheckOfs(nSrcNodeOfs)); + nResult = DirNodeStackGetEntry(&diSrc.dni); + if (nResult != WFSKRN_RESULT_OK) { + goto Error; + } + diSrc.dni.pDns->nBlkAdr = nBlkAdr; + diSrc.dni.pDns->nSubBlkOfs = nSrcNodeOfs; +#if _DEBUG_DIR + ++diSrc.dni.pStrPtr; +#endif + } +Error: + TransFreeBlks5(diSrc.tba.pAreaInfo, diSrc.tba.pAreaInfo->ah.nLog2BlkSize, DIR_MAX_SPLIT_BLK_ALLOC, aDstBlkAdr, diSrc.tba.pTransInfo); + return nResult; +} + + +static WFSKrnResult _DirSbaAllocSubBlkForResize(DirItr *pDi, u32 nLog2Size, u32 *pNewAttrOfs, DirEntryAttrHdr **ppNewAttrHdr){ + while(1) { + // Alloc sub block as the new file attributes + dbg(DirLeafCheckBlk(pDi)); + *pNewAttrOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pDi->pBlkHdr, nLog2Size); + if (*pNewAttrOfs) { + break; + } + // Split the leaf and retry + // ToDo: Update the update map. + // Note: We should not assume that any iterator which performs a resize is going to be registered in the update map. + // The file-size may be changed on file close, after which the iterator is no longer needed. + DirItrUnmapBlks(pDi); + WFSKrnReturnOnError(DirLeafBlkSplit(pDi)); + s32 nDepth=pDi->dni.nDnsDepth-2; + DirNodeStack *pDns = pDi->dni.pDns; + for(; nDepth>0; --nDepth) { + pDns = pDns->pParent; + } + DirItrCloseNoUnpin(pDi); + if (pDi->tba.nBlkAdr != pDns->nBlkAdr) { + pDi->tba.nBlkAdr = pDns->nBlkAdr; + } + pDi->nBlkDepth = 0; + WFSKrnResult nResult = DirFind(&pDi->name, pDi, DIR_MAX_BLK_DEPTH, DIR_FIND_MODE_NORMAL); + if (nResult != WFSKRN_RESULT_DIR_ENTRY_FOUND) { + return nResult; + } + nResult = DirGetBlk(pDi, TRANS_FLAG_RW_BLK, 0); + if (nResult < WFSKRN_RESULT_OK) { + return nResult; + } + DirItrMapBlks(pDi); + } + *ppNewAttrHdr = (DirEntryAttrHdr *)((u8*)pDi->pBlkHdr + *pNewAttrOfs); + return WFSKRN_RESULT_OK; +} + + +#define FILE_RESIZE_CATEGORY_VERY_SMALL_TO_VERY_SMALL ((FILE_SIZE_CATEGORY_VERY_SMALL<<4) + FILE_SIZE_CATEGORY_VERY_SMALL) +#define FILE_RESIZE_CATEGORY_VERY_SMALL_TO_SMALL ((FILE_SIZE_CATEGORY_VERY_SMALL<<4) + FILE_SIZE_CATEGORY_SMALL) +#define FILE_RESIZE_CATEGORY_VERY_SMALL_TO_MEDIUM ((FILE_SIZE_CATEGORY_VERY_SMALL<<4) + FILE_SIZE_CATEGORY_MEDIUM) +#define FILE_RESIZE_CATEGORY_VERY_SMALL_TO_LARGE ((FILE_SIZE_CATEGORY_VERY_SMALL<<4) + FILE_SIZE_CATEGORY_LARGE) +#define FILE_RESIZE_CATEGORY_VERY_SMALL_TO_VERY_LARGE ((FILE_SIZE_CATEGORY_VERY_SMALL<<4) + FILE_SIZE_CATEGORY_VERY_LARGE) +#define FILE_RESIZE_CATEGORY_SMALL_TO_VERY_SMALL ((FILE_SIZE_CATEGORY_SMALL <<4) + FILE_SIZE_CATEGORY_VERY_SMALL) +#define FILE_RESIZE_CATEGORY_SMALL_TO_SMALL ((FILE_SIZE_CATEGORY_SMALL <<4) + FILE_SIZE_CATEGORY_SMALL) +#define FILE_RESIZE_CATEGORY_SMALL_TO_MEDIUM ((FILE_SIZE_CATEGORY_SMALL <<4) + FILE_SIZE_CATEGORY_MEDIUM) +#define FILE_RESIZE_CATEGORY_SMALL_TO_LARGE ((FILE_SIZE_CATEGORY_SMALL <<4) + FILE_SIZE_CATEGORY_LARGE) +#define FILE_RESIZE_CATEGORY_SMALL_TO_VERY_LARGE ((FILE_SIZE_CATEGORY_SMALL <<4) + FILE_SIZE_CATEGORY_VERY_LARGE) +#define FILE_RESIZE_CATEGORY_MEDIUM_TO_VERY_SMALL ((FILE_SIZE_CATEGORY_MEDIUM <<4) + FILE_SIZE_CATEGORY_VERY_SMALL) +#define FILE_RESIZE_CATEGORY_MEDIUM_TO_SMALL ((FILE_SIZE_CATEGORY_MEDIUM <<4) + FILE_SIZE_CATEGORY_SMALL) +#define FILE_RESIZE_CATEGORY_MEDIUM_TO_MEDIUM ((FILE_SIZE_CATEGORY_MEDIUM <<4) + FILE_SIZE_CATEGORY_MEDIUM) +#define FILE_RESIZE_CATEGORY_MEDIUM_TO_LARGE ((FILE_SIZE_CATEGORY_MEDIUM <<4) + FILE_SIZE_CATEGORY_LARGE) +#define FILE_RESIZE_CATEGORY_MEDIUM_TO_VERY_LARGE ((FILE_SIZE_CATEGORY_MEDIUM <<4) + FILE_SIZE_CATEGORY_VERY_LARGE) +#define FILE_RESIZE_CATEGORY_LARGE_TO_VERY_SMALL ((FILE_SIZE_CATEGORY_LARGE <<4) + FILE_SIZE_CATEGORY_VERY_SMALL) +#define FILE_RESIZE_CATEGORY_LARGE_TO_SMALL ((FILE_SIZE_CATEGORY_LARGE <<4) + FILE_SIZE_CATEGORY_SMALL) +#define FILE_RESIZE_CATEGORY_LARGE_TO_MEDIUM ((FILE_SIZE_CATEGORY_LARGE <<4) + FILE_SIZE_CATEGORY_MEDIUM) +#define FILE_RESIZE_CATEGORY_LARGE_TO_LARGE ((FILE_SIZE_CATEGORY_LARGE <<4) + FILE_SIZE_CATEGORY_LARGE) +#define FILE_RESIZE_CATEGORY_LARGE_TO_VERY_LARGE ((FILE_SIZE_CATEGORY_LARGE <<4) + FILE_SIZE_CATEGORY_VERY_LARGE) +#define FILE_RESIZE_CATEGORY_VERY_LARGE_TO_VERY_SMALL ((FILE_SIZE_CATEGORY_VERY_LARGE<<4) + FILE_SIZE_CATEGORY_VERY_SMALL) +#define FILE_RESIZE_CATEGORY_VERY_LARGE_TO_SMALL ((FILE_SIZE_CATEGORY_VERY_LARGE<<4) + FILE_SIZE_CATEGORY_SMALL) +#define FILE_RESIZE_CATEGORY_VERY_LARGE_TO_MEDIUM ((FILE_SIZE_CATEGORY_VERY_LARGE<<4) + FILE_SIZE_CATEGORY_MEDIUM) +#define FILE_RESIZE_CATEGORY_VERY_LARGE_TO_LARGE ((FILE_SIZE_CATEGORY_VERY_LARGE<<4) + FILE_SIZE_CATEGORY_LARGE) +#define FILE_RESIZE_CATEGORY_VERY_LARGE_TO_VERY_LARGE ((FILE_SIZE_CATEGORY_VERY_LARGE<<4) + FILE_SIZE_CATEGORY_VERY_LARGE) + + +WFSKrnResult DirResizeFile(DirItr *pDi, WFSFileSize nNewSize) { + + // Resize file cases + // The resize file operation is complicated by the fact that files have to be laid out + // differently depending on which of 5 size categories they fall into. + // We can go from any category to any other category. + // + // To: Very Small Size Category | Small Size Category | Medium Size Category | Large Size Category | Very Large Size Category | + // --From:-----+-------------------------+----------------------------+---------------------------------+---------------------------------+---------------------------------+ + // | Copy data directly from | Allocate new block(s) | Allocate new medium block(s) | Allocate new large block(s) | Allocate new large blocks and | + // Very Small | old attr sub-block to | -------------------------- | ------------------------------- | ------------------------------- | indirect block(s). | + // Size | new attr sub-block | Copy data from old attr | Copy data from old attr sub- | Copy data from old attr sub- | ------------------------------- | + // Category | | sub-block to first new | block to first large block. | block to first large block. | Copy data from old attr sub- | + // | | block. | ------------------------------- | ------------------------------- | block to first large block. | + // | | -------------------------- | Calculate hash for first 64KB | Calculate hash for first 64KB | ------------------------------- | + // | | Calculate hash for new | and write to new attr sub-block | and write to new attr sub-block | Calculate hash for first 64KB | + // | | block and write to new | | | of large block, and write to | + // | | attr sub-block along | | | first indirect block along with | + // | | with pointers to new | | | pointer. | + // | | blocks. | | | ------------------------------- | + // | | | | | Write pointers to indirect | + // | | | | | block(s) to new attr sub-block. | + // ------------+-------------------------+----------------------------+---------------------------------+---------------------------------+---------------------------------+ + // Small Size | Copy data from first | Allocate new blocks or | Allocate new medium blocks. | Allocate new large blocks. | Allocate new large blocks and | + // Category | block to new attr | free old ones depending | ------------------------------- | ------------------------------- | indirect block(s). | + // | sub-block | on change in file size | Copy data from old blocks to | Copy data from old blocks to | ------------------------------- | + // | ----------------------- | -------------------------- | new large blocks. | new large blocks. | Copy data from old blocks to | + // | Free old block(s). | Copy pointers from old | ------------------------------- | ------------------------------- | first new large block. | + // | | attr sub-block to new | Re-calculate hash values at | Re-calculate hash values at | ------------------------------- | + // | | attr sub-block | 64KB granularity, and write to | 64KB granularity, and write to | Copy pointers and hash values | + // | | | new attr sub-block. | new attr sub-block. | from old attr sub-block to | + // | | | ------------------------------- | ------------------------------- | first new indirect block. | + // | | | Free old blocks. | Free old blocks. | ------------------------------- | + // | | | | | Write pointers to indirect | + // | | | | | block(s) to new attr sub-block. | + // ------------+-------------------------+----------------------------+---------------------------------+---------------------------------+---------------------------------+ + // Medium Size | Copy data from first | Convert the first medium | Allocate new medium blocks or | Allocate new large blocks. | Allocate new large block(s) | + // Category | medium block to new | block into small block(s), | free old ones depending on | ------------------------------- | and indirect block(s). | + // | attr sub-block | calculate hash values on | change in file size. | Copy data from old blocks to | ------------------------------- | + // | ----------------------- | the granularity of small | ------------------------------- | new large blocks. | Copy data from old blocks to | + // | Free old large block(s) | blocks, and store with | copy pointers from old attr | ------------------------------- | new large blocks. | + // | | pointers in the new attr | sub-block to new attr sub-block | copy pointers from old attr | ------------------------------- | + // | | sub-block. | | sub-block to new attr sub-block.| copy pointers from old attr | + // | | -------------------------- | | ------------------------------- | sub-block to new attr sub-block.| + // | | Free unused blocks and | | Free old blocks. | ------------------------------- | + // | | unused parts of the first | | | Free old blocks. | + // | | block. | | | | + // ------------+-------------------------+----------------------------+---------------------------------+---------------------------------+---------------------------------+ + // Large Size | Copy data from first | Convert the first large | Allocate new large blocks or | Allocate new large blocks or | Allocate new large block(s) | + // Category | large block to new | block into small block(s), | free old ones depending on | free old ones depending on | and indirect block(s). | + // | attr sub-block | calculate hash values on | change in file size. | change in file size. | ------------------------------- | + // | ----------------------- | the granularity of small | ------------------------------- | ------------------------------- | Copy pointers and hash values | + // | Free old large block(s) | blocks, and store with | copy pointers from old attr | copy pointers from old attr | from old attr sub-block to | + // | | pointers in the new attr | sub-block to new attr sub-block | sub-block to new attr sub-block | first new indirect block. | + // | | sub-block. | | | ------------------------------- | + // | | -------------------------- | | | Write pointers to indirect | + // | | Free unused blocks and | | | block(s) to new attr sub-block. | + // | | unused parts of the first | | | | + // | | block. | | | | + // ------------+-------------------------+----------------------------+---------------------------------+---------------------------------+---------------------------------+ + // Very Large | Copy data from first | Convert the first large | Copy pointers and hash values | Copy pointers and hash values | Allocate new large blocks and/ | + // Size | large block to new | block into small block(s), | from old indirect block to new | from old indirect block to new | or indirect block(s), or free | + // Category | attr sub-block | calculate hash values on | attr sub-block. | attr sub-block. | old large blocks and/or | + // | ----------------------- | the granularity of small | ------------------------------- | ------------------------------- | indirect block(s) depending on | + // | Free old large blocks | blocks, and store with | Free unused block(s) and | Free unused block(s) and | change in size. | + // | and indirect block(s). | pointers in the new attr | unused indirect block(s). | unused indirect block(s). | ------------------------------- | + // | | sub-block | | | copy pointers from old attr | + // | | -------------------------- | | | sub-block to new attr sub- | + // | | Free unused blocks, | | | block. | + // | | unused parts of the first | | | | + // | | block, and unused indirect | | | | + // | | block(s). | | | | + // ------------+-------------------------+----------------------------+---------------------------------+---------------------------------+---------------------------------+ + +#if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } +#endif +#if _DEBUG_BREAK_POINT + static int c=0; c++; if (c == 196) { + int a; a=0; + } +#endif + + WFSKrnResult nResult = WFSKRN_RESULT_UNKNOWN; + TransBlkAdr *pTba = &pDi->tba; + + DirEntryAttrHdr *pAttrHdr = pDi->pAttrHdr; + u32 nAttrHdrSize = (u32)(&((DirEntryAttrHdr*)0)->aCaseBitArray) + ((pAttrHdr->nNameLen+7)>>3); + u32 nNewAttrOfs = 0; + + u32 nAllocSize = nNewSize; + u8 nNewSizeCategory = 0; + u32 nNewAttrLog2Size = 0; + + u32 nNumBlks = 0; + u32 nNewNumBlks = 0; + u32 nStride = 0; + s32 nNumStartBlks = 0; + + if(nNewSize > pAttrHdr->nAllocSize){ + nNewAttrLog2Size = DirCalculateAttrSubBlkLog2SizeUpdateAllocSize(pDi->tba.pAreaInfo, &nAllocSize, pDi->pAttrHdr->nNameLen, &nNewSizeCategory); + if(nNewSizeCategory < pAttrHdr->nSizeCategory) { + nAllocSize = nNewSize; + nNewAttrLog2Size = DirCalculateAttrSubBlkLog2SizeDecreaseUpdateAllocSize(pDi->tba.pAreaInfo, &nAllocSize, pDi->pAttrHdr->nNameLen, &nNewSizeCategory); + } + } + else{ + /* + pAttrHdr->file.nSize = nNewSize; + return WFSKRN_RESULT_OK; + */ + if(pAttrHdr->nSizeCategory == FILE_SIZE_CATEGORY_VERY_SMALL){ + pAttrHdr->file.nSize = nNewSize; + return WFSKRN_RESULT_OK; + } + nNewAttrLog2Size = DirCalculateAttrSubBlkLog2SizeDecreaseUpdateAllocSize(pDi->tba.pAreaInfo, &nAllocSize, pDi->pAttrHdr->nNameLen, &nNewSizeCategory); + if(nNewSizeCategory > pAttrHdr->nSizeCategory) { + nAllocSize = nNewSize; + nNewAttrLog2Size = DirCalculateAttrSubBlkLog2SizeUpdateAllocSize(pDi->tba.pAreaInfo, &nAllocSize, pDi->pAttrHdr->nNameLen, &nNewSizeCategory); + } + } + + DirEntryAttrHdr *pNewAttrHdr = ( nNewAttrLog2Size == pAttrHdr->nAttrLog2Size && nNewSizeCategory == pAttrHdr->nSizeCategory ) ? pAttrHdr : 0; + + switch(pAttrHdr->nSizeCategory){ + case FILE_SIZE_CATEGORY_SMALL: + nNumBlks = pAttrHdr->nAllocSize ? ((pAttrHdr->nAllocSize-1) >> pTba->pAreaInfo->ah.nLog2BlkSize) + 1 : 0; + break; + case FILE_SIZE_CATEGORY_MEDIUM: + nNumBlks = pAttrHdr->nAllocSize ? ((pAttrHdr->nAllocSize-1) >> pTba->pAreaInfo->ah.nLog2MediumBlkSize) + 1 : 0; + break; + case FILE_SIZE_CATEGORY_LARGE: + case FILE_SIZE_CATEGORY_VERY_LARGE: + nNumBlks = pAttrHdr->nAllocSize ? ((pAttrHdr->nAllocSize-1) >> pTba->pAreaInfo->ah.nLog2LargeBlkSize) + 1 : 0; + break; + } + + // Culculate nNumBlks and nNewNumBlks + if(nAllocSize != pAttrHdr->nAllocSize){ + switch(nNewSizeCategory){ + case FILE_SIZE_CATEGORY_VERY_SMALL:{ + if(pNewAttrHdr != pAttrHdr){ + // Allocate subblock + WFSKrnReturnOnError(_DirSbaAllocSubBlkForResize(pDi, nNewAttrLog2Size, &nNewAttrOfs, &pNewAttrHdr)); + pAttrHdr = pDi->pAttrHdr; + } + break; + } + case FILE_SIZE_CATEGORY_SMALL:{ + nStride = sizeof(WFSFileBlkPtr); + nNewNumBlks = nAllocSize ? ((nAllocSize-1) >> pTba->pAreaInfo->ah.nLog2BlkSize) + 1 : 0; + if(pNewAttrHdr != pAttrHdr){ + // Allocate subblock + WFSKrnReturnOnError(_DirSbaAllocSubBlkForResize(pDi, nNewAttrLog2Size, &nNewAttrOfs, &pNewAttrHdr)); + pAttrHdr = pDi->pAttrHdr; + } + if( pAttrHdr->nAllocSize < nAllocSize || nNewSizeCategory != pAttrHdr->nSizeCategory ){ + // Alloc new blocks + nNumStartBlks = (nNewSizeCategory == pAttrHdr->nSizeCategory) ? nNumBlks : 0; + WFSBlkAdr nRefBlkAdr = nNumStartBlks ? WFSKrnGetFileBlkPtrForCategorySmall(pAttrHdr, pAttrHdr->nAttrLog2Size, nNumStartBlks-1)->nBlkAdr : pTba->nBlkAdr; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pNewAttrHdr, nNewAttrLog2Size, nNewNumBlks-1); + memset(pFileBlkPtr, 0, (nNewNumBlks-nNumStartBlks)*sizeof(WFSFileBlkPtr)); + WFSKrnExitOnError(AreaAllocBlks(pTba->pAreaInfo, nRefBlkAdr, pTba->pAreaInfo->ah.nLog2BlkSize, nNewNumBlks-nNumStartBlks, + (WFSBlkAdr*)&pFileBlkPtr[nNewNumBlks-nNumStartBlks-1], -(s32)nStride)); + _qsort(pFileBlkPtr, nNewNumBlks-nNumStartBlks, sizeof(WFSFileBlkPtr), CompareBlkAdrReverse); + } else { + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pAttrHdr, pAttrHdr->nAttrLog2Size, nNewNumBlks); + WFSKrnExitOnError(AreaFreeBlks(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2BlkSize, nNumBlks-nNewNumBlks, (WFSBlkAdr*)pFileBlkPtr, -(s32)nStride)); + } + break; + } + case FILE_SIZE_CATEGORY_MEDIUM:{ + nStride = sizeof(WFSFileBlkPtr); + nNewNumBlks = nAllocSize ? ((nAllocSize-1) >> pTba->pAreaInfo->ah.nLog2MediumBlkSize) + 1 : 0; + if(pNewAttrHdr != pAttrHdr){ + // Allocate subblock + WFSKrnReturnOnError(_DirSbaAllocSubBlkForResize(pDi, nNewAttrLog2Size, &nNewAttrOfs, &pNewAttrHdr)); + pAttrHdr = pDi->pAttrHdr; + } + // Alloc new blocks + if( pAttrHdr->nAllocSize < nAllocSize || nNewSizeCategory != pAttrHdr->nSizeCategory ){ + nNumStartBlks = (nNewSizeCategory == pAttrHdr->nSizeCategory) ? nNumBlks : 0; + WFSBlkAdr nRefBlkAdr = nNumStartBlks ? WFSKrnGetFileBlkPtrForCategoryMedium(pAttrHdr, pAttrHdr->nAttrLog2Size, nNumStartBlks-1)->nBlkAdr : pTba->nBlkAdr; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pNewAttrHdr, nNewAttrLog2Size, nNewNumBlks-1); + memset(pFileBlkPtr, 0, (nNewNumBlks-nNumStartBlks)*sizeof(WFSFileBlkPtr)); + WFSKrnExitOnError(AreaAllocBlks(pTba->pAreaInfo, nRefBlkAdr, pTba->pAreaInfo->ah.nLog2MediumBlkSize, nNewNumBlks-nNumStartBlks, + (WFSBlkAdr*)&pFileBlkPtr[nNewNumBlks-nNumStartBlks-1], -(s32)nStride)); + _qsort(pFileBlkPtr, nNewNumBlks-nNumStartBlks, sizeof(WFSFileBlkPtr), CompareBlkAdrReverse); + } else { + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pAttrHdr, pAttrHdr->nAttrLog2Size, nNewNumBlks); + WFSKrnExitOnError(AreaFreeBlks(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2MediumBlkSize, nNumBlks-nNewNumBlks, (WFSBlkAdr*)pFileBlkPtr, -(s32)nStride)); + } + break; + } + case FILE_SIZE_CATEGORY_LARGE:{ + nStride = pTba->pAreaInfo->nLargeBlkPtrSize; + nNewNumBlks = nAllocSize ? ((nAllocSize-1) >> pTba->pAreaInfo->ah.nLog2LargeBlkSize) + 1 : 0; + if(pNewAttrHdr != pAttrHdr){ + // Allocate subblock + WFSKrnReturnOnError(_DirSbaAllocSubBlkForResize(pDi, nNewAttrLog2Size, &nNewAttrOfs, &pNewAttrHdr)); + pAttrHdr = pDi->pAttrHdr; + } + // Alloc new blocks + if( pAttrHdr->nAllocSize < nAllocSize ){ + nNumStartBlks = (nNewSizeCategory == pAttrHdr->nSizeCategory) ? nNumBlks : 0; + WFSBlkAdr nRefBlkAdr = nNumStartBlks ? WFSKrnGetFileLargeBlkPtrForCategoryLarge(pAttrHdr, pAttrHdr->nAttrLog2Size, nNumStartBlks-1)->nBlkAdr : pTba->nBlkAdr; + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrForCategoryLarge(pNewAttrHdr, nNewAttrLog2Size, nNewNumBlks-1); + memset(pFileLargeBlkPtr, 0, (nNewNumBlks-nNumStartBlks)*sizeof(WFSFileLargeBlkPtr)); + WFSKrnExitOnError(AreaAllocBlks(pTba->pAreaInfo, nRefBlkAdr, pTba->pAreaInfo->ah.nLog2LargeBlkSize, nNewNumBlks-nNumStartBlks, + (WFSBlkAdr*)&pFileLargeBlkPtr[nNewNumBlks-nNumStartBlks-1], -(s32)nStride)); + _qsort(pFileLargeBlkPtr, nNewNumBlks-nNumStartBlks, sizeof(WFSFileLargeBlkPtr), CompareBlkAdrReverse); + } else if (nNewSizeCategory == pAttrHdr->nSizeCategory){ + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrForCategoryLarge(pAttrHdr, pAttrHdr->nAttrLog2Size, nNewNumBlks); + WFSKrnExitOnError(AreaFreeBlks(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2LargeBlkSize, nNumBlks-nNewNumBlks, (WFSBlkAdr*)pFileLargeBlkPtr, -(s32)nStride)); + } + break; + } + case FILE_SIZE_CATEGORY_VERY_LARGE:{ + nStride = pTba->pAreaInfo->nLargeBlkPtrSize; + nNewNumBlks = nAllocSize ? ((nAllocSize-1) >> pTba->pAreaInfo->ah.nLog2LargeBlkSize) + 1 : 0; + if(pNewAttrHdr != pAttrHdr){ + // Allocate subblock + WFSKrnReturnOnError(_DirSbaAllocSubBlkForResize(pDi, nNewAttrLog2Size, &nNewAttrOfs, &pNewAttrHdr)); + pAttrHdr = pDi->pAttrHdr; + } + // Alloc new blocks + if( pAttrHdr->nAllocSize < nAllocSize ){ + s32 nNumIndirectBlks = 0; + if(nNewSizeCategory == pAttrHdr->nSizeCategory){ + nNumStartBlks = nNumBlks; + nNumIndirectBlks = (nNumStartBlks+pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk-1)/pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk; + *WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pNewAttrHdr, nNewAttrLog2Size, nNumIndirectBlks-1) = + *WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, nNumIndirectBlks-1); + } else if (pAttrHdr->nSizeCategory == FILE_SIZE_CATEGORY_LARGE){ + nNumStartBlks = nNumBlks; + } + s32 nNewNumIndirectBlks = (nNewNumBlks+pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk-1)/pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk; + if(nNumIndirectBlks < nNewNumIndirectBlks){ + WFSBlkAdr *pBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pNewAttrHdr, nNewAttrLog2Size, nNewNumIndirectBlks-1); + WFSBlkAdr nRefBlkAdr = nNumStartBlks ? pBlkAdr[nNewNumIndirectBlks-nNumIndirectBlks] : pTba->nBlkAdr; + WFSKrnExitOnError(AreaAllocBlks(pTba->pAreaInfo, nRefBlkAdr, pTba->pAreaInfo->ah.nLog2BlkSize, nNewNumIndirectBlks-nNumIndirectBlks, + &pBlkAdr[nNewNumIndirectBlks-nNumIndirectBlks-1], -(s32)sizeof(WFSBlkAdr))); + _qsort(pBlkAdr, nNewNumIndirectBlks-nNumIndirectBlks, sizeof(WFSBlkAdr), CompareBlkAdrReverse); + } + u32 nFlag; + u32 nStartBlkOfs = nNumStartBlks%pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk; + u32 nEndBlkOfs = nNewNumBlks ? (nNewNumBlks-1)%pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk+1 : 0; + if(nStartBlkOfs == 0 || pAttrHdr->nSizeCategory == FILE_SIZE_CATEGORY_LARGE) { + ++nNumIndirectBlks; + nFlag = TRANS_FLAG_WRITE_BLK; + } else { + nFlag = TRANS_FLAG_RW_BLK; + } + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pNewAttrHdr, nNewAttrLog2Size, nNumIndirectBlks-1); + WFSBlkAdr nRefBlkAdr = *pIndirectBlkAdr; + for(;nNumIndirectBlks<=nNewNumIndirectBlks;nNumIndirectBlks++){ + u8 *pIndirectBlkPtr; + WFSKrnReturnOnError(TransGetAndPinBlk5(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo, nFlag, (void**)&pIndirectBlkPtr)); + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrFromIndirectBlkForCategoryVeryLarge(pIndirectBlkPtr, nStartBlkOfs); + if(nFlag == TRANS_FLAG_RW_BLK) { nRefBlkAdr = ((WFSFileLargeBlkPtr*)((u8*)pFileLargeBlkPtr-sizeof(WFSFileLargeBlkPtr)))->nBlkAdr; } + u32 nNumAllocBlks = nNumIndirectBlks < nNewNumIndirectBlks ? pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk-nStartBlkOfs : nEndBlkOfs-nStartBlkOfs; + memset(pFileLargeBlkPtr, 0, nNumAllocBlks*sizeof(WFSFileLargeBlkPtr)); + WFSKrnExitOnError(AreaAllocBlks(pTba->pAreaInfo, nRefBlkAdr, pTba->pAreaInfo->ah.nLog2LargeBlkSize, nNumAllocBlks, &pFileLargeBlkPtr->nBlkAdr, (s32)nStride)); + _qsort(&pFileLargeBlkPtr->nBlkAdr, nNumAllocBlks, sizeof(WFSFileLargeBlkPtr), CompareBlkAdrForward); + nRefBlkAdr = WFSKrnGetFileLargeBlkPtrFromIndirectBlkForCategoryVeryLarge(pIndirectBlkPtr, nNumAllocBlks+nStartBlkOfs-1)->nBlkAdr; + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + pIndirectBlkAdr = &pIndirectBlkAdr[-1]; + nFlag = TRANS_FLAG_WRITE_BLK; + nStartBlkOfs = 0; + } + } else if (nNewSizeCategory == pAttrHdr->nSizeCategory){ + s32 nNumIndirectBlks = (nNumBlks-1)/pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk+1; + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, nNumIndirectBlks-1); + s32 nNumEndBlks = (nNumBlks-1)%pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk+1; + u32 nNumFreeBlks = nNumBlks-nNewNumBlks; + while(nNumFreeBlks > 0){ + u8 *pIndirectBlkPtr; + WFSKrnReturnOnError(TransGetAndPinBlk5(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo, TRANS_FLAG_READ_BLK, (void**)&pIndirectBlkPtr)); + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrFromIndirectBlkForCategoryVeryLarge(pIndirectBlkPtr, nNumEndBlks-1); + if(nNumFreeBlks >= nNumEndBlks){ + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2LargeBlkSize, nNumEndBlks, &pFileLargeBlkPtr->nBlkAdr, -(s32)nStride, pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2BlkSize, 1, pIndirectBlkAdr, -(s32)nStride, pTba->pTransInfo)); + nNumFreeBlks -= nNumEndBlks; + } else { + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2LargeBlkSize, nNumFreeBlks, &pFileLargeBlkPtr->nBlkAdr, -(s32)nStride, pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + nNumFreeBlks = 0; + } + pIndirectBlkAdr = &pIndirectBlkAdr[1]; + nNumEndBlks = pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk; + } + } + break; + } + } + } else { + nNewNumBlks = nNumBlks; + nNewSizeCategory = pAttrHdr->nSizeCategory; + } + + if(pNewAttrHdr != pAttrHdr){ + u32 nCopyForward = nAttrHdrSize; + u32 nNewSizeCategory2 = (pAttrHdr->nSizeCategory << 4) + nNewSizeCategory; + switch(nNewSizeCategory2) { + // Same categories + case FILE_RESIZE_CATEGORY_VERY_SMALL_TO_VERY_SMALL:{ + // Copy attribute header and data( for only increase ) + nCopyForward += pAttrHdr->file.nSize < nAllocSize ? pAttrHdr->file.nSize : nAllocSize; + break; + } + case FILE_RESIZE_CATEGORY_SMALL_TO_SMALL:{ + // Copy attribute data (nBlkAdr + hash) + WFSFileBlkPtr *pFileBlkPtr = 0; + u32 nNumCopyBlks = pAttrHdr->nAllocSize < nAllocSize ? nNumBlks : nNewNumBlks; + memcpy((u8*)pNewAttrHdr+(1<nAttrLog2Size)-(nStride*nNumCopyBlks), nStride*nNumCopyBlks); + if(pAttrHdr->nAllocSize < nAllocSize){ + nNumCopyBlks = pAttrHdr->file.nSize ? ((pAttrHdr->file.nSize-1)>>pTba->pAreaInfo->ah.nLog2BlkSize)+1 : 0; + } + int nI; + u32 nHashOfs = 0; + for(nI=0;nIhash - (u8*)pDi->pBlkHdr; + nResult = BCacheSetHash(pTba->pAreaInfo->pVolInfo, pFileBlkPtr->nBlkAdr, pTba->nBlkAdr, nHashOfs); + if (nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND) { + goto Exit; + } + } + if(pAttrHdr->nAllocSize > nAllocSize && nNumCopyBlks){ + WFSKrnExitOnError(TransTrancateFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, pTba->pAreaInfo->nBlkSize, ((nNewSize-1)&(pTba->pAreaInfo->nBlkSize-1))+1)); + } + break; + } + case FILE_RESIZE_CATEGORY_MEDIUM_TO_MEDIUM:{ + // Copy attribute data (nBlkAdr + hash) + WFSFileBlkPtr *pFileBlkPtr = 0; + u32 nNumCopyBlks = pAttrHdr->nAllocSize < nAllocSize ? nNumBlks : nNewNumBlks; + memcpy((u8*)pNewAttrHdr+(1<nAttrLog2Size)-(nStride*nNumCopyBlks), nStride*nNumCopyBlks); + if(pAttrHdr->nAllocSize < nAllocSize){ + nNumCopyBlks = pAttrHdr->file.nSize ? ((pAttrHdr->file.nSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize)+1 : 0; + } + int nI; + u32 nHashOfs = 0; + for(nI=0;nIhash - (u8*)pDi->pBlkHdr; + nResult = BCacheSetHash(pTba->pAreaInfo->pVolInfo, pFileBlkPtr->nBlkAdr, pTba->nBlkAdr, nHashOfs); + if (nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND) { + goto Exit; + } + } + if(pAttrHdr->nAllocSize > nAllocSize && nNumCopyBlks){ + WFSKrnExitOnError(TransTrancateFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, pTba->pAreaInfo->nMediumBlkSize, ((nNewSize-1)&(pTba->pAreaInfo->nMediumBlkSize-1))+1 )); + } + break; + } + case FILE_RESIZE_CATEGORY_LARGE_TO_LARGE: { + // Copy attribute data (nBlkAdr + hash) + WFSFileLargeBlkPtr *pFileLargeBlkPtr = 0; + u32 nNumCopyBlks = pAttrHdr->nAllocSize < nAllocSize ? nNumBlks : nNewNumBlks; + memcpy((u8*)pNewAttrHdr+(1<nAttrLog2Size)-(nStride*nNumCopyBlks), nStride*nNumCopyBlks); + if(pAttrHdr->nAllocSize < nAllocSize){ + nNumCopyBlks = pAttrHdr->file.nSize ? ((pAttrHdr->file.nSize-1)>>pTba->pAreaInfo->ah.nLog2LargeBlkSize)+1 : 0; + } + int nI, nJ; + for(nI=0;nIpAreaInfo->nLog2MediumBlkPerLargeBlk;nJ++){ + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge(pTba->pAreaInfo, pFileLargeBlkPtr, nJ); + u32 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pDi->pBlkHdr; + nResult = BCacheSetHash(pTba->pAreaInfo->pVolInfo, fileBlkInfo.nBlkAdr, pTba->nBlkAdr, nHashOfs); + if (nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND) { + goto Exit; + } + } + } + if(pAttrHdr->nAllocSize > nAllocSize && nNumCopyBlks){ + u32 nMedBlkIdx = ((nNewSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize)&((1<pAreaInfo->nLog2MediumBlkPerLargeBlk)-1); + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge(pTba->pAreaInfo, pFileLargeBlkPtr, nMedBlkIdx); + u32 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pDi->pBlkHdr; + WFSKrnExitOnError(TransTrancateFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, fileBlkInfo.nBlkAdr, pTba->pAreaInfo->nMediumBlkSize, + ((nNewSize-1)&(pTba->pAreaInfo->nMediumBlkSize-1))+1)); + } + break; + } + case FILE_RESIZE_CATEGORY_VERY_LARGE_TO_VERY_LARGE:{ + u32 nCopyBytes = sizeof(WFSBlkAdr)*((nNumBlks+pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk-1)/pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk); + if(nCopyBytes){ + memcpy((u8*)pNewAttrHdr+(1<nAttrLog2Size)-nCopyBytes, nCopyBytes); + } + if(pAttrHdr->nAllocSize > nAllocSize && nNewSize){ + u8 *pIndirectBlkPtr; + u32 nTrancateSize = ((nNewSize-1)&(pTba->pAreaInfo->nMediumBlkSize-1))+1; + if(nTrancateSize == pTba->pAreaInfo->nMediumBlkSize){ break; } + u32 nIndirectBlkIdx = (nNewNumBlks-1)/pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk; + u32 nMedBlkIdx = ((nNewSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize)%(pTba->pAreaInfo->nNumMediumBlkPtrsPerBlk); + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pNewAttrHdr, nNewAttrLog2Size, nIndirectBlkIdx); + WFSKrnReturnOnError(TransGetAndPinBlk5(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo, TRANS_FLAG_RW_BLK, (void**)&pIndirectBlkPtr)); + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoFromIndirectBlkForCategoryVeryLarge(pTba->pAreaInfo, pIndirectBlkPtr, nMedBlkIdx); + u16 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pIndirectBlkPtr; + WFSKrnExitOnError(TransTrancateFileMediumBlk(pTba, *pIndirectBlkAdr, nHashOfs, fileBlkInfo.nBlkAdr, pTba->pAreaInfo->nMediumBlkSize, nTrancateSize)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + } + break; + } + // Different categories + case FILE_RESIZE_CATEGORY_VERY_SMALL_TO_SMALL:{ + if(pAttrHdr->file.nSize){ + u8 *pBlkPtr; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pNewAttrHdr, nNewAttrLog2Size, 0); + u16 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_WRITE_BLK, pAttrHdr->file.nSize, (void**)&pBlkPtr)); + memcpy(pBlkPtr, (u8*)pAttrHdr+nAttrHdrSize, pAttrHdr->file.nSize); + WFSKrnExitOnError(TransStoreBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + } + break; + } + case FILE_RESIZE_CATEGORY_VERY_SMALL_TO_MEDIUM:{ + if(pAttrHdr->file.nSize){ + u8 *pBlkPtr; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pNewAttrHdr, nNewAttrLog2Size, 0); + u16 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_WRITE_BLK, pAttrHdr->file.nSize, (void**)&pBlkPtr)); + memcpy(pBlkPtr, (u8*)pAttrHdr+nAttrHdrSize, pAttrHdr->file.nSize); + WFSKrnExitOnError(TransStoreBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + } + break; + } + case FILE_RESIZE_CATEGORY_VERY_SMALL_TO_LARGE:{ + if(pAttrHdr->file.nSize){ + u8 *pBlkPtr; + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge4(pTba->pAreaInfo, pNewAttrHdr, nNewAttrLog2Size, 0); + u16 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pDi->pBlkHdr; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, fileBlkInfo.nBlkAdr, TRANS_FLAG_WRITE_BLK, pAttrHdr->file.nSize, (void**)&pBlkPtr)); + memcpy(pBlkPtr, (u8*)pAttrHdr+nAttrHdrSize, pAttrHdr->file.nSize); + WFSKrnExitOnError(TransStoreBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + } + break; + } + case FILE_RESIZE_CATEGORY_VERY_SMALL_TO_VERY_LARGE:{ + if(pAttrHdr->file.nSize){ + u8 *pBlkPtr; + u8 *pIndirectBlkPtr; + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pNewAttrHdr, nNewAttrLog2Size, 0); + WFSKrnReturnOnError(TransGetAndPinBlk5(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo, TRANS_FLAG_RW_BLK, (void**)&pIndirectBlkPtr)); + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoFromIndirectBlkForCategoryVeryLarge(pTba->pAreaInfo, pIndirectBlkPtr, 0); + u16 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pIndirectBlkPtr; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, *pIndirectBlkAdr, nHashOfs, fileBlkInfo.nBlkAdr, TRANS_FLAG_WRITE_BLK, pAttrHdr->file.nSize, (void**)&pBlkPtr)); + memcpy(pBlkPtr, (u8*)pAttrHdr+nAttrHdrSize, pAttrHdr->file.nSize); + WFSKrnExitOnError(TransStoreBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, fileBlkInfo.nBlkAdr, pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + } + break; + } + case FILE_RESIZE_CATEGORY_SMALL_TO_MEDIUM:{ + // Copy file block data + u32 nI; + u32 nMediumBlkIdx = 0; + u32 nSize = pAttrHdr->file.nSize; + u8 *pDstBlkPtr = 0; + WFSFileBlkPtr *pFileMediumBlkPtr = NULL; + for(nI=0;nSize>0;nI++){ + if(!(nI%(1<pAreaInfo->nLog2BlksPerMediumBlk))){ + pFileMediumBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pNewAttrHdr, nNewAttrLog2Size, nMediumBlkIdx); + u16 nHashOfs = (u8*)&pFileMediumBlkPtr->hash - (u8*)pDi->pBlkHdr; + u32 nValidSize = nSize < pTba->pAreaInfo->nMediumBlkSize ? nSize : pTba->pAreaInfo->nMediumBlkSize; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileMediumBlkPtr->nBlkAdr, TRANS_FLAG_WRITE_BLK, nValidSize, (void**)&pDstBlkPtr)); + } + else{ + pDstBlkPtr += pTba->pAreaInfo->nBlkSize; + } + u8 *pSrcBlkPtr; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pAttrHdr, pAttrHdr->nAttrLog2Size, nI); + u16 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + if(nSize > pTba->pAreaInfo->nBlkSize){ + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_READ_BLK, pTba->pAreaInfo->nBlkSize, (void**)&pSrcBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, pTba->pAreaInfo->nBlkSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + nSize -= pTba->pAreaInfo->nBlkSize; + } else { + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_READ_BLK, nSize, (void**)&pSrcBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, nSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + nSize = 0; + } + if(!((nI+1)%(1<pAreaInfo->nLog2BlksPerMediumBlk)) || !nSize){ + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileMediumBlkPtr->nBlkAdr, pTba->pTransInfo)); + ++nMediumBlkIdx; + } + } + for(nI=0;nIpAreaInfo, pFileMediumBlkPtr->nBlkAdr, pTba->pTransInfo); + if(nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND){ + goto Exit; + } + } + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2BlkSize, nNumBlks, (WFSBlkAdr*)WFSKrnGetFileBlkPtrForCategorySmall(pAttrHdr, pAttrHdr->nAttrLog2Size, 0), + -(s32)sizeof(WFSFileBlkPtr), pTba->pTransInfo)); + break; + } + case FILE_RESIZE_CATEGORY_SMALL_TO_LARGE:{ + // Copy file block data + u32 nI; + u32 nMaxHashBlkId = 0; + u32 nSize = pAttrHdr->file.nSize; + u8 *pDstBlkPtr = 0; + WFSFileBlkInfo fileLargeBlkInfo; + for(nI=0;nSize>0;nI++){ + if(!(nI%(1<pAreaInfo->nLog2BlksPerMediumBlk))){ + fileLargeBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge4(pTba->pAreaInfo, pNewAttrHdr, nNewAttrLog2Size, nMaxHashBlkId); + u16 nHashOfs = (u8*)fileLargeBlkInfo.pHash - (u8*)pDi->pBlkHdr; + u32 nValidSize = nSize < pTba->pAreaInfo->nMediumBlkSize ? nSize : pTba->pAreaInfo->nMediumBlkSize; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, fileLargeBlkInfo.nBlkAdr, TRANS_FLAG_WRITE_BLK, nValidSize, (void**)&pDstBlkPtr)); + } + else{ + pDstBlkPtr += pTba->pAreaInfo->nBlkSize; + } + u8 *pSrcBlkPtr; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pAttrHdr, pAttrHdr->nAttrLog2Size, nI); + u16 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + if(nSize > pTba->pAreaInfo->nBlkSize){ + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_READ_BLK, pTba->pAreaInfo->nBlkSize, (void**)&pSrcBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, pTba->pAreaInfo->nBlkSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + nSize -= pTba->pAreaInfo->nBlkSize; + } else { + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_READ_BLK, nSize, (void**)&pSrcBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, nSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + nSize = 0; + } + if(!((nI+1)%(1<pAreaInfo->nLog2BlksPerMediumBlk)) || !nSize){ + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, fileLargeBlkInfo.nBlkAdr, pTba->pTransInfo)); + ++nMaxHashBlkId; + } + } + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrForCategoryLarge(pNewAttrHdr, nNewAttrLog2Size, 0); + for(nI=0;nI<(nMaxHashBlkId<pAreaInfo->nLog2BlksPerMediumBlk);nI+=(1<pAreaInfo->nLog2BlksPerMediumBlk)){ + WFSKrnResult nResult = TransStoreBlk3(pTba->pAreaInfo, pFileLargeBlkPtr->nBlkAdr+nI, pTba->pTransInfo); + if(nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND){ + goto Exit; + } + } + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2BlkSize, nNumBlks, (WFSBlkAdr*)WFSKrnGetFileBlkPtrForCategorySmall(pAttrHdr, pAttrHdr->nAttrLog2Size, 0), + -(s32)sizeof(WFSFileBlkPtr), pTba->pTransInfo)); + break; + } + case FILE_RESIZE_CATEGORY_SMALL_TO_VERY_LARGE:{ + // Copy file block data + u8 *pIndirectBlkPtr; + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pNewAttrHdr, nNewAttrLog2Size, 0); + WFSKrnReturnOnError(TransGetAndPinBlk5(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo, TRANS_FLAG_RW_BLK, (void**)&pIndirectBlkPtr)); + u32 nI; + u32 nMaxHashBlkId = 0; + u32 nSize = pAttrHdr->file.nSize; + u8 *pDstBlkPtr = 0; + WFSFileBlkInfo fileLargeBlkInfo; + for(nI=0;nSize>0;nI++){ + if(!(nI%(1<pAreaInfo->nLog2BlksPerMediumBlk))){ + fileLargeBlkInfo = WFSKrnGetFileBlkInfoFromIndirectBlkForCategoryVeryLarge(pTba->pAreaInfo, pIndirectBlkPtr, nMaxHashBlkId); + u16 nHashOfs = (u8*)fileLargeBlkInfo.pHash - (u8*)pIndirectBlkPtr; + u32 nValidSize = nSize < pTba->pAreaInfo->nMediumBlkSize ? nSize : pTba->pAreaInfo->nMediumBlkSize; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, *pIndirectBlkAdr, nHashOfs, fileLargeBlkInfo.nBlkAdr, TRANS_FLAG_WRITE_BLK, nValidSize, (void**)&pDstBlkPtr)); + } + else{ + pDstBlkPtr += pTba->pAreaInfo->nBlkSize; + } + u8 *pSrcBlkPtr; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pAttrHdr, pAttrHdr->nAttrLog2Size, nI); + u16 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + if(nSize > pTba->pAreaInfo->nBlkSize){ + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_READ_BLK, pTba->pAreaInfo->nBlkSize, (void**)&pSrcBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, pTba->pAreaInfo->nBlkSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + nSize -= pTba->pAreaInfo->nBlkSize; + } else { + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_READ_BLK, nSize, (void**)&pSrcBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, nSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + nSize = 0; + } + if(!((nI+1)%(1<pAreaInfo->nLog2BlksPerMediumBlk)) || !nSize){ + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, fileLargeBlkInfo.nBlkAdr, pTba->pTransInfo)); + ++nMaxHashBlkId; + } + } + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrFromIndirectBlkForCategoryVeryLarge(pIndirectBlkPtr, 0); + for(nI=0;nI<(nMaxHashBlkId<pAreaInfo->nLog2BlksPerMediumBlk);nI+=(1<pAreaInfo->nLog2BlksPerMediumBlk)){ + WFSKrnResult nResult = TransStoreBlk3(pTba->pAreaInfo, pFileLargeBlkPtr->nBlkAdr+nI, pTba->pTransInfo); + if(nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND){ + goto Exit; + } + } + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2BlkSize, nNumBlks, (WFSBlkAdr*)WFSKrnGetFileBlkPtrForCategorySmall(pAttrHdr, pAttrHdr->nAttrLog2Size, 0), + -(s32)sizeof(WFSFileBlkPtr), pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + break; + } + case FILE_RESIZE_CATEGORY_MEDIUM_TO_SMALL:{ + // Copy file block data + u32 nI; + u32 nMediumBlkIdx = 0; + u32 nOldSize = pAttrHdr->file.nSize; + u32 nSize = pAttrHdr->file.nSize < nNewSize ? pAttrHdr->file.nSize : nNewSize; + u8 *pSrcBlkPtr = 0; + WFSFileBlkPtr *pFileMediumBlkPtr = NULL; + for(nI=0;nSize>0;nI++){ + if(!(nI%(1<pAreaInfo->nLog2BlksPerMediumBlk))){ + pFileMediumBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pAttrHdr, pAttrHdr->nAttrLog2Size, nMediumBlkIdx); + u16 nHashOfs = (u8*)&pFileMediumBlkPtr->hash - (u8*)pDi->pBlkHdr; + u32 nValidSize = nOldSize < pTba->pAreaInfo->nMediumBlkSize ? nOldSize : pTba->pAreaInfo->nMediumBlkSize; + nOldSize -= pTba->pAreaInfo->nMediumBlkSize; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileMediumBlkPtr->nBlkAdr, TRANS_FLAG_READ_BLK, nValidSize, (void**)&pSrcBlkPtr)); + } + else{ + pSrcBlkPtr += pTba->pAreaInfo->nBlkSize; + } + u8 *pDstBlkPtr; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pNewAttrHdr, nNewAttrLog2Size, nI); + u16 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + if(nSize > pTba->pAreaInfo->nBlkSize){ + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_WRITE_BLK, pTba->pAreaInfo->nBlkSize, (void**)&pDstBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, pTba->pAreaInfo->nBlkSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + nSize -= pTba->pAreaInfo->nBlkSize; + } else { + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_WRITE_BLK, nSize, (void**)&pDstBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, nSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + nSize = 0; + } + if(!((nI+1)%(1<pAreaInfo->nLog2BlksPerMediumBlk)) || !nSize){ + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileMediumBlkPtr->nBlkAdr, pTba->pTransInfo)); + ++nMediumBlkIdx; + } + } + for(nI=0;nIpAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo); + if(nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND){ + goto Exit; + } + } + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2MediumBlkSize, nNumBlks, (WFSBlkAdr*)WFSKrnGetFileBlkPtrForCategoryMedium(pAttrHdr, pAttrHdr->nAttrLog2Size, 0), + -(s32)sizeof(WFSFileBlkPtr), pTba->pTransInfo)); + + break; + } + case FILE_RESIZE_CATEGORY_MEDIUM_TO_LARGE:{ + // Copy file block data + u32 nI; + u32 nSize = pAttrHdr->file.nSize; + u32 nNumCopyBlks = pAttrHdr->file.nSize ? ((pAttrHdr->file.nSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize)+1 : 0; + for(nI=0;nIpAreaInfo, pNewAttrHdr, nNewAttrLog2Size, nI); + u32 nValidSize = nSize < pTba->pAreaInfo->nMediumBlkSize ? nSize : pTba->pAreaInfo->nMediumBlkSize; + nSize -= pTba->pAreaInfo->nMediumBlkSize; + u16 nHashOfs = (u8*)fileLargeBlkInfo.pHash - (u8*)pDi->pBlkHdr; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, fileLargeBlkInfo.nBlkAdr, TRANS_FLAG_WRITE_BLK, nValidSize, (void**)&pDstBlkPtr)); + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pAttrHdr, pAttrHdr->nAttrLog2Size, nI); + nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_READ_BLK, nValidSize, (void**)&pSrcBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, pTba->pAreaInfo->nMediumBlkSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, fileLargeBlkInfo.nBlkAdr, pTba->pTransInfo)); + } + for(nI=0;nIpAreaInfo, pNewAttrHdr, nNewAttrLog2Size, nI); + WFSKrnResult nResult = TransStoreBlk3(pTba->pAreaInfo, fileLargeBlkInfo.nBlkAdr, pTba->pTransInfo); + if(nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND){ + goto Exit; + } + } + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2MediumBlkSize, nNumBlks, + (WFSBlkAdr*)WFSKrnGetFileBlkPtrForCategoryMedium(pAttrHdr, pAttrHdr->nAttrLog2Size, 0), + -(s32)sizeof(WFSFileBlkPtr), pTba->pTransInfo)); + break; + } + case FILE_RESIZE_CATEGORY_MEDIUM_TO_VERY_LARGE:{ + // Copy file block data + u32 nSize = pAttrHdr->file.nSize; + u32 nNumCopyBlks = pAttrHdr->file.nSize ? ((pAttrHdr->file.nSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize)+1 : 0; + u8 *pIndirectBlkPtr; + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pNewAttrHdr, nNewAttrLog2Size, 0); + WFSKrnReturnOnError(TransGetAndPinBlk5(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo, TRANS_FLAG_RW_BLK, (void**)&pIndirectBlkPtr)); + u32 nI; + for(nI=0;nIpAreaInfo, pIndirectBlkPtr, nI); + u32 nValidSize = nSize < pTba->pAreaInfo->nMediumBlkSize ? nSize : pTba->pAreaInfo->nMediumBlkSize; + nSize -= pTba->pAreaInfo->nMediumBlkSize; + u16 nHashOfs = (u8*)fileLargeBlkInfo.pHash - (u8*)pIndirectBlkPtr; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, *pIndirectBlkAdr, nHashOfs, fileLargeBlkInfo.nBlkAdr, TRANS_FLAG_WRITE_BLK, nValidSize, (void**)&pDstBlkPtr)); + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pAttrHdr, pAttrHdr->nAttrLog2Size, nI); + nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_READ_BLK, nValidSize, (void**)&pSrcBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, pTba->pAreaInfo->nMediumBlkSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, fileLargeBlkInfo.nBlkAdr, pTba->pTransInfo)); + } + for(nI=0;nIpAreaInfo, pIndirectBlkPtr, nI); + WFSKrnResult nResult = TransStoreBlk3(pTba->pAreaInfo, fileLargeBlkInfo.nBlkAdr, pTba->pTransInfo); + if(nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND){ + goto Exit; + } + } + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2MediumBlkSize, nNumBlks, + (WFSBlkAdr*)WFSKrnGetFileBlkPtrForCategoryMedium(pAttrHdr, pAttrHdr->nAttrLog2Size, 0), + -(s32)sizeof(WFSFileBlkPtr), pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + break; + } + case FILE_RESIZE_CATEGORY_LARGE_TO_SMALL:{ + // Copy file block data + u32 nI; + u32 nMaxHashBlkId = 0; + u32 nOldSize = pAttrHdr->file.nSize; + u32 nSize = pAttrHdr->file.nSize < nNewSize ? pAttrHdr->file.nSize : nNewSize; + u8 *pSrcBlkPtr = 0; + WFSFileBlkInfo fileLargeBlkInfo; + for(nI=0;nSize>0;nI++){ + if(!(nI%(1<pAreaInfo->nLog2BlksPerMediumBlk))){ + fileLargeBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge4(pTba->pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, nMaxHashBlkId); + u16 nHashOfs = (u8*)fileLargeBlkInfo.pHash - (u8*)pDi->pBlkHdr; + u32 nValidSize = nOldSize < pTba->pAreaInfo->nMediumBlkSize ? nOldSize : pTba->pAreaInfo->nMediumBlkSize; + nOldSize -= pTba->pAreaInfo->nMediumBlkSize; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, fileLargeBlkInfo.nBlkAdr, TRANS_FLAG_READ_BLK, nValidSize, (void**)&pSrcBlkPtr)); + } + else{ + pSrcBlkPtr += pTba->pAreaInfo->nBlkSize; + } + u8 *pDstBlkPtr; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pNewAttrHdr, nNewAttrLog2Size, nI); + u16 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + if(nSize > pTba->pAreaInfo->nBlkSize){ + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_WRITE_BLK, pTba->pAreaInfo->nBlkSize, (void**)&pDstBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, pTba->pAreaInfo->nBlkSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + nSize -= pTba->pAreaInfo->nBlkSize; + } else { + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_WRITE_BLK, nSize, (void**)&pDstBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, nSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + nSize = 0; + } + if(!((nI+1)%(1<pAreaInfo->nLog2BlksPerMediumBlk)) || !nSize){ + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, fileLargeBlkInfo.nBlkAdr, pTba->pTransInfo)); + ++nMaxHashBlkId; + } + } + for(nI=0;nIpAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo); + if(nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND){ + goto Exit; + } + } + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2LargeBlkSize, nNumBlks, (WFSBlkAdr*)WFSKrnGetFileLargeBlkPtrForCategoryLarge(pAttrHdr, pAttrHdr->nAttrLog2Size, 0), + -(s32)sizeof(WFSFileLargeBlkPtr), pTba->pTransInfo)); + break; + } + case FILE_RESIZE_CATEGORY_LARGE_TO_MEDIUM:{ + // Copy file block data + u32 nI; + u32 nOldSize = pAttrHdr->file.nSize; + u32 nSize = pAttrHdr->file.nSize < nNewSize ? pAttrHdr->file.nSize : nNewSize; + u32 nNumCopyBlks = pAttrHdr->file.nSize < nNewSize ? pAttrHdr->file.nSize : nNewSize; + if (nNumCopyBlks) {nNumCopyBlks = ((nNumCopyBlks-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize)+1;} + for(nI=0;nIpAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, nI); + u32 nValidSize = nOldSize < pTba->pAreaInfo->nMediumBlkSize ? nOldSize : pTba->pAreaInfo->nMediumBlkSize; + nOldSize -= pTba->pAreaInfo->nMediumBlkSize; + u16 nHashOfs = (u8*)fileLargeBlkInfo.pHash - (u8*)pDi->pBlkHdr; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, fileLargeBlkInfo.nBlkAdr, TRANS_FLAG_READ_BLK, nValidSize, (void**)&pSrcBlkPtr)); + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pNewAttrHdr, nNewAttrLog2Size, nI); + nValidSize = nSize < pTba->pAreaInfo->nMediumBlkSize ? nSize : pTba->pAreaInfo->nMediumBlkSize; + nSize -= pTba->pAreaInfo->nMediumBlkSize; + nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_WRITE_BLK, nValidSize, (void**)&pDstBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, pTba->pAreaInfo->nMediumBlkSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, fileLargeBlkInfo.nBlkAdr, pTba->pTransInfo)); + } + for(nI=0;nIpAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo); + if(nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND){ + goto Exit; + } + } + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2LargeBlkSize, nNumBlks, (WFSBlkAdr*)WFSKrnGetFileLargeBlkPtrForCategoryLarge(pAttrHdr, pAttrHdr->nAttrLog2Size, 0), + -(s32)sizeof(WFSFileLargeBlkPtr), pTba->pTransInfo)); + break; + } + case FILE_RESIZE_CATEGORY_LARGE_TO_VERY_LARGE:{ + u8 *pIndirectBlkPtr; + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pNewAttrHdr, nNewAttrLog2Size, 0); + WFSKrnReturnOnError(TransGetAndPinBlk5(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo, TRANS_FLAG_WRITE_BLK, (void**)&pIndirectBlkPtr)); + WFSFileLargeBlkPtr *pSrcFileLargeBlkPtr = 0, *pDstFileLargeBlkPtr = 0; + int nI, nJ; + for(nI=0;nInAttrLog2Size, nI); + pDstFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrFromIndirectBlkForCategoryVeryLarge(pIndirectBlkPtr, nI); + *pDstFileLargeBlkPtr = *pSrcFileLargeBlkPtr; + for(nJ=0;nJ<(1<pAreaInfo->nLog2MediumBlkPerLargeBlk);nJ++){ + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge(pTba->pAreaInfo, pDstFileLargeBlkPtr, nJ); + u32 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pIndirectBlkPtr; + nResult = BCacheSetHash(pTba->pAreaInfo->pVolInfo, fileBlkInfo.nBlkAdr, *pIndirectBlkAdr, nHashOfs); + if (nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND) { + goto Exit; + } + } + } + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + break; + } + case FILE_RESIZE_CATEGORY_VERY_LARGE_TO_SMALL:{ + // Copy file block data + u8 *pIndirectBlkPtr; + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, 0); + WFSKrnReturnOnError(TransGetAndPinBlk5(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo, TRANS_FLAG_READ_BLK, (void**)&pIndirectBlkPtr)); + s32 nI; + u32 nMaxHashBlkId = 0; + u32 nOldSize = pAttrHdr->file.nSize; + u32 nSize = pAttrHdr->file.nSize < nNewSize ? pAttrHdr->file.nSize : nNewSize; + u8 *pSrcBlkPtr = 0; + WFSFileBlkInfo fileLargeBlkInfo; + for(nI=0;nSize>0;nI++){ + if(!(nI%(1<pAreaInfo->nLog2BlksPerMediumBlk))){ + fileLargeBlkInfo = WFSKrnGetFileBlkInfoFromIndirectBlkForCategoryVeryLarge(pTba->pAreaInfo, pIndirectBlkPtr, nMaxHashBlkId); + u16 nHashOfs = (u8*)fileLargeBlkInfo.pHash - (u8*)pIndirectBlkPtr; + u32 nValidSize = nOldSize < pTba->pAreaInfo->nMediumBlkSize ? nOldSize : pTba->pAreaInfo->nMediumBlkSize; + nOldSize -= pTba->pAreaInfo->nMediumBlkSize; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, *pIndirectBlkAdr, nHashOfs, fileLargeBlkInfo.nBlkAdr, TRANS_FLAG_READ_BLK, nValidSize, (void**)&pSrcBlkPtr)); + } + else{ + pSrcBlkPtr += pTba->pAreaInfo->nBlkSize; + } + u8 *pDstBlkPtr; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pNewAttrHdr, nNewAttrLog2Size, nI); + u16 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + if(nSize > pTba->pAreaInfo->nBlkSize){ + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_WRITE_BLK, pTba->pAreaInfo->nBlkSize, (void**)&pDstBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, pTba->pAreaInfo->nBlkSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + nSize -= pTba->pAreaInfo->nBlkSize; + } else { + WFSKrnExitOnError(TransGetAndPinFileBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_WRITE_BLK, nSize, (void**)&pDstBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, nSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + nSize = 0; + } + if(!((nI+1)%(1<pAreaInfo->nLog2BlksPerMediumBlk)) || !nSize){ + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, fileLargeBlkInfo.nBlkAdr, pTba->pTransInfo)); + ++nMaxHashBlkId; + } + } + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + for(nI=0;nIpAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo); + if(nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND){ + goto Exit; + } + } + u32 nNumIndirectBlks = (nNumBlks+pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk-1)/pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk; + for(nI=0;nIpAreaInfo, pIndirectBlkAdr[-nI], pTba->pTransInfo, TRANS_FLAG_READ_BLK, (void**)&pIndirectBlkPtr)); + if(nI+1==nNumIndirectBlks){ + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2LargeBlkSize, (nNumBlks-1)%pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk+1, + (WFSBlkAdr*)(pIndirectBlkPtr+sizeof(WFSMetaDataHdr)), (s32)sizeof(WFSFileLargeBlkPtr), pTba->pTransInfo)); + } else { + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2LargeBlkSize, pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk, + (WFSBlkAdr*)(pIndirectBlkPtr+sizeof(WFSMetaDataHdr)), (s32)sizeof(WFSFileLargeBlkPtr), pTba->pTransInfo)); + } + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pIndirectBlkAdr[-nI], pTba->pTransInfo)); + } + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2BlkSize, nNumIndirectBlks, pIndirectBlkAdr, -(s32)sizeof(WFSBlkAdr), pTba->pTransInfo)); + break; + } + case FILE_RESIZE_CATEGORY_VERY_LARGE_TO_MEDIUM:{ + // Copy file block data + u32 nOldSize = pAttrHdr->file.nSize; + u32 nSize = pAttrHdr->file.nSize < nNewSize ? pAttrHdr->file.nSize : nNewSize; + u32 nNumCopyBlks = pAttrHdr->file.nSize < nNewSize ? pAttrHdr->file.nSize : nNewSize; + if (nNumCopyBlks) {nNumCopyBlks = ((nNumCopyBlks-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize)+1;} + u8 *pIndirectBlkPtr; + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, 0); + WFSKrnReturnOnError(TransGetAndPinBlk5(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo, TRANS_FLAG_READ_BLK, (void**)&pIndirectBlkPtr)); + s32 nI; + for(nI=0;nIpAreaInfo, pIndirectBlkPtr, nI); + u32 nValidSize = nOldSize < pTba->pAreaInfo->nMediumBlkSize ? nOldSize : pTba->pAreaInfo->nMediumBlkSize; + nOldSize -= pTba->pAreaInfo->nMediumBlkSize; + u16 nHashOfs = (u8*)fileLargeBlkInfo.pHash - (u8*)pIndirectBlkPtr; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, *pIndirectBlkAdr, nHashOfs, fileLargeBlkInfo.nBlkAdr, TRANS_FLAG_READ_BLK, nValidSize, (void**)&pSrcBlkPtr)); + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pNewAttrHdr, nNewAttrLog2Size, nI); + nValidSize = nSize < pTba->pAreaInfo->nMediumBlkSize ? nSize : pTba->pAreaInfo->nMediumBlkSize; + nSize -= pTba->pAreaInfo->nMediumBlkSize; + nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + WFSKrnExitOnError(TransGetAndPinFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, TRANS_FLAG_WRITE_BLK, nValidSize, (void**)&pDstBlkPtr)); + memcpy(pDstBlkPtr, pSrcBlkPtr, pTba->pAreaInfo->nMediumBlkSize); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, fileLargeBlkInfo.nBlkAdr, pTba->pTransInfo)); + } + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + for(nI=0;nIpAreaInfo, pFileBlkPtr->nBlkAdr, pTba->pTransInfo); + if(nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND){ + goto Exit; + } + } + u32 nNumIndirectBlks = (nNumBlks+pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk-1)/pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk; + for(nI=0;nIpAreaInfo, pIndirectBlkAdr[-nI], pTba->pTransInfo, TRANS_FLAG_READ_BLK, (void**)&pIndirectBlkPtr)); + if(nI+1==nNumIndirectBlks){ + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2LargeBlkSize, (nNumBlks-1)%pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk+1, + (WFSBlkAdr*)(pIndirectBlkPtr+sizeof(WFSMetaDataHdr)), (s32)sizeof(WFSFileLargeBlkPtr), pTba->pTransInfo)); + } else { + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2LargeBlkSize, pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk, + (WFSBlkAdr*)(pIndirectBlkPtr+sizeof(WFSMetaDataHdr)), (s32)sizeof(WFSFileLargeBlkPtr), pTba->pTransInfo)); + } + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, pIndirectBlkAdr[-nI], pTba->pTransInfo)); + } + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2BlkSize, nNumIndirectBlks, pIndirectBlkAdr, -(s32)sizeof(WFSBlkAdr), pTba->pTransInfo)); + break; + } + case FILE_RESIZE_CATEGORY_VERY_LARGE_TO_LARGE:{ + u8 *pIndirectBlkPtr; + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, 0); + WFSKrnReturnOnError(TransGetAndPinBlk5(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo, TRANS_FLAG_READ_BLK, (void**)&pIndirectBlkPtr)); + WFSFileLargeBlkPtr *pSrcFileLargeBlkPtr = 0, *pDstFileLargeBlkPtr = 0; + int nI, nJ; + for(nI=0;nIpAreaInfo->nLog2MediumBlkPerLargeBlk);nJ++){ + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge(pTba->pAreaInfo, pDstFileLargeBlkPtr, nJ); + u32 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pDi->pBlkHdr; + nResult = BCacheSetHash(pTba->pAreaInfo->pVolInfo, fileBlkInfo.nBlkAdr, pTba->nBlkAdr, nHashOfs); + if (nResult != WFSKRN_RESULT_OK && nResult != WFSKRN_RESULT_BCACHE_NOT_FOUND) { + goto Exit; + } + } + } + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + s32 nNumIndirectBlks = (nNumBlks-1)/pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk+1; + pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, nNumIndirectBlks-1); + s32 nNumEndBlks = (nNumBlks-1)%pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk+1; + u32 nNumFreeBlks = nNumBlks-nNewNumBlks; + while(nNumFreeBlks > 0){ + u8 *pIndirectBlkPtr; + WFSKrnReturnOnError(TransGetAndPinBlk5(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo, TRANS_FLAG_READ_BLK, (void**)&pIndirectBlkPtr)); + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrFromIndirectBlkForCategoryVeryLarge(pIndirectBlkPtr, nNumEndBlks-1); + if(nNumFreeBlks >= nNumEndBlks){ + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2LargeBlkSize, nNumEndBlks, &pFileLargeBlkPtr->nBlkAdr, -(s32)nStride, pTba->pTransInfo)); + nNumFreeBlks -= nNumEndBlks; + } else { + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2LargeBlkSize, nNumFreeBlks, &pFileLargeBlkPtr->nBlkAdr, -(s32)nStride, pTba->pTransInfo)); + nNumFreeBlks = 0; + } + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + pIndirectBlkAdr = &pIndirectBlkAdr[1]; + nNumEndBlks = pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk; + } + WFSKrnExitOnError(TransFreeBlks6(pTba->pAreaInfo, pTba->pAreaInfo->ah.nLog2BlkSize, nNumIndirectBlks, &pIndirectBlkAdr[-1], -(s32)sizeof(WFSBlkAdr), pTba->pTransInfo)); + if(pAttrHdr->nAllocSize > nAllocSize && nNewNumBlks){ + u32 nMedBlkIdx = ((nNewSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize)&((1<pAreaInfo->nLog2MediumBlkPerLargeBlk)-1); + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge(pTba->pAreaInfo, pDstFileLargeBlkPtr, nMedBlkIdx); + u32 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pDi->pBlkHdr; + WFSKrnExitOnError(TransTrancateFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, fileBlkInfo.nBlkAdr, pTba->pAreaInfo->nMediumBlkSize, + ((nNewSize-1)&(pTba->pAreaInfo->nMediumBlkSize-1))+1)); + } + break; + } + default: + return WFSKRN_RESULT_NOT_IMPLEMENTED; + } + memcpy(pNewAttrHdr, pAttrHdr, nCopyForward); + } else{ + if(pAttrHdr->file.nSize > nNewSize && nNewSize){ + switch(nNewSizeCategory){ + case FILE_SIZE_CATEGORY_SMALL:{ + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pAttrHdr, pAttrHdr->nAttrLog2Size, nNewNumBlks-1); + u32 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + u32 nOldBlkSize = ((nNewSize-1)>>pTba->pAreaInfo->ah.nLog2BlkSize == (pAttrHdr->file.nSize-1)>>pTba->pAreaInfo->ah.nLog2BlkSize) ? + ((pAttrHdr->file.nSize-1)&(pTba->pAreaInfo->nBlkSize-1))+1 : pTba->pAreaInfo->nBlkSize; + WFSKrnExitOnError(TransTrancateFileBlk( pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, + nOldBlkSize, ((nNewSize-1)&(pTba->pAreaInfo->nBlkSize-1))+1) ); + break; + } + case FILE_SIZE_CATEGORY_MEDIUM:{ + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pAttrHdr, pAttrHdr->nAttrLog2Size, nNewNumBlks-1); + u32 nHashOfs = (u8*)&pFileBlkPtr->hash - (u8*)pDi->pBlkHdr; + u32 nOldBlkSize = ((nNewSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize == (pAttrHdr->file.nSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize) ? + ((pAttrHdr->file.nSize-1)&(pTba->pAreaInfo->nMediumBlkSize-1))+1 : pTba->pAreaInfo->nMediumBlkSize; + WFSKrnExitOnError(TransTrancateFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, pFileBlkPtr->nBlkAdr, + nOldBlkSize, ((nNewSize-1)&(pTba->pAreaInfo->nMediumBlkSize-1))+1)); + break; + } + case FILE_SIZE_CATEGORY_LARGE:{ + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrForCategoryLarge(pAttrHdr, pAttrHdr->nAttrLog2Size, nNewNumBlks-1); + u32 nMedBlkIdx = ((nNewSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize)&((1<pAreaInfo->nLog2MediumBlkPerLargeBlk)-1); + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge(pTba->pAreaInfo, pFileLargeBlkPtr, nMedBlkIdx); + u32 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pDi->pBlkHdr; + u32 nOldBlkSize = ((nNewSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize == (pAttrHdr->file.nSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize) ? + ((pAttrHdr->file.nSize-1)&(pTba->pAreaInfo->nMediumBlkSize-1))+1 : pTba->pAreaInfo->nMediumBlkSize; + WFSKrnExitOnError(TransTrancateFileMediumBlk(pTba, pTba->nBlkAdr, nHashOfs, fileBlkInfo.nBlkAdr, + nOldBlkSize, ((nNewSize-1)&(pTba->pAreaInfo->nMediumBlkSize-1))+1)); + break; + } + case FILE_SIZE_CATEGORY_VERY_LARGE:{ + u8 *pIndirectBlkPtr; + u32 nTrancateSize = ((nNewSize-1)&(pTba->pAreaInfo->nMediumBlkSize-1))+1; + if(nTrancateSize == pTba->pAreaInfo->nMediumBlkSize){ break; } + u32 nIndirectBlkIdx = (nNewNumBlks-1)/pTba->pAreaInfo->nNumLargeBlkPtrsPerBlk; + u32 nMedBlkIdx = ((nNewSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize)%(pTba->pAreaInfo->nNumMediumBlkPtrsPerBlk); + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pTba->pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, nIndirectBlkIdx); + WFSKrnReturnOnError(TransGetAndPinBlk5(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo, TRANS_FLAG_RW_BLK, (void**)&pIndirectBlkPtr)); + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoFromIndirectBlkForCategoryVeryLarge(pTba->pAreaInfo, pIndirectBlkPtr, nMedBlkIdx); + u16 nHashOfs = (u8*)fileBlkInfo.pHash - (u8*)pIndirectBlkPtr; + u32 nOldBlkSize = ((nNewSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize == (pAttrHdr->file.nSize-1)>>pTba->pAreaInfo->ah.nLog2MediumBlkSize) ? + ((pAttrHdr->file.nSize-1)&(pTba->pAreaInfo->nMediumBlkSize-1))+1 : pTba->pAreaInfo->nMediumBlkSize; + WFSKrnExitOnError(TransTrancateFileMediumBlk(pTba, *pIndirectBlkAdr, nHashOfs, fileBlkInfo.nBlkAdr, nOldBlkSize, nTrancateSize)); + WFSKrnExitOnError(TransUnpinBlk3(pTba->pAreaInfo, *pIndirectBlkAdr, pTba->pTransInfo)); + break; + } + } + } + } + + // Update the attributes data. + if(nAllocSize == pAttrHdr->nAllocSize){ + pAttrHdr->file.nSize = nNewSize; + } else { + pNewAttrHdr->nAllocSize = nAllocSize; + pNewAttrHdr->file.nSize = nNewSize; + pNewAttrHdr->nAttrLog2Size = nNewAttrLog2Size; + pNewAttrHdr->nSizeCategory = nNewSizeCategory; + if(pNewAttrHdr != pAttrHdr){ + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pDi->pBlkHdr, *pDi->dni.pOfs, pDi->dni.nLog2Size); + pDi->pAttrHdr = pNewAttrHdr; + pDi->dni.nLog2Size = nNewAttrLog2Size; + *pDi->dni.pOfs = nNewAttrOfs; + dbg(DirLeafCheckBlk(pDi)); + } + } + return WFSKRN_RESULT_OK; + +Exit:; + if(pNewAttrHdr != pAttrHdr){ + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pDi->pBlkHdr, nNewAttrOfs, nNewAttrLog2Size); + dbg(DirLeafCheckBlk(pDi)); + } + + return nResult; + +} + + +WFSKrnResult DirInsertRaw(WFSFileName *pName, DirItr *pDi, u32 nAllocSize) { +#if _DEBUG_BREAK_POINT + static int c=0;++c;if(c>=0x76){ + int a;a=0; + } +#endif + // Inserts a new name into the directory + // pDi->tba.pAreaInfo [In] .. pointer to area info which contains details of are location on disk + // pDi->tba.nBlkAdr [In] .. logical block address relative to the start of the area + // pDi->tba.pTransInfo [In] .. index specifying the transaction + + // Specifies a block as a combination of pAreaInfo, relative + // ToDo: Make sorted sequential insertion give most compact packing. Currently gives least compact packing! +#if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } +#endif + + // WFSBlkAdr nDirRootBlkAdr = pDi->tba.nBlkAdr; + u8 nSizeCategory; + DirEntryAttrHdr *pAttrHdr; + u8 nAttrLog2Size = (u8)DirCalculateAttrSubBlkLog2SizeUpdateAllocSize(pDi->tba.pAreaInfo, &nAllocSize, pName->nLen, &nSizeCategory); + WFSKrnResult nResult = DirSbaAllocAndRegistSubBlk(pName, pDi, nAttrLog2Size, &pAttrHdr); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + + pAttrHdr->nAccessListIdx = 0; + pAttrHdr->nAllocSize = nAllocSize; + pAttrHdr->nNameLen = pName->nLen; + pAttrHdr->nAttrLog2Size = nAttrLog2Size; + pAttrHdr->nSizeCategory = nSizeCategory; + + switch(nSizeCategory) { + case FILE_SIZE_CATEGORY_VERY_SMALL: { + #if _DEBUG_DIR + u8 nTestSizeCategory; + u8 nTestAttrLog2Size = (u8)DirCalculateAttrSubBlkLog2Size(pDi->tba.pAreaInfo, nAllocSize, pName->nLen, &nTestSizeCategory); + if ((nTestAttrLog2Size != nAttrLog2Size) || (nTestSizeCategory != nTestSizeCategory)) { + WFSKrnOutputErrorStr("Error: AllocSize does not fit in allocated block"); + } + nTestAttrLog2Size = (u16)DirCalculateAttrSubBlkLog2Size(pDi->tba.pAreaInfo, nAllocSize+1, pName->nLen, &nTestSizeCategory); + if ((nTestAttrLog2Size == nAttrLog2Size) && (nTestSizeCategory == nTestSizeCategory)) { + WFSKrnOutputErrorStr("Error: AllocSize+1 fits in allocated block"); + } + #endif + nResult = WFSKRN_RESULT_OK; + break; + } + case FILE_SIZE_CATEGORY_SMALL: { + u32 nNumFileBlks = nAllocSize ? ((nAllocSize-1)>>pDi->tba.pAreaInfo->ah.nLog2BlkSize)+1 : 0; + // Set 0 to the all of WFSFileBlkPtr. + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pAttrHdr, pAttrHdr->nAttrLog2Size, nNumFileBlks-1); + memset(pFileBlkPtr, 0, nNumFileBlks*sizeof(WFSFileBlkPtr)); + // Alloc new block address for UserData. + nResult = AreaAllocBlks(pDi->tba.pAreaInfo, pDi->tba.nBlkAdr, pDi->tba.pAreaInfo->ah.nLog2BlkSize, + nNumFileBlks, &pFileBlkPtr[nNumFileBlks-1].nBlkAdr, -(signed)sizeof(WFSFileBlkPtr)); + // Sort the allocated block addresses into reverse order (since we access the WFSFileBlkPtr in reverse order). + _qsort(&pFileBlkPtr->nBlkAdr, nNumFileBlks, sizeof(WFSFileBlkPtr), CompareBlkAdrReverse); + break; + } + case FILE_SIZE_CATEGORY_MEDIUM: { + u32 nNumFileMediumBlks = nAllocSize ? ((nAllocSize-1)>>pDi->tba.pAreaInfo->ah.nLog2MediumBlkSize)+1 : 0; + // Set 0 to the all of WFSFileBlkPtr. + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pAttrHdr, pAttrHdr->nAttrLog2Size, nNumFileMediumBlks-1); + memset(pFileBlkPtr, 0, nNumFileMediumBlks*sizeof(WFSFileBlkPtr)); + // Alloc new block address for UserData. + nResult = AreaAllocBlks(pDi->tba.pAreaInfo, pDi->tba.nBlkAdr, pDi->tba.pAreaInfo->ah.nLog2MediumBlkSize, + nNumFileMediumBlks, &pFileBlkPtr[nNumFileMediumBlks-1].nBlkAdr, -(signed)sizeof(WFSFileBlkPtr)); + // Sort the allocated block addresses into reverse order (since we access the WFSFileBlkPtr in reverse order). + _qsort(&pFileBlkPtr->nBlkAdr, nNumFileMediumBlks, sizeof(WFSFileBlkPtr), CompareBlkAdrReverse); + break; + } + case FILE_SIZE_CATEGORY_LARGE: { + u32 nNumFileLargeBlks = nAllocSize ? ((nAllocSize-1)>>pDi->tba.pAreaInfo->ah.nLog2LargeBlkSize)+1 : 0; + // Set 0 to the all of WFSFileBlkPtr. + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrForCategoryLarge(pAttrHdr, pAttrHdr->nAttrLog2Size, nNumFileLargeBlks-1); + memset(pFileLargeBlkPtr, 0, nNumFileLargeBlks*sizeof(WFSFileLargeBlkPtr)); + // Alloc new block address for UserData. + nResult = AreaAllocBlks(pDi->tba.pAreaInfo, pDi->tba.nBlkAdr, pDi->tba.pAreaInfo->ah.nLog2LargeBlkSize, + nNumFileLargeBlks, &pFileLargeBlkPtr[nNumFileLargeBlks-1].nBlkAdr, -(signed)sizeof(WFSFileLargeBlkPtr)); + // Sort the allocated block addresses into reverse order (since we access the WFSFileBlkPtr in reverse order). + _qsort(&pFileLargeBlkPtr->nBlkAdr, nNumFileLargeBlks, sizeof(WFSFileLargeBlkPtr), CompareBlkAdrReverse); + break; + } + case FILE_SIZE_CATEGORY_VERY_LARGE: { + u32 nNumFileLargeBlks = nAllocSize ? ((nAllocSize-1)>>pDi->tba.pAreaInfo->ah.nLog2LargeBlkSize)+1 : 0; + u32 nNumIndirectBlks = (nNumFileLargeBlks+pDi->tba.pAreaInfo->nNumLargeBlkPtrsPerBlk-1)/pDi->tba.pAreaInfo->nNumLargeBlkPtrsPerBlk; + // Set 0 to the all of indirect block addresses. + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(pDi->tba.pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, nNumIndirectBlks-1); + //memset(pIndirectBlkAdr, 0, nNumIndirectBlks*sizeof(WFSBlkAdr)); + pIndirectBlkAdr = &pIndirectBlkAdr[nNumIndirectBlks-1]; + // Alloc new block addresses for indirect blocks. + nResult = AreaAllocBlks(pDi->tba.pAreaInfo, pDi->tba.nBlkAdr, pDi->tba.pAreaInfo->ah.nLog2BlkSize, nNumIndirectBlks, pIndirectBlkAdr, -(s32)sizeof(WFSBlkAdr)); + // Sort the allocated block addresses into reverse order (since we access the WFSFileBlkPtr in reverse order). + _qsort(&pIndirectBlkAdr[1-nNumIndirectBlks], nNumIndirectBlks, sizeof(WFSBlkAdr), CompareBlkAdrReverse); + // Alloc new block addresses for file data blocks. + u32 nI, nRefBlkAdr = *pIndirectBlkAdr; + for(nI=0;nItba.pAreaInfo, *pIndirectBlkAdr, pDi->tba.pTransInfo, TRANS_FLAG_WRITE_BLK, (void**)&pIndirectBlkPtr)); + // Set 0 to the all of indirect block addresses. + // Alloc new block address for indirect blocks. + u32 nNumAllocLargeBlks = (nI+1 == nNumIndirectBlks) ? (nNumFileLargeBlks-1)%pDi->tba.pAreaInfo->nNumLargeBlkPtrsPerBlk+1 : pDi->tba.pAreaInfo->nNumLargeBlkPtrsPerBlk; + memset((u8*)pIndirectBlkPtr+sizeof(WFSMetaDataHdr), 0, nNumAllocLargeBlks*sizeof(WFSFileLargeBlkPtr)); + nResult = AreaAllocBlks(pDi->tba.pAreaInfo, nRefBlkAdr, pDi->tba.pAreaInfo->ah.nLog2LargeBlkSize, nNumAllocLargeBlks, + (WFSBlkAdr*)((u8*)pIndirectBlkPtr+sizeof(WFSMetaDataHdr)), (s32)sizeof(WFSFileLargeBlkPtr)); + // Sort the allocated block addresses into reverse order (since we access the WFSFileBlkPtr in reverse order). + _qsort((u8*)pIndirectBlkPtr+sizeof(WFSMetaDataHdr), nNumAllocLargeBlks, sizeof(WFSFileLargeBlkPtr), CompareBlkAdrForward); + // Update the reference block address + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrFromIndirectBlkForCategoryVeryLarge(pIndirectBlkPtr, nNumAllocLargeBlks-1); + nRefBlkAdr = pFileLargeBlkPtr->nBlkAdr; + // Unpin the indirect block + WFSKrnReturnOnError(TransUnpinBlk3(pDi->tba.pAreaInfo, *pIndirectBlkAdr, pDi->tba.pTransInfo)); + pIndirectBlkAdr = &pIndirectBlkAdr[-1]; + } + break; + } + } + + dbg(DirLeafCheckBlk(pDi)); + + return nResult; +} + + +WFSKrnResult DirDeleteEntry(DirItr *pDi) { +#if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + DirLeafCheckBlk(pDi); + } +#endif + DirBlkHdr *pBlkHdr; + WFSKrnResult nResult = DirGetBlk(pDi, TRANS_FLAG_RW_BLK, &pBlkHdr); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + SbaFreeSubBlk((WFSSubBlkAllocHdr*)pBlkHdr, *pDi->dni.pOfs, pDi->pAttrHdr->nAttrLog2Size); + --pBlkHdr->nNumRecs; + // Backtrack within leaf block + while(1) { + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + pDi->dni.pDns->nSubBlkOfs); + pDi->dni.nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + pDi->dni.nEntryIdx = pDi->dni.pDns->nEntryIdx; + if (pDi->dni.pSubBlkHdr->nNumEntries!=1) { + break; + } + // This is the only entry in the sub-block. Delete it, and delete the corresponding entry from its parent. + // If this leaves the parent empty, delete the parent and repeat with earlier ancestors. + SbaFreeSubBlk((WFSSubBlkAllocHdr*)pBlkHdr, pDi->dni.pDns->nSubBlkOfs, pDi->dni.nLog2Size); + if (pDi->dni.pDns->nSubBlkOfs == pBlkHdr->nRootOfs) { + // This was the last sub block of the block + goto DeleteFromNode; + } + DirPopNodeStackEntry(&pDi->dni); + } + u16 *pExistingNodeOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + u16 *pSrcStart = DirLeafGetIntraBlkOfsPtr_ote(pDi->dni.pSubBlkHdr->nNumEntries, pExistingNodeOfsTblEnd); + u16 *pSrcEnd = DirLeafGetIntraBlkOfsPtr_ote(pDi->dni.nEntryIdx, pExistingNodeOfsTblEnd); + // Delete the choice character from the original block + utf8 *pSrc = &pDi->dni.pSubBlkHdr->aFirstChar[pDi->dni.pSubBlkHdr->nStrLen + pDi->dni.nEntryIdx]; + memmove(pSrc-1, pSrc, pDi->dni.pSubBlkHdr->nNumEntries - pDi->dni.nEntryIdx); + --pDi->dni.pSubBlkHdr->nNumEntries; + u32 nUpdatedNodeLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + if (nUpdatedNodeLog2Size != pDi->dni.nLog2Size) { + u32 nUpdatedNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nUpdatedNodeLog2Size); + if (nUpdatedNodeOfs == 0) { + // Could not allocate a new block, so resize in place + u16 *pDstStart = DirLeafGetIntraBlkOfsPtr_l2s(pDi->dni.pSubBlkHdr->nNumEntries, pDi->dni.pSubBlkHdr, nUpdatedNodeLog2Size); + u32 nCopySize2 = (u8*)pSrcEnd - (u8*)pSrcStart; + memmove(pDstStart, pSrcStart, nCopySize2); + if (pDi->dni.nEntryIdx != 1) { + pDstStart = (u16*)((u8*)pDstStart + nCopySize2); + pSrcStart = &pSrcEnd[1]; + memcpy(pDstStart, pSrcStart, (u8*)pExistingNodeOfsTblEnd - (u8*)pSrcStart); + } + SbaReduceSubBlkSize((WFSSubBlkAllocHdr *)pBlkHdr, pDi->dni.pDns->nSubBlkOfs, pDi->dni.nLog2Size, nUpdatedNodeLog2Size); + } else { + // Delete offset pointer while copying to a new sub block + DirSubBlkHdr *pUpdatedNodeHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nUpdatedNodeOfs); + u32 nCopySize1 = sizeof(DirSubBlkHdr)-1 + pDi->dni.pSubBlkHdr->nStrLen + pDi->dni.pSubBlkHdr->nNumEntries; + memcpy(pUpdatedNodeHdr, pDi->dni.pSubBlkHdr, nCopySize1); + u16 *pDstStart = DirLeafGetIntraBlkOfsPtr_l2s(pDi->dni.pSubBlkHdr->nNumEntries, pUpdatedNodeHdr, nUpdatedNodeLog2Size); + u32 nCopySize2 = (u8*)pSrcEnd - (u8*)pSrcStart; + memcpy(pDstStart, pSrcStart, nCopySize2); + pDstStart = (u16*)((u8*)pDstStart + nCopySize2); + pSrcStart = &pSrcEnd[1]; + memcpy(pDstStart, pSrcStart, (u8*)pExistingNodeOfsTblEnd - (u8*)pSrcStart); + // Update parent to point to the new node. Parent may be the nRootOfs of the block + SbaFreeSubBlk((WFSSubBlkAllocHdr*)pBlkHdr, pDi->dni.pDns->nSubBlkOfs, pDi->dni.nLog2Size); + DirLeafUpdateParentOfsPtr(pDi, nUpdatedNodeOfs); + pDi->dni.pSubBlkHdr = pUpdatedNodeHdr; + } + } else { + // Delete entry from existing node + u16 *pDstStart = DirLeafGetIntraBlkOfsPtr_ote(pDi->dni.pSubBlkHdr->nNumEntries, pExistingNodeOfsTblEnd); + u32 nCopySize2 = (u8*)pSrcEnd - (u8*)pSrcStart; + memmove(pDstStart, pSrcStart, nCopySize2); + } + if ((pDi->dni.pSubBlkHdr->nNumEntries==1) && (pDi->dni.pSubBlkHdr->aFirstChar[pDi->dni.pSubBlkHdr->nStrLen] != 0)) { + // The sub block has been left with one entry after deletion. + // If it has a child pointer, it must be concatenated with the child. + u16 nNewOfs = DirLeafMergeSubBlkWithItsSingleChild(pDi, pBlkHdr, pDi->dni.pDns->nSubBlkOfs); + if (nNewOfs == 0) { + // ToDo: This case may need to be handled properly + WFSKrnOutputErrorStr("No space to merge sub-blocks!"); + } + DirLeafUpdateParentOfsPtr(pDi, nNewOfs); + } + dbg(DirLeafCheckBlk(pDi)); + goto Done; + + // Backtrack within node blocks + while(1) { + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + pDi->dni.pDns->nSubBlkOfs); + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + pDi->dni.nEntryIdx = pDi->dni.pDns->nEntryIdx; + if (pDi->dni.pSubBlkHdr->nNumEntries!=1) { + break; + } + // This is the only entry in the sub-block. Delete it, and delete the corresponding entry from its parent. + // If this leaves the parent empty, delete the parent and repeat with earlier ancestors. + SbaFreeSubBlk((WFSSubBlkAllocHdr*)pBlkHdr, pDi->dni.pDns->nSubBlkOfs, pDi->dni.nLog2Size); + //if (pDi->dni.pOfs == &pBlkHdr->nRootOfs) { + if (pDi->dni.pDns->nSubBlkOfs == pBlkHdr->nRootOfs) { + // This was the last sub block of the block + // If a parent node exists, we should delete this block, and proceed to remove the splitter from the parent. + // Otherwise, if this is the only block in the directory, we should leave it in the empty state. +DeleteFromNode: + if (pDi->dni.nDnsDepth==2) { + DirReinitBlk(pDi->tba.pAreaInfo, pBlkHdr, (WFSMetaDataFlags)(pBlkHdr->sbah.mdh.nFlags | WFS_MDF_DIR_LEAF_BLK)); + //DirCreateAndInitNewBlk(&pDi->tba, (WFSMetaDataFlags)(pBlkHdr->sbah.mdh.nFlags | WFS_MDF_DIR_LEAF_BLK)); + DirBlkCreateRootNode(pBlkHdr); + dbg(DirNodeCheckBlk(pDi)); + goto Done; + } + --pDi->nBlkDepth; + DirUnpinAndFreeBlk(pDi->tba.pAreaInfo, pDi->tba.nBlkAdr, pDi->tba.pTransInfo); + pDi->tba.nBlkAdr = pDi->dni.pDns->pParent->nBlkAdr; + osTPrintf( "%s, %d : %d, %d\n", __FUNCTION__, __LINE__, pDi->tba.nBlkAdr, pDi->dni.pDns->pParent->nBlkAdr); + WFSKrnReturnOnError( DirGetBlk(pDi, TRANS_FLAG_RW_BLK | BCACHE_FLAG_PINNED, &pBlkHdr) ); + dbg(DirNodeCheckBlk(pDi)); + + // Deletion sometimes requires the used space in a node to increase. + // This is due to the constraint that nodes with exactly one child must be merged with their child. + // In such cases the merged node may require more space than the total of the pre-merged nodes beacuse + // it must be allocated as a contiguous power-of-two sized sub block. + // We must detect cases where the deletion would cause the used space to increase beyond the size of + // the node, and split the node in advance. + + u32 nExtraSize = 0; + DirNodeStack *pDns = pDi->dni.pDns->pParent; + DirSubBlkHdr *pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + pDns->nSubBlkOfs); + if (pSubBlkHdr->nNumEntries == 1) { + pDns = pDns->pParent; + pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + pDns->nSubBlkOfs); + } + if (pDns->nBlkAdr == pDi->tba.nBlkAdr) { + if (pSubBlkHdr->nNumEntries == 2) { + if ((pDns->nEntryIdx == 1) || (pSubBlkHdr->aFirstChar[pSubBlkHdr->nStrLen] != 0)) { + u32 nLog2Size = DirNodeGetSubBlkLog2Size(pSubBlkHdr); + u16 nOfs = DirNodeGetIntraBlkOfs(pDns->nEntryIdx^3, pSubBlkHdr); + pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOfs); + u32 nLog2Size2 = DirNodeGetSubBlkLog2Size(pSubBlkHdr); + nExtraSize = (u32)(- (1< nTotalFree) { + DirPopNodeStackEntry(&pDi->dni); + u32 nFirstBlockToFree = 0; + WFSBlkAdr aDstBlkAdr[DIR_MAX_SPLIT_BLK_ALLOC-2]; + pDi->tba.nBlkAdr = pDi->dni.pDns->nBlkAdr; + WFSKrnReturnOnError(AreaAllocBlks(pDi->tba.pAreaInfo, pDi->tba.nBlkAdr, pDi->tba.pAreaInfo->ah.nLog2BlkSize, DIR_MAX_SPLIT_BLK_ALLOC-2, aDstBlkAdr, sizeof(WFSBlkAdr))); + WFSKrnReturnOnError(DirNodeBlkSplit(pDi, aDstBlkAdr, &nFirstBlockToFree)); + u32 nFindMaxDepth = pDi->nBlkDepth; // Note: This must be after the call to DirNodeBlkSplit + while(pDi->dni.nDnsDepth > 2) { + DirPopNodeStackEntry(&pDi->dni); + } + pDi->tba.nBlkAdr = pDi->dni.pDns->nBlkAdr; + DirItrClose(pDi); + pDi->nBlkDepth = 0; + nResult = DirFind(&pDi->name, pDi, nFindMaxDepth+1, DIR_FIND_MODE_NODE_SEARCH); + if (nResult != WFSKRN_RESULT_OK) { + return nResult; + } + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + dbg(if (*pDi->dni.pOfs != ((u8*)pDi->dni.pSubBlkHdr - (u8*)pBlkHdr)) { + WFSKrnOutputErrorStr("Ofs mismatch error!"); + }) + --pBlkHdr->nNumRecs; + continue; + } + --pBlkHdr->nNumRecs; + } + DirPopNodeStackEntry(&pDi->dni); + } + // Calculate srouce pointer location first (because it would change if we are deleting choice 0) + pExistingNodeOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + if ((pDi->dni.pDns->nSubBlkOfs == pBlkHdr->nRootOfs) && (pDi->dni.nEntryIdx==1)) { + if (pDi->dni.pSubBlkHdr->aFirstChar[0]!=0) { + WFSKrnOutputErrorStr("First entry of node non-zero!"); + } + // Instead of deleting the "" entry, then renaming the next entry to be "", + // we can make the "" entry point to same as the next entry, and delete the next entry. + // This method would have less problems with handling almost-full nodes. + pDi->dni.pDns->nEntryIdx = 2; + u16 nOfs = DirNodeGetIntraBlkOfs_ote(pDi->dni.pDns->nEntryIdx, pDi->dni.pSubBlkHdr, pExistingNodeOfsTblEnd); + u16 *pOfsTblEnd; + while(1) { + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOfs); + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + pOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + WFSKrnReturnOnError(DirNodeStackGetEntry(&pDi->dni)); + pDi->dni.pDns->nEntryIdx = 1; + pDi->dni.pDns->nSubBlkOfs = nOfs; + pDi->dni.pDns->nBlkAdr = pDi->tba.nBlkAdr; + if (pDi->dni.pSubBlkHdr->aFirstChar[pDi->dni.pSubBlkHdr->nStrLen] == 0) { + break; + } + nOfs = DirNodeGetIntraBlkOfs_ote(1, pDi->dni.pSubBlkHdr, pOfsTblEnd); + } + // We have found the end of the splitter. Record the child block off. + ((WFSBlkAdr*)pExistingNodeOfsTblEnd)[-1] = DirNodeGetBlkAdr_ote(pDi->dni.pSubBlkHdr, pOfsTblEnd); + if (pDi->dni.pSubBlkHdr->nNumEntries==1) { + SbaFreeSubBlk((WFSSubBlkAllocHdr*)pBlkHdr, pDi->dni.pDns->nSubBlkOfs, pDi->dni.nLog2Size); + DirPopNodeStackEntry(&pDi->dni); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + pDi->dni.pDns->nSubBlkOfs); + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + pDi->dni.nEntryIdx = pDi->dni.pDns->nEntryIdx; + } + pExistingNodeOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + } + pSrcStart = DirNodeGetIntraBlkOfsPtr_ote(pDi->dni.pSubBlkHdr->nNumEntries, pDi->dni.pSubBlkHdr, pExistingNodeOfsTblEnd); + pSrcEnd = DirNodeGetIntraBlkOfsPtr_ote(pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pExistingNodeOfsTblEnd); + // Delete the choice character from the original block + pSrc = &pDi->dni.pSubBlkHdr->aFirstChar[pDi->dni.pSubBlkHdr->nStrLen + pDi->dni.nEntryIdx]; + memmove(pSrc-1, pSrc, pDi->dni.pSubBlkHdr->nNumEntries - pDi->dni.nEntryIdx); + --pDi->dni.pSubBlkHdr->nNumEntries; + nUpdatedNodeLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + if (nUpdatedNodeLog2Size != pDi->dni.nLog2Size) { + u32 nUpdatedNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nUpdatedNodeLog2Size); + if (nUpdatedNodeOfs == 0) { + // Could not allocate a new block, so resize in place + u16 *pDstStart = DirNodeGetIntraBlkOfsPtr_l2s(pDi->dni.pSubBlkHdr->nNumEntries, pDi->dni.pSubBlkHdr, nUpdatedNodeLog2Size); + u32 nCopySize2 = (u8*)pSrcEnd - (u8*)pSrcStart; + memmove(pDstStart, pSrcStart, nCopySize2); + if (pDi->dni.nEntryIdx != 1) { + pDstStart = (u16*)((u8*)pDstStart + nCopySize2); + pSrcStart = &pSrcEnd[1]; + memcpy(pDstStart, pSrcStart, (u8*)pExistingNodeOfsTblEnd - (u8*)pSrcStart); + } + SbaReduceSubBlkSize((WFSSubBlkAllocHdr *)pBlkHdr, pDi->dni.pDns->nSubBlkOfs, pDi->dni.nLog2Size, nUpdatedNodeLog2Size); + } else { + // Delete offset pointer while copying to a new sub block + DirSubBlkHdr *pUpdatedNodeHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nUpdatedNodeOfs); + u32 nCopySize1 = sizeof(DirSubBlkHdr)-1 + pDi->dni.pSubBlkHdr->nStrLen + pDi->dni.pSubBlkHdr->nNumEntries; + memcpy(pUpdatedNodeHdr, pDi->dni.pSubBlkHdr, nCopySize1); + u16 *pDstStart = DirNodeGetIntraBlkOfsPtr_l2s(pDi->dni.pSubBlkHdr->nNumEntries, pUpdatedNodeHdr, nUpdatedNodeLog2Size); + u32 nCopySize2 = (u8*)pSrcEnd - (u8*)pSrcStart; + memcpy(pDstStart, pSrcStart, nCopySize2); + if (pDi->dni.nEntryIdx != 1) { + pDstStart = (u16*)((u8*)pDstStart + nCopySize2); + pSrcStart = &pSrcEnd[1]; + memcpy(pDstStart, pSrcStart, (u8*)pExistingNodeOfsTblEnd - (u8*)pSrcStart); + } + // Update parent to point to the new node. Parent may be the nRootOfs of the block + SbaFreeSubBlk((WFSSubBlkAllocHdr*)pBlkHdr, pDi->dni.pDns->nSubBlkOfs, pDi->dni.nLog2Size); + DirNodeUpdateParentOfsPtr(pDi, nUpdatedNodeOfs); +#if _DEBUG + if (pBlkHdr != pDi->pBlkHdr) { + WFSKrnOutputErrorStr("pDi->pBlkHdr changed"); + } +#endif + pDi->dni.pSubBlkHdr = pUpdatedNodeHdr; + } + } else { + // Delete entry from existing node + u16 *pDstStart = DirNodeGetIntraBlkOfsPtr_ote(pDi->dni.pSubBlkHdr->nNumEntries, pDi->dni.pSubBlkHdr, pExistingNodeOfsTblEnd); + u32 nCopySize2 = (u8*)pSrcEnd - (u8*)pSrcStart; + memmove(pDstStart, pSrcStart, nCopySize2); + } + if ((pDi->dni.pSubBlkHdr->nNumEntries==1) && (pDi->dni.pSubBlkHdr->aFirstChar[pDi->dni.pSubBlkHdr->nStrLen] != 0)) { + // The sub block has been left with one entry after deletion. + // If it has a child pointer, it must be concatenated with the child. + u16 nNewOfs = DirNodeMergeSubBlkWithItsSingleChild(pDi, pBlkHdr, pDi->dni.pDns->nSubBlkOfs); + if (nNewOfs == 0) { + // ToDo: This case may need to be handled properly + WFSKrnOutputErrorStr("No space to merge sub-blocks!"); + } + DirNodeUpdateParentOfsPtr(pDi, nNewOfs); +#if _DEBUG + if (pBlkHdr != pDi->pBlkHdr) { + WFSKrnOutputErrorStr("pDi->pBlkHdr changed"); + } +#endif + } + DirSubBlkHdr *pRootSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + pBlkHdr->nRootOfs); + if (pRootSubBlkHdr->aFirstChar[0] != 0) { // Note: Testing first char, not first choice since there must be a "" entry in every node + nResult = DirNodeRenameFirstRec(pBlkHdr); + if (nResult != WFSKRN_RESULT_OK) { + WFSKrnOutputErrorCode(nResult); + } + } + dbg(DirNodeCheckBlk(pDi)); +Done: + return nResult; +} + + +WFSKrnResult DirSbaAllocAndRegistSubBlk(WFSFileName *pName, DirItr *pDi, u32 nAttrLog2Size, DirEntryAttrHdr **ppNewAttrHdr){ + + WFSBlkAdr nDirRootBlkAdr = pDi->tba.nBlkAdr; +Retry: + pDi->tba.nBlkAdr = nDirRootBlkAdr; + pDi->nBlkDepth = 0; + WFSKrnResult nResult = DirFind(pName, pDi, DIR_MAX_BLK_DEPTH, DIR_FIND_MODE_NORMAL); + if (nResult == WFSKRN_RESULT_DIR_ENTRY_FOUND) { + // File name already exists + return WFSKRN_RESULT_ALREADY_EXISTS; + } + else if ((nResult == WFSKRN_RESULT_MEDIA_ERROR) || (nResult == WFSKRN_RESULT_CORRUPTION)) { + return nResult; + } + DirBlkHdr *pBlkHdr; + WFSKrnReturnOnError(DirGetBlk(pDi, TRANS_FLAG_RW_BLK, &pBlkHdr)); + u16 *pExistingNodeOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + // Format of name node sub blocks: + // [ StrLen, NumEntries, Char0, Char1, .. Char(StrLen-1), Choice1, .. Choice N, |<--gap-->|, Link N, Link N-1, .. Link 1 ] + // [ StrLen, NumEntries, Char0, Char1, .. Char(StrLen-1), Choice1, .. Choice N, |<--gap-->|, Link N, Link N-1, .. Link 1 ] + u16 nAttrOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nAttrLog2Size); + if (nAttrOfs == 0) { +AttrNotAllocated: + WFSKrnReturnOnError(DirLeafBlkSplit(pDi)); + DirItrCloseNoUnpin(pDi); + goto Retry; + } + DirEntryAttrHdr *pAttrHdr= pDi->pAttrHdr = (DirEntryAttrHdr *)((u8*)pBlkHdr + nAttrOfs); + // Some fields of the attributes block must be initialized here incase a split is required, which needs the size of + // the attribute block to be calculatable. Also, making sure to overwrite the start of the attributes block so that + // it no longer contains the magic number that is used to recognize free blocks in "wfskrn_SubBlkAlloc.cpp". + + u32 nSuffixLen = (u32)(pName->nLen - (pDi->dni.pStrPtr - pName->sStr)); + u32 nLog2Size; + if (pBlkHdr->nNumRecs==0) { + // No records in this directory yet. Add the first record. + pDi->dni.pSubBlkHdr->nStrLen = pName->nLen; + pDi->dni.pSubBlkHdr->nNumEntries = 1; + nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + //SbaReduceSubBlkSize((WFSSubBlkAllocHdr *)pBlkHdr, pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size, nLog2Size); + if (nLog2Size != pDi->dni.nLog2Size) { + u32 nOfs = (u32)((u8*)pDi->dni.pSubBlkHdr - (u8*)pBlkHdr); + dbg(SbaCheckOfs(nOfs)); + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nOfs, pDi->dni.nLog2Size); + pDi->dni.nLog2Size = nLog2Size; + nOfs = *pDi->dni.pOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, pDi->dni.nLog2Size); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nOfs); + } + pDi->dni.pSubBlkHdr->nStrLen = pName->nLen; //(u8)(pName->nLen - (pDi->dni.pStrPtr - pName->sStr)); +#if _DEBUG_DIR + if (pDi->dni.pStrPtr != pName->sStr) { + WFSKrnOutputErrorStr("Expected suffix == full name"); + } +#endif + pDi->dni.pSubBlkHdr->nNumEntries = 1; + memcpy(pDi->dni.pSubBlkHdr->aFirstChar, pDi->dni.pStrPtr, (size_t)(pDi->dni.pSubBlkHdr->nStrLen+1)); + u16 *pOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + pDi->dni.pOfs = &pOfsTblEnd[-1]; + *pDi->dni.pOfs = nAttrOfs; + ++pBlkHdr->nNumRecs; + //DirNodeStackFree(&di); + pDi->dni.nLog2Size = nAttrLog2Size; + goto Exit; + //return WFSKRN_RESULT_OK; + } + + // Insert the new name at the location found + // + // To insert a new file name into a directory block requires to allocate up to two new sub blocks + // for name nodes, resize an existing name node, and add a new sub block for file attributes and + // block pointers. It needs to be determined up-front whether this will require splitting the block. + // + // Cases: nNodeNumLeft nNumMatching nSuffixLen Result + // "",? + "zyx",0 -> 0 0 3 "",z("yx",0),? + // "",? + "",0 -> 0 0 0 "",0,? + // "abc",? + "abc",0 -> 0 3 0 "abc",0,? + // "abc",? + "abczyx",0 -> 0 3 3 "abc",z("yx",0),? + // "abc",0,? + "abczyx",0 -> 0 3 3 "abc",0,z("yx",0),? + // "abc",? + "ab",0 -> 1 2 0 "ab",0,c("",?) + // "abc",? + "abzyx",0 -> 1 2 3 "ab",c("",?),z("yx",0) + // "abc",? + "a",0 -> 2 1 0 "a",0,b("c",?) + // "abc",? + "azyx",0 -> 2 1 3 "a",b("c",?),z("yx",0) + // "abc",? + "zyx",0 -> 3 0 3 "",a("bc",?),z("yx",0) + + u32 nNumMatching = (u32)(pDi->dni.pNodeStrPtr - pDi->dni.pSubBlkHdr->aFirstChar); + u32 nNodeNumLeft = pDi->dni.pSubBlkHdr->nStrLen - nNumMatching; + u16 nNameSubBlkLog2Size = 0; + u16 nNameSubBlkOfs; + u16 nChoiceNodeSubBlkLog2Size; + u16 nChoiceNodeSubBlkOfs; + u16 *pNodeOfsTblEnd; + u16 *pAttrOfs = 0; + + if (nSuffixLen) { + // allocate a sub block for the new name entry + nNameSubBlkLog2Size = (u16)DirLeafGetSubBlkLog2Size_2(nSuffixLen-1, 1); + nNameSubBlkOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNameSubBlkLog2Size); + if (nNameSubBlkOfs == 0) { +NameNotAllocated: + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nAttrOfs, nAttrLog2Size); + goto AttrNotAllocated; + } + DirSubBlkHdr *pNameSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nNameSubBlkOfs); + u16 *pNameOfsTblEnd = (u16*)((u8*)pNameSubBlkHdr + (1<nNumEntries = 1; + pNameSubBlkHdr->nStrLen = (u8)(nSuffixLen-1); + memcpy(pNameSubBlkHdr->aFirstChar, &pDi->dni.pStrPtr[1], nSuffixLen); // includes copying the NULL terminator + pAttrOfs = &pNameOfsTblEnd[-1]; + pNameOfsTblEnd[-1] = nAttrOfs; + } else { + nNameSubBlkOfs = nAttrOfs; + } + + if (nNodeNumLeft == 0) { + // Add a new option to the existing node + u16 nUpdatedNodeOfs; + u16 nUpdatedNodeLog2Size = (u16)DirLeafGetSubBlkLog2Size_2(pDi->dni.pSubBlkHdr->nStrLen, (u32)(pDi->dni.pSubBlkHdr->nNumEntries+1)); + if (nUpdatedNodeLog2Size != pDi->dni.nLog2Size) { + // The node needs to be copied to a larger sub block + nUpdatedNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nUpdatedNodeLog2Size); + if (nUpdatedNodeOfs == 0) { + // Allocation failed, so undo any changes so far, split the block, and try again + if (nSuffixLen) { + // Undo the allocation of the name sub block + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNameSubBlkOfs, nNameSubBlkLog2Size); + } + goto NameNotAllocated; + } + DirSubBlkHdr *pUpdatedNodeHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nUpdatedNodeOfs); + u16 *pUpdatedNodeOfsTblEnd = (u16*)((u8*)pUpdatedNodeHdr + (1<dni.pSubBlkHdr->nStrLen + pDi->dni.nEntryIdx; + memcpy(pUpdatedNodeHdr, pDi->dni.pSubBlkHdr, nCopySize1); + u8 *pDst = &((u8*)pUpdatedNodeHdr)[nCopySize1]; + *pDst++ = (u8)pDi->dni.pStrPtr[0]; + s32 nCopySize2 = (s32)(pDi->dni.pSubBlkHdr->nNumEntries - pDi->dni.nEntryIdx); + memcpy(pDst, &((u8*)pDi->dni.pSubBlkHdr)[nCopySize1], (u32)nCopySize2); + ++pUpdatedNodeHdr->nNumEntries; + // Copy the table of child offset pointers from the old block to the new block while inserting the new offset + u16 *pDst2 = &pUpdatedNodeOfsTblEnd[-(s32)pUpdatedNodeHdr->nNumEntries]; + memcpy(pDst2, &pExistingNodeOfsTblEnd[-(s32)pDi->dni.pSubBlkHdr->nNumEntries], nCopySize2 * sizeof(u16)); + pDst2+=nCopySize2; + if (pAttrOfs == 0) { + pAttrOfs = pDst2; + } + *pDst2++ = nNameSubBlkOfs; + memcpy(pDst2, &pExistingNodeOfsTblEnd[nCopySize2-pDi->dni.pSubBlkHdr->nNumEntries], pDi->dni.nEntryIdx * sizeof(u16)); + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, *pDi->dni.pOfs, pDi->dni.nLog2Size); + *pDi->dni.pOfs = nUpdatedNodeOfs; // Update the parent pointer + } else { + // The new option can be added without changing the size of the node + utf8 *pCharInsertPoint = pDi->dni.pSubBlkHdr->aFirstChar + pDi->dni.pSubBlkHdr->nStrLen + pDi->dni.nEntryIdx; + s32 nCopySize = (s32)(pDi->dni.pSubBlkHdr->nNumEntries - pDi->dni.nEntryIdx); + memmove(pCharInsertPoint+1, pCharInsertPoint, (u32)nCopySize); + pCharInsertPoint[0] = pDi->dni.pStrPtr[0]; + u16 *pPtrArray = &pExistingNodeOfsTblEnd[-(s32)pDi->dni.pSubBlkHdr->nNumEntries]; + memmove(pPtrArray-1, pPtrArray, sizeof(u16) * nCopySize); + if (pAttrOfs == 0) { + pAttrOfs = &pPtrArray[nCopySize-1]; + } + pPtrArray[nCopySize-1] = nNameSubBlkOfs; + ++pDi->dni.pSubBlkHdr->nNumEntries; + } + } else { + // Replace the start of the existing node with a new 2-choice node + // and update the existing node to contain only the end of the string, + // resizing the node if its size drops to a smaller power-of-2 allocation size. + // (note: the resize is compulsory due to the algorithms used elsewhere). + // + // First, try to allocate a sub block for the new 2-choice node. + nChoiceNodeSubBlkLog2Size = (u16)DirLeafGetSubBlkLog2Size_2(nNumMatching, 2); + nChoiceNodeSubBlkOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nChoiceNodeSubBlkLog2Size); + if (nChoiceNodeSubBlkOfs == 0) { + // Allocation failed, so undo any changes so far, split the block, and try again + if (nSuffixLen) { + // Undo the allocation of the name sub block + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nNameSubBlkOfs, nNameSubBlkLog2Size); + } + goto NameNotAllocated; + } + DirSubBlkHdr *pChoiceNodeHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nChoiceNodeSubBlkOfs); + pNodeOfsTblEnd = (u16*)((u8*)pChoiceNodeHdr + (1<nNumEntries = 2; + pChoiceNodeHdr->nStrLen = (u8)nNumMatching; + memcpy(pChoiceNodeHdr->aFirstChar, pDi->dni.pSubBlkHdr->aFirstChar, nNumMatching); + utf8 cNodeChar = pDi->dni.pSubBlkHdr->aFirstChar[nNumMatching]; + utf8 cNameChar = pDi->dni.pStrPtr[0]; + + // Now, update the existing node + u16 nUpdatedNodeOfs; + u16 nUpdatedNodeLog2Size = (u16)DirLeafGetSubBlkLog2Size_2(nNodeNumLeft-1, pDi->dni.pSubBlkHdr->nNumEntries); + DirSubBlkHdr *pUpdatedNodeHdr; + if (nUpdatedNodeLog2Size != pDi->dni.nLog2Size) { + // The existing node should be reduced in size. + // First try to allocate a new smaller sub block. + // If this is not possible, then resize in place. + nUpdatedNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nUpdatedNodeLog2Size); + u16 *pUpdatedNodeOfsTblEnd; + u32 nOldNodeOfs = (u16)((u8*)pDi->dni.pSubBlkHdr - (u8*)pBlkHdr); + if (nUpdatedNodeOfs == 0) { + // allocation failed, so resize in place + // shift/copy the end of the string and the following choices backwards over the start of the string + pUpdatedNodeHdr = pDi->dni.pSubBlkHdr; + nUpdatedNodeOfs = (u16)nOldNodeOfs; + pUpdatedNodeOfsTblEnd = (u16*)((u8*)pUpdatedNodeHdr + (1<aFirstChar, &pUpdatedNodeHdr->aFirstChar[nNumMatching+1], nNodeNumLeft + pUpdatedNodeHdr->nNumEntries); + // shift over the table of pointers at the end of the sub block + memmove(&pUpdatedNodeOfsTblEnd[-(s32)pUpdatedNodeHdr->nNumEntries], &pExistingNodeOfsTblEnd[-(s32)pUpdatedNodeHdr->nNumEntries], sizeof(u16) * pUpdatedNodeHdr->nNumEntries); + SbaReduceSubBlkSize((WFSSubBlkAllocHdr *)pBlkHdr, nUpdatedNodeOfs, pDi->dni.nLog2Size, nUpdatedNodeLog2Size); + } else { + // copy the end of the node to the new node, and free the old node + pUpdatedNodeHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + nUpdatedNodeOfs); + *pDi->dni.pOfs = nUpdatedNodeOfs; // Update the parent pointer + pUpdatedNodeHdr->nNumEntries = pDi->dni.pSubBlkHdr->nNumEntries; + memcpy(pUpdatedNodeHdr->aFirstChar, &pDi->dni.pSubBlkHdr->aFirstChar[nNumMatching+1], nNodeNumLeft + pUpdatedNodeHdr->nNumEntries - 1); + pUpdatedNodeOfsTblEnd = (u16*)((u8*)pUpdatedNodeHdr + (1<nNumEntries], &pExistingNodeOfsTblEnd[-(s32)pUpdatedNodeHdr->nNumEntries], sizeof(u16) * pUpdatedNodeHdr->nNumEntries); + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBlkHdr, nOldNodeOfs, pDi->dni.nLog2Size); + } + } else { + // the sub block remains the same size + pUpdatedNodeHdr = pDi->dni.pSubBlkHdr; + nUpdatedNodeOfs = (u16)((u8*)pUpdatedNodeHdr - (u8*)pBlkHdr); + dbg(SbaCheckOfs(nUpdatedNodeOfs)); + // Remove characters from the start of the string + memmove(pUpdatedNodeHdr->aFirstChar, &pUpdatedNodeHdr->aFirstChar[nNumMatching+1], nNodeNumLeft + pUpdatedNodeHdr->nNumEntries - 1); + } + pUpdatedNodeHdr->nStrLen = (u8)(nNodeNumLeft-1); + *pDi->dni.pOfs = nChoiceNodeSubBlkOfs; + + if ((unsigned)cNodeChar < (unsigned)cNameChar) { + pChoiceNodeHdr->aFirstChar[nNumMatching] = cNodeChar; + pChoiceNodeHdr->aFirstChar[nNumMatching+1] = cNameChar; + pNodeOfsTblEnd[-1] = nUpdatedNodeOfs; + if (pAttrOfs == 0) { + pAttrOfs = &pNodeOfsTblEnd[-2]; + } + pNodeOfsTblEnd[-2] = nNameSubBlkOfs; + } else { + pChoiceNodeHdr->aFirstChar[nNumMatching] = cNameChar; + pChoiceNodeHdr->aFirstChar[nNumMatching+1] = cNodeChar; + if (pAttrOfs == 0) { + pAttrOfs = &pNodeOfsTblEnd[-1]; + } + pNodeOfsTblEnd[-1] = nNameSubBlkOfs; + pNodeOfsTblEnd[-2] = nUpdatedNodeOfs; + } + } + ++pBlkHdr->nNumRecs; + pDi->dni.pOfs = pAttrOfs; + pDi->dni.nLog2Size = nAttrLog2Size; + +Exit:; + + if(ppNewAttrHdr){ + *ppNewAttrHdr = pAttrHdr; + } + + //DirLeafCheckBlk(pDi); + return WFSKRN_RESULT_OK; +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirApi.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirApi.cpp new file mode 100644 index 0000000..ddb2c35 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirApi.cpp @@ -0,0 +1,695 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_DirApi.cpp - Top layer of the Directory module + + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_DirApi.cpp,v $ + Revision 1.26 2008/11/05 15:08:20 ueno + Modified DirItrMapBlks() to roll back the update map in case of error. + + Revision 1.25 2008/10/31 09:51:11 ueno + Modified WFSSrvAPIs to return WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED when path cache is short of memory. + + Revision 1.24 2008/10/30 04:51:28 kondo_masahiro + Fixed DirDeleteFile + + Revision 1.23 2008/10/20 00:30:54 nakanose_jin + (none) + + Revision 1.22 2008/10/17 08:50:48 kondo_masahiro + Added the new MEDIUM size category (40KB-320KB) + + Revision 1.21 2008/10/16 09:30:39 ooizumi + Fixed definitions for debug build. + + Revision 1.20 2008/10/15 00:14:57 kondo_masahiro + Fixed a bug about 4GB-1 + + Revision 1.19 2008/10/14 12:11:49 kondo_masahiro + Fixed a bug in DirDeleteFile + + Revision 1.18 2008/10/14 10:26:24 kondo_masahiro + Added codes to access very large size file data + + Revision 1.17 2008/10/10 02:11:20 kondo_masahiro + Fixed a bug to access large files + + Revision 1.16 2008/10/09 04:16:53 kondo_masahiro + Fixed member of AreaHdr and AreaInfo + + Revision 1.15 2008/10/08 23:19:54 kondo_masahiro + Added codes to access large size file data + + Revision 1.14 2008/09/28 23:31:51 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.13 2008/09/02 23:34:39 ooizumi + Added several casting. + + Revision 1.12 2008/09/02 23:02:47 ooizumi + Fixed a bug failed to treat utf8 as unsigned value. + + Revision 1.11 2008/08/05 03:58:49 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.10 2008/07/28 22:05:32 paul + Improved updateMap processing. Fixed a bug in DirDeleteSubDir(). + + Revision 1.9 2008/07/25 02:51:28 paul + Changed from nTransIdx to *pTransInfo + + Revision 1.8 2008/07/21 22:39:16 paul + Fixed a bug in DirItrCheckAndUnmapBlks() + Changed name from DirItrPinBlkAndUpdatePtrs() -> DirItrPinBlkAndFixPtrs() + + Revision 1.7 2008/07/17 22:47:11 paul + Added functions to support updateMap + + Revision 1.6 2008/07/09 00:30:20 paul + Changes to make directory code work with block cache. + + Revision 1.5 2008/06/09 17:21:58 paul + Added WFSKrnValidateCopyStrAndConvertToLowerCase() + + Revision 1.4 2008/05/12 22:35:37 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.3 2008/05/12 19:11:22 paul + Moved DirModuleInit here from wfskrn_Dir.cpp. + Updated DirItrClose to remove pDi from list of open iterators. + + Revision 1.2 2008/05/10 03:59:44 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.1 2008/04/25 17:29:16 kondo_masahiro + Initial check-in + + Revision 1.2 2008/04/23 00:25:23 paul + Modified some functions to take utf8 strings instead of WFSFileName structs + + Revision 1.1 2008/04/21 18:58:30 paul + *** empty log message *** +*---------------------------------------------------------------------------*/ + +#undef _KRN_FILE_ +#define _KRN_FILE_ "DirApi" + +#include "wfskrn_Api.h" +#include "wfskrn_Dir.h" +#include "wfskrn_DirFind.h" +#include "wfskrn_DirNodeStack.h" +#include "wfskrn_Area.h" +#include "wfskrn_PTree.h" +#include "wfskrn_Handles.h" + +DirGlobals dirGlobals; + + +void DirModuleInit() { + u32 nI=0; + for(nI=0; nI<256; nI++) { + dirGlobals.aToLower[nI] = dirGlobals.aToUpper[nI] = (utf8)nI; + } + for(nI='A'; nI<='Z'; nI++) { + dirGlobals.aToLower[nI] = (utf8)(nI + ('a'-'A')); + } + for(nI='a'; nI<='z'; nI++) { + dirGlobals.aToUpper[nI] = (utf8)(nI - ('a'-'A')); + } + DirAllocateMoreNodeStackEntries(); + dirGlobals.pOpenDirItrListAnchor = (DirItr *)((u8*)&dirGlobals.openDirItrListAnchor - (size_t)&((DirItr *)0)->link); + dirGlobals.openDirItrListAnchor.pNext = dirGlobals.openDirItrListAnchor.pPrev = dirGlobals.pOpenDirItrListAnchor; + PathCacheInit(); //dirGlobals.nUpdateCtr = 0; + dirGlobals.updateMapAllocator.pBase = (void*)&wkg.pathCache.pRxtHdr->sbah; + dirGlobals.updateMapAllocator.fpAllocNode = (PTreeAllocNodeFunc) PTreeAllocNodeFromSba; + dirGlobals.updateMapAllocator.fpAllocNodes = (PTreeAllocNodesFunc)PTreeAllocNodesFromSba; + dirGlobals.updateMapAllocator.fpFreeNode = (PTreeFreeNodeFunc) PTreeFreeNodeToSba; + PTreeInit(&dirGlobals.updateMap, &dirGlobals.updateMapAllocator); +} + +void WFSKrnCopyFileName(WFSFileName *pDst, WFSFileName *pSrc) { + if (pSrc->nLen > WFS_MAX_FILE_NAME_SIZE) { + pSrc->nLen = WFS_MAX_FILE_NAME_SIZE; + } + pDst->nLen = pSrc->nLen; + strncpy(pDst->sStr, pSrc->sStr, pDst->nLen); + pDst->sStr[pDst->nLen] = 0; +} + +inline void WFSKrnCopyStrAndConvertToLowerCase(utf8 *pDstStr, const utf8 *pSrcStr, u32 nLen) { + const utf8 *pSrcEnd = pSrcStr + nLen; + for(; pSrcStr nMaxLen) { + return WFSKRN_RESULT_INVALID; + } + WFSKrnCopyStrAndConvertToLowerCase(pDstStr, pSrcStr, nLen); + return WFSKRN_RESULT_OK; +} + +void WFSKrnCopyFileNameAndConvertToLowerCase(WFSFileName *pDst, WFSFileName *pSrc) { + if (pSrc->nLen > WFS_MAX_FILE_NAME_SIZE) { + pSrc->nLen = WFS_MAX_FILE_NAME_SIZE; + } + pDst->nLen = pSrc->nLen; + WFSKrnCopyStrAndConvertToLowerCase(pDst->sStr, pSrc->sStr, pSrc->nLen); +} + +void WFSKrnCopyFileNameAndRestoreCase(utf8 *pDst, WFSFileName *pSrc, u8 *pCaseBitArray) { + u32 nCaseBits = (u32)(256 + *pCaseBitArray); + if (pSrc->nLen > WFS_MAX_FILE_NAME_SIZE) { + pSrc->nLen = WFS_MAX_FILE_NAME_SIZE; + } + utf8 *pDstStr = pDst; + utf8 *pSrcStr = pSrc->sStr; + utf8 *pSrcEnd = pSrcStr + pSrc->nLen; + for(; pSrcStr>= 1; + if (nCaseBits == 1) { + nCaseBits = (u32)(256 + *(++pCaseBitArray)); + } + } + *pDstStr = 0; +} + +void WFSKrnStoreCaseInformationStr(u8 *pCaseBitArray, const utf8 *pStr, u32 nLen) { + u32 nCaseBit = 1; + u8 nCaseByte = 0; + const utf8 *pStrEnd = pStr + nLen; + for(; pStr 1) { + *pCaseBitArray = nCaseByte; + } +} + + +// Update Counter & Update Map Operations: +// +// BlkAdr: +// * Blocks must be referred to by absolute block address in the update map. +// +// Interaction with the transaction process: +// * In transactions, the block to be updated is first re-mapped to a different physical block. +// * When the update has been commited, it is copied to the logical block address. +// * For the purpose of update map processing, it should be OK to ignore the transaction process. +// +// When a block is initialized as a directory block: +// - First check the update map to see if any iterator is already referring to it. If so, copy the initial update count from there. +// Otherwise, the initial update count is initialized to 0. +// +// When a directory meta-data block gets freed: +// - If the block is in the update-map, increment its counter, then reduce its reference count, removing it if the reference count is zero. +// +// When a block is accessed by a directory iterator during DirFind or DirFindNext +// - The iterator copies the update counter of the block to its DirNodeStack. +// +// When a block is to be updated in the course of a executing a WFS command +// - Update the update counter in the block. //ToDo: it would be better if we only updated the counter when an existing sub-block is moved or deleted. +// - If the counter exists in the update map, increment it. Otherwise (in debug mode at least), reset the counter to 0. +// +// When an iterator is to be left open by a WFS command: +// - Increment the reference count of the blocks in the update map, or add them to the update map if neccessary. +// - Update the counter +// +// When an iterator is to re-used after a gap +// - The blocks it references should be found in the update map, and checked against the values stored in the iterator. +// - If necessary, the file attributes should be re-located using DirFind. + + +static DirNodeStack* MapBlks(DirItr *pDi) { +#if _DEBUG_BREAK_POINT + static int c=0;++c;if(c>=7019){//8194){ + int a;a=0; + } + if (wkg.pathCache.pRxtHdr->sbah.aSubBlkList[0].nNumFree > 16) { + int a;a=0; + } +#endif + // When a new iterator is to be left open, we need to register the address of any blocks referenced in its DirNodeStack, + // and map each of these to the latest value of that block's update counter. + // However there are some complications: + // The same block could be referenced by multiple iterators, so they need to be reference-counted. + // An update operation consists of incrementing the reference count, and overwriting the update counter. + DirNodeStack *pDns = pDi->dni.pDns; + WFSBlkAdr nAbsStartBlkAdr = pDi->tba.pAreaInfo->nAbsStartBlkAdr; + WFSBlkAdr nBlkAdr = pDi->tba.nBlkAdr; + u32 nUpdateCtr = (u32)(pDi->nUpdateCtr & WFS_MDF_DIR_COUNTER_MASK); + while(nBlkAdr) { + WFSBlkAdr nAbsBlkAdr = nAbsStartBlkAdr + nBlkAdr; + PTreeItr pti; + u32 nData = DIR_BLK_REF_COUNT_INC | (nUpdateCtr & WFS_MDF_DIR_COUNTER_MASK); +Retry:; + WFSKrnResult nResult = PTreeInsert(&dirGlobals.updateMap, &pti, nAbsBlkAdr, nData, &dirGlobals.updateMapAllocator); + if (nResult == WFSKRN_RESULT_PTREE_ENTRY_FOUND) { + pti.pLeaf->aData[pti.aEntryIdx[0]] = nData + (pti.pLeaf->aData[pti.aEntryIdx[0]] & (u32)(-DIR_BLK_REF_COUNT_INC)); + } else if (nResult == WFSKRN_RESULT_PTREE_FULL) { + nResult = PathCacheDeleteLru(); + if (nResult != WFSKRN_RESULT_OK) + { + return pDns; + } + goto Retry; + } +#if _DEBUG + else if (nResult != WFSKRN_RESULT_OK) { + WFSKrnOutputErrorCode(nResult); + } +#endif + if (pDns==0) { + return pDns; + } + while(pDns->nBlkAdr == nBlkAdr) { + pDns = pDns->pParent; + if (pDns==0) { + return pDns; + } + } + nBlkAdr = pDns->nBlkAdr; + nUpdateCtr = pDns->nUpdateCtr; + } + + return NULL; +} + + +static void UnmapBlks(DirItr* pDi, DirNodeStack* pDns) +{ + PTreeItr pti; + WFSBlkAdr nAbsBlkAdr; + WFSKrnResult nResult; + u32 nUpdateCtr; + WFSBlkAdr nBlkAdr; + WFSBlkAdr nAbsStartBlkAdr = pDi->tba.pAreaInfo->nAbsStartBlkAdr; + DirNodeStack* pDnsEnd = pDi->dni.pDns; + + while (pDns != pDnsEnd) + { + // [check] must check this rollback routine. + pDns = pDns->pParent; + nBlkAdr = pDns->nBlkAdr; + nUpdateCtr = pDns->nUpdateCtr; + + nAbsBlkAdr = nAbsStartBlkAdr + nBlkAdr; + nResult = PTreeFind(&dirGlobals.updateMap, &pti, nAbsBlkAdr, &dirGlobals.updateMapAllocator); + +#if _DEBUG + if (nResult != WFSKRN_RESULT_PTREE_ENTRY_FOUND) + { + WFSKrnOutputErrorStr("DirItr block not found in updateMap"); + } + ASSERT(nResult == WFSKRN_RESULT_PTREE_ENTRY_FOUND); +#endif + // Decrement the reference counter + pti.pLeaf->aData[pti.aEntryIdx[0]] -= DIR_BLK_REF_COUNT_INC; + if ((pti.pLeaf->aData[pti.aEntryIdx[0]] & (u32)(-DIR_BLK_REF_COUNT_INC)) == 0) + { + // The reference counter is zero, so remove the mapping + PTreeDelete(&dirGlobals.updateMap, &pti, &dirGlobals.updateMapAllocator); + } + while (pDns->nBlkAdr == nBlkAdr) + { + pDns = pDns->pParent; + } + } +} + +WFSKrnResult DirItrMapBlks(DirItr *pDi) +{ + WFSKrnResult nResult = WFSKRN_RESULT_OK; + DirNodeStack* pDns; + pDns = MapBlks(pDi); + if (pDns) // [check] name. + { + // roll back. + nResult = WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED; + UnmapBlks(pDi, pDns); +#if _DEBUG + WFSKrnOutputErrorStr("DirItrMapBlks() : WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED\n"); +#endif + } + + return nResult; +} + + +void DirItrUnmapBlks(DirItr *pDi) { +#if _DEBUG_BREAK_POINT + static int c=0;++c;if(c>=2284){ + int a;a=0; + } +#endif +#if _DEBUG + if (dirGlobals.updateMap.nRootOfs == 0) { + WFSKrnOutputErrorStr("updateMap invalid"); + } +#endif + // Reduce the reference count of the blocks referenced by an iterator, and unmap them if the reference count reaches 0 + DirNodeStack *pDns = pDi->dni.pDns; + WFSBlkAdr nAbsStartBlkAdr = pDi->tba.pAreaInfo->nAbsStartBlkAdr; + WFSBlkAdr nBlkAdr = pDi->tba.nBlkAdr; + u32 nUpdateCtr = (u32)(pDi->nUpdateCtr & WFS_MDF_DIR_COUNTER_MASK); + while(nBlkAdr) { + WFSBlkAdr nAbsBlkAdr = nAbsStartBlkAdr + nBlkAdr; + PTreeItr pti; + WFSKrnResult nResult = PTreeFind(&dirGlobals.updateMap, &pti, nAbsBlkAdr, &dirGlobals.updateMapAllocator); + if (nResult != WFSKRN_RESULT_PTREE_ENTRY_FOUND) { + WFSKrnOutputErrorStr("DirItr block not found in updateMap"); + } +#if _DEBUG + else if (nResult != WFSKRN_RESULT_PTREE_ENTRY_FOUND) { + WFSKrnOutputErrorCode(nResult); + } +#endif + // Decrement the reference counter + pti.pLeaf->aData[pti.aEntryIdx[0]] -= DIR_BLK_REF_COUNT_INC; + if ((pti.pLeaf->aData[pti.aEntryIdx[0]] & (u32)(-DIR_BLK_REF_COUNT_INC)) == 0) { + // The reference counter is zero, so remove the mapping + PTreeDelete(&dirGlobals.updateMap, &pti, &dirGlobals.updateMapAllocator); + } + if (pDns==0) { + return; + } + while(pDns->nBlkAdr == nBlkAdr) { + pDns = pDns->pParent; + if (pDns==0) { + return; + } + } + nBlkAdr = pDns->nBlkAdr; + nUpdateCtr = pDns->nUpdateCtr; + } +} + + +WFSKrnResult DirItrCheckMapBlks(DirItr *pDi) { + // Check the updateCounter of blocks referenced by an iterator. + DirNodeStack *pDns = pDi->dni.pDns; + WFSBlkAdr nAbsStartBlkAdr = pDi->tba.pAreaInfo->nAbsStartBlkAdr; + WFSBlkAdr nBlkAdr = pDi->tba.nBlkAdr; + u32 nUpdateCtr = (u32)(pDi->nUpdateCtr & WFS_MDF_DIR_COUNTER_MASK); + while(nBlkAdr) { + WFSBlkAdr nAbsBlkAdr = nAbsStartBlkAdr + nBlkAdr; + PTreeItr pti; + WFSKrnResult nResult = PTreeFind(&dirGlobals.updateMap, &pti, nAbsBlkAdr, &dirGlobals.updateMapAllocator); + if (nResult != WFSKRN_RESULT_PTREE_ENTRY_FOUND) { + WFSKrnOutputErrorStr("DirItr block not found in updateMap"); + } +#if _DEBUG + else if (nResult != WFSKRN_RESULT_PTREE_ENTRY_FOUND) { + WFSKrnOutputErrorCode(nResult); + } +#endif + if ((pti.nData ^ nUpdateCtr) & WFS_MDF_DIR_COUNTER_MASK) { + return WFSKRN_RESULT_DIR_ITR_INVALID; + } + if (pDns==0) { + return WFSKRN_RESULT_OK; + } + while(pDns->nBlkAdr == nBlkAdr) { + pDns = pDns->pParent; + if (pDns==0) { + return WFSKRN_RESULT_OK; + } + } + nBlkAdr = pDns->nBlkAdr; + nUpdateCtr = pDns->nUpdateCtr; + } + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult DirItrCheckAndUnmapBlks(DirItr *pDi) { +#if _DEBUG_BREAK_POINT + static int c=0;++c;if(c>=4749){//5045 + int a;a=0; + } +#endif + // Check the updateCounter of blocks referenced by an iterator, and decrement the reference count for all blocks. + DirNodeStack *pDns = pDi->dni.pDns; + WFSKrnResult nResult = WFSKRN_RESULT_OK; + WFSBlkAdr nAbsStartBlkAdr = pDi->tba.pAreaInfo->nAbsStartBlkAdr; + WFSBlkAdr nBlkAdr = pDi->tba.nBlkAdr; + u32 nUpdateCtr = (u32)(pDi->nUpdateCtr & WFS_MDF_DIR_COUNTER_MASK); + while(nBlkAdr) { + WFSBlkAdr nAbsBlkAdr = nAbsStartBlkAdr + nBlkAdr; + PTreeItr pti; + WFSKrnResult nTempResult = PTreeFind(&dirGlobals.updateMap, &pti, nAbsBlkAdr, &dirGlobals.updateMapAllocator); +// #if _DEBUG + if (nTempResult != WFSKRN_RESULT_PTREE_ENTRY_FOUND) { + WFSKrnOutputErrorStr("DirItr block not found in updateMap"); + } +// #endif + if ((pti.nData ^ nUpdateCtr) & WFS_MDF_DIR_COUNTER_MASK) { + nResult = WFSKRN_RESULT_DIR_ITR_INVALID; + } + // Decrement the reference counter + pti.pLeaf->aData[pti.aEntryIdx[0]] -= DIR_BLK_REF_COUNT_INC; + if ((pti.pLeaf->aData[pti.aEntryIdx[0]] & (u32)(-DIR_BLK_REF_COUNT_INC)) == 0) { + // The reference counter is zero, so remove the mapping + PTreeDelete(&dirGlobals.updateMap, &pti, &dirGlobals.updateMapAllocator); + } + if (pDns==0) { + break; + } + while(pDns->nBlkAdr == nBlkAdr) { + pDns = pDns->pParent; + if (pDns==0) { + goto Done; + } + } + nBlkAdr = pDns->nBlkAdr; + nUpdateCtr = pDns->nUpdateCtr; + } +Done: + return nResult; +} + + +WFSKrnResult DirItrClose(DirItr *pDi) { + WFSKrnResult nResult = WFSKRN_RESULT_OK; + if (pDi->ppDnsRootParent) { + nResult = TransUnpinBlk(&pDi->tba); + //MyOSReport("%d: Close(%p)\n", nDirTest, pDi); + DirNodeStackFree(&pDi->dni, pDi->ppDnsRootParent); +//#if _DEBUG + pDi->ppDnsRootParent = 0; +//#endif + pDi->link.pNext->link.pPrev = pDi->link.pPrev; + pDi->link.pPrev->link.pNext = pDi->link.pNext; + } + return nResult; +} + + +WFSKrnResult DirItrCloseNoUnpin(DirItr *pDi) { + WFSKrnResult nResult = WFSKRN_RESULT_OK; + if (pDi->ppDnsRootParent) { + //MyOSReport("%d: Close(%p)\n", nDirTest, pDi); + DirNodeStackFree(&pDi->dni, pDi->ppDnsRootParent); +//#if _DEBUG + pDi->ppDnsRootParent = 0; +//#endif + pDi->link.pNext->link.pPrev = pDi->link.pPrev; + pDi->link.pPrev->link.pNext = pDi->link.pNext; + } + return nResult; +} + + +WFSKrnResult DirItrPinBlkAndFixPtrs(DirItr *pDi, u32 nTransFlags) { + // Ensure that the block referenced to by the directory iterator is in memory, + // If not, load it into memory and adjust the pDi->pAttrHdr and pDi->dni.pOfs pointers to point to the new location + s32 nPtrAdjustment = -(s32)pDi->pBlkHdr; + DirBlkHdr *pBlkHdr; + WFSKrnReturnOnError(DirGetBlk(pDi, nTransFlags | BCACHE_FLAG_PINNED, &pBlkHdr)); + nPtrAdjustment += (s32)pBlkHdr; + pDi->dni.pOfs = (u16*)((u8*)pDi->dni.pOfs + nPtrAdjustment); + pDi->pAttrHdr = (DirEntryAttrHdr *)((u8*)pDi->pAttrHdr + nPtrAdjustment); + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult DirFindName(WFSFileName *pName, DirItr *pDi) { + WFSKrnCopyFileNameAndConvertToLowerCase(&pDi->name, pName); + pDi->nBlkDepth = 0; + WFSKrnResult nResult = DirFind(&pDi->name, pDi, DIR_MAX_BLK_DEPTH, DIR_FIND_MODE_NORMAL); + switch(nResult) { + case WFSKRN_RESULT_DIR_ENTRY_FOUND: + WFSKrnCopyFileNameAndRestoreCase(pName->sStr, &pDi->name, pDi->pAttrHdr->aCaseBitArray); + pName->nLen = pDi->name.nLen; + return WFSKRN_RESULT_OK; + case WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH: + case WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND: + return WFSKRN_RESULT_NOT_FOUND; + default: + return nResult; + } +} + + +WFSKrnResult DirFindRaw(DirItr *pDi) { + pDi->nBlkDepth = 0; + WFSKrnResult nResult = DirFind(&pDi->name, pDi, DIR_MAX_BLK_DEPTH, DIR_FIND_MODE_NORMAL); + switch(nResult) { + case WFSKRN_RESULT_DIR_ENTRY_FOUND: + return WFSKRN_RESULT_OK; + case WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH: + case WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND: + return WFSKRN_RESULT_NOT_FOUND; + default: + return nResult; + } +} + + +WFSKrnResult DirFindFirstNamePrefixMatch(WFSFileName *pName, DirItr *pDi) { + pDi->nBlkDepth = 0; + WFSKrnCopyFileNameAndConvertToLowerCase(&pDi->name, pName); + WFSKrnResult nResult = DirFind(&pDi->name, pDi, DIR_MAX_BLK_DEPTH, DIR_FIND_MODE_PREFIX_SEARCH); + switch(nResult) { + case WFSKRN_RESULT_DIR_ENTRY_FOUND: + case WFSKRN_RESULT_DIR_NODE_STRING_PREFIX: + case WFSKRN_RESULT_DIR_CHOICE_PREFIX: + WFSKrnCopyFileNameAndRestoreCase(pName->sStr, &pDi->name, pDi->pAttrHdr->aCaseBitArray); + pName->nLen = pDi->name.nLen; + return WFSKRN_RESULT_OK; + case WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH: + case WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND: + return WFSKRN_RESULT_NOT_FOUND; + default: + return nResult; + } +} + + +WFSKrnResult DirNextName(WFSFileName *pName, DirItr *pDi) { + pDi->nBlkDepth = 0; + //WFSKrnCopyFileNameAndConvertToLowerCase(&pDi->name, pName); + WFSKrnResult nResult = DirNextRaw(&pDi->name, pDi); + switch(nResult) { + case WFSKRN_RESULT_OK: + case WFSKRN_RESULT_DIR_ENTRY_FOUND: + WFSKrnCopyFileNameAndRestoreCase(pName->sStr, &pDi->name, pDi->pAttrHdr->aCaseBitArray); + pName->nLen = pDi->name.nLen; + return WFSKRN_RESULT_OK; + default: + return nResult; + } +} + + +WFSKrnResult DirInsertName(WFSFileName *pName, DirItr *pDi, u32 nAllocSize) { + WFSKrnCopyFileNameAndConvertToLowerCase(&pDi->name, pName); + WFSKrnReturnOnError(DirInsertRaw(&pDi->name, pDi, nAllocSize)); + WFSKrnStoreCaseInformation(pDi->pAttrHdr->aCaseBitArray, pName); + // ToDo: Add other file attributes to pDi->pAttrHdr + return WFSKRN_RESULT_OK; +} + + +void DirInitFileEntryAttrHdr(DirEntryAttrHdr *pAttrHdr) { + memset(pAttrHdr, 0, sizeof(DirEntryAttrHdr)); +} + + +void DirInitDirEntryAttrHdr(DirEntryAttrHdr *pAttrHdr) { + memset(pAttrHdr, 0, sizeof(DirEntryAttrHdr)); + pAttrHdr->nAccessListIdx = WFS_FLAG_IS_A_DIRECTORY; +} + + +WFSKrnResult DirDeleteFile(DirItr *pDi) { + DirEntryAttrHdr *pAttrHdr = pDi->pAttrHdr; + TransBlkAdr tba = pDi->tba; + switch(pAttrHdr->nSizeCategory){ + case FILE_SIZE_CATEGORY_VERY_SMALL: + return WFSKRN_RESULT_OK; + case FILE_SIZE_CATEGORY_SMALL:{ + u32 nNumBlks = pAttrHdr->nAllocSize ? ((pAttrHdr->nAllocSize-1) >> tba.pAreaInfo->ah.nLog2BlkSize) + 1 : 0; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategorySmall(pAttrHdr, pAttrHdr->nAttrLog2Size, 0); + return TransFreeBlks6(tba.pAreaInfo, tba.pAreaInfo->ah.nLog2BlkSize, nNumBlks, (WFSBlkAdr*)pFileBlkPtr, -(s32)sizeof(WFSFileBlkPtr), tba.pTransInfo); + } + case FILE_SIZE_CATEGORY_MEDIUM:{ + u32 nNumMediumBlks = pAttrHdr->nAllocSize ? ((pAttrHdr->nAllocSize-1) >> tba.pAreaInfo->ah.nLog2MediumBlkSize) + 1 : 0; + WFSFileBlkPtr *pFileBlkPtr = WFSKrnGetFileBlkPtrForCategoryMedium(pAttrHdr, pAttrHdr->nAttrLog2Size, 0); + return TransFreeBlks6(tba.pAreaInfo, tba.pAreaInfo->ah.nLog2MediumBlkSize, nNumMediumBlks, (WFSBlkAdr*)pFileBlkPtr, -(s32)sizeof(WFSFileBlkPtr), tba.pTransInfo); + } + case FILE_SIZE_CATEGORY_LARGE: { + u32 nNumLargeBlks = pAttrHdr->nAllocSize ? ((pAttrHdr->nAllocSize-1) >> tba.pAreaInfo->ah.nLog2LargeBlkSize) + 1 : 0; + WFSFileLargeBlkPtr *pFileBlkLargePtr = WFSKrnGetFileLargeBlkPtrForCategoryLarge(pAttrHdr, pAttrHdr->nAttrLog2Size, 0); + return TransFreeBlks6(tba.pAreaInfo, tba.pAreaInfo->ah.nLog2LargeBlkSize, nNumLargeBlks, + (WFSBlkAdr*)pFileBlkLargePtr, -(s32)sizeof(WFSFileLargeBlkPtr), tba.pTransInfo); + } + case FILE_SIZE_CATEGORY_VERY_LARGE: { + u32 nNumLargeBlks = pAttrHdr->nAllocSize ? ((pAttrHdr->nAllocSize-1) >> tba.pAreaInfo->ah.nLog2LargeBlkSize) + 1 : 0; + u32 nNumIndirectBlks = (nNumLargeBlks+tba.pAreaInfo->nNumLargeBlkPtrsPerBlk-1)/tba.pAreaInfo->nNumLargeBlkPtrsPerBlk; + WFSBlkAdr *pIndirectBlkAdr = WFSKrnGetBlkAdrPtrFromAttrHdrAndIndirectBlkIdxForCategoryVeryLarge(tba.pAreaInfo, pAttrHdr, pAttrHdr->nAttrLog2Size, 0); + s32 nI; + for(nI=0;nIah.nLog2LargeBlkSize, (nNumLargeBlks-1)%tba.pAreaInfo->nNumLargeBlkPtrsPerBlk+1, + (WFSBlkAdr*)(pIndirectBlkPtr+sizeof(WFSMetaDataHdr)), (s32)sizeof(WFSFileLargeBlkPtr), tba.pTransInfo)); + } else { + WFSKrnReturnOnError(TransFreeBlks6(tba.pAreaInfo, tba.pAreaInfo->ah.nLog2LargeBlkSize, tba.pAreaInfo->nNumLargeBlkPtrsPerBlk, + (WFSBlkAdr*)(pIndirectBlkPtr+sizeof(WFSMetaDataHdr)), (s32)sizeof(WFSFileLargeBlkPtr), tba.pTransInfo)); + } + WFSKrnReturnOnError(TransUnpinBlk3(tba.pAreaInfo, pIndirectBlkAdr[-nI], tba.pTransInfo)); + } + return TransFreeBlks6(tba.pAreaInfo, tba.pAreaInfo->ah.nLog2BlkSize, nNumIndirectBlks, pIndirectBlkAdr, -(s32)sizeof(WFSBlkAdr), tba.pTransInfo); + } + default: + return WFSKRN_RESULT_NOT_IMPLEMENTED; + } +} + + +WFSKrnResult DirDeleteSubDir(DirItr *pDi) { + DirEntryAttrHdr *pAttrHdr = pDi->pAttrHdr; + TransBlkAdr tba = pDi->tba; + tba.nBlkAdr = pAttrHdr->dir.nSubDirBlkAdr; + DirBlkHdr *pSubDirBlkHdr; + + WFSKrnReturnOnError(TransGetAndPinBlk(&tba, TRANS_FLAG_READ_BLK, (void**)&pSubDirBlkHdr)); +/* + nResult = TransGetAndPinBlk(&tba, TRANS_FLAG_READ_BLK, (void**)&pSubDirBlkHdr); + if (nResult < WFSKRN_RESULT_OK){ + return nResult; + } + */ + if (pSubDirBlkHdr->nNumRecs) { + TransUnpinBlk(&tba); + return WFSKRN_RESULT_NOT_EMPTY; + } + WFSKrnReturnOnError(TransUnpinAndFreeBlks(pDi->tba.pAreaInfo, pDi->tba.pAreaInfo->ah.nLog2BlkSize, 1, &tba.nBlkAdr, pDi->tba.pTransInfo)); + return WFSKRN_RESULT_OK; +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirCheck.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirCheck.cpp new file mode 100644 index 0000000..83376cf --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirCheck.cpp @@ -0,0 +1,655 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_DirCheck.cpp + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_DirCheck.cpp,v $ + Revision 1.14 2008/11/18 04:57:12 saito_tomoya + Modified SetBit() and added SetBitArray(). + + Revision 1.13 2008/10/30 04:50:45 kondo_masahiro + Added DirCheckDisk + + Revision 1.12 2008/10/17 08:50:48 kondo_masahiro + Added the new MEDIUM size category (40KB-320KB) + + Revision 1.11 2008/10/16 09:30:39 ooizumi + Fixed definitions for debug build. + + Revision 1.10 2008/09/01 01:57:26 kondo_masahiro + Minor fixed for IOP compiler. + + Revision 1.9 2008/08/27 23:02:55 ooizumi + Fixed newline to CR+LF(Windows format). + + Revision 1.8 2008/08/27 09:47:43 paul + Removed nTotalFree from block header. Added pAttrHdr->nAttrLog2Size + + Revision 1.7 2008/07/09 00:31:36 paul + Minor changes + + Revision 1.6 2008/06/09 17:22:38 paul + Changed comment + + Revision 1.5 2008/05/27 18:44:19 paul + Made utf8 variable definitions more consistent, and use (unsigned) for comparisons + + Revision 1.4 2008/05/14 02:16:52 paul + Fixed the node choice ordering check to prevent utf8 being upgraded to signed int + + Revision 1.3 2008/05/10 03:59:44 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.2 2008/04/25 17:29:46 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.5 2008/04/22 23:26:55 paul + Changed areaHdrRoot to areaInfoRoot + + Revision 1.4 2008/04/19 05:50:57 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.3 2008/04/15 18:51:26 paul + Made some changes to debug code + + Revision 1.2 2008/04/08 00:25:34 paul + Added an extra check for radix tree nodes with 0 entries + + Revision 1.1 2008/04/05 00:03:30 paul + Integrity checks for directory node blocks and directory leaf blocks + + *---------------------------------------------------------------------------*/ + +#undef _KRN_FILE_ +#define _KRN_FILE_ "DirCheck" + +#include "wfskrn_Dir.h" +#include "wfskrn_SubBlkAlloc.h" +#include "wfskrn_DirNodeStack.h" +#include "wfskrn_Area.h" +#include "wfskrn_BitField.h" +#include "wfskrn_Heap.h" +#include "wfskrn_Api.h" +#include "wfskrn_Mutex.h" + +#if _DEBUG_DIR +bool bCheckDirBlks = true; // extern +#endif + +static +void DirSubBlkDebugPrint(DirSubBlkHdr *pSubBlkHdr) { + utf8 *pChoiceChar = &pSubBlkHdr->aFirstChar[pSubBlkHdr->nStrLen]; + utf8 cTemp = *pChoiceChar; + *pChoiceChar = 0; + MyOSReport("%d,%d,\"%s\"", pSubBlkHdr->nStrLen, pSubBlkHdr->nNumEntries, pSubBlkHdr->aFirstChar); + *pChoiceChar = cTemp; + u32 nI; + for(nI=0; nInNumEntries; nI++) { + if ((*pChoiceChar<32)||(*pChoiceChar>127)) { + MyOSReport(",%d", *pChoiceChar); + } else { + MyOSReport(",'%c'", *pChoiceChar); + } + ++pChoiceChar; + } + MyOSReport("\n"); +} + +void DirLeafCheckBlk(DirItr *pDi) { +#if _DEBUG_DIR + // Checks that all allocated sub blocks of pDi->pBlkHdr are reachable, and all non-allocated blocks are on the free list + if (!bCheckDirBlks) { + return; + } +#endif +#if _DEBUG_DIR_NODE_STACK + bool bOldCheckDirNodeStack = bCheckDirNodeStack; + bCheckDirNodeStack = false; +#endif + DirItr di = *pDi; + + di.dni.nDnsDepth = 0; + WFSKrnResult nResult = DirNodeStackGetEntry(&di.dni); + di.ppDnsRootParent = &di.dni.pDns->pParent; + + DirBlkHdr *pBlkHdr = (DirBlkHdr *)di.pBlkHdr; + u32 nSrcNodeOfs = pBlkHdr->nRootOfs; + utf8 *pChoiceChar; + u32 nConnectedSize=(1<nMagic == SBA_FREE_SUB_BLK_MAGIC) { + WFSKrnOutputErrorStr("Pointer to deleted sub block detected!"); + } + di.dni.nLog2Size = DirLeafGetSubBlkLog2Size(di.dni.pSubBlkHdr); + di.dni.pDns->nBlkAdr = di.tba.nBlkAdr; + di.dni.pDns->nSubBlkOfs = nSrcNodeOfs; +#if _DEBUG_DIR + if ((nDirTest>=nDirTestBreakPoint-1)&&(nDirTest<=nDirTestBreakPoint)) { + u32 nI; + for(nI=nSrcLeafStartDepth; nI>SBA_MIN_LOG2_SUB_BLK_SIZE, 1<<(di.dni.nLog2Size-SBA_MIN_LOG2_SUB_BLK_SIZE))) { + WFSKrnOutputErrorStr("Overlap!"); + } + nConnectedSize += (u32)(1<nEntryIdx = 1; + if (di.dni.pSubBlkHdr->nNumEntries == 0) { + if (pBlkHdr->nNumRecs) { + WFSKrnOutputErrorStr("No entries!"); + } + } + pChoiceChar = &di.dni.pSubBlkHdr->aFirstChar[di.dni.pSubBlkHdr->nStrLen]; + if (*pChoiceChar == 0) { + // String terminator char indicates this is a record, so increment the record count + u32 nAttrOfs = pSrcNodeOfsTblEnd[-1]; + SbaCheckOfs(nAttrOfs); + DirEntryAttrHdr *pAttrHdr = (DirEntryAttrHdr *)((u8*)pBlkHdr + nAttrOfs); + WFSSubBlkFreeHdr *pSbfHdr = (WFSSubBlkFreeHdr *)pAttrHdr; + if (pSbfHdr->nMagic == SBA_FREE_SUB_BLK_MAGIC) { + WFSKrnOutputErrorStr("Pointer to deleted attr block detected!"); + } + u8 nSizeCategory; + u16 nAttrLog2Size = (u16)DirCalculateAttrSubBlkLog2Size(di.tba.pAreaInfo, pAttrHdr->nAllocSize, pAttrHdr->nNameLen, &nSizeCategory); + if (nSizeCategory != pAttrHdr->nSizeCategory) { + nAttrLog2Size = (u16)DirCalculateAttrSubBlkLog2SizeDecrease(di.tba.pAreaInfo, pAttrHdr->nAllocSize, pAttrHdr->nNameLen, &nSizeCategory); + if (nSizeCategory != pAttrHdr->nSizeCategory) { + WFSKrnOutputErrorStr("Size category incorrect"); + } + } + if (WfsTestAndSetBitField((unsigned*)aUtilization, nAttrOfs>>SBA_MIN_LOG2_SUB_BLK_SIZE, 1<<(nAttrLog2Size-SBA_MIN_LOG2_SUB_BLK_SIZE))) { + WFSKrnOutputErrorStr("Overlap!"); + } + if (nAttrLog2Size != pAttrHdr->nAttrLog2Size) { + WFSKrnOutputErrorStr("Attr log 2 size incorrect"); + } + if (nSizeCategory != pAttrHdr->nSizeCategory) { + WFSKrnOutputErrorStr("Size category incorrect"); + } + nConnectedSize += (u32)(1<nEntryIdx; + } else if (di.dni.pSubBlkHdr->nNumEntries == 1) { + WFSKrnOutputErrorStr("Non-terminating single-choice node!"); + } + if (di.dni.pDns->nEntryIdx > di.dni.pSubBlkHdr->nNumEntries) { + do { + if (di.dni.nDnsDepth == nSrcLeafStartDepth) { + // We reached the top of the stack, so this should be the last record + goto CheckFreeSpace; + } + DirPopNodeStackEntry(&di.dni); + di.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + di.dni.pDns->nSubBlkOfs); + ++di.dni.pDns->nEntryIdx; + } while(di.dni.pDns->nEntryIdx > di.dni.pSubBlkHdr->nNumEntries); + pChoiceChar = &di.dni.pSubBlkHdr->aFirstChar[di.dni.pSubBlkHdr->nStrLen + di.dni.pDns->nEntryIdx-1]; + if ((unsigned)pChoiceChar[-1] >= (unsigned)*pChoiceChar) { + WFSKrnOutputErrorStr("Choice out of order!"); + } + } + + nSrcNodeOfs = DirLeafGetIntraBlkOfs(di.dni.pDns->nEntryIdx, di.dni.pSubBlkHdr); + SbaCheckOfs(nSrcNodeOfs); + nResult = DirNodeStackGetEntry(&di.dni); + if (nResult != WFSKRN_RESULT_OK) { + WFSKrnOutputErrorCode(nResult); + break; + } + } +CheckFreeSpace:; + // Next check the free space + u32 nTotalFree = SbaCheckFreeSpace((WFSSubBlkAllocHdr *)pBlkHdr, aUtilization); + if ((nTotalFree + nConnectedSize) != pDi->tba.pAreaInfo->nBlkSize) { + WFSKrnOutputErrorStr("Memory Leak detected within block!"); + } + if (nRecIdx != pBlkHdr->nNumRecs) { + WFSKrnOutputErrorStr("NumRecs Error!"); + } + DirNodeStackFree(&di.dni, di.ppDnsRootParent); +#if _DEBUG_DIR + if ((nDirTest>=nDirTestBreakPoint-1)&&(nDirTest<=nDirTestBreakPoint)) { + MyOSReport("\n"); + } +#endif +#if _DEBUG_DIR_NODE_STACK + bCheckDirNodeStack = bOldCheckDirNodeStack; +#endif +} + +void DirNodeCheckBlk(DirItr *pDi) { +#if _DEBUG_DIR + // Checks that all allocated sub blocks of pDi->pBlkHdr are reachable, and all non-allocated blocks are on the free list + if (!bCheckDirBlks) { + return; + } +#endif +#if _DEBUG_DIR_NODE_STACK + bool bOldCheckDirNodeStack = bCheckDirNodeStack; + bCheckDirNodeStack = false; +#endif + + DirItr di = *pDi; + DirBlkHdr *pBlkHdr = (DirBlkHdr *)di.pBlkHdr; + u32 nSrcNodeOfs = pBlkHdr->nRootOfs; + utf8 *pChoiceChar; + u32 nConnectedSize=(1<nMagic == SBA_FREE_SUB_BLK_MAGIC) { + WFSKrnOutputErrorStr("Pointer to deleted sub block detected!"); + } + di.dni.nLog2Size = DirNodeGetSubBlkLog2Size(di.dni.pSubBlkHdr); + di.dni.pDns->nBlkAdr = di.tba.nBlkAdr; + di.dni.pDns->nSubBlkOfs = nSrcNodeOfs; +#if _DEBUG_DIR + if ((nDirTest>=nDirTestBreakPoint-1)&&(nDirTest<=nDirTestBreakPoint)) { + u32 nI; + for(nI=nSrcNodeStartDepth; nI>SBA_MIN_LOG2_SUB_BLK_SIZE, 1<<(di.dni.nLog2Size-SBA_MIN_LOG2_SUB_BLK_SIZE))) { + WFSKrnOutputErrorStr("Overlap!"); + } + nConnectedSize += (u32)(1<nEntryIdx = 1; + if (di.dni.pSubBlkHdr->nNumEntries == 0) { + if (pBlkHdr->nNumRecs) { + WFSKrnOutputErrorStr("No entries!"); + } + } + pChoiceChar = &di.dni.pSubBlkHdr->aFirstChar[di.dni.pSubBlkHdr->nStrLen]; + if (*pChoiceChar == 0) { + // String terminator char indicates this is a record, so increment the record count + ++nRecIdx; + ++di.dni.pDns->nEntryIdx; + } else if (di.dni.pSubBlkHdr->nNumEntries == 1) { + WFSKrnOutputErrorStr("Non-terminating single-choice node!"); + } + if (di.dni.pDns->nEntryIdx > di.dni.pSubBlkHdr->nNumEntries) { + do { + if (di.dni.nDnsDepth == nSrcNodeStartDepth) { + // We reached the top of the stack, so this should be the last record + goto CheckFreeSpace; + } + DirPopNodeStackEntry(&di.dni); + di.dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + di.dni.pDns->nSubBlkOfs); + ++di.dni.pDns->nEntryIdx; + } while(di.dni.pDns->nEntryIdx > di.dni.pSubBlkHdr->nNumEntries); + pChoiceChar = &di.dni.pSubBlkHdr->aFirstChar[di.dni.pSubBlkHdr->nStrLen + di.dni.pDns->nEntryIdx -1]; + if ((unsigned)pChoiceChar[-1] >= (unsigned)*pChoiceChar) { + WFSKrnOutputErrorStr("Choice out of order!"); + } + } + nSrcNodeOfs = DirNodeGetIntraBlkOfs(di.dni.pDns->nEntryIdx, di.dni.pSubBlkHdr); + SbaCheckOfs(nSrcNodeOfs); + nResult = DirNodeStackGetEntry(&di.dni); + if (nResult != WFSKRN_RESULT_OK) { + WFSKrnOutputErrorCode(nResult); + break; + } + } +CheckFreeSpace:; + // Next check the free space + u32 nTotalFree = SbaCheckFreeSpace((WFSSubBlkAllocHdr *)pBlkHdr, aUtilization); + if ((nTotalFree + nConnectedSize) != pDi->tba.pAreaInfo->nBlkSize) { + WFSKrnOutputErrorStr("Memory Leak detected within block!"); + } + if (nRecIdx != pBlkHdr->nNumRecs) { + WFSKrnOutputErrorStr("NumRecs Error!"); + } +#if _DEBUG_DIR + if ((nDirTest>=nDirTestBreakPoint-1)&&(nDirTest<=nDirTestBreakPoint)) { + MyOSReport("\n"); + } +#endif +#if _DEBUG_DIR_NODE_STACK + bCheckDirNodeStack = bOldCheckDirNodeStack; +#endif +} + +void DirCheckBlk(DirItr *pDi) { +#if _DEBUG_DIR + // Checks that all allocated blocks are reachable, and all non-allocated blocks are on the free list + if (!bCheckDirBlks) { + return; + } +#endif + if (pDi->pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK) { + DirLeafCheckBlk(pDi); + } else { + DirNodeCheckBlk(pDi); + } +} + + +static void SetBit(WFSSrvFileHandle fh, u32 diskAddr) +{ + u32 byte = diskAddr / 8; + u32 bit = diskAddr % 8; + u8 flag = (1 << bit); + + u8 dst; + + WFSResult nResult; + nResult = (WFSResult)WFSSrvReadFile(fh, &dst, byte, 1); + if(nResult < WFS_RESULT_OK){ + osTPrintf("SetBit() error %d\n", nResult); + } + + ASSERT(0 == (dst & flag)); + dst |= flag; + nResult = WFSSrvWriteFile(fh, &dst, byte, 1, true); + +} + +static void SetBitArrayInternal(WFSSrvFileHandle fh, u8* pBuffer, u32 bufferSize, u32 diskAddr, u32 length){ + + u32 byte = diskAddr / 8; + u32 bit = diskAddr % 8; + u32 byteLength = (diskAddr + length - 1) / 8 - byte + 1; + + WFSResult nResult; + + // read + nResult = (WFSResult)WFSSrvReadFile(fh, pBuffer, byte, byteLength); + if(nResult < WFS_RESULT_OK){ + osTPrintf("SetBitArray() error %d\n", nResult); + } + + // set bits + int i; + for(i=bit; i (bufferSize-1)*8){ + SetBitArrayInternal(fh, pBuffer, bufferSize, diskAddr, (bufferSize-1)*8); + length -= (bufferSize-1)*8; + diskAddr += (bufferSize-1)*8; + } + SetBitArrayInternal(fh, pBuffer, bufferSize, diskAddr, length); +} + + +WFSKrnResult DirCheckDisk(WFSBlkAdr rootBlkAdr, DirItr *pDi, WFSSrvFileHandle fh, u8* pBuffer, u32 bufferSize, u32 nFlag) { + + DirBlkHdr *pBlkHdr; + pDi->tba.nBlkAdr = rootBlkAdr; + + /// + //pCheckDiskArray[rootBlkAdr/8] |= 1<<(rootBlkAdr%8); + SetBit(fh, rootBlkAdr); + + pDi->nBlkDepth = 0; + WFSKrnReturnOnError(DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, &pBlkHdr)); + + pDi->dni.nDnsDepth = 0; + WFSKrnReturnOnError(DirNodeStackGetEntry(&pDi->dni)); + pDi->ppDnsRootParent = &pDi->dni.pDns->pParent; + + pDi->dni.pDns->nBlkAdr = 0; //tba.nBlkAdr; + pDi->dni.pDns->nSubBlkOfs = pBlkHdr->nRootOfs; + SbaCheckOfs(pDi->dni.pDns->nSubBlkOfs); + pDi->dni.pDns->nEntryIdx = 1; + + pDi->dni.nEntryIdx = 1; + pDi->dni.pOfs = &pBlkHdr->nRootOfs; + SbaCheckOfs(*pDi->dni.pOfs); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + if (pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK) { + pDi->dni.nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } else { + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } + + while(1){ +#if _DEBUG_BREAK_POINT + static int c=0; c++; if(c==0x2b){ + int a; a=0; + } +#endif + while (pDi->dni.nEntryIdx > pDi->dni.pSubBlkHdr->nNumEntries) { + if(pDi->dni.pDns->nBlkAdr == 0){ + TransUnpinBlk(&pDi->tba); + DirPopNodeStackEntry(&pDi->dni); + pDi->nBlkDepth = 0; + return WFSKRN_RESULT_OK; + } + if(pDi->tba.nBlkAdr != pDi->dni.pDns->nBlkAdr){ + TransUnpinBlk(&pDi->tba); + pDi->tba.nBlkAdr = pDi->dni.pDns->nBlkAdr; + WFSKrnReturnOnError( DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, &pBlkHdr) ); + } + pDi->dni.nEntryIdx = ++pDi->dni.pDns->nEntryIdx; + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + pDi->dni.pDns->nSubBlkOfs); + if (pDi->dni.nEntryIdx <= pDi->dni.pSubBlkHdr->nNumEntries){ + if (pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK) { + pDi->dni.nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + pDi->dni.pOfs = DirLeafGetIntraBlkOfsPtr_l2s((s32)pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } else { + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + pDi->dni.pOfs = DirNodeGetIntraBlkOfsPtr_l2s((s32)pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } + pDi->dni.nEntryIdx = 1; + } else { + DirPopNodeStackEntry(&pDi->dni); + --pDi->nBlkDepth; + } + } + WFSKrnReturnOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + ++pDi->nBlkDepth; + pDi->dni.pDns->nUpdateCtr = pDi->nUpdateCtr; + + if (pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK) { + if(pDi->dni.nEntryIdx == 1 && pDi->dni.pSubBlkHdr->aFirstChar[pDi->dni.pSubBlkHdr->nStrLen] == 0){ + u16 nOfs = *DirLeafGetIntraBlkOfsPtr_l2s(1, pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size); + pDi->pAttrHdr = (DirEntryAttrHdr *)((u8*)pBlkHdr + nOfs); + if (pDi->pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) { + TransUnpinBlk(&pDi->tba); + pDi->tba.nBlkAdr = pDi->pAttrHdr->dir.nSubDirBlkAdr; + + /// + //pCheckDiskArray[pDi->tba.nBlkAdr/8] |= 1<<(pDi->tba.nBlkAdr%8); + SetBit(fh, pDi->tba.nBlkAdr); + + WFSKrnReturnOnError( DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, &pBlkHdr) ); + pDi->dni.pOfs = &pBlkHdr->nRootOfs; + SbaCheckOfs(*pDi->dni.pOfs); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + if (pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK) { + pDi->dni.nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } else { + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } + pDi->dni.nEntryIdx = 1; + } else { + if(nFlag == DIR_CHECK_DISK_FOR_DIR_TREE){ + switch(pDi->pAttrHdr->nSizeCategory){ + case FILE_SIZE_CATEGORY_SMALL:{ + u32 nI, nNumSmallBlks = pDi->pAttrHdr->nAllocSize>>pDi->tba.pAreaInfo->ah.nLog2BlkSize; + for(nI=0;nIpAttrHdr, pDi->pAttrHdr->nAttrLog2Size, nI); + //if(pCheckDiskArray[pFileBlkPtr->nBlkAdr/8]&(1<<(pFileBlkPtr->nBlkAdr%8))){ + // int a; a=0; + //} + + /// + //pCheckDiskArray[pFileBlkPtr->nBlkAdr/8] |= 1<<(pFileBlkPtr->nBlkAdr%8); + SetBit(fh, pFileBlkPtr->nBlkAdr); + + } + break; + } + case FILE_SIZE_CATEGORY_MEDIUM:{ + u32 nI, nNumMediumBlks = pDi->pAttrHdr->nAllocSize>>pDi->tba.pAreaInfo->ah.nLog2MediumBlkSize; + for(nI=0;nIpAttrHdr, pDi->pAttrHdr->nAttrLog2Size, nI); + //u8 flag = 0xff<<(pFileBlkPtr->nBlkAdr%8); + + /// + SetBitArray(fh, pBuffer, bufferSize, pFileBlkPtr->nBlkAdr, 8); // array! + /* + pCheckDiskArray[pFileBlkPtr->nBlkAdr/8] |= flag; + + if(~flag){ + + /// + pCheckDiskArray[pFileBlkPtr->nBlkAdr/8+1] |= ~flag; + } + */ + } + break; + } + case FILE_SIZE_CATEGORY_LARGE:{ + u32 nI, nJ, nNumLargeBlks = pDi->pAttrHdr->nAllocSize>>pDi->tba.pAreaInfo->ah.nLog2LargeBlkSize; + for(nJ=0;nJpAttrHdr, pDi->pAttrHdr->nAttrLog2Size, nJ); + for(nI=0;nI<(1<tba.pAreaInfo->nLog2MediumBlkPerLargeBlk);nI++){ + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge(pDi->tba.pAreaInfo, pFileLargeBlkPtr, nI); + //u8 flag = 0xff<<(fileBlkInfo.nBlkAdr%8); + + SetBitArray(fh, pBuffer, bufferSize, fileBlkInfo.nBlkAdr, 8); // array! + /* + /// + pCheckDiskArray[fileBlkInfo.nBlkAdr/8] |= flag; + if(~flag){ + + /// + pCheckDiskArray[fileBlkInfo.nBlkAdr/8+1] |= ~flag; + }*/ + } + } + break; + } + case FILE_SIZE_CATEGORY_VERY_LARGE: { + WFSBlkAdr nBlkAdr = pDi->tba.nBlkAdr; + u32 nI, nJ, nK; + u32 nNumLargeBlks = pDi->pAttrHdr->nAllocSize>>pDi->tba.pAreaInfo->ah.nLog2LargeBlkSize; + u32 nNumIndirectBlks = (nNumLargeBlks-1)/pDi->tba.pAreaInfo->nNumLargeBlkPtrsPerBlk+1; + for(nK=0;nKtba.pAreaInfo, pDi->pAttrHdr, pDi->pAttrHdr->nAttrLog2Size, nK); + + /// + //pCheckDiskArray[*pBlkAdr/8] |= 1<<(*pBlkAdr%8); + SetBit(fh, *pBlkAdr); + pDi->tba.nBlkAdr = *pBlkAdr; + WFSKrnReturnOnError( DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, (DirBlkHdr**)&pIndirectPtr) ); + for(nJ=0;nJtba.pAreaInfo->nNumLargeBlkPtrsPerBlk;nJ++){ + WFSFileLargeBlkPtr *pFileLargeBlkPtr = WFSKrnGetFileLargeBlkPtrFromIndirectBlkForCategoryVeryLarge(pIndirectPtr, nJ); + for(nI=0;nI<(1<tba.pAreaInfo->nLog2MediumBlkPerLargeBlk);nI++){ + WFSFileBlkInfo fileBlkInfo = WFSKrnGetFileBlkInfoForCategoryLarge(pDi->tba.pAreaInfo, pFileLargeBlkPtr, nI); + //u8 nFlag = 0xff<<(fileBlkInfo.nBlkAdr%8); + + SetBitArray(fh, pBuffer, bufferSize, fileBlkInfo.nBlkAdr, 8); // array! + + /* + /// + pCheckDiskArray[fileBlkInfo.nBlkAdr/8] |= nFlag; + nFlag = ~nFlag; + if(nFlag){ + + /// + pCheckDiskArray[fileBlkInfo.nBlkAdr/8+1] |= nFlag; + } + */ + } + if(--nNumLargeBlks == 0){ + break; + } + } + TransUnpinBlk(&pDi->tba); + } + pDi->tba.nBlkAdr = nBlkAdr; + break; + } + } + } + DirPopNodeStackEntry(&pDi->dni); + pDi->dni.nEntryIdx = 2; + } + } + else{ + pDi->dni.pOfs = DirLeafGetIntraBlkOfsPtr_l2s((s32)pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size); + SbaCheckOfs(*pDi->dni.pOfs); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + pDi->dni.nEntryIdx = 1; + } + } else { + if (pDi->dni.nEntryIdx == 1 && pDi->dni.pSubBlkHdr->aFirstChar[pDi->dni.pSubBlkHdr->nStrLen] == 0){ + u32 nNewBlkAdr = DirNodeGetBlkAdr_l2s(pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size); + + /// + //pCheckDiskArray[nNewBlkAdr/8] |= 1<<(nNewBlkAdr%8); + SetBit(fh, nNewBlkAdr); + + TransUnpinBlk(&pDi->tba); + pDi->tba.nBlkAdr = nNewBlkAdr; + WFSKrnReturnOnError( DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, &pBlkHdr) ); + pDi->dni.pOfs = &pBlkHdr->nRootOfs; + SbaCheckOfs(*pDi->dni.pOfs); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + if (pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK) { + pDi->dni.nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } else { + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } + } else { + pDi->dni.pOfs = DirNodeGetIntraBlkOfsPtr_l2s((s32)pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size); + SbaCheckOfs(*pDi->dni.pOfs); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } + pDi->dni.nEntryIdx = 1; + } + } +} + diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirFind.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirFind.cpp new file mode 100644 index 0000000..956bcc7 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirFind.cpp @@ -0,0 +1,774 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_DirFind.cpp - Functions for finding + + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_DirFind.cpp,v $ + Revision 1.15 2008/10/30 04:49:31 kondo_masahiro + Deleted the function of DirItrCheckList + + Revision 1.14 2008/10/14 10:27:14 kondo_masahiro + Added #define _DEBUG_BREAK_POINT + + Revision 1.13 2008/09/28 23:32:04 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.12 2008/08/27 09:46:48 paul + Added pAttrHdr->nAttrLog2Size + + Revision 1.11 2008/08/05 03:58:43 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.10 2008/07/28 22:17:10 paul + Improved updateMap processing. + + Revision 1.9 2008/07/25 02:51:28 paul + Changed from nTransIdx to *pTransInfo + + Revision 1.8 2008/07/09 00:37:03 paul + Changes to make directory code work with block cache. + + Revision 1.7 2008/06/09 17:25:31 paul + Fixed a bug in DirFindNext() + + Revision 1.6 2008/05/27 18:44:44 paul + Made utf8 variable definitions more consistent, and use (unsigned) for comparisons + + Revision 1.5 2008/05/17 03:54:59 paul + Fixed a bug in DirFindNext + + Revision 1.4 2008/05/16 18:42:15 paul + Added DirFindNext to allow WFSSrvSearchDirectoryNext to work while adding/deleting files in the directory + + Revision 1.3 2008/05/12 19:13:34 paul + Removed dni local variable from DirFind. + Made DirFind add pDi to a list of open iterators. + + Revision 1.2 2008/05/10 03:59:44 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.1 2008/04/25 17:29:11 kondo_masahiro + Initial check-in + + Revision 1.2 2008/04/22 23:28:12 paul + WfsArea* -> Area* + + Revision 1.1 2008/04/21 18:58:31 paul + *** empty log message *** + +*---------------------------------------------------------------------------*/ + +#undef _KRN_FILE_ +#define _KRN_FILE_ "DirFind" + +#include "wfskrn_SubBlkAlloc.h" + +#include "wfskrn_Dir.h" +#include "wfskrn_DirFind.h" +#include "wfskrn_DirNodeStack.h" +#include "wfskrn_DirRxTree.h" + +#undef dbg +#if _DEBUG_DIR + #define dbg(s) s +#else + #define dbg(s) +#endif + + +WFSKrnResult DirFind(WFSFileName *pName, DirItr *pDi, u32 nMaxBlkDepth, u32 nMode) { + // This function searches for a particular named entry in a directory up to a given max depth. + // If the name is found, its location within the appropriate leaf block is returned in pDi, and the function returns WFSKRN_RESULT_DIR_ENTRY_FOUND. + // If the name is not found, the location where it should be inserted within the appropriate leaf block, is returned in pDi, and the function returns .... + // In addition, if the input name is a prefix of one or more entries in the directory, then the characters beyond the end of the input string + // will be filled with the characters of the first matching entry from the directory. This can be used to help implement pattern searches, + // or just to get the first entry in a directory (by searching for ""). +#if _DEBUG_BREAK_POINT + static int c=0;++c;if(c>=6979){ + int a;a=0; + } + if (nDbgCommandCount==2850){ + int a;a=0; + } +#endif +#if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } +#endif + DirBlkHdr *pBlkHdr; + WFSKrnReturnOnError(DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, &pBlkHdr)); + DirNodeItr dniTemp; + utf8 *pStrEnd = pName->sStr + pName->nLen; + u32 nStrIdx, nPrefixStrIdx; + utf8 *pChoiceStrPtr = pName->sStr; // To keep track of how many characters are common between adjacent splitters when we move to a child block, so that it can implement prefix suppression. + utf8 cSubBlkChar, cSearchChar=pChoiceStrPtr[0]; + u16 *pOfsTblEnd; + u32 nSubBlkStrLen; + WFSKrnResult nResult = WFSKRN_RESULT_OK; + +#if _DEBUG + if ((pDi->dni.nDnsDepth == 0) && (pDi->ppDnsRootParent != 0)) { + WFSKrnOutputErrorStr("Directory Iterator already opened"); + } + // Check pDi is not already on the open iterator list + DirItr *pListDi = dirGlobals.openDirItrListAnchor.pNext; + while(pListDi != dirGlobals.pOpenDirItrListAnchor) { + if (pListDi == pDi) { + WFSKrnOutputErrorStr("pDi already on open iterator list"); + } + if (pListDi->link.pNext->link.pPrev != pListDi) { + WFSKrnOutputErrorStr("pDi link error"); + } + pListDi = pListDi->link.pNext; + } +#endif + //MyOSReport("%d: Open(%p)\n", nDirTest, pDi); + pDi->link.pNext = dirGlobals.openDirItrListAnchor.pNext; + pDi->link.pPrev = dirGlobals.pOpenDirItrListAnchor; + dirGlobals.openDirItrListAnchor.pNext->link.pPrev = pDi; + dirGlobals.openDirItrListAnchor.pNext = pDi; + + pDi->dni.nDnsDepth = 0; + WFSKrnReturnOnError(DirNodeStackGetEntry(&pDi->dni)); + pDi->ppDnsRootParent = &pDi->dni.pDns->pParent; + + pDi->dni.pDns->nBlkAdr = 0; //tba.nBlkAdr; + pDi->dni.pDns->nSubBlkOfs = pBlkHdr->nRootOfs; + dbg(SbaCheckOfs(pDi->dni.pDns->nSubBlkOfs)); + pDi->dni.pDns->nEntryIdx = 1; + nPrefixStrIdx=0; + + while(1) { + nStrIdx = nPrefixStrIdx-1; +#if DIR_PREFIX_SUPPRESSION + pDi->dni.pStrPtr = pChoiceStrPtr; // This should skip any common prefix shared by all file name key fields or splitters in the block +#else + pDi->dni.pStrPtr = pName->sStr; +#endif + pDi->dni.pOfs = &pBlkHdr->nRootOfs; + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + if ((pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK) || (pDi->nBlkDepth >= nMaxBlkDepth)) { + break; + } + ++pDi->nBlkDepth; + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + while(1) { + nSubBlkStrLen = pDi->dni.pSubBlkHdr->nStrLen; + nStrIdx += nSubBlkStrLen + 1; + pDi->dni.pNodeStrPtr = pDi->dni.pSubBlkHdr->aFirstChar; + if ((pStrEnd - pDi->dni.pStrPtr) < nSubBlkStrLen) { + do { + cSearchChar = *pDi->dni.pStrPtr++; + cSubBlkChar = *pDi->dni.pNodeStrPtr++; + } while(cSearchChar == cSubBlkChar); + if ((unsigned)cSearchChar < (unsigned)cSubBlkChar) { + goto BackTrack; + } + goto ChooseMaxDescendent; + } + while(nSubBlkStrLen--) { + cSearchChar = *pDi->dni.pStrPtr++; + cSubBlkChar = *pDi->dni.pNodeStrPtr++; + if (cSearchChar != cSubBlkChar) { + if ((unsigned)cSearchChar < (unsigned)cSubBlkChar) { + goto BackTrack; + } + goto ChooseMaxDescendent; + } + } + // matched all the characters from the prefix. pDi->dni.pNodeStrPtr should now be pointing to the array of choices following the prefix. + cSearchChar = *pDi->dni.pStrPtr; + pOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + + WFSBool bFound = DirBinarySplitSearchChoices(pDi->dni.pNodeStrPtr, pDi->dni.pSubBlkHdr->nNumEntries, cSearchChar, &pDi->dni.nEntryIdx); +#if DIR_PREFIX_SUPPRESSION + if ((pDi->dni.nEntryIdx>=1) && (pDi->dni.nEntryIdx < pDi->dni.pSubBlkHdr->nNumEntries)) { + // ToDo: Implement prefix suppression + nPrefixStrIdx = nStrIdx; + } +#endif + WFSKrnExitOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + pDi->dni.pDns->nUpdateCtr = pDi->nUpdateCtr; + if (bFound) { + // Found the search character. + pDi->dni.pDns->nStrIdx = (u8)nStrIdx; + if (cSearchChar==0) { + // We matched a 0 .. means the file name matched one of the splitters exactly + // This may still be a valid file name. + // Note: A splitter can be arbitrary. It does not even have to be a prefix of an existing file name. + // (This can happen after deleting the filename which was originally chosen as a split point). + break; + } + if (pDi->dni.pSubBlkHdr->nNumEntries>1) { + if (pDi->dni.nEntryIdx>1) { + // Update the previous record information + dniTemp = pDi->dni; + --dniTemp.nEntryIdx; + } + pChoiceStrPtr = pDi->dni.pStrPtr; + } + pDi->dni.pOfs = DirNodeGetIntraBlkOfsPtr_ote((s32)pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pOfsTblEnd); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + ++pDi->dni.pStrPtr; + continue; + } + + if (pDi->dni.nEntryIdx==0) { + // The binary split search determined that the search character was smaller than the smallest choice +BackTrack: + while(pDi->dni.pDns != dniTemp.pDns) { + DirPopNodeStackEntry(&pDi->dni); + }; + pDi->dni = dniTemp; + pDi->dni.pDns->nEntryIdx = pDi->dni.nEntryIdx; + nStrIdx = (u32)(pDi->dni.pDns->nStrIdx);// + pDi->dni.pSubBlkHdr->nStrLen + 1); + pChoiceStrPtr = pDi->dni.pStrPtr; + pOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + pDi->dni.pNodeStrPtr = &pDi->dni.pSubBlkHdr->aFirstChar[pDi->dni.pSubBlkHdr->nStrLen]; + } + pDi->dni.pDns->nStrIdx = (u8)nStrIdx; + if ((pDi->dni.nEntryIdx==1)&&(pDi->dni.pNodeStrPtr[0]==0)) { + break; + } + // Offset is an intra block offset + pDi->dni.pOfs = DirNodeGetIntraBlkOfsPtr_ote((s32)pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pOfsTblEnd); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + nStrIdx += pDi->dni.pSubBlkHdr->nStrLen + 1; + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); +ChooseMaxDescendent: + // Follow intra block offsets until max splitter end is encountered + if (pDi->dni.pSubBlkHdr->nNumEntries > 1) { + while(1) { + pDi->dni.nEntryIdx = pDi->dni.pSubBlkHdr->nNumEntries; + WFSKrnExitOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + pDi->dni.pDns->nUpdateCtr = pDi->nUpdateCtr; + nStrIdx += pDi->dni.pSubBlkHdr->nStrLen; + pDi->dni.pDns->nStrIdx = (u8)nStrIdx; + if (pDi->dni.pSubBlkHdr->nNumEntries == 1) { + break; + } + ++nStrIdx; + pDi->dni.pOfs = DirNodeGetIntraBlkOfsPtr_l2s(pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + }; + pOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + break; + } + // we should now be at the end of the line + pOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + pDi->dni.nEntryIdx = 1; + WFSKrnExitOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + pDi->dni.pDns->nUpdateCtr = pDi->nUpdateCtr; + pDi->dni.pDns->nStrIdx = nStrIdx; + break; + } + if (nMode == DIR_FIND_MODE_NODE_SEARCH) { + if (pDi->nBlkDepth >= nMaxBlkDepth) { + goto Exit; + } + } + { + u32 nNewBlkAdr = DirNodeGetBlkAdr_ote(pDi->dni.pSubBlkHdr, pOfsTblEnd); + TransUnpinBlk(&pDi->tba); + pDi->tba.nBlkAdr = nNewBlkAdr; + WFSKrnExitOnError( DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, &pBlkHdr) ); + } + } + + +#if (DIR_PREFIX_SUPPRESSION==0) + // ToDo: Prefix suppression not yet implemented + pDi->dni.pStrPtr = pName->sStr; +#endif + + // Search the leaf node + if (pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK) { + pDi->dni.nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } else { + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } + while(1) { + nSubBlkStrLen = pDi->dni.pSubBlkHdr->nStrLen; + nStrIdx += nSubBlkStrLen + 1; + pDi->dni.pNodeStrPtr = pDi->dni.pSubBlkHdr->aFirstChar; + if ((pStrEnd - pDi->dni.pStrPtr) < nSubBlkStrLen) { + while(*pDi->dni.pStrPtr == *pDi->dni.pNodeStrPtr) { + ++pDi->dni.pStrPtr; ++pDi->dni.pNodeStrPtr; + } + nSubBlkStrLen -= (pDi->dni.pNodeStrPtr - pDi->dni.pSubBlkHdr->aFirstChar); + nResult = WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH; + break; + } + while((nSubBlkStrLen) && (*pDi->dni.pStrPtr == *pDi->dni.pNodeStrPtr)) { + ++pDi->dni.pStrPtr; ++pDi->dni.pNodeStrPtr; --nSubBlkStrLen; + } + if (nSubBlkStrLen) { + nResult = WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH; + break; + } + // matched all the characters from the prefix. pDi->dni.pNodeStrPtr should now be pointing to the array of choices following the prefix. + cSearchChar = *pDi->dni.pStrPtr; + if (!DirBinarySplitSearchChoices(pDi->dni.pNodeStrPtr, pDi->dni.pSubBlkHdr->nNumEntries, cSearchChar, &pDi->dni.nEntryIdx)) { + nResult = WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND; + break; + } + WFSKrnExitOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + pDi->dni.pDns->nUpdateCtr = pDi->nUpdateCtr; + pDi->dni.pDns->nStrIdx = nStrIdx; + // Found the search character. + if (cSearchChar==0) { + // We matched a 0 .. which means we have found the filename + nResult = WFSKRN_RESULT_DIR_ENTRY_FOUND; + break; + } + if (pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK) { + pDi->dni.pOfs = DirLeafGetIntraBlkOfsPtr_l2s((s32)pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } else { + pDi->dni.pOfs = DirNodeGetIntraBlkOfsPtr_l2s((s32)pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + } + ++pDi->dni.pStrPtr; + } + + // This is the location passed back to the caller + pDi->pBlkHdr = pBlkHdr; + + if ((*pDi->dni.pStrPtr) || (pBlkHdr->nNumRecs==0) || (!(pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK))) { + goto Done; + } + + if (nResult == WFSKRN_RESULT_DIR_ENTRY_FOUND) { + goto GetAttr; + } + + if (nMode != DIR_FIND_MODE_PREFIX_SEARCH) { + goto Done; + } + + if (nResult == WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH) { + nResult = WFSKRN_RESULT_DIR_NODE_STRING_PREFIX; + } else { + nResult = WFSKRN_RESULT_DIR_CHOICE_PREFIX; + } + + // The exact name was not found, but it was a prefix of one or more exising names. + // We continue traversing to find the left-most descendent. + // This is useful for iterating through the directory, and wildcard pattern search. + pDi->dni.nEntryIdx = 1; + while(1) { + while(nSubBlkStrLen--) { + *pDi->dni.pStrPtr++ = *pDi->dni.pNodeStrPtr++; + } + //if (pDi->dni.pSubBlkHdr->nNumEntries > 1) { + WFSKrnExitOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + pDi->dni.pDns->nUpdateCtr = pDi->nUpdateCtr; + pDi->dni.pDns->nStrIdx = nStrIdx; + //} + cSubBlkChar = pDi->dni.pSubBlkHdr->aFirstChar[pDi->dni.pSubBlkHdr->nStrLen]; + *pDi->dni.pStrPtr++ = cSubBlkChar; + if (cSubBlkChar==0) { + //pDi->dni = pDi->dni; + pName->nLen = nStrIdx; + goto GetAttr; + } + pOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + pDi->dni.pOfs = &pOfsTblEnd[-1]; + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + nSubBlkStrLen = pDi->dni.pSubBlkHdr->nStrLen; + nStrIdx += nSubBlkStrLen + 1; + pDi->dni.pNodeStrPtr = pDi->dni.pSubBlkHdr->aFirstChar; + } + +GetAttr: + pDi->dni.pOfs = DirLeafGetIntraBlkOfsPtr_l2s(1, pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size); + pDi->pAttrHdr = (DirEntryAttrHdr *)((u8*)pDi->pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = pDi->pAttrHdr->nAttrLog2Size; +Done: + return nResult; +Exit: + pDi->pBlkHdr = pBlkHdr; + return nResult; +} + + +WFSKrnResult DirFindNext(WFSFileName *pName, DirItr *pDi) { +#if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } +#endif + DirBlkHdr *pBlkHdr; + WFSKrnReturnOnError( DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, &pBlkHdr) ); + DirNodeItr dniPrev, dniNext; + utf8 *pStrEnd = pName->sStr + pName->nLen; + u32 nStrIdx, nPrefixStrIdx; + utf8 *pChoiceStrPtr = pName->sStr; // To keep track of how many characters are common between adjacent splitters when we move to a child block, so that it can implement prefix suppression. + utf8 cSubBlkChar, cSearchChar=pChoiceStrPtr[0]; + u16 *pOfsTblEnd; + u32 nSubBlkStrLen; + WFSKrnResult nResult = WFSKRN_RESULT_OK; + +#if _DEBUG + if ((pDi->dni.nDnsDepth == 0) && (pDi->ppDnsRootParent != 0)) { + WFSKrnOutputErrorStr("Directory Iterator already opened"); + } + // Check pDi is not already on the open iterator list + DirItr *pListDi = dirGlobals.openDirItrListAnchor.pNext; + while(pListDi != dirGlobals.pOpenDirItrListAnchor) { + if (pListDi == pDi) { + WFSKrnOutputErrorStr("pDi already on open iterator list"); + } + if (pListDi->link.pNext->link.pPrev != pListDi) { + WFSKrnOutputErrorStr("pDi link error"); + } + pListDi = pListDi->link.pNext; + } +#endif + //MyOSReport("%d: Open(%p)\n", nDirTest, pDi); + pDi->link.pNext = dirGlobals.openDirItrListAnchor.pNext; + pDi->link.pPrev = dirGlobals.pOpenDirItrListAnchor; + dirGlobals.openDirItrListAnchor.pNext->link.pPrev = pDi; + dirGlobals.openDirItrListAnchor.pNext = pDi; + + pDi->dni.nDnsDepth = 0; + WFSKrnReturnOnError(DirNodeStackGetEntry(&pDi->dni)); + pDi->ppDnsRootParent = &pDi->dni.pDns->pParent; + + pDi->dni.pDns->nBlkAdr = 0; //tba.nBlkAdr; + pDi->dni.pDns->nSubBlkOfs = pBlkHdr->nRootOfs; + dbg(SbaCheckOfs(pDi->dni.pDns->nSubBlkOfs)); + pDi->dni.pDns->nEntryIdx = 1; + nPrefixStrIdx = 0; + dniNext.nEntryIdx = 0; + + while(1) { + nStrIdx = nPrefixStrIdx-1; +#if DIR_PREFIX_SUPPRESSION + pDi->dni.pStrPtr = pChoiceStrPtr; // This should skip any common prefix shared by all file name key fields or splitters in the block +#else + pDi->dni.pStrPtr = pName->sStr; +#endif + pDi->dni.pOfs = &pBlkHdr->nRootOfs; + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + if (pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK) { + break; + } +#if _DEBUG_DIR + /*if (nDirTest == nDirTestBreakPoint) { + nDirTest = nDirTestBreakPoint; + pDi->pBlkHdr = pBlkHdr; + DirNodeCheckBlk(pDi); + }*/ +#endif + ++pDi->nBlkDepth; + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + while(1) { + nSubBlkStrLen = pDi->dni.pSubBlkHdr->nStrLen; + nStrIdx += nSubBlkStrLen + 1; + pDi->dni.pNodeStrPtr = pDi->dni.pSubBlkHdr->aFirstChar; + if ((pStrEnd - pDi->dni.pStrPtr) < nSubBlkStrLen) { + do { + cSearchChar = *pDi->dni.pStrPtr++; + cSubBlkChar = *pDi->dni.pNodeStrPtr++; + } while(cSearchChar == cSubBlkChar); + if ((unsigned)cSearchChar < (unsigned)cSubBlkChar) { + goto BackTrackNodePrev; + } + goto ChooseMaxDescendent; + } + while(nSubBlkStrLen--) { + cSearchChar = *pDi->dni.pStrPtr++; + cSubBlkChar = *pDi->dni.pNodeStrPtr++; + if (cSearchChar != cSubBlkChar) { + if ((unsigned)cSearchChar < (unsigned)cSubBlkChar) { + goto BackTrackNodePrev; + } + goto ChooseMaxDescendent; + } + } + // matched all the characters from the prefix. pDi->dni.pNodeStrPtr should now be pointing to the array of choices following the prefix. + cSearchChar = *pDi->dni.pStrPtr; + pOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + + WFSBool bFound = DirBinarySplitSearchChoices(pDi->dni.pNodeStrPtr, pDi->dni.pSubBlkHdr->nNumEntries, cSearchChar, &pDi->dni.nEntryIdx); +#if DIR_PREFIX_SUPPRESSION + if ((pDi->dni.nEntryIdx>=1) && (pDi->dni.nEntryIdx < pDi->dni.pSubBlkHdr->nNumEntries)) { + // ToDo: Implement prefix suppression + nPrefixStrIdx = nStrIdx; + } +#endif + WFSKrnExitOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + pDi->dni.pDns->nUpdateCtr = pDi->nUpdateCtr; + if (pDi->dni.nEntryIdx < pDi->dni.pSubBlkHdr->nNumEntries) { + dniNext = pDi->dni; + } + + if (bFound) { + // Found the search character. + pDi->dni.pDns->nStrIdx = (u8)nStrIdx; + if (cSearchChar==0) { + // We matched a 0 .. means the file name matched one of the splitters exactly + // This may still be a valid file name. + // Note: A splitter can be arbitrary. It does not even have to be a prefix of an existing file name. + // (This can happen after deleting the filename which was originally chosen as a split point). + break; + } + if (pDi->dni.pSubBlkHdr->nNumEntries>1) { + if (pDi->dni.nEntryIdx>1) { + // Update the previous record information + dniPrev = pDi->dni; + } + pChoiceStrPtr = pDi->dni.pStrPtr; + } + pDi->dni.pOfs = DirNodeGetIntraBlkOfsPtr_ote((s32)pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pOfsTblEnd); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + ++pDi->dni.pStrPtr; + continue; + } + + if (pDi->dni.nEntryIdx==0) { + // The binary split search determined that the search character was smaller than the smallest choice +BackTrackNodePrev: + while(pDi->dni.pDns != dniPrev.pDns) { + DirPopNodeStackEntry(&pDi->dni); + }; + pDi->dni = dniPrev; + pDi->dni.pDns->nEntryIdx = --pDi->dni.nEntryIdx; + dniNext = pDi->dni; + nStrIdx = (u32)(pDi->dni.pDns->nStrIdx);// + pDi->dni.pSubBlkHdr->nStrLen + 1); + pChoiceStrPtr = pDi->dni.pStrPtr; + pOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + pDi->dni.pNodeStrPtr = &pDi->dni.pSubBlkHdr->aFirstChar[pDi->dni.pSubBlkHdr->nStrLen]; + } + pDi->dni.pDns->nStrIdx = (u8)nStrIdx; + if ((pDi->dni.nEntryIdx==1)&&(pDi->dni.pNodeStrPtr[0]==0)) { + break; + } + // Offset is an intra block offset + pDi->dni.pOfs = DirNodeGetIntraBlkOfsPtr_ote((s32)pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pOfsTblEnd); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + nStrIdx += pDi->dni.pSubBlkHdr->nStrLen + 1; + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); +ChooseMaxDescendent: + // Follow intra block offsets until max splitter end is encountered + if (pDi->dni.pSubBlkHdr->nNumEntries > 1) { + while(1) { + pDi->dni.nEntryIdx = pDi->dni.pSubBlkHdr->nNumEntries; + WFSKrnExitOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + pDi->dni.pDns->nUpdateCtr = pDi->nUpdateCtr; + nStrIdx += pDi->dni.pSubBlkHdr->nStrLen; + pDi->dni.pDns->nStrIdx = (u8)nStrIdx; + if (pDi->dni.pSubBlkHdr->nNumEntries == 1) { + break; + } + ++nStrIdx; + pDi->dni.pOfs = DirNodeGetIntraBlkOfsPtr_l2s(pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = DirNodeGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + }; + pOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + break; + } + // we should now be at the end of the line + pOfsTblEnd = (u16*)((u8*)pDi->dni.pSubBlkHdr + (1<dni.nLog2Size)); + pDi->dni.nEntryIdx = 1; + WFSKrnExitOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + pDi->dni.pDns->nUpdateCtr = pDi->nUpdateCtr; + pDi->dni.pDns->nStrIdx = nStrIdx; + break; + } + { + u32 nNewBlkAdr = DirNodeGetBlkAdr_ote(pDi->dni.pSubBlkHdr, pOfsTblEnd); + TransUnpinBlk(&pDi->tba); + pDi->tba.nBlkAdr = nNewBlkAdr; + WFSKrnExitOnError( DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, &pBlkHdr) ); + } + } + + +#if (DIR_PREFIX_SUPPRESSION==0) + // ToDo: Prefix suppression not yet implemented + pDi->dni.pStrPtr = pName->sStr; +#endif + +#if _DEBUG_DIR + /*if (nDirTest == nDirTestBreakPoint) { + pDi->pBlkHdr = pBlkHdr; + DirLeafCheckBlk(pDi); + }*/ +#endif + + // Search the leaf node + pDi->dni.nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + while(1) { + nSubBlkStrLen = pDi->dni.pSubBlkHdr->nStrLen; + nStrIdx += nSubBlkStrLen + 1; + pDi->dni.pNodeStrPtr = pDi->dni.pSubBlkHdr->aFirstChar; + if ((pStrEnd - pDi->dni.pStrPtr) < nSubBlkStrLen) { + while(*pDi->dni.pStrPtr == *pDi->dni.pNodeStrPtr) { + ++pDi->dni.pStrPtr; ++pDi->dni.pNodeStrPtr; + } + nSubBlkStrLen -= (pDi->dni.pNodeStrPtr - pDi->dni.pSubBlkHdr->aFirstChar); + } else { + while((nSubBlkStrLen) && (*pDi->dni.pStrPtr == *pDi->dni.pNodeStrPtr)) { + ++pDi->dni.pStrPtr; ++pDi->dni.pNodeStrPtr; --nSubBlkStrLen; + } + } + if (nSubBlkStrLen) { + if (*pDi->dni.pStrPtr > *pDi->dni.pNodeStrPtr) { + goto BackTrack; + } + pDi->dni.nEntryIdx = 1; + goto ChooseMinDescendentLeaf; + } + // matched all the characters from the prefix. pDi->dni.pNodeStrPtr should now be pointing to the array of choices following the prefix. + WFSKrnExitOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + pDi->dni.pDns->nUpdateCtr = pDi->nUpdateCtr; + pDi->dni.pDns->nStrIdx = nStrIdx; + cSearchChar = *pDi->dni.pStrPtr; + if (DirBinarySplitSearchChoices(pDi->dni.pNodeStrPtr, pDi->dni.pSubBlkHdr->nNumEntries, cSearchChar, &pDi->dni.nEntryIdx)) { + pDi->dni.pDns->nEntryIdx = pDi->dni.nEntryIdx; + if (pDi->dni.nEntryIdx < pDi->dni.pSubBlkHdr->nNumEntries) { + dniNext = pDi->dni; + } + } else { + //*pDi->dni.pStrPtr++ = pDi->dni.pNodeStrPtr[pDi->dni.nEntryIdx]; + pDi->dni.pNodeStrPtr += pDi->dni.nEntryIdx; + ++pDi->dni.nEntryIdx; + if (pDi->dni.nEntryIdx > pDi->dni.pSubBlkHdr->nNumEntries) { + goto BackTrack; + } + goto ChooseMinDescendentLeaf; + } + // Found the search character. + if (cSearchChar==0) { + // We matched a 0 .. which means we have found the filename + // However an exact match is not what we are looking for. We want the next entry. +BackTrack: + if (dniNext.nEntryIdx == 0) { + nResult = WFSKRN_RESULT_NOT_FOUND; + goto Exit; + } + nResult = WFSKRN_RESULT_DIR_ENTRY_FOUND; + //WFSBlkAdr nLeafBlkAdr = pDi->dni.pDns->nBlkAdr; + while(pDi->dni.pDns != dniNext.pDns) { + DirPopNodeStackEntry(&pDi->dni); + } + pDi->dni = dniNext; + if (pDi->tba.nBlkAdr != dniNext.pDns->nBlkAdr) { + // We have back tracked to a previous node + TransUnpinBlk(&pDi->tba); + pDi->tba.nBlkAdr = dniNext.pDns->nBlkAdr; + WFSKrnExitOnError( DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, &pBlkHdr) ); + ++pDi->dni.pDns->nEntryIdx; + pDi->dni.pOfs = DirNodeGetIntraBlkOfsPtr(pDi->dni.pDns->nEntryIdx, pDi->dni.pSubBlkHdr); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.nEntryIdx=1; + do { + while(1) { + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + WFSKrnExitOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + pDi->dni.pDns->nUpdateCtr = pDi->nUpdateCtr; + if (pDi->dni.pSubBlkHdr->aFirstChar[pDi->dni.pSubBlkHdr->nStrLen] == 0) { + break; + } + pDi->dni.pOfs = DirNodeGetIntraBlkOfsPtr(pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + } + { + WFSBlkAdr nNewBlkAdr = DirNodeGetBlkAdr(pDi->dni.pSubBlkHdr); + TransUnpinBlk(&pDi->tba); + pDi->tba.nBlkAdr = nNewBlkAdr; + WFSKrnExitOnError( DirGetBlk(pDi, TRANS_FLAG_READ_BLK | BCACHE_FLAG_PINNED, &pBlkHdr) ); + } + DirCheckBlk(pDi); +#if _DEBUG_DIR + /*if (nDirTest == nDirTestBreakPoint) { + pDi->pBlkHdr = pBlkHdr; + DirCheckBlk(pDi); + }*/ +#endif + pDi->dni.pOfs = &pBlkHdr->nRootOfs; + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nEntryIdx = 1; + } while(!(pBlkHdr->sbah.mdh.nFlags & WFS_MDF_DIR_LEAF_BLK)); + nStrIdx = (u32)-1; + pDi->dni.pStrPtr = pName->sStr; + } else { + nStrIdx = dniNext.pDns->nStrIdx; + *pDi->dni.pStrPtr++ = pDi->dni.pNodeStrPtr[dniNext.nEntryIdx]; + ++dniNext.nEntryIdx; + pDi->dni.pOfs = DirLeafGetIntraBlkOfsPtr(dniNext.nEntryIdx, pDi->dni.pSubBlkHdr); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + } + nSubBlkStrLen = pDi->dni.pSubBlkHdr->nStrLen; + nStrIdx += nSubBlkStrLen + 1; + pDi->dni.pNodeStrPtr = pDi->dni.pSubBlkHdr->aFirstChar; + pDi->dni.nEntryIdx = 1; + +ChooseMinDescendentLeaf: + ++nSubBlkStrLen; + while(1) { + memcpy(pDi->dni.pStrPtr, pDi->dni.pNodeStrPtr, nSubBlkStrLen); + pDi->dni.pStrPtr += nSubBlkStrLen; + if(pDi->dni.pDns->nBlkAdr != pDi->tba.nBlkAdr || pDi->dni.pDns->nSubBlkOfs != *pDi->dni.pOfs){ + WFSKrnReturnOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + } else { + pDi->dni.pDns->nEntryIdx = (u8)pDi->dni.nEntryIdx; + } + //WFSKrnExitOnError(DirPushNodeStackEntry(&pDi->dni, pDi->tba.nBlkAdr)); + pDi->dni.pDns->nUpdateCtr = pDi->nUpdateCtr; + pDi->dni.pDns->nStrIdx = (u8)nStrIdx; + pDi->dni.pOfs = DirLeafGetIntraBlkOfsPtr(pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + if (pDi->dni.pNodeStrPtr[nSubBlkStrLen-1] == 0) { + break; + } + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.pNodeStrPtr = pDi->dni.pSubBlkHdr->aFirstChar; + nSubBlkStrLen = pDi->dni.pSubBlkHdr->nStrLen + 1; + nStrIdx += nSubBlkStrLen; + pDi->dni.nEntryIdx = 1; + }; + break; + } + pDi->dni.pOfs = DirLeafGetIntraBlkOfsPtr_l2s((s32)pDi->dni.nEntryIdx, pDi->dni.pSubBlkHdr, pDi->dni.nLog2Size); + dbg(SbaCheckOfs(*pDi->dni.pOfs)); + pDi->dni.pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->dni.nLog2Size = DirLeafGetSubBlkLog2Size(pDi->dni.pSubBlkHdr); + ++pDi->dni.pStrPtr; + } + pDi->pAttrHdr = (DirEntryAttrHdr*)((u8*)pBlkHdr + *pDi->dni.pOfs); + pDi->name.nLen = nStrIdx; +Exit: + pDi->pBlkHdr = pBlkHdr; + return nResult; +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirNodeStack.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirNodeStack.cpp new file mode 100644 index 0000000..9db6068 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirNodeStack.cpp @@ -0,0 +1,418 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_DirNodeStack.cpp + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_DirNodeStack.cpp,v $ + Revision 1.8 2008/10/16 09:30:39 ooizumi + Fixed definitions for debug build. + + Revision 1.7 2008/10/14 10:27:14 kondo_masahiro + Added #define _DEBUG_BREAK_POINT + + Revision 1.6 2008/09/28 23:32:04 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.5 2008/08/05 03:58:31 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.4 2008/07/09 00:37:52 paul + Changes to make directory code work with block cache. + + Revision 1.3 2008/05/10 03:59:44 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.2 2008/04/25 17:29:50 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.10 2008/04/23 01:56:07 paul + Fixed bCheckDirNodeStack to be visible from wfskrn_Dir.cpp + + Revision 1.9 2008/04/22 22:12:40 paul + Changed WFSArea* to Area* + + Revision 1.8 2008/04/19 05:50:51 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.7 2008/04/15 18:45:09 paul + Added some debug code to output calling locations for NodeStack functions + + Revision 1.6 2008/04/04 22:53:33 paul + Changed debug triggers to use bCheckDirNodeStack + + Revision 1.5 2008/04/04 21:16:33 paul + Fixed loop-detecting code + + Revision 1.4 2008/04/03 23:38:31 kondo_masahiro + change name of debug parameter + + Revision 1.3 2008/03/05 11:02:13 paul + Changed stack checking functions to not allocate memory + + Revision 1.2 2008/02/28 06:31:49 kondo_masahiro + Fixed code to accept PPC compiler + + Revision 1.1 2008/02/27 09:46:53 paul + *** empty log message *** + + Revision 1.2 2008/02/27 00:38:44 paul + Updated debug code + + Revision 1.1 2008/02/21 04:35:34 paul + *** empty log message *** + + + *---------------------------------------------------------------------------*/ + +#undef _KRN_FILE_ +#define _KRN_FILE_ "DirNS" + +#include "wfskrn_DirNodeStack.h" +#include "wfskrn_Mutex.h" +#include "wfskrn_Api.h" + + +#if _DEBUG_DIR_NODE_STACK + #define dbg_check(s) s + #define dbg_output(s) +#else + #define dbg_check(s) + #define dbg_output(s) +#endif + + +#if _DEBUG_DIR_NODE_STACK + bool bCheckDirNodeStack = false; // extern +#endif + +typedef struct { + WFSKrnMutex mxMutex; + dbg_check(u32 nTotalAllocated;) + dbg_check(u32 nNumUsed;) + u32 nNumFreeDnsPoolEntries; + DirNodeStack *pDnsPoolFreeList; +} DirNodeStackGlobals; + +DirNodeStackGlobals dnsg; + +#if _DEBUG_DIR + void DebugCheckNumFreeDnsPoolEntries(char *str) { + static u32 nPrev=0; + char *s; s = str; // for warning + if (nPrev != dnsg.nNumFreeDnsPoolEntries) { + nPrev = dnsg.nNumFreeDnsPoolEntries; + dbg_output(MyOSReport("%s: dnsg.nNumFreeDnsPoolEntries=%d\n", str, dnsg.nNumFreeDnsPoolEntries)); + if ((dnsg.nNumFreeDnsPoolEntries!=WFS_DIR_NODE_STACK_ENTRY_POOL_ALLOC_UNIT)&& + (dnsg.nNumFreeDnsPoolEntries!=(WFS_DIR_NODE_STACK_ENTRY_POOL_ALLOC_UNIT*2))) { + //int a=0; // for warning + } + } + } +#endif //_DEBUG_DIR + + +#if _DEBUG_DIR_NODE_STACK + + DirNodeStack *pDebugLastNodeStackAlloc; + u32 nDebugCountNodeStackCheckAlloc = 0; + u32 nDebugCountNodeStackCheckFreeList = 0; + + static + void DirNodeStackCheckAlloc(DirNodeItr *pDni) { + nDebugCountNodeStackCheckAlloc++; + dbg_output(MyOSReport("%d. ", nDebugCountNodeStackCheckAlloc)); + DirNodeStack *pDns = pDni->pDns; + u32 nI; + for(nI=pDni->nDnsDepth; --nI; ) { + //s32 nIdx = pDns-pDebugLastNodeStackAlloc; // unused + dbg_output(MyOSReport("%d,", nIdx)); + if ((u32)pDns==0xbaadf00d) { + WFSKrnOutputErrorStr("DirNodeStack Error! Bad entry!\n"); + } + DirNodeStack *pDns2 = pDns; + u32 nJ; + for(nJ=nI; --nJ; ) { + pDns2 = pDns2->pParent; + if (pDns2 == pDns) { + WFSKrnOutputErrorStr("DirNodeStack Error! Same entry appears twice!\n"); + } + } + //u32 nOfs = pDns->nSubBlkOfs; // unused + //u32 nBlkAdr = pDns->nBlkAdr; + pDns = pDns->pParent; + /*if ((nI>1) && (pDns->nSubBlkOfs == nOfs) && (pDns->nBlkAdr == nBlkAdr)) { + WFSKrnOutputErrorStr("DirNodeStack Error! Same offset repeats!\n"); + }*/ + } + dbg_output(MyOSReport(": ")); + } + + void DirNodeStackCheckFreeList() { + nDebugCountNodeStackCheckFreeList++; + DirNodeStack *pDns = dnsg.pDnsPoolFreeList; + u32 nI; + for(nI=0; nIpParent; + } + pDns = pDns->pParent; + } + dbg_output(MyOSReport("\n")); + //WFSKrnHeapFree(&wkg.heap, ppDns); + } + +#endif //_DEBUG_DIR_NODE_STACK + + +WFSKrnResult DirAllocateMoreNodeStackEntries() { + dnsg.pDnsPoolFreeList = (DirNodeStack *)WFSKrnHeapAlloc(&wkg.heap, WFS_DIR_NODE_STACK_ENTRY_POOL_ALLOC_UNIT * sizeof(DirNodeStack)); + dbg_check(pDebugLastNodeStackAlloc = dnsg.pDnsPoolFreeList); + if (dnsg.pDnsPoolFreeList == 0) { + return WFSKRN_RESULT_OUT_OF_MEMORY; + } + u32 nI; + for(nI=0; nIpParent; + WFSKrnUnlockMutex(&dnsg.mxMutex); + pNewDnsEntry->pParent = pDni->pDns; + pDni->pDns = pNewDnsEntry; + ++pDni->nDnsDepth; +#if _DEBUG_DIR_NODE_STACK + if (bCheckDirNodeStack) { + dbg_output(MyOSReport("GetEntry: ")); + DirNodeStackCheckAlloc(pDni); + DirNodeStackCheckFreeList(); + } +#endif + return WFSKRN_RESULT_OK; +} + + +#if _DEBUG_DIR_NODE_STACK +void _DirNodeStackFree(char *sFile, u32 nLine, DirNodeItr *pDni, DirNodeStack **ppParent) { + dnsg.nNumUsed -= pDni->nDnsDepth; + if (bCheckDirNodeStack) + MyOSReport("Dns:%d, %s Ln:%d Free\n", dnsg.nNumUsed, sFile, nLine); + if (bCheckDirNodeStack) { + dbg_output(MyOSReport("StackFree(%d) { ", pDni->nDnsDepth)); + DirNodeStackCheckAlloc(pDni); + DirNodeStackCheckFreeList(); + } +#else +void DirNodeStackFree(DirNodeItr *pDni, DirNodeStack **ppParent) { +#endif + WFSKrnLockMutex(&dnsg.mxMutex); + dnsg.nNumFreeDnsPoolEntries += pDni->nDnsDepth; + *ppParent = dnsg.pDnsPoolFreeList; + dnsg.pDnsPoolFreeList = pDni->pDns; + WFSKrnUnlockMutex(&dnsg.mxMutex); +#if _DEBUG_DIR_NODE_STACK + if (bCheckDirNodeStack) { + dbg_output(MyOSReport("} StackFree: ")); + DirNodeStackCheckAlloc(pDni); + DirNodeStackCheckFreeList(); + } +#endif +} + + +#if _DEBUG_DIR_NODE_STACK +WFSKrnResult _DirPushNodeStackEntry(char *sFile, u32 nLine, DirNodeItr *pDni, WFSBlkAdr nBlkAdr) { + ++dnsg.nNumUsed; + if (bCheckDirNodeStack) + MyOSReport("Dns:%d, %s Ln:%d Push\n", dnsg.nNumUsed, sFile, nLine); + #if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } + #endif +#else +WFSKrnResult DirPushNodeStackEntry(DirNodeItr *pDni, WFSBlkAdr nBlkAdr) { +#endif +#if _DEBUG_BREAK_POINT + static int c=0; c++; if(c == 2601){ + int a; a=0; + } + if( pDni->pDns->nBlkAdr == nBlkAdr && pDni->pDns->nSubBlkOfs == *pDni->pOfs ){ + int a; a=0; + } +#endif + WFSKrnLockMutex(&dnsg.mxMutex); + if (dnsg.nNumFreeDnsPoolEntries==0) { + WFSKrnUnlockMutex(&dnsg.mxMutex); + WFSKrnReturnOnError(DirAllocateMoreNodeStackEntries()); + WFSKrnLockMutex(&dnsg.mxMutex); + } + --dnsg.nNumFreeDnsPoolEntries; + DirNodeStack *pNewDnsEntry = dnsg.pDnsPoolFreeList; +#if _WIN32 + if ((u32)dnsg.pDnsPoolFreeList == 0xbaadf00d) { + WFSKrnOutputErrorStr("Bad Node Stack Entry"); + } +#endif + dnsg.pDnsPoolFreeList = dnsg.pDnsPoolFreeList->pParent; + pNewDnsEntry->pParent = pDni->pDns; + pDni->pDns = pNewDnsEntry; + ++pDni->nDnsDepth; + WFSKrnUnlockMutex(&dnsg.mxMutex); + pNewDnsEntry->nBlkAdr = nBlkAdr; + pNewDnsEntry->nSubBlkOfs = *pDni->pOfs; + //} + pNewDnsEntry->nEntryIdx = (u8)pDni->nEntryIdx; +#if _DEBUG_DIR_NODE_STACK + if (bCheckDirNodeStack) { + dbg_output(MyOSReport("PushEntry: ")); + DirNodeStackCheckAlloc(pDni); + DirNodeStackCheckFreeList(); + } +#endif + return WFSKRN_RESULT_OK; +} + + +#if _DEBUG_DIR_NODE_STACK +void _DirPopNodeStackEntry(char *sFile, u32 nLine, DirNodeItr *pDni) { + --dnsg.nNumUsed; + if (bCheckDirNodeStack) + MyOSReport("Dns:%d, %s Ln:%d Pop\n", dnsg.nNumUsed, sFile, nLine); +#else +void DirPopNodeStackEntry(DirNodeItr *pDni) { +#endif + WFSKrnLockMutex(&dnsg.mxMutex); + DirNodeStack *pNewFreeEntry = pDni->pDns; + pDni->pDns = pNewFreeEntry->pParent; + pNewFreeEntry->pParent = dnsg.pDnsPoolFreeList; + dnsg.pDnsPoolFreeList = pNewFreeEntry; + --pDni->nDnsDepth; + ++dnsg.nNumFreeDnsPoolEntries; +#if _DEBUG_DIR_NODE_STACK + if (bCheckDirNodeStack) { + dbg_output(MyOSReport("PopEntry: ")); + DirNodeStackCheckAlloc(pDni); + DirNodeStackCheckFreeList(); + } +#endif + WFSKrnUnlockMutex(&dnsg.mxMutex); +} + + +void DirConstructEntryNameFromNodeStack(WFSFileName *pKey, DirItr *pDi) { + // This function parses the node stack constructing the key name + // ToDo: This function simply concatenates the strings from SubBlks, + // but it should take account of the adjustment needed between blocks +#if (_DEBUG_DIR && _DEBUG_DIR_NODE_STACK) + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } +#endif + DirBlkHdr *pBlkHdr = pDi->pBlkHdr; + DirNodeStack *pDns = pDi->dni.pDns; + u32 nI=pDi->dni.nDnsDepth; + pKey->nLen = pDns->nStrIdx;//nStrLen-1; + utf8 *pStr = pKey->sStr; + // Trace back through the leaf + u32 nMinStrIdx = WFS_MAX_FILE_NAME_SIZE; + do { + DirSubBlkHdr *pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + pDns->nSubBlkOfs); + nMinStrIdx = (u32)(pDns->nStrIdx - pSubBlkHdr->nStrLen); + pStr[pDns->nStrIdx] = pSubBlkHdr->aFirstChar[pSubBlkHdr->nStrLen + pDns->nEntryIdx-1]; + memcpy(&pStr[nMinStrIdx], pSubBlkHdr->aFirstChar, pSubBlkHdr->nStrLen); + if (0 == --nI) { + return; + } + pDns = pDns->pParent; + } while (pDi->tba.nBlkAdr == pDns->nBlkAdr); + // Trace back through nodes +#if (DIR_PREFIX_SUPPRESSION) + pDi->tba.nBlkAdr = pDns->nBlkAdr; +#if AREA_ENABLE_BLK_CACHE + AreaBlkMap(pDi->tba.pAreaInfo, pDi->tba.nBlkAdr, TRUE, TRUE, TRUE, (void**) &pBlkHdr); +#else + TransGetAndPinBlk(&pDi->tba, &pBlkHdr); +#endif + while(nMinStrIdx) { + DirSubBlkHdr *pSubBlkHdr = (DirSubBlkHdr *)((u8*)pBlkHdr + pDns->nSubBlkOfs); + utf8 cChoiceChar = pSubBlkHdr->aFirstChar[pSubBlkHdr->nStrLen + pDns->nEntryIdx-1]; + if (pDns->nStrIdx <= nMinStrIdx) { + if (pDns->nStrIdx < nMinStrIdx) { + pStr[pDns->nStrIdx] = cChoiceChar; + } + memcpy(&pStr[pDns->nStrIdx - pSubBlkHdr->nStrLen], pSubBlkHdr->aFirstChar, pSubBlkHdr->nStrLen); + nMinStrIdx = pDns->nStrIdx; + } + if (0 == --nI) { + return; + } + pDns = pDns->pParent; + if (pDi->tba.nBlkAdr != pDns->nBlkAdr) { + pDi->tba.nBlkAdr = pDns->nBlkAdr; +#if AREA_ENABLE_BLK_CACHE + AreaBlkUnpin(pDi->tba.pAreaInfo, pDi->tba.nBlkAdr); + AreaBlkMap(pDi->tba.pAreaInfo, pDns->nBlkAdr, TRUE, TRUE, TRUE, (void**) &pBlkHdr); +#else + TransGetAndPinBlk(&pDi->tba, &pBlkHdr); +#endif + } + } +#if AREA_ENABLE_BLK_CACHE + AreaBlkUnpin(pDi->tba.pAreaInfo, pDi->tba.nBlkAdr); +#endif +#endif +} + + +#if _DEBUG_DIR_NODE_STACK +void _DirNodeStackCheckEmpty() { + if (dnsg.nNumUsed != 0) { + WFSKrnOutputErrorStr("Dir Node Stack Not Empty"); + } +} +#endif diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirRxTree.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirRxTree.cpp new file mode 100644 index 0000000..21e5748 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_DirRxTree.cpp @@ -0,0 +1,1170 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_DirRxTree.cpp - Functions for creating and using radix trees + + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_DirRxTree.cpp,v $ + Revision 1.20 2008/12/08 00:01:42 kondo_masahiro + Fixed RxtMergeNodeWithItsSingleChild(). + + Revision 1.19 2008/12/05 05:47:26 kondo_masahiro + Fixed error handling in RxtDeleteNode() + ToDo: PathCache have to be fixed to the efficient method of delete node and to prevent the error. + + Revision 1.18 2008/11/27 00:03:28 ooizumi + Fixed a bug in RxtInsert(). + + Revision 1.17 2008/11/13 12:44:18 ooizumi + Fixed a bug in RxtInsert(). + + Revision 1.16 2008/10/29 02:22:16 ooizumi + Fixed codes for IOP compiler. + + Revision 1.15 2008/10/28 08:13:34 ooizumi + Modified RxtFindNext() to fix node offsets in currently accessing search directory infos. + This code must be fixed in the future. + + Revision 1.14 2008/10/14 10:27:14 kondo_masahiro + Added #define _DEBUG_BREAK_POINT + + Revision 1.13 2008/10/10 10:48:41 ooizumi + Fixed RxtNextUntilSeparator(). + + Revision 1.12 2008/09/26 07:37:22 ooizumi + Fixed a bug RxtFindNext cannot handle separator. + + Revision 1.11 2008/09/02 00:09:22 ooizumi + Fixed a bug with pRxi->pNodeStrPtr when inserting a new choice character and resizing node size. + + Revision 1.10 2008/08/28 05:54:38 paul + Fixed a bug with pRxi->pOfs when inserting a prefix to an existing name + + Revision 1.9 2008/08/27 23:02:55 ooizumi + Fixed newline to CR+LF(Windows format). + + Revision 1.8 2008/08/27 09:49:10 paul + Added debug asserts + + Revision 1.7 2008/07/28 22:18:22 paul + Fixed a bug in RxtDeleteNode(). + + Revision 1.6 2008/07/21 22:37:04 paul + Added a callback parameter to RxtCheck() to allow path cache entries to be checked for consistency + + Revision 1.5 2008/07/17 22:51:30 paul + Fixed a bug + + Revision 1.4 2008/07/09 00:38:54 paul + Minor changes + + Revision 1.3 2008/06/09 17:53:07 paul + Rewrote DirRxTree to support PathCache. New version includes parent pointers in each node. + + Revision 1.2 2008/05/14 02:17:46 paul + Fixed the DirBinarySplitSearchChoices() node choice ordering check to prevent utf8 being upgraded to signed int + + Revision 1.1 2008/05/10 03:57:03 kondo_masahiro + Initial check-in + +*---------------------------------------------------------------------------*/ + +#undef _KRN_FILE_ +#define _KRN_FILE_ "DirRxTree" + +#include "wfskrn_SubBlkAlloc.h" + +#include "wfskrn_Dir.h" +#include "wfskrn_DirFind.h" +#include "wfskrn_DirNodeStack.h" +#include "wfskrn_DirRxTree.h" + +#include "wfskrn_Api.h" + +#undef dbg +#if _DEBUG_DIR + #define dbg(s) s +#else + #define dbg(s) +#endif + + +WFSBool DirBinarySplitSearchChoices(utf8 *aSortedArray, u32 nNumEntries, utf8 cSearchChar, u32 *pEntryIdx) { + if (nNumEntries==0) { + return false; + } + u32 nLow = 0; + u32 nHigh = nNumEntries-1; + utf8 cVal; + while(1) { + *pEntryIdx = (nLow + nHigh + 1)>>1; + cVal = aSortedArray[*pEntryIdx]; + if (nLow >= nHigh) { + if ((unsigned)cSearchChar >= (unsigned)aSortedArray[0]) { + ++(*pEntryIdx); + } + return ((*pEntryIdx) && (cVal==cSearchChar)); + } + if ((unsigned)cVal>(unsigned)cSearchChar) { + nHigh = *pEntryIdx-1; + } else { + nLow = *pEntryIdx; + } + } +} + + +void RxtInit(RxtHdr *pRxtHdr, u32 nLog2Size) { + SbaBlkInit(pRxtHdr, nLog2Size, WFS_NUM_BITS_REQUIRED(sizeof(RxtHdr))); + u32 nRootNodeLog2Size = RxtGetNodeLog2Size_2(0, 0); + pRxtHdr->nRootOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nRootNodeLog2Size); + pRxtHdr->nReserveOfs = 0; + RxtNodeHdr *pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + pRxtHdr->nRootOfs); + pNodeHdr->nParentOfs = 0; + pNodeHdr->nStrLen = 0; + pNodeHdr->nNumEntries = 0; + pNodeHdr->aFirstChar[0] = (utf8)0xC1; + pNodeHdr->nLog2Size = nRootNodeLog2Size; +} + + +void RxtGetString(RxtHdr *pRxtHdr, RxtNodeHdr *pNodeHdr, utf8 *sStr, u32 nStrLen) { + utf8 *pStr = &sStr[nStrLen]; + *pStr=0; + while(1) { + pStr -= pNodeHdr->nStrLen; +#if _DEBUG + if (pStr < sStr) { + WFSKrnOutputErrorStr("String too long"); + } +#endif + memcpy(pStr, pNodeHdr->aFirstChar, pNodeHdr->nStrLen); + if (pNodeHdr->nParentOfs == 0) { + return; + } + u32 nEntryIdx = pNodeHdr->nEntryIdx; + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + pNodeHdr->nParentOfs); +#if _DEBUG + if (pStr == sStr) { + WFSKrnOutputErrorStr("String too long"); + } +#endif + *(--pStr) = pNodeHdr->aFirstChar[pNodeHdr->nStrLen + nEntryIdx]; + } +} + + +static +void RxtNodeDebugPrint(RxtNodeHdr *pNodeHdr) { + utf8 *pChoiceChar = &pNodeHdr->aFirstChar[pNodeHdr->nStrLen]; + utf8 cTemp = *pChoiceChar; + *pChoiceChar = 0; + MyOSReport("%d,%d,\"%s\"", pNodeHdr->nStrLen, pNodeHdr->nNumEntries, pNodeHdr->aFirstChar); + *pChoiceChar = cTemp; + u32 nI; + for(nI=0; nInNumEntries; nI++) { + if ((*pChoiceChar<32)||(*pChoiceChar>127)) { + MyOSReport(",%d", *pChoiceChar); + } else { + MyOSReport(",'%c'", *pChoiceChar); + } + ++pChoiceChar; + } + //MyOSReport("\n"); +} + + +#if _CHECK_RXT +void RxtCheck(RxtHdr *pRxtHdr, u32 nTotalSize, RxtCheckEntry cbCheckEntry) { + // Checks the integrity of the radix tree: + // * That all allocated sub blocks of pRxtHdr are reachable + // * That all non-allocated blocks are on the free list + // * That no blocks overlap + // * That each node within the tree contains a sorted list of choices + // * That calculated node sizes match the stored node sizes + // * That parent pointers point to the correct parent + // * That nEntryIdx matches + RxtItr rxi; + rxi.nDepth = 0; + u32 nParentOfs = 0; + u32 nOfs = pRxtHdr->nRootOfs; + utf8 *pChoiceChar; + u32 nConnectedSize=1<nReserveOfs) { + nConnectedSize += 1<nMagic == SBA_FREE_SUB_BLK_MAGIC) { + WFSKrnOutputErrorStr("Pointer to deleted sub block detected!"); + } +#if _DEBUG_PATH_CACHE + if ((nDirTest>=nDirTestBreakPoint-1)&&(nDirTest<=nDirTestBreakPoint)) { + u32 nI; + for(nI=0; nInLog2Size) { + WFSKrnOutputErrorStr("pNodeHdr->nLog2Size incorrect!"); + } + if (nParentOfs != rxi.pNodeHdr->nParentOfs) { + WFSKrnOutputErrorStr("pNodeHdr->nParentOfs incorrect!"); + } + if (rxi.nEntryIdx != rxi.pNodeHdr->nEntryIdx + 1) { + WFSKrnOutputErrorStr("pNodeHdr->nEntryIdx incorrect!"); + } + if (WfsTestAndSetBitField((unsigned*)aUtilization, nOfs>>SBA_MIN_LOG2_SUB_BLK_SIZE, 1<<(nNodeLog2Size-SBA_MIN_LOG2_SUB_BLK_SIZE))) { + WFSKrnOutputErrorStr("DirRxTree: Overlap!"); + } + nConnectedSize += (u32)(1<nStrLen+1; + u16 *pSrcNodeOfsTblEnd = (u16*)((u8*)rxi.pNodeHdr + (1<nNumEntries == 0) { + if (pRxtHdr->nNumRecs) { + WFSKrnOutputErrorStr("No entries!"); + } + } + pChoiceChar = &rxi.pNodeHdr->aFirstChar[rxi.pNodeHdr->nStrLen]; + if (*pChoiceChar == 0) { + // String terminator char indicates this is a record, so increment the record count + u32 nAttrOfs = pSrcNodeOfsTblEnd[-1]; + RxtAttrHdr *pAttrHdr = (RxtAttrHdr *)((u8*)pRxtHdr + nAttrOfs); + WFSSubBlkFreeHdr *pSbfHdr = (WFSSubBlkFreeHdr *)pAttrHdr; + if (pSbfHdr->nMagic == SBA_FREE_SUB_BLK_MAGIC) { + WFSKrnOutputErrorStr("Pointer to deleted attr block detected!"); + } + u16 nAttrLog2Size = pAttrHdr->nLog2Size; + if (nOfs != pAttrHdr->nParentOfs) { + WFSKrnOutputErrorStr("pAttrHdr->nParentOfs incorrect!"); + } + if (WfsTestAndSetBitField((unsigned*)aUtilization, nAttrOfs>>SBA_MIN_LOG2_SUB_BLK_SIZE, 1<<(nAttrLog2Size-SBA_MIN_LOG2_SUB_BLK_SIZE))) { + WFSKrnOutputErrorStr("DirRxTree: Overlap!"); + } + nConnectedSize += (u32)(1<=nDirTestBreakPoint-1)&&(nDirTest<=nDirTestBreakPoint)) { + WFSPathName path; + RxtGetString(pRxtHdr, rxi.pNodeHdr, path.sStr, nStrIdx); + MyOSReport(" %s\n", path.sStr); + } +#endif + } else if (rxi.pNodeHdr->nNumEntries == 1) { + WFSKrnOutputErrorStr("Non-terminating single-choice node!"); + } else { +#if _DEBUG_PATH_CACHE + if ((nDirTest>=nDirTestBreakPoint-1)&&(nDirTest<=nDirTestBreakPoint)) { + MyOSReport("\n"); + } +#endif + } + if (rxi.nEntryIdx > rxi.pNodeHdr->nNumEntries) { + do { + if (rxi.nDepth == 0) { + // We reached the top of the stack, so this should be the last record + goto CheckFreeSpace; + } + rxi.nEntryIdx = rxi.pNodeHdr->nEntryIdx + 2; + nOfs = rxi.pNodeHdr->nParentOfs; + nStrIdx -= rxi.pNodeHdr->nStrLen+1; + rxi.pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nOfs); + --rxi.nDepth; + } while(rxi.nEntryIdx > rxi.pNodeHdr->nNumEntries); + pChoiceChar = &rxi.pNodeHdr->aFirstChar[rxi.pNodeHdr->nStrLen + rxi.nEntryIdx-1]; + if ((unsigned)pChoiceChar[-1] >= (unsigned)*pChoiceChar) { + WFSKrnOutputErrorStr("Choice out of order!"); + } + } + ++rxi.nDepth; + nParentOfs = nOfs; + nOfs = RxtGetChildOfs(rxi.nEntryIdx, rxi.pNodeHdr); + } +CheckFreeSpace: + // Next check the free space + SbaCheckFreeSpace((WFSSubBlkAllocHdr *)pRxtHdr, aUtilization); + if (nTotalSize) { + if ((pRxtHdr->sbah.nTotalFree + nConnectedSize) != nTotalSize) { + WFSKrnOutputErrorStr("DirRxTree: Memory Leak detected within block!"); + } + } + if (nRecIdx != pRxtHdr->nNumRecs) { + WFSKrnOutputErrorStr("NumRecs Error!"); + } +} +#endif //_CHECK_RXT + + +WFSKrnResult RxtFind(RxtHdr *pRxtHdr, RxtItr *pRxi, u32 nStrLen) { + pRxi->nDepth = 0; + pRxi->pOfs = &pRxtHdr->nRootOfs; + WFSKrnResult nResult; + utf8 *pStrEnd = pRxi->pStrPtr + nStrLen; + RxtNodeHdr *pNodeHdr; + while(1) { + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + *pRxi->pOfs); + u32 nNodeStrLen = pNodeHdr->nStrLen; + pRxi->pNodeStrPtr = pNodeHdr->aFirstChar; + u32 nSearchStrLen = pStrEnd - pRxi->pStrPtr; + if (nSearchStrLen < nNodeStrLen) { + while((nSearchStrLen) && (*pRxi->pStrPtr == *pRxi->pNodeStrPtr)) { + ++pRxi->pStrPtr; ++pRxi->pNodeStrPtr; --nSearchStrLen; + } + nNodeStrLen -= (pRxi->pNodeStrPtr - pNodeHdr->aFirstChar); + pRxi->nEntryIdx = -(s32)nNodeStrLen; + nResult = WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH; + if (nSearchStrLen == 0) { + nResult = WFSKRN_RESULT_DIR_NODE_STRING_PREFIX; + } + break; + } + while((nNodeStrLen) && (*pRxi->pStrPtr == *pRxi->pNodeStrPtr)) { + ++pRxi->pStrPtr; ++pRxi->pNodeStrPtr; --nNodeStrLen; + } + if (nNodeStrLen) { + pRxi->nEntryIdx = pRxi->pNodeStrPtr - pNodeHdr->aFirstChar; + nResult = WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH; + break; + } + // matched all the characters from the prefix. pRxi->pNodeStrPtr should now be pointing to the array of choices following the prefix. + utf8 cSearchChar = *pRxi->pStrPtr; + if (pRxi->pStrPtr == pStrEnd){ + cSearchChar = 0; + } + if (!DirBinarySplitSearchChoices(pRxi->pNodeStrPtr, pNodeHdr->nNumEntries, cSearchChar, (u32*)&pRxi->nEntryIdx)) { + nResult = WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND; + break; + } + // Found the search character. + if (cSearchChar==0) { + // We matched a 0 .. which means we have found the search string + nResult = WFSKRN_RESULT_DIR_ENTRY_FOUND; + break; + } + ++pRxi->nDepth; + pRxi->pOfs = RxtGetChildOfsPtr((s32)pRxi->nEntryIdx, pNodeHdr); + ++pRxi->pStrPtr; + } + pRxi->pNodeHdr = pNodeHdr; + return nResult; +} + + +WFSKrnResult RxtNextUntilSeparator(RxtHdr *pRxtHdr, RxtItr *pRxi, utf8 cSeparator) { + RxtNodeHdr *pNodeHdr = pRxi->pNodeHdr; + utf8 *pDst, *pSrc, *pSrcEnd; + if (pRxi->nEntryIdx < 0) { + pDst = pRxi->pStrPtr; + pSrc = pRxi->pNodeStrPtr; + pSrcEnd = pSrc + 1-pRxi->nEntryIdx; + if(*pDst) + pDst++; // Skip choice char + while(pSrc < pSrcEnd) { + if (*pSrc == cSeparator) { + return WFSKRN_RESULT_DIR_NODE_STRING_PREFIX; + } + *pDst++ = *pSrc++; + } + pRxi->pStrPtr = pDst-1; + pRxi->nEntryIdx = 1; + } else { + while(pRxi->nEntryIdx == pNodeHdr->nNumEntries) { + u32 nParentOfs = (u32)pNodeHdr->nParentOfs; + if (nParentOfs == 0) { + return WFSKRN_RESULT_NOT_FOUND; + } + if (pNodeHdr->aFirstChar[pNodeHdr->nStrLen + pNodeHdr->nNumEntries-1] == cSeparator) { + return WFSKRN_RESULT_NOT_FOUND; + } + pSrc = pNodeHdr->aFirstChar; + pSrcEnd = pSrc + pNodeHdr->nStrLen; + while(pSrcpStrPtr -= pNodeHdr->nStrLen+1; + pRxi->nEntryIdx = pNodeHdr->nEntryIdx+1; + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nParentOfs); + } + *pRxi->pStrPtr = pNodeHdr->aFirstChar[pNodeHdr->nStrLen + pRxi->nEntryIdx]; + ++pRxi->nEntryIdx; + } + if (*pRxi->pStrPtr == 0) { + return WFSKRN_RESULT_OK; + } + ++pRxi->pStrPtr; + u32 nOfs = RxtGetChildOfs(pRxi->nEntryIdx, pNodeHdr); + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nOfs); + pRxi->nEntryIdx = 1; + while(1) { + pDst = pRxi->pStrPtr; + pSrc = pNodeHdr->aFirstChar; + pSrcEnd = pSrc + pNodeHdr->nStrLen + 1; + while(pSrc < pSrcEnd) { + if (*pSrc == cSeparator) { + *pDst = 0; + return WFSKRN_RESULT_OK; + //return WFSKRN_RESULT_DIR_NODE_STRING_PREFIX; + } + *pDst++ = *pSrc++; + } + //memcpy(pRxi->pStrPtr, pNodeHdr->aFirstChar, pNodeHdr->nStrLen+1); + pRxi->pStrPtr += pNodeHdr->nStrLen; + if (*pRxi->pStrPtr == 0) { + pRxi->pNodeHdr = pNodeHdr; + return WFSKRN_RESULT_OK; + } + ++pRxi->pStrPtr; +#if _DEBUG_DIR + u32 nParentOfs = nOfs; +#endif + nOfs = RxtGetChildOfs(1, pNodeHdr); + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nOfs); +#if _DEBUG_DIR + if (pNodeHdr->nParentOfs != nParentOfs) { + WFSKrnOutputErrorStr("Parent Incorrect"); + } +#endif + } +} + + +WFSKrnResult RxtNext(RxtHdr *pRxtHdr, RxtItr *pRxi) { + RxtNodeHdr *pNodeHdr = pRxi->pNodeHdr; + if (pRxi->nEntryIdx < 0) { + memcpy(pRxi->pStrPtr, pRxi->pNodeStrPtr, 1-pRxi->nEntryIdx); + pRxi->pStrPtr -= pRxi->nEntryIdx; + pRxi->nEntryIdx = 1; + } else { + while(pRxi->nEntryIdx == pNodeHdr->nNumEntries) { + u32 nParentOfs = (u32)pNodeHdr->nParentOfs; + if (nParentOfs == 0) { + return WFSKRN_RESULT_NOT_FOUND; + } + pRxi->pStrPtr -= pNodeHdr->nStrLen+1; + pRxi->nEntryIdx = pNodeHdr->nEntryIdx+1; + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nParentOfs); + } + *pRxi->pStrPtr = pNodeHdr->aFirstChar[pNodeHdr->nStrLen + pRxi->nEntryIdx]; + ++pRxi->nEntryIdx; + } + if (*pRxi->pStrPtr == 0) { + return WFSKRN_RESULT_OK; + } + ++pRxi->pStrPtr; + u32 nOfs = RxtGetChildOfs(pRxi->nEntryIdx, pNodeHdr); + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nOfs); + pRxi->nEntryIdx = 1; + while(1) { + memcpy(pRxi->pStrPtr, pNodeHdr->aFirstChar, pNodeHdr->nStrLen+1); + pRxi->pStrPtr += pNodeHdr->nStrLen; + if (*pRxi->pStrPtr == 0) { + pRxi->pNodeHdr = pNodeHdr; + return WFSKRN_RESULT_OK; + } + ++pRxi->pStrPtr; +#if _DEBUG_DIR + u32 nParentOfs = nOfs; +#endif + nOfs = RxtGetChildOfs(1, pNodeHdr); + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nOfs); +#if _DEBUG_DIR + if (pNodeHdr->nParentOfs != nParentOfs) { + WFSKrnOutputErrorStr("Parent Incorrect"); + } +#endif + } +} + + +WFSKrnResult RxtFindNext(RxtHdr *pRxtHdr, RxtItr *pRxi, utf8 cSeparator) { + // This function requires that pRxi->pNodeHdr is pointing to a RxtAttrHdr entry within the radix tree + pRxi->nDepth = 0; + pRxi->pOfs = &pRxtHdr->nRootOfs; + //WFSKrnResult nResult; + //utf8 *pStrEnd = pRxi->pStrPtr + nStrLen; + RxtNodeHdr *pNodeHdr = pRxi->pNodeHdr; + pRxi->nEntryIdx = pNodeHdr->nEntryIdx + 1; + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + pNodeHdr->nParentOfs); + // If separator is found in choice chars of parent node, search failed. + if (pNodeHdr->aFirstChar[pNodeHdr->nStrLen + pRxi->nEntryIdx - 1] == cSeparator) { + return WFSKRN_RESULT_NOT_FOUND; + } + // To backtrack radix tree until finding next entry. + while(pRxi->nEntryIdx == pNodeHdr->nNumEntries) { + // If no parent node, search failed. + u32 nParentOfs = (u32)pNodeHdr->nParentOfs; + if (nParentOfs == 0) { + return WFSKRN_RESULT_NOT_FOUND; + } + // If separator is found in common chars, search failed. + utf8 *pPrefix = pNodeHdr->aFirstChar; + utf8 *pPrefixEnd = pPrefix + pNodeHdr->nStrLen; + while(pPrefixpStrPtr -= pNodeHdr->nStrLen+1; + pRxi->nEntryIdx = pNodeHdr->nEntryIdx+1; + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nParentOfs); + // If separator is found in choice chars of parent node, search failed. + if (pNodeHdr->aFirstChar[pNodeHdr->nStrLen + pRxi->nEntryIdx - 1] == cSeparator) { + return WFSKRN_RESULT_NOT_FOUND; + } + } + *pRxi->pStrPtr = pNodeHdr->aFirstChar[pNodeHdr->nStrLen + pRxi->nEntryIdx]; + ++pRxi->nEntryIdx; + + if (*pRxi->pStrPtr == 0) { + return WFSKRN_RESULT_OK; + } + ++pRxi->pStrPtr; + u32 nOfs = RxtGetChildOfs(pRxi->nEntryIdx, pNodeHdr); + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nOfs); + pRxi->nEntryIdx = 1; + while(1) { + memcpy(pRxi->pStrPtr, pNodeHdr->aFirstChar, pNodeHdr->nStrLen+1); + pRxi->pStrPtr += pNodeHdr->nStrLen; + if (*pRxi->pStrPtr == 0) { + pRxi->pNodeHdr = pNodeHdr; + return WFSKRN_RESULT_OK; + } + ++pRxi->pStrPtr; +#if _DEBUG_DIR + u32 nParentOfs = nOfs; +#endif + nOfs = RxtGetChildOfs(1, pNodeHdr); + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nOfs); +#if _DEBUG_DIR + if (pNodeHdr->nParentOfs != nParentOfs) { + WFSKrnOutputErrorStr("Parent Incorrect"); + } +#endif + } +/* if (pRxi->nEntryIdx > pNodeHdr->nNumEntries) { + return WFSKRN_RESULT_NOT_FOUND; + } + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + RxtGetChildOfs(pRxi->nEntryIdx, pNodeHdr)); + return WFSKRN_RESULT_OK;*/ +} + +WFSKrnResult RxtInsert(RxtHdr *pRxtHdr, RxtItr *pRxi, u32 nSuffixLen, RxtAttrHdr *pAttrHdr) { + //MyOSReport("RxtInsert: pRxtHdr = %x, pRxi = %x, nSuffixLen = %d, pAttrHdr = %x\n", pRxtHdr, pRxi, nSuffixLen, pAttrHdr); + //MyOSReport("RxtInsert: pRxi->pStrPtr= %s\n", pRxi->pStrPtr); +#if _DEBUG_BREAK_POINT + static int c=0;++c;if(c>=126307){ + int a;a=0; + } +#endif + if (pRxtHdr->nReserveOfs == 0) { + // Note: This technique sacrifices a block of bytes in order to make the delete implementation simpler + // The on-disk structures do not use this technique within blocks because it would reduce the compaction of every block. + // It is fine for a one-off in-memory structure however. + pRxtHdr->nReserveOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, RXT_LOG2_RESERVE_SIZE); + if (pRxtHdr->nReserveOfs == 0) { + return WFSKRN_RESULT_DIR_BLK_FULL; + } + } + u32 nAttrOfs = (u32)((u8*)pAttrHdr - (u8*)pRxtHdr); + //RxtAttrHdr *pAttrHdr = (RxtAttrHdr *)((u8*)pRxtHdr + nAttrOfs); + RxtNodeHdr *pNodeHdr = pRxi->pNodeHdr; + u16 *pExistingNodeOfsTblEnd = (u16*)((u8*)pNodeHdr + (1<nLog2Size)); + if (pRxtHdr->nNumRecs==0) { + // No records in this directory yet. Add the first record. + pNodeHdr->nStrLen = nSuffixLen; + pNodeHdr->nNumEntries = 1; + u32 nNewLog2Size = RxtGetNodeLog2Size(pNodeHdr); + if (pNodeHdr->nLog2Size != nNewLog2Size) { + u32 nOfs = (u32)((u8*)pNodeHdr - (u8*)pRxtHdr); + dbg(SbaCheckOfs(nOfs)); + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nOfs, pNodeHdr->nLog2Size); + *pRxi->pOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nNewLog2Size); + pNodeHdr = pRxi->pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + *pRxi->pOfs); + //MyOSReport("pRxi->pOfs was updated\n"); + } + pNodeHdr->nLog2Size = nNewLog2Size; + pNodeHdr->nEntryIdx = 0; + pNodeHdr->nParentOfs = 0; + pNodeHdr->nStrLen = nSuffixLen; + pNodeHdr->nNumEntries = 1; + memcpy(pNodeHdr->aFirstChar, pRxi->pStrPtr, (size_t)(pNodeHdr->nStrLen+1)); + RxtSetChildOfs(1, nAttrOfs, pNodeHdr); + pAttrHdr->nParentOfs = pRxtHdr->nRootOfs; + ++pRxtHdr->nNumRecs; +#if (_CHECK_RXT >= 2) + RxtCheck(pRxtHdr, 0, 0); //WFS_LOG2_PATH_CACHE_SIZE, NULL); +#endif + return WFSKRN_RESULT_OK; + } + + // Insert the new name at the location found + // + // To insert a new file name into a directory block requires to allocate up to two new sub blocks + // for name nodes, resize an existing name node, and add a new sub block for file attributes and + // block pointers. It needs to be determined up-front whether this will require splitting the block. + + u32 nNumMatching = (u32)(pRxi->pNodeStrPtr - pNodeHdr->aFirstChar); + u32 nNodeNumLeft = pNodeHdr->nStrLen - nNumMatching; + u16 nNameNodeLog2Size = 0; + u16 nNameNodeOfs; + u16 nForkNodeLog2Size; + u16 nForkNodeOfs; + u16 *pForkNodeOfsTblEnd; + RxtNodeHdr *pNameNodeHdr = 0; + u16 *pAttrOfs = 0; + u8 nEntryIdx; + utf8 cNameChar = pRxi->pStrPtr[0]; + + if (nSuffixLen) { + // allocate a sub block for the new name entry + u32 nNodeStrLen = nSuffixLen-1; + nNameNodeLog2Size = (u16)RxtGetNodeLog2Size_2(nNodeStrLen, 1); + nNameNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nNameNodeLog2Size); + if (nNameNodeOfs == 0) { + return WFSKRN_RESULT_DIR_BLK_FULL; + } + pNameNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nNameNodeOfs); + pNameNodeHdr->nLog2Size = nNameNodeLog2Size; + pNameNodeHdr->nNumEntries = 1; + pNameNodeHdr->nStrLen = (u8)nNodeStrLen; + memcpy(pNameNodeHdr->aFirstChar, &pRxi->pStrPtr[1], nNodeStrLen); + pRxi->pNodeHdr = pNameNodeHdr; + pRxi->pNodeStrPtr = &pNameNodeHdr->aFirstChar[nNodeStrLen]; + *pRxi->pNodeStrPtr = 0; + pAttrOfs = RxtGetChildOfsPtr(1, pNameNodeHdr); + *pAttrOfs = nAttrOfs; + pAttrHdr->nParentOfs = nNameNodeOfs; + } else { + nNameNodeOfs = nAttrOfs; + cNameChar = 0; + } + + if (nNodeNumLeft == 0) { + // Add a new option to the existing node + u16 nUpdatedNodeOfs; + u16 nUpdatedNodeLog2Size = (u16)RxtGetNodeLog2Size_2(pNodeHdr->nStrLen, (u32)(pNodeHdr->nNumEntries+1)); + if (nUpdatedNodeLog2Size != pNodeHdr->nLog2Size) { + // The node needs to be copied to a larger sub block + nUpdatedNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nUpdatedNodeLog2Size); + if (nUpdatedNodeOfs == 0) { + // Allocation failed, so undo any changes so far, split the block, and try again + if (nSuffixLen) { + // Undo the allocation of the name sub block + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nNameNodeOfs, nNameNodeLog2Size); + } + //goto NameNotAllocated; + return WFSKRN_RESULT_DIR_BLK_FULL; + } + RxtNodeHdr *pUpdatedNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nUpdatedNodeOfs); + pUpdatedNodeHdr->nLog2Size = nUpdatedNodeLog2Size; + u16 *pUpdatedNodeOfsTblEnd = (u16*)((u8*)pUpdatedNodeHdr + (1<nEntryIdx; // Note: This code may need to be changed if the RxtNodeHdr struct changes + u8 *pCopySrc = (u8*)&pNodeHdr->nEntryIdx; + s32 nCopySize1 = (u8*)&pNodeHdr->aFirstChar[pNodeHdr->nStrLen + pRxi->nEntryIdx] - pCopySrc; + memcpy(pCopyDst, pCopySrc, nCopySize1); + pCopyDst += nCopySize1; + pCopySrc += nCopySize1; + *pCopyDst++ = (u8)cNameChar; + s32 nCopySize2 = (s32)(pNodeHdr->nNumEntries - pRxi->nEntryIdx); + memcpy(pCopyDst, pCopySrc, (u32)nCopySize2); + pUpdatedNodeHdr->nNumEntries = pNodeHdr->nNumEntries+1; + // Copy the table of child offset pointers from the old block to the new block while inserting the new offset. + // Fix up parent pointers of existing children to point to new location. + u16 *pDst = &pUpdatedNodeOfsTblEnd[-(s32)pUpdatedNodeHdr->nNumEntries]; + u16 *pDstEnd = pDst + nCopySize2; + u16 *pSrcStart = &pExistingNodeOfsTblEnd[-(s32)pNodeHdr->nNumEntries]; + memcpy(pDst, pSrcStart, (u8*)pDstEnd-(u8*)pDst); + nEntryIdx = pNodeHdr->nNumEntries; + while(pDstnParentOfs = nUpdatedNodeOfs; + pChildNodeHdr->nEntryIdx = nEntryIdx--; + } + if (pAttrOfs == 0) { + pAttrOfs = pDst; + pAttrHdr->nParentOfs = nUpdatedNodeOfs; + pRxi->pNodeHdr = pUpdatedNodeHdr; + pRxi->pNodeStrPtr = &pUpdatedNodeHdr->aFirstChar[pUpdatedNodeHdr->nStrLen]; + } + u16 *pOfs = pRxi->pOfs; + pRxi->pOfs = pDst; + *pDst++ = nNameNodeOfs; + if (pNameNodeHdr) { + pNameNodeHdr->nParentOfs = nUpdatedNodeOfs; + pNameNodeHdr->nEntryIdx = nEntryIdx; + } + pSrcStart = &pExistingNodeOfsTblEnd[nCopySize2-pNodeHdr->nNumEntries]; + pDstEnd = pDst + pRxi->nEntryIdx; + memcpy(pDst, pSrcStart, pRxi->nEntryIdx * sizeof(u16)); + while(pDstnParentOfs = nUpdatedNodeOfs; + } + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, *pOfs, pNodeHdr->nLog2Size); + // Fixed node offsets in currently accessing search directory infos. + // ToDo: Fix only when issuing search directory functions. + u32 nJ; + for(nJ = 0; nJ < WFSKRN_MAX_SEARCH_DIR_HANDLES; nJ++) + { + if(wkg.hnd.aSearchDirInfo[nJ].pci.rxi.pNodeHdr == (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + *pOfs)) + wkg.hnd.aSearchDirInfo[nJ].pci.rxi.pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + nUpdatedNodeOfs); + } + *pOfs = nUpdatedNodeOfs; // Update the parent pointer + } else { + // The new option can be added without changing the size of the node + utf8 *pCharInsertPoint = pNodeHdr->aFirstChar + pNodeHdr->nStrLen + pRxi->nEntryIdx; + s32 nCopySize = (s32)(pNodeHdr->nNumEntries - pRxi->nEntryIdx); + memmove(pCharInsertPoint+1, pCharInsertPoint, (u32)nCopySize); + pCharInsertPoint[0] = cNameChar; + u16 *pSrcStart = &pExistingNodeOfsTblEnd[-(s32)pNodeHdr->nNumEntries]; + u16 *pDst = pSrcStart-1; + u16 *pDstEnd = pDst + nCopySize; + memmove(pDst, pSrcStart, sizeof(u16) * nCopySize); + nEntryIdx = pNodeHdr->nNumEntries; + while(pDstnEntryIdx = nEntryIdx--; + } + if (pAttrOfs == 0) { + pAttrOfs = pDst; + pAttrHdr->nParentOfs = (u16)((u8*)pNodeHdr - (u8*)pRxtHdr); + } else { +#if _DEBUG_DIR + if ((pNameNodeHdr==0)||(*pRxi->pOfs != (u8*)pNodeHdr - (u8*)pRxtHdr)) { + WFSKrnOutputErrorStr("RxtInsert: Unexpected"); + } +#endif + //pNameNodeHdr->nParentOfs = *pRxi->pOfs; // Note: Sometimes *pRxi->pOfs points invalid offset. + // ToDo: Comfirm when *pRxi->pOfs points unexpected offset. + pNameNodeHdr->nParentOfs = (u8*)pNodeHdr - (u8*)pRxtHdr; + pNameNodeHdr->nEntryIdx = nEntryIdx; + } + // If allocated a sub block for the new name entry, it is need to update the parent pointer. + if(nSuffixLen) + pRxi->pOfs = pDst; + *pDst = nNameNodeOfs; + ++pNodeHdr->nNumEntries; + } + } else { + // Replace the start of the existing node with a new 2-choice node + // and update the existing node to contain only the end of the string, + // resizing the node if its size drops to a smaller power-of-2 allocation size. + // (note: the resize is compulsory due to the algorithms used elsewhere). + // + // First, try to allocate a sub block for the new 2-choice node. + nForkNodeLog2Size = (u16)RxtGetNodeLog2Size_2(nNumMatching, 2); + nForkNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nForkNodeLog2Size); + if (nForkNodeOfs == 0) { + // Allocation failed, so undo any changes so far, split the block, and try again + if (nSuffixLen) { + // Undo the allocation of the name sub block + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nNameNodeOfs, nNameNodeLog2Size); + } + return WFSKRN_RESULT_DIR_BLK_FULL; + } + RxtNodeHdr *pForkNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nForkNodeOfs); + pForkNodeHdr->nLog2Size = nForkNodeLog2Size; + pForkNodeOfsTblEnd = (u16*)((u8*)pForkNodeHdr + (1<nParentOfs = pNodeHdr->nParentOfs; + pForkNodeHdr->nEntryIdx = pNodeHdr->nEntryIdx; + if (pNameNodeHdr) { + pNameNodeHdr->nParentOfs = nForkNodeOfs; + } + pForkNodeHdr->nNumEntries = 2; + pForkNodeHdr->nStrLen = (u8)nNumMatching; + memcpy(pForkNodeHdr->aFirstChar, pNodeHdr->aFirstChar, nNumMatching); + utf8 cNodeChar = pNodeHdr->aFirstChar[nNumMatching]; + + // Now, update the existing node + u16 nUpdatedNodeOfs; + u16 nUpdatedNodeLog2Size = (u16)RxtGetNodeLog2Size_2(nNodeNumLeft-1, pNodeHdr->nNumEntries); + RxtNodeHdr *pUpdatedNodeHdr; + if (nUpdatedNodeLog2Size != pNodeHdr->nLog2Size) { + // The existing node should be reduced in size. + // First try to allocate a new smaller sub block. + // If this is not possible, then resize in place. + nUpdatedNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nUpdatedNodeLog2Size); + u16 *pUpdatedNodeOfsTblEnd; + u32 nOldNodeOfs = (u16)((u8*)pNodeHdr - (u8*)pRxtHdr); + if (nUpdatedNodeOfs == 0) { + // allocation failed, so resize in place + // shift/copy the end of the string and the following choices backwards over the start of the string + pUpdatedNodeHdr = pNodeHdr; + nUpdatedNodeOfs = (u16)nOldNodeOfs; + pUpdatedNodeOfsTblEnd = (u16*)((u8*)pUpdatedNodeHdr + (1<aFirstChar, &pUpdatedNodeHdr->aFirstChar[nNumMatching+1], nNodeNumLeft + pUpdatedNodeHdr->nNumEntries); + // shift over the table of pointers at the end of the sub block + memmove(&pUpdatedNodeOfsTblEnd[-(s32)pUpdatedNodeHdr->nNumEntries], &pExistingNodeOfsTblEnd[-(s32)pUpdatedNodeHdr->nNumEntries], sizeof(u16) * pUpdatedNodeHdr->nNumEntries); + SbaReduceSubBlkSize((WFSSubBlkAllocHdr *)pRxtHdr, nUpdatedNodeOfs, pNodeHdr->nLog2Size, nUpdatedNodeLog2Size); + } else { + // copy the end of the node to the new node, and free the old node + pUpdatedNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nUpdatedNodeOfs); + // Copy the old choices to the new sub block while inserting the new choice + *((u64*)pUpdatedNodeHdr) = *((u64*)pNodeHdr); // Note: This code may need to be changed if the RxtNodeHdr struct changes + memcpy(pUpdatedNodeHdr->aFirstChar, &pNodeHdr->aFirstChar[nNumMatching+1], nNodeNumLeft + pUpdatedNodeHdr->nNumEntries - 1); + pUpdatedNodeOfsTblEnd = (u16*)((u8*)pUpdatedNodeHdr + (1<nNumEntries]; + u16 *pSrcStart = &pExistingNodeOfsTblEnd[-(s32)pUpdatedNodeHdr->nNumEntries]; + u16 *pDstEnd = pDst + pUpdatedNodeHdr->nNumEntries; + memcpy(pDst, pSrcStart, (u8*)pDstEnd - (u8*)pDst); + while(pDstnParentOfs = nUpdatedNodeOfs; + } + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nOldNodeOfs, pNodeHdr->nLog2Size); + } + } else { + // the sub block remains the same size + pUpdatedNodeHdr = pNodeHdr; + nUpdatedNodeOfs = (u16)((u8*)pUpdatedNodeHdr - (u8*)pRxtHdr); + dbg(SbaCheckOfs(nUpdatedNodeOfs)); + // Remove characters from the start of the string + memmove(pUpdatedNodeHdr->aFirstChar, &pUpdatedNodeHdr->aFirstChar[nNumMatching+1], nNodeNumLeft + pUpdatedNodeHdr->nNumEntries - 1); + } + pUpdatedNodeHdr->nLog2Size = nUpdatedNodeLog2Size; + pUpdatedNodeHdr->nParentOfs = nForkNodeOfs; + pUpdatedNodeHdr->nStrLen = (u8)(nNodeNumLeft-1); + *pRxi->pOfs = nForkNodeOfs; + //pRxi->pNodeHdr = pForkNodeHdr; + if ((unsigned)cNodeChar < (unsigned)cNameChar) { + pForkNodeHdr->aFirstChar[nNumMatching] = cNodeChar; + pForkNodeHdr->aFirstChar[nNumMatching+1] = cNameChar; + pForkNodeOfsTblEnd[-1] = nUpdatedNodeOfs; + pForkNodeOfsTblEnd[-2] = nNameNodeOfs; + pRxi->pOfs = &pForkNodeOfsTblEnd[-2]; + if (pAttrOfs == 0) { + WFSKrnOutputErrorStr("RxtInsert: Unexpected Fork"); + } + pUpdatedNodeHdr->nEntryIdx = 0; + if (pNameNodeHdr) { + pNameNodeHdr->nEntryIdx = 1; + } + } else { + pForkNodeHdr->aFirstChar[nNumMatching] = cNameChar; + pForkNodeHdr->aFirstChar[nNumMatching+1] = cNodeChar; + pForkNodeOfsTblEnd[-1] = nNameNodeOfs; + pForkNodeOfsTblEnd[-2] = nUpdatedNodeOfs; + if (pAttrOfs == 0) { + pAttrOfs = &pForkNodeOfsTblEnd[-1]; + pAttrHdr->nParentOfs = nForkNodeOfs; + pRxi->pNodeHdr = pForkNodeHdr; + pRxi->pNodeStrPtr = &pForkNodeHdr->aFirstChar[pForkNodeHdr->nStrLen]; + } else { + pRxi->pOfs = &pForkNodeOfsTblEnd[-1]; + } + pUpdatedNodeHdr->nEntryIdx = 1; + if (pNameNodeHdr) { + pNameNodeHdr->nEntryIdx = 0; + } + } + } + ++pRxtHdr->nNumRecs; + //pRxi->pOfs = pAttrOfs; + pRxi->pStrPtr += nSuffixLen; +#if (_CHECK_RXT >= 2) + RxtCheck(pRxtHdr, 0, 0); //WFS_LOG2_PATH_CACHE_SIZE, NULL); +#endif + return WFSKRN_RESULT_OK; +} + + +static +u16 RxtMergeNodeWithItsSingleChild(RxtHdr *pRxtHdr, u16 nOldOfs) { + //MyOSReport("RxtMergeNodeWithItsSingleChild: pRxtHdr = %x, nOldOfs = %x\n", pRxtHdr, nOldOfs); +#if _DEBUG_DIR + if (nDirTest == nDirTestBreakPoint) { + int a; a=0; + } +#endif + // A non-leaf node of the radix tree is not allowed to end up with exactly 1 child. This function can be used to merge it with the child. + RxtNodeHdr *pOldNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nOldOfs); + u32 nOldLog2Size = pOldNodeHdr->nLog2Size; //RxtGetNodeLog2Size(pOldNodeHdr); + u16 *pOldNodeOfsTblEnd = (u16*)((u8*)pOldNodeHdr + (1<nLog2Size; + u32 nNewStrLen = (u32)(pOldNodeHdr->nStrLen + pOldChildHdr->nStrLen + 1); + u32 nNewNodeLog2Size = RxtGetNodeLog2Size_2(nNewStrLen, pOldChildHdr->nNumEntries); + if (nOldChildLog2Size == nNewNodeLog2Size) { + memmove(&pOldChildHdr->aFirstChar[pOldNodeHdr->nStrLen+1], pOldChildHdr->aFirstChar, (u32)(pOldChildHdr->nStrLen + pOldChildHdr->nNumEntries)); + memcpy(pOldChildHdr->aFirstChar, pOldNodeHdr->aFirstChar, (u32)(pOldNodeHdr->nStrLen+1)); + pOldChildHdr->nStrLen = (u8)nNewStrLen; + pOldChildHdr->nEntryIdx = pOldNodeHdr->nEntryIdx; + pOldChildHdr->nParentOfs = pOldNodeHdr->nParentOfs; + if (pOldChildHdr->nParentOfs != 0) { + RxtNodeHdr *pParentNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + pOldChildHdr->nParentOfs); + RxtSetChildOfs(pOldChildHdr->nEntryIdx+1, nOldChildOfs, pParentNodeHdr); + } else { + pRxtHdr->nRootOfs = nOldChildOfs; + } + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nOldOfs, nOldLog2Size); + return (u16)nOldChildOfs; + } + // The merged node will require more space than the original, so it must be reallocated + u32 nNewNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nNewNodeLog2Size); + if (nNewNodeOfs == 0) { + // Could not allocate a larger block + return 0; + } + RxtNodeHdr *pNewNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nNewNodeOfs); + u32 nCopySize1 = sizeof(RxtNodeHdr) + pOldNodeHdr->nStrLen; + memcpy(pNewNodeHdr, pOldNodeHdr, nCopySize1); + u32 nCopySize2 = pOldChildHdr->nStrLen + pOldChildHdr->nNumEntries; + memcpy((u8*)pNewNodeHdr + nCopySize1, pOldChildHdr->aFirstChar, nCopySize2); + pNewNodeHdr->nLog2Size = nNewNodeLog2Size; + pNewNodeHdr->nStrLen = (u16)nNewStrLen; + pNewNodeHdr->nNumEntries = pOldChildHdr->nNumEntries; + s32 nNumEntries = (s32)pOldChildHdr->nNumEntries; + u16 *pDstEnd = (u16*)((u8*)pNewNodeHdr + (1<nParentOfs = nNewNodeOfs; + } + if (pOldChildHdr->nParentOfs != 0) { + RxtNodeHdr *pParentNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + pOldNodeHdr->nParentOfs); + RxtSetChildOfs(pOldNodeHdr->nEntryIdx+1, nNewNodeOfs, pParentNodeHdr); + } else { + pRxtHdr->nRootOfs = nNewNodeOfs; + } + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nOldChildOfs, nOldChildLog2Size); + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nOldOfs, nOldLog2Size); + return (u16)nNewNodeOfs; +} + + +WFSKrnResult RxtDeleteNode(RxtHdr *pRxtHdr, RxtItr *pRxi, u32 nEntryIdx, u32 nNodeOfs, RxtNodeHdr *pNodeHdr) { +#if _DEBUG_BREAK_POINT + static int c=0; c++; if(c==0xa842){ + int a; a=0; + } +#endif + //MyOSReport("RxtDeleteNode: pRxtHdr = %x, pRxi = %x, nEntryIdx = %d, nNodeOfs = %x, pNodeHdr = %x\n", pRxtHdr, pRxi, nEntryIdx, nNodeOfs, pNodeHdr); + //MyOSReport("RxtDeleteNode: pRxi->pStrPtr= %s\n", pRxi->pStrPtr); + u16 *pSrcStart = RxtGetChildOfsPtr(pNodeHdr->nNumEntries, pNodeHdr); + // Delete the choice character from the original block + utf8 *pSrc = &pNodeHdr->aFirstChar[pNodeHdr->nStrLen + nEntryIdx]; + memmove(pSrc-1, pSrc, pNodeHdr->nNumEntries - nEntryIdx); + --pNodeHdr->nNumEntries; + u32 nUpdatedNodeLog2Size = RxtGetNodeLog2Size(pNodeHdr); + if (nUpdatedNodeLog2Size != pNodeHdr->nLog2Size) { + u32 nUpdatedNodeOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nUpdatedNodeLog2Size); + if (nUpdatedNodeOfs == 0) { + // Could not allocate a new block, so resize in place + u32 nOldLog2Size = pNodeHdr->nLog2Size; + pNodeHdr->nLog2Size = nUpdatedNodeLog2Size; + u16 *pDst = RxtGetChildOfsPtr(pNodeHdr->nNumEntries, pNodeHdr); + u16 *pDstEnd = RxtGetChildOfsPtr(nEntryIdx-1, pNodeHdr); + u32 nCopySize2 = (u8*)pDstEnd - (u8*)pDst; + memmove(pDst, pSrcStart, nCopySize2); + nEntryIdx = pNodeHdr->nNumEntries; + while(pDstnEntryIdx = --nEntryIdx; + } + if (nEntryIdx) { + pSrcStart = (u16*)((u8*)pSrcStart + nCopySize2 + 2); + memcpy(pDst, pSrcStart, sizeof(u16) * nEntryIdx); + } + SbaReduceSubBlkSize((WFSSubBlkAllocHdr *)pRxtHdr, nNodeOfs, nOldLog2Size, nUpdatedNodeLog2Size); + } else { + // Delete offset pointer while copying to a new sub block + RxtNodeHdr *pUpdatedNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nUpdatedNodeOfs); + u32 nCopySize1 = sizeof(RxtNodeHdr)-1 + pNodeHdr->nStrLen + pNodeHdr->nNumEntries; + memcpy(pUpdatedNodeHdr, pNodeHdr, nCopySize1); + pUpdatedNodeHdr->nLog2Size = nUpdatedNodeLog2Size; + u16 *pDst = RxtGetChildOfsPtr(pNodeHdr->nNumEntries, pUpdatedNodeHdr); + u16 *pDstEnd = RxtGetChildOfsPtr(nEntryIdx-1, pUpdatedNodeHdr); + u32 nCopySize2 = (u8*)pDstEnd - (u8*)pDst; + memcpy(pDst, pSrcStart, nCopySize2); + nEntryIdx = pNodeHdr->nNumEntries; + while(pDstnEntryIdx = --nEntryIdx; + pChildNodeHdr->nParentOfs = nUpdatedNodeOfs; + } + pSrcStart = (u16*)((u8*)pSrcStart + nCopySize2 + 2); + memcpy(pDst, pSrcStart, sizeof(u16) * nEntryIdx); + pDstEnd = pDst + nEntryIdx; + while(pDstnParentOfs = nUpdatedNodeOfs; + } + // Update parent to point to the new node. Parent may be the nRootOfs of the block + if (pUpdatedNodeHdr->nParentOfs != 0) { + RxtNodeHdr *pParentNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + pUpdatedNodeHdr->nParentOfs); + RxtSetChildOfs(pUpdatedNodeHdr->nEntryIdx+1, nUpdatedNodeOfs, pParentNodeHdr); + } else { + pRxtHdr->nRootOfs = nUpdatedNodeOfs; + } + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nNodeOfs, pNodeHdr->nLog2Size); + pNodeHdr = pUpdatedNodeHdr; + nNodeOfs = nUpdatedNodeOfs; + pRxi->pNodeHdr = pUpdatedNodeHdr; + } + } else { + // Delete entry from existing node + u16 *pDst = RxtGetChildOfsPtr(pNodeHdr->nNumEntries, pNodeHdr); + u16 *pDstEnd = RxtGetChildOfsPtr(nEntryIdx-1, pNodeHdr); + memmove(pDst, pSrcStart, (u8*)pDstEnd - (u8*)pDst); + nEntryIdx = pNodeHdr->nNumEntries; + while(pDstnEntryIdx = --nEntryIdx; + } + } + if ((pNodeHdr->nNumEntries==1) && (pNodeHdr->aFirstChar[pNodeHdr->nStrLen] != 0)) { + // The sub block has been left with one entry after deletion. + // If it has a child pointer, it must be concatenated with the child. + u16 nNewOfs = RxtMergeNodeWithItsSingleChild(pRxtHdr, nNodeOfs); + if (nNewOfs == 0) { + if (pRxtHdr->nReserveOfs) { + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, pRxtHdr->nReserveOfs, RXT_LOG2_RESERVE_SIZE); + pRxtHdr->nReserveOfs = 0; + nNewOfs = RxtMergeNodeWithItsSingleChild(pRxtHdr, nNodeOfs); + } + if (nNewOfs == 0) { + // WFSKrnOutputErrorCode(WFSKRN_RESULT_DIR_BLK_FULL); + // ToDo : PathCache tree achieve the error reraly. + // PathCache have to be fixed to the efficient method of delete node and to prevent the error. + MyOSReport("Output error WFSKRN_RESULT_DIR_BLK_FULL in RxtDeleteNode().\n"); + return WFSKRN_RESULT_DIR_BLK_FULL; + } + } + pRxi->pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nNewOfs); + } +#if (_CHECK_RXT >= 2) + RxtCheck(pRxtHdr, 0, 0); //WFS_LOG2_PATH_CACHE_SIZE, NULL); +#endif + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult RxtDelete(RxtHdr *pRxtHdr, RxtItr *pRxi) { + //MyOSReport("RxtDelete: pRxtHdr = %x, pRxi = %x\n", pRxtHdr, pRxi); + //MyOSReport("RxtDelete: pRxi->pStrPtr = %s\n", pRxi->pStrPtr); + --pRxtHdr->nNumRecs; + // Backtrack within leaf block + RxtNodeHdr *pNodeHdr = pRxi->pNodeHdr; + u32 nNodeOfs = (u8*)pNodeHdr - (u8*)pRxtHdr; + u32 nParentOfs, nEntryIdx = 1; //pNodeHdr->nEntryIdx+1; + if (pNodeHdr->nNumEntries==1) { + // This is the only entry in the sub-block. Delete it, and delete the corresponding entry from its parent. + nParentOfs = pNodeHdr->nParentOfs; + nEntryIdx = pNodeHdr->nEntryIdx+1; + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pRxtHdr, nNodeOfs, pNodeHdr->nLog2Size); + if (nNodeOfs == pRxtHdr->nRootOfs) { + // This was the last sub block of the block + // ToDo: Add in a NULL node + return WFSKRN_RESULT_OK; + } + nNodeOfs = nParentOfs; + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + nNodeOfs); + } + return RxtDeleteNode(pRxtHdr, pRxi, nEntryIdx, nNodeOfs, pNodeHdr); +} + +#if (_WIN32 && _DEBUG) + + #include "randomlib.h" + + typedef struct { + u8 aRxtBuf[1<nEntryIdx = 0; + nResult = RxtInsert(rxtg.pRxtHdr, &rxi, nSuffixLen, pAttrHdr); + RxtQuickCheck(nI==18840); + } + } + +#endif diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_EPTree.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_EPTree.cpp new file mode 100644 index 0000000..d25bd66 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_EPTree.cpp @@ -0,0 +1,937 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_EPTree.cpp + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_EPTree.cpp,v $ + Revision 1.5 2008/12/18 08:53:11 ueno + Refactoring to avoid recursive call. + + Revision 1.4 2008/12/17 05:06:49 ueno + Cleanup. + + Revision 1.3 2008/12/15 04:14:40 ueno + Cleanup. + + Revision 1.2 2008/12/15 02:40:07 ueno + Added support for multi p-tree. + + Revision 1.1 2008/12/02 04:55:13 ueno + Added EPTree to support multi-PTree. + + +*---------------------------------------------------------------------------*/ +#include "wfskrn_Area.h" +#include "wfskrn_FTree.h" +#include "wfskrn_FreeBlkAlloc.h" + +#define ROUNDUP32BYTE(val) (((size_t)(val)+31)&~31) +#define ROUNDDOWN(val, unit) ((u32) (val) & ~((unit)-1)) +#define ROUNDUP(val, unit) ((u32) ((val) + ((unit)-1)) & ~((unit)-1)) + +#define FBA_PTREE_MIN_HEIGHT 1 + +typedef struct _EPTreeChildInfo +{ + EPTreeHdr* eptreeHdr; + u32 address; + u32 numEntries; + u32 subTreeType; + u32 firstKey; +} EPTreeChildInfo; + +typedef struct _EPTreeSplitInfo +{ + EPTreeChildInfo right; + EPTreeChildInfo left; + u32 splitKey; + u32 newChild; + u32 totalNumRecs; +} EPTreeSplitInfo; + +EPTreeItr* EPTreeGetLastIter(MEPTreeItr* iter) +{ + ASSERT(iter->eptreeHdr[0]); + u8 height = iter->eptreeHdr[0]->height; + EPTreeItr* last = &iter->epti[height-1]; + return last; +} + +static inline void AllocatorInit(PTreeAllocator* allocator, EPTreeHdr* eptreeHdr) +{ + allocator->pBase = GET_BLOCK_HEAD(eptreeHdr); + allocator->fpAllocNode = FTreeAllocEntry; + allocator->fpAllocNodes = FTreeAllocEntries; + allocator->fpFreeNode = FTreeFreeEntry; +} + +static WFSKrnResult GetAndPinEPTreeHdr(AreaInfo* area, + MEPTreeItr* iter, u32 level, WFSBlkAdr addr, u32 flags) +{ + WFSKrnResult result = WFSKRN_RESULT_OK; + void* block; + + if (level == 0) + { + // root ptree block is already pinned. + return WFSKRN_RESULT_OK; + } + + if (iter->eptreeHdr[level] && + iter->eptreeHdr[level]->addr == addr) + { + return WFSKRN_RESULT_OK; + } + + if (iter->eptreeHdr[level]) + { + ASSERT(iter->eptreeHdr[level]->addr != 0); + FBAUnpinCache(area, iter->eptreeHdr[level]->addr); // unpin old ptree block. + } + + result = FBAGetCache(area, addr, flags, &block); + if (result == WFSKRN_RESULT_OK) + { + iter->eptreeHdr[level] = GET_EPTREEHDR(block); + ASSERT(iter->eptreeHdr[level]->addr == addr); + } + else + { + iter->eptreeHdr[level] = 0; + } + return result; +} + +EPTreeHdr* EPTreeBlockInit(AreaInfo* area, void* block, WFSBlkAdr addr, u32 offset, u8 height) +{ + EPTreeHdr* eptreeHdr; + FTreeSbaInit(area, block, sizeof(EPTreeHdr), offset); + eptreeHdr = GET_EPTREEHDR(block); + eptreeHdr->addr = addr; + eptreeHdr->height = height; + + PTreeInit(&eptreeHdr->ptreeHdr, NULL); // 2nd argument is not used in PTreeInit(). + return eptreeHdr; // keep pinning. +}; + +/* + + * initial state. + +[ToDo] update the figures. + + disk address (FBA_ROOT_BLK). (PLeaf in 8kB) + +----------+ + | sbaHdr | + +----------+ + | PTreeHdr |--->PLeaf + +----------+ +---+---+---+---+ + | PLeaf | | 0 | 0 | 0 | 0 | + +----------+ +---+---+---+---+ + : : | 1 | ? | ? | ? | + : : +---+---+---+---+ + | | + +----------+ + + disk address (FBA_INITIAL_FTREE_BLK) + +----------+ + | sbaHdr | + +- - - - - + + | FTreeHdr | + +----------+ + : empty : + : : + | | + +----------+ + +*/ + +WFSKrnResult EPTreeInit(AreaInfo* pAreaInfo, u32 offset) +{ + WFSKrnResult result; + FTreeHdr* ftreeHdr; + EPTreeHdr* eptreeHdr; + void* cache; + void* eptreeBlock; + + // FBA_ROOT_BLK is already pinned. + + eptreeBlock = (u8*) pAreaInfo->pAflh - offset; // FBA_ROOT_BLK is already pinned. + eptreeHdr = EPTreeBlockInit(pAreaInfo, eptreeBlock, FBA_ROOT_BLK, ROUNDUP32BYTE(offset), FBA_PTREE_MIN_HEIGHT); + + // create an F-tree block. + result = FBAGetCache(pAreaInfo, FBA_INITIAL_FTREE_BLK, BCACHE_FLAG_PINNED | BCACHE_FLAG_DIRTY, &cache); + + if (result == WFSKRN_RESULT_OK) + { + PTreeAllocator allocator; + EPTreeItr epti; + + ftreeHdr = FTreeBlockInit(pAreaInfo, cache); + BCacheUnpin(pAreaInfo->pVolInfo, pAreaInfo->nAbsStartBlkAdr + FBA_INITIAL_FTREE_BLK); + + // +---+---+---+---+ + // | 0 | 0 | 0 | 0 | + // +---+---+---+---+ + // | 1 | ? | ? | ? | + // +---+---+---+---+ + // A + // | + // FBA_INITIAL_FTREE_BLK + + AllocatorInit(&allocator, eptreeHdr); + result = PTreeInsert(&eptreeHdr->ptreeHdr, &epti, 0, FBA_INITIAL_FTREE_BLK, &allocator); + WFSKRN_FTREE_ASSERT(result == WFSKRN_RESULT_OK); + } + + // the EP-tree block is pinned. + return result; +} + +WFSKrnResult EPTreeReinit(AreaInfo* pAreaInfo, u32 offset) +{ + WFSKrnResult result; + EPTreeHdr* eptreeHdr; + void* eptreeBlock; + + // FBA_ROOT_BLK is already pinned. + + eptreeBlock = (u8*) pAreaInfo->pAflh - offset; // FBA_ROOT_BLK is already pinned. + eptreeHdr = EPTreeBlockInit(pAreaInfo, eptreeBlock, FBA_ROOT_BLK, ROUNDUP32BYTE(offset), FBA_PTREE_MIN_HEIGHT); + + PTreeAllocator allocator; + EPTreeItr epti; + + // +---+---+---+---+ + // | 0 | 0 | 0 | 0 | + // +---+---+---+---+ + // | 1 | ? | ? | ? | + // +---+---+---+---+ + // A + // | + // FBA_INITIAL_FTREE_BLK + + // FBA_INITIAL_FTREE_BLK is not initialized, because it may include some freeblocks. + + AllocatorInit(&allocator, eptreeHdr); + result = PTreeInsert(&eptreeHdr->ptreeHdr, &epti, 0, FBA_INITIAL_FTREE_BLK, &allocator); + WFSKRN_FTREE_ASSERT(result == WFSKRN_RESULT_OK); + + // the EP-tree block is pinned. + return result; +} + +// determine the threshold block address. +static u32 GetSplitAddress(PTreeHdr* ptreeHdr, EPTreeItr* iter, PTreeAllocator* allocator) +{ + WFSKrnResult result; + u32 halfNumRecs = ptreeHdr->nNumRecs / 2; + + result = PTreeFirst(ptreeHdr, iter, allocator); + while (halfNumRecs--) + { + result = PTreeNext(ptreeHdr, iter, allocator); + ASSERT(result == WFSKRN_RESULT_OK); + } + + return PTREE_GET_KEY(iter); +} + +static WFSKrnResult GetNewControlBlock(AreaInfo* area, WFSBlkAdr nNGBlkAdr1, WFSBlkAdr nNGBlkAdr2, WFSBlkAdr nRefBlkAdr, FTreeExtent* extent, u32* subTreeIdx) +{ + WFSKrnResult result = WFSKRN_RESULT_NOT_FOUND; + FBATreeItr iter; + FBAItrOpen(area, &iter); + + u32 idx; + for (idx = FTREE_TYPE_A; idx < MAX_SUB_TREE; ++idx) + { + result = FreeBlkFind(area, &iter, nRefBlkAdr, FTreeBlkLog2Ofs[idx]); + while ((result == WFSKRN_RESULT_OK) && + (nNGBlkAdr1 == FBA_RESULT_KEY(&iter) || + nNGBlkAdr2 == FBA_RESULT_KEY(&iter))) + { + result = FreeBlkPrev(area, &iter); + } + if (result == WFSKRN_RESULT_OK) + { + extent->start = FBA_RESULT_KEY(&iter); + extent->len = (FBA_RESULT_DATA(&iter) + 1) * (1<addr = addr; + return eptreeHdr; +} + +// allocate 2 blocks. (must not remove them from FBA tree, because it may cause another p-tree splitting.) +static WFSKrnResult SplitTreeInit(AreaInfo* area, EPTreeHdr* eptreeHdr, EPTreeSplitInfo* info, PTreeAllocator* allocator) +{ + EPTreeItr iter; + WFSKrnResult result; + FTreeExtent newCb; + u32 subTreeIdxNewCb; + + // choose split key. + info->splitKey = GetSplitAddress(&eptreeHdr->ptreeHdr, &iter, allocator); + + result = GetNewControlBlock(area, 0 /* no NG address */, 0 /* no NG address */, + info->splitKey, &newCb, &subTreeIdxNewCb); + ASSERT(result == WFSKRN_RESULT_OK); + + info->left.address = newCb.start; + info->left.subTreeType = subTreeIdxNewCb; + + if (newCb.len == 1) + { + result = GetNewControlBlock(area, info->left.address, 0, newCb.start + 1, &newCb, &subTreeIdxNewCb); + ASSERT(result == WFSKRN_RESULT_OK); + info->right.address = newCb.start; + } + else + { + info->right.address = info->left.address + 1; + } + info->right.subTreeType = subTreeIdxNewCb; + + // height field is only used by root ptree block. + info->left.eptreeHdr = ControlBlockInit(area, info->left.address, eptreeHdr->height); + info->right.eptreeHdr = ControlBlockInit(area, info->right.address, eptreeHdr->height); + + return WFSKRN_RESULT_OK; +} + +static WFSKrnResult CreateChildBlocks(AreaInfo* area, EPTreeSplitInfo* info, PTreeHdr* ptreeHdr, PTreeAllocator* allocatorParent) +{ + WFSKrnResult result; + PTreeAllocator allocator; + PTreeItr ptiSearch; + PTreeItr ptiInsert; + + // insert to left child. + result = PTreeFirst(ptreeHdr, &ptiSearch, allocatorParent); + ASSERT(result == WFSKRN_RESULT_OK); + + AllocatorInit(&allocator, info->left.eptreeHdr); // [ToDo] single ptree. + + info->left.firstKey = PTREE_GET_KEY(&ptiSearch); + int count = ptreeHdr->nNumRecs; + while ((int) (ptreeHdr->nNumRecs - ptreeHdr->nNumRecs / 2) < count) + { + ASSERT(PTREE_GET_KEY(&ptiSearch) < info->splitKey); + result = PTreeInsert(&info->left.eptreeHdr->ptreeHdr, &ptiInsert, + PTREE_GET_KEY(&ptiSearch), PTREE_GET_DATA(&ptiSearch), &allocator); + if (result != WFSKRN_RESULT_OK) + { + ASSERT(result == WFSKRN_RESULT_OK); + goto ERROR_CREATECHILDBLOCKS; + } + + result = PTreeNext(ptreeHdr, &ptiSearch, allocatorParent); + if (result != WFSKRN_RESULT_OK) + { + ASSERT(result == WFSKRN_RESULT_OK); + goto ERROR_CREATECHILDBLOCKS; + } + --count; + } + + ASSERT(result == WFSKRN_RESULT_OK); + + // insert to right child. + info->right.firstKey = PTREE_GET_KEY(&ptiSearch); + AllocatorInit(&allocator, info->right.eptreeHdr); // [ToDo] single ptree. + while (0 < count) + { + ASSERT(info->splitKey <= PTREE_GET_KEY(&ptiSearch)); + result = PTreeInsert(&info->right.eptreeHdr->ptreeHdr, &ptiInsert, + PTREE_GET_KEY(&ptiSearch), PTREE_GET_DATA(&ptiSearch), &allocator); + if (result != WFSKRN_RESULT_OK) + { + ASSERT(result == WFSKRN_RESULT_OK); + goto ERROR_CREATECHILDBLOCKS; + } + + if (--count == 0) + { + break; + } + + ASSERT(result == WFSKRN_RESULT_OK); + result = PTreeNext(ptreeHdr, &ptiSearch, allocatorParent); + if (result != WFSKRN_RESULT_OK) + { + ASSERT(result == WFSKRN_RESULT_OK); + goto ERROR_CREATECHILDBLOCKS; + } + } + +ERROR_CREATECHILDBLOCKS: + return result; +} + +static inline WFSBool IsRootBlock(AreaInfo* area, EPTreeHdr* eptreeHdr) +{ + FBATreeHdr* fbaTreeHdr = GET_FBATREE_HDR(area); + return ((u32) (eptreeHdr->height) == fbaTreeHdr->ptreeHeight); +} + +static WFSKrnResult InsertToParentBlocks(AreaInfo* area, EPTreeHdr* eptreeHdr, EPTreeSplitInfo* info) +{ + WFSKrnResult result; + EPTreeHdr* tempEptreeHdr; + PTreeItr pti; + PTreeAllocator allocator; + + if (IsRootBlock(area, eptreeHdr) == (WFSBool) TRUE) + { + u32 offset; + u32 subTreeIdxTempCb; + u32 originalAddr; + FBATreeHdr* fbaTreeHdr = GET_FBATREE_HDR(area); + FTreeExtent tempCb; + + // create a new level. + ++fbaTreeHdr->ptreeHeight; + ASSERT(fbaTreeHdr->ptreeHeight <= EPTREE_MAX_HEIGHT); + + + result = GetNewControlBlock(area, info->left.address, info->right.address, + 1, &tempCb, &subTreeIdxTempCb); + ASSERT(result == WFSKRN_RESULT_OK); + + tempEptreeHdr = ControlBlockInit(area, tempCb.start, (u8) (fbaTreeHdr->ptreeHeight)); + + // copy original parent ptree. + memmove((u8*) GET_BLOCK_FROM_EPTREEHDR(tempEptreeHdr), GET_BLOCK_FROM_EPTREEHDR(eptreeHdr), area->nBlkSize); + + // clear all entries + offset = eptreeHdr->sbaHdr.offset; + EPTreeBlockInit(area, GET_BLOCK_FROM_EPTREEHDR(tempEptreeHdr), tempCb.start, offset, (u8) (fbaTreeHdr->ptreeHeight)); + + // insert child blocks into the parent. + AllocatorInit(&allocator, tempEptreeHdr); + + result = PTreeInsert(&tempEptreeHdr->ptreeHdr, &pti, info->left.firstKey, info->left.address, &allocator); + ASSERT(result == WFSKRN_RESULT_OK); + + result = PTreeInsert(&tempEptreeHdr->ptreeHdr, &pti, info->right.firstKey, info->right.address, &allocator); + ASSERT(result == WFSKRN_RESULT_OK); + + originalAddr = eptreeHdr->addr; + memmove(GET_BLOCK_FROM_EPTREEHDR(eptreeHdr), GET_BLOCK_FROM_EPTREEHDR(tempEptreeHdr), area->nBlkSize); // remap + eptreeHdr->addr = originalAddr; + FBAFreeCache(area, tempCb.start); // unpin the temporary parent block. + } + else + { + // insert the split key into the parent block. + AllocatorInit(&allocator, eptreeHdr); + result = PTreeInsert(&eptreeHdr->ptreeHdr, &pti, info->splitKey, 1, &allocator); + } + + // remove left and right child blocks from the FBA tree. + return result; +} + +static WFSKrnResult EPTreeSplit(AreaInfo* area, MEPTreeItr* iter, EPTreeHdr* eptreeHdr, EPTreeSplitInfo* info) +{ + WFSKrnResult result; + PTreeAllocator allocator; + + if (EPTREE_MAX_HEIGHT == iter->eptreeHdr[0]->height) + { + return WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED; + } + + AllocatorInit(&allocator, eptreeHdr); + + result = SplitTreeInit(area, eptreeHdr, info, &allocator); + if (result != WFSKRN_RESULT_OK) + { + return result; + } + + // split the original block to two children. + result = CreateChildBlocks(area, info, &eptreeHdr->ptreeHdr, &allocator); + + FBAUnpinCache(area, info->left.address); + FBAUnpinCache(area, info->right.address); + + if (result != WFSKRN_RESULT_OK) + { + return result; + } + + // create new parent block and remap it to the original block. + result = InsertToParentBlocks(area, eptreeHdr, info); + if (result == WFSKRN_RESULT_OK) + { + FBATreeItr iterDelete; + + FBAItrOpen(area, &iterDelete); + iterDelete.fti.subTree = FTreeSelectSubTree(iterDelete.ftreeHdr, info->left.subTreeType); + + // remove child block address from the FBA tree. + result = FreeBlkDelete(area, &iterDelete, + info->left.address, 1, FTreeBlkLog2Ofs[info->left.subTreeType]); + ASSERT(result == WFSKRN_RESULT_OK); + + iterDelete.fti.subTree = FTreeSelectSubTree(iterDelete.ftreeHdr, info->right.subTreeType); + result = FreeBlkDelete(area, &iterDelete, + info->right.address, 1, FTreeBlkLog2Ofs[info->right.subTreeType]); + ASSERT(result == WFSKRN_RESULT_OK); + + FBAItrClose(area, &iterDelete); + } + + return result; +} + +WFSKrnResult EPTreeFirst(AreaInfo* area, MEPTreeItr* iter) +{ + WFSKrnResult result; + PTreeAllocator allocator; + int level; + u8 ptreeHeight; + + AllocatorInit(&allocator, iter->eptreeHdr[0]); + result = PTreeFirst(&iter->eptreeHdr[0]->ptreeHdr, (PTreeItr*) &iter->epti[0], &allocator); + + ptreeHeight = iter->eptreeHdr[0]->height; + for (level = 1; level < ptreeHeight; ++level) + { + if (result != WFSKRN_RESULT_OK) + { + break; + } + + result = GetAndPinEPTreeHdr(area, iter, level, + EPTREE_GET_DATA(&iter->epti[level-1]), BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + + if (result != WFSKRN_RESULT_OK) + { + break; + } + + AllocatorInit(&allocator, iter->eptreeHdr[level]); + result = PTreeFirst(&iter->eptreeHdr[level]->ptreeHdr, (PTreeItr*) &iter->epti[level], &allocator); + } + + return result; +} + +WFSKrnResult EPTreeLast(AreaInfo* area, MEPTreeItr* iter) +{ + WFSKrnResult result; + PTreeAllocator allocator; + int level; + u8 ptreeHeight; + + AllocatorInit(&allocator, iter->eptreeHdr[0]); + result = PTreeLast(&iter->eptreeHdr[0]->ptreeHdr, (PTreeItr*) &iter->epti[0], &allocator); + + ptreeHeight = iter->eptreeHdr[0]->height; + for (level = 1; level < ptreeHeight; ++level) + { + if (result != WFSKRN_RESULT_OK) + { + break; + } + + result = GetAndPinEPTreeHdr(area, iter, level, + EPTREE_GET_DATA(&iter->epti[level-1]), BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + + if (result != WFSKRN_RESULT_OK) + { + break; + } + + AllocatorInit(&allocator, iter->eptreeHdr[level]); + result = PTreeLast(&iter->eptreeHdr[level]->ptreeHdr, (PTreeItr*) &iter->epti[level], &allocator); + } + + return result; +} + +WFSKrnResult EPTreeNext(AreaInfo* area, MEPTreeItr* iter) +{ + WFSKrnResult result = WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; + PTreeAllocator allocator; + EPTreeHdr* eptreeHdr; + u8 ptreeHeight = iter->eptreeHdr[0]->height; + + eptreeHdr = iter->eptreeHdr[ptreeHeight-1]; + + AllocatorInit(&allocator, eptreeHdr); + result = PTreeNext(&eptreeHdr->ptreeHdr, (PTreeItr*) &iter->epti[ptreeHeight-1], &allocator); + if (result == WFSKRN_RESULT_PTREE_ENTRY_FOUND) + { + return result; + } + + // go back and lookup an entry in the next node. + int level = ptreeHeight; + while (result == WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND && --level) + { + eptreeHdr = iter->eptreeHdr[level-1]; + AllocatorInit(&allocator, eptreeHdr); + result = PTreeNext(&eptreeHdr->ptreeHdr, (PTreeItr*) &iter->epti[level-1], &allocator); + } + + if (result == WFSKRN_RESULT_OK) + { + for (;level < ptreeHeight; ++level) + { + result = GetAndPinEPTreeHdr(area, iter, level, + EPTREE_GET_DATA(&iter->epti[level-1]), BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result != WFSKRN_RESULT_OK) + { + break; + } + eptreeHdr = iter->eptreeHdr[level]; + AllocatorInit(&allocator, eptreeHdr); + result = PTreeFirst(&eptreeHdr->ptreeHdr, (PTreeItr*) &iter->epti[level], &allocator); + if (result != WFSKRN_RESULT_OK) + { + break; + } + } + } + + return result; +} + +WFSKrnResult EPTreePrev(AreaInfo* area, MEPTreeItr* iter) +{ + WFSKrnResult result = WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; + PTreeAllocator allocator; + EPTreeHdr* eptreeHdr; + u8 ptreeHeight = iter->eptreeHdr[0]->height; + + eptreeHdr = iter->eptreeHdr[ptreeHeight-1]; + + AllocatorInit(&allocator, eptreeHdr); + result = PTreePrev(&eptreeHdr->ptreeHdr, (PTreeItr*) &iter->epti[ptreeHeight-1], &allocator); + if (result == WFSKRN_RESULT_PTREE_ENTRY_FOUND) + { + return result; + } + + // go back and lookup an entry in the next node. + int level = ptreeHeight; + while (result == WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND && --level) + { + eptreeHdr = iter->eptreeHdr[level-1]; + AllocatorInit(&allocator, eptreeHdr); + result = PTreePrev(&eptreeHdr->ptreeHdr, (PTreeItr*) &iter->epti[level-1], &allocator); + } + + if (result == WFSKRN_RESULT_OK) + { + for (;level < ptreeHeight; ++level) + { + result = GetAndPinEPTreeHdr(area, iter, level, + EPTREE_GET_DATA(&iter->epti[level-1]), BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result != WFSKRN_RESULT_OK) + { + break; + } + eptreeHdr = iter->eptreeHdr[level]; + AllocatorInit(&allocator, eptreeHdr); + result = PTreeLast(&eptreeHdr->ptreeHdr, (PTreeItr*) &iter->epti[level], &allocator); + if (result != WFSKRN_RESULT_OK) + { + break; + } + } + } + + return result; +} + +static WFSKrnResult EPTreeInsertWithoutSplitting(AreaInfo* area, MEPTreeItr* iter, u32 key, u32 data) +{ + WFSKrnResult result; + EPTreeHdr* eptreeHdr; + EPTreeItr* epti; + PTreeAllocator allocator; + u8 height; + + result = EPTreeFind(area, iter, key); + if (result == WFSKRN_RESULT_OK) + { + return WFSKRN_RESULT_ALREADY_EXISTS; + } + + if (result != WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND) + { + return result; + } + + height = iter->eptreeHdr[0]->height; + epti = &iter->epti[height-1]; + eptreeHdr = iter->eptreeHdr[height-1]; + + AllocatorInit(&allocator, eptreeHdr); + result = PTreeInsert(&eptreeHdr->ptreeHdr, (PTreeItr*) epti, key, data, &allocator); + return result; +} + +WFSKrnResult EPTreeInsert(AreaInfo* area, MEPTreeItr* iter, u32 key, u32 data) +{ + WFSKrnResult result; + while (WFSKRN_RESULT_PTREE_FULL == (result = EPTreeInsertWithoutSplitting(area, iter, key, data))) + { + EPTreeSplitInfo info; + result = EPTreeSplit(area, (MEPTreeItr*) iter, iter->eptreeHdr[0], &info); + if (result != WFSKRN_RESULT_OK) + { +#ifdef _DEBUG + OS_TPrintf("*** EPTreeInsert(): split error (%d) ***\n", result); +#endif // _DEBUG + ASSERT(result == WFSKRN_RESULT_OK || + result == WFSKRN_RESULT_DIRECTORY_QUOTA); + break; + } + } + return result; +} + +static WFSKrnResult DelteEmptyBlocks(AreaInfo* area, MEPTreeItr* iter, WFSBlkAdr* freeBlks) +{ + WFSKrnResult result = WFSKRN_RESULT_OK; + EPTreeHdr* eptreeHdr; + EPTreeItr* epti; + PTreeAllocator allocator; + + WFSBlkAdr addr; + int level; + int height = (int) iter->eptreeHdr[0]->height; + for (level = height - 2; 0 <= level; --level) + { + eptreeHdr = iter->eptreeHdr[level]; + + epti = &iter->epti[level]; + addr = EPTREE_GET_DATA(epti); + AllocatorInit(&allocator, eptreeHdr); + result = PTreeDelete(&eptreeHdr->ptreeHdr, (PTreeItr*) epti, &allocator); + if (result != WFSKRN_RESULT_OK) + { + break; + } + iter->eptreeHdr[level+1] = 0; + FBAFreeCache(area, addr); + freeBlks[level] = addr; // save to insert it into FBA tree, later. + if (0 < eptreeHdr->ptreeHdr.nNumRecs) + { + break; + } + } + return result; +} + +WFSKrnResult EPTreeShrink(AreaInfo* area, MEPTreeItr* iter, WFSBlkAdr* freeBlks) +{ + WFSKrnResult result = EPTreeLast(area, iter); + if (result == WFSKRN_RESULT_OK) + { + u32 height = (u32) iter->eptreeHdr[0]->height; + EPTreeItr* epti = EPTreeGetLastIter(iter); + if (EPTREE_GET_DATA(epti) == FBA_INITIAL_FTREE_BLK && + EPTREE_GET_KEY(epti) == 0) + { + MEPTreeItr iterInsert; + iterInsert.eptreeHdr[0] = GET_EPTREEHDR_FROM_AREAINFO(area); + u32 level; + for (level = 1; level < EPTREE_MAX_HEIGHT; ++level) + { + iterInsert.eptreeHdr[level] = 0; + } + + FBATreeHdr* fbaTreeHdr = GET_FBATREE_HDR(area); + fbaTreeHdr->ptreeHeight = 1; + u32 offset = area->nBlkSize - GET_FBATREE_HDR(area)->ofsEPtreeHdr - sizeof(EPTreeHdr); + EPTreeReinit(area, ROUNDUP32BYTE(offset)); + + for (level = 0; level < (int) height; ++level) + { + u32 addr = iter->epti[level].nData; + if (addr != FBA_INITIAL_FTREE_BLK) + { + FBAFreeCache(area, addr); + freeBlks[level + (EPTREE_MAX_HEIGHT-1)] = addr; + } + } + } + } + return result; +} + +WFSKrnResult EPTreeDelete(AreaInfo* area, MEPTreeItr* iter, u32 key, WFSBlkAdr* freeBlks) +{ + WFSKrnResult result; + EPTreeHdr* eptreeHdr; + PTreeAllocator allocator; + + result = EPTreeFind(area, iter, key); + if (result == WFSKRN_RESULT_OK || + result == WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND) // not found? + { + u8 height = iter->eptreeHdr[0]->height; + EPTreeItr* epti = &iter->epti[height-1]; + eptreeHdr = iter->eptreeHdr[height-1]; + + AllocatorInit(&allocator, eptreeHdr); + result = PTreeDelete(&eptreeHdr->ptreeHdr, (PTreeItr*) epti, &allocator); + if (eptreeHdr->ptreeHdr.nNumRecs <= 1 && 2 <= height) + { + if (eptreeHdr->ptreeHdr.nNumRecs == 0) + { + result = DelteEmptyBlocks(area, iter, freeBlks); + if (result == WFSKRN_RESULT_OK) + { + result = EPTreeShrink(area, iter, freeBlks); + } + } + else if (epti->pLeaf->aKey[0] == 0 && + epti->pLeaf->aData[0] == FBA_INITIAL_FTREE_BLK) + { + // eptreeHdr->ptreeHdr.nNumRecs == 1. + result = EPTreeShrink(area, iter, freeBlks); + } + } + } + return result; +} + +// search a P-tree by key. +/* + P-tree node + +-----------------+ + | P-Tree | + |key: 100 | + | | + +-----------------+ + | | + p-tree leaf V V p-tree leaf + +-----------------+ +-----------------+ + | P-Tree | | P-Tree | + |key: 80 96 | |key: 110 116 119 | + | | | | + +-----------------+ +-----------------+ + A A A A + | | | | + (1) (2) (3) (4) + + key result pPti->nKey + (1) 101 => WFSKRN_RESULT_NOT_FOUND - (no value is set). + (2) 110 => WFSKRN_RESULT_OK 110 + (3) 118 => WFSKRN_RESULT_OK 116 + (4) 120 => WFSKRN_RESULT_OK 119 +*/ +WFSKrnResult EPTreeFind(AreaInfo* area, MEPTreeItr* iter, u32 key) +{ + WFSKrnResult result = WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; + PTreeAllocator allocator; + EPTreeHdr* eptreeHdr; + EPTreeItr* epti; + int level; + u8 ptreeHeight = iter->eptreeHdr[0]->height; + + for (level = 0; level < ptreeHeight; ++level) + { + eptreeHdr = iter->eptreeHdr[level]; + AllocatorInit(&allocator, eptreeHdr); + result = PTreeFind(&eptreeHdr->ptreeHdr, (PTreeItr*) &iter->epti[level], key, &allocator); + + epti = &iter->epti[level]; + if (result == WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND) + { + if (iter->eptreeHdr[level]->ptreeHdr.nNumRecs == 0) + { + result = WFSKRN_RESULT_PTREE_EMPTY; + goto RESULT_EPTREEFIND; + } + else if (epti->aEntryIdx[0] == 0) + { + // the key is smaller than the minimum key in this P-tree. + result = EPTreePrev(area, iter); + if (result != WFSKRN_RESULT_OK) + { + result = WFSKRN_RESULT_NOT_FOUND; + goto RESULT_EPTREEFIND; + } + if (key == EPTREE_GET_KEY(epti)) + { + result = WFSKRN_RESULT_PTREE_ENTRY_FOUND; + } + else + { + result = WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; + } + } + else + { + // In this case, PTreeFind() saved the nearest key. + --epti->aEntryIdx[0]; + } + } + + if (result != WFSKRN_RESULT_PTREE_ENTRY_FOUND && + result != WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND) + { + break; + } + + epti->nKey = epti->pLeaf->aKey[epti->aEntryIdx[0]]; + epti->nData = epti->pLeaf->aData[epti->aEntryIdx[0]]; + + if (level == ptreeHeight - 1) + { + // the bottom of multi EP-Tree. + break; + } + + result = GetAndPinEPTreeHdr(area, iter, level + 1, EPTREE_GET_DATA(epti), BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result != WFSKRN_RESULT_OK) + { + break; + } + } + + if (result == WFSKRN_RESULT_PTREE_ENTRY_FOUND) + { + result = WFSKRN_RESULT_OK; + } + +RESULT_EPTREEFIND: + return result; +} + diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Errors.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Errors.cpp new file mode 100644 index 0000000..8a98460 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Errors.cpp @@ -0,0 +1,216 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Errors.cpp + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Errors.cpp,v $ + Revision 1.13 2008/09/28 23:32:04 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.12 2008/09/04 23:53:04 nakanose_jin + wfsdev has no pathcache. + + Revision 1.11 2008/08/27 23:23:28 ooizumi + Fixed newline to CR+LF(Windows format). + + Revision 1.10 2008/08/27 09:38:04 paul + Added error messages. small change to error output. + + Revision 1.9 2008/07/11 18:04:54 paul + Updated to match latest error defs + + Revision 1.8 2008/07/09 00:43:54 paul + Renamed some error messages. Added software breakpoint for nDbgCommandCount. + + Revision 1.7 2008/07/02 06:34:57 nakanose_jin + temporary edit + + Revision 1.6 2008/06/10 20:12:44 kondo_masahiro + Fixed WFSKrnCommandCountBreak. + + Revision 1.5 2008/06/09 17:51:14 paul + Added support for logging calls to WFSSrv functions. + Added new error codes. + + Revision 1.4 2008/05/10 03:59:34 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.3 2008/04/25 17:35:50 kondo_masahiro + Fixed log information + + Revision 1.2 2008/04/25 12:07:44 nakanose_jin + add new errors + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.7 2008/04/25 04:35:37 nakanose_jin + add new errors + + Revision 1.6 2008/04/22 23:22:39 paul + Made errors match laters wfskrn_Errors.h + + Revision 1.5 2008/04/19 05:50:45 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.4 2008/04/04 21:18:58 paul + Added \n to error message + + Revision 1.3 2008/02/27 07:24:29 paul + Updated error strings + + Revision 1.2 2008/02/27 00:37:24 paul + Fixed a typo + + Revision 1.1 2008/02/21 00:49:14 paul + *** empty log message *** + + *---------------------------------------------------------------------------*/ + + +#include "wfskrn_Defs.h" +#include "wfskrn_Errors.h" + +#if _DEBUG + u32 nDbgCommandCount = 0; + u32 nDbgCommandOutputStart = 0; //15520; //(u32)-1; + u32 nDbgCommandOutputEnd = (u32)-1; + u32 nDbgCommandCountBreak = (u32)-1; +#if _WIN32 + FILE *fpLog; +#endif +#endif //_DEBUG + +const char *WFSKrnGetErrorString( WFSKrnResult nResult ) { + const char *p; + switch(nResult) { + case WFSKRN_RESULT_OK :p="OK" ; break; + case WFSKRN_RESULT_BUSY :p="BUSY" ; break; + case WFSKRN_RESULT_OUT_OF_MEMORY :p="OUT_OF_MEMORY" ; break; + case WFSKRN_RESULT_INVALID :p="INVALID" ; break; + case WFSKRN_RESULT_ACCESS :p="ACCESS" ; break; + case WFSKRN_RESULT_LIB_NOT_INITIALIZED :p="LIB_NOT_INITIALIZED" ; break; + case WFSKRN_RESULT_LIB_ALREADY_INITIALIZED :p="LIB_ALREADY_INITIALIZED" ; break; + case WFSKRN_RESULT_FILE_TOO_BIG :p="FILE_TOO_BIG" ; break; + case WFSKRN_RESULT_NO_CHANGE_SIZE :p="NO_CHANGE_SIZE" ; break; + case WFSKRN_RESULT_MEDIA_ERROR :p="MEDIA_ERROR" ; break; + case WFSKRN_RESULT_DEV_UNUSABLE :p="DEV_UNUSABLE" ; break; + case WFSKRN_RESULT_DEV_NOT_INITIALIZED :p="DEV_NOT_INITIALIZED" ; break; + case WFSKRN_RESULT_DEV_IN_USE :p="DEV_IN_USE" ; break; + case WFSKRN_RESULT_VOL_ID_ERROR :p="VOL_ID_ERROR" ; break; + case WFSKRN_RESULT_WRITE_PROTECTED :p="WRITE_PROTECTED" ; break; + case WFSKRN_RESULT_ALREADY_MOUNTED :p="ALREADY_MOUNTED" ; break; + case WFSKRN_RESULT_PERMISSION :p="PERMISSION" ; break; + case WFSKRN_RESULT_PERMISSION_CL :p="PERMISSION_CL" ; break; + case WFSKRN_RESULT_ACL_FULL :p="ACL_FULL" ; break; + case WFSKRN_RESULT_ACL_ENTRY_NOT_FOUND :p="ACL_ENTRY_NOT_FOUND" ; break; + case WFSKRN_RESULT_AUTHENTICATION :p="AUTHENTICATION" ; break; + case WFSKRN_RESULT_CORRUPTION :p="CORRUPTION" ; break; + case WFSKRN_RESULT_DIRECTORY_QUOTA :p="DIRECTORY_QUOTA" ; break; + case WFSKRN_RESULT_MAX_HANDLES :p="MAX_HANDLES" ; break; + case WFSKRN_RESULT_ALREADY_EXISTS :p="ALREADY_EXISTS" ; break; + case WFSKRN_RESULT_NOT_FOUND :p="NOT_FOUND" ; break; + case WFSKRN_RESULT_NOT_EMPTY :p="NOT_EMPTY" ; break; + case WFSKRN_RESULT_NOT_FILE :p="NOT_FILE" ; break; + case WFSKRN_RESULT_NOT_DIRECTORY :p="NOT_DIRECTORY" ; break; + case WFSKRN_RESULT_FILE_OPEN :p="FILE_OPEN" ; break; + case WFSKRN_RESULT_LOCKED :p="LOCKED" ; break; + case WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED :p="RESOURCE_LIMIT_EXCEEDED" ; break; + case WFSKRN_RESULT_DIR_ENTRY_FOUND :p="DIR_ENTRY_FOUND" ; break; + case WFSKRN_RESULT_DIR_NODE_STRING_PREFIX :p="DIR_NODE_STRING_PREFIX" ; break; + case WFSKRN_RESULT_DIR_CHOICE_PREFIX :p="DIR_CHOICE_PREFIX" ; break; + case WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH :p="DIR_NODE_STRING_MISMATCH" ; break; + case WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND :p="DIR_NODE_CHOICE_NOT_FOUND" ; break; + case WFSKRN_RESULT_DIR_BLK_FULL :p="DIR_BLK_FULL" ; break; + case WFSKRN_RESULT_SRV_END_OF_PATH :p="SRV_END_OF_PATH" ; break; + case WFSKRN_RESULT_SRV_PATH_DEPTH_1 :p="SRV_PATH_DEPTH_1" ; break; + case WFSKRN_RESULT_SRV_PATH_DEV :p="SRV_PATH_DEV" ; break; + case WFSKRN_RESULT_SRV_PATH_VOL :p="SRV_PATH_VOL" ; break; + case WFSKRN_RESULT_SRV_PATH_VOL_ROOT :p="SRV_PATH_VOL_ROOT" ; break; + case WFSKRN_RESULT_PTREE_ENTRY_FOUND :p="PTREE_ENTRY_FOUND" ; break; + case WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND :p="PTREE_ENTRY_NOT_FOUND" ; break; + case WFSKRN_RESULT_PTREE_FULL :p="PTREE_FULL" ; break; + case WFSKRN_RESULT_DEVICE_ERROR :p="DEVICE_ERROR" ; break; + case WFSKRN_RESULT_DEVICE_INVALID_PARAMETER :p="DEVICE_INVALID_PARAMETER" ; break; + case WFSKRN_RESULT_DEVICE_NOT_FOUND :p="DEVICE_INVALID_PARAMETER" ; break; + case WFSKRN_RESULT_BLK_CACHE_ALLOC_FAILED :p="BLK_CACHE_ALLOC_FAILED" ; break; + case WFSKRN_RESULT_BCACHE_ERROR :p="BCACHE_ERROR" ; break; + case WFSKRN_RESULT_BCACHE_RESOURCE_LIMIT :p="BCACHE_RESOURCE_LIMIT" ; break; + case WFSKRN_RESULT_BCACHE_INVALID_PARAMETER :p="BCACHE_INVALID_PARAMETER" ; break; + case WFSKRN_RESULT_BCACHE_NO_MEMORY :p="BCACHE_NO_MEMORY" ; break; + case WFSKRN_RESULT_BCACHE_NOT_FOUND :p="BCACHE_NOT_FOUND" ; break; + case WFSKRN_RESULT_BCACHE_MAX_DEVICES :p="BCACHE_MAX_DEVICES" ; break; + case WFSKRN_RESULT_BCACHE_INVALID_DEVICE :p="BCACHE_INVALID_DEVICE" ; break; + case WFSKRN_RESULT_BCACHE_INVALID_HANDLE :p="BCACHE_INVALID_HANDLE" ; break; + case WFSKRN_RESULT_BCACHE_INVALID_VOLUME :p="BCACHE_INVALID_VOLUME" ; break; + case WFSKRN_RESULT_BCACHE_ALREADY_MAPPED :p="BCACHE_ALREADY_MAPPED" ; break; + case WFSKRN_RESULT_BCACHE_ALLOC :p="BCACHE_ALLOC" ; break; + case WFSKRN_RESULT_BCACHE_HASH_BLK_NOT_MAPPED :p="BCACHE_PMEM" ; break; + case WFSKRN_RESULT_VOLUME_ERROR :p="VOLUME_ERROR" ; break; + case WFSKRN_RESULT_VOLUME_INVALID_PARAMETER :p="VOLUME_INVALID_PARAMETER" ; break; + case WFSKRN_RESULT_VOLUME_BCACHE_ALLOC :p="VOLUME_BCACHE_ALLOC" ; break; + case WFSKRN_RESULT_VOLUME_BCACHE_CONFIG :p="VOLUME_BCACHE_CONFIG" ; break; + //case WFSKRN_RESULT_VOLUME_ID :p="VOLUME_ID" ; break; + //case WFSKRN_RESULT_VOLUME_CORRUPT_MR :p="VOLUME_CORRUPT_MR" ; break; + //case WFSKRN_RESULT_VOLUME_AREA_ALLOC :p="VOLUME_AREA_ALLOC" ; break; + //case WFSKRN_RESULT_VOLUME_DEVICE_PARAMETER :p="VOLUME_DEVICE_PARAMETER" ; break; + //case WFSKRN_RESULT_VOLUME_NOT_MAPPED :p="VOLUME_NOT_MAPPED" ; break; + case WFSKRN_RESULT_TRANSACTION_ERROR :p="TRANSACTION_ERROR" ; break; + case WFSKRN_RESULT_TRANSACTION_INVALID_PARAMETER:p="TRANSACTION_INVALID_PARAMETER"; break; + case WFSKRN_RESULT_ACL_ERROR :p="ACL_ERROR" ; break; + case WFSKRN_RESULT_ACL_INVALID_PARAMETER :p="ACL_INVALID_PARAMETER" ; break; + case WFSKRN_RESULT_ACL_MAX_ENTRIES :p="ACL_MAX_ENTRIES" ; break; + case WFSKRN_RESULT_ACL_CACHE :p="ACL_CACHE" ; break; + case WFSKRN_RESULT_ACL_FILE :p="ACL_FILE" ; break; + case WFSKRN_RESULT_ACL_FILENAME :p="ACL_FILENAME" ; break; + case WFSKRN_RESULT_ACL_HANDLE :p="ACL_HANDLE" ; break; + case WFSKRN_RESULT_AREA_ERROR :p="AREA_ERROR" ; break; + case WFSKRN_RESULT_AREA_INVALID_PARAMETER :p="AREA_INVALID_PARAMETER" ; break; + case WFSKRN_RESULT_AREA_BCACHE_ALLOC :p="AREA_BCACHE_ALLOC" ; break; + case WFSKRN_RESULT_NOT_IMPLEMENTED :p="NOT_IMPLEMENTED" ; break; + case WFSKRN_RESULT_UNKNOWN :p="UNKNOWN" ; break; + case WFSKRN_RESULT_FATAL_ERROR :p="FATAL_ERROR" ; break; + default: p="???" ;break ; + } + return p; +} + +WFSKrnResult WFSKrnOutputErrorCode(WFSKrnResult nResult) { +#if _DEBUG + MyOSReport("%d. Error: (%d) WFSKRN_RESULT_%s\n", nDbgCommandCount, nResult, WFSKrnGetErrorString(nResult) ); +#endif + if (nResult != WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND) { + return nResult; + } + WFSKrnDbgOutputClose(); + return nResult; +} + +void PathCacheDebugOutput(); + +WFSKrnResult WFSKrnOutputErrorStr(const char *pStr) { +#if _DEBUG + MyOSReport("%d. %s\n", nDbgCommandCount, pStr); + WFSKrnDbgOutputClose(); +#endif + return WFSKRN_RESULT_UNKNOWN; +} + +void WFSKrnCommandCountBreak() { +#if _DEBUG + if(nDbgCommandCount >= nDbgCommandCountBreak) { +#ifndef WFSDEV + PathCacheDebugOutput(); +#endif + int a; a=0; + } +#endif +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_FTree.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_FTree.cpp new file mode 100644 index 0000000..b4fd48c --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_FTree.cpp @@ -0,0 +1,2118 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_FTree.cpp + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_FTree.cpp,v $ + Revision 1.20 2008/12/18 08:37:04 ueno + Cleanup. + + Revision 1.19 2008/12/18 00:31:27 ueno + Moved FTreeBlkLog2Ofs{} for IOP. + + Revision 1.18 2008/12/17 05:06:49 ueno + Cleanup. + + Revision 1.17 2008/12/15 00:57:39 ueno + Modified to prevent from overwriting a new F-tree block. + + Revision 1.16 2008/10/14 10:27:14 kondo_masahiro + Added #define _DEBUG_BREAK_POINT + + Revision 1.15 2008/10/09 12:51:03 ueno + Fixed FTreeInsert(). + + Revision 1.14 2008/10/03 08:37:56 kondo_masahiro + Fixed codes for porting IOP + + Revision 1.12 2008/09/30 05:55:52 ueno + Cleanup. + + Revision 1.10 2008/09/29 10:19:36 ueno + Revised to support multi-B-tree-based allocator. + + Revision 1.9 2008/09/29 01:57:23 ueno + Modified RemapControlBlocks() not to copy hash and flags. + + Revision 1.8 2008/09/28 23:32:04 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.17 2008/09/29 01:58:57 ueno + Modified to call BCacheInvalidateBlks() in FreeBlkFree() to invalidate caches of user data. + + Revision 1.7 2008/09/02 07:00:45 kondo_masahiro + Fixed VerifyMemoryBlock -> VerifyMemoryBlockFTree + + Revision 1.6 2008/08/09 03:32:51 ueno + Disabled runtime check. + + Revision 1.5 2008/08/09 02:01:41 ueno + Cleanup. + + Revision 1.4 2008/08/07 10:46:33 ueno + Modified for BTREE_BASED_ALLOCATOR (now debugging). + + Revision 1.3 2008/08/02 11:52:40 ueno + Revised the positions of FTreeHdr{} and FBAPTreeHdr{} in 8KB-blocks to protect hash code. + + Revision 1.2 2008/08/01 07:00:05 ueno + Added copyrights. + + Revision 1.1 2008/08/01 06:57:39 ueno + Initial Check-in. + +*---------------------------------------------------------------------------*/ +#include "wfskrn_Area.h" +#if BTREE_BASED_ALLOCATOR + +#include "wfskrn_FreeBlkAlloc.h" +#include "wfskrn_FTree.h" + +#ifdef FBA_DEBUG_VERBOSE +extern WFSBool FBADebugVerbose; +#endif // FBA_DEBUG_VERBOSE + +#define ROUNDUP32BYTE(val) (((size_t)val+31)&~31) +#define IS_OUT_OF_RANGE(pLeaf, key) ((key) < (u32*) (pLeaf)) + +typedef struct _ChildInfo +{ + FTreeHdr* ftreeHdr; + u32 address; + u32 numEntries[PTREE_MAX_HEIGHT+1]; + u32 totalEntries; // leaves and nodes. + u32 firstEntry; // byte offset of the first leaf (or node). + u32 firstKey; // the minimum key in the tree. + u32 nRootHeight; + u16 nNumRecs; // the number of keys in the tree. + u16 nRootOfs; +} ChildInfo; + +typedef struct _SplitInfo +{ + ChildInfo right; + ChildInfo left; + u32 splitKey; + u32 newChild; + u32 newChildSubTreeType; + u32 totalNumRecs; +} SplitInfo; + +const u32 FTreeBlkLog2Ofs[MAX_SUB_TREE+1] = +{ + FTREE_LOG2_OFS_A, + FTREE_LOG2_OFS_B, + FTREE_LOG2_OFS_C, + FTREE_LOG2_OFS_D, + FTREE_LOG2_OFS_E, + FTREE_LOG2_OFS_F, + FTREE_LOG2_OFS_G, + FTREE_LOG2_OFS_END +}; + +// p-tree +WFSKrnResult PTreeInsertIntoNode(PTreeHdr *pPTreeHdr, PTreeItr *pPti, u32 nKey, u32 *pChildOfs, PTreeAllocator *pAllocator); +u32 PTreeFindLeafOfs(PTreeHdr *pPTreeHdr, PTreeItr *pPti, u32 nKey, PTreeAllocator *pAllocator); +u32 PTreeGetOfs(void *pNode, PTreeAllocator *pAllocator); +PTreeLeaf *PTreeGetLeaf(PTreeAllocator *pAllocator, u32 nOfs); +PTreeNode *PTreeGetNode(PTreeAllocator *pAllocator, u32 nOfs); + +// for BCache +static WFSBool VerifySBA(FTreeHdr* header); +static WFSBool VerifyTree(FTreeHdr* header); + +PTreeHdr* FTreeSelectSubTree(FTreeHdr* header, WFSBlkAdr unitLen) +{ + PTreeHdr* subTree; + + // An extent in lower subtree will be frequently referred. + if (unitLen == FTREE_LOG2_OFS_A) + { + subTree = &header->tree[0]; + } + else if (unitLen == FTREE_LOG2_OFS_B) + { + subTree = &header->tree[1]; + } + else if (unitLen == FTREE_LOG2_OFS_C) + { + subTree = &header->tree[2]; + } + else if (unitLen == FTREE_LOG2_OFS_D) + { + subTree = &header->tree[3]; + } + else if (unitLen == FTREE_LOG2_OFS_E) + { + subTree = &header->tree[4]; + } + else if (unitLen == FTREE_LOG2_OFS_F) + { + subTree = &header->tree[5]; + } + else if (unitLen == FTREE_LOG2_OFS_G) + { + subTree = &header->tree[6]; + } + else + { + // must not reach here. + WFSKRN_FTREE_ASSERT(0); + return NULL; + } + return subTree; +} + +static inline void LEAF_SET_LEN(FTreeLeaf* pLeaf, u32 index, u32 value) +{ + u32 mask = 0xf << (4 * index); + pLeaf->data &= ~mask; + pLeaf->data |= ((value & 0x0f) << (4 * (index))); +} + +static inline u16 GetOfs(FTreeHdr* header, void* subblock) +{ + WFSKRN_FTREE_ASSERT(GET_BLOCK_HEAD(header) < (FTreeBlock*)subblock); // kondo_masahiro 08/08/15 + WFSKRN_FTREE_ASSERT((FTreeHdr*)subblock < header); // kondo_masahiro 08/08/15 + return (u16) ((u8*) subblock - (u8*) GET_BLOCK_HEAD(header)); +} + +static inline void AllocatorInit(PTreeAllocator* allocator, FTreeHdr* header) +{ + allocator->pBase = GET_BLOCK_HEAD(header); + allocator->fpAllocNode = FTreeAllocEntry; + allocator->fpAllocNodes = FTreeAllocEntries; + allocator->fpFreeNode = FTreeFreeEntry; +} + +static inline FTreeLeaf* FTreeGetLeaf(FTreeHdr* header, u16 ofs) +{ + return (FTreeLeaf*) GET_SUBBLOCK(header, ofs); +} + +/* + + If key[n] <= nKey = key[n+1], return key[n]. + + If key[last] <= nKey < key[0]_of_the_next_leaf, return key[last]. + + leaf the next leaf + |---------------------| |---------------------| + 0 1 2 3 4 0 1 2 3 + |--->|---->|----->|-->|------>|------->|---->|----->|- - -> + + +SearchKey(): +search the leaf for the specified key. +If the key is found, return the ponter to the key. (c) +If not found, return the nearest key which is smaller then the specified key. (b, d) +Note that the key returned may not be in the leaf. (a) + + leaf + |---------------------| + 0 1 2 3 4 + |--->|---->|----->|-->| + A A A A + | | | | +(a) (b) (c) (d) <--- the specified key. + + return value (k_result) + (a) k_result < k0 + (b) k_result = k1 + (c) k_result = k3 + (d) k_result = k4 + +*/ +static inline u32* SearchKey(FTreeLeaf *pLeaf, u32 nKey) +{ + u32* key; + key = &pLeaf->aKey[3]; + if (nKey < *key || *key == 0) + { + key -= 2; // &pLeaf->aKey[1]; + } + else + { + key += 2; // &pLeaf->aKey[5]; + } + + // [1] or [5] + if (nKey < *key || *key == 0) + { + --key; // [0] or [4]. + if (nKey < *key || *key == 0) + { + if (pLeaf->aKey[0] == 0 && key == &pLeaf->aKey[0]) + { + // [0] is a valid key. + } + else + { + --key; // error or [3]. + } + } + } + else + { + ++key; // [2] or [6] + if (nKey < *key || *key == 0) + { + --key; // [1] or [5]. + } + } + return key; +} + +// +// split F-tree block. +// + +// calculate the number of nodes and leaves in the new F-tree. +static WFSKrnResult EstimateNewTree(ChildInfo* childInfo) +{ + u32 count; + u32 level = 0; + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(childInfo->ftreeHdr)); + + childInfo->numEntries[level] = (childInfo->nNumRecs + FTREE_LEAF_APPROPRIATE_NUM-1) / (FTREE_LEAF_APPROPRIATE_NUM); + count = childInfo->numEntries[0]; // the number of leaves. + while (1 < childInfo->numEntries[level]) + { + childInfo->numEntries[level+1] = (childInfo->numEntries[level] + FTREE_NODE_APPROPRIATE_NUM) / (FTREE_NODE_APPROPRIATE_NUM + 1); + count += childInfo->numEntries[level+1]; // add the number of nodes in (level + 1). + ++level; + if (PTREE_MAX_HEIGHT - 1 < level) + { + return WFSKRN_RESULT_PTREE_FULL; // cannot split. It must not happen... + } + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(childInfo->ftreeHdr)); + } + childInfo->nRootHeight = level; + childInfo->numEntries[++level] = 0; // this level does not exist. + + childInfo->totalEntries = count; // leaves and nodes. + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(childInfo->ftreeHdr)); + return WFSKRN_RESULT_OK; +} + +// determine the threshold block address. +static u32 GetSplitAddress(FTreeHdr* header, FTreeItr* iter) +{ + WFSKrnResult result; + u32 halfNumRecs; + int index; + int indexMajority = -1; + int nNumRecsMax = 0; + PTreeHdr* subTree; + + // search majority. + for (index = 0; index < MAX_SUB_TREE; ++index) + { + subTree = &header->tree[index]; + + if (nNumRecsMax < subTree->nNumRecs) + { + nNumRecsMax = subTree->nNumRecs; + indexMajority = index; + } + } + + WFSKRN_FTREE_ASSERT(0 <= indexMajority && nNumRecsMax != 0); + iter->subTree = &header->tree[indexMajority]; + + halfNumRecs = iter->subTree->nNumRecs / 2; + result = FTreeFirst(header, iter); // [check] error handling. + WFSKRN_FTREE_ASSERT(result == WFSKRN_RESULT_OK); + while (halfNumRecs--) + { + result = FTreeNext(header, iter); // [check] error handling. + WFSKRN_FTREE_ASSERT(result == WFSKRN_RESULT_OK); + } + + return FTREE_GET_KEY(iter); +} + +static WFSKrnResult GetTemporaryControlBlock(FTreeHdr* header, FTreeItr* iter, u32 key) +{ + WFSKrnResult result = WFSKRN_RESULT_NOT_FOUND; + result = FTreeFind(header, iter, key, (WFSBool) FALSE); + WFSKRN_FTREE_ASSERT(result == WFSKRN_RESULT_OK); // key must be found, because the subtree has the most entry. + return result; +} + +static FTreeHdr* ControlBlockInit(AreaInfo* area, u32 addr) +{ + void* pBlock; + FTreeHdr* hdr; + + WFSKrnResult result = FBAGetCache(area, addr, BCACHE_FLAG_DIRTY | BCACHE_FLAG_PINNED, &pBlock); + if (result != WFSKRN_RESULT_OK) + { + return NULL; + } + FTreeBlockInit(area, pBlock); + + hdr = GET_FTREEHDR(pBlock); + return hdr; +} + +// prepare split. +static WFSKrnResult SplitTreeInit(AreaInfo* area, FTreeHdr* header, SplitInfo* splitInfo) +{ + FTreeItr iter; + WFSKrnResult result; + + splitInfo->splitKey = GetSplitAddress(header, &iter); + + result = GetTemporaryControlBlock(header, &iter, splitInfo->splitKey); + WFSKRN_FTREE_ASSERT(result == WFSKRN_RESULT_OK); + + splitInfo->right.address = FTREE_GET_KEY(&iter); + if (FTREE_GET_DATA(&iter) == 0 && + iter.subTree == &header->tree[FTREE_TYPE_A]) + { + // need one more block for the left child. + result = FTreeNext(header, &iter); + WFSKRN_FTREE_ASSERT(result == WFSKRN_RESULT_OK); + splitInfo->left.address = FTREE_GET_KEY(&iter); + } + else + { + splitInfo->left.address = splitInfo->right.address + 1; + } + + splitInfo->right.ftreeHdr = ControlBlockInit(area, splitInfo->right.address); + splitInfo->left.ftreeHdr = ControlBlockInit(area, splitInfo->left.address); + + return WFSKRN_RESULT_OK; +} + +static void InsertToLeafAtOnce(FTreeLeaf* leaf, u32* key, u32* data, u32 num) +{ + int i; + + leaf->data = 0; + for (i = 0; i < num; ++i) + { + WFSKRN_FTREE_ASSERT(data[i] < 16); + leaf->aKey[i] = key[i]; + leaf->data |= ((data[i] & 0xf) << 4 * i); + + // the root area can be larger than 16GB. + WFSKRN_FTREE_ASSERT(key[i] < 1024 * 1024 * 1024); // [check] 8TB. + /* + WFSKRN_FTREE_ASSERT(key[i] < 1024 * 1024 * 2); // the maximum area size is 16GB, for now. + // 2 * 1024 * 1024 means 16GB (= 2 * 1k * 1k * 8KB). + */ + } + + for (;i < FTREE_LEAF_FAN_OUT; ++i) + { + leaf->aKey[i] = 0; + } +} + +static inline u32 GetKey(FTreeHdr* child, ChildInfo* childInfo, u32 index) +{ + u32 ofs = childInfo->firstEntry + (index / 5) * sizeof(FTreeBlock); // [check] hard-coding. + WFSKRN_FTREE_ASSERT(ofs < BLOCK_SIZE); + WFSKRN_FTREE_ASSERT(sizeof(WFSMetaDataFlags) + sizeof(WFSHashCode) <= ofs); + FTreeLeaf* pLeaf = FTreeGetLeaf(child, ofs); + u32 key = pLeaf->aKey[index % 5]; // [check] hard-coding. + + return key; +} + +// connect nodes in a new F-tree block. +static WFSKrnResult LinkNodes(FTreeHdr* child, ChildInfo* childInfo) +{ + PTreeNode* node = 0; // kondo_masahiro 08/08/15 + FTreeBlock* block; + u32 height; + u32 index; // key index + u32 lastIndex; + int count; + u32 numNodes; + WFSKrnResult result; + + int i; + u32 factor = 5; // [check] hard-coding. + u32 leafOfs; + u32 ofsLeaves = childInfo->numEntries[0] * sizeof(FTreeBlock); + block = GET_SUBBLOCK(child, childInfo->firstEntry + ofsLeaves); + + lastIndex = childInfo->nNumRecs; + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(childInfo->ftreeHdr)); + + numNodes = childInfo->totalEntries - childInfo->numEntries[0]; + if (numNodes == 0) + { + if (0 < childInfo->totalEntries) + { + childInfo->nRootOfs = childInfo->firstEntry; + } + return WFSKRN_RESULT_OK; + } + result = FTreeAllocEntries(GET_BLOCK_HEAD(child), NULL, numNodes); + if (result != WFSKRN_RESULT_OK) + { + return result; + } + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(childInfo->ftreeHdr)); + + leafOfs = childInfo->firstEntry; + for (height = 1; height <= childInfo->nRootHeight; ++height) + { + index = 0; + count = childInfo->numEntries[height]; + u32 numChild = childInfo->numEntries[height-1]; + while (count--) + { + index += factor; + node = (PTreeNode*) block; + ++block; + memset(&node->aKey[0], 0, sizeof(node->aKey)); + +#ifdef FBA_DEBUG_VERBOSE + FTreeLeaf* pLeaf = 0; + if (FBADebugVerbose) + { + OS_TPrintf("node ofs %d\n", (u8*) node - (u8*) GET_BLOCK_HEAD(child)); + } +#endif // FBA_DEBUG_VERBOSE + + if (numChild == 1) + { + // If child is only one, pass through. + + /* pass through node + PTreeNode + +-----+-----+ - - + | 0 | 0 | + +---+---+---+ - - + |ofs| 0 | 0 + +---+---+---+ - - + */ +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + pLeaf = (FTreeLeaf*) GET_SUBBLOCK(child, leafOfs); + } +#endif // FBA_DEBUG_VERBOSE + node->aOfs[0] = leafOfs; + node->aOfs[1] = 0; + leafOfs += sizeof(FTreeBlock); + +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + OS_TPrintf("key : %5d, ofs : %5d, leaf key[0] %d\n", + node->aKey[0], node->aOfs[0], pLeaf->aKey[0]); + OS_TPrintf(" ofs : %5d\n\n", node->aOfs[1]); + } +#endif // FBA_DEBUG_VERBOSE + } + else + { + for (i = 0; i < FTREE_NODE_APPROPRIATE_NUM && 1 < numChild; ++i) + { + if (lastIndex < index && factor * (i+1) <= lastIndex) + { + index = factor * (i+1); + } + + node->aKey[i] = GetKey(child, childInfo, index); + node->aOfs[i] = leafOfs; +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + pLeaf = (FTreeLeaf*) GET_SUBBLOCK(child, leafOfs); + OS_TPrintf("key : %5d, ofs : %5d, leaf key[0] %d\n", + node->aKey[i], node->aOfs[i], pLeaf->aKey[0]); + + WFSKRN_FTREE_ASSERT(leafOfs < BLOCK_SIZE); + } +#endif // FBA_DEBUG_VERBOSE + leafOfs += sizeof(FTreeBlock); + index += factor; + --numChild; + } + + --numChild; + node->aOfs[i] = leafOfs; +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + pLeaf = (FTreeLeaf*) GET_SUBBLOCK(child, leafOfs); + OS_TPrintf(" ofs : %5d, leaf key[0] %d\n\n", + node->aOfs[i], pLeaf->aKey[0]); + } +#endif // FBA_DEBUG_VERBOSE + leafOfs += sizeof(FTreeBlock); + } + } + + lastIndex = (childInfo->nNumRecs / factor) * factor; + factor *= 5; // hard-coding. + } + childInfo->nRootOfs = GetOfs(child, node); + WFSKRN_FTREE_ASSERT(childInfo->nRootOfs < BLOCK_SIZE); + return WFSKRN_RESULT_OK; +} + +static WFSKrnResult AllocMiddleBlock(FTreeHdr* right, SplitInfo* splitInfo, WFSBlkAdr ngAddr) +{ + WFSKrnResult result = WFSKRN_RESULT_UNKNOWN; + FTreeItr iter; + u32 halfNumRecs; + u32 subTreeIndex = 0; + + iter.subTree = &right->tree[subTreeIndex]; + + while (subTreeIndex < FTREE_TYPE_END) + { + iter.subTree = &right->tree[subTreeIndex]; + if (0 < iter.subTree->nNumRecs) + { + halfNumRecs = iter.subTree->nNumRecs / 2; + result = FTreeFirst(right, &iter); + while (halfNumRecs-- && result == WFSKRN_RESULT_OK) + { + result = FTreeNext(right, &iter); + } + if (ngAddr == FTREE_GET_KEY(&iter) && + result == WFSKRN_RESULT_OK) + { +#ifdef _DEBUG + OS_TPrintf("*** prevent from overwriting the left block. ***\n"); +#endif // _DEBUG + result = FTreeNext(right, &iter); + } + break; + } + ++subTreeIndex; + } + + if (subTreeIndex == FTREE_TYPE_END) + { + return WFSKRN_RESULT_FTREE_EMPTY; + } + + if (result == WFSKRN_RESULT_OK) + { + // It is ok even if + // splitInfo->newChild == splitInfo.right.address or + // splitInfo->newChild == splitInfo.left.address. + // Because FBA remaps splitInfo.left.address to the original, then + // remaps splitInfo.right.address to splitInfo->newChild. + splitInfo->newChild = FTREE_GET_KEY(&iter); + splitInfo->newChildSubTreeType = subTreeIndex; + } + + return result; +} + +/* + header (original) left child (temporary) + +---------+ +---------+ + | | remap | | + | 8kb|<----------| 8kb| + +---------+ +---------+ + + right child (new) right child (temporary) + +---------+ +---------+ + | | remap | | + | 8kb|<----------| 8kb| + +---------+ +---------+ + + The new right child is in the middle of the right child area. + */ + +static WFSKrnResult RemapControlBlocks(AreaInfo* area, FTreeHdr* header, SplitInfo* splitInfo) +{ + WFSKrnResult result; + FTreeHdr* newRight; + void* tmpBlock; + void* newBlock; + + result = AllocMiddleBlock(splitInfo->right.ftreeHdr, splitInfo, splitInfo->left.address); + + WFSKRN_FTREE_ASSERT(result == WFSKRN_RESULT_OK); + + if (result == WFSKRN_RESULT_OK) + { + u32 offset = sizeof(WFSMetaDataFlags) + sizeof(WFSHashCode); // to keep hash and flag in 8KB block. + + result = FBAGetCache(area, splitInfo->newChild, BCACHE_FLAG_DIRTY | BCACHE_FLAG_PINNED, &newBlock); + WFSKRN_FTREE_ASSERT(result == WFSKRN_RESULT_OK); + + newRight = GET_FTREEHDR(newBlock); + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(splitInfo->right.ftreeHdr)); + + // remap left child, first. + // splitInfo->left.address may be reused as a splitInfo->newChild. + tmpBlock = GET_BLOCK_HEAD(splitInfo->left.ftreeHdr); + memmove((u8*) GET_BLOCK_HEAD(header) + offset, (u8*) tmpBlock + offset, area->nBlkSize - offset); // [check] must use BCache API. + FBAFreeCache(area, splitInfo->left.address); + + // remap right child. + tmpBlock = GET_BLOCK_HEAD(splitInfo->right.ftreeHdr); + memmove((u8*) newBlock + offset, (u8*) tmpBlock + offset, area->nBlkSize - offset); + FBAFreeCache(area, splitInfo->right.address); + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(newRight)); + + FBAUnpinCache(area, splitInfo->newChild); // unpin the new child block. + } + return result; +} + +static inline WFSKrnResult InsertKeysToLeaf(FTreeHdr* header, SplitInfo* splitInfo, FTreeHdr* child, int count, FTreeItr* iter, u32* numKeys) +{ + u32 key[FTREE_LEAF_APPROPRIATE_NUM]; + u32 data[FTREE_LEAF_APPROPRIATE_NUM]; + u32 offset; + int index = 0; + FTreeLeaf* leaf; + WFSKrnResult result = WFSKRN_RESULT_UNKNOWN; + + *numKeys = 0; + while (count--) + { + key[index] = FTREE_GET_KEY(iter); + data[index] = FTREE_GET_DATA(iter); + if (index == FTREE_LEAF_APPROPRIATE_NUM-1) + { + // insert + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(splitInfo->right.ftreeHdr)); + + offset = FTreeAllocEntry(GET_BLOCK_HEAD(child)); + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(splitInfo->right.ftreeHdr)); + + leaf = FTreeGetLeaf(child, offset); + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(splitInfo->right.ftreeHdr)); + + InsertToLeafAtOnce(leaf, key, data, FTREE_LEAF_APPROPRIATE_NUM); + *numKeys += FTREE_LEAF_APPROPRIATE_NUM; + index = 0; + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(splitInfo->right.ftreeHdr)); + } + else + { + ++index; + } + + result = FTreeNext(header, iter); + if (result != WFSKRN_RESULT_OK) + { + break; + } + } + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(splitInfo->right.ftreeHdr)); + + if (0 < index) + { + // remainder + offset = FTreeAllocEntry(GET_BLOCK_HEAD(child)); + leaf = FTreeGetLeaf(child, offset); + InsertToLeafAtOnce(leaf, key, data, index); + *numKeys += index; + } + + splitInfo->right.nNumRecs = *numKeys; + if (count == 0) + { + result = WFSKRN_RESULT_OK; + } + + return result; +} + +static WFSKrnResult CreateLeavesRight(FTreeHdr* header, SplitInfo* splitInfo, FTreeItr* iter) +{ + FTreeHdr* child; + int count; + u32 numKeys; + WFSKrnResult result = WFSKRN_RESULT_OK; + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(splitInfo->right.ftreeHdr)); + + child = splitInfo->right.ftreeHdr; + splitInfo->right.firstEntry = splitInfo->right.ftreeHdr->sbaHdr.offset + splitInfo->right.ftreeHdr->sbaHdr.freeBlock * sizeof(FTreeBlock); + + count = splitInfo->totalNumRecs - splitInfo->left.nNumRecs; + if (0 < count) + { + result = InsertKeysToLeaf(header, splitInfo, child, count, iter, &numKeys); + } + else + { + splitInfo->right.nNumRecs = 0; + } + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(splitInfo->right.ftreeHdr)); + return result; +} + +static WFSKrnResult CreateLeavesLeft(FTreeHdr* header, SplitInfo* splitInfo, FTreeItr* iter) +{ + u32 key[FTREE_LEAF_APPROPRIATE_NUM]; + u32 data[FTREE_LEAF_APPROPRIATE_NUM]; + WFSKrnResult result; + FTreeHdr* child; + FTreeLeaf* leaf; + u32 numKeys = 0; + int index = 0; + u32 offset; + + if (iter->subTree->nNumRecs == 0) + { + // this subtree is empty. // [check] must check this routine. + splitInfo->left.nNumRecs = 0; + return WFSKRN_RESULT_OK; + } + + splitInfo->left.firstEntry = splitInfo->left.ftreeHdr->sbaHdr.offset + splitInfo->left.ftreeHdr->sbaHdr.freeBlock * sizeof(FTreeBlock); + child = splitInfo->left.ftreeHdr; + + result = FTreeFirst(header, iter); + if (result != WFSKRN_RESULT_OK) + { + return result; + } + + while (FTREE_GET_KEY(iter) < splitInfo->splitKey) + { + key[index] = FTREE_GET_KEY(iter); + data[index] = FTREE_GET_DATA(iter); + if (index == FTREE_LEAF_APPROPRIATE_NUM-1) + { + // insert + offset = FTreeAllocEntry(GET_BLOCK_HEAD(child)); + + leaf = FTreeGetLeaf(child, offset); + InsertToLeafAtOnce(leaf, key, data, FTREE_LEAF_APPROPRIATE_NUM); + numKeys += FTREE_LEAF_APPROPRIATE_NUM; + index = 0; + } + else + { + ++index; + } + + result = FTreeNext(header, iter); + if (result != WFSKRN_RESULT_OK) + { + break; + } + } + + if (0 < index) + { + // remainder + offset = FTreeAllocEntry(GET_BLOCK_HEAD(child)); + leaf = FTreeGetLeaf(child, offset); + InsertToLeafAtOnce(leaf, key, data, index); + numKeys += index; + } + + splitInfo->left.nNumRecs = numKeys; + + if (result != WFSKRN_RESULT_OK) + { + if (iter->subTree->nNumRecs == numKeys) + { + result = WFSKRN_RESULT_OK; + } + } + + return result; +} + +static WFSKrnResult CreateRightChild(FTreeHdr* header, SplitInfo* splitInfo, FTreeItr* iter, int treeType) +{ + WFSKrnResult result; + PTreeHdr* subtree; + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(splitInfo->right.ftreeHdr)); + + result = CreateLeavesRight(header, splitInfo, iter); // [check] error handling. + if (result != WFSKRN_RESULT_OK) + { + goto CREATERIGHTCHILD_ERROR; + } + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(splitInfo->right.ftreeHdr)); + + result = EstimateNewTree(&splitInfo->right); // [check] name should be geometry?? + if (result != WFSKRN_RESULT_OK) + { + goto CREATERIGHTCHILD_ERROR; + } + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(splitInfo->right.ftreeHdr)); + + result = LinkNodes(splitInfo->right.ftreeHdr, &splitInfo->right); // [check] error handling. + if (result != WFSKRN_RESULT_OK) + { + goto CREATERIGHTCHILD_ERROR; + } + + WFSKRN_FTREE_RUNTIME_CHECK(VerifySBA(splitInfo->right.ftreeHdr)); + + subtree = GET_SUBTREE(splitInfo->right.ftreeHdr, treeType); + subtree->nRootHeight = splitInfo->right.nRootHeight; + subtree->nRootOfs = splitInfo->right.nRootOfs; + subtree->nNumRecs = splitInfo->right.nNumRecs; + +CREATERIGHTCHILD_ERROR: + return result; +} + +static WFSKrnResult CreateLeftChild(FTreeHdr* header, SplitInfo* splitInfo, FTreeItr* iter, int treeType) +{ + WFSKrnResult result; + PTreeHdr* subtree; + + iter->subTree = GET_SUBTREE(header, treeType); + + result = CreateLeavesLeft(header, splitInfo, iter); // [check] error handling. + if (result != WFSKRN_RESULT_OK) + { + goto CREATELEFTCHILD_ERROR; + } + + result = EstimateNewTree(&splitInfo->left); // [check] name should be geometry?? + if (result != WFSKRN_RESULT_OK) + { + goto CREATELEFTCHILD_ERROR; + } + + result = LinkNodes(splitInfo->left.ftreeHdr, &splitInfo->left); // [check] error handling. + if (result != WFSKRN_RESULT_OK) + { + goto CREATELEFTCHILD_ERROR; + } + + subtree = GET_SUBTREE(splitInfo->left.ftreeHdr, treeType); + subtree->nRootHeight = splitInfo->left.nRootHeight; + subtree->nRootOfs = splitInfo->left.nRootOfs; + subtree->nNumRecs = splitInfo->left.nNumRecs; + +CREATELEFTCHILD_ERROR: + return result; +} + +/* + nodes (lv.3) + nodes (lv.2) + nodes (lv.1) + leaves (lv.0) +*/ + +static WFSKrnResult SplitTree(AreaInfo* area, FTreeHdr* header, FTreeItr* iter) +{ + WFSKrnResult result; + FTreeItr searchIter; + SplitInfo splitInfo; + int treeType; + +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + OS_TPrintf("[SPLIT TREE]\n"); + } +#endif // FBA_DEBUG_VERBOSE + + // prepare two 8kB-blocks for left and right child-blocks. + // (Both blocks are used as a work buffer.) + result = SplitTreeInit(area, header, &splitInfo); + if (result != WFSKRN_RESULT_OK) + { + return result; + } + + for (treeType = FTREE_TYPE_A; treeType < FTREE_TYPE_G; ++treeType) + { + splitInfo.totalNumRecs = header->tree[treeType].nNumRecs; + result = CreateLeftChild(header, &splitInfo, &searchIter, treeType); + if (result != WFSKRN_RESULT_OK) + { + return result; // [check] + } + result = CreateRightChild(header, &splitInfo, &searchIter, treeType); + if (result != WFSKRN_RESULT_OK) + { + return result; // [check] + } + } + // remap control blocks. + result = RemapControlBlocks(area, header, &splitInfo); + + iter->splitKey = splitInfo.splitKey; + iter->newChild = splitInfo.newChild; + iter->newChildSubTreeType = splitInfo.newChildSubTreeType; + +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + OS_TPrintf("newChild block address %u\n", iter->newChild); + } +#endif // FBA_DEBUG_VERBOSE + + return result; +} + +static WFSKrnResult SplitLeaf(AreaInfo* area, FTreeHdr* header, FTreeItr* iter, FTreeLeaf** ppLeaf, u32 nKey) +{ + FTreeLeaf* pLeaf = *ppLeaf; + FTreeLeaf* pNewLeaf; + u32 nOfs; + u32 key; + WFSKrnResult result; + + // [check] should refine. + if (pLeaf->aKey[4] < nKey) + { + key = pLeaf->aKey[4]; + } + else if (pLeaf->aKey[3] < nKey) + { + key = nKey; + } + else + { + key = pLeaf->aKey[3]; + } + + PTreeAllocator allocator; + AllocatorInit(&allocator, header); + nOfs = GetOfs(header, pLeaf); + WFSKRN_FTREE_ASSERT(nOfs < area->nBlkSize); + result = PTreeInsertIntoNode(iter->subTree, &iter->ptree, key, &nOfs, &allocator); + if (result == WFSKRN_RESULT_PTREE_FULL) + { + WFSKRN_FTREE_RUNTIME_CHECK(VerifyTree(header)); + // split 8kB block. + result = SplitTree(area, header, iter); // WFSKRN_RESULT_FTREE_RETRY or WFSKRN_RESULT_FTREE_SPLIT + // the history in iter became ivalid. retry. + WFSKRN_FTREE_RUNTIME_CHECK(VerifyTree(header)); + if (result == WFSKRN_RESULT_OK) + { + result = WFSKRN_RESULT_FTREE_RETRY; + } + return result; + } + pNewLeaf = (FTreeLeaf*) PTreeGetLeaf(&allocator, nOfs); + + if (pLeaf->aKey[3] < nKey) + { + // left child : key[0]-[3]. + // right child: key[4]-[6] <-- insert nKey later. + memmove(&pNewLeaf->aKey[0], &pLeaf->aKey[4], 3 * sizeof(u32)); + pNewLeaf->data = (pLeaf->data >> 16); + memset(&pLeaf->aKey[4], 0, 3 * sizeof(u32)); + memset(&pNewLeaf->aKey[3], 0, 4 * sizeof(u32)); + pLeaf = pNewLeaf; + } + else + { + // left child : key[0]-[2] <-- insert nKey later. + // right child: key[3]-[6]. + memmove(&pNewLeaf->aKey[0], &pLeaf->aKey[3], 4 * sizeof(u32)); + pNewLeaf->data = (pLeaf->data >> 12); + memset(&pLeaf->aKey[3], 0, 4 * sizeof(u32)); + memset(&pNewLeaf->aKey[4], 0, 3 * sizeof(u32)); + } + + *ppLeaf = pLeaf; + return WFSKRN_RESULT_OK; +} + +// +// Insert a key into F-tree. +// +WFSKrnResult FTreeInsert(AreaInfo* area, FTreeHdr* header, FTreeItr* iter, u32 nKey, u32 nData) +{ + u32* key; + u32 shift; + int index; + u32 mask; + FTreeLeaf* pLeaf; + u32 ofs; + +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + OS_TPrintf(" "); + OS_TPrintf("FTreeInsert(): %u (blk %u) type %d\n", nKey, nData + 1, (iter->subTree - &header->tree[0])); + } +#endif // FBA_DEBUG_VERBOSE + + WFSKRN_FTREE_RUNTIME_CHECK(VerifyTree(header)); + + PTreeAllocator allocator; + AllocatorInit(&allocator, header); + + PTreeHdr* subTree = iter->subTree; + if (subTree->nNumRecs == 0) + { + subTree->nRootHeight = 0; + subTree->nRootOfs = FTreeAllocEntry(GET_BLOCK_HEAD(header)); + if (subTree->nRootOfs == 0) + { + // split 8kB block. + WFSKrnResult result = SplitTree(area, header, iter); // WFSKRN_RESULT_FTREE_RETRY or WFSKRN_RESULT_FTREE_SPLIT + // the history in iter became ivalid. retry. + WFSKRN_FTREE_RUNTIME_CHECK(VerifyTree(header)); + if (result == WFSKRN_RESULT_OK) + { + result = WFSKRN_RESULT_FTREE_RETRY; + } + return result; + } + + WFSKRN_FTREE_ASSERT(subTree->nRootOfs < area->nBlkSize); + pLeaf = iter->pLeaf = FTreeGetLeaf(header, (u32) subTree->nRootOfs); + memset(&pLeaf->aKey[1], 0, (FTREE_LEAF_FAN_OUT-1) * sizeof(u32)); // It is necessary to initialize to 0. + pLeaf->aKey[0] = nKey; + LEAF_SET_LEN(pLeaf, 0, nData); + goto Done; + } + + ofs = PTreeFindLeafOfs(iter->subTree, &iter->ptree, nKey, &allocator); + WFSKRN_FTREE_ASSERT(ofs < area->nBlkSize); + WFSKRN_FTREE_ASSERT(header->sbaHdr.offset <= ofs); + + pLeaf = iter->pLeaf = FTreeGetLeaf(header, ofs); + if (pLeaf->aKey[FTREE_LEAF_FAN_OUT-1] != 0) + { + WFSKRN_FTREE_RUNTIME_CHECK(VerifyTree(header)); + WFSKrnResult result = SplitLeaf(area, header, iter, &pLeaf, nKey); + WFSKRN_FTREE_RUNTIME_CHECK(VerifyTree(header)); + if (result != WFSKRN_RESULT_OK) + { + return result; // WFSKRN_RESULT_FTREE_RETRY or WFSKRN_RESULT_PTREE_FULL + } + } + + key = SearchKey(pLeaf, nKey); + if (!IS_OUT_OF_RANGE(pLeaf, key) && *key == nKey) + { + // cannot overwrite the existing key. + return WFSKRN_RESULT_ALREADY_EXISTS; + } + ++key; + index = (key - &pLeaf->aKey[0]); + WFSKRN_FTREE_ASSERT(0 <= index); + + // insert data. + shift = FTREE_LEAF_FAN_OUT - 1 - index; + memmove(key+1, key, shift * sizeof(u32)); + mask = (0xffffffff << (4 * index)); + pLeaf->data = ((pLeaf->data & mask) << 4) | (pLeaf->data & ~mask); + + *key = nKey; + LEAF_SET_LEN(pLeaf, index, nData); + +#ifdef _DEBUG + int i = 0; + for (i = 0; i < FTREE_LEAF_FAN_OUT; ++i) + { + WFSKRN_FTREE_ASSERT(pLeaf->aKey[i] < 1024 * 1024 * 1024 /* 8TB */); + } +#endif // _DEBUG + +Done: + ++subTree->nNumRecs; + WFSKRN_FTREE_RUNTIME_CHECK(VerifyTree(header)); + + return WFSKRN_RESULT_OK; +} + +static WFSKrnResult ModifyEntry(FTreeLeaf* pLeaf, u32 origKey, u32 modKey, u32 modData) +{ + u32* key; + int index; + u32 origData; + + key = SearchKey(pLeaf, origKey); + if (IS_OUT_OF_RANGE(pLeaf, key) || *key != origKey) + { + return WFSKRN_RESULT_NOT_FOUND; + } + index = (key - &pLeaf->aKey[0]); + WFSKRN_FTREE_ASSERT(0 <= index); + + origData = LEAF_GET_LEN(pLeaf, index); + +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + OS_TPrintf("%u (blk %u) -> %u (blk %u)\n", + origKey, LEAF_GET_LEN(pLeaf, index) + 1, modKey, modData + 1); + } +#endif // FBA_DEBUG_VERBOSE + + pLeaf->aKey[index] = modKey; + LEAF_SET_LEN(pLeaf, index, modData); + + return WFSKRN_RESULT_OK; +} + +WFSKrnResult FTreeModify(FTreeHdr* header, FTreeItr* iter, u32 origKey, u32 modKey, u32 modData) +{ + WFSKrnResult result; + FTreeLeaf* pLeaf; + u32 ofs; + PTreeHdr* subTree; + PTreeAllocator allocator; + +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + OS_TPrintf(" "); + OS_TPrintf("FTreeModify(): type %d: ", (iter->subTree - &header->tree[0])); + } +#endif // FBA_DEBUG_VERBOSE + + AllocatorInit(&allocator, header); + + subTree = iter->subTree; + if (subTree->nNumRecs == 0) + { + return WFSKRN_RESULT_NOT_FOUND; + } + + ofs = PTreeFindLeafOfs(iter->subTree, &iter->ptree, origKey, &allocator); + WFSKRN_FTREE_ASSERT(ofs < BLOCK_SIZE); + WFSKRN_FTREE_ASSERT(header->sbaHdr.offset <= ofs); + pLeaf = iter->pLeaf = FTreeGetLeaf(header, ofs); + + result = ModifyEntry(pLeaf, origKey, modKey, modData); + if (result == WFSKRN_RESULT_OK) + { + FTREE_GET_KEY(iter) = modKey; + FTREE_GET_DATA(iter) = modData; + } + WFSKRN_FTREE_RUNTIME_CHECK(VerifyTree(header)); + return result; +} + +static WFSKrnResult DeleteKey(FTreeLeaf* pLeaf, u32 nKey) +{ + u32* key; + u32 shift; + int index; + u32 maskLow; + u32 maskHigh; + + key = SearchKey(pLeaf, nKey); + if (IS_OUT_OF_RANGE(pLeaf, key) || *key != nKey) + { + return WFSKRN_RESULT_NOT_FOUND; + } + index = (key - &pLeaf->aKey[0]); + WFSKRN_FTREE_ASSERT(0 <= index); + + // insert data. + shift = FTREE_LEAF_FAN_OUT - 1 - index; + memmove(key, key+1, shift * sizeof(u32)); + pLeaf->aKey[FTREE_LEAF_FAN_OUT - 1] = 0; + + maskLow = (0xffffffff << (4 * (index))); + maskHigh = (0xffffffff << (4 * (index+1))); + pLeaf->data = ((pLeaf->data & maskHigh) >> 4) | (pLeaf->data & ~maskLow); + + return WFSKRN_RESULT_OK; +} + +static WFSKrnResult DeleteEntryFromParentNode(PTreeHdr* pPTreeHdr, PTreeItr* pPti, PTreeAllocator *pAllocator) +{ + u32 nOfs; + u32 *pEntryIdx = pPti->aEntryIdx; + + // Delete the entry from the parent node + u32 nLevel = 1; + while(nLevel <= pPTreeHdr->nRootHeight) { + ++pEntryIdx; + PTreeNode *pNode = pPti->apNode[nLevel-1]; + switch(*pEntryIdx) { + case 0: if (pNode->aKey[0]==0) { + break; + } + pNode->aOfs[0] = pNode->aOfs[1]; + case 1: pNode->aKey[0] = pNode->aKey[1]; + pNode->aOfs[1] = pNode->aOfs[2]; + case 2: pNode->aKey[1] = pNode->aKey[2]; + pNode->aOfs[2] = pNode->aOfs[3]; + case 3: pNode->aKey[2] = pNode->aKey[3]; + pNode->aOfs[3] = pNode->aOfs[4]; + case 4: pNode->aKey[3] = pNode->aKey[4]; + pNode->aOfs[4] = pNode->aOfs[5]; + case 5: pNode->aKey[4] = 0; + return WFSKRN_RESULT_OK; + } + nOfs = PTreeGetOfs(pNode, pAllocator); + WFSKRN_FTREE_ASSERT(nOfs < BLOCK_SIZE); + pAllocator->fpFreeNode(pAllocator->pBase, nOfs); + ++nLevel; + } + return WFSKRN_RESULT_OK; +} + +// +// Delete the specified key. +// +WFSKrnResult FTreeDelete(FTreeHdr* header, FTreeItr* iter, u32 nKey) +{ + WFSKrnResult result; + FTreeLeaf* pLeaf; + u32 ofs; + +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + OS_TPrintf(" "); + OS_TPrintf("FTreeDelete(): %u (blk %u) type %d\n", nKey, FTREE_GET_DATA(iter) + 1, (iter->subTree - &header->tree[0])); + } +#endif // FBA_DEBUG_VERBOSE + + if (iter->subTree->nNumRecs == 0) + { + return WFSKRN_RESULT_NOT_FOUND; + } + + WFSKRN_FTREE_RUNTIME_CHECK(VerifyTree(header)); + + PTreeAllocator allocator; + AllocatorInit(&allocator, header); + ofs = PTreeFindLeafOfs(iter->subTree, &iter->ptree, nKey, &allocator); + WFSKRN_FTREE_ASSERT(ofs < BLOCK_SIZE); + WFSKRN_FTREE_ASSERT(header->sbaHdr.offset <= ofs); + pLeaf = iter->pLeaf = FTreeGetLeaf(header, ofs); + PTreeHdr* subTree = iter->subTree; + + if (subTree->nNumRecs == 0) + { + return WFSKRN_RESULT_NOT_FOUND; + } + + if (pLeaf->aKey[1] == 0) + { + if (pLeaf->aKey[0] != nKey) + { + return WFSKRN_RESULT_NOT_FOUND; + } + FTreeFreeEntry(GET_BLOCK_HEAD(header), ofs); + result = DeleteEntryFromParentNode(iter->subTree, &iter->ptree, &allocator); + } + else + { + result = DeleteKey(pLeaf, nKey); + } + + if (result == WFSKRN_RESULT_OK && + --iter->subTree->nNumRecs == 0) + { + iter->subTree->nRootHeight = 0; // reset. + } + + WFSKRN_FTREE_RUNTIME_CHECK(VerifyTree(header)); // [check] header was deleted? + return result; +} + +// +// Sub-block allocator +// +FTreeBlock* MemoryBlockAlloc(SubBlockAllocatorHeader* header, int numBlocks) +{ + FTreeBlock* free = GET_FREEBLOCK(header); + FTreeBlock* prev = NULL; + FTreeBlock* newFree; + + if ((END_OF_CACHE(header) <= GET_FREEBLOCK(header)) || numBlocks == 0) + { + return NULL; // no freeblock. + } + + while (free->num < numBlocks) + { + if (free->next == MAX_FREEBLOCK(header)) + { + WFSKRN_FTREE_RUNTIME_CHECK(VerifyMemoryBlockFTree(header)); + return NULL; + } + WFSKRN_FTREE_ASSERT(0 < free->next); + prev = free; + free = CACHE(header) + free->next; + } + + if (free->num == numBlocks) + { + if (prev) + { + prev->next = free->next; + } + else + { + SET_FREEBLOCK(header, CACHE(header) + free->next); + } + } + else + { + newFree = free + numBlocks; + newFree->next = free->next; + newFree->num = free->num - numBlocks; + + if (prev) + { + prev->next = newFree - CACHE(header); + } + else + { + SET_FREEBLOCK(header, newFree); + } + } + + free->next = 0; // allocated. + free->num = numBlocks; + + WFSKRN_FTREE_RUNTIME_CHECK(VerifyMemoryBlockFTree(header)); + + return free; +} + +int MemoryBlockFree(SubBlockAllocatorHeader* header, FTreeBlock* block, u32 numBlocks) +{ + if ((block < CACHE(header)) || END_OF_CACHE(header) <= block) + { + return -1; // out of memory blocks. + } + if (numBlocks == 0) + { + return 0; + } + +#ifdef _DEBUG + memset((u8*) block, 0xef, sizeof(FTreeBlock) * numBlocks); // clear +#endif // DEBUG + + if (block < GET_FREEBLOCK(header)) + { + if (GET_FREEBLOCK(header) == block + numBlocks) + { + // combine + if (GET_FREEBLOCK(header) == END_OF_CACHE(header)) + { + block->num = numBlocks; // set flags. + block->next = MAX_FREEBLOCK(header); // the tail of memory block. + } + else + { + block->num = GET_FREEBLOCK(header)->num + numBlocks; + block->next = GET_FREEBLOCK(header)->next; + } + } + else + { + block->num = numBlocks; + block->next = GET_FREEBLOCK(header) - CACHE(header); + } + SET_FREEBLOCK(header, block); + WFSKRN_FTREE_RUNTIME_CHECK(VerifyMemoryBlockFTree(header)); + } + else + { + block->num = numBlocks; + + FTreeBlock* free = GET_FREEBLOCK(header); + FTreeBlock* next = CACHE(header) + GET_FREEBLOCK(header)->next; + + while (next < block) + { + free = next; + next = CACHE(header) + next->next; + } + + if (free + free->num == block) + { + // combine + numBlocks += free->num; + free->num = numBlocks; + block = free; + } + else + { + free->next = block - CACHE(header); + } + + if (block + block->num == next && next < END_OF_CACHE(header)) + { + // combine + block->num = next->num + numBlocks; + block->next = next->next; + } + else + { + block->next = next - CACHE(header); + } + WFSKRN_FTREE_RUNTIME_CHECK(VerifyMemoryBlockFTree(header)); + } + return 0; +} + +WFSKrnResult FTreeAllocEntries(void *pBase, u16 *pNodeOfs, u32 nNumNodes) +{ + WFSKrnResult result = WFSKRN_RESULT_OUT_OF_MEMORY; + SubBlockAllocatorHeader* header = GET_SBAHDR(pBase); + FTreeBlock* block; + + if (nNumNodes == 0) + { + return WFSKRN_RESULT_OK; + } + + block = MemoryBlockAlloc(header, nNumNodes); + if (block) + { + result = WFSKRN_RESULT_OK; + header->numBlock += nNumNodes; + if (pNodeOfs) + { + int i; + for (i = 0; i < nNumNodes; ++i) + { + pNodeOfs[i] = (u16) ((u8*) &block[i] - (u8*) pBase); + WFSKRN_FTREE_ASSERT(0 < pNodeOfs[i]); + WFSKRN_FTREE_ASSERT(pNodeOfs[i] < BLOCK_SIZE); + } + } + } + + return result; +} + +u16 FTreeAllocEntry(void *pBase) +{ + SubBlockAllocatorHeader* header = GET_SBAHDR(pBase); + FTreeBlock* block = MemoryBlockAlloc(header, 1); + u32 ret = 0; + if (block) + { + WFSKRN_FTREE_ASSERT(header->numBlock + 1 <= MAX_FREEBLOCK(header)); + ++header->numBlock; + ret = ((u8*) block - (u8*) pBase); // byte-offset from the top of the 8kB block. + WFSKRN_FTREE_ASSERT(0 < ret); + WFSKRN_FTREE_ASSERT(ret < BLOCK_SIZE); + } + return ret; +} + +// nOfs is the byte offset from the top of the 8kB block. +void FTreeFreeEntry(void *pBase, u16 nOfs) +{ + SubBlockAllocatorHeader* header = GET_SBAHDR(pBase); + + FTreeBlock* block = (FTreeBlock*) ((u8*) pBase + nOfs); + if (MemoryBlockFree(header, block, 1) == 0) + { + WFSKRN_FTREE_ASSERT(0 <= header->numBlock - 1); + --header->numBlock; + } +} + +// +// Initialize an 8kB block. +// +/* + an 8kb-block. + +-------------------------+ A <--- block + | | | + | hash code | | sbaHdr->offset ... this must be the multiple of 32 bytes. + | etc.. | | + +-------------------------+ V <--- freeBlock + | | A + | | | + | | | + | | | + | | | + | | | + | | | + | Sub-blocks | | sbaHdr->size + | | | + | | | + | | | + | | | + | | | + | | V + +-------------------------+ <--- ftreeHdr or ptreeHdr A + | | | + +-------------------------+ <--- sbaHdr | footerSize + | SubBlockAllocatorHeader | | + +-------------------------+ V +*/ + +void FTreeSbaInit(AreaInfo* area, void* block, u32 footerSize, u32 offset) +{ + SubBlockAllocatorHeader* sbaHdr; + FTreeBlock* freeBlock; + WFSKRN_FTREE_ASSERT(sizeof(SubBlockAllocatorHeader) < footerSize); + + sbaHdr = GET_SBAHDR(block); + sbaHdr->numBlock = 0; + sbaHdr->freeBlock = 0; + sbaHdr->offset = offset; + sbaHdr->size = area->nBlkSize - (sbaHdr->offset + footerSize); + + WFSKRN_FTREE_ASSERT((sbaHdr->offset + footerSize) < area->nBlkSize); + + freeBlock = CACHE(sbaHdr); + freeBlock->num = sbaHdr->size / sizeof(FTreeBlock); + freeBlock->prev = 0; // first entry. + freeBlock->next = MAX_FREEBLOCK(sbaHdr); + + // initialize ftreeHdr or ptreeHdr. + memset((u8*) freeBlock + sbaHdr->size, 0, footerSize - sizeof(SubBlockAllocatorHeader)); + +} + +FTreeHdr* FTreeBlockInit(AreaInfo* area, void* block /* 8kB block */) +{ + FTreeSbaInit(area, block, sizeof(FTreeHdr), + ROUNDUP32BYTE(sizeof(WFSMetaDataFlags) + sizeof(WFSHashCode))); // offset for hash. + return GET_FTREEHDR(block); +} + +// +// Search an F-tree for the specified key. +// If strictSearch == FALSE, FTreeFind() returns the nearest value, +// which is smaller than nKey, when result == WFSKRN_RESULT_OK. +// +/* + (ex) + F-Tree leaf + +--------------------+ + | 13 16 20 100 | + +--------------------+ + | 100 200 300 400 | + +--------------------+ + A A A A + | | | | + (1) (2) (3) (4) <--- nKey + +* result + + | strictSearch + Case | TRUE | FALSE + -----+-------------+------------- + (1) | NOT_FOUND | NOT_FOUND + (2) | NOT_FOUND | OK + (3) | OK | OK + (4) | NOT_FOUND | OK + +* FTREE_GET_KEY(iter), FTREE_GET_DATA(iter) + + | strictSearch + Case | TRUE | FALSE + -----+------------+------------- + (1) | x, x | 13, 100 <--- note the key, 13 is not smaller than nKey. + (2) | x, x | 13, 100 + (3) | 20, 300 | 20, 300 + (4) | x, x | 100, 400 + + x means no value is set. +*/ + +WFSKrnResult FTreeFind(FTreeHdr* header, FTreeItr* iter, u32 nKey, WFSBool strictSearch) +{ + u32* key; + int index; + u32 ofs; + FTreeLeaf* pLeaf; + + PTreeAllocator allocator; + AllocatorInit(&allocator, header); + + // sub-tree must be selected before FTreeFind(). + WFSKRN_FTREE_ASSERT(&header->tree[0] <= iter->subTree); + WFSKRN_FTREE_ASSERT(iter->subTree <= &header->tree[MAX_SUB_TREE-1]); + PTreeHdr* subTree = iter->subTree; + if (subTree->nNumRecs == 0) + { + return WFSKRN_RESULT_FTREE_EMPTY; + } + + ofs = PTreeFindLeafOfs(iter->subTree, &iter->ptree, nKey, &allocator); + WFSKRN_FTREE_ASSERT(ofs < BLOCK_SIZE); + WFSKRN_FTREE_ASSERT(header->sbaHdr.offset <= ofs); + + pLeaf = FTreeGetLeaf(header, ofs); + iter->ptree.pLeaf = (PTreeLeaf*) pLeaf; + + key = SearchKey(pLeaf, nKey); + if (strictSearch && + (IS_OUT_OF_RANGE(pLeaf, key) || *key != nKey)) + { + return WFSKRN_RESULT_NOT_FOUND; + } + + index = (key - &pLeaf->aKey[0]); + if (index < 0) + { + // nKey < the minimum key. + iter->ptree.aEntryIdx[0] = 0; // save the nearest key. (note: nKey < this key) + + iter->pLeaf = (FTreeLeaf*) iter->ptree.pLeaf; // [check] + FTREE_GET_KEY(iter) = iter->pLeaf->aKey[0]; // [check] + FTREE_GET_DATA(iter) = LEAF_GET_LEN(iter->pLeaf, 0); // [check] + return WFSKRN_RESULT_NOT_FOUND; + } + + iter->ptree.aEntryIdx[0] = index; + + // save data + iter->pLeaf = (FTreeLeaf*) iter->ptree.pLeaf; + FTREE_GET_KEY(iter) = iter->pLeaf->aKey[index]; + FTREE_GET_DATA(iter) = LEAF_GET_LEN(iter->pLeaf, index); + + return WFSKRN_RESULT_OK; +} + +// +// Get the first key in this F-tree. +// +WFSKrnResult FTreeFirst(FTreeHdr* header, FTreeItr* iter) +{ + WFSKrnResult result; + PTreeAllocator allocator; + AllocatorInit(&allocator, header); + + result = PTreeFirst(iter->subTree, &iter->ptree, &allocator); + if (result == WFSKRN_RESULT_OK) + { + iter->pLeaf = (FTreeLeaf*) iter->ptree.pLeaf; + FTREE_GET_KEY(iter) = iter->pLeaf->aKey[0]; + FTREE_GET_DATA(iter) = LEAF_GET_LEN(iter->pLeaf, 0); + result = WFSKRN_RESULT_OK; + } + return result; +} + +// +// Get the next key. +// Must call FTreeFind() or FTreeFirst() before FTreeNext(). +// +// [check] should be unified with PTreeNext. +// parameterize LEAF_FAN_OUT and data format. +WFSKrnResult FTreeNext(FTreeHdr* header, FTreeItr* iter) +{ + PTreeHdr *pPTreeHdr = iter->subTree; + PTreeItr *pPti = &iter->ptree; + PTreeAllocator allocator; + PTreeAllocator *pAllocator = &allocator; + AllocatorInit(&allocator, header); + + WFSKrnResult nResult = WFSKRN_RESULT_OK; + u32 *pEntryIdx = &pPti->aEntryIdx[0]; + ++(*pEntryIdx); + u32 *aKey = pPti->pLeaf->aKey; + u32 *pKey = &aKey[*pEntryIdx]; + if ((*pEntryIdx==FTREE_LEAF_FAN_OUT) || (*pKey==0)) { + u32 *pEntryIdxEnd = &pPti->aEntryIdx[pPTreeHdr->nRootHeight]; + PTreeNode **ppNode = pPti->apNode; + while(1) { + ++pEntryIdx; + if (pEntryIdx > pEntryIdxEnd) { + return WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; + } + aKey = (*ppNode)->aKey; + ++ppNode; + if (*pEntryIdx >= PTREE_NODE_FAN_OUT-1) { + continue; + } + pKey = &aKey[*pEntryIdx]; + ++(*pEntryIdx); + if (*pKey != 0) { + break; + } + } + --ppNode; + u32 nOfs = (*ppNode)->aOfs[pKey - aKey + 1]; + WFSKRN_FTREE_ASSERT(nOfs < BLOCK_SIZE); + while(1) { + --pEntryIdx; + *pEntryIdx = 0; + if (ppNode == pPti->apNode) { + break; + } + --ppNode; + *ppNode = PTreeGetNode(pAllocator, nOfs); + nOfs = (*ppNode)->aOfs[0]; + WFSKRN_FTREE_ASSERT(nOfs < BLOCK_SIZE); + } + pPti->pLeaf = PTreeGetLeaf(pAllocator, nOfs); + WFSKRN_FTREE_ASSERT(pPti->pLeaf); // [check] debug code. + aKey = pPti->pLeaf->aKey; + pKey = &aKey[0]; + } + pPti->nKey = *pKey; + pPti->nData = LEAF_GET_LEN((FTreeLeaf*) pPti->pLeaf, pKey - aKey); + return nResult; +} + +// [check] should be refined. +static inline int GetMaxKey(u32 *aKey, u32 maxKeys) +{ + int count = (int) maxKeys; + while (count) + { + if (aKey[count] != 0) + { + break; + } + --count; + } + + if (count == 0 && aKey[count] == 0) + { + // pass through + --count; + } + return count; +} + +WFSKrnResult static GetPrev(PTreeHdr *pPTreeHdr, PTreeItr *pPti, + PTreeAllocator *pAllocator, u32 leafFanout, u32** ppKey) +{ + WFSKrnResult nResult = WFSKRN_RESULT_OK; + int count; + u32 *pEntryIdx = pPti->aEntryIdx; + + if (pPTreeHdr->nNumRecs == 0) + { + return WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; + } + + // search the current leaf. + WFSKRN_FTREE_ASSERT(*pEntryIdx != 0xffffffff); + + u32 *aKey = pPti->pLeaf->aKey; + u32 *pKey; + if (*pEntryIdx == 0) + { + // search up. + u32 *pEntryIdxEnd = &pPti->aEntryIdx[pPTreeHdr->nRootHeight]; + PTreeNode **ppNode = pPti->apNode; // parent node. + while(1) { + ++pEntryIdx; // parent entry index. + if (pEntryIdxEnd < pEntryIdx) { + return WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; + } + aKey = (*ppNode)->aKey; // parent "key" + ++ppNode; + if (*pEntryIdx == 0) // if parent index is zero, check the next parent. + { + continue; + } + --(*pEntryIdx); + pKey = &aKey[*pEntryIdx]; + if (*pKey != 0) { // [check] necessary? + break; + } + } + // search down. + --ppNode; + u32 nOfs = (*ppNode)->aOfs[pKey - aKey]; + WFSKRN_FTREE_ASSERT(nOfs < BLOCK_SIZE); + while(1) { + --pEntryIdx; + if (ppNode == pPti->apNode) + { + // select the max key in leaf. + break; + } + --ppNode; // select child node. + *ppNode = PTreeGetNode(pAllocator, nOfs); + + // select the max key in the child. + count = GetMaxKey((*ppNode)->aKey, PTREE_NODE_FAN_OUT-2); // + if (count < 0) + { + *pEntryIdx = 0; // [check] pass through must be refined. + } + else + { + *pEntryIdx = count+1; // ofs_index = key_index + 1. + } + nOfs = (*ppNode)->aOfs[*pEntryIdx]; + WFSKRN_FTREE_ASSERT(nOfs < BLOCK_SIZE); + } + pPti->pLeaf = PTreeGetLeaf(pAllocator, nOfs); + aKey = pPti->pLeaf->aKey; + count = GetMaxKey(aKey, leafFanout-1); + if (count < 0) + { + count = 0; // [check] pass through must be refined. + } + + WFSKRN_FTREE_ASSERT(0 <= count && count <= leafFanout-1); + *pEntryIdx = count; + pKey = &aKey[count]; + } + else + { + --(*pEntryIdx); // [check] + pKey = &aKey[*pEntryIdx]; + } + *ppKey = pKey; + return nResult; +} + +// +// Get the previous key in this P-tree. +// Must call PTreeFind() or PTreeLast() before PTreePrev(). +// +WFSKrnResult PTreePrev(PTreeHdr *pPTreeHdr, PTreeItr *pPti, PTreeAllocator *pAllocator) +{ + WFSKrnResult nResult; + u32* pKey; + u32* aKey; + + nResult = GetPrev(pPTreeHdr, pPti, pAllocator, PTREE_LEAF_FAN_OUT, &pKey); + if (nResult == WFSKRN_RESULT_OK) + { + aKey = pPti->pLeaf->aKey; + pPti->nKey = *pKey; + pPti->nData = pPti->pLeaf->aData[pKey - aKey]; + } + return nResult; +} + +// +// Get the previous key in this F-tree. +// Must call FTreeFind() or FTreeLast() before FTreePrev(). +// +WFSKrnResult FTreePrev(FTreeHdr* header, FTreeItr* iter) +{ + WFSKrnResult nResult; + PTreeItr *pPti = &iter->ptree; + PTreeAllocator allocator; + AllocatorInit(&allocator, header); + + u32* pKey; + u32* aKey; + nResult = GetPrev(iter->subTree, pPti, &allocator, FTREE_LEAF_FAN_OUT, &pKey); + if (nResult == WFSKRN_RESULT_OK) + { + aKey = pPti->pLeaf->aKey; + pPti->nKey = *pKey; + pPti->nData = LEAF_GET_LEN((FTreeLeaf*) pPti->pLeaf, pKey - aKey); + } + return nResult; +} + +// +// Get the last key in this P-tree. +// +WFSKrnResult PTreeLast(PTreeHdr *pPTreeHdr, PTreeItr *pPti, PTreeAllocator *pAllocator) { + if (pPTreeHdr->nNumRecs == 0) { + return WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; + } + int index; + u32 nLevel = pPTreeHdr->nRootHeight; + u32 *pEntryIdx = &pPti->aEntryIdx[nLevel]; + u32 nOfs = (u32)pPTreeHdr->nRootOfs; + WFSKRN_FTREE_ASSERT(nOfs < BLOCK_SIZE); + + while (nLevel) { + --nLevel; + PTreeNode *pNode = pPti->apNode[nLevel] = PTreeGetNode(pAllocator, nOfs); + index = GetMaxKey(pNode->aKey, PTREE_NODE_FAN_OUT-2); // [check] should refine. + nOfs = pNode->aOfs[index+1]; //*pEntryIdx + WFSKRN_FTREE_ASSERT(nOfs < BLOCK_SIZE); + *pEntryIdx = index+1; + --pEntryIdx; + } + PTreeLeaf *pLeaf = pPti->pLeaf = PTreeGetLeaf(pAllocator, nOfs); + + index = GetMaxKey(pLeaf->aKey, PTREE_LEAF_FAN_OUT-1); // [check] should refine. + if (index < 0) + { + // path-through + index = 0; + } + *pEntryIdx = index; + pPti->nKey = pLeaf->aKey[index]; + pPti->nData = pLeaf->aData[index]; + + return WFSKRN_RESULT_OK; +} + +// +// Get the last key in this F-tree. +// +// [check] must refine. +WFSKrnResult FTreeLast(FTreeHdr* header, FTreeItr* iter) +{ + return FTreeFind(header, iter, 0xffffffff, (WFSBool) FALSE); // find the max key. +} + +// +// debug code +// +static WFSBool VerifySBA(FTreeHdr* header) +{ + SubBlockAllocatorHeader* sba = &header->sbaHdr; + return VerifyMemoryBlockFTree(sba); +} + +static WFSBool DoubleCheck(FTreeHdr* header, u32 key, int subTreeIndex) +{ + WFSKrnResult result; + FTreeItr iter; + WFSBool strictSearch; + iter.subTree = &header->tree[subTreeIndex]; + + strictSearch = (WFSBool) TRUE; + result = FTreeFind(header, &iter, key, strictSearch); // find + if (result == WFSKRN_RESULT_OK) + { + return (WFSBool) TRUE; + } + return (WFSBool) FALSE; +} + +static WFSBool VerifyTree(FTreeHdr* header) +{ + u32 count; + u32 key; + u32 data; + u32 lastKey; + u32 lastData; + FTreeItr iter; + + int subTreeIndex; + for (subTreeIndex = 0; subTreeIndex < MAX_SUB_TREE; ++subTreeIndex) + { + iter.subTree = &header->tree[subTreeIndex]; + count = iter.subTree->nNumRecs; + if (count == 0) + { + continue; + } + + if (FTreeFirst(header, &iter) != WFSKRN_RESULT_OK) + { + return (WFSBool) FALSE; + } + + key = FTREE_GET_KEY(&iter); + if (DoubleCheck(header, key, subTreeIndex) == (WFSBool) FALSE) + { + return (WFSBool) FALSE; + } + + // if (2 * 1024 * 1024 < FTREE_GET_KEY(&iter)) // the maximum area size is 16GB, for now. + if (1024 * 1024 * 1024 < FTREE_GET_KEY(&iter)) // [check] 8TB + { + return (WFSBool) FALSE; + } + if (16 <= FTREE_GET_DATA(&iter)) + { + return (WFSBool) FALSE; + } + --count; + + lastKey = FTREE_GET_KEY(&iter); + lastData = FTREE_GET_DATA(&iter); + while (count--) + { + if (FTreeNext(header, &iter) != WFSKRN_RESULT_OK) + { + return (WFSBool) FALSE; + } + if (FTREE_GET_KEY(&iter) <= key) + { + return (WFSBool) FALSE; + } + key = FTREE_GET_KEY(&iter); + data = FTREE_GET_DATA(&iter); + if (DoubleCheck(header, key, subTreeIndex) == (WFSBool) FALSE) + { + return (WFSBool) FALSE; + } + // if (2 * 1024 * 1024 < FTREE_GET_KEY(&iter)) // the maximum area size is 16GB, for now. + if (1024 * 1024 * 1024 < FTREE_GET_KEY(&iter)) // [check] 8TB. + { + return (WFSBool) FALSE; + } + if (16 <= FTREE_GET_DATA(&iter)) + { + return (WFSBool) FALSE; + } + if (key < lastKey + lastData + 1) + { + return (WFSBool) FALSE; + } + lastKey = key; + lastData = data; + } + } + return (WFSBool) TRUE; +} + +WFSBool FTreeVerifyTree(FTreeHdr* header) +{ + return VerifyTree(header); +} + +WFSBool VerifyMemoryBlockFTree(SubBlockAllocatorHeader* header) +{ + int numFreeBlock; + FTreeBlock* free; + WFSBool result = (WFSBool) FALSE; + + free = GET_FREEBLOCK(header); + numFreeBlock = 0; + + while (free < END_OF_CACHE(header)) + { + if (MAX_FREEBLOCK(header) < free->next) + { + goto VERIFY_ERROR; + } + if (free->num == 0) + { + goto VERIFY_ERROR; + } + if (MAX_FREEBLOCK(header) < free->num) + { + goto VERIFY_ERROR; + } + numFreeBlock += free->num; + free = CACHE(header) + free->next; + } + + result = (WFSBool) TRUE; + +VERIFY_ERROR: + return result; +} + +#endif // BTREE_BASED_ALLOCATOR diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_FreeBlkAlloc.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_FreeBlkAlloc.cpp new file mode 100644 index 0000000..4c17836 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_FreeBlkAlloc.cpp @@ -0,0 +1,3006 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_FreeBlkAlloc.cpp + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_FreeBlkAlloc.cpp,v $ + Revision 1.43 2008/12/19 07:57:06 ueno + Cleanup. + + Revision 1.42 2008/12/18 00:36:37 ueno + Modified to always select free blocks considering fragmentation and distance from the specified reference address. + + Revision 1.41 2008/12/17 07:43:09 ueno + Modified the priority of free extents. + + Revision 1.40 2008/12/17 06:51:24 ueno + Fixed IsFarawayFromRefAddr() to identify a half of the area size is "far". + + Revision 1.39 2008/12/17 05:07:39 ueno + Cleanup. + Fixed MergeExtents() to check the length of the smaller extent. + + Revision 1.38 2008/12/15 04:14:40 ueno + Cleanup. + + Revision 1.37 2008/12/15 02:40:07 ueno + Added support for multi p-tree. + + Revision 1.36 2008/12/05 04:29:19 nakanose_jin + fix error on Release Target. + + Revision 1.35 2008/12/02 04:55:13 ueno + Added EPTree to support multi-PTree. + + Revision 1.33 2008/11/18 04:57:12 saito_tomoya + Modified SetBit() and added SetBitArray(). + + Revision 1.32 2008/11/12 13:34:17 ueno + Fixed uninitialized value. + + Revision 1.31 2008/10/30 04:32:32 ueno + Modified for release build. + + Revision 1.30 2008/10/27 13:17:28 ueno + Modified to sequentially allocate blocks to improve performance. + + Revision 1.29 2008/10/27 05:44:57 ueno + Modified FreeBlkAlloc() to get blocks near the refernce address when the number of blocks <= 5. + + Revision 1.28 2008/10/17 08:50:48 kondo_masahiro + Added the new MEDIUM size category (40KB-320KB) + + Revision 1.27 2008/10/15 07:41:22 saito_tomoya + fix for porting IOP + + Revision 1.26 2008/10/14 11:22:13 ueno + Committed revision 1.22 again. + - Modified FTreeInsert() to be able to split the block when creating a root node. + - Modified FreeBlkAlloc() to improve performance. + + Revision 1.25 2008/10/06 23:16:17 ueno + Fixed null pointer reference in InsertIntoThisSubTree(). + + Revision 1.24 2008/10/03 10:22:46 ueno + Updated debug function. + + Revision 1.23 2008/10/03 08:37:56 kondo_masahiro + Fixed codes for porting IOP + + Revision 1.21 2008/09/30 05:55:52 ueno + Cleanup. + + Revision 1.20 2008/09/30 05:21:16 ueno + Improved performance of FreeBlkInsert(). + + Revision 1.19 2008/09/30 04:48:41 ueno + Reduced stack usage of FreeBlkInsert(). + Improved performance of FreeBlkNext() and Prev(). + + Revision 1.18 2008/09/30 02:01:19 ueno + Modified to support large disk ( < 32TB). + + Revision 1.17 2008/09/29 10:19:36 ueno + Revised to support multi-B-tree-based allocator. + + Revision 1.16 2008/09/29 01:58:57 ueno + Modified to call BCacheInvalidateBlks() in FreeBlkFree() to invalidate caches of user data. + + Revision 1.15 2008/09/28 23:32:04 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.15 2008/09/28 23:32:04 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.13 2008/09/02 07:02:49 kondo_masahiro + Fixed several points for IOP compiler. + + Revision 1.12 2008/08/28 01:17:41 ueno + Modified FreeBlkAlloc() to resurn WFSKRN_RESULT_DIRECTORY_QUOTA. + + Revision 1.11 2008/08/28 00:23:18 ueno + Modified to skip pin count check in FreeBlkAlloc() and FreeBlkVerify(). + + Revision 1.10 2008/08/13 04:13:28 ueno + Modified FreeBlkAlloc() to allocate blocks near nRefBlkAdr. + + Revision 1.9 2008/08/13 00:12:09 paul + Changed specification of nStride to include sizeof(nBlkAdr) and support negative strides + + Revision 1.8 2008/08/09 03:32:51 ueno + Disabled runtime check. + + Revision 1.7 2008/08/09 02:01:41 ueno + Cleanup. + + Revision 1.6 2008/08/09 00:40:09 ueno + Fixed FreeBlkAlloc() to unpin and pin blocks correctly. + + Revision 1.5 2008/08/08 13:26:50 ueno + Modified to unpin properly. + + Revision 1.4 2008/08/07 10:46:33 ueno + Modified for BTREE_BASED_ALLOCATOR (now debugging). + + Revision 1.3 2008/08/02 11:52:40 ueno + Revised the positions of FTreeHdr{} and FBAPTreeHdr{} in 8KB-blocks to protect hash code. + + Revision 1.2 2008/08/01 07:00:05 ueno + Added copyrights. + + Revision 1.1 2008/08/01 06:57:39 ueno + Initial Check-in. + +*---------------------------------------------------------------------------*/ +#include "wfskrn_Area.h" +#if BTREE_BASED_ALLOCATOR + +#include "wfskrn_FTree.h" +#include "wfskrn_FreeBlkAlloc.h" + +#define ROUNDUP32BYTE(val) (((size_t)(val)+31)&~31) +#define ROUNDDOWN(val, unit) ((u32) (val) & ~((unit)-1)) +#define ROUNDUP(val, unit) ((u32) ((val) + ((unit)-1)) & ~((unit)-1)) + +#define FBA_PTREE_MIN_HEIGHT 1 + +#ifdef FBA_DEBUG_VERBOSE +WFSBool FBADebugVerbose = (WFSBool) FALSE; // enable debug message. +#endif //FBA_DEBUG_VERBOSE + +typedef struct _CacheMap +{ + u32 diskAddr; + void* cache; +} CacheMap; + +void FBAUnpinCache(AreaInfo* area, u32 diskAddr) +{ + BCacheUnpin(area->pVolInfo, area->nAbsStartBlkAdr + diskAddr); +} + +void FBAUnpinFTreeBlk(AreaInfo* area, FBATreeItr* iter) +{ + if (iter->ftreeHdr) + { + FBAUnpinCache(area, FBA_GET_FTREE_BLK(iter)); + iter->ftreeHdr = 0; // no f-tree is pinned. + } +} + +void FBAFreeCache(AreaInfo* area, u32 diskAddr) +{ + BCacheUnpin(area->pVolInfo, area->nAbsStartBlkAdr + diskAddr); + BCacheInvalidate(area->pVolInfo, area->nAbsStartBlkAdr + diskAddr); +} + +WFSKrnResult FBAGetCache(AreaInfo* area, u32 diskAddr, u32 flags, void** cache) +{ + WFSKrnResult result; + + BCacheEntry* pBce; + result = BCacheAllocMetaBlk(area->pVolInfo, area->nAbsStartBlkAdr + diskAddr, flags, &pBce); + if (result == WFSKRN_RESULT_OK) + { + *cache = pBce->pBlkPtr; + } + return result; +} + +static void FBADirtyFtreeBlock(AreaInfo* area, FBATreeItr* iter) +{ +#ifdef _DEBUG + int index; + EPTreeItr* epti = EPTreeGetLastIter((MEPTreeItr*)iter); + index = epti->aEntryIdx[0]; + WFSKRN_FTREE_ASSERT(index < PTREE_LEAF_FAN_OUT); + WFSKRN_FTREE_ASSERT(iter->ftreeAddr == epti->pLeaf->aData[index]); +#endif // _DEBUG + BCacheDirty(area->pVolInfo, area->nAbsStartBlkAdr + iter->ftreeAddr); +} + +static WFSKrnResult FBAGetAndPinFtreeBlock(AreaInfo* area, FBATreeItr* iter, u32 flags) +{ + int index; + EPTreeItr* epti; + WFSKrnResult result; + void* cache; + u8 ptreeHeight = iter->eptreeHdr[0]->height; + + epti = &iter->epti[ptreeHeight-1]; + index = epti->aEntryIdx[0]; + + if (iter->ftreeAddr == epti->pLeaf->aData[index] && + iter->ftreeHdr) + { + // already pinned. + return WFSKRN_RESULT_OK; + } + + if (iter->ftreeHdr) + { + FBAUnpinCache(area, iter->ftreeAddr); + } + + WFSKRN_FTREE_ASSERT(index < PTREE_LEAF_FAN_OUT); + iter->ftreeAddr = epti->pLeaf->aData[index]; + + result = FBAGetCache(area, iter->ftreeAddr, flags, &cache); + if (result == WFSKRN_RESULT_OK) + { + iter->ftreeHdr = GET_FTREEHDR(cache); + } + return result; +} + +void FBAItrOpen(AreaInfo* area, FBATreeItr* iter) +{ + iter->eptreeHdr[0] = GET_EPTREEHDR_FROM_AREAINFO(area); + + u32 i; + for (i = 1; i < EPTREE_MAX_HEIGHT; ++i) + { + iter->eptreeHdr[i] = 0; + } + + iter->ftreeHdr = 0; + iter->isInserted = (WFSBool) FALSE; + iter->height = iter->eptreeHdr[0]->height; // keep the height to know the bottom p-tree in this iter, + // because another iter can change FBA tree height (iter->eptreeHdr[0]->height). +} + +void FBAItrClose(AreaInfo* area, FBATreeItr* iter) +{ + u32 i; + u8 ptreeHeight = iter->eptreeHdr[0]->height; + ASSERT(ptreeHeight <= EPTREE_MAX_HEIGHT); + + iter->eptreeHdr[0] = GET_EPTREEHDR_FROM_AREAINFO(area); + for (i = 1; i < ptreeHeight; ++i) + { + if (iter->eptreeHdr[i]) + { + u32 diskAddr = EPTREE_GET_DATA(&iter->epti[i-1]); + FBAUnpinCache(area, diskAddr); + iter->eptreeHdr[i] = 0; + } + } + + FBAUnpinFTreeBlk(area, iter); +} + +static WFSKrnResult FBAPTreeFind(AreaInfo* area, FBATreeItr* iter, u32 nKey) +{ + WFSKrnResult result = EPTreeFind(area, (MEPTreeItr*) iter, nKey); + if (result == WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND) + { + // NOT_FOUND means the specified key does not match the keys in this P-tree, + // but EPTreeFind() could find a candidate key. + // The candidate is the nearest neighbor of the specified key and + // the candidate key <= the specified key. + result = WFSKRN_RESULT_OK; + } + return result; +} + +static WFSKrnResult FBALookupStrict(AreaInfo* area, FBATreeItr* iter, WFSBlkAdr nBlkAdr, u32 nBlkLog2Size) +{ + WFSKrnResult result; + + // P-tree block is already pinned. + result = FBAPTreeFind(area, iter, nBlkAdr); + if (result == WFSKRN_RESULT_OK) + { + result = FBAGetAndPinFtreeBlock(area, iter, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result == WFSKRN_RESULT_OK) + { + FTreeItr* fti = &iter->fti; + fti->subTree = FTreeSelectSubTree(iter->ftreeHdr, nBlkLog2Size); + result = FTreeFind(iter->ftreeHdr, fti, nBlkAdr, (WFSBool) TRUE); + } + } + + // the P-tree block is pinned. + // an F-tree block is pinned. + return result; +} + +static WFSKrnResult FBALookup(AreaInfo* area, FBATreeItr* iter, WFSBlkAdr nBlkAdr, u32 nBlkLog2Size) +{ + WFSKrnResult result; + + // P-tree block is already pinned. + result = FBAPTreeFind(area, iter, nBlkAdr); + if (result != WFSKRN_RESULT_OK) + { + // FBAPTreeFind() case (1). + result = EPTreePrev(area, (MEPTreeItr*) iter); + } + + if (result == WFSKRN_RESULT_OK) + { + iter->isInserted = (WFSBool) FALSE; // reset + result = FBAGetAndPinFtreeBlock(area, iter, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result == WFSKRN_RESULT_OK) + { + FTreeItr* fti = &iter->fti; + fti->subTree = FTreeSelectSubTree(iter->ftreeHdr, nBlkLog2Size); + result = FTreeFind(iter->ftreeHdr, fti, nBlkAdr, (WFSBool) FALSE); + if (result == WFSKRN_RESULT_NOT_FOUND || + result == WFSKRN_RESULT_FTREE_EMPTY) + { + result = FreeBlkPrev(area, iter); + } + } + } + + // the P-tree block is pinned. + // an F-tree block is pinned. + return result; +} + +// search where to insert the new key. +static WFSKrnResult FBALookupBeforeInsert(AreaInfo* area, FBATreeItr* iter, WFSBlkAdr nBlkAdr, u32 nBlkLog2Size) +{ + WFSKrnResult result; + + // the P-tree block is already pinned. + result = FBAPTreeFind(area, iter, nBlkAdr); + if (result != WFSKRN_RESULT_OK) + { + EPTreeItr* epti; + /* + (ex) + +-----------------+ + | P-Tree | + |key: 10 16 19... | + | | + +-----------------+ + A + | | + nBlkAdr (5) | insert nBlkAdr. + | + V + +-------------------+ + | P-Tree | + |key: 5 16 19... | + | A | + +-----|-------------+ + | + insert the head of the leaf after FBALookupBeforeInsert(). + */ + + epti = EPTreeGetLastIter((MEPTreeItr*) iter); + WFSKRN_FTREE_ASSERT(nBlkAdr < epti->pLeaf->aKey[0]); +#ifdef _DEBUG + if (0 < epti->aEntryIdx[1]) + { + WFSKRN_FTREE_ASSERT(epti->apNode[0]->aKey[epti->aEntryIdx[1]-1] <= nBlkAdr); + } +#endif // _DEBUG + epti->aEntryIdx[0] = 0; + epti->pLeaf->aKey[0] = nBlkAdr; + + epti->nKey = epti->pLeaf->aKey[0]; + epti->nData = epti->pLeaf->aData[0]; + result = WFSKRN_RESULT_OK; + } + + if (result == WFSKRN_RESULT_OK) + { + FTreeItr* fti = &iter->fti; + result = FBAGetAndPinFtreeBlock(area, iter, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result != WFSKRN_RESULT_OK) + { + return result; + } + fti->subTree = FTreeSelectSubTree(iter->ftreeHdr, nBlkLog2Size); + result = FTreeFind(iter->ftreeHdr, fti, nBlkAdr, (WFSBool) FALSE); + } + + iter->isInserted = (WFSBool) FALSE; + + // the P-tree block is pinned. + // an F-tree block is pinned. + return result; +} + +WFSKrnResult InsertNewChild(AreaInfo* area, FBATreeItr* iter, + FTreeExtent* extent, u32 nBlkLog2Size) +{ + WFSKrnResult result; + u32 key = extent->start; + u32 data = extent->len / (1<fti.splitKey, iter->fti.newChild); + if (result != WFSKRN_RESULT_OK) + { + goto INSERTNEWCHILD_ERROR; + } + + iter->height = iter->eptreeHdr[0]->height; // the height may be changed. + + // insert the extent into the freeblock allocator tree. + if (key < iter->fti.splitKey) + { + FTreeHdr* ftreeHdr = iter->ftreeHdr; + result = FTreeInsert(area, ftreeHdr, &iter->fti, key, data); + BCacheDirty(area->pVolInfo, area->nAbsStartBlkAdr + iter->ftreeAddr); // pass through the debug code in DirtyFtreeBlock(). + } + else + { + void* cache; + FTreeHdr* newChildHdr; + result = FBAGetCache(area, iter->fti.newChild, + BCACHE_FLAG_DIRTY | BCACHE_FLAG_READ | BCACHE_FLAG_PINNED, &cache); + if (result != WFSKRN_RESULT_OK) + { + goto INSERTNEWCHILD_ERROR; + } + + newChildHdr = GET_FTREEHDR(cache); + iter->fti.subTree = FTreeSelectSubTree(newChildHdr, nBlkLog2Size); // [check] + + result = FTreeInsert(area, newChildHdr, &iter->fti, key, data); + FBAUnpinCache(area, iter->fti.newChild); // unpin the new child block. + } + + // remove the address of the new control block from the freeblock allocator tree, + // to prevent the block from being allocated as a freeblock. + result = FreeBlkDelete(area, iter, + iter->fti.newChild, 1, FTreeBlkLog2Ofs[iter->fti.newChildSubTreeType]); + +INSERTNEWCHILD_ERROR: + // the P-tree block is pinned. + // an F-tree block (left child) is pinned. + return result; +} + +static inline int GetSubTreeType(WFSBlkAdr len) +{ + int subTreeType; + + if (len < (1<eptreeHdr[0]->height; + for (level = 1; level < ptreeHeight; ++level) + { + // unpin nodes. + if (dst->eptreeHdr[level]) + { + FBAUnpinCache(area, dst->eptreeHdr[level]->addr); + } + } + if (dst->ftreeHdr) + { + FBAUnpinCache(area, dst->ftreeAddr); + } + + *dst = *src; + // the root P-tree block is pinned. + + for (level = 1; level < ptreeHeight; ++level) + { + // pin nodes. + result = FBAGetCache(area, dst->eptreeHdr[level]->addr, flags, &cache); + } + return FBAGetCache(area, dst->ftreeAddr, flags, &cache); +} + +static WFSKrnResult GetNeighbors(AreaInfo* area, FBATreeItr* iter, WFSBlkAdr nBlkAdr, + WFSBlkAdr nBlkLen, FTreeExtentInfo* prev, FTreeExtentInfo* next, u32 nBlkLog2Size, WFSKrnResult resultLookup) +{ + WFSKrnResult result; + FBAItrOpen(area, &prev->iter); + FBAItrOpen(area, &next->iter); + + // search neighbors. + result = CopyFBAIter(area, iter, &prev->iter, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result != WFSKRN_RESULT_OK) + { + return result; + } + result = CopyFBAIter(area, iter, &next->iter, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result != WFSKRN_RESULT_OK) + { + FBAItrClose(area, &prev->iter); + return result; + } + + next->len = 0; + prev->len = 0; + + if (resultLookup != WFSKRN_RESULT_OK) + { + // prev extent cat be in the previous f-tree leaf. + result = FreeBlkPrev(area, &prev->iter); + } + + if (result == WFSKRN_RESULT_OK) + { + FTreeItr* fti = &prev->iter.fti; + WFSBlkAdr len = (FTREE_GET_DATA(fti) + 1) * (1<start = FTREE_GET_KEY(fti); + prev->len = len; + if (nBlkLog2Size == FTREE_LOG2_OFS_G && + (1<len) + { + prev->len = 0; + } + } + } + + result = WFSKRN_RESULT_OK; + if (resultLookup == WFSKRN_RESULT_OK || + resultLookup == WFSKRN_RESULT_FTREE_EMPTY) + { + result = FreeBlkNext(area, &next->iter); + } + /* + else + { F-tree leaf F-tree leaf + +---------------+ +---------------+ + | | | | + |1st_Key | or | empty | + +-A-------------+ +-A-------------+ + A | | A + | +------ iter has this key. -----+ | + nBlkAdr nBlkAdr + } + */ + if (result == WFSKRN_RESULT_OK) + { + FTreeItr* fti = &next->iter.fti; + // next extent + if (nBlkAdr + nBlkLen == FTREE_GET_KEY(fti)) + { + next->start = FTREE_GET_KEY(fti); + next->len = (FTREE_GET_DATA(fti) + 1) * (1<len) + { + next->len = 0; + } + } + + } + + // keep pinning the prev and next extent. + + return WFSKRN_RESULT_OK; +} + +static inline WFSBool IsLastKey(FTreeItr* fti) +{ + u32 index = fti->ptree.aEntryIdx[0]; + return (WFSBool) (fti->subTree->nNumRecs == 0 || + index == FTREE_LEAF_FAN_OUT - 1 || fti->pLeaf->aKey[index+1] == 0); +} + +static WFSKrnResult InsertIntoThisSubTree(AreaInfo* area, FBATreeItr* iter, WFSBlkAdr nBlkLog2Size, + FTreeExtent* newExtent, FTreeExtentInfo* prev, FTreeExtentInfo* next) +{ + WFSKrnResult result; + FTreeItr* fti = &iter->fti; + + if (prev && 0 < prev->len) + { + if (next && 0 < next->len) + { + result = FTreeDelete(next->iter.ftreeHdr, &next->iter.fti, next->start); + if (result != WFSKRN_RESULT_OK) + { + return result; + } + FBADirtyFtreeBlock(area, &next->iter); + } + result = FTreeModify(prev->iter.ftreeHdr, &prev->iter.fti, prev->start, + prev->start, newExtent->len / (1<iter); + } + else if (next && 0 < next->len) + { + if (IsLastKey(fti)) + { + result = FTreeDelete(next->iter.ftreeHdr, &next->iter.fti, next->start); + if (result != WFSKRN_RESULT_OK) + { + return result; + } + FBADirtyFtreeBlock(area, &next->iter); + +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + osTPrintf("*** connect to the next extent ***\n"); + } +#endif // FBA_DEBUG_VERBOSE + result = FreeBlkInsert(area, iter, newExtent->start, newExtent->len); // [check] recursive call. + } + else + { + WFSKRN_FTREE_ASSERT(newExtent->start < next->start); + result = FTreeModify(iter->ftreeHdr, fti, next->start, newExtent->start, newExtent->len / (1<ftreeHdr, fti, newExtent->start, newExtent->len / (1<ftreeHdr)); + + // The F-tree block was full and split into 2 F-tree blocks. + // newExtent is not yet inserted. + + // insert the newExtent. + result = InsertNewChild(area, iter, newExtent, nBlkLog2Size); + + // WFSKRN_FTREE_ASSERT(FTreeVerifyTree(iter->ftreeHdr)); + } + } + return result; +} + +static inline void ConnectToPrevExtent(AreaInfo* area, FBATreeItr* iter, FTreeExtent* newExtent, + FTreeExtentInfo* prev, WFSBlkAdr minBlkLenUpperSubTuree) +{ + if (prev->alignment) + { + if (minBlkLenUpperSubTuree <= (prev->len + newExtent->len)) + { + prev->len = 0; // cannot connect. + return; + } + } + + newExtent->start = prev->start; + newExtent->len += prev->len; +} + +static inline void ConnextToNextExtent(AreaInfo* area, FBATreeItr* iter, FTreeExtent* newExtent, + FTreeExtentInfo* next, WFSBlkAdr minBlkLenUpperSubTuree) +{ + if (next->alignment) + { + if (minBlkLenUpperSubTuree <= (next->len + newExtent->len)) + { + next->len = 0; // cannot connect. + return; + } + } + + newExtent->len += next->len; +} + +static void CheckAlignment(FTreeExtentInfo* prev, FTreeExtentInfo* next, WFSBlkAdr minBlkLenUpperSubTuree) +{ + prev->alignment = (WFSBool) FALSE; + next->alignment = (WFSBool) FALSE; + + if (0 < prev->len) + { + WFSBlkAdr end = prev->start + prev->len; + if (end % minBlkLenUpperSubTuree == 0) + { + prev->alignment = (WFSBool) TRUE; + } + } + + if (0 < next->len) + { + WFSBlkAdr start = next->start; + if (start % minBlkLenUpperSubTuree == 0) + { + next->alignment = (WFSBool) TRUE; + } + } +} + +WFSKrnResult InsertIntoTopTree(AreaInfo* area, FBATreeItr* iter, FTreeExtent* newExtent, + FTreeExtentInfo* prev, FTreeExtentInfo* next, u32 nBlkLog2Size, WFSBlkAdr minBlkLenUpperSubTuree) +{ + WFSKrnResult result = WFSKRN_RESULT_UNKNOWN; + FTreeExtent extent = *newExtent; + FTreeExtentInfo* prevExtent = NULL; + FTreeExtentInfo* nextExtent = NULL; + // insert this subtree. + while (extent.start < newExtent->start + newExtent->len) + { + extent.len = (newExtent->start - extent.start) + newExtent->len; + if (minBlkLenUpperSubTuree < extent.len) + { + WFSBlkAdr end; + end = ROUNDDOWN(extent.start + minBlkLenUpperSubTuree, minBlkLenUpperSubTuree); + extent.len = end - extent.start; + } + + if (extent.start == newExtent->start && 0 < prev->len) + { + prevExtent = prev; + } + else + { + prevExtent = NULL; + } + if (extent.start + extent.len == newExtent->start + newExtent->len && 0 < next->len) + { + nextExtent = next; + } + else + { + nextExtent = NULL; + } + + result = InsertIntoThisSubTree(area, iter, nBlkLog2Size, &extent, prevExtent, nextExtent); + if (result != WFSKRN_RESULT_OK) + { + break; + } + extent.start += extent.len; + } + + return result; +} + +static WFSKrnResult Insert(AreaInfo* area, FBATreeItr* iter, WFSBlkAdr nBlkAdr, WFSBlkAdr nBlkLen, u32 nBlkLog2Size) +{ + WFSKrnResult result; + WFSBlkAdr minBlkLenUpperSubTuree; + u32 subTreeIdx; + FTreeExtent newExtent; + WFSBool InsertUpperTree = (WFSBool) FALSE; + + subTreeIdx = GetSubTreeType(nBlkLen); + minBlkLenUpperSubTuree = (1<eptreeHdr) + { + return WFSKRN_RESULT_INVALID; + } + + /* + +------------------+ +-------------+ + | prev extent | | next extent | + +------------------+ +-------------+ + A Insert + | + alignment | alignment + : | : + +----:---------------:------+ + |head: body : tail | + +----:---------------:------+ + : : + headEnd tailStart + + */ + + subTreeIdx = GetSubTreeType(nBlkLen); + nBlkLog2Size = FTreeBlkLog2Ofs[subTreeIdx]; + subTreeMinBlkLen = (1<isInserted = (WFSBool) TRUE; // leaves or nodes are modified. + + // the P-tree block is pinned. + // an F-tree block is pinned. + + WFSKRN_FTREE_ASSERT(FTreeVerifyTree(iter->ftreeHdr)); + return result; +} + +static WFSKrnResult DivideBlock(WFSBlkAdr existingKey, WFSBlkAdr keyBlkLen, u32 nSubTreeBlkLog2Size, + WFSBlkAdr nBlkAdr, WFSBlkAdr nBlkLen, RemainderExtents* remainder) +{ + WFSBlkAdr len; + if (existingKey == nBlkAdr) + { + // no head. + remainder->head.len = 0; + remainder->head.start = 0; + remainder->fractionHead.len = 0; + remainder->fractionHead.start = 0; + } + else + { + remainder->head.start = existingKey; + remainder->head.len = ROUNDDOWN(nBlkAdr - existingKey, (1<fractionHead.len = (nBlkAdr - existingKey) % (1<fractionHead.start = remainder->head.start + remainder->head.len; + } + + len = (existingKey + keyBlkLen) - (nBlkAdr + nBlkLen); + if (len == 0) + { + // no tail + remainder->tail.len = 0; + remainder->fractionTail.len = 0; + } + else + { + remainder->fractionTail.start = nBlkAdr + nBlkLen; + + remainder->fractionTail.len = ROUNDUP(nBlkAdr + nBlkLen, (1<tail.start = remainder->fractionTail.start + remainder->fractionTail.len; + remainder->tail.len = existingKey + keyBlkLen - (remainder->tail.start); + } + + return WFSKRN_RESULT_OK; +} + +static WFSKrnResult DeleteFTreeBlock(AreaInfo* area, FBATreeItr* iter) +{ + FTreeItr* fti; + EPTreeItr* epti; + WFSKrnResult result = WFSKRN_RESULT_NOT_EMPTY; + PTreeHdr* subTree; + int index; + u32 addrCb; + FBATreeItr insertIter; + + epti = EPTreeGetLastIter((MEPTreeItr*) iter); + if (epti->nKey == 0) // The 1st F-tree is never removed. + { + return WFSKRN_RESULT_NOT_EMPTY; + } + + fti = &iter->fti; + // check other sub-trees. + for (index = 0; index < MAX_SUB_TREE; ++index) + { + subTree = &iter->ftreeHdr->tree[index]; + if (fti->subTree == subTree) + { + continue; + } + if (subTree->nNumRecs != 0) + { + return WFSKRN_RESULT_NOT_EMPTY; + } + } + + // all subtree are empty. +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + osTPrintf("DeleteFTreeBlock(): delete control block\n"); + } +#endif //FBA_DEBUG_VERBOSE + index = epti->aEntryIdx[0]; + addrCb = epti->pLeaf->aData[index]; + + WFSBlkAdr freeBlks[(EPTREE_MAX_HEIGHT-1) * 2]; + memset(freeBlks, 0, sizeof(freeBlks)); + result = EPTreeDelete(area, (MEPTreeItr*) iter, EPTREE_GET_KEY(epti), freeBlks); + FBAFreeCache(area, addrCb); + iter->ftreeHdr = 0; + // unpin ftreeHdr here. + + // the P-tree block is pinned. + FBAItrOpen(area, &insertIter); + + // insert F-tree block into Freeblock allocator as a free block. + result = FreeBlkInsert(area, &insertIter, addrCb, 1); + for (index = 0; index < 2 * (EPTREE_MAX_HEIGHT-1) && result == WFSKRN_RESULT_OK; ++index) + { + if (freeBlks[index] != 0) + { + // no need to increment header->tatalBlks, because + // both a meta-block and freeblocks are in FBA tree. + result = FreeBlkInsert(area, &insertIter, freeBlks[index], 1); + } + } + + FBAItrClose(area, &insertIter); + + // must not increment header->totalBlks here, + // when a control block is changed to a freeblock. + return result; +} + +static WFSKrnResult DeleteBody(AreaInfo* area, FBATreeItr* iter, u32 existingKey) +{ + WFSKrnResult result; + FTreeItr* fti = &iter->fti; + + if (fti->subTree->nNumRecs == 1) + { + result = DeleteFTreeBlock(area, iter); + if (result != WFSKRN_RESULT_NOT_EMPTY) + { + // If result == WFSKRN_RESULT_OK, + // the control block including existingKey was removed, and + // inserted the block address into the freeblock tree as a free block. + return result; + } + } + + result = FTreeDelete(iter->ftreeHdr, fti, existingKey); + if (result != WFSKRN_RESULT_OK) + { + WFSKRN_FTREE_ASSERT(FTreeVerifyTree(iter->ftreeHdr)); + return result; + } + FBADirtyFtreeBlock(area, iter); + + return result; +} + +WFSKrnResult FreeBlkDelete(AreaInfo* area, + FBATreeItr* iter, WFSBlkAdr nBlkAdr, WFSBlkAdr nBlkLen, u32 nBlkLog2Size) +{ + WFSKrnResult result; + FTreeItr* fti = &iter->fti; + u32 nSubTreeBlkLog2Size; + + // the P-tree block is pinned. + // F-tree may be pinned. + + if (!iter->eptreeHdr) + { + return WFSKRN_RESULT_INVALID; + } + + // find f-tree block. + result = FBALookup(area, iter, nBlkAdr, nBlkLog2Size); + if (result == WFSKRN_RESULT_OK) + { + RemainderExtents remainder; + u32 existingKey = FTREE_GET_KEY(fti); + u32 existingData = FTREE_GET_DATA(fti); + WFSBlkAdr keyBlkLen; + int treeType; + + /* + alignment alignment alignemnt alienment alignment + : : : : : + : nBlkAdr : : : : + : | : nBlkLen : : : + : |<---------------------------------->: : : + key0 : V : : : : : + | : +------------------------------------+ : : + V : | : : | : : + +------------------:-----------|------:------------------:----------|-------:------------------+ + |//////////////////:///////////|//////://////////////////://////////|///////://////////////////| + +------------------:-----------|------:------------------:----------|-------:------------------+ + : : | : : | : : + : : +------------------------------------+ : : + : : : : : : : : + : : : : : : : : + : : : : : : : : + <-----------------><----------><-----------------------------------><------><----------------->: + A head fraction to be deleted. fraction tail : + | head tail : + | : + |<-------------------------------------------------------------------------------------------->: + | (existingData + 1) * (1<ftreeHdr, &iter->fti); + nSubTreeBlkLog2Size = FTreeBlkLog2Ofs[treeType]; // [check] should refine. + keyBlkLen = (existingData + 1) * (1<ftreeHdr)); + + if (0 < remainder.head.len) + { + // [check] should refine using FTreeInsert(). + result = FreeBlkInsert(area, iter, remainder.head.start, remainder.head.len); + } + + if (0 < remainder.tail.len) + { + result = FreeBlkInsert(area, iter, remainder.tail.start, remainder.tail.len); + } + + if (0 < remainder.fractionHead.len) + { + result = FreeBlkInsert(area, iter, remainder.fractionHead.start, remainder.fractionHead.len); + } + + if (0 < remainder.fractionTail.len) + { + result = FreeBlkInsert(area, iter, remainder.fractionTail.start, remainder.fractionTail.len); + } + } + +FBA_DELETE_RESULT: + return result; +} + +WFSKrnResult FreeBlkFirst(AreaInfo* area, FBATreeItr* iter, u32 nSubTreeBlkLog2Size) +{ + WFSKrnResult result; + + // the P-tree block is pinned. + + if (!iter->eptreeHdr) + { + return WFSKRN_RESULT_INVALID; + } + + result = EPTreeFirst(area, (MEPTreeItr*) iter); + while (result == WFSKRN_RESULT_OK) + { + FTreeItr* fti = &iter->fti; + result = FBAGetAndPinFtreeBlock(area, iter, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result != WFSKRN_RESULT_OK) + { + break; + } + + // search F-tree. + memset(fti->ptree.aEntryIdx, 0, sizeof(fti->ptree.aEntryIdx)); + fti->subTree = FTreeSelectSubTree(iter->ftreeHdr, nSubTreeBlkLog2Size); + result = FTreeFirst(iter->ftreeHdr, fti); + if (result == WFSKRN_RESULT_OK) + { + break; + } + + // 1st F-tree may be empty. + // (It must not be deleted even when it is empty.) + result = EPTreeNext(area, (MEPTreeItr*) iter); + } + + if (result == WFSKRN_RESULT_OK) + { + iter->isInserted = (WFSBool) FALSE; + } + else + { + iter->isInserted = (WFSBool) TRUE; + } + + // the P-tree block is pinned. + // an F-tree block is pinned. + return result; +} + +WFSKrnResult FreeBlkNext(AreaInfo* area, FBATreeItr* iter) +{ + WFSKrnResult result = WFSKRN_RESULT_FTREE_EMPTY; + FTreeItr* fti = &iter->fti; + int subTreeIndex; + + // the P-tree block is pinned. + // an F-tree block is pinned. + + // FBA_STRICT_ASSERT(FTreeVerifyTree(iter->ftreeHdr)); + if (0 < iter->fti.subTree->nNumRecs) + { + result = FTreeNext(iter->ftreeHdr, fti); + } + + subTreeIndex = (fti->subTree - &iter->ftreeHdr->tree[0]); + while (result == WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND || + result == WFSKRN_RESULT_NOT_FOUND || + result == WFSKRN_RESULT_FTREE_EMPTY) + { + + // search the next F-tree. + result = EPTreeNext(area, (MEPTreeItr*) iter); + if (result == WFSKRN_RESULT_OK) + { + result = FBAGetAndPinFtreeBlock(area, iter, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result == WFSKRN_RESULT_OK) + { + fti->subTree = &iter->ftreeHdr->tree[subTreeIndex]; + if (fti->subTree->nNumRecs == 0) + { + // skip the empty block. + result = WFSKRN_RESULT_FTREE_EMPTY; + continue; + } + result = FTreeFirst(iter->ftreeHdr, fti); + } + } + else + { + break; + } + } + + // the P-tree block is pinned. + // an F-tree block is pinned. + return result; +} + +WFSKrnResult FreeBlkLast(AreaInfo* area, FBATreeItr* iter, u32 nSubTreeBlkLog2Size) +{ + WFSKrnResult result; + FTreeItr* fti = &iter->fti; + + // the P-tree block is pinned. + + if (!iter->eptreeHdr) + { + return WFSKRN_RESULT_INVALID; + } + + result = EPTreeLast(area, (MEPTreeItr*) iter); + while (result == WFSKRN_RESULT_OK) + { + result = FBAGetAndPinFtreeBlock(area, iter, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result == WFSKRN_RESULT_OK) + { + // search F-tree. + memset(fti->ptree.aEntryIdx, 0, sizeof(fti->ptree.aEntryIdx)); + fti->subTree = FTreeSelectSubTree(iter->ftreeHdr, nSubTreeBlkLog2Size); + if (fti->subTree->nNumRecs == 0) + { + iter->isInserted = (WFSBool) FALSE; + result = EPTreePrev(area, (MEPTreeItr*) iter); + continue; + } + + result = FTreeLast(iter->ftreeHdr, fti); + break; + } + } + + if (result == WFSKRN_RESULT_OK) + { + iter->isInserted = (WFSBool) FALSE; + } + else + { + iter->isInserted = (WFSBool) TRUE; + } + + // the P-tree block is pinned. + // an F-tree block is pinned. + return result; +} + +WFSKrnResult FreeBlkPrev(AreaInfo* area, FBATreeItr* iter) +{ + WFSKrnResult result; + FTreeItr* fti = &iter->fti; + + // P-tree and F-tree blocks are pinned. + + // FBA_STRICT_ASSERT(FTreeVerifyTree(iter->ftreeHdr)); + if (iter->isInserted == (WFSBool) TRUE) + { + return WFSKRN_RESULT_FTREE_RETRY; // must call Find() or Last() before FreeBlkPrev(). + } + + result = FTreePrev(iter->ftreeHdr, fti); + while (result == WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND || + result == WFSKRN_RESULT_NOT_FOUND || + result == WFSKRN_RESULT_FTREE_EMPTY) + { + int subTreeIndex = (fti->subTree - &iter->ftreeHdr->tree[0]); + + // lookup the previous F-tree. + result = EPTreePrev(area, (MEPTreeItr*) iter); + if (result == WFSKRN_RESULT_OK) + { + result = FBAGetAndPinFtreeBlock(area, iter, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result == WFSKRN_RESULT_OK) + { + memset(fti->ptree.aEntryIdx, 0, sizeof(fti->ptree.aEntryIdx)); + fti->subTree = &iter->ftreeHdr->tree[subTreeIndex]; + + if (fti->subTree->nNumRecs == 0) + { + result = WFSKRN_RESULT_FTREE_EMPTY; + continue; // skip. Because the subtree in this f-tree block is empty. + } + result = FTreeLast(iter->ftreeHdr, fti); + } + } + else + { + // set 1st. entry. + memset(fti->ptree.aEntryIdx, 0, sizeof(fti->ptree.aEntryIdx)); + break; + } + } + + // the P-tree block is pinned. + // an F-tree block is pinned. + return result; +} + +static inline void AllocatorInit(PTreeAllocator* allocator, EPTreeHdr* eptreeHdr) +{ + allocator->pBase = GET_BLOCK_HEAD(eptreeHdr); + allocator->fpAllocNode = FTreeAllocEntry; + allocator->fpAllocNodes = FTreeAllocEntries; + allocator->fpFreeNode = FTreeFreeEntry; +} + +// public APIs. + +WFSKrnResult FreeBlkFind(AreaInfo* area, FBATreeItr* iter, u32 nRefBlkAdr, u32 nSubTreeBlkLog2Size) +{ + WFSKrnResult result; + + // the P-tree block is pinned. + + if (!iter->eptreeHdr[0]) + { + return WFSKRN_RESULT_INVALID; + } + + result = FBALookup(area, iter, nRefBlkAdr, nSubTreeBlkLog2Size); + + if (result == WFSKRN_RESULT_OK) + { + return WFSKRN_RESULT_OK; + } + + if (iter->fti.subTree->nNumRecs == 0) + { + while (result != WFSKRN_RESULT_OK) + { + result = EPTreeNext(area, (MEPTreeItr*) iter); + if (result != WFSKRN_RESULT_OK) + { + break; + } + + result = FBAGetAndPinFtreeBlock(area, iter, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result == WFSKRN_RESULT_OK) + { + iter->fti.subTree = FTreeSelectSubTree(iter->ftreeHdr, nSubTreeBlkLog2Size); + result = FTreeFirst(iter->ftreeHdr, &iter->fti); + } + } + } + else + { + result = WFSKRN_RESULT_OK; + } + + // the P-tree block is pinned. + // an F-tree block is pinned. + return result; +} + +WFSKrnResult FreeBlkFindStrict(AreaInfo* area, FBATreeItr* iter, u32 nBlkAdr, u32 nSubTreeBlkLog2Size) +{ + WFSKrnResult result; + + // the P-tree block is pinned. + + if (!iter->eptreeHdr) + { + return WFSKRN_RESULT_INVALID; + } + result = FBALookupStrict(area, iter, nBlkAdr, nSubTreeBlkLog2Size); + + // the P-tree block is pinned. + // an F-tree block is pinned. + return result; +} + +static WFSKrnResult InsertFreeBlock(AreaInfo* area) +{ + WFSKrnResult result; + FBATreeItr iter; + FTreeExtent extent; + + // the P-tree block is pinned. + + extent.start = 2; // FBA_ROOT_BLK and FBA_INITIAL_FTREE_BLK are reserved. + extent.len = area->ah.nNumBlks - extent.start; + + FBAItrOpen(area, &iter); + +#if _DEBUG + u32 pinCount = BCacheSkipCheckPin(); +#endif + + result = FreeBlkInsert(area, &iter, extent.start, extent.len); + WFSKRN_FTREE_ASSERT(result == WFSKRN_RESULT_OK); + + GET_FBATREE_HDR(area)->totalBlks = area->ah.nNumBlks; + + FBAItrClose(area, &iter); + +#if _DEBUG + WFSKRN_FTREE_ASSERT(BCacheStopSkipCheckPin(pinCount) == WFSKRN_RESULT_OK); +#endif + + // the P-tree block is pinned. + return result; +} + +WFSKrnResult FreeBlkInit(AreaInfo *pAreaInfo, u32 offset) +{ + FBATreeHdr* header; + WFSKrnResult result; + if (offset < sizeof(WFSMetaDataFlags) + sizeof(WFSHashCode)) + { + // must not overwrite hash. + return WFSKRN_RESULT_INVALID; + } +#ifdef FBA_TEST + offset += pAreaInfo->nBlkSize - offset - sizeof(EPTreeHdr) - 32 * 3; +#endif // _FBA_TEST + // the P-tree block is pinned. + + header = GET_FBATREE_HDR(pAreaInfo); + header->totalBlks = 0; + header->ofsEPtreeHdr = pAreaInfo->nBlkSize - offset - sizeof(EPTreeHdr); // offset from pAreaInfo->pAflh. + header->ptreeHeight = FBA_PTREE_MIN_HEIGHT; // This means only one ptree block in the FBA tree. + + result = EPTreeInit(pAreaInfo, offset); + if (result != WFSKRN_RESULT_OK) + { + return result; + } + + result = InsertFreeBlock(pAreaInfo); + + // the P-tree block is pinned. + return result; +} + +static WFSKrnResult FBAAllocInit(AreaInfo* area, WFSBlkAdr nRefBlkAdr, + FBATreeItr* iter, FBATreeItr* iterPrev, CacheMap* workBuf, u32 nBlkLog2Size) +{ + WFSKrnResult result; + WFSBlkAdr start; + + result = FreeBlkFind(area, iter, nRefBlkAdr, nBlkLog2Size); + if (result != WFSKRN_RESULT_OK) + { + result = FreeBlkFirst(area, iter, nBlkLog2Size); + } + if (result == WFSKRN_RESULT_OK) + { + // prepare backward search. + result = CopyFBAIter(area, iter, iterPrev, BCACHE_FLAG_READ | BCACHE_FLAG_PINNED); + if (result != WFSKRN_RESULT_OK) + { + return result; // [check] error handling. + } + + if (result == WFSKRN_RESULT_OK) + { + start = FBA_RESULT_KEY(iter); + workBuf->diskAddr = start; + } + } + + return result; +} + +static ExtentStorageHeader* InitWorkBuffer(AreaInfo* area, WFSBlkAdr nRefBlkAdr, FBATreeItr* iter, CacheMap* workBuf) +{ + WFSKrnResult result; + ExtentStorageEntry* extents; + ExtentStorageHeader* extentHeader; + + result = FBAGetCache(area, workBuf->diskAddr, BCACHE_FLAG_DIRTY | BCACHE_FLAG_PINNED, &workBuf->cache); + if (result != WFSKRN_RESULT_OK) + { + return NULL; // [check] should return WFSKrnResult? + } + + extentHeader = (ExtentStorageHeader*) (workBuf->cache); + + extents = (ExtentStorageEntry*) ((u8*) extentHeader + sizeof(ExtentStorageHeader)); + if (nRefBlkAdr <= FBA_RESULT_KEY(iter)) + { + // next + extentHeader->numPrev = 0; + extentHeader->numNext = 1; + } + else + { + // prev + int indexPrev = ((area->nBlkSize - sizeof(ExtentStorageHeader)) / sizeof(ExtentStorageEntry)) - 1; + extentHeader->numPrev = 1; + extentHeader->numNext = 0; + extents = &extents[indexPrev]; + } + + + extents->start = FBA_RESULT_KEY(iter); + extents->treeType = (u16) GET_SUBTREE_TYPE(iter->ftreeHdr, &iter->fti); + WFSKRN_FTREE_ASSERT(extents->treeType <= FTREE_TYPE_G); + //WFSKRN_FTREE_ASSERT(FTREE_TYPE_A <= extents->treeType); + extents->len = (FBA_RESULT_DATA(iter) + 1) * (1<treeType]); + + extentHeader->prio = 1; + return extentHeader; +} + +static inline WFSBool IsFarawayFromRefAddr(AreaInfo* area, ExtentStorageHeader* extentHeader, + ExtentStorageEntry* extent, int indexTail, int indexHead, WFSBlkAdr nRefBlkAdr, WFSBlkAdr nBlkLen) +{ + if (0 < extentHeader->numNext) + { + ASSERT(0 < extent[indexTail].start); + if ((area->ah.nNumBlks>>1) < extent[indexTail].start - nRefBlkAdr) // [check] hard-coding. + { + return (WFSBool) TRUE; + } + } + if (0 < extentHeader->numPrev) + { + ASSERT(0 < extent[indexHead].start); + if ((area->ah.nNumBlks>>1) < nRefBlkAdr - extent[indexHead].start) // [check] hard-coding. + { + return (WFSBool) TRUE; + } + } + return (WFSBool) FALSE; +} + +/* + +-------------+ <------ aBlkAdr + | block addr0 | A + +-------------+ | + | | | + : : | nStride + | | | + +-------------+ V + | block addr1 | A + +-------------+ | + | | | + : : | nStride + | | | + +-------------+ V + | block addr2 | + +-------------+ + : : + : : + : : + +-------------+ + | block addrN | N == nNumBlks - 1 + +-------------+ + : : + : : + +-------------+ + disk block + block addr m ----> +----------------+ + | | + | 2^nBlkLog2Size | + | | + +----------------+ +*/ + +static WFSKrnResult SelectFreeBlocks(AreaInfo* area, FBATreeItr* iter, FBATreeItr* iterPrev, + ExtentStorageHeader* extentHeader, WFSBlkAdr nRefBlkAdr, WFSBlkAdr nBlkLen) +{ + WFSKrnResult result = WFSKRN_RESULT_OK; + int indexPrev = ((area->nBlkSize - sizeof(ExtentStorageHeader)) / sizeof(ExtentStorageEntry)) - 1; + int indexNext = 0; + u32 reservedLenPrev = 0; + u32 reservedLenNext = 0; + u32 totalBlk = 0; + u32 len; + u32 dn = 0; + u32 dp = 0; + WFSBool stopSearchNext = (WFSBool) FALSE; + WFSBool stopSearchPrev = (WFSBool) FALSE; + ExtentStorageEntry* extent; + + extent = (ExtentStorageEntry*) ((u8*) extentHeader + sizeof(ExtentStorageHeader)); + if (extentHeader->numNext == 1) + { + dn = extent[indexNext].len; + ++indexNext; + totalBlk += extent->len; + } + else + { + WFSKRN_FTREE_ASSERT(extentHeader->numPrev == 1); + dp = extent[indexPrev].len; + totalBlk += extent[indexPrev].len; + --indexPrev; + } + + // search + while (totalBlk < nBlkLen) + { + if (!stopSearchNext && (stopSearchPrev || dn <= dp)) + { + if (0 < reservedLenNext) + { + ++indexNext; + ++extentHeader->numNext; + len = reservedLenNext; + reservedLenNext = 0; + result = WFSKRN_RESULT_OK; + } + else + { + result = FreeBlkNext(area, iter); + if (result == WFSKRN_RESULT_OK) + { + WFSKRN_FTREE_ASSERT(nRefBlkAdr < FBA_RESULT_KEY(iter)); + dn += FBA_RESULT_KEY(iter) - nRefBlkAdr; + extent[indexNext].start = FBA_RESULT_KEY(iter); + extent[indexNext].treeType = (u16) GET_SUBTREE_TYPE(iter->ftreeHdr, &iter->fti); + + len = (FBA_RESULT_DATA(iter) + 1) * (1<numNext = 1; + extentHeader->numPrev = 0; + break; + } + else + { + ++indexNext; + ++extentHeader->numNext; + } + } + else + { + stopSearchNext = (WFSBool) TRUE; + continue; + } + } + } + else if (!stopSearchPrev) + { + if (0 < reservedLenPrev) + { + --indexPrev; + ++extentHeader->numPrev; + len = reservedLenPrev; + reservedLenPrev = 0; + result = WFSKRN_RESULT_OK; + } + else + { + result = FreeBlkPrev(area, iterPrev); + if (result == WFSKRN_RESULT_OK) + { + WFSKRN_FTREE_ASSERT(FBA_RESULT_KEY(iterPrev) - nRefBlkAdr); + dp += nRefBlkAdr - FBA_RESULT_KEY(iterPrev); + extent[indexPrev].start = FBA_RESULT_KEY(iterPrev); + extent[indexPrev].nNumBlk = FBA_RESULT_DATA(iterPrev); + extent[indexPrev].treeType = (u16) GET_SUBTREE_TYPE(iterPrev->ftreeHdr, &iterPrev->fti); + len = (FBA_RESULT_DATA(iterPrev) + 1) * (1<nBlkSize - sizeof(ExtentStorageHeader)) / sizeof(ExtentStorageEntry)) - 1; + extent[indexPrev0] = extent[indexPrev]; + extentHeader->numNext = 0; + extentHeader->numPrev = 1; + break; + } + else + { + --indexPrev; + ++extentHeader->numPrev; + } + } + else + { + stopSearchPrev = (WFSBool) TRUE; + continue; + } + } + } + else + { + result = WFSKRN_RESULT_DIRECTORY_QUOTA; + // FreeBlkDumpFreeblock(area, header); + goto SEARCHBLK_RESULT; + } + + if (indexPrev <= indexNext) + { + result = WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED; // Work block (8KB) is too small to store all extents. In this case, + // WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED seems to be suitable. + goto SEARCHBLK_RESULT; + } + totalBlk += len; + } + + if (IsFarawayFromRefAddr(area, extentHeader, extent, indexNext-1, indexPrev+1, nRefBlkAdr, nBlkLen)) + { + ++extentHeader->prio; + } + +SEARCHBLK_RESULT: + return result; +} + +static WFSKrnResult SearchAndDelete(AreaInfo* area, FBATreeItr* iter, + WFSBlkAdr nBlkAdr, WFSBlkAdr nNumBlks, u16 startSubTreeType) +{ + WFSKrnResult result = WFSKRN_RESULT_NOT_FOUND; + u16 subTreeType; + for (subTreeType = startSubTreeType; subTreeType < MAX_SUB_TREE; ++subTreeType) + { + osTPrintf("SearchAndDelete: subTree %u start %u len %u\n", subTreeType, nBlkAdr, nNumBlks); + result = FreeBlkDelete(area, iter, nBlkAdr, nNumBlks, FTreeBlkLog2Ofs[subTreeType]); + if (result == WFSKRN_RESULT_OK) + { + osTPrintf("result %d\n", result); + break; + } + } + return result; +} + +static WFSKrnResult MakeFreeBlkListFromForwardSearch(AreaInfo* area, FBATreeItr* iter, + ExtentStorageHeader* extentHeader, WFSBlkAdr nRefBlkAdr, WFSBlkAdr* num, + WFSBlkAdr* aBlkAdr, s32 nStride, u32 unitBlkLen) +{ + WFSKrnResult result = WFSKRN_RESULT_INVALID; + ExtentStorageEntry* storage = (ExtentStorageEntry*) ((u8*) extentHeader + sizeof(ExtentStorageHeader)); + int index; + WFSBlkAdr block; + + if (extentHeader->numNext == 0) + { + return WFSKRN_RESULT_OK; + } + + // result of forward search. + for (index = 0; index < extentHeader->numNext; ++index) + { + ExtentStorageEntry* extent = &storage[index]; + + if (*num * unitBlkLen < extent->len) + { + if (extent->start <= nRefBlkAdr && + nRefBlkAdr + *num * unitBlkLen <= extent->start + extent->len) + { + extent->start = nRefBlkAdr; + } + extent->len = *num * unitBlkLen; + } + + for (block = 0; block * unitBlkLen < extent->len && 0 < *num; ++block) + { + *aBlkAdr = extent->start + block * unitBlkLen; + aBlkAdr = (WFSBlkAdr*) ((u8*) aBlkAdr + nStride); + --*num; + } + +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + osTPrintf("[DEL] start %5u, len %4u, treeType %1d, extent[%4d] \n", + extent->start, extent->len, extent->treeType, index); + } +#endif // FBA_DEBUG_VERBOSE + + result = FreeBlkDelete(area, iter, extent->start, block * unitBlkLen, + FTreeBlkLog2Ofs[extent->treeType]); + if (result != WFSKRN_RESULT_OK) + { + + result = SearchAndDelete(area, iter, extent->start, block * unitBlkLen, extent->treeType + 1); + if (result != WFSKRN_RESULT_OK) + { + // Extents are changed by releasing control blocks, delete blocks one by one. + extent->start += unitBlkLen * (block - 1); + while (block--) + { + result = SearchAndDelete(area, iter, extent->start, unitBlkLen, extent->treeType); + if (result != WFSKRN_RESULT_OK) + { + break; + } + extent->start -= unitBlkLen; + } + } + + if (result != WFSKRN_RESULT_OK) + { + osTPrintf("MakeFreeBlkList() [2]: ***FreeBlkDelete error %d ***\n", result); // [check] restore. NYI. + result = WFSKRN_RESULT_DIRECTORY_QUOTA; // [check] should return WFSKRN_RESULT_FATAL_ERROR? + WFSKRN_FTREE_ASSERT(0); // [check] should not reach here. + break; + } + } + } + return result; +} + +static WFSKrnResult MakeFreeBlkListFromBackwardSearch(AreaInfo* area, FBATreeItr* iter, + ExtentStorageHeader* extentHeader, WFSBlkAdr nRefBlkAdr, WFSBlkAdr* num, + WFSBlkAdr* aBlkAdr, s32 nStride, u32 unitBlkLen) +{ + WFSKrnResult result = WFSKRN_RESULT_INVALID; + ExtentStorageEntry* storage = (ExtentStorageEntry*) ((u8*) extentHeader + sizeof(ExtentStorageHeader)); + int index; + int indexPrevTop; + int indexLast; + WFSBlkAdr block; + + if (extentHeader->numPrev == 0) + { + return WFSKRN_RESULT_OK; + } + + // result of backward search. + indexLast = ((area->nBlkSize - sizeof(ExtentStorageHeader)) / sizeof(ExtentStorageEntry)); + indexPrevTop = indexLast - extentHeader->numPrev; + for (index = indexPrevTop; index < indexPrevTop + extentHeader->numPrev; ++index) + { + ExtentStorageEntry* extent = &storage[index]; + + if (*num * unitBlkLen < extent->len) + { + if (extent->start <= nRefBlkAdr && + nRefBlkAdr + *num * unitBlkLen <= extent->start + extent->len) + { + extent->start = nRefBlkAdr; + } + else + { + extent->start += (extent->len - *num * unitBlkLen); + } + extent->len = *num * unitBlkLen; + } + + for (block = 0; block * unitBlkLen < extent->len && 0 < *num; ++block) + { + *aBlkAdr = extent->start + block * unitBlkLen; + aBlkAdr = (WFSBlkAdr*) ((u8*) aBlkAdr + nStride); + --*num; + } + +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + osTPrintf("[DEL] extent[%4d] len %4u, start %5u, treeType %1d\n", + index, extent->len, extent->start, extent->treeType); + } +#endif // FBA_DEBUG_VERBOSE + + result = FreeBlkDelete(area, iter, extent->start, + block * unitBlkLen, FTreeBlkLog2Ofs[extent->treeType]); + if (result != WFSKRN_RESULT_OK) + { + u16 subTreeType; + for (subTreeType = extent->treeType + 1; subTreeType < MAX_SUB_TREE; ++subTreeType) + { + osTPrintf("[2] subTree %u start %u len %u\n", + extent->treeType, extent->start, block * unitBlkLen); + result = FreeBlkDelete(area, iter, extent->start, + block * unitBlkLen, FTreeBlkLog2Ofs[subTreeType]); + if (result == WFSKRN_RESULT_OK) + { + break; + } + } + + if (result != WFSKRN_RESULT_OK) + { + osTPrintf("MakeFreeBlkList() [1]: ***FreeBlkDelete error %d ***\n", result); // [check] restore. NYI. + result = WFSKRN_RESULT_DIRECTORY_QUOTA; // [check] should return WFSKRN_RESULT_FATAL_ERROR? + WFSKRN_FTREE_ASSERT(0); // [check] should not reach here. + break; + } + } + } + return result; +} + +static WFSKrnResult MakeFreeBlkList(AreaInfo* area, ExtentStorageHeader* extentHeader, + WFSBlkAdr nRefBlkAdr, WFSBlkAdr nNumBlks, WFSBlkAdr* aBlkAdr, s32 nStride, u32 nBlkLog2Size) +{ + WFSKrnResult result = WFSKRN_RESULT_INVALID; + FBATreeItr iter; + WFSBlkAdr numToBeAllocated = nNumBlks; + WFSBlkAdr unitBlkLen = (1<nBlkSize - sizeof(ExtentStorageHeader)) / sizeof(ExtentStorageEntry)) - 1; + int indexPrev = indexEnd; + int indexNext = 0; + int idx; + ExtentStorageHeader* eh; + ExtentStorageEntry* extent; + + for (idx = subTreeIdxMax; subTreeIdxMin <= idx; --idx) + { + if (workBufs[idx].cache) + { + extentHeader = (ExtentStorageHeader*) (workBufs[idx].cache); + *subTreeIdx = (u32) idx; + indexPrev -= extentHeader->numPrev; + indexNext += extentHeader->numNext; + + extent = (ExtentStorageEntry*) ((u8*) extentHeader + sizeof(ExtentStorageHeader)); + int i; + for (i = 0; i < extentHeader->numNext; ++i) + { + totalBlks += extent[i].len; + } + for (i = 0; i < extentHeader->numPrev; ++i) + { + totalBlks += extent[indexEnd - i].len; + } + break; + } + } + + if (extentHeader == NULL) + { + return WFSKRN_RESULT_DIRECTORY_QUOTA; + } + if (nBlkLen <= totalBlks) + { + extentHeader->numNext = indexNext; + extentHeader->numPrev = indexEnd - indexPrev; + return WFSKRN_RESULT_OK; + } + + extent = (ExtentStorageEntry*) ((u8*) extentHeader + sizeof(ExtentStorageHeader)); + + for (idx = subTreeIdxMax; (int) subTreeIdxMin <= idx; --idx) + { + eh = (ExtentStorageHeader*) (workBufs[idx].cache); + + if (!eh || idx == *subTreeIdx) + { + continue; + } + + ExtentStorageEntry* exNext = (ExtentStorageEntry*) ((u8*) eh + sizeof(ExtentStorageHeader)); + ExtentStorageEntry* exPrev = &exNext[indexEnd]; + + int numNext = eh->numNext; + int numPrev = eh->numPrev; + for (;;) + { + if (0 < numNext) + { + extent[indexNext++] = *exNext; + totalBlks += exNext->len; + --numNext; + ++exNext; + } + + if (0 < numPrev) + { + extent[indexPrev--] = *exPrev; + totalBlks += exPrev->len; + --numPrev; + --exPrev; + } + if (nBlkLen <= totalBlks) + { + extentHeader->numNext = indexNext; + extentHeader->numPrev = indexEnd - indexPrev; + return WFSKRN_RESULT_OK; + } + + if (numPrev == 0 && numNext == 0) + { + break; + } + } + } + + return WFSKRN_RESULT_DIRECTORY_QUOTA; +} + +static WFSKrnResult FBASearchLowerSubtrees(AreaInfo* area, + WFSBlkAdr nRefBlkAdr,WFSBlkAdr nNumBlks, u32 nBlkLog2Size, CacheMap* workBuf) +{ + WFSKrnResult result = WFSKRN_RESULT_NOT_FOUND; + WFSBlkAdr nBlkLen; + u32 subTreeIdx = FTREE_TYPE_END; + int subTreeIdxMin; + int subTreeIdxMax; + u32 nSubTreeBlkLog2Size; + int idx; + CacheMap workBufs[MAX_SUB_TREE]; + + FBATreeItr iter; + FBATreeItr iterPrev; + + FBAItrOpen(area, &iter); + FBAItrOpen(area, &iterPrev); + + iterPrev.ftreeAddr = 0xffffffff; // [check] this means the address is not specified. + + memset(workBufs, 0, sizeof(workBufs)); + + ExtentStorageHeader* extentHeader = NULL; + + nBlkLen = (nNumBlks * (1<diskAddr = workBufs[subTreeIdx].diskAddr; + workBuf->cache = workBufs[subTreeIdx].cache; + + u32 threshold; + if (nBlkLen < (1<cache); + if (threshold <= extentHeader->numNext + extentHeader->numPrev) + { + ++extentHeader->prio; + } + } + + // choose + for (idx = subTreeIdxMin; idx <= subTreeIdxMax; ++idx) + { + if (workBufs[idx].diskAddr && (idx != subTreeIdx || result != WFSKRN_RESULT_OK)) + { + FBAFreeCache(area, workBufs[idx].diskAddr); + } + } + + return result; +} + +static WFSKrnResult FBASearchUpperSubtrees(AreaInfo* area, WFSBlkAdr nRefBlkAdr, WFSBlkAdr nNumBlks, u32 nBlkLog2Size, + FBASingleEntry* singleEntry) +{ + WFSBlkAdr nBlkLen; + u32 subTreeIdx; + u32 searchBlkLog2Size; + WFSKrnResult result = WFSKRN_RESULT_UNKNOWN; + ExtentStorageEntry alt; // alternative + WFSBlkAdr start; + WFSBlkAdr len; + WFSBlkAdr dist; + WFSBlkAdr altDist = 0; + FBATreeItr iter; + ExtentStorageEntry* entry = &singleEntry->entry; + + FBAItrOpen(area, &iter); + + nBlkLen = (nNumBlks * (1<len = 0; + alt.len = 0; // indicates the extent not found. + + while (++subTreeIdx < MAX_SUB_TREE) + { + searchBlkLog2Size = FTreeBlkLog2Ofs[subTreeIdx]; + + result = FreeBlkFind(area, &iter, nRefBlkAdr, searchBlkLog2Size); + if (result == WFSKRN_RESULT_OK) + { + start = FBA_RESULT_KEY(&iter); + len = (FBA_RESULT_DATA(&iter) + 1) * (1<start = start; + // entry->nNumBlk = FBA_RESULT_DATA(&iter) + 1; + entry->treeType = subTreeIdx; + entry->len = len; + break; + } + + if (start < nRefBlkAdr) + { + dist = nRefBlkAdr - (start + len); + } + else + { + dist = start - nRefBlkAdr; + } + + if (alt.len == 0 || dist < altDist) + { + altDist = dist; + alt.start = start; + alt.nNumBlk = FBA_RESULT_DATA(&iter) + 1; + alt.treeType = subTreeIdx; + alt.len = len; + } + + if (start + len < nRefBlkAdr) + { + // check the next extent. + result = FreeBlkNext(area, &iter); + if (result == WFSKRN_RESULT_OK) + { + start = FBA_RESULT_KEY(&iter); + len = (FBA_RESULT_DATA(&iter) + 1) * (1<start = start; + entry->treeType = subTreeIdx; + entry->len = len; + singleEntry->header.prio = 0; + break; + } + altDist = start - (nRefBlkAdr + nBlkLen); + alt.start = start; + alt.nNumBlk = FBA_RESULT_DATA(&iter) + 1; + alt.treeType = subTreeIdx; + alt.len = len; + singleEntry->header.prio = 1; + + } + + if (alt.len == 0 || dist < altDist) + { + alt.start = start; + alt.nNumBlk = FBA_RESULT_DATA(&iter) + 1; + alt.treeType = subTreeIdx; + alt.len = len; + } + + if (dist < nBlkLen) + { + break; + } + } + } + } + } + + singleEntry->header.prio = 0; // 0 is the highest. + if (entry->len == 0 && alt.len != 0) + { + *entry = alt; + result = WFSKRN_RESULT_OK; + ++singleEntry->header.prio; // decrease the priority. + } + + singleEntry->header.numPrev = 0; + if (result == WFSKRN_RESULT_OK) + { + singleEntry->header.numNext = 1; + } + else + { + singleEntry->header.numNext = 0; + } + + FBAItrClose(area, &iter); + return result; +} + + +static void MergeExtents(AreaInfo* area, WFSBlkAdr nRefBlkAdr, u32 nNumBlks, u32 nBlkLog2Size, CacheMap* workBuf, FBASingleEntry* singleEntry) +{ + ExtentStorageHeader* extentHeader = (ExtentStorageHeader*) (workBuf->cache); + ExtentStorageEntry* extent = (ExtentStorageEntry*) ((u8*) extentHeader + sizeof(ExtentStorageHeader)); + u32 requiredBlkLen = nNumBlks * (1<entry.start) + { + int index; + for (index = 0; index < extentHeader->numNext; ++index) + { + ExtentStorageEntry* entry = &extent[index]; + if (entry->start + entry->len == singleEntry->entry.start) + { + if (requiredBlkLen <= entry->len) + { + return; // no need to merge. + } + /* + +-------+----------------------------+ + | entry | singleEntry | + +-------+----------------------------+ + */ + extentHeader->numNext = 2; + extentHeader->numPrev = 0; + extent[0] = *entry; + extent[1] = singleEntry->entry; + return; + } + } + } + else + { + + int indexEnd = ((area->nBlkSize - sizeof(ExtentStorageHeader)) / sizeof(ExtentStorageEntry)) - 1; + int index; + for (index = 0; index < extentHeader->numPrev; ++index) + { + ExtentStorageEntry* entry = &extent[indexEnd - index]; + if (entry->start == singleEntry->entry.start + singleEntry->entry.len) + { + if (requiredBlkLen <= entry->len) + { + return; // no need to merge. + } + /* + +----------------------------+-------+ + | singleEntry | entry | + +----------------------------+-------+ + */ + extentHeader->numNext = 0; + extentHeader->numPrev = 2; + singleEntry->entry.len -= entry->len; + extent[indexEnd - 1] = *entry; + extent[indexEnd] = singleEntry->entry; + return; + } + } + } +} + +WFSKrnResult FreeBlkAlloc(AreaInfo *pAreaInfo, WFSBlkAdr nRefBlkAdr, WFSBlkAdr nNumBlks, WFSBlkAdr *aBlkAdr, s32 nStride, u32 nBlkLog2Size) +{ + WFSKrnResult resultUpper = WFSKRN_RESULT_NOT_FOUND; + WFSKrnResult resultLower = WFSKRN_RESULT_NOT_FOUND; + WFSKrnResult result; + FBATreeHdr* header; + CacheMap workBuf; + ExtentStorageHeader* extentHeader; + FBASingleEntry singleEntry; + + ASSERT(aBlkAdr); + ASSERT(pAreaInfo); + ASSERT(0 < nNumBlks); + + // the P-tree block is pinned. + +#if _DEBUG + u32 pinCount = BCacheSkipCheckPin(); +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + osTPrintf("===================\n"); + osTPrintf(" ALLOC (%u, %u)\n", nRefBlkAdr, nNumBlks); + osTPrintf("===================\n"); + } +#endif // FBA_DEBUG_VERBOSE +#endif + header = GET_FBATREE_HDR(pAreaInfo); + WFSKRN_FTREE_ASSERT(header); // header must be set before calling FreeBlkAlloc(). + + nBlkLog2Size -= WFS_LOG2_SMALL_BLK_SIZE; // use offset from WFS_LOG2_SMALL_BLK_SIZE in FreeBlk APIs. + + // try to allocate blocks sequentially. + if (nNumBlks == 1) // [check] hard cording + { + resultLower = FBASearchLowerSubtrees(pAreaInfo, nRefBlkAdr, nNumBlks, nBlkLog2Size, &workBuf); + extentHeader = (ExtentStorageHeader*) (workBuf.cache); + if (resultLower == WFSKRN_RESULT_OK && + extentHeader->prio <= 1) + { + result = MakeFreeBlkList(pAreaInfo, extentHeader, nRefBlkAdr, nNumBlks, aBlkAdr, nStride, nBlkLog2Size); + } + else + { + resultUpper = FBASearchUpperSubtrees(pAreaInfo, nRefBlkAdr, nNumBlks, nBlkLog2Size, &singleEntry); + if (resultUpper == WFSKRN_RESULT_OK) + { + extentHeader = (ExtentStorageHeader*) &singleEntry.header; + result = MakeFreeBlkList(pAreaInfo, extentHeader, nRefBlkAdr, nNumBlks, aBlkAdr, nStride, nBlkLog2Size); + } + else if (resultLower == WFSKRN_RESULT_OK) + { + result = MakeFreeBlkList(pAreaInfo, extentHeader, nRefBlkAdr, nNumBlks, aBlkAdr, nStride, nBlkLog2Size); + } + else + { + result = WFSKRN_RESULT_DIRECTORY_QUOTA; + } + } + } + else + { + resultUpper = FBASearchUpperSubtrees(pAreaInfo, nRefBlkAdr, nNumBlks, nBlkLog2Size, &singleEntry); + if (resultUpper == WFSKRN_RESULT_OK && + singleEntry.header.prio == 0) + { + extentHeader = (ExtentStorageHeader*) &singleEntry.header; + result = MakeFreeBlkList(pAreaInfo, extentHeader, nRefBlkAdr, nNumBlks, aBlkAdr, nStride, nBlkLog2Size); + } + else + { + resultLower = FBASearchLowerSubtrees(pAreaInfo, nRefBlkAdr, nNumBlks, nBlkLog2Size, &workBuf); + extentHeader = (ExtentStorageHeader*) (workBuf.cache); + if (resultLower == WFSKRN_RESULT_OK && + (extentHeader->prio <= 1 || resultUpper != WFSKRN_RESULT_OK)) + { + if (resultUpper == WFSKRN_RESULT_OK) + { + MergeExtents(pAreaInfo, nRefBlkAdr, nNumBlks, nBlkLog2Size, &workBuf, &singleEntry); // Merge singleEntry -> workBuf. + } + result = MakeFreeBlkList(pAreaInfo, extentHeader, nRefBlkAdr, nNumBlks, aBlkAdr, nStride, nBlkLog2Size); + } + else if (resultUpper == WFSKRN_RESULT_OK && + singleEntry.header.prio == 1) + { + extentHeader = (ExtentStorageHeader*) &singleEntry.header; + result = MakeFreeBlkList(pAreaInfo, extentHeader, nRefBlkAdr, nNumBlks, aBlkAdr, nStride, nBlkLog2Size); + } + else + { + result = WFSKRN_RESULT_DIRECTORY_QUOTA; + } + } + } + + if (result == WFSKRN_RESULT_OK) + { + header->totalBlks -= nNumBlks * (1<pVolInfo, startExtent, freeBlks); // must call before FreeBlkInsert(), + // becase a block inserted can be used as a new control block in FreeBlkInsert(). + result = FreeBlkInsert(pAreaInfo, &iter, startExtent, freeBlks); + } + break; + } + + if (*aBlkAdr - *prevBlkAdr != (1<pVolInfo, startExtent, freeBlks); // must call before FreeBlkInsert(), + // becase a block inserted can be used as a new control block in FreeBlkInsert(). + result = FreeBlkInsert(pAreaInfo, &iter, startExtent, freeBlks); + if (result != WFSKRN_RESULT_OK) + { + break; + } + startExtent = *aBlkAdr; + } + + prevBlkAdr = aBlkAdr; + aBlkAdr = (WFSBlkAdr*) ((u8*) aBlkAdr + nStride); + } + + if (result == WFSKRN_RESULT_OK) + { + header->totalBlks += nNumBlks * (1<height; + + memset(node, 0, sizeof(node)); + node[0] = FBA_ROOT_BLK; + numMetaBlks = 1; + + result = EPTreeFirst(area, (MEPTreeItr*) &iter); + while (result == WFSKRN_RESULT_OK) + { + for (level = 1; level < ptreeHeight; ++level) + { + if (node[level] != iter.eptreeHdr[level]->addr) + { + node[level] = iter.eptreeHdr[level]->addr; + ++numMetaBlks; + } + } + + epti = EPTreeGetLastIter((MEPTreeItr*) &iter); + nBlkAdr = PTREE_GET_KEY(epti); + ftreeBlk = PTREE_GET_DATA(epti); + ++numMetaBlks; + + result = EPTreeNext(area, (MEPTreeItr*) &iter); + } + + FBAItrClose(area, &iter); + return numMetaBlks; +} + +u32 FreeBlkGetFreeSize(AreaInfo *pAreaInfo) +{ + FBATreeHdr* header; + + header = GET_FBATREE_HDR(pAreaInfo); + u32 numMetaBlks = GetNumMetaBlks(pAreaInfo); + WFSKRN_FTREE_ASSERT(numMetaBlks <= header->totalBlks); + + return header->totalBlks - numMetaBlks; // unit is 8kB +} + +// +// Debug functions. +// + +WFSBool FreeBlkVerify(AreaInfo* area) +{ + WFSKrnResult result; + WFSBlkAdr nBlkAdr; + FBATreeItr iterSeq; // sequential + FBATreeItr iter; + EPTreeHdr* eptreeHdr; + u32 total = 0; + u32 totalFound = 0; + u32 numMetaBlks; + WFSBool ret; + int i; + + // the P-tree block is pinned. + +#if _DEBUG + FBATreeHdr* header = GET_FBATREE_HDR(area); + u32 pinCount = BCacheSkipCheckPin(); +#endif + + eptreeHdr = GET_EPTREEHDR_FROM_AREAINFO(area); + WFSKRN_FTREE_ASSERT(eptreeHdr->ptreeHdr.nRootHeight < PTREE_MAX_HEIGHT); + + FBAItrOpen(area, &iter); + FBAItrOpen(area, &iterSeq); + + for (i = 0; i < MAX_SUB_TREE; ++i) + { + + result = FreeBlkLast(area, &iterSeq, FTreeBlkLog2Ofs[i]); + while (result == WFSKRN_RESULT_OK) + { + nBlkAdr = FBA_RESULT_KEY(&iterSeq); + + total += (FBA_RESULT_DATA(&iterSeq) + 1) * (1<totalBlks - numMetaBlks); + ret = (WFSBool) TRUE; + +FTREEBLK_VERIFY_RESULT: + FBAItrClose(area, &iterSeq); + +#if _DEBUG + WFSKRN_FTREE_ASSERT(BCacheStopSkipCheckPin(pinCount) == WFSKRN_RESULT_OK); +#endif + // the P-tree block is pinned. + return ret; +} + +u32 FreeBlkGetFreeBlkLen(AreaInfo* area, u32 nBlkLog2SizeOfs) +{ + WFSKrnResult result; + WFSBlkAdr nBlkAdr; + FBATreeItr iter; + u32 total = 0; + EPTreeHdr* eptreeHdr; + +#ifdef _DEBUG + u32 pinCount = BCacheSkipCheckPin(); +#endif // _DEBUG + + // the P-tree block is pinned. + + eptreeHdr = GET_EPTREEHDR_FROM_AREAINFO(area); + WFSKRN_FTREE_ASSERT(eptreeHdr->ptreeHdr.nRootHeight < PTREE_MAX_HEIGHT); + + FBAItrOpen(area, &iter); + + result = FreeBlkLast(area, &iter, nBlkLog2SizeOfs); + while (result == WFSKRN_RESULT_OK) + { + nBlkAdr = FBA_RESULT_KEY(&iter); + total += (FBA_RESULT_DATA(&iter) + 1) * (1< (bufferSize-1)*8){ + SetBitArrayInternal(fh, pBuffer, bufferSize, diskAddr, (bufferSize-1)*8); + length -= (bufferSize-1)*8; + diskAddr += (bufferSize-1)*8; + } + SetBitArrayInternal(fh, pBuffer, bufferSize, diskAddr, length); +} + + +static WFSKrnResult FreeBlkGetMetablock(AreaInfo* area, WFSSrvFileHandle fh, u32 size) +{ + WFSKrnResult result; + WFSBlkAdr nBlkAdr; + WFSBlkAdr ftreeBlk; + FBATreeItr iter; + EPTreeItr* epti; + u8 level; + u8 ptreeHeight; + + WFSBlkAdr node[EPTREE_MAX_HEIGHT]; + + // the P-tree block is pinned. + FBAItrOpen(area, &iter); + ptreeHeight = iter.eptreeHdr[0]->height; + + memset(node, 0, sizeof(node)); + node[0] = FBA_ROOT_BLK; + SetBit(fh, FBA_ROOT_BLK); + + result = EPTreeFirst(area, (MEPTreeItr*) &iter); + while (result == WFSKRN_RESULT_OK) + { + for (level = 1; level < ptreeHeight; ++level) + { + if (node[level] != iter.eptreeHdr[level]->addr) + { + node[level] = iter.eptreeHdr[level]->addr; + SetBit(fh, node[level]); + } + } + + epti = EPTreeGetLastIter((MEPTreeItr*) &iter); + nBlkAdr = PTREE_GET_KEY(epti); + ftreeBlk = PTREE_GET_DATA(epti); + SetBit(fh, ftreeBlk); + + result = EPTreeNext(area, (MEPTreeItr*) &iter); + } + + FBAItrClose(area, &iter); + + // the P-tree block is pinned. + return WFSKRN_RESULT_OK; +} + +static WFSKrnResult FreeBlkGetFreeblock(AreaInfo* area, WFSSrvFileHandle fh, u8* pBuffer, u32 bufferSize, u32 size) +{ + WFSKrnResult result; + WFSBlkAdr start; + u32 len; + int i; + FBATreeItr iter; + + // the P-tree block is pinned. + FBAItrOpen(area, &iter); + + for (i = 0; i < MAX_SUB_TREE; ++i) + { + result = FreeBlkFirst(area, &iter, FTreeBlkLog2Ofs[i]); + while (result == WFSKRN_RESULT_OK) + { + start = FBA_RESULT_KEY(&iter); + len = (FBA_RESULT_DATA(&iter) + 1) * (1<ah.nNumBlks); + WFSKRN_FTREE_ASSERT(start + len <= area->ah.nNumBlks); + SetBitArray(fh, pBuffer, bufferSize, start, len); + result = FreeBlkNext(area, &iter); + } + } + FBAItrClose(area, &iter); + + // the P-tree block is pinned. + return WFSKRN_RESULT_OK; +} + +WFSKrnResult FreeBlkCheckDisk(AreaInfo* area, WFSSrvFileHandle fh, u8* pBuffer, u32 bufferSize, u32 size) +{ + // the P-tree block is pinned. + + WFSKrnResult result; + +#ifdef _DEBUG + EPTreeHdr* eptreeHdr = GET_EPTREEHDR_FROM_AREAINFO(area); + u32 pinCount = BCacheSkipCheckPin(); +#endif // DEBUG + + WFSKRN_FTREE_ASSERT(eptreeHdr->ptreeHdr.nRootHeight < PTREE_MAX_HEIGHT); + result = FreeBlkGetMetablock(area, fh, size); + if (result != WFSKRN_RESULT_OK) + { + FreeBlkDumpFreeblock(area); + goto FTREEBLK_CHECKDISK_RESULT; + } + result = FreeBlkGetFreeblock(area, fh, pBuffer, bufferSize, size); + if (result != WFSKRN_RESULT_OK) + { + FreeBlkDumpFreeblock(area); + goto FTREEBLK_CHECKDISK_RESULT; + } + +FTREEBLK_CHECKDISK_RESULT: + +#ifdef _DEBUG + WFSKRN_FTREE_ASSERT(BCacheStopSkipCheckPin(pinCount) == WFSKRN_RESULT_OK); +#endif // DEBUG + + // the P-tree block is pinned. + return result; +} + +WFSKrnResult FreeBlkDumpFreeblock(AreaInfo* area) +{ + WFSKrnResult result; + WFSBlkAdr start; + u32 len; + int i; + FBATreeItr iter; + + // the P-tree block is pinned. + FBAItrOpen(area, &iter); + + for (i = 0; i < MAX_SUB_TREE; ++i) + { + result = FreeBlkFirst(area, &iter, FTreeBlkLog2Ofs[i]); + while (result == WFSKRN_RESULT_OK) + { + start = FBA_RESULT_KEY(&iter); + len = FBA_RESULT_DATA(&iter) + 1; +#ifdef FBA_DEBUG_VERBOSE + if (FBADebugVerbose) + { + osTPrintf("start %u (len %u)\n", start, len); + } +#endif // FBA_DEBUG_VERBOSE + result = FreeBlkNext(area, &iter); + } + } + + FBAItrClose(area, &iter); + + // the P-tree block is pinned. + return WFSKRN_RESULT_OK; +} + +#endif // BTREE_BASED_ALLOCATOR diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Handles.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Handles.cpp new file mode 100644 index 0000000..26fd9f7 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Handles.cpp @@ -0,0 +1,119 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Handles.cpp - Module for file handles and search directory handles + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Handles.cpp,v $ + Revision 1.2 2008/10/07 06:00:57 ueno + Modified WFSKrnFileInfoAlloc() to set WFSKRN_HANDLE_ALLOCATED in order to indicate the handle is allocated. + + Revision 1.1 2008/04/25 17:29:06 kondo_masahiro + Initial check-in + + Revision 1.1 2008/04/23 00:27:17 paul + Copied and modified from wfscli_Handles.cpp + +*---------------------------------------------------------------------------*/ + +#include "wfskrn_Api.h" + +static bool bMutexInitialized = false; // [check] + +void WFSKrnInitHandles() { + if (!bMutexInitialized) + { + bMutexInitialized = true; + WFSKrnInitMutex(&wkg.hnd.mxAccessTheFileInfo); + WFSKrnInitMutex(&wkg.hnd.mxAccessTheSearchDirInfo); + } + wkg.hnd.nFileHandleCounter = 0; + wkg.hnd.nSearchDirHandleCounter = 0; + wkg.hnd.nFirstFreeFileHandle = 0; + wkg.hnd.nFirstFreeSearchDirHandle = 0; + wkg.hnd.nNumUsedFileHandles = 0; + wkg.hnd.nNumUsedSearchDirHandles = 0; + //wkg.hnd.nFirstUsedFileHandle = WFSKRN_MAX_FILE_HANDLES; // A value of WFSKRN_MAX_FILE_HANDLES is the list terminator + //wkg.hnd.nFirstUsedSearchDirHandle = WFSKRN_MAX_SEARCH_DIR_HANDLES; // A value of WFSKRN_MAX_SEARCH_DIR_HANDLES is the list terminator + u32 nI; + for(nI=0; nInHandle == sfh)?WFSKRN_RESULT_OK:WFSKRN_RESULT_INVALID; +} + +WFSKrnResult WFSKrnGetSearchDirInfo(WFSKrnSearchDirInfo **ppSdi, WFSSrvSearchDirectoryHandle ssdh) { + *ppSdi = &wkg.hnd.aSearchDirInfo[ssdh&(WFSKRN_MAX_SEARCH_DIR_HANDLES-1)]; + return ((*ppSdi)->nHandle == ssdh)?WFSKRN_RESULT_OK:WFSKRN_RESULT_INVALID; +} + +WFSKrnResult WFSKrnFileInfoAlloc(WFSKrnFileInfo **ppFi) { + WFSKrnLockMutex(&wkg.hnd.mxAccessTheFileInfo); + if (wkg.hnd.nFirstFreeFileHandle == WFSKRN_MAX_FILE_HANDLES) { + WFSKrnUnlockMutex(&wkg.hnd.mxAccessTheFileInfo); + return WFSKRN_RESULT_MAX_HANDLES; + } + wkg.hnd.nNumUsedFileHandles++; + u32 nIdx = wkg.hnd.nFirstFreeFileHandle; + wkg.hnd.nFirstFreeFileHandle = wkg.hnd.aFileInfo[nIdx].nNext; + wkg.hnd.aFileInfo[nIdx].nNext = WFSKRN_HANDLE_ALLOCATED; + *ppFi = &wkg.hnd.aFileInfo[nIdx]; + wkg.hnd.aFileInfo[nIdx].nHandle = wkg.hnd.nFileHandleCounter | nIdx; + wkg.hnd.nFileHandleCounter += WFSKRN_FILE_HANDLE_INC; + wkg.hnd.nFileHandleCounter &= WFSKRN_HANDLE_COUNTER_MASK; + WFSKrnUnlockMutex(&wkg.hnd.mxAccessTheFileInfo); + return WFSKRN_RESULT_OK; +} + +WFSKrnResult WFSKrnSearchDirInfoAlloc(WFSKrnSearchDirInfo **ppSdi) { + + WFSKrnLockMutex(&wkg.hnd.mxAccessTheSearchDirInfo); + if (wkg.hnd.nFirstFreeSearchDirHandle == WFSKRN_MAX_SEARCH_DIR_HANDLES) { + WFSKrnUnlockMutex(&wkg.hnd.mxAccessTheSearchDirInfo); + return WFSKRN_RESULT_MAX_HANDLES; + } + wkg.hnd.nNumUsedSearchDirHandles++; + u32 nIdx = wkg.hnd.nFirstFreeSearchDirHandle; + wkg.hnd.nFirstFreeSearchDirHandle = wkg.hnd.aSearchDirInfo[nIdx].nNext; + wkg.hnd.aSearchDirInfo[nIdx].nNext = WFSKRN_HANDLE_ALLOCATED; + *ppSdi = &wkg.hnd.aSearchDirInfo[nIdx]; + wkg.hnd.aSearchDirInfo[nIdx].nHandle = wkg.hnd.nSearchDirHandleCounter | nIdx; + wkg.hnd.nSearchDirHandleCounter += WFSKRN_SEARCH_DIR_HANDLE_INC; + wkg.hnd.nSearchDirHandleCounter &= WFSKRN_HANDLE_COUNTER_MASK; + WFSKrnUnlockMutex(&wkg.hnd.mxAccessTheSearchDirInfo); + return WFSKRN_RESULT_OK; +} + +void WFSKrnFileInfoFree(WFSKrnFileInfo *pFi) { + WFSKrnLockMutex(&wkg.hnd.mxAccessTheFileInfo); + u32 nIdx = (u32)(pFi - wkg.hnd.aFileInfo); + pFi->nHandle ^= 0x5555; // ensures the deleted handle is invalid + pFi->nNext = wkg.hnd.nFirstFreeFileHandle; + wkg.hnd.nNumUsedFileHandles--; + wkg.hnd.nFirstFreeFileHandle = nIdx; + WFSKrnUnlockMutex(&wkg.hnd.mxAccessTheFileInfo); +} + +void WFSKrnSearchDirInfoFree(WFSKrnSearchDirInfo *pSdi) { + WFSKrnLockMutex(&wkg.hnd.mxAccessTheSearchDirInfo); + u32 nIdx = (u32)(pSdi - wkg.hnd.aSearchDirInfo); + pSdi->nHandle ^= 0x5555; // ensures the deleted handle is invalid + pSdi->nNext = wkg.hnd.nFirstFreeSearchDirHandle; + wkg.hnd.nNumUsedSearchDirHandles--; + wkg.hnd.nFirstFreeSearchDirHandle = nIdx; + WFSKrnUnlockMutex(&wkg.hnd.mxAccessTheSearchDirInfo); +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Heap.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Heap.cpp new file mode 100644 index 0000000..768ed5e --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Heap.cpp @@ -0,0 +1,141 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Heap.cpp + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Heap.cpp,v $ + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.3 2008/04/19 05:50:40 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.2 2007/12/27 11:07:04 paul + fixed some copy-paste errors: changed WFS to WFSKrn + + Revision 1.1 2007/12/27 11:04:05 paul + similar to wfs_Heap.cpp, but will eventually support IOP, so will eventually be different + + +*---------------------------------------------------------------------------*/ + +#include "wfskrn_Heap.h" +#include "firm.h" + +#undef dbg +#if _DEBUG_WFSKRN_ALLOC +#define dbg(s) s +#else +#define dbg(s) +#endif + +#if _WIN32 + +dbg(u32 nSizeAvaliable=0;) + +void WFSKrnCreateHeap(WFSKrnHeap *pHeap, void *pBase, size_t nSize) { + *pHeap = HeapCreate(0, nSize, nSize); + dbg(nSizeAvaliable = nSize); +} + +void *WFSKrnHeapAlloc(WFSKrnHeap *pHeap, size_t nSize) { + void *pAddr = HeapAlloc(*pHeap, 0, nSize); + dbg(nSizeAvaliable -= nSize; + MyOSReport("A:Heap:%d\n", nSizeAvaliable)); + return pAddr; +} + +void WFSKrnHeapFree(WFSKrnHeap *pHeap, void *pAddr) { + dbg(nSizeAvaliable += HeapSize(pHeap, NULL, pAddr); + MyOSReport("F:Heap:%d\n", nSizeAvaliable)); + HeapFree(*pHeap, 0, pAddr); +} + +void WFSKrnHeapDestroy(WFSKrnHeap *pHeap) { + dbg(MyOSReport("WFSKrnHeapDestroy()\n")); + HeapDestroy(*pHeap); +} + +//-- twl modified +#elif _TWL + +void WFSKrnCreateHeap(WFSKrnHeap *pHeap, void *pBase, size_t nSize) { + osTPrintf( "%s needs modify.\n", __FUNCTION__); + //main.cで行っている +} + +void *WFSKrnHeapAlloc(WFSKrnHeap *pHeap, size_t nSize) { + void *pAddr = osAlloc( nSize); + if( pAddr == NULL) { + osTPrintf( "%s error!\n", __FUNCTION__); + } +// void *pAddr = OS_AllocFromHeap( OS_ARENA_MAIN_SUBPRIV, *pHeap, nSize); + return pAddr; +} + +void WFSKrnHeapFree(WFSKrnHeap *pHeap, void *pAddr) { + osFree( pAddr); +// OS_FreeToHeap( OS_ARENA_MAIN_SUBPRIV, *pHeap, pAddr); +} + +void WFSKrnHeapDestroy(WFSKrnHeap *pHeap) { + osTPrintf( "%s needs modify.\n", __FUNCTION__); +// OS_DestroyHeap( OS_ARENA_MAIN_SUBPRIV, *pHeap); +} + + +//-- twl modified + +#elif _RVL + +void WFSKrnCreateHeap(WFSKrnHeap *pHeap, void *pBase, size_t nSize) { + pHeap->handle = MEMCreateExpHeap(pBase, nSize); + MEMInitAllocatorForExpHeap(&pHeap->allocator, pHeap->handle, WFS_HEAP_DEFAULT_ALIGNMENT); +} + +void *WFSKrnHeapAlloc(WFSKrnHeap *pHeap, size_t nSize) { +// osTPrintf("==> %s:%d pHeap: 0x%08x size: %d\n", __FILE__, __LINE__, pHeap->pAllocator, nSize); + void *pAddr = MEMAllocFromAllocator(&pHeap->allocator, nSize); +// osTPrintf("==> %s:%d pAddr: 0x%08x\n", __FILE__, __LINE__, pAddr); + return pAddr; +} + +void WFSKrnHeapFree(WFSKrnHeap *pHeap, void *pAddr) { + MEMFreeToAllocator(&pHeap->allocator, pAddr); +} + +void WFSKrnHeapDestroy(WFSKrnHeap *pHeap) { + MEMDestroyExpHeap(pHeap->handle); +} + +#elif _IOP + +void WFSKrnCreateHeap(WFSKrnHeap *pHeap, void *pBase, size_t nSize) { + *pHeap = IOS_CreateHeap(pBase, nSize); +} + +void *WFSKrnHeapAlloc(WFSKrnHeap *pHeap, size_t nSize) { +// osTPrintf("==> %s:%d pHeap: 0x%08x size: %d\n", __FILE__, __LINE__, pHeap, nSize); + void *pAddr = IOS_AllocAligned(*pHeap, nSize, 32); +// osTPrintf("==> %s:%d pAddr: 0x%08x\n", __FILE__, __LINE__, pAddr); + return pAddr; +} + +void WFSKrnHeapFree(WFSKrnHeap *pHeap, void *pAddr) { + IOS_Free(*pHeap, pAddr); +} + +void WFSKrnHeapDestroy(WFSKrnHeap *pHeap) { + IOS_DestroyHeap(*pHeap); +} + + +#endif diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Mutex.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Mutex.cpp new file mode 100644 index 0000000..9269cf5 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Mutex.cpp @@ -0,0 +1,354 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Mutex.cpp + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Mutex.cpp,v $ + Revision 1.2 2008/04/25 17:28:54 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.2 2008/04/19 05:50:34 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.1 2007/12/27 11:11:58 paul + similar to wfs_Mutex.cpp, but will eventually need to support IOP + + +*---------------------------------------------------------------------------*/ + +#include "wfskrn_Mutex.h" + +#undef dbg +#if _DEBUG_WFSKRN_MUTEX +#define dbg(s) s +#else +#define dbg(s) +#endif + +#if _WIN32 + +dbg(u32 aSignalCounter[0x2000]); + +void WFSKrnInitMutex(WFSKrnMutex *pMx) { + pMx->hHandle = CreateMutex(NULL, false, NULL); + ReleaseMutex(pMx->hHandle); + dbg(aSignalCounter[(u32)pMx->hHandle&0x1fff]=1; + MyOSReport("InitMutex(%x:%d)\n", pMx->hHandle, aSignalCounter[(u32)pMx->hHandle&0x1fff])); +} + +void WFSKrnLockMutex(WFSKrnMutex *pMx) { + dbg(MyOSReport("Wait(%x:%d)\n", pMx->hHandle, aSignalCounter[(u32)pMx->hHandle&0x1fff])); + WaitForSingleObject(pMx->hHandle, INFINITE); + dbg(aSignalCounter[(u32)pMx->hHandle&0x1fff]--); +} + +bool WFSKrnTryLockMutex(WFSKrnMutex *pMx) { + return (WaitForSingleObject(pMx->hHandle, 0) != WAIT_TIMEOUT); +} + +void WFSKrnUnlockMutex(WFSKrnMutex *pMx) { + dbg(aSignalCounter[(u32)pMx->hHandle&0x1fff]++; + MyOSReport("Release(%x:%d)\n", pMx->hHandle, aSignalCounter[(u32)pMx->hHandle&0x1fff])); + ReleaseMutex(pMx->hHandle); +} + +void WFSKrnInitCond(WFSKrnCond *pCond) { + pCond->hAutoResetEvent = CreateEvent(NULL, false, false, NULL); + dbg(aSignalCounter[(u32)pCond->hAutoResetEvent&0x1fff]=0; + MyOSReport("InitCond(%x:%d)\n", pCond->hAutoResetEvent, aSignalCounter[(u32)pCond->hAutoResetEvent&0x1fff])); + //ResetEvent(pCond->hAutoResetEvent); + //pCond->hManualResetEvent = CreateEvent(NULL, true, false, NULL); +} + +void WFSKrnSignalCond(WFSKrnCond *pCond) { + //PulseEvent(pCond->hAutoResetEvent); + dbg(aSignalCounter[(u32)pCond->hAutoResetEvent&0x1fff]++; + MyOSReport("Signal(%x:%d)\n", pCond->hAutoResetEvent, aSignalCounter[(u32)pCond->hAutoResetEvent&0x1fff])); + SetEvent(pCond->hAutoResetEvent); +} + +void WFSKrnWaitCond(WFSKrnCond *pCond, WFSKrnMutex* pMx) { +#if 1 + dbg(aSignalCounter[(u32)pMx->hHandle&0x1fff]++; + MyOSReport("Signal(%x:%d) And Wait(%x:%d)\n", pMx->hHandle, aSignalCounter[(u32)pMx->hHandle&0x1fff], pCond->hAutoResetEvent, aSignalCounter[(u32)pCond->hAutoResetEvent&0x1fff])); + //DWORD nRet = SignalObjectAndWait(pMx->hHandle, pCond->hAutoResetEvent, INFINITE, false); + dbg(aSignalCounter[(u32)pCond->hAutoResetEvent&0x1fff]--); +#else + ReleaseMutex(pMx->hHandle); + WaitForSingleObject(pCond->hAutoResetEvent, INFINITE); +#endif + dbg(MyOSReport("Wait(%x:%d)\n", pMx->hHandle, aSignalCounter[(u32)pMx->hHandle&0x1fff])); + WaitForSingleObject(pMx->hHandle, INFINITE); + dbg(aSignalCounter[(u32)pMx->hHandle&0x1fff]--); +} + +void WFSKrnResetCond(WFSKrnCond *pCond) { + ResetEvent(pCond->hAutoResetEvent); +} + +bool WFSKrnCreateThread(WFSKrnThread *pThread, + WFSKrnThreadFunc threadFunc, + void* param, + void* stackBase, + u32 stackSize, + OSPriority priority) +{ + pThread->hThread = CreateThread(NULL, stackSize, (LPTHREAD_START_ROUTINE)threadFunc, param, CREATE_SUSPENDED, 0); + SetThreadPriority(pThread->hThread, 16-priority); + return true; +} + +s32 WFSKrnResumeThread(WFSKrnThread *pThread) { + return ResumeThread(pThread->hThread); +} + +void WFSKrnCancelThread(WFSKrnThread *pThread) { + // Note: On windows, this does not do any cleanup - should avoid using + TerminateThread(pThread->hThread, 0); +} + +void WFSKrnExitThread(void *pVal) { + ExitThread((DWORD)pVal); +} + +s32 WFSKrnSuspendThread(WFSKrnThread *pThread) +{ + return SuspendThread(pThread->hThread); +} + +bool WFSKrnIsThreadTerminated(WFSKrnThread *pThread) +{ + switch (WaitForSingleObject(pThread->hThread, 0)) + { + case WAIT_TIMEOUT: + return false; + case WAIT_OBJECT_0: // the thread has exited. + case WAIT_ABANDONED: // [check] + case WAIT_FAILED: // the thread does not exist. [check] should check error code? + default: + break; + } + + return true; +} + +bool WFSKrnJoinThread(WFSKrnThread *pThread, void** val) +{ +#pragma unused (val) // exit value is not supported. + switch (WaitForSingleObject(pThread->hThread, INFINITE)) + { + case WAIT_OBJECT_0: + return true; + case WAIT_TIMEOUT: + case WAIT_ABANDONED: + case WAIT_FAILED: + default: + break; + } + return false; +} + +#elif _RVL + + +bool WFSKrnCreateThread(WFSKrnThread *pThread, + WFSKrnThreadFunc threadFunc, + void* param, + void* stackBase, + u32 stackSize, + OSPriority priority) +{ + return OSCreateThread(pThread, threadFunc, param, (void*)((u32)stackBase+stackSize), stackSize, priority, OS_THREAD_ATTR_DETACH); +} + +//--- twl modified +#elif _TWL +typedef void (*MyThreadFunc)(void*); +bool WFSKrnCreateThread(WFSKrnThread *pThread, + WFSKrnThreadFunc threadFunc, + void* param, + void* stackBase, + u32 stackSize, + OSPriority priority) +{ + osCreateThread( pThread, (MyThreadFunc)threadFunc, param, (void*)((u32)stackBase+stackSize), stackSize, priority); + return true; +} + +s32 WFSKrnResumeThread(WFSKrnThread *pThread) +{ + osWakeupThreadDirect( pThread); +#if 1 +// osTPrintf( "Need TWL modifies.\n"); + return 0; +#else + if(WFSKrnIsThreadTerminated(pThread)){ + return 0; + } + else if(--pThread->count == 0){ + IOS_StartThread(pThread->tid); + } + return pThread->count; +#endif +} + +void WFSKrnCancelThread(WFSKrnThread *pThread) +{ + osDestroyThread( pThread); +} + +void WFSKrnExitThread(void *pVal) +{ + osExitThread(); +} + +s32 WFSKrnSuspendThread(WFSKrnThread *pThread) +{ +#if 1 + osTPrintf( "Need TWL modifies.\n"); + return 0; +#else + if(WFSKrnIsThreadTerminated(pThread)){ + return 0; + } + else if(++pThread->count == 1){ + IOS_StopThread(pThread->tid); + } + return pThread->count; +#endif +} + +bool WFSKrnIsThreadTerminated(WFSKrnThread *pThread) +{ + return( osIsThreadTerminated( pThread)); +} + +bool WFSKrnJoinThread(WFSKrnThread *pThread, void** val) +{ +#pragma unused (val) // exit value is not supported. + osJoinThread( pThread); + return true; +} + + +void WFSKrnInitCond(WFSCond *pCond) { + osInitEvent( pCond); +} + +void WFSKrnSignalCond(WFSCond *pCond) { + osSignalEvent( pCond, 1); +} + +void WFSKrnWaitCond(WFSCond *pCond, WFSMutex* pMx) { + osUnlockMutex( pMx); + osWaitEventEx( pCond, 1, OS_EVENT_MODE_OR, 1); //イベント待ち後にクリアを伴う +} + +void WFSKrnResetCond(WFSCond *pCond) { + osClearAllEvent( pCond); + return; +} +//-- twl modified + +#elif _IOP + +void WFSKrnInitMutex(WFSKrnMutex *mutex) +{ + mutex->mqid = IOS_CreateMessageQueue(mutex->mq, WFSKRN_MUTEX_Q_SIZE); + IOS_SendMessage(mutex->mqid, 0xabcd1234, IOS_MESSAGE_NOBLOCK); +} + +void WFSKrnLockMutex(WFSKrnMutex *mutex) +{ + IOSMessage msg; + IOS_ReceiveMessage(mutex->mqid, &msg, IOS_MESSAGE_BLOCK); +} + +bool WFSKrnTryLockMutex(WFSKrnMutex *mutex) +{ + IOSMessage msg; + if(IOS_ReceiveMessage(mutex->mqid, &msg, IOS_MESSAGE_NOBLOCK) == IOS_ERROR_OK ) + return true; + else + return false; +} + +void WFSKrnUnlockMutex(WFSKrnMutex *mutex) +{ + IOS_SendMessage(mutex->mqid, 0xabcd1234, IOS_MESSAGE_NOBLOCK); +} + +bool WFSKrnCreateThread(WFSKrnThread *pThread, + WFSKrnThreadFunc threadFunc, + void* param, + void* stackBase, + u32 stackSize, + OSPriority priority) +{ + IOSError ie = IOS_CreateThread((IOSEntryProc)threadFunc, param, stackBase, stackSize, (u32)priority, IOS_THREAD_CREATE_JOINABLE); + if(ie < 0) return false; + pThread->tid = ie; + pThread->count = 1; + return true; +} + +s32 WFSKrnResumeThread(WFSKrnThread *pThread) +{ + if(WFSKrnIsThreadTerminated(pThread)){ + return 0; + } + else if(--pThread->count == 0){ + IOS_StartThread(pThread->tid); + } + return pThread->count; +} + +void WFSKrnCancelThread(WFSKrnThread *pThread) +{ + IOS_DestroyThread(pThread->tid, 0); +} + +void WFSKrnExitThread(void *pVal) +{ + IOS_DestroyThread(IOS_GetThreadId(), pVal); +} + +s32 WFSKrnSuspendThread(WFSKrnThread *pThread) +{ + if(WFSKrnIsThreadTerminated(pThread)){ + return 0; + } + else if(++pThread->count == 1){ + IOS_StopThread(pThread->tid); + } + return pThread->count; +} + +bool WFSKrnIsThreadTerminated(WFSKrnThread *pThread) +{ + if(IOS_GetThreadPriority(pThread->tid) >= 0) + return true; + else + return false; +} + +bool WFSKrnJoinThread(WFSKrnThread *pThread, void** val) +{ + if(IOS_JoinThread(pThread->tid, val) == IOS_ERROR_OK) + return true; + else + return false; +} + +#endif diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_PTree.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_PTree.cpp new file mode 100644 index 0000000..5fa2433 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_PTree.cpp @@ -0,0 +1,1096 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_PTree.cpp + + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_PTree.cpp,v $ + Revision 1.5 2008/10/14 10:32:51 kondo_masahiro + Added #define _DEBUG_BREAK_POINT + + Revision 1.4 2008/08/22 01:20:30 ueno + Modified line feed. + + Revision 1.3 2008/08/22 01:07:54 ueno + Fixed PTreeInsert(). + + Revision 1.2 2008/07/17 23:00:28 paul + PTree is now used by updateMap. + Changed name of adapter functions to the Sba allocators. + Fixed PTreeInsert() to update pPti->aEntryIdx[0]. + Added PTreeInsertOrUpdateRec(). + + Revision 1.1 2008/07/09 01:43:05 paul + u32->u32 mapping optimized B-Tree. (for use by new block allocator, and transaction block re-mapper) + +*---------------------------------------------------------------------------*/ + +#undef _KRN_FILE_ +#define _KRN_FILE_ "PTree" + +#include "wfskrn_Defs.h" +#include "wfskrn_Api.h" +#include "wfskrn_Area.h" +#include "wfskrn_Errors.h" +#include "wfskrn_PTree.h" +#include "randomlib.h" + +#if _DEBUG_PTREE + static u32 nCurKey; + static u32 nNodeCount; +#endif + + +u16 PTreeAllocNodeFromSba(void *pBase) { + return SbaAllocSubBlk((WFSSubBlkAllocHdr *)pBase, PTREE_LOG2_NODE_SIZE); +} + +WFSKrnResult PTreeAllocNodesFromSba(void *pBase, u16 aNodeOfs[], u32 nNumNodes) { + return SbaAllocSubBlks((WFSSubBlkAllocHdr *)pBase, PTREE_LOG2_NODE_SIZE, aNodeOfs, nNumNodes); +} + +void PTreeFreeNodeToSba(void *pBase, u16 nOfs) { + SbaFreeSubBlk((WFSSubBlkAllocHdr *)pBase, nOfs, PTREE_LOG2_NODE_SIZE); +} + +//inline +PTreeNode *PTreeGetNode(PTreeAllocator *pAllocator, u32 nOfs) { + return (PTreeNode *)((u8*)pAllocator->pBase + nOfs); +} + +//inline +PTreeLeaf *PTreeGetLeaf(PTreeAllocator *pAllocator, u32 nOfs) { + return (PTreeLeaf *)((u8*)pAllocator->pBase + nOfs); +} + +/*inline*/ +u32 PTreeGetOfs(void *pNode, PTreeAllocator *pAllocator) { + return (u8*)pNode - (u8*)pAllocator->pBase; +} + + +void PTreeInit(PTreeHdr *pPTreeHdr, PTreeAllocator *pAllocator) { + pPTreeHdr->nRootHeight = 0; + pPTreeHdr->nNumRecs = 0; +} + +void PTreeInitRootNode(PTreeHdr *pPTreeHdr, PTreeAllocator *pAllocator) { + pPTreeHdr->nRootOfs = pAllocator->fpAllocNode(pAllocator->pBase); + PTreeNode *pNode = PTreeGetNode(pAllocator, (u32)pPTreeHdr->nRootOfs); + memset(pNode, 0, sizeof(PTreeNode)); +} + + +inline u32 PTreeFindLeafOfs(PTreeHdr *pPTreeHdr, PTreeItr *pPti, u32 nKey, PTreeAllocator *pAllocator) { + u32 nLevel = pPTreeHdr->nRootHeight; + u32 *pEntryIdx = &pPti->aEntryIdx[nLevel]; + u32 nOfs = (u32)pPTreeHdr->nRootOfs; + // K | Input | Out | K<=k[0] | K<=k[1] | K<=k[2] | K<=k[3] | K<=k[4] | 0==k[0] | 0==k[1] | 0==k[2] | 0==k[3] | 0==k[4] | + // ---+-------------+------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ + // K | 0 0 0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | + // K | a 0 0 0 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | + // K | z 0 0 0 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | + // K | a b 0 0 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | + // K | a z 0 0 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | + // K | y z 0 0 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | + // K | a b c 0 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | + // K | a b z 0 0 | 2 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | + // K | a y z 0 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | + // K | x y z 0 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | + // K | a b c d 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | + // K | a b c z 0 | 3 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | + // K | a b y z 0 | 2 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | + // K | a x y z 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | + // K | w x y z 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | + // K | a b c d e | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | + // K | a b c d z | 4 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | a b c y z | 3 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | a b x y z | 2 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | a w x y z | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | v w x y z | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + // --+-------------+------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ + // 5 8 9 8 5 0 2 5 9 14 + while (nLevel) { + PTreeNode *pNode = pPti->apNode[nLevel-1] = PTreeGetNode(pAllocator, nOfs); + // Hard-coded binary split search which avoids need to store length of sorted array, by assuming a 0 terminated array + if (pNode->aKey[3] == 0) { + // 10 possibilities + if (pNode->aKey[2] == 0) { + // 6 possibilities + if (pNode->aKey[1] != 0) { + // 3 possibilities + goto FindInRange0to2; + } + // 3 possibilities + if (pNode->aKey[0] > nKey) { + *pEntryIdx = 0; + } else { + if (pNode->aKey[0] == 0) { + *pEntryIdx = 0; + } else { + *pEntryIdx = 1; + } + } + } else { + // 4 possibilities + if (pNode->aKey[1] > nKey) { + goto FindInRange0to1; + } else { + if (pNode->aKey[2] > nKey) { + *pEntryIdx = 2; + } else { + *pEntryIdx = 3; + } + } + } + } else { + // 11 possibilities + if (pNode->aKey[4] == 0) { + // 5 possibilities + if (pNode->aKey[2] > nKey) { + // 3 possibilities + goto FindInRange0to2; + } + // 2 possibilities + if (pNode->aKey[3] > nKey) { + *pEntryIdx = 3; + } else { + *pEntryIdx = 4; + } + } else { + // 6 possibilities + if (pNode->aKey[2] > nKey) { + // 3 possibilities +FindInRange0to2: + if (pNode->aKey[1] > nKey) { + // 2 possibilities +FindInRange0to1: + if (pNode->aKey[0] > nKey) { + *pEntryIdx = 0; + } else { + *pEntryIdx = 1; + } + } else { + *pEntryIdx = 2; + } + } else { + // 3 possibilities + if (pNode->aKey[4] > nKey) { + // 2 possibilities + if (pNode->aKey[3] > nKey) { + *pEntryIdx = 3; + } else { + *pEntryIdx = 4; + } + } else { + *pEntryIdx = 5; + } + } + } + } + nOfs = (u32)pNode->aOfs[*pEntryIdx]; + --pEntryIdx; + --nLevel; + } + return nOfs; +} + + +WFSKrnResult PTreeFind(PTreeHdr *pPTreeHdr, PTreeItr *pPti, u32 nKey, PTreeAllocator *pAllocator) { + if (pPTreeHdr->nNumRecs == 0) { + return WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; + } + u32 nOfs = PTreeFindLeafOfs(pPTreeHdr, pPti, nKey, pAllocator); + PTreeLeaf *pLeaf = pPti->pLeaf = PTreeGetLeaf(pAllocator, nOfs); + // 32 cases to distinguish + // Insert(K) : Different cases for leaf update + // K | Input | Output | K<=k[0] | K>=k[0] | K<=k[1] | K>=k[1] | K<=k[2] | K>=k[2] | K<=k[3] | K>=k[3] | 0==k[0] | 0==k[1] | 0==k[2] | 0==k[3] | + // --+-----------+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ + // 0 | k 0 0 0 | 0 Found | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | + // K | k 0 0 0 | 0 Found | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | + // 0 | k t 0 0 | 0 Found | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | + // K | k t 0 0 | 0 Found | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + // 0 | k r t 0 | 0 Found | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | + // K | k r t 0 | 0 Found | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + // 0 | k p r t | 0 Found | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | + // K | k p r t | 0 Found | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // 0 | r t 0 0 | 0 Not Found | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | + // K | r t 0 0 | 0 Not Found | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + // 0 | p r t 0 | 0 Not Found | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | + // K | p r t 0 | 0 Not Found | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + // 0 | n p r t | 0 Not Found | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | n p r t | 0 Not Found | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // 0 | t 0 0 0 | 0 Not Found | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | + // K | t 0 0 0 | 0 Not Found | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | + // K | b k t 0 | 1 Found | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | b k 0 0 | 1 Found | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + // K | b k r t | 1 Found | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | b r t 0 | 1 Not Found | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | b 0 0 0 | 1 Not Found | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | + // K | b t 0 0 | 1 Not Found | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + // K | b p r t | 1 Not Found | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | b d k 0 | 2 Found | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | b d k t | 2 Found | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | b d 0 0 | 2 Not Found | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + // K | b d t 0 | 2 Not Found | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | b d r t | 2 Not Found | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | b d f k | 3 Found | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | + // K | b d f 0 | 3 Not Found | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | b d f t | 3 Not Found | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | b d f j | 4 Not Found | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | + // --+-----------+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ + // 16 24 20 17 20 18 16 23 4 5 12 21 + u32 *pEntryIdx = pPti->aEntryIdx; + if ((pLeaf->aKey[1] >= nKey) || (pLeaf->aKey[1] == 0)) { + if (pLeaf->aKey[0] >= nKey) { + *pEntryIdx = 0; + } else { + *pEntryIdx = 1; + } + } else { + if (pLeaf->aKey[2] >= nKey) { + *pEntryIdx = 2; + } else { + if (pLeaf->aKey[3] == 0) { + if (pLeaf->aKey[2] == 0) { + *pEntryIdx = 2; + } else { + *pEntryIdx = 3; + } + } else { + if (pLeaf->aKey[3] < nKey) { + *pEntryIdx = 4; + return WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; + } else { + *pEntryIdx = 3; + } + } + } + } + if (pLeaf->aKey[*pEntryIdx] == nKey) { + pPti->nData = pLeaf->aData[*pEntryIdx]; + return WFSKRN_RESULT_PTREE_ENTRY_FOUND; + } + return WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; +} + + +WFSKrnResult PTreeInsertIntoNode(PTreeHdr *pPTreeHdr, PTreeItr *pPti, u32 nKey, u32 *pChildOfs, PTreeAllocator *pAllocator) { + // *pChildOfs [IN/OUT] = On entry, contains the address of the left child. On output, contains the offset of the right child. + // K | Input | Output | K<=k[0] | K<=k[1] | K<=k[2] | K<=k[3] | K<=k[4] | 0==k[0] | 0==k[1] | 0==k[2] | 0==k[3] | 0==k[4] | + // ---+-------------+-------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ + // K | 0 0 0 0 0 | a K 0 0 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | + // K | a 0 0 0 0 | a K 0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | + // K | z 0 0 0 0 | K z 0 0 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | + // K | a b 0 0 0 | a b K 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | + // K | a z 0 0 0 | a K z 0 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | + // K | y z 0 0 0 | K y z 0 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | + // K | a b c 0 0 | a b c K 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | + // K | a b z 0 0 | a b K z 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | + // K | a y z 0 0 | a K y z 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | + // K | x y z 0 0 | K x y z 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | + // K | a b c d 0 | a b c d K | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | + // K | a b c z 0 | a b c K z | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | + // K | a b y z 0 | a b K y z | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | + // K | a x y z 0 | a K x y z | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | + // K | w x y z 0 | K w x y z | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | + // K | a b c d e | a b 0 0 0 e K 0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | + // K | a b c d z | a b 0 0 0 K z 0 0 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | a b c y z | a b 0 0 0 y z 0 0 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | a b x y z | a b K 0 0 y z 0 0 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | a w x y z | a K w 0 0 y z 0 0 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | v w x y z | K v w 0 0 y z 0 0 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + // --+-------------+-------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ + // 5 8 9 8 5 0 2 5 9 14 + PTreeNode *pNode, *pNewNode; + u32 nLeftChildOfs = *pChildOfs; + u32 nLevel = 1; + // Allocate the necessary number of new blocks first + u32 nNumNewNodes = 1; // One for new leaf, one for new parent + PTreeNode **ppNode = pPti->apNode; + PTreeNode **ppNodeEnd = ppNode + pPTreeHdr->nRootHeight; + while(1) { + if (ppNode == ppNodeEnd) { + if ((ppNode - pPti->apNode) > PTREE_MAX_HEIGHT-2) { + // We cannot split this node as it is the root node, and the tree is already at the maximum height + return WFSKRN_RESULT_PTREE_FULL; + } + ++nNumNewNodes; + break; + } + if ((*ppNode)->aKey[PTREE_NODE_FAN_OUT-2]==0) { + break; + } + ++ppNode; + ++nNumNewNodes; + } + u16 aNodeOfs[PTREE_MAX_HEIGHT]; + if (pAllocator->fpAllocNodes(pAllocator->pBase, aNodeOfs, nNumNewNodes) != WFSKRN_RESULT_OK) { + return WFSKRN_RESULT_PTREE_FULL; + } + u32 nRightChildOfs = *pChildOfs = aNodeOfs[0]; // Offset of new leaf node + u16 *pNewNodeOfs = aNodeOfs+1; + while(1) { + if (nLevel <= pPTreeHdr->nRootHeight) { + pNode = pPti->apNode[nLevel-1]; + } else { + // Add a new level + ++pPTreeHdr->nRootHeight; + pNode = pPti->apNode[nLevel-1] = PTreeGetNode(pAllocator, *pNewNodeOfs); + pPTreeHdr->nRootOfs = (u16)*pNewNodeOfs; + memset(&pNode->aKey[1], 0, sizeof(u32) * 4); + pNode->aKey[0] = nKey; + pNode->aOfs[0] = (u16)nLeftChildOfs; + pNode->aOfs[1] = (u16)nRightChildOfs; + return WFSKRN_RESULT_OK; + } + u32 *pEntryIdx = &pPti->aEntryIdx[nLevel]; + if (pNode->aKey[PTREE_NODE_FAN_OUT-2] == 0) { + // Key can be inserted without requiring a node split + switch(*pEntryIdx) { + case 0: pNode->aKey[4] = pNode->aKey[3]; + pNode->aKey[3] = pNode->aKey[2]; + pNode->aKey[2] = pNode->aKey[1]; + pNode->aKey[1] = pNode->aKey[0]; + pNode->aKey[0] = nKey; + pNode->aOfs[5] = pNode->aOfs[4]; + pNode->aOfs[4] = pNode->aOfs[3]; + pNode->aOfs[3] = pNode->aOfs[2]; + pNode->aOfs[2] = pNode->aOfs[1]; + pNode->aOfs[1] = nRightChildOfs; + break; + case 1: pNode->aKey[4] = pNode->aKey[3]; + pNode->aKey[3] = pNode->aKey[2]; + pNode->aKey[2] = pNode->aKey[1]; + pNode->aKey[1] = nKey; + pNode->aOfs[5] = pNode->aOfs[4]; + pNode->aOfs[4] = pNode->aOfs[3]; + pNode->aOfs[3] = pNode->aOfs[2]; + pNode->aOfs[2] = nRightChildOfs; + break; + case 2: pNode->aKey[4] = pNode->aKey[3]; + pNode->aKey[3] = pNode->aKey[2]; + pNode->aKey[2] = nKey; + pNode->aOfs[5] = pNode->aOfs[4]; + pNode->aOfs[4] = pNode->aOfs[3]; + pNode->aOfs[3] = nRightChildOfs; + break; + case 3: pNode->aKey[4] = pNode->aKey[3]; + pNode->aKey[3] = nKey; + pNode->aOfs[5] = pNode->aOfs[4]; + pNode->aOfs[4] = nRightChildOfs; + break; + case 4: pNode->aKey[4] = nKey; + pNode->aOfs[5] = nRightChildOfs; + break; + } + return WFSKRN_RESULT_OK; + } else { + // Key insertion requires a node split + // The node needs to be split before the new key can be inserted + pNewNode = pPti->apNode[nLevel-1] = PTreeGetNode(pAllocator, *pNewNodeOfs); + u32 nOldKey; + switch(*pEntryIdx) { + case 0: pNewNode->aKey[0] = pNode->aKey[3]; + pNewNode->aKey[1] = pNode->aKey[4]; + pNewNode->aKey[2] = pNewNode->aKey[3] = pNewNode->aKey[4] = 0; + pNewNode->aOfs[0] = pNode->aOfs[3]; + pNewNode->aOfs[1] = pNode->aOfs[4]; + pNewNode->aOfs[2] = pNode->aOfs[5]; + nOldKey = nKey; + nKey = pNode->aKey[2]; + pNode->aKey[2] = pNode->aKey[1]; + pNode->aKey[1] = pNode->aKey[0]; + pNode->aKey[0] = nOldKey; + pNode->aOfs[3] = pNode->aOfs[2]; + pNode->aOfs[2] = pNode->aOfs[1]; + pNode->aOfs[1] = nRightChildOfs; + break; + case 1: pNewNode->aKey[0] = pNode->aKey[3]; + pNewNode->aKey[1] = pNode->aKey[4]; + pNewNode->aKey[2] = pNewNode->aKey[3] = pNewNode->aKey[4] = 0; + pNewNode->aOfs[0] = pNode->aOfs[3]; + pNewNode->aOfs[1] = pNode->aOfs[4]; + pNewNode->aOfs[2] = pNode->aOfs[5]; + nOldKey = nKey; + nKey = pNode->aKey[2]; + pNode->aKey[2] = pNode->aKey[1]; + pNode->aKey[1] = nOldKey; + pNode->aOfs[3] = pNode->aOfs[2]; + pNode->aOfs[2] = nRightChildOfs; + break; + case 2: pNewNode->aKey[0] = pNode->aKey[3]; + pNewNode->aKey[1] = pNode->aKey[4]; + pNewNode->aKey[2] = pNewNode->aKey[3] = pNewNode->aKey[4] = 0; + pNewNode->aOfs[0] = pNode->aOfs[3]; + pNewNode->aOfs[1] = pNode->aOfs[4]; + pNewNode->aOfs[2] = pNode->aOfs[5]; + nOldKey = nKey; + nKey = pNode->aKey[2]; + pNode->aKey[2] = nOldKey; + pNode->aOfs[3] = nRightChildOfs; + break; + case 3: pNewNode->aKey[0] = pNode->aKey[3]; + pNewNode->aKey[1] = pNode->aKey[4]; + pNewNode->aKey[2] = pNewNode->aKey[3] = pNewNode->aKey[4] = 0; + pNewNode->aOfs[0] = nRightChildOfs; + pNewNode->aOfs[1] = pNode->aOfs[4]; + pNewNode->aOfs[2] = pNode->aOfs[5]; + break; + case 4: pNewNode->aKey[0] = nKey; + pNewNode->aKey[1] = pNode->aKey[4]; + pNewNode->aKey[2] = pNewNode->aKey[3] = pNewNode->aKey[4] = 0; + pNewNode->aOfs[0] = pNode->aOfs[4]; + pNewNode->aOfs[1] = nRightChildOfs; + pNewNode->aOfs[2] = pNode->aOfs[5]; + nKey = pNode->aKey[3]; + break; + case 5: pNewNode->aKey[0] = pNode->aKey[4]; + pNewNode->aKey[1] = nKey; + pNewNode->aKey[2] = pNewNode->aKey[3] = pNewNode->aKey[4] = 0; + pNewNode->aOfs[0] = pNode->aOfs[4]; + pNewNode->aOfs[1] = pNode->aOfs[5]; + pNewNode->aOfs[2] = nRightChildOfs; + nKey = pNode->aKey[3]; + break; + } + pNode->aKey[3] = pNode->aKey[4] = 0; + nRightChildOfs = *pNewNodeOfs++; + nLeftChildOfs = PTreeGetOfs(pNode, pAllocator); + ++nLevel; + } + } +// return WFSKRN_RESULT_OK; +} + + +WFSKrnResult PTreeInsert(PTreeHdr *pPTreeHdr, PTreeItr *pPti, u32 nKey, u32 nData, PTreeAllocator *pAllocator) { + u32 nOfs; + PTreeLeaf *pLeaf; + PTreeLeaf *pNewLeaf; + u32 *pEntryIdx = pPti->aEntryIdx; + + // check if the P-tree is empty before PTreeFindLeafOfs(). + if (pPTreeHdr->nNumRecs == 0) { + u16 nOfs = pAllocator->fpAllocNode(pAllocator->pBase); + if (nOfs == 0) { + return WFSKRN_RESULT_PTREE_FULL; + } + pPTreeHdr->nRootOfs = nOfs; + pPTreeHdr->nRootHeight = 0; + pLeaf = pPti->pLeaf = PTreeGetLeaf(pAllocator, (u32)pPTreeHdr->nRootOfs); + *pEntryIdx = 0; + memset(&pLeaf->aKey[1], 0, 3 * sizeof(u32)); // It is necessary to initialize to 0 + pLeaf->aKey[0] = nKey; + pLeaf->aData[0] = nData; + goto Done; + } + + nOfs = PTreeFindLeafOfs(pPTreeHdr, pPti, nKey, pAllocator); + pLeaf = pPti->pLeaf = PTreeGetLeaf(pAllocator, nOfs); + + // 32 cases to distinguish + // Insert(K) : Different cases for leaf update + // K | Input | Output | K<=k[0] | K>=k[0] | K<=k[1] | K>=k[1] | K<=k[2] | K>=k[2] | K<=k[3] | K>=k[3] | 0==k[0] | 0==k[1] | 0==k[2] | 0==k[3] | + // --+-----------+---------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ + // 0 | k 0 0 0 | Error | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | + // 0 | t 0 0 0 | K t 0 0 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | + // 0 | k t 0 0 | Error | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | + // 0 | r t 0 0 | K r t 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | + // 0 | k r t 0 | Error | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | + // 0 | p r t 0 | K p r t | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | + // 0 | k p r t | Error | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | + // 0 | n p r t | K n 0 0 p r t 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | b 0 0 0 | b K 0 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | + // K | k 0 0 0 | Error | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | + // K | t 0 0 0 | K t 0 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | + // K | b d 0 0 | b d K 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + // K | b k 0 0 | Error | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + // K | b t 0 0 | b K t 0 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + // K | k t 0 0 | Error | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + // K | r t 0 0 | K r t 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + // K | b d f 0 | b d f K | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | b d k 0 | Error | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | b d t 0 | b d K t | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | b k t 0 | Error | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | b r t 0 | b K r t | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | k r t 0 | Error | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | p r t 0 | K p r t | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | b d f j | b d f 0 j K 0 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | + // K | b d f k | Error | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | + // K | b d f t | b d f 0 K t 0 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | b d k t | Error | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | b d r t | b d K 0 r t 0 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | b k r t | Error | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | b p r t | b K 0 0 p r t 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | k p r t | Error | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | n p r t | K n 0 0 p r t 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // --+-----------+---------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ + // 16 24 20 17 20 18 16 23 4 5 12 21 + if (pLeaf->aKey[0] >= nKey) { + // 16 possibilities remain + *pEntryIdx = 0; + if (pLeaf->aKey[0] == nKey) { + // nKey matches aKey[0] - covers 8 cases + // 0 | k 0 0 0 | Error | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | + // 0 | k t 0 0 | Error | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | + // 0 | k r t 0 | Error | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | + // 0 | k p r t | Error | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | + // K | k 0 0 0 | Error | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | + // K | k t 0 0 | Error | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + // K | k r t 0 | Error | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | k p r t | Error | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + return WFSKRN_RESULT_PTREE_ENTRY_FOUND; + } else { + if (pLeaf->aKey[3] == 0) { + // insert nKey to position aKey[0] in leaf - covers 6 cases + // 0 | t 0 0 0 | K t 0 0 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | + // 0 | r t 0 0 | K r t 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | + // K | t 0 0 0 | K t 0 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | + // K | r t 0 0 | K r t 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + // 0 | p r t 0 | K p r t | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | + // K | p r t 0 | K p r t | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + pLeaf->aKey[3] = pLeaf->aKey[2]; + pLeaf->aKey[2] = pLeaf->aKey[1]; + pLeaf->aKey[1] = pLeaf->aKey[0]; + pLeaf->aData[3] = pLeaf->aData[2]; + pLeaf->aData[2] = pLeaf->aData[1]; + pLeaf->aData[1] = pLeaf->aData[0]; + } else { + // Split leaf 1:3 preparing to insert nKey at position aKey[0], and initizling unused aKey[] elements to 0 - covers 2 cases + // 0 | n p r t | K n 0 0 p r t 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + // K | n p r t | K n 0 0 p r t 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + WFSKrnReturnOnError(PTreeInsertIntoNode(pPTreeHdr, pPti, pLeaf->aKey[1], &nOfs, pAllocator)); + pNewLeaf = PTreeGetLeaf(pAllocator, nOfs); + pNewLeaf->aKey[0] = pLeaf->aKey[1]; + pNewLeaf->aKey[1] = pLeaf->aKey[2]; + pNewLeaf->aKey[2] = pLeaf->aKey[3]; + pNewLeaf->aData[0] = pLeaf->aData[1]; + pNewLeaf->aData[1] = pLeaf->aData[2]; + pNewLeaf->aData[2] = pLeaf->aData[3]; + pLeaf->aKey[1] = pLeaf->aKey[0]; + pLeaf->aData[1] = pLeaf->aData[0]; + pNewLeaf->aKey[3] = pLeaf->aKey[2] = pLeaf->aKey[3] = 0; + } + // inserting K to position aKey[0] - covers above 8 cases + pLeaf->aKey[0] = nKey; + pLeaf->aData[0] = nData; + } + } else { + // 16 possibilities remain + if (pLeaf->aKey[2] >= nKey) { + // 8 possibilities remain + if (pLeaf->aKey[1] < nKey) { + // 4 possibilities remain + *pEntryIdx = 2; + if (pLeaf->aKey[2] == nKey) { + // nKey matches aKey[2] - covers 2 cases + // K | b d k 0 | Error | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | b d k t | Error | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + return WFSKRN_RESULT_PTREE_ENTRY_FOUND; + } else { + if (pLeaf->aKey[3] == 0) { + // shift position 2 to position 3 - covers 1 case + // K | b d t 0 | b d K t | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + pLeaf->aKey[3] = pLeaf->aKey[2]; + pLeaf->aData[3] = pLeaf->aData[2]; + } else { + // split leaf into 2:2 and initialize unused elements to 0 - covers 1 case + // K | b d r t | b d K 0 r t 0 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + WFSKrnReturnOnError(PTreeInsertIntoNode(pPTreeHdr, pPti, pLeaf->aKey[2], &nOfs, pAllocator)); + pNewLeaf = PTreeGetLeaf(pAllocator, nOfs); + pNewLeaf->aKey[0] = pLeaf->aKey[2]; + pNewLeaf->aKey[1] = pLeaf->aKey[3]; + pNewLeaf->aData[0] = pLeaf->aData[2]; + pNewLeaf->aData[1] = pLeaf->aData[3]; + pNewLeaf->aKey[2] = pNewLeaf->aKey[3] = pLeaf->aKey[3] = 0; + } + // inserting K to position aKey[2] - covers above 2 cases + pLeaf->aKey[2] = nKey; + pLeaf->aData[2] = nData; + } + } else { + // 4 possibilities remain + *pEntryIdx = 1; + if (pLeaf->aKey[1] == nKey) { + // nKey matches aKey[1] - covers 2 cases + // K | b k t 0 | Error | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + // K | b k r t | Error | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + return WFSKRN_RESULT_PTREE_ENTRY_FOUND; + } else { + // 2 possibilities remain + if (pLeaf->aKey[3] == 0) { + // shift positions 1 and 2 to to the right - covers 1 case + // K | b r t 0 | b K r t | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | + pLeaf->aKey[3] = pLeaf->aKey[2]; + pLeaf->aKey[2] = pLeaf->aKey[1]; + pLeaf->aData[3] = pLeaf->aData[2]; + pLeaf->aData[2] = pLeaf->aData[1]; + } else { + // split leaf into 1:3 and initialize unused elements to 0 - covers 1 case + // K | b p r t | b K 0 0 p r t 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + WFSKrnReturnOnError(PTreeInsertIntoNode(pPTreeHdr, pPti, pLeaf->aKey[1], &nOfs, pAllocator)); + pNewLeaf = PTreeGetLeaf(pAllocator, nOfs); + pNewLeaf->aKey[0] = pLeaf->aKey[1]; + pNewLeaf->aKey[1] = pLeaf->aKey[2]; + pNewLeaf->aKey[2] = pLeaf->aKey[3]; + pNewLeaf->aData[0] = pLeaf->aData[1]; + pNewLeaf->aData[1] = pLeaf->aData[2]; + pNewLeaf->aData[2] = pLeaf->aData[3]; + pNewLeaf->aKey[3] = pLeaf->aKey[2] = pLeaf->aKey[3] = 0; + } + // inserting K to position aKey[1] - covers above 2 cases + pLeaf->aKey[1] = nKey; + pLeaf->aData[1] = nData; + } + } + } else { + // 8 possibilities remain + if (pLeaf->aKey[2] == 0) { + // 4 possibilities remain + if (pLeaf->aKey[1] >= nKey) { + // 2 possibilities remain + *pEntryIdx = 1; + if (pLeaf->aKey[1] == nKey) { + // nKey matches aKey[1] in leaf - covers 1 case + // K | b k 0 0 | Error | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + return WFSKRN_RESULT_PTREE_ENTRY_FOUND; + } else { + // insert nKey to position aKey[1] - covers 1 case + // K | b t 0 0 | b K t 0 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + pLeaf->aKey[2] = pLeaf->aKey[1]; + pLeaf->aData[2] = pLeaf->aData[1]; + pLeaf->aKey[1] = nKey; + pLeaf->aData[1] = nData; + } + } else { + // 2 possibilities remain + if (pLeaf->aKey[1] == 0) { + // append nKey to position aKey[1] - covers 1 case + // K | b 0 0 0 | b K 0 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | + *pEntryIdx = 1; + pLeaf->aKey[1] = nKey; + pLeaf->aData[1] = nData; + } else { + // append nKey to position aKey[2] - covers 1 case + // K | b d 0 0 | b d K 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | + *pEntryIdx = 2; + pLeaf->aKey[2] = nKey; + pLeaf->aData[2] = nData; + } + } + } else { + // 4 possibilities remain + if (pLeaf->aKey[3] >= nKey) { + // 2 possibilities remain + if (pLeaf->aKey[3] == nKey) { + // nKey matches aKey[3] in leaf - covers 1 case + // K | b d f k | Error | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | + *pEntryIdx = 3; + return WFSKRN_RESULT_PTREE_ENTRY_FOUND; + } else { + // split leaf 3:1 inserting K into position aKey[0] of the right hand side, and initializing unused keys to 0 - covers 1 case + // K | b d f t | b d f 0 K t 0 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | + WFSKrnReturnOnError(PTreeInsertIntoNode(pPTreeHdr, pPti, nKey, &nOfs, pAllocator)); + pNewLeaf = PTreeGetLeaf(pAllocator, nOfs); + pNewLeaf->aKey[1] = pLeaf->aKey[3]; + pNewLeaf->aData[1] = pLeaf->aData[3]; + pNewLeaf->aKey[2] = pNewLeaf->aKey[3] = pLeaf->aKey[3] = 0; + *pEntryIdx = 0; + pNewLeaf->aKey[0] = nKey; + pNewLeaf->aData[0] = nData; + } + } else { + // 2 possibilities remain + if (pLeaf->aKey[3] == 0) { + // append nKey to position aKey[3] - covers 1 case + // K | b d f 0 | b d f K | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | + *pEntryIdx = 3; + pLeaf->aKey[3] = nKey; + pLeaf->aData[3] = nData; + } else { + // split leaf into 3:1 inserting K to position aKey[1] of the right hand side, and initializing unused keys to 0 - covers 1 case + // K | b d f j | b d f 0 j K 0 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | + WFSKrnReturnOnError(PTreeInsertIntoNode(pPTreeHdr, pPti, pLeaf->aKey[3], &nOfs, pAllocator)); + pNewLeaf = PTreeGetLeaf(pAllocator, nOfs); + pNewLeaf->aKey[0] = pLeaf->aKey[3]; + pNewLeaf->aData[0] = pLeaf->aData[3]; + pNewLeaf->aKey[2] = pNewLeaf->aKey[3] = pLeaf->aKey[3] = 0; + *pEntryIdx = 1; + pNewLeaf->aKey[1] = nKey; + pNewLeaf->aData[1] = nData; + } + } + } + } + } +Done: + ++pPTreeHdr->nNumRecs; + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult PTreeDelete(PTreeHdr *pPTreeHdr, PTreeItr *pPti, PTreeAllocator *pAllocator) { +#if _DEBUG_BREAK_POINT + static int c=0;++c;if(c>=12805){ + int a;a=0; + } +#endif + --pPTreeHdr->nNumRecs; + PTreeLeaf *pLeaf = pPti->pLeaf; + u32 *pEntryIdx = pPti->aEntryIdx; + switch(*pEntryIdx) { + case 0: if (pLeaf->aKey[1]==0) { + break; + } + pLeaf->aKey[0] = pLeaf->aKey[1]; + pLeaf->aData[0] = pLeaf->aData[1]; + case 1: pLeaf->aKey[1] = pLeaf->aKey[2]; + pLeaf->aData[1] = pLeaf->aData[2]; + case 2: pLeaf->aKey[2] = pLeaf->aKey[3]; + pLeaf->aData[2] = pLeaf->aData[3]; + case 3: pLeaf->aKey[3] = 0; + return WFSKRN_RESULT_OK; + } + // No records left in the leaf - delete the leaf + u32 nOfs = PTreeGetOfs(pLeaf, pAllocator); + pAllocator->fpFreeNode(pAllocator->pBase, nOfs); + // Delete the entry from the parent node + u32 nLevel = 1; + while(nLevel <= pPTreeHdr->nRootHeight) { + ++pEntryIdx; + PTreeNode *pNode = pPti->apNode[nLevel-1]; + switch(*pEntryIdx) { + case 0: if (pNode->aKey[0]==0) { + break; + } + pNode->aOfs[0] = pNode->aOfs[1]; + case 1: pNode->aKey[0] = pNode->aKey[1]; + pNode->aOfs[1] = pNode->aOfs[2]; + case 2: pNode->aKey[1] = pNode->aKey[2]; + pNode->aOfs[2] = pNode->aOfs[3]; + case 3: pNode->aKey[2] = pNode->aKey[3]; + pNode->aOfs[3] = pNode->aOfs[4]; + case 4: pNode->aKey[3] = pNode->aKey[4]; + pNode->aOfs[4] = pNode->aOfs[5]; + case 5: pNode->aKey[4] = 0; + return WFSKRN_RESULT_OK; + } + nOfs = PTreeGetOfs(pNode, pAllocator); + pAllocator->fpFreeNode(pAllocator->pBase, nOfs); + ++nLevel; + } + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult PTreeFirst(PTreeHdr *pPTreeHdr, PTreeItr *pPti, PTreeAllocator *pAllocator) { + if (pPTreeHdr->nNumRecs == 0) { + return WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; + } + u32 nLevel = pPTreeHdr->nRootHeight; + u32 *pEntryIdx = &pPti->aEntryIdx[nLevel]; + u32 nOfs = (u32)pPTreeHdr->nRootOfs; + memset(pPti->aEntryIdx, 0, sizeof(pPti->aEntryIdx)); + while (nLevel) { + --nLevel; + PTreeNode *pNode = pPti->apNode[nLevel] = PTreeGetNode(pAllocator, nOfs); + nOfs = pNode->aOfs[0]; //*pEntryIdx + --pEntryIdx; + } + PTreeLeaf *pLeaf = pPti->pLeaf = PTreeGetLeaf(pAllocator, nOfs); + pPti->nKey = pLeaf->aKey[0]; + pPti->nData = pLeaf->aData[0]; + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult PTreeNext(PTreeHdr *pPTreeHdr, PTreeItr *pPti, PTreeAllocator *pAllocator) { + WFSKrnResult nResult = WFSKRN_RESULT_OK; + u32 *pEntryIdx = pPti->aEntryIdx; +#if _DEBUG_PTREE + if (pPti->pLeaf->aKey[*pEntryIdx] < nCurKey) { + WFSKrnOutputErrorStr("Leaf key out of order wrt. parent"); + } + nCurKey = pPti->pLeaf->aKey[*pEntryIdx]; +#endif + ++(*pEntryIdx); + u32 *aKey = pPti->pLeaf->aKey; + u32 *pKey = &aKey[*pEntryIdx]; + if ((*pEntryIdx==PTREE_LEAF_FAN_OUT) || (*pKey==0)) { + u32 *pEntryIdxEnd = &pPti->aEntryIdx[pPTreeHdr->nRootHeight]; + PTreeNode **ppNode = pPti->apNode; + while(1) { + ++pEntryIdx; + if (pEntryIdx > pEntryIdxEnd) { + return WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND; + } + aKey = (*ppNode)->aKey; + ++ppNode; +#if _DEBUG_PTREE + ++nNodeCount; +#endif + if (*pEntryIdx >= PTREE_NODE_FAN_OUT-1) { + continue; + } + pKey = &aKey[*pEntryIdx]; +#if _DEBUG_PTREE + if (*pKey != 0) { + //MyOSReport("0x%08x\n", *pKey); + if (*pKey < nCurKey) { + WFSKrnOutputErrorStr("Parent key out of order wrt. previous child"); + } + } + nCurKey = *pKey; +#endif + ++(*pEntryIdx); + if (*pKey != 0) { + break; + } + } + --ppNode; + u32 nOfs = (*ppNode)->aOfs[pKey - aKey + 1]; + while(1) { + --pEntryIdx; + *pEntryIdx = 0; + if (ppNode == pPti->apNode) { + break; + } + --ppNode; + *ppNode = PTreeGetNode(pAllocator, nOfs); + nOfs = (*ppNode)->aOfs[0]; + } + pPti->pLeaf = PTreeGetLeaf(pAllocator, nOfs); + aKey = pPti->pLeaf->aKey; + pKey = &aKey[0]; + } + pPti->nKey = *pKey; + pPti->nData = pPti->pLeaf->aData[pKey - aKey]; + return nResult; +} + + +WFSKrnResult PTreeInsertOrUpdateRec(PTreeHdr *pPTreeHdr, u32 nKey, u32 nData, PTreeAllocator *pAllocator) { + // This function either adds a new record, or if a record already exists with the specified key, updates it to the new data + PTreeItr pti; + WFSKrnResult nResult = PTreeInsert(pPTreeHdr, &pti, nKey, nData, pAllocator); + if (nResult == WFSKRN_RESULT_PTREE_ENTRY_FOUND) { + pti.pLeaf->aData[pti.aEntryIdx[0]] = nData; + } + return nResult; +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if _DEBUG_PTREE + + void PTreeCheck(PTreeHdr *pPTreeHdr, PTreeAllocator *pAllocator, bool bReport) { + nCurKey = 0; + nNodeCount = 0; + PTreeItr pti; + u32 nNumRecs = 0; + WFSKrnResult nResult = PTreeFirst(pPTreeHdr, &pti, pAllocator); + if (nResult == WFSKRN_RESULT_OK) { + ++nNodeCount; + while(1) { + ++nNumRecs; + u32 nPrevKey = pti.nKey; + if (bReport) { + MyOSReport("%4d. %04x 0x%08x 0x%08x\n", nNumRecs, PTreeGetOfs(pti.pLeaf, pAllocator), pti.nKey, pti.nData); + } + nResult = PTreeNext(pPTreeHdr, &pti, pAllocator); + if (nResult != WFSKRN_RESULT_OK) { + break; + } + if (pti.nKey <= nPrevKey) { + WFSKrnOutputErrorStr("PTree: key sorting error"); + } + } + } + if (bReport) { + MyOSReport("\n"); + } + if (nResult != WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND) { + WFSKrnOutputErrorCode(nResult); + } + if (nNumRecs != pPTreeHdr->nNumRecs) { + WFSKrnOutputErrorStr("Error! Not enough records\n"); + } + } + + void PTreeChoosePath(PTreeHdr *pPTreeHdr, PTreeItr *pPti, u32 nPathDeterminer, PTreeAllocator *pAllocator) { + u32 nLevel = pPTreeHdr->nRootHeight; + u32 *pEntryIdx = &pPti->aEntryIdx[nLevel]; + u32 nOfs = (u32)pPTreeHdr->nRootOfs; + while (nLevel) { + PTreeNode *pNode = pPti->apNode[nLevel-1] = PTreeGetNode(pAllocator, nOfs); + // Hard-coded binary split search which avoids need to store length of sorted array, by assuming a 0 terminated array + if (pNode->aKey[3] == 0) { + if (pNode->aKey[1] == 0) { + if (pNode->aKey[0] == 0) { + // There are 0 keys (1 child) + *pEntryIdx = 0; + } else { + // There is 1 key (2 children) + *pEntryIdx = nPathDeterminer&1; nPathDeterminer>>=1; + } + } else { + if (pNode->aKey[2] == 0) { + // There are 2 keys (3 children) + *pEntryIdx = nPathDeterminer%3; nPathDeterminer/=3; + } else { + // There are 3 keys (4 children) + *pEntryIdx = nPathDeterminer&3; nPathDeterminer>>=2; + } + } + } else { + if (pNode->aKey[4] == 0) { + // There are 4 keys (5 children) + *pEntryIdx = nPathDeterminer%5; nPathDeterminer/=5; + } else { + // There are 5 keys (6 children) + *pEntryIdx = nPathDeterminer%6; nPathDeterminer/=6; + } + } + nOfs = (u32)pNode->aOfs[*pEntryIdx]; + --pEntryIdx; + --nLevel; + } + PTreeLeaf *pLeaf = pPti->pLeaf = PTreeGetLeaf(pAllocator, nOfs); + if (pLeaf->aKey[2] == 0) { + if (pLeaf->aKey[1] == 0) { + // There is 1 key = (1 child) + *pEntryIdx = 0; + } else { + // There are 2 keys (2 children) + *pEntryIdx = nPathDeterminer&1; + } + } else { + if (pLeaf->aKey[3] == 0) { + // There are 3 keys (3 children) + *pEntryIdx = nPathDeterminer%3; + } else { + // There are 4 keys (4 children) + *pEntryIdx = nPathDeterminer&3; + } + } + pPti->nKey = pLeaf->aKey[*pEntryIdx]; + pPti->nData = pLeaf->aData[*pEntryIdx]; + } + + #include + using namespace std; + void PTreeTest() { + set testSet; + PTreeAllocator allocator; + allocator.pBase = (void*)&wkg.pathCache.pRxtHdr->sbah; + allocator.fpAllocNode = (PTreeAllocNodeFunc) PTreeAllocNodeFromSba; + allocator.fpAllocNodes = (PTreeAllocNodesFunc)PTreeAllocNodesFromSba; + allocator.fpFreeNode = (PTreeFreeNodeFunc) PTreeFreeNodeToSba; + PTreeHdr ptreeHdr; + PTreeItr pti; + PTreeInit(&ptreeHdr, &allocator); + u32 aTarget[] = { 3, 0, 50, 0, 500, 0, 1000, 200, 800, 500, 1200, 0, 2000 }; + u32 nTargetIdx; + u32 nIntialTotalSize = wkg.pathCache.pRxtHdr->sbah.nTotalFree; + for(nTargetIdx=0; nTargetIdx>16) | (nKey<<16); + WFSKrnResult nResult = PTreeInsert(&ptreeHdr, &pti, nKey, nData, &allocator); + switch(nResult) { + case WFSKRN_RESULT_OK: + break; + case WFSKRN_RESULT_PTREE_FULL: + goto Done; + case WFSKRN_RESULT_PTREE_ENTRY_FOUND: + if (testSet.find(nKey) == testSet.end()) { + WFSKrnOutputErrorStr("Error! PTreeInsert() detected erroneous duplicate"); + } + continue; + default: + WFSKrnOutputErrorCode(nResult); + } + if (testSet.find(nKey) != testSet.end()) { + WFSKrnOutputErrorStr("Error! PTreeInsert() did not detect duplicate"); + } + testSet.insert(nKey); + PTreeCheck(&ptreeHdr, &allocator, false); + u32 nTotalSize = wkg.pathCache.pRxtHdr->sbah.nTotalFree + (nNodeCount * (1<sbah.nTotalFree, nNodeCount); + WFSKrnOutputErrorStr("Memory leak detected in PTree\n"); + } + } + while(ptreeHdr.nNumRecs > nTarget) { + u32 nRandomPathDeterminer = RandomU32(); + PTreeChoosePath(&ptreeHdr, &pti, nRandomPathDeterminer, &allocator); + if (testSet.find(pti.nKey) == testSet.end()) { + WFSKrnOutputErrorStr("Error! PTreeChoosePath() picked a key which should not be in the tree"); + } + testSet.erase(pti.nKey); + PTreeDelete(&ptreeHdr, &pti, &allocator); + PTreeCheck(&ptreeHdr, &allocator, false); + u32 nTotalSize = wkg.pathCache.pRxtHdr->sbah.nTotalFree + (nNodeCount * (1<sbah.nTotalFree, nNodeCount); + WFSKrnOutputErrorStr("Memory leak detected in PTree\n"); + } + } + u32 nKey=0; + for(; nKey<=0xFFFF00; nKey+=0x100) { + WFSKrnResult nResult = PTreeFind(&ptreeHdr, &pti, nKey, &allocator); + switch(nResult) { + case WFSKRN_RESULT_PTREE_ENTRY_NOT_FOUND: + if (testSet.find(nKey) != testSet.end()) { + WFSKrnOutputErrorStr("Error! PTreeFind() did not find an existing entry"); + } + if (ptreeHdr.nNumRecs) { + if (pti.aEntryIdx[0]>PTREE_LEAF_FAN_OUT) { + WFSKrnOutputErrorStr("Error! entryIdx out of range\n"); break; + } + if (pti.aEntryIdx[0]!=0) { + if (pti.pLeaf->aKey[pti.aEntryIdx[0]-1] >= nKey) { + WFSKrnOutputErrorStr("Error! entryIdx too high\n"); break; + } + } + if (pti.aEntryIdx[0]aKey[pti.aEntryIdx[0]]; + if ((nHigh!=0)&&(nHigh<=nKey)) { + WFSKrnOutputErrorStr("Error! entryIdx too low\n"); break; + } + } + } + break; + case WFSKRN_RESULT_PTREE_ENTRY_FOUND: + if (testSet.find(nKey) == testSet.end()) { + WFSKrnOutputErrorStr("Error! PTreeFind() found a non-existing entry"); + } + break; + default: + WFSKrnOutputErrorCode(nResult); + } + } + } + Done: + PTreeCheck(&ptreeHdr, &allocator, true); + u32 nTotalSize = wkg.pathCache.pRxtHdr->sbah.nTotalFree + (nNodeCount * (1<sbah.nTotalFree, nNodeCount); + WFSKrnOutputErrorStr("Memory leak detected in PTree\n"); + } + } + +#endif //_DEBUG_PTREE diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_PathCache.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_PathCache.cpp new file mode 100644 index 0000000..22d1e55 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_PathCache.cpp @@ -0,0 +1,1036 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_PathCache.cpp - Caches recently used path names plus root path names "/dev", "/vol" + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_PathCache.cpp,v $ + Revision 1.23 2008/12/04 00:48:21 ooizumi + Fixed variable name witch is defined twice. + Changed definition name to enable permission. + + Revision 1.22 2008/11/05 15:08:20 ueno + Modified DirItrMapBlks() to roll back the update map in case of error. + + Revision 1.21 2008/10/31 09:51:11 ueno + Modified WFSSrvAPIs to return WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED when path cache is short of memory. + + Revision 1.20 2008/10/14 04:13:07 ooizumi + Modified PathCacheFindParentDir() to return WFSKRN_RESULT_NOT_DIRECTORY + when device path is specified. + + Revision 1.19 2008/10/10 01:21:06 ooizumi + Fixed to call PathCacheInitSlash() in PathCacheFindParentDir(). + + Revision 1.18 2008/10/09 14:11:33 ueno + Modified PathCacheIncreaseEntryOpenHandleCount() to return WFSKRN_RESULT_FILE_OPEN when writing a file which is already open. + + Revision 1.17 2008/10/09 04:15:11 ooizumi + Fixed build error. + + Revision 1.16 2008/10/09 03:24:32 ooizumi + Fixed to update volume root's nAccessListIdx in PathCacheData. + + Revision 1.15 2008/10/08 04:57:25 ooizumi + Fixed a bug PathCacheFindPath doesn't return devAttr when device name is specified. + + Revision 1.14 2008/10/07 10:31:09 ooizumi + Modified to update nObjCreator in PathCache. + + Revision 1.13 2008/08/28 06:04:38 ooizumi + Modified to set 0 to pAreaInfo when the path had depth 1 is passed to PathCacheFindParentDir. + Fixed an error message. + + Revision 1.12 2008/08/05 03:56:29 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.11 2008/07/30 21:10:15 paul + Fixed a bug in PathCacheInsertCommon(). + + Revision 1.10 2008/07/30 06:11:57 ooizumi + Implemented initial version of permission functions. + + Revision 1.9 2008/07/28 22:21:56 paul + Fixed a bug in PathCacheDeleteSubTree(). + + Revision 1.8 2008/07/21 22:32:02 paul + Added more consistency checking code for path cache entries. + Fixed bugs related to the distinction between the RadixTree and the DirectoryTree - special handling of the '/' character. + + Revision 1.7 2008/07/17 22:56:54 paul + Fixed some bugs. Changed PathCacheDecreaseEntryOpenHandleCount() to move from pinned list to MRU list. + + Revision 1.6 2008/07/17 05:33:38 kondo_masahiro + Fixed codes for porting IOP. + + Revision 1.5 2008/07/09 00:49:01 paul + Changes to make directory code work with block cache. Also a fix for device attach. + + Revision 1.4 2008/06/09 17:56:14 paul + Rewrote PathCache to use a radix tree. Now actually provides PathCache functionality. + Also stores a list of open file / directory search paths so that invalid WFSSrv calls can be detected. + + Revision 1.3 2008/05/12 22:35:32 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.2 2008/05/12 19:16:41 paul + Made naming more consistent + + Revision 1.1 2008/05/10 03:57:13 kondo_masahiro + Initial check-in + +*---------------------------------------------------------------------------*/ + +#undef _KRN_FILE_ +#define _KRN_FILE_ "PathCache" + +#include "wfskrn_Config.h" +#include "wfskrn_PathCache.h" +#include "wfskrn_Defs.h" +#include "wfskrn_Api.h" +#include "wfskrn_DirRxTree.h" +#include "wfskrn_DirNodeStack.h" +#include "wfskrn_DirFind.h" +#include "wfskrn_Errors.h" + + +// This module is used for 4 distinct purposes: +// 1. To store the contents of the "/", "/dev", and "/vol", directories which only exist in memory, not on physical storage. +// It assists in allowing these virtual directories to be searched like real directories. +// 2. To keep track of which Files and Directories have associated Open File Handles or Search Directory Handles. +// (For example this is used to prevent renaming a directory which has one or more open files below it) +// 3. To speed up access to recently used directories and reduce the size of the block cache working set, by +// avoiding the need to re-navigate directories along the path every time an operation is performed. +// 4. To store results of intermediate calculations in order to speed up the parsing of permissions chains +// in the WFS Permissions API. +// ToDo: Purpose 4 is not yet implemented + +#if _WIN32 + static FILE *fpOut; +#endif + +void PathCacheDebugOutputList(PathCacheEntry *pAnchor, char cChar) { + PathCacheEntry *pEntry = pAnchor->ml.pNext; + while(pEntry != pAnchor) { + WFSPathName path; + RxtNodeHdr *pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + pEntry->ah.nParentOfs); + RxtGetString(wkg.pathCache.pRxtHdr, pNodeHdr, path.sStr, pEntry->pcd.nStrLen); + MyOSReport("%p %c %2d %2d %s\n", pEntry->pcd.pData, cChar, pEntry->pcd.nPinCount, pEntry->pcd.nOpenHandleCount, path.sStr); +#if _WIN32 + fprintf(fpOut, "%p %c %2d %2d %s\n", pEntry->pcd.pData, cChar, pEntry->pcd.nPinCount, pEntry->pcd.nOpenHandleCount, path.sStr); +#endif + pEntry = pEntry->ml.pNext; + } + MyOSReport("\n"); +} + +void PathCacheDebugOutput() { +#if _WIN32 + char sFileName[40]; + sprintf(sFileName, "PathCache.txt"); + //sprintf(sFileName, "PathCache_%d.txt", nDbgCommandCount); + fpOut = fopen(sFileName, "w"); +#endif + PathCacheDebugOutputList(wkg.pathCache.pPinAnchor, 'P'); + PathCacheDebugOutputList(wkg.pathCache.pMruAnchor, 'C'); +#if _WIN32 + fclose(fpOut); +#endif +} + + +#if _CHECK_PATH_CACHE +void PathCacheEntryCheck(u32 nRecIdx, u32 nNodeDepth, utf8 *sPath, void *pEntryPtr) { + // This is a callback function called by RxtCheck() to check the contents of a radix tree entry (in this case a path cache entry) + // Checks: + // * That OpenHandleCount matches the sum of immediate children's OpenHandleCount and the sum of all descendants' PinCount + static utf8 sLastPath[WFS_MAX_PATH_NAME_SIZE]; + static u32 aPinCount[WFS_MAX_PATH_DEPTH]; + static u32 aSumOpenHandleCount[WFS_MAX_PATH_DEPTH]; + static u32 nLastPathDepth; + utf8 *pSrcStr = sPath; + utf8 *pDstStr = sLastPath; + u32 nPathDepth = 0; + PathCacheEntry *pEntry = (PathCacheEntry *)pEntryPtr; + if (pEntry->pcd.nOpenHandleCount) { + while(*pSrcStr) { + if (*pDstStr != *pSrcStr) { + break; + } + if (*pSrcStr == '/') { + ++nPathDepth; + } + ++pDstStr; + ++pSrcStr; + } + u32 nDiffDepth = nPathDepth; + while(*pSrcStr) { + if (*pSrcStr == '/') { + if (nPathDepth > 0) { + aSumOpenHandleCount[nPathDepth] = aSumOpenHandleCount[nPathDepth-1]; + } + ++nPathDepth; + } + *pDstStr++ = *pSrcStr++; + } + *pDstStr = 0; + if (nDiffDepth < nPathDepth) { + aSumOpenHandleCount[nPathDepth] = 0; + nLastPathDepth = nPathDepth; + } else { + while(nLastPathDepth > nPathDepth) { + aPinCount[nLastPathDepth] = 0; + aSumOpenHandleCount[nLastPathDepth-1] = aSumOpenHandleCount[nLastPathDepth]; + --nLastPathDepth; + } + } + if (nRecIdx==0) { + aSumOpenHandleCount[nPathDepth] = 0; + } + aSumOpenHandleCount[nPathDepth] += pEntry->pcd.nOpenHandleCount; + aPinCount[nPathDepth] = pEntry->pcd.nPinCount; +#if _DEBUG + if (nPathDepth >= 2) { + if (aSumOpenHandleCount[nPathDepth] > aSumOpenHandleCount[nPathDepth-1]) { + PathCacheDebugOutput(); + WFSKrnOutputErrorStr("nOpenHandleCount inconsistent!"); + } + } + if (nPathDepth >= 4) { + if ((aSumOpenHandleCount[nPathDepth] + aPinCount[nPathDepth-1]) > aSumOpenHandleCount[nPathDepth-1]) { + PathCacheDebugOutput(); + WFSKrnOutputErrorStr("nOpenHandleCount + nPinCount inconsistent!"); + } + } +#endif + } +} + +void PathCacheCheck() { + RxtCheck(wkg.pathCache.pRxtHdr, 0, PathCacheEntryCheck); //WFS_LOG2_PATH_CACHE_SIZE, PathCacheEntryCheck); +#if _DEBUG_PATH_CACHE + if ((nDirTest>=nDirTestBreakPoint-1)&&(nDirTest<=nDirTestBreakPoint)) { + MyOSReport("\n"); + } +#endif //_DEBUG_PATH_CACHE +} +#endif //_CHECK_PATH_CACHE + + +void PathCacheInsertToEntryListAfterCursorEntry(PathCacheEntry *pCursorEntry, PathCacheEntry *pNewEntry) { + pNewEntry->ml.pNext = pCursorEntry->ml.pNext; + pCursorEntry->ml.pNext->ml.pPrev = pNewEntry; + pNewEntry->ml.pPrev = pCursorEntry; + pCursorEntry->ml.pNext = pNewEntry; +} + + +inline void PathCacheDeleteLink(PathCacheEntry *pEntry) { + pEntry->ml.pPrev->ml.pNext = pEntry->ml.pNext; + pEntry->ml.pNext->ml.pPrev = pEntry->ml.pPrev; +} + + +void PathCacheDeleteEntry(PathCacheEntry *pEntry) { + PathCacheDeleteLink(pEntry); + RxtItr rxi; + rxi.nEntryIdx = pEntry->ah.nEntryIdx+1; + rxi.pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + pEntry->ah.nParentOfs); + SbaFreeSubBlk((WFSSubBlkAllocHdr *)wkg.pathCache.pRxtHdr, (u32)((u8*)pEntry - (u8*)wkg.pathCache.pRxtHdr), PATH_CACHE_LOG2_NODE_SIZE); + RxtDelete(wkg.pathCache.pRxtHdr, &rxi); +} + + +WFSKrnResult PathCacheRecursiveDelete(RxtItr *pRxi) { + // Deletes a sub-tree of entries from the path cach. + RxtNodeHdr *pNodeHdr = pRxi->pNodeHdr; + u32 nNodeOfs = (u8*)pNodeHdr - (u8*)wkg.pathCache.pRxtHdr; + u32 nParentOfs = 0; + utf8 *pChoiceChar; + while(1) { + u16 *pSrcNodeOfsTblEnd = (u16*)((u8*)pNodeHdr + (1<nLog2Size)); + pRxi->nEntryIdx = 1; + pChoiceChar = &pNodeHdr->aFirstChar[pNodeHdr->nStrLen]; + if (*pChoiceChar == 0) { + // String terminator char indicates this is path cache entry + u32 nAttrOfs = pSrcNodeOfsTblEnd[-1]; + PathCacheEntry *pEntry = (PathCacheEntry *)((u8*)wkg.pathCache.pRxtHdr + nAttrOfs); + PathCacheDeleteLink(pEntry); + SbaFreeSubBlk((WFSSubBlkAllocHdr *)wkg.pathCache.pRxtHdr, (u32)((u8*)pEntry - (u8*)wkg.pathCache.pRxtHdr), PATH_CACHE_LOG2_NODE_SIZE); + --wkg.pathCache.pRxtHdr->nNumRecs; + ++pRxi->nEntryIdx; + } + if (pRxi->nEntryIdx > pNodeHdr->nNumEntries) { + do { + pRxi->nEntryIdx = pNodeHdr->nEntryIdx + 2; + nParentOfs = pNodeHdr->nParentOfs; + SbaFreeSubBlk((WFSSubBlkAllocHdr *)wkg.pathCache.pRxtHdr, nNodeOfs, pNodeHdr->nLog2Size); + nNodeOfs = nParentOfs; + pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + nNodeOfs); + if (pRxi->nDepth == 0) { + // We reached the top of the stack, so this should be the last record + --pRxi->nEntryIdx; + return RxtDeleteNode(wkg.pathCache.pRxtHdr, pRxi, pRxi->nEntryIdx, nNodeOfs, pNodeHdr); + } + --pRxi->nDepth; + } while(pRxi->nEntryIdx > pNodeHdr->nNumEntries); + pChoiceChar = &pNodeHdr->aFirstChar[pNodeHdr->nStrLen + pRxi->nEntryIdx-1]; + if ((unsigned)pChoiceChar[-1] >= (unsigned)*pChoiceChar) { + WFSKrnOutputErrorStr("PathCache: Choice out of order!"); + } + } + ++pRxi->nDepth; + nParentOfs = nNodeOfs; + nNodeOfs = RxtGetChildOfs(pRxi->nEntryIdx, pNodeHdr); + pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + nNodeOfs); + } +// return WFSKRN_RESULT_OK; +} + + +WFSKrnResult PathCacheDeleteSubTree(PathCacheEntry *pEntry) { + RxtItr rxi; + rxi.nEntryIdx = pEntry->ah.nEntryIdx+1; + u32 nParentOfs = pEntry->ah.nParentOfs; + rxi.pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + nParentOfs); + utf8 *pChoiceChar = &rxi.pNodeHdr->aFirstChar[rxi.pNodeHdr->nStrLen]; + rxi.nEntryIdx = 1; + while(rxi.nEntryIdx <= rxi.pNodeHdr->nNumEntries) { + switch(pChoiceChar[rxi.nEntryIdx-1]) { + case 0: { + u32 nAttrOfs = RxtGetChildOfs(rxi.nEntryIdx, rxi.pNodeHdr); + PathCacheEntry *pTargetEntry = (PathCacheEntry *)((u8*)wkg.pathCache.pRxtHdr + nAttrOfs); + PathCacheDeleteLink(pTargetEntry); + --wkg.pathCache.pRxtHdr->nNumRecs; + SbaFreeSubBlk((WFSSubBlkAllocHdr *)wkg.pathCache.pRxtHdr, (u32)((u8*)pEntry - (u8*)wkg.pathCache.pRxtHdr), PATH_CACHE_LOG2_NODE_SIZE); + u32 nNumEntries = rxi.pNodeHdr->nNumEntries; + if (nNumEntries > 1) { + utf8 cNextChoice = pChoiceChar[1]; + WFSKrnResult nResult = RxtDeleteNode(wkg.pathCache.pRxtHdr, &rxi, rxi.nEntryIdx, nParentOfs, rxi.pNodeHdr); + if (nNumEntries == 2) { + if (cNextChoice == '/') { + rxi.nDepth = 0; + return PathCacheRecursiveDelete(&rxi); + } + return nResult; + } + pChoiceChar = &rxi.pNodeHdr->aFirstChar[rxi.pNodeHdr->nStrLen]; + rxi.nEntryIdx = 0; + } else { + rxi.nEntryIdx = rxi.pNodeHdr->nEntryIdx + 1; + u32 nNodeOfs = rxi.pNodeHdr->nParentOfs; + SbaFreeSubBlk((WFSSubBlkAllocHdr *)wkg.pathCache.pRxtHdr, nParentOfs, rxi.pNodeHdr->nLog2Size); + rxi.pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + nNodeOfs); + return RxtDeleteNode(wkg.pathCache.pRxtHdr, &rxi, rxi.nEntryIdx, nNodeOfs, rxi.pNodeHdr); + } + break; + } + case'/': + rxi.pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + RxtGetChildOfs(rxi.nEntryIdx, rxi.pNodeHdr)); + rxi.nDepth = 0; + return PathCacheRecursiveDelete(&rxi); + } + ++rxi.nEntryIdx; + } + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult PathCacheDeleteLru() { + PathCacheEntry *pEntry = wkg.pathCache.mruAnchor.pPrev; + if (pEntry == wkg.pathCache.pMruAnchor) { +#if _DEBUG + WFSKrnOutputErrorStr("Path Cache MRU list already empty\n"); +#endif + return WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED; // MRU list is empty. + } +#if _DEBUG_PATH_CACHE + if (pEntry->pcd.nPinCount) { + WFSKrnOutputErrorStr("PinCount != 0\n"); + } +#endif + PathCacheDeleteEntry(pEntry); + return WFSKRN_RESULT_OK; +} + +inline WFSKrnResult PathCacheDeleteLruAndFixItr(RxtItr *pRxi) { + // After deleting the LRU element, fix up pRxi which could otherwise be invalidated by the delete + WFSKrnResult nResult = PathCacheDeleteLru(); + if (nResult == WFSKRN_RESULT_OK) + { + if (pRxi->pNodeHdr->nParentOfs) { + RxtNodeHdr *pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + pRxi->pNodeHdr->nParentOfs); + pRxi->pOfs = RxtGetChildOfsPtr(pRxi->pNodeHdr->nEntryIdx+1, pNodeHdr); + } else { + pRxi->pOfs = &wkg.pathCache.pRxtHdr->nRootOfs; + } + } + return nResult; +} + + +PathCacheEntry *PathCacheFind3(RxtItr *pRxi, u32 nStrLen, void **ppData) { + WFSKrnResult nResult = RxtFind(wkg.pathCache.pRxtHdr, pRxi, nStrLen); + if (nResult == WFSKRN_RESULT_DIR_ENTRY_FOUND) { + PathCacheEntry *pEntry = (PathCacheEntry *)((u8*)wkg.pathCache.pRxtHdr + RxtGetChildOfs(1, pRxi->pNodeHdr)); + *ppData = pEntry->pcd.pData; + return pEntry; + } + return 0; +} + + +void PathCacheInitSlash(PathCacheItr *pPci) { + // This function fixes up the Pci to skip the root '/' so that PathCacheIncrementalFindEntry can be used + pPci->rxi.nDepth = 0; + pPci->rxi.pOfs = &wkg.pathCache.pRxtHdr->nRootOfs; + pPci->rxi.pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + *pPci->rxi.pOfs); + pPci->rxi.pNodeStrPtr = pPci->rxi.pNodeHdr->aFirstChar; +} + + +WFSKrnResult PathCacheIncrementalFind(RxtItr *pRxi, u32 nStrLen) { + RxtHdr *pRxtHdr = wkg.pathCache.pRxtHdr; + WFSKrnResult nResult; + utf8 *pStrEnd = pRxi->pStrPtr + nStrLen; + RxtNodeHdr *pNodeHdr = pRxi->pNodeHdr; + utf8 cSearchChar = '/'; + if (*pRxi->pStrPtr != cSearchChar) { + --pRxi->pStrPtr; + } + goto EntryPoint; + while(1) { + pNodeHdr = (RxtNodeHdr *)((u8*)pRxtHdr + *pRxi->pOfs); + u32 nNodeStrLen = pNodeHdr->nStrLen; + pRxi->pNodeStrPtr = pNodeHdr->aFirstChar; + u32 nSearchStrLen = pStrEnd - pRxi->pStrPtr; + if (nSearchStrLen < nNodeStrLen) { + while((nSearchStrLen) && (*pRxi->pStrPtr == *pRxi->pNodeStrPtr)) { + ++pRxi->pStrPtr; ++pRxi->pNodeStrPtr; --nSearchStrLen; + } + nNodeStrLen -= (pRxi->pNodeStrPtr - pNodeHdr->aFirstChar); + pRxi->nEntryIdx = -(s32)nNodeStrLen; + nResult = WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH; + if (nSearchStrLen == 0) { + nResult = WFSKRN_RESULT_DIR_NODE_STRING_PREFIX; + } + break; + } + while((nNodeStrLen) && (*pRxi->pStrPtr == *pRxi->pNodeStrPtr)) { + ++pRxi->pStrPtr; ++pRxi->pNodeStrPtr; --nNodeStrLen; + } + if (nNodeStrLen) { + pRxi->nEntryIdx = pRxi->pNodeStrPtr - pNodeHdr->aFirstChar; + nResult = WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH; + break; + } + // matched all the characters from the prefix. pRxi->pNodeStrPtr should now be pointing to the array of choices following the prefix. + cSearchChar = *pRxi->pStrPtr; + if (pRxi->pStrPtr == pStrEnd){ + cSearchChar = 0; + } +EntryPoint: + if (!DirBinarySplitSearchChoices(pRxi->pNodeStrPtr, pNodeHdr->nNumEntries, cSearchChar, (u32*)&pRxi->nEntryIdx)) { + nResult = WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND; + break; + } + // Found the search character. + if (cSearchChar==0) { + // We matched a 0 .. which means we have found the search string + nResult = WFSKRN_RESULT_DIR_ENTRY_FOUND; + break; + } + ++pRxi->nDepth; + pRxi->pOfs = RxtGetChildOfsPtr((s32)pRxi->nEntryIdx, pNodeHdr); + ++pRxi->pStrPtr; + } + pRxi->pNodeHdr = pNodeHdr; + return nResult; +} + + +inline PathCacheEntry *PathCacheIncrementalFindEntry(RxtItr *pRxi, u32 nStrLen, void **ppData) { + WFSKrnResult nResult = PathCacheIncrementalFind(pRxi, nStrLen); + if (nResult == WFSKRN_RESULT_DIR_ENTRY_FOUND) { + PathCacheEntry *pEntry = (PathCacheEntry *)((u8*)wkg.pathCache.pRxtHdr + RxtGetChildOfs(1, pRxi->pNodeHdr)); + *ppData = pEntry->pcd.pData; + return pEntry; + } + return 0; +} + + +PathCacheEntry *PathCacheInsertCommon(WFSKrnResult nResult, PathCacheEntry *pCursorEntry, RxtItr *pRxi, utf8 *sStr, u32 nStrLen) { +#if _CHECK_PATH_CACHE + PathCacheCheck(); +#endif + PathCacheEntry *pEntry; + if (nResult == WFSKRN_RESULT_DIR_ENTRY_FOUND) { + // The string already exists in the cache + pEntry = (PathCacheEntry *)((u8*)wkg.pathCache.pRxtHdr + RxtGetChildOfs(1, pRxi->pNodeHdr)); + // Delete entry from current position on recency list and move it to the MRU position + if (pEntry->pcd.nPinCount == 0) { + pEntry->ml.pPrev->ml.pNext = pEntry->ml.pNext; + pEntry->ml.pNext->ml.pPrev = pEntry->ml.pPrev; + goto InsertToEntryList; + } + goto IncCount; + } + u32 nAttrOfs; + while(1) { + nAttrOfs = SbaAllocSubBlk((WFSSubBlkAllocHdr *)wkg.pathCache.pRxtHdr, PATH_CACHE_LOG2_NODE_SIZE); + if (nAttrOfs) { + pEntry = (PathCacheEntry *)((u8*)wkg.pathCache.pRxtHdr + nAttrOfs); + pEntry->ah.nLog2Size = PATH_CACHE_LOG2_NODE_SIZE; + pEntry->ah.nEntryIdx = 0; + u32 nSuffixLen = nStrLen - (pRxi->pStrPtr - sStr); + nResult = RxtInsert(wkg.pathCache.pRxtHdr, pRxi, nSuffixLen, (RxtAttrHdr *)pEntry); + if (nResult == WFSKRN_RESULT_OK) { + break; + } + if (nResult != WFSKRN_RESULT_DIR_BLK_FULL) { + WFSKrnOutputErrorCode(nResult); + return 0; + } + SbaFreeSubBlk((WFSSubBlkAllocHdr *)wkg.pathCache.pRxtHdr, nAttrOfs, PATH_CACHE_LOG2_NODE_SIZE); + } + nResult = PathCacheDeleteLruAndFixItr(pRxi); + if (nResult != WFSKRN_RESULT_OK) + { +#if _DEBUG + WFSKrnOutputErrorStr("PathCacheInsertCommon() : WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED\n"); +#endif + return NULL; // [check] + } + pRxi->pStrPtr = sStr; + RxtFind(wkg.pathCache.pRxtHdr, pRxi, nStrLen); + } + memset(&pEntry->pcd, 0, sizeof(PathCacheData)); + pEntry->pcd.nStrLen = nStrLen; + // Calculate sum of OpenHandleCount from any pre-existing children + u32 nSumOfOpenHandleCounts = 0; + RxtNodeHdr *pBaseNodeHdr = pRxi->pNodeHdr; + u32 nNumEntries = pBaseNodeHdr->nNumEntries; + if (nNumEntries > 1) { + utf8 *pChoiceChar; + // Calculate the sum of open handle counts for any direct child paths + u32 nEntryIdx = 1; + while(nEntryIdx<=nNumEntries) { + if (pBaseNodeHdr->aFirstChar[pBaseNodeHdr->nStrLen+nEntryIdx-1] == '/') { + u32 nNodeOfs = RxtGetChildOfs(nEntryIdx, pBaseNodeHdr); + RxtNodeHdr *pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + nNodeOfs); + u32 nRootDepth = pRxi->nDepth; + u32 nParentOfs = (u8*)pBaseNodeHdr - (u8*)wkg.pathCache.pRxtHdr; + while(1) { + u16 *pSrcNodeOfsTblEnd = (u16*)((u8*)pNodeHdr + (1<nLog2Size)); + utf8 *pStr = pNodeHdr->aFirstChar; + pChoiceChar = pStr + pNodeHdr->nStrLen; + pRxi->nEntryIdx = 1; + if (*pChoiceChar == 0) { + // String terminator char indicates this is a record, so increment the record count + PathCacheEntry *pChildEntry = (PathCacheEntry *)((u8*)wkg.pathCache.pRxtHdr + RxtGetChildOfs_ote(1, pSrcNodeOfsTblEnd)); + nSumOfOpenHandleCounts += pChildEntry->pcd.nOpenHandleCount; + ++pRxi->nEntryIdx; + ++pChoiceChar; + } + if (*pChoiceChar == '/') { + TryNextEntry: + ++pChoiceChar; + ++pRxi->nEntryIdx; + } + if (pRxi->nEntryIdx > pNodeHdr->nNumEntries) { + do { + pRxi->nEntryIdx = pNodeHdr->nEntryIdx + 2; + pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + pNodeHdr->nParentOfs); + if (pRxi->nDepth == nRootDepth) { + // We reached the top of the stack, so this should be the last record + --pRxi->nEntryIdx; + goto BranchFinished; + } + --pRxi->nDepth; + } while(pRxi->nEntryIdx > pNodeHdr->nNumEntries); + pChoiceChar = &pNodeHdr->aFirstChar[pNodeHdr->nStrLen + pRxi->nEntryIdx-1]; + #if _DEBUG + if ((unsigned)pChoiceChar[-1] >= (unsigned)*pChoiceChar) { + WFSKrnOutputErrorStr("PathCache: Choice out of order!"); + } + #endif + if (*pChoiceChar == '/') { + goto TryNextEntry; + } + } + ++pRxi->nDepth; + nParentOfs = nNodeOfs; + nNodeOfs = RxtGetChildOfs(pRxi->nEntryIdx, pNodeHdr); + pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + nNodeOfs); + } + } + BranchFinished: + ++nEntryIdx; + } + } + pEntry->pcd.nOpenHandleCount = nSumOfOpenHandleCounts; +InsertToEntryList: + PathCacheInsertToEntryListAfterCursorEntry(pCursorEntry, pEntry); +IncCount: + if (pCursorEntry == wkg.pathCache.pPinAnchor) { + ++pEntry->pcd.nPinCount; +#if _DEBUG_PATH_CACHE + ++wkg.pathCache.nNumPinned; + MyOSReport("of:%2d + od:%2d - pc:%2d = %2d :: ", wkg.hnd.nNumUsedFileHandles, wkg.hnd.nNumUsedSearchDirHandles, wkg.pathCache.nNumPinned, + wkg.hnd.nNumUsedFileHandles + wkg.hnd.nNumUsedSearchDirHandles - wkg.pathCache.nNumPinned); + MyOSReport("%s <- %d\n", sStr, pEntry->pcd.nPinCount); +#endif + } + return pEntry; +} + + +PathCacheEntry *PathCacheIncrementalInsertAfterCursorEntry(PathCacheEntry *pCursorEntry, RxtItr *pRxi, u32 nPrefixLen, u32 nSuffixLen) { + u32 nStrLen = nPrefixLen + nSuffixLen; + utf8 *sStr = &pRxi->pStrPtr[-(s32)nPrefixLen]; + WFSKrnResult nResult = PathCacheIncrementalFind(pRxi, nSuffixLen); + return PathCacheInsertCommon(nResult, pCursorEntry, pRxi, sStr, nStrLen); +} + + +WFSKrnResult PathCacheIncrementalInsertPinnedEntry(PathCacheItr *pPci, u32 nStrLen) { + u32 nSuffixLen = pPci->pNameEnd - pPci->rxi.pStrPtr; + if (nSuffixLen) { + pPci->pEntry = PathCacheIncrementalInsertAfterCursorEntry(wkg.pathCache.pPinAnchor, &pPci->rxi, nStrLen - nSuffixLen, nSuffixLen); + } else { + PathCacheEntry *pEntry = pPci->pEntry; + if (pEntry->pcd.nPinCount == 0) { + PathCacheDeleteLink(pEntry); + PathCacheInsertToEntryListAfterCursorEntry(wkg.pathCache.pPinAnchor, pEntry); + } + ++pEntry->pcd.nPinCount; + } + + if (pPci->pEntry) + { + return WFSKRN_RESULT_OK; + } + return WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED; +} + + +#if _DEBUG_PATH_CACHE + void PathCachePinEntry(PathCacheEntry *pEntry, utf8 *sStr) { +#else + void PathCachePinEntry(PathCacheEntry *pEntry) { +#endif + if (pEntry->pcd.nPinCount==0) { + // Transfer to pinned list + pEntry->ml.pPrev->ml.pNext = pEntry->ml.pNext; + pEntry->ml.pNext->ml.pPrev = pEntry->ml.pPrev; + PathCacheInsertToEntryListAfterCursorEntry(wkg.pathCache.pPinAnchor, pEntry); + } + ++pEntry->pcd.nPinCount; +#if _DEBUG_PATH_CACHE + ++wkg.pathCache.nNumPinned; + MyOSReport("of:%2d + od:%2d - pc:%2d = %2d :: ", wkg.hnd.nNumUsedFileHandles, wkg.hnd.nNumUsedSearchDirHandles, wkg.pathCache.nNumPinned, + wkg.hnd.nNumUsedFileHandles + wkg.hnd.nNumUsedSearchDirHandles - wkg.pathCache.nNumPinned); + MyOSReport("%s <- %d\n", sStr, pEntry->pcd.nPinCount); +#endif +} + + +PathCacheEntry *PathCacheInsertAfterCursorEntry3(PathCacheEntry *pCursorEntry, utf8 *sStr, u32 nStrLen) { + RxtItr rxi; + rxi.pStrPtr = sStr; + WFSKrnResult nResult = RxtFind(wkg.pathCache.pRxtHdr, &rxi, nStrLen); + return PathCacheInsertCommon(nResult, pCursorEntry, &rxi, sStr, nStrLen); +} + + +#if _DEBUG_PATH_CACHE + WFSKrnResult PathCacheIncreaseEntryOpenHandleCount(PathCacheItr *pPci, WFSAccess nDesiredAccess, utf8 *sStr) { +#else + WFSKrnResult PathCacheIncreaseEntryOpenHandleCount(PathCacheItr *pPci, WFSAccess nDesiredAccess) { +#endif + PathCacheEntry *pEntry = pPci->pEntry; + if (pEntry->pcd.nFlags & PATH_CACHE_FLAG_OPEN_FOR_WRITE) { + --pEntry->pcd.nPinCount; // Assuming the PinCount has been incremented and needs to be undone +#if _DEBUG_PATH_CACHE + --wkg.pathCache.nNumPinned; + MyOSReport("of:%2d + od:%2d - pc:%2d = %2d :: ", wkg.hnd.nNumUsedFileHandles, wkg.hnd.nNumUsedSearchDirHandles, wkg.pathCache.nNumPinned, + wkg.hnd.nNumUsedFileHandles + wkg.hnd.nNumUsedSearchDirHandles - wkg.pathCache.nNumPinned); + MyOSReport("%s <- %d\n", sStr, pEntry->pcd.nPinCount); +#endif + return WFSKRN_RESULT_FILE_OPEN; + } + if (nDesiredAccess & WFS_ACCESS_WRITE) { + if (1 < pEntry->pcd.nPinCount) + { + // This file is already open. // [check] right? + return WFSKRN_RESULT_FILE_OPEN; + } + pEntry->pcd.nFlags |= PATH_CACHE_FLAG_OPEN_FOR_WRITE; + } + RxtNodeHdr *pNodeHdr = pPci->rxi.pNodeHdr; + while(1) { + ++pEntry->pcd.nOpenHandleCount; + while(1) { + if (pNodeHdr->nParentOfs == 0) { + return WFSKRN_RESULT_OK; + } + u32 nEntryIdx = pNodeHdr->nEntryIdx; + pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + pNodeHdr->nParentOfs); + utf8 *pStr = pNodeHdr->aFirstChar; + utf8 *pStrEnd = pStr + pNodeHdr->nStrLen; + if (pStrEnd[nEntryIdx] == '/') { + goto FoundSlash; + } + while(pStraFirstChar[pNodeHdr->nStrLen] != 0) { + if (pNodeHdr->nParentOfs == 0) { + return WFSKRN_RESULT_OK; + } + pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + pNodeHdr->nParentOfs); + }; + pEntry = (PathCacheEntry *)((u8*)wkg.pathCache.pRxtHdr + RxtGetChildOfs(1, pNodeHdr)); + } +} + + +#if _DEBUG_PATH_CACHE + WFSKrnResult PathCacheDecreaseEntryOpenHandleCount(PathCacheItr *pPci, utf8 *sStr) { +#else + WFSKrnResult PathCacheDecreaseEntryOpenHandleCount(PathCacheItr *pPci) { +#endif + PathCacheEntry *pEntry = pPci->pEntry; + pPci->rxi.nEntryIdx = pEntry->ah.nEntryIdx+1; + RxtNodeHdr *pNodeHdr = pPci->rxi.pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + pEntry->ah.nParentOfs); + while(1) { +#if _DEBUG + if (pEntry->pcd.nOpenHandleCount == 0) { + WFSKrnOutputErrorStr("OpenHandleCount already 0!"); + } +#endif + --pEntry->pcd.nOpenHandleCount; + while(1) { + if (pNodeHdr->nParentOfs == 0) { + goto ExitLoop; + } + u32 nEntryIdx = pNodeHdr->nEntryIdx; + pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + pNodeHdr->nParentOfs); + utf8 *pStr = pNodeHdr->aFirstChar; + utf8 *pStrEnd = pStr + pNodeHdr->nStrLen; + if (pStrEnd[nEntryIdx] == '/') { + goto FoundSlash; + } + while(pStraFirstChar[pNodeHdr->nStrLen] != 0) { + if (pNodeHdr->nParentOfs == 0) { + goto ExitLoop; + } + pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + pNodeHdr->nParentOfs); + } + pEntry = (PathCacheEntry *)((u8*)wkg.pathCache.pRxtHdr + RxtGetChildOfs(1, pNodeHdr)); + } +ExitLoop: + pEntry = pPci->pEntry; +#if _DEBUG + if (pEntry->pcd.nPinCount == 0) { + WFSKrnOutputErrorStr("nPinCount already 0!"); + } +#endif + --pEntry->pcd.nPinCount; +#if _DEBUG_PATH_CACHE + --wkg.pathCache.nNumPinned; + MyOSReport("of:%2d + od:%2d - pc:%2d = %2d :: ", wkg.hnd.nNumUsedFileHandles, wkg.hnd.nNumUsedSearchDirHandles, wkg.pathCache.nNumPinned, + wkg.hnd.nNumUsedFileHandles + wkg.hnd.nNumUsedSearchDirHandles - wkg.pathCache.nNumPinned); + MyOSReport("%s <- %d\n", sStr, pEntry->pcd.nPinCount); +#endif + if (pEntry->pcd.nPinCount == 0) { +#if 0 + PathCacheDeleteEntry(pEntry); +#else + // Move to MRU list + pEntry->pcd.nFlags &=~PATH_CACHE_FLAG_OPEN_FOR_WRITE; + PathCacheDeleteLink(pEntry); + PathCacheInsertToEntryListAfterCursorEntry(wkg.pathCache.pMruAnchor, pEntry); +#endif + return WFSKRN_RESULT_OK; + } + return WFSKRN_RESULT_NOT_EMPTY; +} + + +void PathCacheInit() { + wkg.pathCache.pMruAnchor = (PathCacheEntry *)((u8*)&wkg.pathCache.mruAnchor - (size_t)&((PathCacheEntry *)0)->ml); + wkg.pathCache.pMruAnchor->ml.pNext = wkg.pathCache.pMruAnchor->ml.pPrev = wkg.pathCache.pMruAnchor; + wkg.pathCache.pPinAnchor = (PathCacheEntry *)((u8*)&wkg.pathCache.pinAnchor - (size_t)&((PathCacheEntry *)0)->ml); + wkg.pathCache.pPinAnchor->ml.pNext = wkg.pathCache.pPinAnchor->ml.pPrev = wkg.pathCache.pPinAnchor; + wkg.pathCache.pRxtHdr = (RxtHdr *)wkg.pathCache.aRxtBuf; + RxtInit(wkg.pathCache.pRxtHdr, WFS_LOG2_PATH_CACHE_SIZE); +} + + +#if (!_IOP && _DEBUG) + #include "randomlib.h" + void VolumeConvertU32ToVolId(WFSVolumeId *pVolId, u32 nVolId); + extern utf8 **aTestWords; + + void PathCacheTest() { + PathCacheDebugOutputList(wkg.pathCache.pMruAnchor, 'C'); + u32 nDev; + for(nDev=0; nDev<1000; ++nDev) { + utf8 sVolPath[WFS_MAX_DEVICE_NAME_SIZE + 50]; + u32 nVolId = ((RandomU32()%24) * 10000) + 5000; + WFSVolumeId volId; + VolumeConvertU32ToVolId(&volId, nVolId); + SNPRINTF(sVolPath, WFS_MAX_DEVICE_NAME_SIZE + 50,"vol/%s", aTestWords[nVolId]); + PathCacheInsertAfterCursorEntry2(wkg.pathCache.pMruAnchor, sVolPath)->pcd.pData = &nDev; + PathCacheDebugOutputList(wkg.pathCache.pMruAnchor, 'C'); + } + PathCacheDebugOutputList(wkg.pathCache.pMruAnchor, 'C'); + } +#endif + + +WFSKrnResult PathCacheParseNextName(WFSFileName *pName, const utf8 **ppSrc) { + const utf8 *pSrc = *ppSrc + 1; + utf8 *pDst = pName->sStr; + utf8 *pDstEnd = &pName->sStr[WFS_MAX_FILE_NAME_SIZE]; + while((*pSrc!='/')&&(*pSrc!=0)) { + if (pDst == pDstEnd) { + return WFSKRN_RESULT_INVALID; + } + *pDst++ = *pSrc++; + } + *pDst = 0; + *ppSrc = pSrc; + pName->nLen = pDst - pName->sStr; + if ((*pSrc=='/')&&(pSrc[1]!=0)) { + return WFSKRN_RESULT_OK; + } else { + return WFSKRN_RESULT_SRV_END_OF_PATH; + } +} + + +void PathCacheSetItrToVolumeRootArea(PathCacheItr *pPci, VolumeInfo *pVolInfo) { + pPci->di.tba.pAreaInfo = &pVolInfo->rootAreaInfo; + pPci->di.tba.nBlkAdr = pPci->di.tba.pAreaInfo->ah.nRootBlkAdr; + pPci->di.pAttrHdr = &pVolInfo->rootAttr; + pPci->di.ppDnsRootParent = 0; +} + + +WFSKrnResult PathCacheFindParentDir(const WFSPathName *pAbsPathName, utf8 *sLowerCaseStr, PathCacheItr *pPci) { + // This function searches for the parent directory of the input path name, and + // sets up the directory iterator to the top of this directory. + pPci->di.ppDnsRootParent = 0; + pPci->pNameEnd = pPci->rxi.pStrPtr = sLowerCaseStr; + WFSKrnResult nResult = PathCacheParseNextName(&pPci->di.name, &pPci->pNameEnd); + if (nResult == WFSKRN_RESULT_SRV_END_OF_PATH) { + // If we get here, it means the path had depth 1. (e.g. "/something") + PathCacheInitSlash(pPci); // to skip the root '/' + pPci->di.tba.pAreaInfo = 0; + nResult = WFSKRN_RESULT_SRV_PATH_DEPTH_1; + goto SetEntry; + } else if (nResult != WFSKRN_RESULT_OK) { + return nResult; + } + void *pRootData; + if (!PathCacheFind3(&pPci->rxi, pPci->pNameEnd - pPci->rxi.pStrPtr, &pRootData)) { + return WFSKRN_RESULT_NOT_FOUND; + } + // First name should be "/vol" or "/dev" + nResult = PathCacheParseNextName(&pPci->di.name, &pPci->pNameEnd); + if (nResult == WFSKRN_RESULT_SRV_END_OF_PATH) { + // The path was found in the path cache (e.g. "/vol" or "/dev") + pPci->di.tba.pAreaInfo = 0; + nResult = (WFSKrnResult)((u32)pRootData); + goto SetEntry; + } else if (nResult != WFSKRN_RESULT_OK) { + return nResult; + } + void *pData; + pPci->pEntry = PathCacheIncrementalFindEntry(&pPci->rxi, pPci->pNameEnd - pPci->rxi.pStrPtr, &pData); + if (pPci->pEntry) { + if (((DeviceInfo*)pData >= wkg.aDevInfo) && ((DeviceInfo*)pData < &wkg.aDevInfo[WFSKRN_MAX_DEVICES])) { + // Cannot directly access devices listed under /dev + //return WFSKRN_RESULT_PERMISSION; + // If we get here, the path included device name as directory. + return WFSKRN_RESULT_NOT_DIRECTORY; + } + if (((VolumeInfo*)pData >= wkg.aVolInfo) && ((VolumeInfo*)pData < &wkg.aVolInfo[WFSKRN_MAX_VOLUMES])) { + // Access the root directory of a volume + PathCacheSetItrToVolumeRootArea(pPci, (VolumeInfo*)pData); +#ifdef PERMISSION_ENABLED + pPci->pEntry->pcd.nAccessListIdx = pPci->di.pAttrHdr->nAccessListIdx; +#endif + // On this path, the condition "nResult == WFSKRN_RESULT_SRV_END_OF_PATH" could not be true + if (nResult == WFSKRN_RESULT_SRV_END_OF_PATH) { + // If we get here, the path was a volume root directory e.g. "/vol/abcdefg") + nResult = WFSKRN_RESULT_SRV_PATH_VOL_ROOT; + goto SetEntry; + } + else if(pPci->di.tba.pAreaInfo->pVolInfo->pDevInfo->nFlags & WFS_DEVFLAG_UNUSABLE) { + return WFSKRN_RESULT_DEV_UNUSABLE; + } + else if(pPci->di.tba.pAreaInfo->pVolInfo->pDevInfo->nFlags & WFS_DEVFLAG_WRITE_PROTECTED) { + return WFSKRN_RESULT_WRITE_PROTECTED; + } + else if(pPci->di.tba.pAreaInfo->pVolInfo->pDevInfo->nFlags & WFS_DEVFLAG_NOT_INITIALIZED) { + return WFSKRN_RESULT_DEV_NOT_INITIALIZED; + } + } else { + return WFSKRN_RESULT_NOT_FOUND; + } + } else { + return WFSKRN_RESULT_NOT_FOUND; + } + PathCacheEntry *pCursorEntry = wkg.pathCache.pMruAnchor; + // Now we are ready to start parsing normal directories within a volume + while(1) { + pPci->nRootBlkAdr = pPci->di.tba.nBlkAdr; + PathCacheParseNextName(&pPci->di.name, &pPci->pNameEnd); + if ((pPci->pNameEnd[0]!='/')||(pPci->pNameEnd[1]==0)) { + goto Done; + } + pPci->pEntry = PathCacheIncrementalInsertAfterCursorEntry(pCursorEntry, &pPci->rxi, pPci->rxi.pStrPtr - sLowerCaseStr, pPci->di.name.nLen+1); + if (pPci->pEntry == NULL) + { + return WFSKRN_RESULT_RESOURCE_LIMIT_EXCEEDED; + } + +#if PATH_CACHE_ENABLED + if (pPci->pEntry->pcd.pAreaInfo == 0) { +#endif + if (pPci->di.name.nLen==0) { + return WFSKRN_RESULT_INVALID; + } + nResult = DirFindRaw(&pPci->di); + if (nResult != WFSKRN_RESULT_OK) { + goto Exit; + } + if ((pPci->di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY)==0) { + nResult = WFSKRN_RESULT_NOT_DIRECTORY; + goto Exit; + } + pPci->pEntry->pcd.pAreaInfo = pPci->di.tba.pAreaInfo; + pPci->pEntry->pcd.nBlkAdr = pPci->di.pAttrHdr->dir.nSubDirBlkAdr; +#ifdef PERMISSION_ENABLED + pPci->pEntry->pcd.nAccessListIdx = pPci->di.pAttrHdr->nAccessListIdx; + pPci->pEntry->pcd.nObjCreator = pPci->di.pAttrHdr->nObjCreator; +#endif + DirItrClose(&pPci->di); + pPci->di.tba.nBlkAdr = pPci->pEntry->pcd.nBlkAdr; +#if PATH_CACHE_ENABLED + } else { + pPci->di.tba.pAreaInfo = pPci->pEntry->pcd.pAreaInfo; + pPci->di.tba.nBlkAdr = pPci->pEntry->pcd.nBlkAdr; + } +#endif + //pPci->rxi.pStrPtr = const_cast(pPci->pNameEnd); + pPci->rxi.pStrPtr = (utf8*)(pPci->pNameEnd); // IOP compiler + if (pPci->pEntry->pcd.nPinCount == 0) { + pCursorEntry = pPci->pEntry; + } + } +SetEntry: + pPci->pEntry = (PathCacheEntry *)((u8*)wkg.pathCache.pRxtHdr + RxtGetChildOfs(1, pPci->rxi.pNodeHdr)); +Done: + ++pPci->rxi.pStrPtr; + u32 nStrLen = pPci->pNameEnd - pPci->rxi.pStrPtr; + memcpy(pPci->di.name.sStr, pPci->rxi.pStrPtr, nStrLen); + pPci->pRawNameStart = pAbsPathName->sStr + (pPci->rxi.pStrPtr - sLowerCaseStr); + return nResult; +Exit: + DirItrClose(&pPci->di); + return nResult; +} + + +bool WFSKrnNameMatchesPattern(utf8 *sName, utf8 *sPattern); + + +WFSKrnResult PathCacheFindName(PathCacheItr *pPci) { + void *pData; + RxtItr oldRxi = pPci->rxi; + PathCacheEntry *pEntry = PathCacheIncrementalFindEntry(&pPci->rxi, pPci->pNameEnd - pPci->rxi.pStrPtr, &pData); + if (pEntry) { + pPci->pEntry = pEntry; + return WFSKRN_RESULT_OK; + } else { + pPci->rxi = oldRxi; + return WFSKRN_RESULT_NOT_FOUND; + } +} + + +WFSKrnResult PathCacheFindPath(const WFSPathName *pAbsPathName, utf8 *sLowerCaseStr, PathCacheItr *pPci) { + WFSKrnResult nResult = PathCacheFindParentDir(pAbsPathName, sLowerCaseStr, pPci); + void *pData; + switch(nResult) { + case WFSKRN_RESULT_OK: { + PathCacheFindName(pPci); + nResult = DirFindRaw(&pPci->di); + return nResult; + } + case WFSKRN_RESULT_SRV_PATH_DEPTH_1: { + //PathCacheInitSlash(pPci); + //pPci->di.tba.pAreaInfo = 0; + s32 nStrLen = pPci->pNameEnd - pPci->rxi.pStrPtr; + if (nStrLen == 0) { + nResult = WFSKRN_RESULT_OK; + pPci->di.pAttrHdr = &wkg.rootDirAttr; + break; + } + if (PathCacheIncrementalFindEntry(&pPci->rxi, nStrLen, &pData)) { + // The path was found in the path cache (e.g. "/vol" or "/dev") + nResult = (WFSKrnResult)((u32)pData); + if (nResult == WFSKRN_RESULT_SRV_PATH_DEV) { + pPci->di.pAttrHdr = &wkg.devDirAttr; + } else { + pPci->di.pAttrHdr = &wkg.volDirAttr; + } + nResult = WFSKRN_RESULT_OK; + break; + } + return WFSKRN_RESULT_NOT_FOUND; + } + case WFSKRN_RESULT_SRV_PATH_DEV: + nResult = PathCacheFindName(pPci); + if (nResult == WFSKRN_RESULT_OK) { + pPci->di.pAttrHdr = &wkg.devAttr; + } + break; + case WFSKRN_RESULT_SRV_PATH_VOL: + if (PathCacheIncrementalFindEntry(&pPci->rxi, pPci->pNameEnd - pPci->rxi.pStrPtr, &pData)) { + PathCacheSetItrToVolumeRootArea(pPci, (VolumeInfo*)pData); + nResult = WFSKRN_RESULT_OK; + break; + } + return WFSKRN_RESULT_NOT_FOUND; + case WFSKRN_RESULT_SRV_PATH_VOL_ROOT: + nResult = WFSKRN_RESULT_OK; + break; + default: + return nResult; + } + return nResult; +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission.cpp new file mode 100644 index 0000000..56f0d65 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission.cpp @@ -0,0 +1,1241 @@ +/*---------------------------------------------------------------------------* + Project: wfsKrn + File: wfsKrn_Permission.cpp - Functions for permissions. + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission.cpp,v $ + Revision 1.16 2008/12/08 04:15:52 ooizumi + Clean up GetInheritedEntry(). + + Revision 1.15 2008/12/05 04:09:27 ooizumi + Fixed a bug failed to update self entry. + + Revision 1.14 2008/12/04 00:49:24 ooizumi + Fixed. + + Revision 1.13 2008/11/19 05:05:59 ooizumi + Fixed. + + Revision 1.12 2008/11/04 06:35:15 ooizumi + Fixed a bug failed to check VolumeInfo specified as AreaInfo. + + Revision 1.11 2008/10/10 10:47:21 ooizumi + Fixed a bug. + + Revision 1.10 2008/10/10 04:24:37 ooizumi + Fixed a bug stacking in infinite loop when calculating everyone entry's creator's permission. + + Revision 1.9 2008/10/09 09:39:03 ooizumi + Fixed bugs. + - Failed to get parent directory's permissions. + - Changed a routine to decide whether to create acl entry or not. + + Revision 1.8 2008/10/09 04:11:16 ooizumi + Fixed build error. + + Revision 1.7 2008/10/09 03:33:15 ooizumi + Fixed several bugs. + - Failed to get/set permissions of volume root. + - A caller which has negative CL value have several permissions. + - Failed to create acl entry which has no permissions (0x00000000). + + Revision 1.6 2008/10/08 04:16:15 ooizumi + Fixed not to check CL when it is no need to update acl. + + Revision 1.5 2008/10/07 10:42:51 ooizumi + Supported inherited permissions without using pathcache. + + Revision 1.4 2008/07/31 23:59:19 ooizumi + Fixed permission of special directories.. + + Revision 1.3 2008/07/30 06:11:57 ooizumi + Implemented initial version of permission functions. + + Revision 1.2 2008/07/14 00:42:00 ueno + Commented out because the APIs in this file are obsolete. + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.22 2008/04/03 07:06:39 ueno + Fixed typos. + + Revision 1.20 2008/03/14 08:02:53 ueno + Revised API prefixes (WFS -> WFSKrn). + + Revision 1.19 2008/03/11 11:39:01 ueno + Cleanup. + + Revision 1.18 2008/03/11 11:10:47 ueno + Moved accesslist functions into wfskrn_Permission_AccessList.cpp. + + Revision 1.17 2008/03/11 09:51:54 ueno + Fixed EscapeAccessList() to make a filename from UTF-16 characters (0x3300-0x33ff). + + Revision 1.16 2008/03/11 06:53:05 ueno + Added WFSAccessListSetPermission() and GetPermission(). + + Revision 1.15 2008/03/07 05:43:59 ueno + Cleanup. + + Revision 1.14 2008/03/07 05:32:07 ueno + Modified WFSCreateAccessList() to be able to create an accesslist for directories. + + Revision 1.13 2008/03/06 12:25:27 ueno + Revised cache freelist (signgle -> double link list). + + Revision 1.12 2008/03/06 11:01:38 ueno + Fixed asserts. + + Revision 1.11 2008/03/06 10:45:44 ueno + Revised accesslist cache. + + Revision 1.10 2008/02/29 07:29:10 ueno + Added Windows api wrappers. + + Revision 1.9 2008/02/29 00:48:05 ueno + Changed the attribute of index to inout (WFSAccessListAddEntry() and RemoveEntry()). + + Revision 1.8 2008/02/28 13:11:01 ueno + Revised to keep accesslist cache and indexlist handle in WFSAreaHdr{}. + + Revision 1.7 2008/02/28 07:01:52 ueno + Fixed escape sequence for accesslist filename. + + Revision 1.6 2008/02/28 04:36:32 ueno + Cleanup. + + Revision 1.5 2008/02/27 10:05:36 ueno + Revised to use WFSAreaHdr{} to specifiy WFS area. + + Revision 1.4 2008/02/27 04:29:24 ueno + Modified WFSAccessListAddEntry() and RemoveEntry() to delete accesslist file when the reference count is zero. + + Revision 1.3 2008/02/26 14:11:43 ueno + Added WFSAccessListAddEntry() and WFSAccessListRemoveEntry() to edit accesslist. + + Revision 1.2 2008/02/25 09:43:57 ueno + Added support for accesslist cache. + + Revision 1.1 2008/02/22 05:16:13 ueno + Initial Check-in. + + +*---------------------------------------------------------------------------*/ +#include "wfskrn_Config.h" + +#ifdef PERMISSION_ENABLED + +#include "wfskrn_Api.h" +#include "wfskrn_DirRxTree.h" +#include "wfskrn_PathCache.h" + +#include "wfskrn_Permission.h" +#include "wfskrn_Permission_AccessList.h" + +/*---------------------------------------------------------------------------* + Name: BacktrackToSlash + + Description: Backtrack radix tree iterator to slash. + + Arguments: pRxi Radix tree iterator + + Returns: Result of operation. + *---------------------------------------------------------------------------*/ +static WFSKrnResult BacktrackToSlash(RxtItr *pRxi) +{ + RxtNodeHdr *pNodeHdr = pRxi->pNodeHdr; + u32 nDepth = 0; + u16 nLen = 0; + while (1) + { + if (pNodeHdr->nParentOfs == 0) + { + // If we get here, it means the path had depth 1. (e.g. "/something") + return WFSKRN_RESULT_SRV_PATH_DEPTH_1; + } + // Searching parent node until '/' is found. + ++nDepth; + nLen += pNodeHdr->nStrLen + 1; + u32 nEntryIdx = pNodeHdr->nEntryIdx; + pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + pNodeHdr->nParentOfs); + utf8 *pStr = pNodeHdr->aFirstChar; + utf8 *pStrEnd = pStr + pNodeHdr->nStrLen; + if (pStrEnd[nEntryIdx] == '/') + { + break; + } + } + if (!*(pRxi->pStrPtr)) + { + --nLen; + } + + pRxi->pNodeHdr = pNodeHdr; + pRxi->pStrPtr -= nLen; + pRxi->pNodeStrPtr = &pNodeHdr->aFirstChar[pNodeHdr->nStrLen]; + pRxi->nEntryIdx = pNodeHdr->nEntryIdx; + pRxi->nDepth -= nDepth; + + pNodeHdr = (RxtNodeHdr *)((u8*)wkg.pathCache.pRxtHdr + pNodeHdr->nParentOfs); + pRxi->pOfs = RxtGetChildOfsPtr(pRxi->nEntryIdx + 1, pNodeHdr); + + return WFSKRN_RESULT_OK; +} + +/*---------------------------------------------------------------------------* + Name: GetParentPathCacheEntry + + Description: Get parent path cache entry. + + Arguments: pEntry Path cache entry + pRxi Radix tree iterator + + Returns: Parent entry. If failed, returns NULL. + *---------------------------------------------------------------------------*/ +static PathCacheEntry *GetParentPathCacheEntry(PathCacheEntry *pEntry, RxtItr *pRxi) +{ + if (*pRxi->pStrPtr || (BacktrackToSlash(pRxi) == WFSKRN_RESULT_OK)) + { + PathCacheEntry *entry = (PathCacheEntry *)((u8*)wkg.pathCache.pRxtHdr + RxtGetChildOfs(1, pRxi->pNodeHdr)); + BacktrackToSlash(pRxi); + return entry; + } + return 0; +} + +// Control level converting functions +static inline s32 GetRelCL(u32 perm) +{ + switch (perm & WFS_PERM_CL_MASK) + { + case WFS_PERM_CL_MINUS_0: return 0; + case WFS_PERM_CL_MINUS_1: return -1; + case WFS_PERM_CL_MINUS_2: return -2; + case WFS_PERM_CL_MINUS_3: return -3; + default: return 1; + } +} +static inline s32 GetAbsCL(u32 perm) +{ + switch (perm & WFS_PERM_CL_MASK) + { + case WFS_PERM_CL_0: return 0; + case WFS_PERM_CL_1: return 1; + case WFS_PERM_CL_2: return 2; + case WFS_PERM_CL_3: return 3; + default: return -1; + } +} +static inline u32 GetAbsCLFlag(s32 abs) +{ + switch (abs) + { + case 0: return WFS_PERM_CL_0; + case 1: return WFS_PERM_CL_1; + case 2: return WFS_PERM_CL_2; + case 3: return WFS_PERM_CL_3; + default: return 0; + } +} + +static inline u32 GetRelCLFlag(s32 rel) +{ + switch (rel) + { + case 0: return WFS_PERM_CL_MINUS_0; + case -1: return WFS_PERM_CL_MINUS_1; + case -2: return WFS_PERM_CL_MINUS_2; + case -3: return WFS_PERM_CL_MINUS_3; + default: return 0; + } +} + +/*---------------------------------------------------------------------------* + Name: GetAclEntries + + Description: Get acl entries for specified title. Title entry, self entry + and everyone entry. + + Arguments: pAreaInfo Pointer to AreaInfo + nAccessListIdx Access list handle + nTitleId Key title id + + pTitleEntry Pointer to WFSAccessListEntry buffer to + pSelfEntry store entry informations + pEveryoneEntry + + Returns: If failed, returns error code from WFSKrnGetAccessList. + *---------------------------------------------------------------------------*/ +static WFSKrnResult GetAclEntries(const AreaInfo* pAreaInfo, WFSKrnAclHandle nAccessListIdx, WFSTitleId nTitleId, + WFSAccessListEntry* pTitleEntry, WFSAccessListEntry* pSelfEntry, WFSAccessListEntry* pEveryoneEntry) +{ + // to get access list entry + WFSAccessListEntry aAclEntry[ACL_MAX_ENTRIES]; // 12*12=144 + s32 num; + + WFSKRN_PERM_ASSERT(pTitleEntry); + WFSKRN_PERM_ASSERT(pSelfEntry); + WFSKRN_PERM_ASSERT(pEveryoneEntry); + + num = (WFSKrnResult)WFSKrnGetAccessList(pAreaInfo, nAccessListIdx, aAclEntry, ACL_MAX_ENTRIES); + if (num < 0) + { + return (WFSKrnResult)num; + } + while (num) + { + if (aAclEntry[num-1].titleId == nTitleId) + { + if (aAclEntry[num-1].titleId == aAclEntry[num-1].entryCreatorId) + { + pSelfEntry->titleId = aAclEntry[num-1].titleId; + pSelfEntry->entryCreatorId = aAclEntry[num-1].entryCreatorId; + pSelfEntry->permissions = aAclEntry[num-1].permissions; + } + else + { + pTitleEntry->titleId = aAclEntry[num-1].titleId; + pTitleEntry->entryCreatorId = aAclEntry[num-1].entryCreatorId; + pTitleEntry->permissions = aAclEntry[num-1].permissions; + } + } + if (aAclEntry[num-1].titleId == WFS_EVERYONE_ID) + { + pEveryoneEntry->titleId = aAclEntry[num-1].titleId; + pEveryoneEntry->entryCreatorId = aAclEntry[num-1].entryCreatorId; + pEveryoneEntry->permissions = aAclEntry[num-1].permissions; + } + num--; + } + return WFSKRN_RESULT_OK; +} + +/*---------------------------------------------------------------------------* + Name: UpdateParentPermForChild + + Description: Update parent permissions for child entry by calculating + object creator's privilege and WFS_PERM_DELETE_OR_MOVE. + + Arguments: nFlags Flags from parent entry + bDir Directory or not + bCreator Object creator's privilege is enabled or not + + Returns: Updated nFlags value. + *---------------------------------------------------------------------------*/ +static u32 UpdateParentPermForChild(u32 nFlags, BOOL bDir, BOOL bCreator) +{ + if (bDir) + { + if (nFlags & WFS_PERM_ADD_OR_DELETE_SUBDIR) + { + if (bCreator) + { + nFlags |= WFS_PERM_DIR_FULL; + } + } + else + { + nFlags &= ~WFS_PERM_DELETE_OR_MOVE; + } + } + else + { + if (nFlags & WFS_PERM_ADD_OR_DELETE_FILE) + { + if (bCreator) + { + nFlags |= WFS_PERM_FILE_FULL; + } + } + else + { + nFlags &= ~WFS_PERM_DELETE_OR_MOVE; + } + } + return nFlags; +} + +/*---------------------------------------------------------------------------* + Name: CalcPermissions + + Description: Calculate permissions from base flags and entry permissions. + + Arguments: nFlags Base flags + nPermissions Affected entry's permissions + + Returns: Updated flags value. + *---------------------------------------------------------------------------*/ +static u32 CalcPermissions(u32 nFlags, u32 nPermissions) +{ + if (((s32)GetAbsCL(nFlags) + GetRelCL(nPermissions)) < 0) + { + // if CL is a negative value, title have no permission. + nFlags = 0; + } + else + { + nFlags = + GetAbsCLFlag(GetAbsCL(nFlags) + GetRelCL(nPermissions)) | + ((nPermissions & ~WFS_PERM_CL_MASK) & (nFlags & ~WFS_PERM_CL_MASK)); + } + return nFlags; +} + + +#define IS_ENTRY_AVAILABLE(entry) ((entry)->titleId != 0) +#define IS_SPECIAL_DIR(area) ((area) == (void*)0 || \ + (area) == (void*)WFSKRN_RESULT_SRV_PATH_DEV || \ + (area) == (void*)WFSKRN_RESULT_SRV_PATH_VOL) + +/*---------------------------------------------------------------------------* + Name: GetInheritedEntry + + Description: Get inherited acl entry. + + Arguments: pEntry Path cache entry + pRxi Radix tree iterator + pAreaInfo Area info + nAccessListIdx Access list handle + nObjCreator Object creator's title id + pPerm Specified target title id + self Enable self entry or not + everyone Enable everyone entry or not + + Returns: WFSKrnResult code. + *---------------------------------------------------------------------------*/ +static WFSKrnResult GetInheritedEntry(PathCacheEntry *pEntry, RxtItr *pRxi, + AreaInfo* pAreaInfo, u32 nAccessListIdx, WFSTitleId nObjCreator, + PathCachePerm* pPerm, + BOOL self, BOOL everyone) +{ + WFSKrnResult nResult = WFSKRN_RESULT_OK; // 4 + RxtItr rxi; // 24 + + WFSTitleId titleId; // 4 + + PathCachePerm entryCreatorPerm; // 16 + PathCachePerm parentPerm; // 16 + PathCachePerm everyonePerm; // 16 + + PathCacheEntry* pParentEntry; // 4 + AreaInfo* pParentAreaInfo; // 4 + + titleId = pPerm->nTitleId; + + // root has full permission. + if (titleId == WFS_ROOT_ID) + { + pPerm->nFlags = WFS_PERM_CL_3 | WFS_PERM_DIR_FULL | WFS_PERM_FILE_FULL; + pPerm->nEntryCreatorId = WFS_ROOT_ID; + pPerm->nEntryCreatorCl = 3; + nResult = WFSKRN_RESULT_OK; + goto Exit; + } + + // permissions for special dirs. + if (IS_SPECIAL_DIR(pAreaInfo)) + { + pPerm->nFlags = WFS_PERM_LIST; + pPerm->nEntryCreatorId = WFS_ROOT_ID; + pPerm->nEntryCreatorCl = 0; + nResult = WFSKRN_RESULT_OK; + goto Exit; + } + + memcpy(&rxi, pRxi, sizeof(RxtItr)); + + // to get access list entry + WFSAccessListEntry titleEntry; // 12 + WFSAccessListEntry selfEntry; // 12 + WFSAccessListEntry everyoneEntry; // 12 + titleEntry.titleId = 0; + selfEntry.titleId = 0; + everyoneEntry.titleId = 0; + + nResult = GetAclEntries(pAreaInfo, nAccessListIdx, titleId, + &titleEntry, &selfEntry, &everyoneEntry); + if (nResult < 0) + { + goto Exit; + } + + if (!self) + { + selfEntry.titleId = 0; + } + + // get title's inherited entry at parent dir + pParentEntry = GetParentPathCacheEntry(pEntry, &rxi); + // if no parent entry is there, it doesn't reach heare. + WFSKRN_PERM_ASSERT(pParentEntry); + + pParentAreaInfo = pParentEntry->pcd.pAreaInfo; + if (!pParentEntry->pcd.nBlkAdr) + { + // Special directory has no nBlkAdr in PathCache + void *pData = pParentEntry->pcd.pData; + if (((VolumeInfo*)pData >= wkg.aVolInfo) && ((VolumeInfo*)pData < &wkg.aVolInfo[WFSKRN_MAX_VOLUMES]) && + !(((u32)pData - (u32)wkg.aVolInfo) % sizeof(VolumeInfo))) + { + // Access the root directory of a volume + pParentAreaInfo = &((VolumeInfo*)pParentAreaInfo)->rootAreaInfo; + } + // ToDo: To handle error. + } + parentPerm.nTitleId = titleId; + if (IS_SPECIAL_DIR(pParentAreaInfo)) + { + parentPerm.nFlags = 0; + parentPerm.nEntryCreatorId = WFS_ROOT_ID; + parentPerm.nEntryCreatorCl = 0; + } + else + { + nResult = GetInheritedEntry(pParentEntry, &rxi, + pParentAreaInfo, pParentEntry->pcd.nAccessListIdx, pParentEntry->pcd.nObjCreator, + &parentPerm, + TRUE, TRUE); + if (nResult < 0) + { + goto Exit; + } + } + + // update parent entry permissions for child, + // by calculating object creator's privilege and WFS_PERM_DELETE_OR_MOVE + parentPerm.nFlags = UpdateParentPermForChild(parentPerm.nFlags, + (nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY), + (nObjCreator == titleId)); + + // There are 4 patterns. + // - No entry. + // - Title entry only. + // - Title entry and self entry. + // - Self entry only. + if (!IS_ENTRY_AVAILABLE(&titleEntry) && !IS_ENTRY_AVAILABLE(&selfEntry)) + { + // Inherit parent permissions + pPerm->nFlags = parentPerm.nFlags; + pPerm->nEntryCreatorId = parentPerm.nEntryCreatorId; + pPerm->nEntryCreatorCl = parentPerm.nEntryCreatorCl; + } + else if (IS_ENTRY_AVAILABLE(&titleEntry) && !IS_ENTRY_AVAILABLE(&selfEntry)) + { + // To get entry creator's permissions + entryCreatorPerm.nTitleId = titleEntry.entryCreatorId; + nResult = GetInheritedEntry(pEntry, pRxi, + pAreaInfo, nAccessListIdx, nObjCreator, + &entryCreatorPerm, + TRUE, + IS_ENTRY_AVAILABLE(&everyoneEntry) ? (everyoneEntry.entryCreatorId != titleId) : TRUE); + + // To compare entry creator's CL with parent inherited entry creator's CL. + WFSKRN_PERM_REPORT("Entry Creator %d <-> Parent %d\n", GetAbsCL(entryCreatorPerm.nFlags), parentPerm.nEntryCreatorCl); + if (GetAbsCL(entryCreatorPerm.nFlags) < parentPerm.nEntryCreatorCl) + { + pPerm->nFlags = parentPerm.nFlags; + pPerm->nEntryCreatorId = parentPerm.nEntryCreatorId; + pPerm->nEntryCreatorCl = parentPerm.nEntryCreatorCl; + } + else + { + // At first, calculate title entry's inherited vaues. + WFSKRN_PERM_REPORT("Entry Creator %d, Title Entry RelCL %d\n", GetAbsCL(entryCreatorPerm.nFlags), GetRelCL(titleEntry.permissions)); + pPerm->nFlags = CalcPermissions(entryCreatorPerm.nFlags, titleEntry.permissions); + pPerm->nEntryCreatorId = titleEntry.entryCreatorId; + pPerm->nEntryCreatorCl = GetAbsCL(entryCreatorPerm.nFlags); + } + } + else if (IS_ENTRY_AVAILABLE(&titleEntry) && IS_ENTRY_AVAILABLE(&selfEntry)) + { + // To get entry creator's permissions + entryCreatorPerm.nTitleId = titleEntry.entryCreatorId; + nResult = GetInheritedEntry(pEntry, pRxi, + pAreaInfo, nAccessListIdx, nObjCreator, + &entryCreatorPerm, + TRUE, + IS_ENTRY_AVAILABLE(&everyoneEntry) ? (everyoneEntry.entryCreatorId != titleId) : TRUE); + + // To compare entry creator's CL with parent inherited entry creator's CL. + WFSKRN_PERM_REPORT("Entry Creator %d <-> Parent %d\n", GetAbsCL(entryCreatorPerm.nFlags), parentPerm.nEntryCreatorCl); + if (GetAbsCL(entryCreatorPerm.nFlags) < parentPerm.nEntryCreatorCl) + { + WFSKRN_PERM_REPORT("Entry Creator %d, Self Entry RelCL %d\n", GetAbsCL(parentPerm.nFlags), GetRelCL(selfEntry.permissions)); + pPerm->nFlags = CalcPermissions(parentPerm.nFlags, selfEntry.permissions); + pPerm->nEntryCreatorId = parentPerm.nEntryCreatorId; + pPerm->nEntryCreatorCl = parentPerm.nEntryCreatorCl; + } + else + { + // At first, calculate title entry's inherited vaues. + WFSKRN_PERM_REPORT("Entry Creator %d, Title Entry RelCL %d\n", GetAbsCL(entryCreatorPerm.nFlags), GetRelCL(titleEntry.permissions)); + pPerm->nFlags = CalcPermissions(entryCreatorPerm.nFlags, titleEntry.permissions); + // Next, calculate self entry. + WFSKRN_PERM_REPORT("Entry Creator %d, Self Entry RelCL %d\n", GetAbsCL(pPerm->nFlags), GetRelCL(selfEntry.permissions)); + pPerm->nFlags = CalcPermissions(pPerm->nFlags, selfEntry.permissions); + + pPerm->nEntryCreatorId = parentPerm.nEntryCreatorId; + pPerm->nEntryCreatorCl = parentPerm.nEntryCreatorCl; + } + } + else // == if (!IS_ENTRY_AVAILABLE(&titleEntry) && IS_ENTRY_AVAILABLE(&selfEntry)) + { + WFSKRN_PERM_REPORT("Entry Creator %d, Self Entry RelCL %d\n", GetAbsCL(parentPerm.nFlags), GetRelCL(selfEntry.permissions)); + pPerm->nFlags = CalcPermissions(parentPerm.nFlags, selfEntry.permissions); + pPerm->nEntryCreatorId = parentPerm.nEntryCreatorId; + pPerm->nEntryCreatorCl = parentPerm.nEntryCreatorCl; + } + + // Skip to calculate everyone's permission at several situations. + if (!everyone) + { + // Skip when specified from caller. + goto Exit; + } + if (WFS_EVERYONE_ID == titleId) + { + // Skip when calculate itself. + goto Exit; + } + if (IS_ENTRY_AVAILABLE(&everyoneEntry) && everyoneEntry.entryCreatorId == titleId) + { + // Skip when calculate everyone entry's creator's permission. + goto Exit; + } + + // to get everyone permissions. + everyonePerm.nTitleId = WFS_EVERYONE_ID; + nResult = GetInheritedEntry(pEntry, pRxi, + pAreaInfo, nAccessListIdx, nObjCreator, + &everyonePerm, + TRUE, TRUE); + + // To compare everyone entry creator's CL with current selected entry creator's CL. + WFSKRN_PERM_REPORT("Everyone %d <-> Inherited %d\n", everyonePerm.nEntryCreatorCl, pPerm->nEntryCreatorCl); + if (everyonePerm.nEntryCreatorCl < pPerm->nEntryCreatorCl) + { + // Everyone entry is disabled. No operation is needed. + } + else if (everyonePerm.nEntryCreatorCl == pPerm->nEntryCreatorCl) + { + // It is need to OR. + pPerm->nFlags |= (everyonePerm.nFlags & ~WFS_PERM_CL_MASK); + } + else + { + // To use everyone entry. + pPerm->nTitleId = WFS_EVERYONE_ID; + pPerm->nFlags = everyonePerm.nFlags; + pPerm->nEntryCreatorId = everyonePerm.nEntryCreatorId; + pPerm->nEntryCreatorCl = everyonePerm.nEntryCreatorCl; + } + +Exit: + // To mask + if (nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) + { + pPerm->nFlags &= (WFS_PERM_CL_MASK | WFS_PERM_DIR_FULL); + } + else + { + pPerm->nFlags &= (WFS_PERM_CL_MASK | WFS_PERM_FILE_FULL); + } + WFSKRN_PERM_REPORT("%02d:%08X(%d)->%08X %08X\n", pRxi->nDepth, pPerm->nEntryCreatorId, pPerm->nEntryCreatorCl, pPerm->nTitleId, pPerm->nFlags); + return nResult; +} + +WFSKrnResult WFSKrnGetInheritedPermissionForUserDi(PathCacheItr* pPci, u32* pFlags, WFSTitleId titleId) +{ + WFSKrnResult nResult = WFSKRN_RESULT_OK; + + AreaInfo* pAreaInfo; + u32 nAccessListIdx; + u32 nObjCreator; + if (pPci->di.pAttrHdr == &wkg.rootDirAttr || // / + pPci->di.pAttrHdr == &wkg.devDirAttr || // /dev + pPci->di.pAttrHdr == &wkg.volDirAttr) // /vol + { + *pFlags = WFS_PERM_LIST; + nResult = WFSKRN_RESULT_OK; + goto Exit; + } + if (!pPci->di.tba.pAreaInfo) + { + // volume root + if (titleId == WFS_ROOT_ID) + { + *pFlags = WFS_PERM_FULL; + nResult = WFSKRN_RESULT_OK; + } + else + { + *pFlags = 0; + nResult = WFSKRN_RESULT_OK; + } + goto Exit; + } + pAreaInfo = pPci->di.tba.pAreaInfo; + nAccessListIdx = pPci->di.pAttrHdr->nAccessListIdx; + nObjCreator = pPci->di.pAttrHdr->nObjCreator; + + WFSKRN_PERM_REPORT("access list 0x%08X.\n", nAccessListIdx); + + PathCachePerm perm; + perm.nTitleId = titleId; + GetInheritedEntry(pPci->pEntry, &pPci->rxi, + pAreaInfo, nAccessListIdx, nObjCreator, + &perm, + TRUE, TRUE); + nResult = WFSKRN_RESULT_OK; + *pFlags = perm.nFlags; + WFSKRN_PERM_REPORT("get di %08X(%d)->%08X %08X.\n", perm.nEntryCreatorId, perm.nEntryCreatorCl, titleId, *pFlags); + nResult = WFSKRN_RESULT_OK; +Exit: + // ToDo: remapping error code? + return nResult; +} + +WFSKrnResult WFSKrnGetInheritedPermissionForUserPci(PathCacheItr* pPci, u32* pFlags, WFSTitleId titleId) +{ + WFSKrnResult nResult = WFSKRN_RESULT_OK; + + AreaInfo* pAreaInfo; + u32 nAccessListIdx; + u32 nObjCreator; + //WFSKRN_PERM_REPORT("pEntry 0x%08X.\n", pPci->pEntry); + if (pPci->pEntry->pcd.pData == (void*)0 || // / + pPci->pEntry->pcd.pData == (void*)WFSKRN_RESULT_SRV_PATH_DEV || // /dev + pPci->pEntry->pcd.pData == (void*)WFSKRN_RESULT_SRV_PATH_VOL) // /vol + { + *pFlags = WFS_PERM_LIST; + nResult = WFSKRN_RESULT_OK; + goto Exit; + } + pAreaInfo = pPci->pEntry->pcd.pAreaInfo; + if (!pPci->pEntry->pcd.nBlkAdr) + { + // Special directory has no nBlkAdr in PathCache + void *pData = pPci->pEntry->pcd.pData; + if (((VolumeInfo*)pData >= wkg.aVolInfo) && ((VolumeInfo*)pData < &wkg.aVolInfo[WFSKRN_MAX_VOLUMES]) && + !(((u32)pData - (u32)wkg.aVolInfo) % sizeof(VolumeInfo))) + { + // Access the root directory of a volume + pAreaInfo = &((VolumeInfo*)pAreaInfo)->rootAreaInfo; + } + } + nAccessListIdx = pPci->pEntry->pcd.nAccessListIdx; + nObjCreator = pPci->pEntry->pcd.nObjCreator; + + WFSKRN_PERM_REPORT("access list 0x%08X.\n", nAccessListIdx); + + RxtItr rxi; + memcpy(&rxi, &pPci->rxi, sizeof(RxtItr)); + BacktrackToSlash(&rxi); + + PathCachePerm perm; + perm.nTitleId = titleId; + GetInheritedEntry(pPci->pEntry, &rxi, + pAreaInfo, nAccessListIdx, nObjCreator, + &perm, + TRUE, TRUE); + nResult = WFSKRN_RESULT_OK; + *pFlags = perm.nFlags; + WFSKRN_PERM_REPORT("get pci %08X(%d)->%08X %08X.\n", perm.nEntryCreatorId, perm.nEntryCreatorCl, titleId, *pFlags); + nResult = WFSKRN_RESULT_OK; +Exit: + // ToDo: remapping error code? + return nResult; +} + +WFSKrnResult WFSKrnGetParentInheritedPermissionForUserPci(PathCacheItr* pPci, u32* pFlags, WFSTitleId titleId) +{ + WFSKrnResult nResult = WFSKRN_RESULT_OK; + + RxtItr parentRxi; + memcpy(&parentRxi, &pPci->rxi, sizeof(RxtItr)); + PathCacheEntry* pParentEntry = GetParentPathCacheEntry(pPci->pEntry, &parentRxi); + + WFSKRN_PERM_REPORT("parent pEntry 0x%08X.\n", pParentEntry); + AreaInfo* pAreaInfo; + u32 nAccessListIdx; + u32 nObjCreator; + if (pParentEntry->pcd.pData == (void*)0 || // / + pParentEntry->pcd.pData == (void*)WFSKRN_RESULT_SRV_PATH_DEV || // /dev + pParentEntry->pcd.pData == (void*)WFSKRN_RESULT_SRV_PATH_VOL) // /vol + { + *pFlags = WFS_PERM_LIST; + nResult = WFSKRN_RESULT_OK; + goto Exit; + } + + pAreaInfo = pParentEntry->pcd.pAreaInfo; + if (!pParentEntry->pcd.nBlkAdr) + { + // Special directory has no nBlkAdr in PathCache + void *pData = pParentEntry->pcd.pData; + if (((VolumeInfo*)pData >= wkg.aVolInfo) && ((VolumeInfo*)pData < &wkg.aVolInfo[WFSKRN_MAX_VOLUMES]) && + !(((u32)pData - (u32)wkg.aVolInfo) % sizeof(VolumeInfo))) + { + // Access the root directory of a volume + pAreaInfo = &((VolumeInfo*)pAreaInfo)->rootAreaInfo; + } + } + nAccessListIdx = pParentEntry->pcd.nAccessListIdx; + nObjCreator = pParentEntry->pcd.nObjCreator; + + WFSKRN_PERM_REPORT("parent access list 0x%08X.\n", nAccessListIdx); + + PathCachePerm perm; + perm.nTitleId = titleId; + GetInheritedEntry(pParentEntry, &parentRxi, + pAreaInfo, nAccessListIdx, nObjCreator, + &perm, + TRUE, TRUE); + nResult = WFSKRN_RESULT_OK; + *pFlags = perm.nFlags; + WFSKRN_PERM_REPORT("parent :%08X(%d)->%08X %08X.\n", perm.nEntryCreatorId, perm.nEntryCreatorCl, titleId, *pFlags); + +Exit: + // ToDo: remapping error code? + return nResult; +} + +WFSKrnResult WFSKrnSetInheritedPermissionForUser(PathCacheItr* pPci, u32 nFlags, u32 nMask, WFSTitleId entryCreatorId, WFSTitleId titleId) +{ + WFSKrnResult nResult = WFSKRN_RESULT_OK; + u32 mask; + + WFSKRN_PERM_REPORT("WFSKrnSetInheritedPermissionForUser start\n"); + + mask = nMask & ((pPci->di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) ? (WFS_PERM_CL_MASK | WFS_PERM_DIR_FULL) : (WFS_PERM_CL_MASK | WFS_PERM_FILE_FULL)); + + if (titleId == WFS_ROOT_ID) + { + if (entryCreatorId != WFS_ROOT_ID) + { + // invalid + nResult = WFSKRN_RESULT_PERMISSION; // INVALID? + } + if (((nFlags & mask) & WFS_PERM_CL_MASK) == 0 && ((nFlags & mask) & WFS_PERM_CL_3) == 0 && ((nFlags & mask) & WFS_PERM_CL_MINUS_0) == 0 ) + { + nResult = WFSKRN_RESULT_PERMISSION; + } + if ((WFS_PERM_FULL & mask & ~WFS_PERM_CL_MASK) != (nFlags & mask & ~WFS_PERM_CL_MASK)) + { + nResult = WFSKRN_RESULT_PERMISSION; + } + goto Exit; + } + + // to get access list entry + WFSAccessListEntry aAclEntry[ACL_MAX_ENTRIES]; // 12*12=144 + WFSAccessListEntry* pTitleEntry = NULL; + WFSAccessListEntry* pSelfEntry = NULL; + WFSAccessListEntry* pEveryoneEntry = NULL; + + nResult = (WFSKrnResult)WFSKrnGetAccessList(pPci->di.tba.pAreaInfo, pPci->di.pAttrHdr->nAccessListIdx, aAclEntry, ACL_MAX_ENTRIES); + if (nResult < 0) + { + goto Exit; + } + while (nResult) + { + if (aAclEntry[nResult-1].titleId == titleId) + { + if (aAclEntry[nResult-1].titleId == aAclEntry[nResult-1].entryCreatorId) + pSelfEntry = &aAclEntry[nResult-1]; + else + pTitleEntry = &aAclEntry[nResult-1]; + } + if (aAclEntry[nResult-1].titleId == WFS_EVERYONE_ID) + { + pEveryoneEntry = &aAclEntry[nResult-1]; + } + nResult = (WFSKrnResult)((s32)nResult - 1); + } + + AreaInfo* pAreaInfo; + + u32 newFlags; + RxtItr parentRxi; + PathCacheEntry* pParentEntry; + AreaInfo* pParentAreaInfo; + + PathCachePerm entryCreatorPerm; + PathCachePerm titleCreatorPerm; + PathCachePerm everyonePerm; + PathCachePerm parentPerm; + PathCachePerm currentPerm; + + memcpy(&parentRxi, &pPci->rxi, sizeof(RxtItr)); + pParentEntry = GetParentPathCacheEntry(pPci->pEntry, &parentRxi); + + if (pPci->di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) + { + pAreaInfo = pPci->di.tba.pAreaInfo; + } + else + { + pAreaInfo = pParentEntry->pcd.pAreaInfo; + } + + if (((VolumeInfo*)pAreaInfo >= wkg.aVolInfo) && ((VolumeInfo*)pAreaInfo < &wkg.aVolInfo[WFSKRN_MAX_VOLUMES]) && + !(((u32)pAreaInfo - (u32)wkg.aVolInfo) % sizeof(VolumeInfo))) + { + // Access the root directory of a volume + pAreaInfo = &((VolumeInfo*)pAreaInfo)->rootAreaInfo; + } + + entryCreatorPerm.nTitleId = entryCreatorId; + GetInheritedEntry(pPci->pEntry, &pPci->rxi, + pAreaInfo, pPci->di.pAttrHdr->nAccessListIdx, pPci->di.pAttrHdr->nObjCreator, + &entryCreatorPerm, + (entryCreatorId == titleId) ? FALSE : TRUE, TRUE); + WFSKRN_PERM_REPORT("creator:%08X(%d)->%08X %08X %08X.\n", + entryCreatorPerm.nEntryCreatorId, entryCreatorPerm.nEntryCreatorCl, + entryCreatorPerm.nTitleId, entryCreatorPerm.nFlags, + pPci->di.pAttrHdr->nAccessListIdx); + + pParentAreaInfo = pParentEntry->pcd.pAreaInfo; + if (!pParentEntry->pcd.nBlkAdr) + { + // Special directory has no nBlkAdr in PathCache + void *pData = pParentEntry->pcd.pData; + if (((VolumeInfo*)pData >= wkg.aVolInfo) && ((VolumeInfo*)pData < &wkg.aVolInfo[WFSKRN_MAX_VOLUMES]) && + !(((u32)pData - (u32)wkg.aVolInfo) % sizeof(VolumeInfo))) + { + // Access the root directory of a volume + pParentAreaInfo = &((VolumeInfo*)pParentAreaInfo)->rootAreaInfo; + } + } + parentPerm.nTitleId = titleId; + if (pParentAreaInfo == (void*)WFSKRN_RESULT_SRV_PATH_DEV || // /dev + pParentAreaInfo == (void*)WFSKRN_RESULT_SRV_PATH_VOL) // /vol + { + parentPerm.nFlags = 0; + parentPerm.nEntryCreatorId = WFS_ROOT_ID; + parentPerm.nEntryCreatorCl = 0; + nResult = WFSKRN_RESULT_OK; + } + else + { + GetInheritedEntry(pParentEntry, &parentRxi, + pParentAreaInfo, pParentEntry->pcd.nAccessListIdx, pParentEntry->pcd.nObjCreator, + &parentPerm, + TRUE, TRUE); + } + WFSKRN_PERM_REPORT("parent :%08X(%d)->%08X %08X %08X.\n", + parentPerm.nEntryCreatorId, parentPerm.nEntryCreatorCl, + parentPerm.nTitleId, parentPerm.nFlags, + pParentEntry->pcd.nAccessListIdx); + + if (pTitleEntry) + { + titleCreatorPerm.nTitleId = pTitleEntry->entryCreatorId; + GetInheritedEntry(pPci->pEntry, &pPci->rxi, + pAreaInfo, pPci->di.pAttrHdr->nAccessListIdx, pPci->di.pAttrHdr->nObjCreator, + &titleCreatorPerm, + TRUE, pEveryoneEntry ? (pEveryoneEntry->entryCreatorId != titleId) : TRUE); + WFSKRN_PERM_REPORT("title :%08X(%d)->%08X %08X %08X.\n", + titleCreatorPerm.nEntryCreatorId, titleCreatorPerm.nEntryCreatorCl, + titleCreatorPerm.nTitleId, titleCreatorPerm.nFlags, + pPci->di.pAttrHdr->nAccessListIdx); + } + + // wild card + if (nFlags == WFS_PERM_FULL && nMask == WFS_PERM_FULL) + { + if (titleId == entryCreatorId) + { + nFlags = WFS_PERM_CL_MINUS_0 | (entryCreatorPerm.nFlags & ~WFS_PERM_CL_MASK); + } + else + { + nFlags = WFS_PERM_CL_MINUS_1 | (entryCreatorPerm.nFlags & ~WFS_PERM_CL_MASK); + } + } + + // calculate object creator's privilege and WFS_PERM_DELETE_OR_MOVE + if (pPci->di.pAttrHdr->nAccessListIdx & WFS_FLAG_IS_A_DIRECTORY) + { + if (parentPerm.nFlags & WFS_PERM_ADD_OR_DELETE_SUBDIR) + { + if (pPci->di.pAttrHdr->nObjCreator == titleId) + parentPerm.nFlags |= WFS_PERM_DIR_FULL; + } + } + else + { + if (parentPerm.nFlags & WFS_PERM_ADD_OR_DELETE_FILE) + { + if (pPci->di.pAttrHdr->nObjCreator == titleId) + parentPerm.nFlags |= WFS_PERM_FILE_FULL; + } + } + + currentPerm.nTitleId = titleId; + if (pTitleEntry) + { + WFSKRN_PERM_REPORT("Entry Creator %d <-> Parent %d\n", GetAbsCL(titleCreatorPerm.nFlags), parentPerm.nEntryCreatorCl); + if (GetAbsCL(titleCreatorPerm.nFlags) < parentPerm.nEntryCreatorCl) + { + if (pSelfEntry) + { + if (((s32)GetAbsCL(parentPerm.nFlags) + GetRelCL(pSelfEntry->permissions)) < 0) + { + // if CL is a negative value, title have no permission. + currentPerm.nFlags = 0; + } + else + { + currentPerm.nFlags = + GetAbsCLFlag(GetAbsCL(parentPerm.nFlags) + GetRelCL(pSelfEntry->permissions)) | + ((pSelfEntry->permissions & ~WFS_PERM_CL_MASK) & (parentPerm.nFlags & ~WFS_PERM_CL_MASK)); + } + } + else + { + currentPerm.nFlags = parentPerm.nFlags; + } + currentPerm.nEntryCreatorId = parentPerm.nEntryCreatorId; + currentPerm.nEntryCreatorCl = parentPerm.nEntryCreatorCl; + } + else + { + if (((s32)GetAbsCL(titleCreatorPerm.nFlags) + GetRelCL(pTitleEntry->permissions)) < 0) + { + // if CL is a negative value, title have no permission. + currentPerm.nFlags = 0; + } + else + { + // At first, culclate title entry's inherited values. + currentPerm.nFlags = + GetAbsCLFlag(GetAbsCL(titleCreatorPerm.nFlags) + GetRelCL(pTitleEntry->permissions)) | + ((pTitleEntry->permissions & ~WFS_PERM_CL_MASK) & (titleCreatorPerm.nFlags & ~WFS_PERM_CL_MASK)); + } + if (pSelfEntry) + { + if (((s32)GetAbsCL(currentPerm.nFlags) + GetRelCL(pSelfEntry->permissions)) < 0) + { + // if CL is a negative value, title have no permission. + currentPerm.nFlags = 0; + } + else + { + // Next, culclate self entry. + currentPerm.nFlags = + GetAbsCLFlag(GetAbsCL(currentPerm.nFlags) + GetRelCL(pSelfEntry->permissions)) | + ((pSelfEntry->permissions & ~WFS_PERM_CL_MASK) & (currentPerm.nFlags & ~WFS_PERM_CL_MASK)); + } + } + currentPerm.nEntryCreatorId = titleCreatorPerm.nTitleId; + currentPerm.nEntryCreatorCl = GetAbsCL(titleCreatorPerm.nFlags); + } + } + else + { + if (pSelfEntry) + { + if (((s32)GetAbsCL(parentPerm.nFlags) + GetRelCL(pSelfEntry->permissions)) < 0) + { + // if CL is a negative value, title have no permission. + currentPerm.nFlags = 0; + } + else + { + currentPerm.nFlags = + GetAbsCLFlag(GetAbsCL(parentPerm.nFlags) + GetRelCL(pSelfEntry->permissions)) | + ((pSelfEntry->permissions & ~WFS_PERM_CL_MASK) & (parentPerm.nFlags & ~WFS_PERM_CL_MASK)); + } + } + else + { + currentPerm.nFlags = parentPerm.nFlags; + } + currentPerm.nEntryCreatorId = parentPerm.nEntryCreatorId; + currentPerm.nEntryCreatorCl = parentPerm.nEntryCreatorCl; + } + + // to calculate everyone permissions. + if (WFS_EVERYONE_ID != titleId) + { + everyonePerm.nTitleId = WFS_EVERYONE_ID; + nResult = GetInheritedEntry(pPci->pEntry, &pPci->rxi, + pAreaInfo, pPci->di.pAttrHdr->nAccessListIdx, pPci->di.pAttrHdr->nObjCreator, + &everyonePerm, + TRUE, TRUE); + WFSKRN_PERM_REPORT("everyone :%08X(%d)->%08X %08X %08X.\n", + everyonePerm.nEntryCreatorId, everyonePerm.nEntryCreatorCl, + everyonePerm.nTitleId, everyonePerm.nFlags, + pPci->di.pAttrHdr->nAccessListIdx); + + WFSKRN_PERM_REPORT("Everyone %d <-> Inherited %d\n", everyonePerm.nEntryCreatorCl, currentPerm.nEntryCreatorCl); + if (everyonePerm.nEntryCreatorCl < currentPerm.nEntryCreatorCl) + { + // no need to update. + } + else if (everyonePerm.nEntryCreatorCl == currentPerm.nEntryCreatorCl) + { + // ORed + currentPerm.nFlags |= (everyonePerm.nFlags & ~WFS_PERM_CL_MASK); + } + else + { + // to select everyone entry. + currentPerm.nTitleId = WFS_EVERYONE_ID; + currentPerm.nFlags = everyonePerm.nFlags; + currentPerm.nEntryCreatorId = everyonePerm.nEntryCreatorId; + currentPerm.nEntryCreatorCl = everyonePerm.nEntryCreatorCl; + } + } + + + if (mask & WFS_PERM_CL_MASK) + { + if (GetRelCL(nFlags) <= 0) + { + if (((s32)GetAbsCL(entryCreatorPerm.nFlags) + GetRelCL(nFlags)) < 0) + { + WFSKRN_PERM_REPORT("caller doesn't have permission to set entry.\n"); + nResult = WFSKRN_RESULT_PERMISSION_CL; + goto Exit; + } + newFlags = (currentPerm.nFlags & ~WFS_PERM_CL_MASK & ~mask) | (nFlags & ~WFS_PERM_CL_MASK & mask) | GetAbsCLFlag((s32)GetAbsCL(entryCreatorPerm.nFlags) + GetRelCL(nFlags)); + nFlags = (currentPerm.nFlags & ~WFS_PERM_CL_MASK & ~mask) | (nFlags & ~WFS_PERM_CL_MASK & mask) | (nFlags & WFS_PERM_CL_MASK); + } + else if (GetAbsCL(nFlags) >= 0) + { + if ((GetAbsCL(nFlags) - (s32)GetAbsCL(entryCreatorPerm.nFlags)) > 0) + { + WFSKRN_PERM_REPORT("caller doesn't have permission to set entry.\n"); + nResult = WFSKRN_RESULT_PERMISSION_CL; + goto Exit; + } + newFlags = (currentPerm.nFlags & ~WFS_PERM_CL_MASK & ~mask) | (nFlags & ~WFS_PERM_CL_MASK & mask) | (nFlags & WFS_PERM_CL_MASK); + nFlags = (currentPerm.nFlags & ~WFS_PERM_CL_MASK & ~mask) | (nFlags & ~WFS_PERM_CL_MASK & mask) | GetRelCLFlag(GetAbsCL(nFlags) - (s32)GetAbsCL(entryCreatorPerm.nFlags)); + } + else + { + WFSKRN_PERM_REPORT("invalid control level argument.\n"); + nResult = WFSKRN_RESULT_INVALID; + goto Exit; + } + } + else + { + if ((GetAbsCL(currentPerm.nFlags) - (s32)GetAbsCL(entryCreatorPerm.nFlags)) > 0) + { + WFSKRN_PERM_REPORT("caller doesn't have permission to set entry.\n"); + nResult = WFSKRN_RESULT_PERMISSION_CL; + goto Exit; + } + newFlags = (currentPerm.nFlags & ~mask) | (nFlags & mask); + nFlags = (currentPerm.nFlags & ~WFS_PERM_CL_MASK & ~mask) | (nFlags & mask) | GetRelCLFlag(GetAbsCL(currentPerm.nFlags) - (s32)GetAbsCL(entryCreatorPerm.nFlags)); + } + + WFSKRN_PERM_REPORT("current:%08X(%d)->%08X %08X %08X.\n", + currentPerm.nEntryCreatorId, currentPerm.nEntryCreatorCl, + currentPerm.nTitleId, currentPerm.nFlags, + pPci->di.pAttrHdr->nAccessListIdx); + + if ((newFlags != currentPerm.nFlags) || + (currentPerm.nEntryCreatorId == WFS_ROOT_ID && currentPerm.nEntryCreatorCl == 0)) // effective entry has not created yet. + { + if (titleId == entryCreatorId) + { + // cannot create self entry which has minused CL. + if (GetRelCLFlag(nFlags) < 0) + { + WFSKRN_PERM_REPORT("cannot create self entry which has minused CL.\n"); + //nResult = WFSKRN_RESULT_INVALID; + //goto Exit; + } + // Does creator have enough permissions to set entry? + if ((nFlags & ~WFS_PERM_CL_MASK & mask) & ~(entryCreatorPerm.nFlags & ~WFS_PERM_CL_MASK)) + { + WFSKRN_PERM_REPORT("caller doesn't have permission to set entry.\n"); + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit; + } + } + else + { + if (GetAbsCL(entryCreatorPerm.nFlags) == 0) + { + WFSKRN_PERM_REPORT("caller has CL 0.\n"); + nResult = WFSKRN_RESULT_PERMISSION_CL; + goto Exit; + } + // Does creator have enought CL to set entry? + if (GetAbsCL(entryCreatorPerm.nFlags) < currentPerm.nEntryCreatorCl) + { + WFSKRN_PERM_REPORT("caller doesn't have enough cl to set entry.\n"); + nResult = WFSKRN_RESULT_PERMISSION_CL; + goto Exit; + } + // Does creator have enough permissions to set entry? + if ((nFlags & ~WFS_PERM_CL_MASK & mask) & ~(entryCreatorPerm.nFlags & ~WFS_PERM_CL_MASK)) + { + WFSKRN_PERM_REPORT("caller doesn't have permission to set entry.\n"); + nResult = WFSKRN_RESULT_PERMISSION; + goto Exit; + } + } + + WFSKRN_PERM_REPORT("change :%08X->%08X\n", currentPerm.nFlags, newFlags); + + // cannot delete other created entry. + if (pTitleEntry && (titleId != entryCreatorId)) + { + WFSKrnDeletePermissions(pAreaInfo, &(pPci->di.pAttrHdr->nAccessListIdx), + pTitleEntry->entryCreatorId, pTitleEntry->titleId); + WFSKRN_PERM_REPORT("entry %08X(X)->%08X %08X is deleted. %08X.\n", + pTitleEntry->entryCreatorId, pTitleEntry->titleId, pTitleEntry->permissions, + pPci->di.pAttrHdr->nAccessListIdx); + } + + if (pSelfEntry) + { + WFSKrnDeletePermissions(pAreaInfo, &(pPci->di.pAttrHdr->nAccessListIdx), + pSelfEntry->entryCreatorId, pSelfEntry->titleId); + WFSKRN_PERM_REPORT("entry %08X(X)->%08X %08X is deleted. %08X.\n", + pSelfEntry->entryCreatorId, pSelfEntry->titleId, pSelfEntry->permissions, + pPci->di.pAttrHdr->nAccessListIdx); + } + + // if already set new permissions. + if (newFlags == parentPerm.nFlags && + !(parentPerm.nEntryCreatorId == WFS_ROOT_ID && parentPerm.nEntryCreatorCl == 0)) // effective entry has already created. + { + WFSKRN_PERM_REPORT("no need to create new entry.\n"); + nResult = WFSKRN_RESULT_OK; + goto Exit; + } + + WFSKrnExitOnError(WFSKrnSetAccessList(pAreaInfo, &(pPci->di.pAttrHdr->nAccessListIdx), nFlags, + mask, entryCreatorId, titleId)); + WFSKRN_PERM_REPORT("new entry %08X(%d)->%08X %08X is created. %08X.\n", + entryCreatorId, GetAbsCL(entryCreatorPerm.nFlags), titleId, nFlags, pPci->di.pAttrHdr->nAccessListIdx); + } + else + { + WFSKRN_PERM_REPORT("no need to create new entry.\n"); + nResult = WFSKRN_RESULT_OK; + } + +Exit: + WFSKRN_PERM_REPORT("WFSKrnSetInheritedPermissionForUser end\n"); + // ToDo: remapping error code? + return nResult; +} + +#endif diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission_AccessList.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission_AccessList.cpp new file mode 100644 index 0000000..4ae0c05 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission_AccessList.cpp @@ -0,0 +1,1682 @@ +/*---------------------------------------------------------------------------* + Project: wfsKrn + File: wfsKrn_Permission.cpp - Functions for permissions. + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission_AccessList.cpp,v $ + Revision 1.25 2008/10/20 00:30:54 nakanose_jin + (none) + + Revision 1.24 2008/10/09 04:39:07 ueno + Fixed DeletePermission() not to set WFSKRN_ACCESSLIST_FREEINDEX to handle in error case. + + Revision 1.23 2008/10/09 01:44:22 ueno + Added workarounds. + + Revision 1.22 2008/10/03 08:37:56 kondo_masahiro + Fixed codes for porting IOP + + Revision 1.21 2008/09/26 11:07:21 ueno + Cleanup. + + Revision 1.20 2008/09/24 07:33:21 ueno + Added AclHdr{} to AreaHdr{} to save configuration of accesslists in a disk. + + Revision 1.19 2008/08/19 08:12:23 ueno + Fixed error handling in WFSKrnAccessListCreateFile(). + + Revision 1.18 2008/07/23 01:57:53 ueno + Commented out unused functions. + + Revision 1.17 2008/07/11 08:10:36 ueno + Fixed control level check. + + Revision 1.16 2008/07/11 01:30:32 ueno + Added null pointer check to WFSKrnAccessListInit(). + + Revision 1.15 2008/07/02 06:34:57 nakanose_jin + temporary edit + + Revision 1.14 2008/06/05 14:05:22 ueno + Modified to reserve accesslist index 0 as the default (empty) accesslist. + + Revision 1.13 2008/06/05 08:07:48 ueno + Revised permission APIs. + + Revision 1.12 2008/06/02 15:10:02 ueno + Revised WFSKrnAccessList{} to reduce the size. + + Revision 1.11 2008/05/30 08:50:07 ueno + Cleanup. + + Revision 1.10 2008/05/28 02:12:49 ueno + Cleanup. + + Revision 1.9 2008/05/23 06:32:08 ueno + Cleanup. + + Revision 1.8 2008/05/16 11:16:17 ueno + Implemented permission APIs with directory module. + + Revision 1.7 2008/05/08 11:43:33 ueno + Cleanup. + + Revision 1.6 2008/05/06 02:23:58 ueno + Fixed IsAllowed() to check root operation. + + Revision 1.5 2008/04/29 01:12:54 ueno + Defined WFS_ROOT_ID and WFS_EVERYONE_ID. + + Revision 1.4 2008/04/25 06:22:55 ueno + Cleanup. + + Revision 1.3 2008/04/25 04:40:07 ueno + Added support for WFSDEV. + + Revision 1.27 2008/04/23 08:59:47 ueno + Replaced WFSAreaHdr by AreaInfo. + Revised directory permission (change -> add). + + Revision 1.26 2008/04/15 07:36:01 ueno + Changed return type to WFSKrnResult. + + Revision 1.25 2008/04/14 13:49:59 ueno + Cleanup. + + Revision 1.24 2008/04/14 03:00:39 ueno + Modified WFSKrnCreateRootAccessList() to create an accesslist only for the root. + Added WFSKrnDebugCreateAccessList() for tests. + + Revision 1.23 2008/04/11 13:21:42 ueno + Removed WFSKrnAccessListSetInstallerPermission(). + Fixed WFSKrnAccessListCheckDirectoryPermission() and CheckFilePermission(). + + Revision 1.22 2008/04/11 06:16:47 ueno + Defined WFSAclFileHandle. + + Revision 1.21 2008/04/11 04:53:05 ueno + Added WFSKRN_ACL_USE_MUTEX to switch mutex. + + Revision 1.20 2008/04/11 02:57:59 ueno + Renamed WFSKrnCreateAccessList() to make clear the purpose. + + Revision 1.19 2008/04/09 11:30:10 ueno + Fine-granularity locking. + + Revision 1.18 2008/04/09 03:01:01 ueno + Modified to initialize mutex in AccessListControlBlock. + + Revision 1.17 2008/04/08 06:39:32 ueno + Cleanup. + + Revision 1.16 2008/04/08 05:43:21 ueno + Revised creator’s inherited permissions in a new accesslist. + + Revision 1.15 2008/04/07 12:46:56 ueno + Added support for group others. + + Revision 1.14 2008/04/07 09:21:46 ueno + Added WFSKrnAccessListSetInstallerPermission() to set permissions for the installer by the root. + + Revision 1.13 2008/04/03 11:40:44 ueno + Replaced accesslist index by accesslist handle. + + Revision 1.12 2008/04/03 10:00:22 ueno + Cleanup. + + Revision 1.11 2008/04/03 06:39:30 ueno + Modified GetInheritAccessList() to set proper control levels of the caller. + Cleanup. + + Revision 1.10 2008/04/02 14:14:53 ueno + Revised permission inheritance. + + Revision 1.9 2008/04/01 08:24:54 ueno + Fixed cache reference count. + + Revision 1.8 2008/03/31 14:07:27 ueno + Removed WFSKrnAccessListAddUser() and RemoveUser(). + Removed WFSKrnAccessListCan*(). + + Revision 1.7 2008/03/19 10:18:32 ueno + Revised WFSKrnAddUser() and RemoveUser() to specify operator title ID. + + Revision 1.6 2008/03/18 13:44:04 ueno + Fixed refernce count of cache. + Revised WFSKrnAddEntry(), RemoveEntry() and SetPermission() for cleanup. + + Revision 1.5 2008/03/14 08:02:53 ueno + Revised API prefixes (WFS -> WFSKrn). + + Revision 1.4 2008/03/12 06:37:37 ueno + Added WFSAccessListCanRead(), Write()... + + Revision 1.3 2008/03/11 12:10:41 ueno + Cleanup. + + Revision 1.2 2008/03/11 11:39:01 ueno + Cleanup. + + Revision 1.1 2008/03/11 11:10:47 ueno + Moved accesslist functions into wfskrn_Permission_AccessList.cpp. + + Revision 1.17 2008/03/11 09:51:54 ueno + Fixed EscapeAccessList() to make a filename from UTF-16 characters (0x3300-0x33ff). + + Revision 1.16 2008/03/11 06:53:05 ueno + Added WFSAccessListSetPermission() and GetPermission(). + + Revision 1.15 2008/03/07 05:43:59 ueno + Cleanup. + + Revision 1.14 2008/03/07 05:32:07 ueno + Modified WFSCreateAccessList() to be able to create an accesslist for directories. + + Revision 1.13 2008/03/06 12:25:27 ueno + Revised cache freelist (signgle -> double link list). + + Revision 1.12 2008/03/06 11:01:38 ueno + Fixed asserts. + + Revision 1.11 2008/03/06 10:45:44 ueno + Revised accesslist cache. + + Revision 1.10 2008/02/29 07:29:10 ueno + Added Windows api wrappers. + + Revision 1.9 2008/02/29 00:48:05 ueno + Changed the attribute of index to inout (WFSAccessListAddEntry() and RemoveEntry()). + + Revision 1.8 2008/02/28 13:11:01 ueno + Revised to keep accesslist cache and indexlist handle in WFSAreaHdr{}. + + Revision 1.7 2008/02/28 07:01:52 ueno + Fixed escape sequence for accesslist filename. + + Revision 1.6 2008/02/28 04:36:32 ueno + Cleanup. + + Revision 1.5 2008/02/27 10:05:36 ueno + Revised to use WFSAreaHdr{} to specifiy WFS area. + + Revision 1.4 2008/02/27 04:29:24 ueno + Modified WFSAccessListAddEntry() and RemoveEntry() to delete accesslist file when the reference count is zero. + + Revision 1.3 2008/02/26 14:11:43 ueno + Added WFSAccessListAddEntry() and WFSAccessListRemoveEntry() to edit accesslist. + + Revision 1.2 2008/02/25 09:43:57 ueno + Added support for accesslist cache. + + Revision 1.1 2008/02/22 05:16:13 ueno + Initial Check-in. + + +*---------------------------------------------------------------------------*/ +#define WFSKrn_ACCESSLIST_KEEP_REF + +#include "wfs_Defs.h" +#include "wfskrn_Permission_AccessList.h" + +#ifdef WFSDEV +#include "wfskrn_Permission_Win32.h" +#else // WFSDEV +#include "wfskrn_Permission_Iop.h" +#endif // WFSDEV + +#include "wfskrn_Permission_File.h" +#include "wfskrn_Permission_Private.h" + +#define FreeBlockAddress(x) ((x)->accessListCb->freeBlock) // WFSKrnAccessListBlock* +#define MemoryBlockAddress(x) ((x)->accessListCb->memoryBlock) // WFSKrnAccessListBlock* +#define NumMemoryBlock(x) ((x)->accessListCb->numBlock) +#define AccessListCache(x) ((x)->accessListCb->cache) +#define AccessListCacheFreeList(x) ((x)->accessListCb->cacheFreeList) +#define Mutex(x) ((x)->accessListCb->mxMutex) +#define Initialized(x) ((x)->accessListCb->initialized) +#define InstallerDirPm(x) ((x)->accessListCb->installerDirPermission) +#define InstallerFilePm(x) ((x)->accessListCb->installerFilePermission) + +#define CacheIsEmpty() (AccessListCache(area).tail == NULL) +#define CacheFreeListIsEmpty() (AccessListCacheFreeList(area).tail == NULL) + +#define IsCacheEnd(list) ((list) == NULL) +#define SIZE_OF_LIST(x) (sizeof(WFSKrnKrnAccessList) + WFSKrnKrnAccessListGetNum(x) * sizeof(WFSKrnAccessListBlock)) + +#define IsDirectory(x) ((x)->handle & WFS_FLAG_IS_A_DIRECTORY) + +#define GetFirstEntry(list) ((WFSKrnAccessListEntry*) ((list)+1)) +#define GetEntry(list, index) ((WFSKrnAccessListEntry*) ((list)+1) + (index)) + +#define BRANCH_MODE_SET 0 +#define BRANCH_MODE_ADD 1 +#define BRANCH_MODE_MODIFY 2 +#define BRANCH_MODE_DELETE 3 + +#define DP_RESERVED (~(WFS_PERM_DIR_FULL | WFS_PERM_CL_MASK)) +#define FP_RESERVED (~(WFS_PERM_FILE_FULL | WFS_PERM_CL_MASK)) + +#define IsGroup(x) ((x) & WFSKRN_ACCESSLIST_GROUP) + +static WFSBool VerifyCacheList(const AreaInfo* area); +static WFSBool VerifyList(const WFSKrnAccessList* list); + +// [check] should be macro. +static WFSKrnAccessListBlock* ACL_CACHE_ADDRESS(const AreaInfo* area, u8 blockNumber) +{ + WFSKrnAccessListBlock* address; + + if (blockNumber == ACL_NO_ENTRY) + { + address = NULL; + } + else + { + address = MemoryBlockAddress(area) + blockNumber; + } + return address; +} + +// [check] should be macro. +static u8 ACL_CACHE_BLOCK(const AreaInfo* area, WFSKrnAccessListBlock* address) +{ + u8 blockNumber; + if (address) + { + blockNumber = (address - MemoryBlockAddress(area)); + } + else + { + blockNumber = ACL_NO_ENTRY; + } + return blockNumber; +} + +// [check] should be macro. +void WFSKrnAccessListCacheAdd(const AreaInfo* area, WFSKrnAccessList* list) +{ + register WFSKrnAccessList* next; + next = AccessListCache(area).head; + if (IsCacheEnd(next)) + { + AccessListCache(area).tail = list; + } + else + { + next->prevBlock = ACL_CACHE_BLOCK(area, (WFSKrnAccessListBlock*) list); + } + list->prevBlock = ACL_NO_ENTRY; + list->nextBlock = ACL_CACHE_BLOCK(area, (WFSKrnAccessListBlock*) next); + AccessListCache(area).head = list; +} + +// [check] should be macro. +void WFSKrnAccessListCacheRemove(const AreaInfo* area, WFSKrnAccessList* list) +{ + register WFSKrnAccessList* next; + register WFSKrnAccessList* prev; + + next = (WFSKrnAccessList*) ACL_CACHE_ADDRESS(area, list->nextBlock); + prev = (WFSKrnAccessList*) ACL_CACHE_ADDRESS(area, list->prevBlock); + + if (IsCacheEnd(next)) + { + AccessListCache(area).tail = prev; + } + else + { + next->prevBlock = ACL_CACHE_BLOCK(area, (WFSKrnAccessListBlock*) prev); + } + + if (IsCacheEnd(prev)) + { + AccessListCache(area).head = next; + } + else + { + prev->nextBlock = ACL_CACHE_BLOCK(area, (WFSKrnAccessListBlock*) next); + } +} + +// [check] should be macro. +// look up an accesslist cache (0 <= ref) in the cache list, +WFSKrnAccessList* WFSKrnAccessListLookupByIndex(const AreaInfo* area, WFSKrnAclHandle handle) +{ + register WFSKrnAccessList* list; + list = AccessListCache(area).head; + while (list != NULL) + { + if (list->handle == handle) + { + return list; + } + list = (WFSKrnAccessList*) ACL_CACHE_ADDRESS(area, list->nextBlock); + } + return NULL; +} + +// [check] should be macro. +// look up an active accesslist (0 < ref) +WFSKrnAccessList* WFSKrnAccessListLookup(const AreaInfo* area, WFSKrnAclHandle handle) +{ + WFSKrnAccessList* list = WFSKrnAccessListLookupByIndex(area, handle); + if (!list || list->ref == 0) + { + return NULL; + } + return list; +} + +// [check] should be macro. +static void CacheFreeListInsertTail(const AreaInfo* area, WFSKrnAccessList* list) +{ + register WFSKrnAccessList* prev; + prev = AccessListCacheFreeList(area).tail; + if (IsCacheEnd(prev)) + { + AccessListCacheFreeList(area).head = list; + } + else + { + prev->nextFreeCacheBlock = ACL_CACHE_BLOCK(area, (WFSKrnAccessListBlock*) list); + } + list->prevFreeCacheBlock = ACL_CACHE_BLOCK(area, (WFSKrnAccessListBlock*) prev); + list->nextFreeCacheBlock = ACL_NO_ENTRY; + AccessListCacheFreeList(area).tail = list; +} + +// [check] should be macro. +static WFSKrnAccessList* CacheFreeListRemoveHead(const AreaInfo* area) +{ + register WFSKrnAccessList* head; + register WFSKrnAccessList* next; + + head = AccessListCacheFreeList(area).head; + if (head) + { + next = (WFSKrnAccessList*) ACL_CACHE_ADDRESS(area, head->nextFreeCacheBlock); + if (IsCacheEnd(next)) + { + AccessListCacheFreeList(area).tail = next; + } + else + { + next->prevFreeCacheBlock = ACL_NO_ENTRY; + } + AccessListCacheFreeList(area).head = next; + } + return head; +} + +// [check] should be macro. +void WFSKrnAccessListCacheFreeListRemove(const AreaInfo* area, WFSKrnAccessList* list) +{ + register WFSKrnAccessList* next; + register WFSKrnAccessList* prev; + + next = (WFSKrnAccessList*) ACL_CACHE_ADDRESS(area, list->nextFreeCacheBlock); + prev = (WFSKrnAccessList*) ACL_CACHE_ADDRESS(area, list->prevFreeCacheBlock); + + if (IsCacheEnd(next)) + { + AccessListCacheFreeList(area).tail = prev; + } + else + { + next->prevFreeCacheBlock = ACL_CACHE_BLOCK(area, (WFSKrnAccessListBlock*) prev); + } + + if (IsCacheEnd(prev)) + { + AccessListCacheFreeList(area).head = next; + } + else + { + prev->nextFreeCacheBlock = ACL_CACHE_BLOCK(area, (WFSKrnAccessListBlock*) next); + } +} + +// [check] should be macro. +static void CacheFreeListInvalidate(const AreaInfo* area, WFSKrnAccessList* list) +{ + int ret; + WFSKrnAccessListCacheFreeListRemove(area, list); + ret = WFSKrnMemoryBlockFree(area, (WFSKrnAccessListBlock*) list, WFSKRN_BLOCKS_IN_LIST(list)); + WFSKRN_ACL_ASSERT(ret == 0); +} + +// +// Memory block +// +static int SetFreeBlockNum(WFSKrnAccessListBlock* free, u32 num) +{ + WFSKRN_ACL_ASSERT(num <= ACL_MAX_MEMORY_BLOCK); + free->num = (u8) num; + free->type = WFSKRN_ACCESSLIST_FREEBLOCK; + return 0; +} + +static int GetFreeBlockNum(const WFSKrnAccessListBlock* free) +{ + WFSKRN_ACL_ASSERT(free->type == WFSKRN_ACCESSLIST_FREEBLOCK); + return free->num; +} + +u32 WFSKrnAccessListGetNum(const WFSKrnAccessList* list) +{ + return (u32) (list->num); +} + +void WFSKrnAccessListSetNum(WFSKrnAccessList* list, u32 num) +{ + WFSKRN_ACL_ASSERT(num <= ACL_MAX_MEMORY_BLOCK); + list->num = (u8) num; +} + +static int WFSKrnMemoryBlockInit(const AreaInfo* area) +{ + if (!(area->accessListCb) || !MemoryBlockAddress(area)) + { + return -1; + } + + // all memory blocks are free. + FreeBlockAddress(area) = MemoryBlockAddress(area); + FreeBlockAddress(area)->nextBlock = NumMemoryBlock(area); // end of memory block. + SetFreeBlockNum(FreeBlockAddress(area), NumMemoryBlock(area)); + + if (WFSKrnAccessListIndexListInit(area) < 0) + { + return -1; + } + + return 0; +} + +WFSKrnAccessListBlock* WFSKrnMemoryBlockAlloc(const AreaInfo* area, int numBlocks) +{ + WFSKrnAccessListBlock* free = FreeBlockAddress(area); + WFSKrnAccessListBlock* prev = NULL; + WFSKrnAccessListBlock* newFree; + + if (MemoryBlockAddress(area) + NumMemoryBlock(area) <= FreeBlockAddress(area) || + numBlocks == 0) + { + return NULL; // no freeblock. + } + + while (GetFreeBlockNum(free) < numBlocks) + { + if (free->nextBlock == NumMemoryBlock(area)) + { + WFSKRN_ACL_ASSERT(VerifyMemoryBlock(area)); + return NULL; + } + prev = free; + free = MemoryBlockAddress(area) + free->nextBlock; + } + + if (GetFreeBlockNum(free) == numBlocks) + { + if (prev) + { + prev->nextBlock = free->nextBlock; + } + else + { + FreeBlockAddress(area) = MemoryBlockAddress(area) + free->nextBlock; + } + } + else + { + newFree = free + numBlocks; + newFree->nextBlock = free->nextBlock; + SetFreeBlockNum(newFree, GetFreeBlockNum(free) - numBlocks); + + if (prev) + { + prev->nextBlock = newFree - MemoryBlockAddress(area); + } + else + { + FreeBlockAddress(area) = newFree; + } + } + + free->nextBlock = 0; // allocated. + SetFreeBlockNum(free, numBlocks); + free->type = 0; // allocated. + + WFSKRN_ACL_ASSERT(VerifyMemoryBlock(area)); + + return free; +} + +int WFSKrnMemoryBlockFree(const AreaInfo* area, WFSKrnAccessListBlock* block, u32 numBlocks) +{ + if (block < MemoryBlockAddress(area) || MemoryBlockAddress(area) + NumMemoryBlock(area) <= block) + { + return -1; // out of memory blocks. + } + if (numBlocks == 0) + { + return 0; + } + + if (block < FreeBlockAddress(area)) + { + if (FreeBlockAddress(area) == block + numBlocks) + { + // combine + if (FreeBlockAddress(area) == MemoryBlockAddress(area) + NumMemoryBlock(area)) + { + SetFreeBlockNum(block, numBlocks); // set flags. + block->nextBlock = NumMemoryBlock(area); // the tail of memory block. + } + else + { + SetFreeBlockNum(block, GetFreeBlockNum(FreeBlockAddress(area)) + numBlocks); + block->nextBlock = FreeBlockAddress(area)->nextBlock; + } + } + else + { + SetFreeBlockNum(block, numBlocks); + block->nextBlock = FreeBlockAddress(area) - MemoryBlockAddress(area); + } + FreeBlockAddress(area) = block; + WFSKRN_ACL_ASSERT(VerifyMemoryBlock(area)); + } + else + { + WFSKrnAccessListBlock* free; + WFSKrnAccessListBlock* next; + + SetFreeBlockNum(block, numBlocks); + free = FreeBlockAddress(area); + next = MemoryBlockAddress(area) + FreeBlockAddress(area)->nextBlock; + + while (next < block) + { + free = next; + next = MemoryBlockAddress(area) + next->nextBlock; + } + + if (free + GetFreeBlockNum(free) == block) + { + // combine + numBlocks += GetFreeBlockNum(free); + SetFreeBlockNum(free, numBlocks); + block = free; + } + else + { + free->nextBlock = block - MemoryBlockAddress(area); + } + + if (block + GetFreeBlockNum(block) == next && next < MemoryBlockAddress(area) + NumMemoryBlock(area)) + { + // combine + SetFreeBlockNum(block, GetFreeBlockNum(next) + numBlocks); + block->nextBlock = next->nextBlock; + } + else + { + block->nextBlock = next - MemoryBlockAddress(area); + } + WFSKRN_ACL_ASSERT(VerifyMemoryBlock(area)); + } + + return 0; +} + +static int AccessListCacheInit(const AreaInfo* area) +{ + AccessListCache(area).head = NULL; + AccessListCache(area).tail = NULL; + + AccessListCacheFreeList(area).head = NULL; + AccessListCacheFreeList(area).tail = NULL; + + return 0; +} + +// create an accesslist file corresponding to the specified list. +static WFSKrnResult WFSKrnInitializeAccessList(const AreaInfo* area, WFSKrnAccessList** list) +{ + int result; + utf8 filename[WFS_MAX_FILE_NAME_SIZE]; + if ((*list)->ref != 1) + { + WFSKRN_ACL_ASSERT((*list)->ref == 1); + } + + if (ACL_MAX_ENTRIES < WFSKrnAccessListGetNum(*list)) + { + WFSKRN_ACL_REPORT("WFSKrnInitializeAccessList(): too many entries.\n"); + return WFSKRN_RESULT_ACL_MAX_ENTRIES; + } + + result = WFSKrnConvertAccessListToFilename((*list), filename, WFS_MAX_FILE_NAME_SIZE); + if (result < 0) + { + return WFSKRN_RESULT_ACL_INVALID_PARAMETER; + } + + result = WFSKrnAccessListCreateFile(area, filename, list); + if (result < 0) + { + return WFSKRN_RESULT_ACL_FILE; + } + return WFSKRN_RESULT_OK; +} + +static void CloseAccessList(const AreaInfo* area, WFSKrnAccessList* list) +{ + WFSAclLockMutex(&Mutex(area)); + WFSKrnAccessListFree(area, list); + WFSAclUnlockMutex(&Mutex(area)); +} + +static WFSKrnResult CheckCreateParams(u32 aclType, WFSTitleId entryCreatorId, WFSTitleId titleId, u32 nFlags) +{ + s32 cl; + if (aclType & ~ACL_FLAG_DIRECTORY) + { + // support directory flag only. + return WFSKRN_RESULT_ACL_INVALID_PARAMETER; + } + + if (entryCreatorId == WFS_ROOT_ID && + titleId == WFS_ROOT_ID) + { + return WFSKRN_RESULT_OK; + } + + if (aclType & (u32)ACL_FLAG_DIRECTORY) + { + if (nFlags & DP_RESERVED) + { + return WFSKRN_RESULT_ACL_INVALID_PARAMETER; + } + } + else + { + if (nFlags & FP_RESERVED) + { + return WFSKRN_RESULT_ACL_INVALID_PARAMETER; + } + } + + if (titleId == WFS_ROOT_ID && entryCreatorId != WFS_ROOT_ID) + { + // cannot create root entry by others. + return WFSKRN_RESULT_PERMISSION; + } + + if (ACL_GET_CL_RELATIVE(nFlags, (int*)&cl) != WFSKRN_RESULT_OK) + { + return WFSKRN_RESULT_PERMISSION; + } + if (entryCreatorId == titleId) + { + if (cl <= 0) + { + return WFSKRN_RESULT_PERMISSION; + } + } + else if (entryCreatorId != WFS_ROOT_ID && 0 < cl) + { + return WFSKRN_RESULT_PERMISSION; + } + return WFSKRN_RESULT_OK; +} + +static WFSKrnResult CreateAccessList(const AreaInfo* area, u32 aclType, + WFSTitleId entryCreatorId, WFSTitleId titleId, u32 nFlags, WFSKrnAclHandle* newHandle) +{ + WFSKrnAccessList* list = NULL; + WFSKrnResult result; + WFSKrnAccessListEntry* entry; + + result = CheckCreateParams(aclType, entryCreatorId, titleId, nFlags); + if (result != WFSKRN_RESULT_OK) + { + return result; + } + + WFSAclLockMutex(&Mutex(area)); + if (titleId == WFS_ROOT_ID) + { + // The root implicitly has all permissions for all objects. + result = WFSKrnAccessListAlloc(area, 0, &list); + } + else + { + result = WFSKrnAccessListAlloc(area, 1, &list); + if (result == WFSKRN_RESULT_OK) + { + entry = GetFirstEntry(list); + entry->id = titleId; + entry->ecId = entryCreatorId; + entry->pm = nFlags; + } + } + + if (result == WFSKRN_RESULT_OK) + { + list->handle = aclType; + result = WFSKrnInitializeAccessList(area, &list); + if (result != WFSKRN_RESULT_OK) + { + WFSKrnMemoryBlockFree(area, (WFSKrnAccessListBlock*) (list), WFSKRN_BLOCKS_IN_LIST(list)); // [check] must test this code. + } + } + + if (result == WFSKRN_RESULT_OK) + { + *newHandle = list->handle; + CloseAccessList(area, list); + } + WFSKRN_ACL_ASSERT(VerifyCacheList(area)); + WFSAclUnlockMutex(&Mutex(area)); + return result; +} + +static WFSKrnResult CreateDefaultAccessList(const AreaInfo* area) +{ + WFSKrnResult result; + WFSKrnAclHandle handle; + result = CreateAccessList(area, 0, WFS_ROOT_ID, 0, 0, &handle); + if (result != WFSKRN_RESULT_OK || handle != 0) + { + return WFSKRN_RESULT_ACL_HANDLE; + } + return WFSKRN_RESULT_OK; +} + +WFSKrnResult WFSKrnDebugCreateAccessList(const AreaInfo* area, u32 aclType, + WFSTitleId entryCreatorId, WFSTitleId titleId, u32 nFlags, WFSKrnAclHandle* newHandle) +{ + return CreateAccessList(area, aclType, entryCreatorId, titleId, nFlags, newHandle); +} + +WFSKrnResult WFSKrnAccessListInit(AreaInfo* area) +{ + WFSKrnResult result; + + WFSKRN_ACL_ASSERT(area); + WFSKRN_ACL_ASSERT(area->accessListCb); + + if (Initialized(area)) + { + WFSKRN_ACL_REPORT("WARNING: WFSKrnAccessListInit(): ACL is already initialized!\n"); + return WFSKRN_RESULT_LIB_ALREADY_INITIALIZED; + } + + if (WFSKrnAccessListDirectoryInit(area) < 0) + { + return WFSKRN_RESULT_ACL_ERROR; + } + + // allocator for accesslists. + if (WFSKrnMemoryBlockInit(area) < 0) + { + return WFSKRN_RESULT_OUT_OF_MEMORY; + } + + WFSAclInitMutex(&Mutex(area)); + AccessListCacheInit(area); + + result = CreateDefaultAccessList(area); + if (result == WFSKRN_RESULT_OK) + { + Initialized(area) = TRUE; + } + return result; +} + +WFSKrnResult WFSKrnAccessListOpen(const AreaInfo* area) +{ + //WFSKrnResult result; + + WFSKRN_ACL_ASSERT(area); + WFSKRN_ACL_ASSERT(area->accessListCb); + + if (Initialized(area)) + { + WFSKRN_ACL_REPORT("WARNING: WFSKrnAccessListOpen(): ACL is already initialized!\n"); + return WFSKRN_RESULT_LIB_ALREADY_INITIALIZED; + } + + // allocator for accesslists. + if (WFSKrnMemoryBlockInit(area) < 0) + { + return WFSKRN_RESULT_OUT_OF_MEMORY; + } + + WFSAclInitMutex(&Mutex(area)); + AccessListCacheInit(area); + + Initialized(area) = TRUE; + return WFSKRN_RESULT_OK; +} + + + +WFSKrnResult WFSKrnAccessListExit(const AreaInfo* area) +{ + if (WFSKrnAccessListIndexListExit(area) < 0) + { + return WFSKRN_RESULT_AREA_ERROR; + } + return WFSKRN_RESULT_OK; +} + +// lookup +static WFSKrnAccessList* OpenAccessList(const AreaInfo* area, WFSKrnAclHandle handle) +{ + WFSKrnAccessList* list; + WFSAclLockMutex(&Mutex(area)); + + list = WFSKrnAccessListLookupByIndex(area, handle); + if (list) + { + if (list->ref == 0) + { + WFSKrnAccessListCacheFreeListRemove(area, list); + } + ++list->ref; + } + else + { + list = WFSKrnAccessListLookupFile(area, handle); + WFSKRN_ACL_ASSERT(!list || list->handle == handle); + } + WFSAclUnlockMutex(&Mutex(area)); + return list; +} + +static WFSBool LookupEntryInList(const WFSKrnAccessList* list, const WFSKrnAccessListEntry* target, WFSKrnAccessListEntry** editPosition) +{ + WFSKrnAccessListEntry* entry; + u32 numEntry; + WFSBool checkEntryCreator = (WFSBool) FALSE; + + entry = (WFSKrnAccessListEntry*) (list+1); + numEntry = WFSKrnAccessListGetNum(list); + + while (numEntry--) + { + if (entry->id == target->id && !checkEntryCreator) + { + checkEntryCreator = (WFSBool) TRUE; + } + + if (checkEntryCreator && entry->ecId == target->ecId) + { + *editPosition = entry; + return TRUE; + } + + if (target->id < entry->id || + (checkEntryCreator && target->ecId < entry->ecId)) + { + *editPosition = entry; + return FALSE; // target not found in list. + } + ++entry; + } + *editPosition = entry; + return FALSE; // not found in list. +} + +static void SetEntry(WFSKrnAccessList* newList, u32 index, WFSKrnAccessListEntry* newEntry, u32 nMask) +{ + WFSKrnAccessListEntry* entry = GetFirstEntry(newList); + entry += index; + entry->id = newEntry->id; + entry->ecId = newEntry->ecId; + entry->pm = (newEntry->pm & nMask) | (entry->pm & ~nMask); +} + +static void ModifyEntry(const WFSKrnAccessList* list, WFSKrnAccessList* newList, + u32 index, WFSKrnAccessListEntry* entry, u32 nMask) +{ + memmove(GetFirstEntry(newList), GetFirstEntry(list), + WFSKrnAccessListGetNum(list) * sizeof(WFSKrnAccessListEntry)); + SetEntry(newList, index, entry, nMask); +} + +static void RemoveEntry(const WFSKrnAccessList* list, WFSKrnAccessList* newList, u32 index) +{ + if (0 < index) + { + memmove(GetFirstEntry(newList), GetFirstEntry(list), index * sizeof(WFSKrnAccessListEntry)); + } + // shift + if (index < WFSKrnAccessListGetNum(list)) + { + memmove(GetFirstEntry(newList) + index, GetFirstEntry(list) + index + 1, + (WFSKrnAccessListGetNum(newList) - index) * sizeof(WFSKrnAccessListEntry)); + } +} + +static void AddEntry(const WFSKrnAccessList* list, WFSKrnAccessList* newList, + u32 index, WFSKrnAccessListEntry* entry, u32 nMask) +{ + if (0 < index) + { + memmove(GetFirstEntry(newList), GetFirstEntry(list), index * sizeof(WFSKrnAccessListEntry)); + } + SetEntry(newList, index, entry, nMask); + // shift + if (index < WFSKrnAccessListGetNum(list)) + { + memmove(GetEntry(newList, index + 1), GetEntry(list, index), + (WFSKrnAccessListGetNum(list) - index) * sizeof(WFSKrnAccessListEntry)); + } +} + +static WFSKrnResult BranchAccessList(const AreaInfo* area, const WFSKrnAccessList* list, + WFSKrnAccessListEntry* entry, u32 nMask, int mode, WFSKrnAccessList** newList) +{ + WFSKrnResult result; + WFSKrnAccessListEntry* target; + u32 entryIndex; // index of the entry to be modified. + u32 numUsers; + u32 newPm; + WFSBool found; + + numUsers = WFSKrnAccessListGetNum(list); + found = LookupEntryInList(list, entry, &target); + + if (mode == BRANCH_MODE_SET) + { + if (found) + { + newPm = (entry->pm & nMask) | (target->pm & ~nMask); + if (target->pm == newPm) + { + *newList = (WFSKrnAccessList*) list; + return WFSKRN_RESULT_OK; + } + mode = BRANCH_MODE_MODIFY; + } + else + { + newPm = (entry->pm & nMask); + ++numUsers; // add entry. + nMask = 0xffffffff; // zero clear except for newPm. + mode = BRANCH_MODE_ADD; + } + } + else if (found) + { + --numUsers; // remove entry. + mode = BRANCH_MODE_DELETE; + } + else + { + // the entry to be deleted is not found. + *newList = NULL; + return WFSKRN_RESULT_NOT_FOUND; + } + + result = WFSKrnAccessListAlloc(area, numUsers, newList); + if (result != WFSKRN_RESULT_OK) + { + *newList = NULL; + return result; // [check] + } + (*newList)->handle = ACL_TYPE(list); // only copy accesslist type. + // handle itself is assigned in WFSKrnAccessListCreateFile(). + entryIndex = target - GetFirstEntry(list); + switch (mode) + { + case BRANCH_MODE_ADD: + AddEntry(list, *newList, entryIndex, entry, nMask); + break; + case BRANCH_MODE_MODIFY: + ModifyEntry(list, *newList, entryIndex, entry, nMask); + break; + case BRANCH_MODE_DELETE: + RemoveEntry(list, *newList, entryIndex); + break; + } + return WFSKRN_RESULT_OK; +} + +static WFSKrnResult GetModifiedAccessList(const AreaInfo* area, WFSKrnAccessList* list, + WFSKrnAccessListEntry* entry, u32 nMask, int mode, WFSKrnAccessList** newList) +{ + WFSKrnAclHandle handle; + WFSKrnResult result; + + result = BranchAccessList(area, list, entry, nMask, mode, newList); + if (!(*newList) || (*newList) == list) + { + return result; + } + + result = WFSKrnInitializeAccessList(area, newList); + if (result != WFSKRN_RESULT_OK) + { + WFSKrnMemoryBlockFree(area, (WFSKrnAccessListBlock*) (*newList), WFSKRN_BLOCKS_IN_LIST(*newList)); + *newList = 0; + return result; + } + + handle = list->handle; + // decrement the reference count of the trunk (list). + WFSKrnAccessListFree(area, list); // reduce the reference count of the cache to zero + // before deleting an accesslist file. + WFSKrnReleaseAccessList(area, handle); + return result; +} + +WFSKrnResult WFSKrnAccessListAlloc(const AreaInfo* area, u32 numEntries, WFSKrnAccessList** newList) +{ + WFSKrnAccessList* list = NULL; + WFSKrnAccessList* freeCache; + + if (ACL_MAX_ENTRIES < numEntries) + { + return WFSKRN_RESULT_ACL_MAX_ENTRIES; + } + + while (!list) + { + list = (WFSKrnAccessList*) WFSKrnMemoryBlockAlloc(area, + (int) (sizeof(WFSKrnAccessList)/sizeof(WFSKrnAccessListBlock) + + numEntries * (sizeof(WFSKrnAccessListEntry)/sizeof(WFSKrnAccessListBlock)))); + if (list) + { + WFSKrnAccessListSetNum(list, numEntries); + list->ref = 1; + list->handle = WFSKRN_ACCESSLIST_FREEINDEX; + break; + } + + // no free memory block. + // Free an entry in the cache freelist. + if (CacheFreeListIsEmpty()) + { + WFSKRN_ACL_REPORT("WFSKrnAccessListAlloc(): cannot allocate momory blocks for the new cache. (numEntries %d)\n", numEntries); + PrintMemoryBlock(area); // debug code. + break; + } + /* [check] should wait until any list is inserted into the freelist. + while (CacheFreeListIsEmpty()) + { + // wait + } + */ + + freeCache = CacheFreeListRemoveHead(area); + if (freeCache->handle != WFSKRN_ACCESSLIST_FREEINDEX) + { + WFSKrnAccessListCacheRemove(area, freeCache); + } + WFSKrnMemoryBlockFree(area, (WFSKrnAccessListBlock*) freeCache, WFSKRN_BLOCKS_IN_LIST(freeCache)); + + WFSKRN_ACL_ASSERT(VerifyCacheList(area)); + } + + if (!list) + { + return WFSKRN_RESULT_ACL_CACHE; + } + + *newList = list; + return WFSKRN_RESULT_OK; +} + +int WFSKrnAccessListFree(const AreaInfo* area, WFSKrnAccessList* list) +{ + u32 ref = --list->ref; + if (ref == 0) + { + // insert the list into the cache freelist. + // The cache remains in the cache list. + CacheFreeListInsertTail(area, list); + // [check] NYI. notifyAll. + } + + return ref; +} + +// Remove the access list from disk if the refernce count is zero. +WFSKrnResult WFSKrnReleaseAccessList(const AreaInfo* area, WFSKrnAclHandle handle) +{ + u32 ref; + WFSKrnResult result = WFSKRN_RESULT_ACL_ERROR; + WFSKrnAccessList* cache; + + WFSKRN_ACL_ASSERT(Initialized(area) == TRUE); + + if ((handle & ACL_TYPE_MASK) == 0) + { + // index 0 is reserved for the empty accesslist. + return WFSKRN_RESULT_OK; + } + + WFSAclLockMutex(&Mutex(area)); + result = WFSKrnAccessListGetFileReferenceCount(area, handle, &ref); + if (result == WFSKRN_RESULT_OK) + { + if (ref == 1 && WFSKrnAccessListLookup(area, handle)) + { + // All caches must be closed before deleting the accesslist file. + result = WFSKRN_RESULT_ACL_CACHE; + } + else if (0 < --ref) + { + result = WFSKrnAccessListSetFileReferenceCount(area, handle, ref); + } + else + { + cache = WFSKrnAccessListLookupByIndex(area, handle); + + result = WFSKrnAccessListDeleteFile(area, handle); + if (result == WFSKRN_RESULT_OK && cache) + { + WFSKRN_ACL_ASSERT(cache->ref == 0); + WFSKRN_ACL_ASSERT(cache->handle != WFSKRN_ACCESSLIST_FREEINDEX); + WFSKrnAccessListCacheRemove(area, cache); + WFSKrnFreeAccessListIndex(area, cache->handle); + CacheFreeListInvalidate(area, cache); // set handle to WFSKRN_ACCESSLIST_FREEINDEX. + } + } + } + WFSAclUnlockMutex(&Mutex(area)); + return result; +} + +/* +static u32 GetRootPermission(const WFSKrnAccessList* list) +{ + if (IsDirectory(list)) + { + return WFS_PERM_CL_3 | WFS_PERM_DIR_FULL; + } + return WFS_PERM_CL_3 | WFS_PERM_FILE_FULL; +} + +static int SearchGroup(const WFSKrnAccessList* list, const WFSTitleId groupId, const WFSTitleId titleId) +{ + if (groupId == WFS_EVERYONE_ID) + { + return 0; + } + + // WFSAclLockMutex(&Mutex(area)); + // NYI. + // WFSAclUnlockMutex(&Mutex(area)); + + return -1; +} +*/ + +static WFSBool IsAllowed(const AreaInfo* area, WFSKrnAccessList* list, + WFSTitleId entryCreatorId, WFSTitleId titleId, u32 newPermission, u32 mask) +{ + s32 cl; + u32 reserved; + + // check mask. + if (IsDirectory(list)) + { + reserved = (u32) DP_RESERVED; + } + else + { + reserved = (u32) FP_RESERVED; + } + + if (reserved & mask) + { + return (WFSBool) FALSE; + } + + if (mask & WFS_PERM_CL_MASK) + { + // check control level. + if (ACL_GET_CL_RELATIVE(newPermission, (int*)&cl) != WFSKRN_RESULT_OK) + { + return (WFSBool) FALSE; + } + + if (entryCreatorId == titleId) + { + if (0 < cl) + { + return (WFSBool) FALSE; + } + } + else + { + if (entryCreatorId != WFS_ROOT_ID && 0 <= cl) + { + return (WFSBool) FALSE; + } + } + } + return (WFSBool) TRUE;; +} + +static WFSKrnResult SetPermission(const AreaInfo* area, WFSKrnAccessList* list, + WFSTitleId entryCreatorId, WFSTitleId titleId, u32 newPermission, u32 mask, WFSKrnAclHandle* handle) +{ + WFSKrnResult result = WFSKRN_RESULT_PERMISSION; + WFSKrnAccessList* newList; + + WFSKRN_ACL_ASSERT(VerifyList(list)); + if (IsAllowed(area, list, entryCreatorId, titleId, newPermission, mask)) + { + WFSKrnAccessListEntry newEntry; + newEntry.id = titleId; + newEntry.ecId = entryCreatorId; + newEntry.pm = newPermission; + + WFSAclLockMutex(&Mutex(area)); + result = GetModifiedAccessList(area, list, &newEntry, mask, BRANCH_MODE_SET, &newList); + WFSAclUnlockMutex(&Mutex(area)); + + if (result == WFSKRN_RESULT_OK && newList) + { + *handle = newList->handle; + CloseAccessList(area, newList); + WFSAclLockMutex(&Mutex(area)); + WFSKRN_ACL_ASSERT(VerifyList(newList)); + WFSAclUnlockMutex(&Mutex(area)); + return WFSKRN_RESULT_OK; + } + } + CloseAccessList(area, list); + WFSKRN_ACL_ASSERT(VerifyList(list)); + return result; +} + +static WFSKrnResult CheckSetParams(WFSTitleId entryCreatorId, WFSTitleId titleId) +{ + // [check] any restriction? + if (titleId == WFS_ROOT_ID) // The root always has all permissions. + { + return WFSKRN_RESULT_PERMISSION; + } + return WFSKRN_RESULT_OK; +} + +WFSKrnResult WFSKrnSetAccessList(const AreaInfo* area, WFSKrnAclHandle* handle, + u32 nFlags, u32 nMask, WFSTitleId entryCreatorId, WFSTitleId titleId) +{ + WFSKRN_ACL_ASSERT(Initialized(area) == TRUE); + + WFSKrnAccessList* list; + WFSKrnResult result = WFSKRN_RESULT_PERMISSION; + + if (CheckSetParams(entryCreatorId, titleId) == WFSKRN_RESULT_OK) + { + list = OpenAccessList(area, *handle); + if (list) + { + result = SetPermission(area, list, + entryCreatorId, titleId, nFlags, nMask, handle); + } + } + return result; +} + +static WFSKrnResult DeletePermissions(const AreaInfo* area, WFSKrnAccessList* list, + WFSTitleId entryCreatorId, WFSTitleId titleId, WFSKrnAclHandle* handle) +{ + WFSKrnResult result = WFSKRN_RESULT_PERMISSION; + WFSKrnAccessList* newList; + WFSKrnAccessListEntry entry; + + // [check] any restriction? + + entry.id = titleId; + entry.ecId = entryCreatorId; + + WFSAclLockMutex(&Mutex(area)); + result = GetModifiedAccessList(area, list, &entry, 0, BRANCH_MODE_DELETE, &newList); + WFSAclUnlockMutex(&Mutex(area)); + + if (newList) + { + *handle = newList->handle; + CloseAccessList(area, newList); + WFSAclLockMutex(&Mutex(area)); + WFSKRN_ACL_ASSERT(VerifyList(newList)); + WFSAclUnlockMutex(&Mutex(area)); + return WFSKRN_RESULT_OK; + } + result = WFSKRN_RESULT_ACL_ERROR; + CloseAccessList(area, list); + return result; +} + +WFSKrnResult WFSKrnDeletePermissions(const AreaInfo* area, + WFSKrnAclHandle* handle, WFSTitleId entryCreatorId, WFSTitleId titleId) +{ + WFSKrnAccessList* list; + WFSKrnResult result = WFSKRN_RESULT_NOT_FOUND; + + WFSKRN_ACL_ASSERT(Initialized(area) == TRUE); + + // [check] any restriction? + + list = OpenAccessList(area, *handle); + if (list) + { + result = DeletePermissions(area, list, + entryCreatorId, titleId, handle); + } + return result; +} + +static s32 GetAccessList(const AreaInfo* area, WFSKrnAclHandle handle, WFSKrnAccessList* list, + WFSAccessListEntry *pAccessList, u32 nMaxElements) +{ + s32 result; + u32 num; + int i; + WFSKrnAccessListEntry* entry; + + WFSKRN_ACL_ASSERT(Initialized(area) == TRUE); + + num = WFSKrnAccessListGetNum(list); + if (num <= nMaxElements) + { + entry = GetFirstEntry(list); + for (i = 0; i < num; ++i) + { + pAccessList->titleId = entry->id; + pAccessList->entryCreatorId = entry->ecId; + pAccessList->permissions = entry->pm; + ++pAccessList; + ++entry; + } + result = (s32) num; + } + else + { + result = (s32) WFSKRN_RESULT_ACL_BUFFER_TOO_SMALL; + } + return result; +} + +s32 WFSKrnGetAccessList(const AreaInfo* area, WFSKrnAclHandle handle, WFSAccessListEntry *pAccessList, u32 nMaxElements) +{ + s32 result; + WFSKrnAccessList* list; + + if (!area) + { + return WFSKRN_RESULT_INVALID; // [check] workaround to prevent WFSGetAccessList("/", ...) from throwing exception. + } + + list = OpenAccessList(area, handle); + if (list) + { + result = GetAccessList(area, handle, list, pAccessList, nMaxElements); + CloseAccessList(area, list); + } + else + { + result = (s32) WFSKRN_RESULT_ACL_ENTRY_NOT_FOUND; + } + WFSAclLockMutex(&Mutex(area)); + WFSKRN_ACL_ASSERT(VerifyCacheList(area)); + WFSAclUnlockMutex(&Mutex(area)); + + return result; +} + +void PrintMemoryBlock(const AreaInfo* area) +{ + WFSKrnAccessListBlock* block; + int count; + WFSKrnAccessList* list; + + block = MemoryBlockAddress(area); + while (block < MemoryBlockAddress(area) + NumMemoryBlock(area)) + { + if (block->type == WFSKRN_ACCESSLIST_FREEBLOCK) + { + count = GetFreeBlockNum(block); + WFSKRN_ACL_ASSERT(0 < count && count <= area->accessListCb->numBlock); + block += count; + + if (block->nextBlock != ACL_NO_ENTRY) + { + while (count--) + { + WFSKRN_ACL_REPORT("_"); + } + } + else + { + // allocated. + while (count--) + { + WFSKRN_ACL_REPORT("*"); + } + } + } + else + { + list = (WFSKrnAccessList*) block; + if (list->handle == WFSKRN_ACCESSLIST_FREEINDEX) + { + WFSKRN_ACL_REPORT("FFF"); + } + else + { + WFSKRN_ACL_REPORT("AAA"); + } + block += sizeof(WFSKrnAccessList)/sizeof(WFSKrnAccessListBlock); + count = WFSKrnAccessListGetNum(list) * (sizeof(WFSKrnAccessListEntry)/sizeof(WFSKrnAccessListBlock)); + WFSKRN_ACL_ASSERT(0 <= count && count <= area->accessListCb->numBlock); + block += count; + while (count--) + { + WFSKRN_ACL_REPORT("E"); + } + } + } + WFSKRN_ACL_REPORT("\n"); +} + +WFSBool VerifyMemoryBlock(const AreaInfo* area) +{ + int numFreeBlock; + WFSKrnAccessListBlock* free; + WFSBool result = (WFSBool) FALSE; + + free = FreeBlockAddress(area); + numFreeBlock = 0; + + while (free < MemoryBlockAddress(area) + NumMemoryBlock(area)) + { + if (free->type != WFSKRN_ACCESSLIST_FREEBLOCK) + { + goto VERIFY_ERROR; + } + if (NumMemoryBlock(area) < free->nextBlock) + { + goto VERIFY_ERROR; + } + if (GetFreeBlockNum(free) <= 0) + { + goto VERIFY_ERROR; + } + if (NumMemoryBlock(area) < GetFreeBlockNum(free)) + { + goto VERIFY_ERROR; + } + numFreeBlock += GetFreeBlockNum(free); + free = MemoryBlockAddress(area) + free->nextBlock; + } + result = (WFSBool) TRUE; + +VERIFY_ERROR: + return result; +} + +static WFSBool VerifyList(const WFSKrnAccessList* list) +{ + u32 numEntry = WFSKrnAccessListGetNum(list); + int i; + int j; + WFSKrnAccessListEntry* entry0 = (WFSKrnAccessListEntry*) (list+1); + for (i = 0; i < numEntry; ++i) + { + WFSKrnAccessListEntry* entry1 = (WFSKrnAccessListEntry*) (list+1); + for (j = 0; j < numEntry; ++j) + { + if (entry0 != entry1 && entry0->id == entry1->id && entry0->ecId == entry1->ecId ) + { + return (WFSBool) FALSE; + } + ++entry1; + } + ++entry0; + } + return (WFSBool) TRUE; +} + +static void DumpCache(const AreaInfo* area) +{ + WFSKrnAccessListLinkList* CacheList = &area->accessListCb->cache; + WFSKrnAccessList* list = CacheList->head; + + osTPrintf("[CacheList]->"); + while (list) + { + osTPrintf("[%08x]->", list->handle); + list = (WFSKrnAccessList*) ACL_CACHE_ADDRESS(area, list->nextBlock); + } + osTPrintf("NULL\n"); +} + +static WFSBool VerifyCacheList(const AreaInfo* area) +{ + WFSKrnAccessList* head = AccessListCache(area).head; + WFSKrnAccessList* tail = AccessListCache(area).tail; + WFSKrnAccessList* list = head; + WFSKrnAccessList* next; + + int count = 256; // [check] + WFSKRN_ACL_ASSERT(!tail || ACL_CACHE_ADDRESS(area, tail->nextBlock) == NULL); + + while (list) + { + next = (WFSKrnAccessList*) ACL_CACHE_ADDRESS(area, list->nextBlock); + if (next) + { + WFSKRN_ACL_ASSERT(next->prevBlock == ACL_CACHE_BLOCK(area, (WFSKrnAccessListBlock*) list)); + } + + if (next == head) + { + WFSKRN_ACL_REPORT("*** [Cache List] chain loop!!! *** \n"); + DumpCache(area); + return (WFSBool) FALSE; + } + list = next; + WFSKRN_ACL_ASSERT(0 < count--); + } + + head = AccessListCacheFreeList(area).head; + tail = AccessListCacheFreeList(area).tail; + list = head; + + count = 256; // [check] + WFSKRN_ACL_ASSERT(!tail || ACL_CACHE_ADDRESS(area, tail->nextFreeCacheBlock) == 0); + while (list) + { + next = (WFSKrnAccessList*) ACL_CACHE_ADDRESS(area, list->nextFreeCacheBlock); + if (next) + { + WFSKRN_ACL_ASSERT((WFSKrnAccessList*) ACL_CACHE_ADDRESS(area, next->prevFreeCacheBlock) == list); + } + if (next == head) + { + WFSKRN_ACL_REPORT("*** [Free List] chain loop!!! *** \n"); + return (WFSBool) FALSE; + } + list = next; + WFSKRN_ACL_ASSERT(0 < count--); + } + + return (WFSBool) TRUE; +} + +static void DumpListHeader(const AreaInfo* area, const WFSKrnAccessList* list) +{ + WFSKRN_ACL_REPORT("---------------- List (0x%p) ----------------\n", list); + WFSKRN_ACL_REPORT(" num 0x%x\n" + " handle 0x%x\n" + " ref 0x%x\n", list->num, list->handle, list->ref); +} + +static void DumpAcl(WFSKrnAccessListEntry* entry, u32 num) +{ + int cl; + WFSKRN_ACL_REPORT ("ID EntryCreator CL D LAA RWC\n"); + while (num--) + { + WFSKrnResult ret = ACL_GET_CL_RELATIVE(entry->pm, &cl); + WFSKRN_ACL_ASSERT( ret == WFSKRN_RESULT_OK ); + WFSKRN_ACL_REPORT("0x%08x 0x%08x [%2d] %1d %1d%1d%1d %1d%1d%1d\n", + entry->id, entry->ecId, + (ret == WFSKRN_RESULT_OK) ? cl : 0, + entry->pm & WFS_PERM_CHANGE_SIZE ? 1:0, + entry->pm & WFS_PERM_WRITE ? 1:0, + entry->pm & WFS_PERM_READ ? 1:0, + entry->pm & WFS_PERM_ADD_OR_DELETE_FILE ? 1:0, + entry->pm & WFS_PERM_ADD_OR_DELETE_SUBDIR ? 1:0, + entry->pm & WFS_PERM_LIST ? 1:0, + entry->pm & WFS_PERM_DELETE_OR_MOVE ? 1:0); + ++entry; + } + WFSKRN_ACL_REPORT("---------------------------------------------\n"); +} + +static void DumpList(const AreaInfo* area, const WFSKrnAccessList* list) +{ + u32 num; + WFSKrnAccessListEntry* entry; + + DumpListHeader(area, list); + + num = WFSKrnAccessListGetNum(list); + entry = GetFirstEntry(list); + DumpAcl(entry, num); +} + +void WFSKrnDebugPrintAccessList(const AreaInfo* area, WFSKrnAclHandle handle) +{ + WFSKrnAccessList* list; + WFSAclLockMutex(&Mutex(area)); + list = OpenAccessList(area, handle); + if (!list) + { + WFSKRN_ACL_REPORT("Error: no accesslist %x\n", handle); + return; + } + CloseAccessList(area, list); // reduce ref before dump. + DumpList(area, list); + WFSAclUnlockMutex(&Mutex(area)); +} + diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission_File.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission_File.cpp new file mode 100644 index 0000000..57c4013 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission_File.cpp @@ -0,0 +1,1073 @@ +/*---------------------------------------------------------------------------* + Project: wfsKrn + File: wfsKrn_Permission_File.cpp - Functions for permissions. + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission_File.cpp,v $ + Revision 1.24 2008/10/08 08:34:15 ueno + Fixed for WFSDEV. + + Revision 1.23 2008/08/19 08:12:23 ueno + Fixed error handling in WFSKrnAccessListCreateFile(). + + Revision 1.22 2008/08/04 04:02:27 ueno + Modified to use TransInfo. + + Revision 1.21 2008/07/23 04:17:14 ueno + Reduced memory size required for accesslist. + + Revision 1.20 2008/06/05 14:05:22 ueno + Modified to reserve accesslist index 0 as the default (empty) accesslist. + + Revision 1.19 2008/06/05 08:07:48 ueno + Revised permission APIs. + + Revision 1.18 2008/05/30 08:50:07 ueno + Cleanup. + + Revision 1.17 2008/05/28 02:12:49 ueno + Cleanup. + + Revision 1.16 2008/05/22 06:36:12 ueno + Ported permission APIs to IOP. + + Revision 1.15 2008/05/20 07:08:38 ueno + Added debug code. + + Revision 1.14 2008/05/19 11:00:04 ueno + Updated comments. + + Revision 1.13 2008/05/19 10:11:52 ueno + Revised not to use hardlink. + + Revision 1.12 2008/05/19 05:30:50 ueno + Defined accesslist meta-data types. + + Revision 1.11 2008/05/16 11:16:17 ueno + Implemented permission APIs with directory module. + + Revision 1.10 2008/05/15 13:31:54 ueno + Updated. + + Revision 1.9 2008/05/08 08:07:44 ueno + Revised AclReadFile() and AclWriteFile() to set offset. + + Revision 1.8 2008/05/06 07:40:39 ueno + Modified to support WFS (not WFSDEV) codes. + + Revision 1.7 2008/05/06 03:17:51 ueno + Added AclGetFileSize() to wrap Windows API.. + + Revision 1.6 2008/05/06 02:26:03 ueno + Fixed ifdef. + + Revision 1.5 2008/04/29 06:25:20 ueno + Cleanup. + + Revision 1.4 2008/04/25 06:22:55 ueno + Cleanup. + + Revision 1.3 2008/04/25 04:40:07 ueno + Added support for WFSDEV. + + Revision 1.26 2008/04/23 08:59:46 ueno + Replaced WFSAreaHdr by AreaInfo. + Revised directory permission (change -> add). + + Revision 1.25 2008/04/15 07:36:01 ueno + Changed return type to WFSKrnResult. + + Revision 1.24 2008/04/11 06:16:47 ueno + Defined WFSAclFileHandle. + + Revision 1.23 2008/04/08 06:39:31 ueno + Cleanup. + + Revision 1.22 2008/04/08 04:28:50 ueno + Modified to invert bits before escape sequence from accesslist content to filename. + + Revision 1.21 2008/04/03 11:40:44 ueno + Replaced accesslist index by accesslist handle. + + Revision 1.20 2008/04/03 06:35:08 ueno + Cleanup. + + Revision 1.19 2008/04/01 08:24:54 ueno + Fixed cache reference count. + + Revision 1.18 2008/03/14 08:02:53 ueno + Revised API prefixes (WFS -> WFSKrn). + + Revision 1.17 2008/03/11 12:10:41 ueno + Cleanup. + + Revision 1.16 2008/03/11 11:10:57 ueno + Moved accesslist functions into wfskrn_Permission_AccessList.cpp. + + Revision 1.15 2008/03/11 10:48:22 ueno + Cleanup. + + Revision 1.14 2008/03/11 09:51:54 ueno + Fixed EscapeAccessList() to make a filename from UTF-16 characters (0x3300-0x33ff). + + Revision 1.13 2008/03/11 06:53:06 ueno + Added WFSAccessListSetPermission() and GetPermission(). + + Revision 1.12 2008/03/07 05:32:07 ueno + Modified WFSCreateAccessList() to be able to create an accesslist for directories. + + Revision 1.11 2008/03/06 10:45:28 ueno + Added debug codes. + + Revision 1.10 2008/02/29 07:29:10 ueno + Added Windows api wrappers. + + Revision 1.9 2008/02/28 13:11:01 ueno + Revised to keep accesslist cache and indexlist handle in WFSAreaHdr{}. + + Revision 1.8 2008/02/28 07:01:52 ueno + Fixed escape sequence for accesslist filename. + + Revision 1.7 2008/02/28 04:36:32 ueno + Cleanup. + + Revision 1.6 2008/02/27 13:12:33 ueno + Revised to store a filename of an accesslist in a file (*.name). + + Revision 1.5 2008/02/27 10:05:36 ueno + Revised to use WFSAreaHdr{} to specifiy WFS area. + + Revision 1.4 2008/02/27 04:29:26 ueno + Modified WFSAccessListAddEntry() and RemoveEntry() to delete accesslist file when the reference count is zero. + + Revision 1.3 2008/02/26 14:11:43 ueno + Added WFSAccessListAddEntry() and WFSAccessListRemoveEntry() to edit accesslist. + + Revision 1.2 2008/02/25 09:43:57 ueno + Added support for accesslist cache. + + Revision 1.1 2008/02/22 05:16:14 ueno + Initial Check-in. + + +*---------------------------------------------------------------------------*/ +#include "wfs_Defs.h" +#include "wfskrn_Permission_AccessList.h" + +#ifdef WFSDEV +#include "wfskrn_Permission_Win32.h" +#else // WFSDEV +#include "wfskrn_Permission_Iop.h" +#endif // WFSDEV + +#include "wfskrn_Permission_File.h" +#include "wfskrn_Permission_Private.h" + +#include + +#define AclIndexType(x) ((x) & ~ACL_TYPE_MASK) +#define AccessListFileHeaderIndex(x) ((x).index & ACL_TYPE_MASK) + +/* + * Accesslist file + The name of an accesslist file represents the content of the accesslist (title IDs and the permissions). + + Accesslist file contains the index of the accesslist. + + - WFS + accesslist file: + +-------+ + | index | + +-------+ + + - WFSDEV + accesslist file: + +-------+ + | index | + +-------+ + + * How to access an accesslist file from the accesslist index. + - WFS and WFSDEV + accesslist index x (u32) + | + | read accesslist name file. + | + | accesslist name file: + | +-------+-------+--------------------------+ + | | num | ref | filename of accesslist x | + | +-------+-------+--------------------------+ + | + | get the filename of the accesslist file. + V + access the accesslist file. + + * How to get the filename of an accesslist. + - WFS and WFSDEV + The filename of accesslist x is kept in the file . + file: + +-------+-------+--------------------------+ + | num | ref | filename of accesslist x | + +-------+-------+--------------------------+ + +*/ + +int WFSKrnAccessListGetAclFileInfo(const AreaInfo* area, const utf8* filename, u32 type, AclFileInfo* aclFile) +{ + // memset(&aclFile->di, 0, sizeof(DirItr)); // [check] workaround. + aclFile->type = type; +#ifdef WFSDEV + utf8* ptr; + int len; + len = GetAccessListPath(area, aclFile); + if (len <= 0 || + WFSKRN_ACCESSLIST_MAX_PATH_LEN <= len) + { + return -1; + } + + ptr = aclFile->path; + ptr += len; + + switch (aclFile->type) + { + case ACL_TYPE_INDEXLIST: + case ACL_TYPE_NAMEFILE: + len = OS_SNPrintf(ptr, WFSKRN_ACCESSLIST_MAX_PATH_LEN - len, "\\"NAMEFILE_DIR"\\%s", filename); + break; + case ACL_TYPE_ACLFILE: + len = OS_SNPrintf(ptr, WFSKRN_ACCESSLIST_MAX_PATH_LEN - len, "\\%s", filename); + break; + default: + return -1; + } + + if (len <= 0) + { + return -1; + } +#else // WFSDEV + int len; + len = osSNPrintf(ACL_FILEINFO_NAME(aclFile), WFS_MAX_FILE_NAME_SIZE, "%s", filename); + if (len <= 0) + { + return -1; + } +#endif // WFSDEV + + return 0; +} + +int WFSKrnAccessListOpenList(const AreaInfo* area, const utf8* filename, AclFileInfo* aclFile, + WFSBool create, WFSAclFileHandle *pFh) +{ + WFSBool exist; + + if (WFSKrnAccessListGetAclFileInfo(area, filename, ACL_TYPE_ACLFILE, aclFile) < 0) + { + return -1; + } + + exist = AclAccessListAlreadyExist(area, aclFile); + if (!exist && !create) + { + return -1; + } + + if (AclCreateAccessListFile(area, aclFile, create, pFh) != WFS_RESULT_OK) + { + return -1; + } + + return exist ? 1 : 0; +} + +static const char* UnescapeFilename(const char* src, char* dst, int count) +{ + while (count--) + { + if (*src == ESCAPE) + { + ++src; + if (*src == ESCAPED_NULL) + { + *dst++ = 0x00; + } + else + { + *dst++ = ~*src; + } + ++src; + } + else + { + *dst++ = ~*src++; + } + } + + return src; +} + +static char* EscapeAccessList(char* buf, const char* bufEnd, void* value, u32 size) +{ + char* ptr = (char*) value; + const char* end = ptr + size; + u8 inverted; + + if (bufEnd - buf < size) + { + return NULL; + } + + + while (ptr < end) + { + inverted = ~*ptr; + if (inverted == '\0') + { + if (bufEnd < buf + 1) + { + return NULL; + } + *buf++ = ESCAPE; + *buf++ = ESCAPED_NULL; + } + else if (ESCAPE == inverted || strchr("*/?", inverted)) // [check] need not escape '*', '/' and '?'? + { + if (bufEnd < buf + 1) + { + return NULL; + } + *buf++ = ESCAPE; + *buf++ = inverted; + } + else + { + if (bufEnd < buf) + { + return NULL; + } + *buf++ = inverted; + } + ++ptr; + } + + return buf; +} + +// +// Index list +// +/* + Index list is a file. + It consists of an IndexListHeader and an array of IndexListEntry structures. + + An IndexListEntry keeps the location of an accesslist in a WFS area. + + IndexList + +----------------+ + | IndexListHeader| + +----------------+ + | IndexListEntry | the location of accesslist 0. + +----------------+ + | IndexListEntry | the location of accesslist 1. + +----------------+ + : : + : : + : : + +----------------+ + | IndexListEntry | + +----------------+ + + If the location field in an IndexListEntry{} is set to WFSKRN_ACCESSLIST_FREEINDEX, + the accesslist is free. +*/ + +static int SetIndexList(const AreaInfo* area, WFSAclFileHandle indexListHandle, int page, IndexListHeader* header, IndexListEntry* indexList, u32 listSize) +{ + WFSFileSize offset; + + if (AclWriteFile(area, indexListHandle, header, sizeof(IndexListHeader), 0) != WFS_RESULT_OK) + { + return -1; + } + + offset = WFSKRN_ACCESSLIST_INDEXES_IN_PAGE * page * sizeof(IndexListEntry) + sizeof(IndexListHeader); + if (AclWriteFile(area, indexListHandle, indexList, listSize, offset) != WFS_RESULT_OK) + { + return -1; + } + + return 0; +} + +static int CreateIndexList(const AreaInfo* area, WFSAclFileHandle* indexListHandle, AclFileInfo* indexListInfo) +{ +#ifndef WFSDEV + *indexListHandle = indexListInfo; +#endif // WFSDEV + + if (WFSKrnAccessListGetAclFileInfo(area, INDEXLIST_FILENAME, ACL_TYPE_INDEXLIST, indexListInfo) < 0) + { + return -1; + } + if (AclCreateFile(area, indexListInfo, (WFSBool) TRUE, indexListHandle) != WFS_RESULT_OK) + { + return -1; + } + return 0; +} + +int OpenIndexList(const AreaInfo* area, WFSAclFileHandle* indexListHandle, AclFileInfo* indexListInfo) +{ +#ifndef WFSDEV + *indexListHandle = indexListInfo; +#endif // WFSDEV + + if (WFSKrnAccessListGetAclFileInfo(area, INDEXLIST_FILENAME, ACL_TYPE_INDEXLIST, indexListInfo) < 0) + { + return -1; + } + if (AclCreateFile(area, indexListInfo, (WFSBool) FALSE, indexListHandle) != WFS_RESULT_OK) + { + return -1; + } + return 0; +} + +int CloseIndexList(const AreaInfo* area, WFSAclFileHandle indexListHandle) +{ + int result = -1; + if (AclCloseFile(indexListHandle) == WFS_RESULT_OK) + { + result = 0; + } +#ifdef _DEBUG + else + { + WFSKRN_ACL_REPORT("CloseIndexList() WARNING: unable to close index list.\n"); + } +#endif // _DEBUG + return result; +} + +int WFSKrnAccessListIndexListInit(const AreaInfo* area) +{ + int ret = -1; + WFSFileSize fileSize; + IndexListHeader header; + u32 index; + IndexListEntry indexList[WFSKRN_ACCESSLIST_INDEXES_IN_PAGE]; + + WFSAclFileHandle indexListHandle; + AclFileInfo indexListInfo; // [check] + + if (CreateIndexList(area, &indexListHandle, &indexListInfo) < 0) + { + return -1; + } + + if (AclGetFileSize(area, indexListHandle, &fileSize) == WFS_RESULT_OK) + { + if (fileSize == 0) + { + // create a new indexlist. + for (index = 0; index < WFSKRN_ACCESSLIST_INDEXES_IN_PAGE; ++index) + { + indexList[index].location = WFSKRN_ACCESSLIST_FREEINDEX; + } + + header.numEntry = WFSKRN_ACCESSLIST_INDEXES_IN_PAGE; + ret = SetIndexList(area, indexListHandle, 0, &header, indexList, sizeof(indexList)); + } + else + { + // [check] should verify the list? + ret = 0; // already exists. + } + } + +#ifdef WFSDEV + CloseIndexList(area, indexListHandle); +#endif // WFSDEV + return ret; +} + +int WFSKrnAccessListIndexListExit(const AreaInfo* area) +{ + // index list is closed when each access is completed. + return 0; +} + +static int SetAccessListIndex(const AreaInfo* area, WFSAclFileHandle indexListHandle, + WFSKrnAclHandle handle, const IndexListEntry* entry) +{ + WFSKRN_ACL_ASSERT(handle < WFSKRN_ACCESSLIST_INDEXES_IN_PAGE * WFSKRN_ACCESSLIST_INDEXLIST_MAX_PAGE); + WFSFileSize offset = sizeof(IndexListHeader) + handle * sizeof(IndexListEntry); + + if (AclWriteFile(area, indexListHandle, entry, sizeof(IndexListEntry), offset) == WFS_RESULT_OK) + { + return 0; + } + return -1; +} + +int GetAccessListIndex(const AreaInfo* area, WFSAclFileHandle indexListHandle, WFSKrnAclHandle handle, IndexListEntry* entry) +{ + WFSKRN_ACL_ASSERT(handle < WFSKRN_ACCESSLIST_INDEXES_IN_PAGE * WFSKRN_ACCESSLIST_INDEXLIST_MAX_PAGE); + WFSFileSize offset = sizeof(IndexListHeader) + handle * sizeof(IndexListEntry); + + if (AclReadFile(area, indexListHandle, entry, sizeof(IndexListEntry), offset) == sizeof(IndexListEntry)) + { + return 0; + } + return -1; +} + +static int GetIndexList(const AreaInfo* area, WFSAclFileHandle indexListHandle, + int page, IndexListHeader* header, IndexListEntry* indexList, u32 size) +{ + u32 offset; + + WFSKRN_ACL_ASSERT(page < WFSKRN_ACCESSLIST_INDEXLIST_MAX_PAGE); + if (header) + { + if (AclReadFile(area, indexListHandle, header, sizeof(IndexListHeader), 0) + != sizeof(IndexListHeader) || header->numEntry == 0) + { + return -1; + } + } + + if (indexList) + { + offset = WFSKRN_ACCESSLIST_INDEXES_IN_PAGE * page * sizeof(IndexListEntry) + sizeof(IndexListHeader); + if (AclReadFile(area, indexListHandle, indexList, size, offset) != (int) size) + { + return -1; + } + } + return 0; +} + +static int GetIndexListHeader(const AreaInfo* area, WFSAclFileHandle indexListHandle, IndexListHeader* header) +{ + return GetIndexList(area, indexListHandle, 0, header, NULL, 0); +} + +static int GetIndexListPage(const AreaInfo* area, WFSAclFileHandle indexListHandle, int page, IndexListEntry* indexList, u32 size) +{ + WFSKRN_ACL_ASSERT(size == sizeof(IndexListEntry) * WFSKRN_ACCESSLIST_INDEXES_IN_PAGE); + return GetIndexList(area, indexListHandle, page, NULL, indexList, size); +} + +static int AllocAccessListIndex(const AreaInfo* area, WFSAclFileHandle indexListHandle, u32 aclType, WFSKrnAclHandle* newIndex, u32 num) +{ + IndexListHeader header; + IndexListEntry* entry; + IndexListEntry indexList[WFSKRN_ACCESSLIST_INDEXES_IN_PAGE]; + u32 numEntry; + u32 page; + int pageInList; + u32 index; + + // read the header. + if (GetIndexListHeader(area, indexListHandle, &header) < 0) + { + return -1; + } + + if (num == 0) + { + // index 0 is reserved for default (empty) accesslist. + IndexListEntry entry; + entry.location = 0; + if (SetAccessListIndex(area, indexListHandle, 0, &entry) < 0) // [check] should rename? + { + return -1; + } + *newIndex = aclType; + return 0; + } + + pageInList = header.numEntry / WFSKRN_ACCESSLIST_INDEXES_IN_PAGE; + for (page = 0; page < pageInList; ++page) + { + // read a page. + if (GetIndexListPage(area, indexListHandle, page, indexList, sizeof(indexList)) < 0) + { + return -1; + } + numEntry = WFSKRN_ACCESSLIST_INDEXES_IN_PAGE; + entry = indexList; + if (page == 0) + { + numEntry--; + ++entry; // index 0 is reserved for default (empty) accesslist. + } + while (0 < numEntry--) + { + if (entry->location == WFSKRN_ACCESSLIST_FREEINDEX) + { + index = (entry - indexList) + page * WFSKRN_ACCESSLIST_INDEXES_IN_PAGE; + WFSKRN_ACL_ASSERT((aclType & index) == 0 && + (aclType | index) != WFSKRN_ACCESSLIST_FREEINDEX); + + entry->location = (aclType | index); // save aclType in location field. + + if (SetAccessListIndex(area, indexListHandle, index, entry) < 0) // [check] should rename? + { + return -1; + } + *newIndex = (aclType | index); + return 0; + } + ++entry; + } + } + + if (WFSKRN_ACCESSLIST_INDEXLIST_MAX_PAGE <= page) + { + WFSKRN_ACL_REPORT("AllocAccessListIndex() Error: no free index\n"); + return -1; + } + + // add a new page to the list. + index = header.numEntry; + WFSKRN_ACL_ASSERT((aclType & index) == 0 && + (aclType | index) != WFSKRN_ACCESSLIST_FREEINDEX); + indexList[0].location = (aclType | index); + for (numEntry = 1; numEntry < WFSKRN_ACCESSLIST_INDEXES_IN_PAGE; ++numEntry) + { + indexList[numEntry].location = WFSKRN_ACCESSLIST_FREEINDEX; + } + + header.numEntry += WFSKRN_ACCESSLIST_INDEXES_IN_PAGE; + if (SetIndexList(area, indexListHandle, page, &header, indexList, sizeof(indexList)) < 0) + { + return -1; + } + *newIndex = (aclType | index); + + return 0; +} + +int WFSKrnAllocAccessListIndex(const AreaInfo* area, u32 aclType, WFSKrnAclHandle* newIndex, u32 num) +{ + int result = -1; + int openResult; + WFSAclFileHandle indexListHandle; + AclFileInfo indexListInfo; + + openResult = OpenIndexList(area, &indexListHandle, &indexListInfo); + if (openResult == 0) + { + result = AllocAccessListIndex(area, indexListHandle, aclType, newIndex, num); + } + +#ifdef WFSDEV + if (openResult == 0) + { + CloseIndexList(area, indexListHandle); + } +#else + CloseIndexList(area, indexListHandle); // must call close() even when open() returns an error + // to release dns stack memory. +#endif + + return result; +} + +static int FreeAccessListIndex(const AreaInfo* area, WFSAclFileHandle indexListHandle, WFSKrnAclHandle handle) +{ + IndexListHeader header; + IndexListEntry entry; + + handle &= ACL_TYPE_MASK; // discard flags. + + if (handle == WFSKRN_ACCESSLIST_FREEINDEX) + { + return 0; + } + + if (GetIndexListHeader(area, indexListHandle, &header) < 0) + { + return -1; + } + + if (header.numEntry <= handle) + { + return -1; // out of range. + } + + if (GetAccessListIndex(area, indexListHandle, handle, &entry) < 0) + { + return -1; + } + + if (entry.location == WFSKRN_ACCESSLIST_FREEINDEX) + { + return 0; + } + + entry.location = WFSKRN_ACCESSLIST_FREEINDEX; + if (SetAccessListIndex(area, indexListHandle, handle, &entry) < 0) + { + return -1; + } + return 0; +} + +int WFSKrnFreeAccessListIndex(const AreaInfo* area, WFSKrnAclHandle handle) +{ + int result = -1; + int openResult; + WFSAclFileHandle indexListHandle; + AclFileInfo indexListInfo; + + openResult = OpenIndexList(area, &indexListHandle, &indexListInfo); + if (openResult == 0) + { + result = FreeAccessListIndex(area, indexListHandle, handle); + } +#ifdef WFSDEV + if (openResult == 0) + { + CloseIndexList(area, indexListHandle); + } +#else + CloseIndexList(area, indexListHandle); // must call close() even when open() returns an error + // to release dns stack memory. +#endif + + return result; +} + +// debug code. +static WFSBool VerifyList(const WFSKrnAccessList* list) +{ + u32 numEntry = WFSKrnAccessListGetNum(list); + int i; + int j; + WFSKrnAccessListEntry* entry0 = (WFSKrnAccessListEntry*) (list+1); + for (i = 0; i < numEntry; ++i) + { + WFSKrnAccessListEntry* entry1 = (WFSKrnAccessListEntry*) (list+1); + for (j = 0; j < numEntry; ++j) + { + if (entry0 != entry1 && entry0->id == entry1->id && entry0->ecId == entry1->ecId) + { + // double registration. + return (WFSBool) FALSE; + } + ++entry1; + } + ++entry0; + } + return (WFSBool) TRUE; +} + +/* + Create a filename of an accesslist by encoding + the accesslist content. + + A filename only represents title IDs, the permissions and aclType (WFSKRN_ACCESSLIST_FLAG_*). + The handle and reference count of an accesslist are written in a file. +*/ +int WFSKrnConvertAccessListToFilename(const WFSKrnAccessList* list, utf8* filename, u32 size) +{ + utf8* filenameEnd = (utf8*) ((char*) filename + (size - 1)); // reserve a byte for '\0'. + WFSKrnAccessListEntry* entry = (WFSKrnAccessListEntry*) (list+1); + u32 numEntry; + u32 aclType; + u16 pm; + + WFSKRN_ACL_ASSERT(VerifyList(list)); + numEntry = WFSKrnAccessListGetNum(list); + + while (numEntry--) + { + // [check] endian. + filename = EscapeAccessList(filename, filenameEnd, &entry->id, sizeof(u32)); + if (!filename) + { + return -1; + } + filename = EscapeAccessList(filename, filenameEnd, &entry->ecId, sizeof(u32)); + if (!filename) + { + return -1; + } + pm = (u16) (entry->pm & 0xffff); + filename = EscapeAccessList(filename, filenameEnd, &pm, sizeof(u16)); + if (!filename) + { + return -1; + } + ++entry; + } + + aclType = ACL_TYPE(list); + filename = EscapeAccessList(filename, filenameEnd, &aclType, sizeof(u32)); + if (!filename) + { + return -1; + } + *filename++ = 0; + + return 0; +} + +int WFSKrnConvertFilenameToAccessList(const utf8* filename, u32 filenameLen, WFSKrnAccessList* list) +{ + const char* src = filename; + u32 num; + u32 aclType; + WFSKrnAccessListEntry* entry; + u16 pm; + + entry = (WFSKrnAccessListEntry*) (list + 1); + num = WFSKrnAccessListGetNum(list); + while (num--) + { + src = UnescapeFilename(src, (char*) &entry->id, sizeof(u32)); + src = UnescapeFilename(src, (char*) &entry->ecId, sizeof(u32)); + src = UnescapeFilename(src, (char*) &pm, sizeof(u16)); + entry->pm = pm; + ++entry; + } + UnescapeFilename(src, (char*) &aclType, sizeof(u32)); + WFSKRN_ACL_ASSERT(!(aclType & ACL_TYPE_MASK)); + + WFSKRN_ACL_ASSERT(VerifyList(list)); + return 0; +} + +static int AclGetIndex(const AreaInfo* area, WFSAclFileHandle hFile, WFSKrnAclHandle* index) +{ + if (AclReadFile(area, hFile, index, sizeof(u32), 0) != sizeof(u32)) + { + return -1; + } + return 0; +} + +static int AclSetIndex(const AreaInfo* area, WFSAclFileHandle hFile, WFSKrnAclHandle handle) +{ + // save the index. + if (AclWriteFile(area, hFile, &handle, sizeof(WFSKrnAclHandle), 0) != WFS_RESULT_OK) + { + return -1; + } + return 0; +} + +static int AclIncrementFileRef(const AreaInfo* area, WFSKrnAclHandle index) // [check] must be global? +{ + u32 ref; + if ((index & ACL_TYPE_MASK) == 0) + { + // index 0 is reserved for the empty accesslist. + return 0; + } + + if (ReadNamefile(area, index, &ref, sizeof(u32), sizeof(u32)) < 0) + { + return -1; + } + + ++ref; + if (WriteNamefile(area, index, &ref, sizeof(u32), sizeof(u32)) < 0) + { + return -1; + } + return 0; +} + +// increment reference count of the specified accesslist if the file already exists. +// otherwise, create an accesslist file and write information in it. +int WFSKrnAccessListCreateFile(const AreaInfo* area, const utf8* filename, WFSKrnAccessList** list) +{ + int resultOpen; + int result = -1; + WFSAclFileHandle hFile; + AclNameFileHeader header; + WFSKrnAclHandle index; + AclFileInfo aclFile; + + resultOpen = WFSKrnAccessListOpenList(area, filename, &aclFile, (WFSBool) TRUE, &hFile); + if (resultOpen < 0) + { + goto WFSCREATEACCESSFILEINIT_RESULT; + } + + if (resultOpen == 1) // already exist. + { + if (AclGetIndex(area, hFile, &index) < 0 || + AclIncrementFileRef(area, index) < 0) + { + + // [check] should return fatal error? + goto WFSCREATEACCESSFILEINIT_RESULT; + } + + WFSKrnAccessList* cache = WFSKrnAccessListLookupByIndex(area, index); + if (cache) + { + WFSKRN_ACL_ASSERT(ACL_TYPE(*list) == ACL_TYPE(cache)); + // exchange. + WFSKrnMemoryBlockFree(area, (WFSKrnAccessListBlock*) (*list), WFSKRN_BLOCKS_IN_LIST(*list)); + if (cache->ref == 0) + { + // remove from the FREE cachlist. + WFSKrnAccessListCacheFreeListRemove(area, cache); + } + (*list) = cache; + ++(*list)->ref; + } + else + { + WFSKRN_ACL_ASSERT(ACL_TYPE(*list) == AclIndexType(index)); // [check] + WFSKRN_ACL_ASSERT((*list)->ref == 1); + // change list index, if no cache. + (*list)->handle = index; + WFSKrnAccessListCacheAdd(area, *list); + } + result = 1; // list was modified. + } + else + { + int ret; + // create a new file. + // (*list)->handle only contains flags at this moment. + if (WFSKrnAllocAccessListIndex(area, (*list)->handle, + &(*list)->handle, WFSKrnAccessListGetNum(*list)) < 0) + { + goto WFSCREATEACCESSFILEINIT_RESULT; + } + + if (AclSetIndex(area, hFile, (*list)->handle) < 0) + { + WFSKrnFreeAccessListIndex(area, (*list)->handle); + AclDeleteAccessListFile(area, &aclFile); // [check] must test this code. + goto WFSCREATEACCESSFILEINIT_RESULT; + } + + header.ref = 1; // note header.ref is not equal to (*list)->ref. + header.num = WFSKrnAccessListGetNum(*list); + ret = CreateNamefile(area, (*list)->handle, &header, filename); + if (ret < 0) + { + WFSKrnFreeAccessListIndex(area, (*list)->handle); + AclDeleteAccessListFile(area, &aclFile); // [check] must test this code. + goto WFSCREATEACCESSFILEINIT_RESULT; + } + WFSKrnAccessListCacheAdd(area, *list); + result = 0; + } + +WFSCREATEACCESSFILEINIT_RESULT: +#ifdef WFSDEV + if (result < 0) + { + WFSKRN_ACL_REPORT("WFSKrnAccessListCreateFile() Error %ld\n", GetLastError()); + } + if (0 <= resultOpen) + { + AclCloseFile(hFile); + } +#endif // WFSDEV + return result; +} + +int WFSKrnGetFilename(const AreaInfo* area, WFSKrnAclHandle handle, utf8* filename, u32 size) +{ + return ReadNamefile(area, handle, filename, size, sizeof(AclNameFileHeader)); +} + +WFSKrnAccessList* WFSKrnAccessListLookupFile(const AreaInfo* area, WFSKrnAclHandle handle) +{ + WFSKrnResult result; + WFSKrnAccessList* list = NULL; + AclNameFileHeader header; + utf8 filename[WFS_MAX_FILE_NAME_SIZE]; + + if (ReadNamefile(area, handle, &header, sizeof(header), 0) < 0) + { + return NULL; + } + + result = WFSKrnAccessListAlloc(area, header.num, &list); + if (result != WFSKRN_RESULT_OK) + { + return NULL; + } + list->handle = handle; // [check] set flag? + + if (WFSKrnGetFilename(area, list->handle, filename, sizeof(filename)) < 0 || + WFSKrnConvertFilenameToAccessList(filename, STRNLEN(filename, WFS_MAX_FILE_NAME_SIZE), list) < 0) + { + WFSKrnAccessListFree(area, list); + return NULL; + } + + WFSKrnAccessListCacheAdd(area, list); + return list; +} + +WFSKrnResult WFSKrnAccessListGetFileReferenceCount(const AreaInfo* area, WFSKrnAclHandle handle, u32* ref) +{ + if ((handle & ACL_TYPE_MASK) == 0) + { + // index 0 is reserved for the empty accesslist. + *ref = 1; + return WFSKRN_RESULT_OK; + } + + if (ReadNamefile(area, handle, ref, sizeof(u32), sizeof(u32))) + { + return WFSKRN_RESULT_ACL_FILE; + } + return WFSKRN_RESULT_OK; +} + +WFSKrnResult WFSKrnAccessListSetFileReferenceCount(const AreaInfo* area, WFSKrnAclHandle handle, u32 ref) +{ + if ((handle & ACL_TYPE_MASK) == 0) + { + // index 0 is reserved for the empty accesslist. + return WFSKRN_RESULT_OK; // just return. + } + + if (WriteNamefile(area, handle, &ref, sizeof(u32), sizeof(u32)) < 0) + { + return WFSKRN_RESULT_ACL_FILE; + } + return WFSKRN_RESULT_OK; +} + +WFSKrnResult WFSKrnAccessListDeleteFile(const AreaInfo* area, WFSKrnAclHandle handle) +{ + AclFileInfo aclFile; + utf8 filename[WFS_MAX_FILE_NAME_SIZE]; + + if (WFSKrnGetFilename(area, handle, filename, sizeof(filename)) < 0 || + WFSKrnAccessListGetAclFileInfo(area, filename, ACL_TYPE_ACLFILE, &aclFile) < 0) + { + return WFSKRN_RESULT_ACL_FILE; + } + + if (AclDeleteAccessListFile(area, &aclFile) != WFS_RESULT_OK || + DeleteNamefile(area, handle) < 0) + { + WFSKRN_ACL_REPORT("WFSKrnAccessListDeleteFile Error.\n"); + return WFSKRN_RESULT_ACL_FILE; + } + return WFSKRN_RESULT_OK; +} diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission_Iop.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission_Iop.cpp new file mode 100644 index 0000000..bdfaa30 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission_Iop.cpp @@ -0,0 +1,746 @@ +/*---------------------------------------------------------------------------* + Project: wfsKrn + File: wfsKrn_Permission_Iop.cpp - Functions for permissions. + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission_Iop.cpp,v $ + Revision 1.27 2008/10/10 04:05:05 kondo_masahiro + Fixed change arguments of AreaFreeBlks + + Revision 1.26 2008/10/08 23:19:54 kondo_masahiro + Added codes to access large size file data + + Revision 1.25 2008/09/24 07:33:21 ueno + Added AclHdr{} to AreaHdr{} to save configuration of accesslists in a disk. + + Revision 1.24 2008/08/27 23:19:26 paul + Added nStride to AreaAllocBlks, AreaFreeBlks + + Revision 1.23 2008/08/05 03:56:24 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.22 2008/08/04 04:02:27 ueno + Modified to use TransInfo. + + Revision 1.21 2008/07/25 16:12:49 paul + Changed nTransIdx to *pTransInfo. Changed WFSTransBlkAdr to TransBlkAdr + + Revision 1.20 2008/07/23 04:17:14 ueno + Reduced memory size required for accesslist. + + Revision 1.19 2008/07/23 02:01:09 ueno + Modified to call TransGetBlk() to set read/write flag before writing or deleting a file. + Modified to call TransUnpinBlk() instead of TransUnpinBlk3(). + + Revision 1.18 2008/07/22 04:10:44 ueno + Modified to call TransUnpinBlk3() after DirCreateAndInitBewBlk(). + + Revision 1.17 2008/07/21 23:24:48 ueno + Added debug code. + + Revision 1.16 2008/07/14 00:43:51 ueno + Revised directory initialization. + + Revision 1.15 2008/06/05 14:05:22 ueno + Modified to reserve accesslist index 0 as the default (empty) accesslist. + + Revision 1.14 2008/05/30 08:50:07 ueno + Cleanup. + + Revision 1.13 2008/05/28 02:12:49 ueno + Cleanup. + + Revision 1.12 2008/05/28 01:09:09 ueno + Added AclCheckDisk() to check acl meta-data. + + Revision 1.11 2008/05/23 06:32:08 ueno + Cleanup. + + Revision 1.10 2008/05/22 08:54:59 ueno + Fixed debug routine. + + Revision 1.9 2008/05/22 08:32:23 ueno + Fixed assert. + + Revision 1.8 2008/05/22 07:57:25 ueno + Fixed debug flag. + + Revision 1.7 2008/05/22 06:36:12 ueno + Ported permission APIs to IOP. + + Revision 1.6 2008/05/20 07:08:38 ueno + Added debug code. + + Revision 1.5 2008/05/19 10:11:52 ueno + Revised not to use hardlink. + + Revision 1.4 2008/05/19 05:30:50 ueno + Defined accesslist meta-data types. + + Revision 1.3 2008/05/16 11:16:17 ueno + Implemented permission APIs with directory module. + + Revision 1.2 2008/05/15 13:31:46 ueno + Implemented initialization using directory module. + + Revision 1.1 2008/05/06 07:38:40 ueno + Initial Check-in. + +*---------------------------------------------------------------------------*/ +#ifndef WFSDEV + +#include "wfs_Defs.h" +#include "wfskrn_Permission_AccessList.h" +#include "wfskrn_Permission_Iop.h" +#include "wfskrn_Permission_File.h" + +#include + +#define FILEHANDLE_DI(fh) ((fh)->di) +#define FILEHANDLE_TYPE(fh) ((fh)->type) +#define FILEHANDLE_NAME(fh) (&(FILEHANDLE_DI(fh).name)) + +static void AclDirIterOpen(const AreaInfo* area, DirItr* file, u32 type, TransInfo* pTransInfo) +{ + WFSBlkAdr parentBlock = 0; + switch (type) + { + case ACL_TYPE_INDEXLIST: + case ACL_TYPE_NAMEFILE: + parentBlock = NameBlock(area); + break; + case ACL_TYPE_ACLFILE: + parentBlock = AclBlock(area); + break; + default: + WFSKRN_ACL_REPORT("AclDirIterOpen(): invalid type (%u).\n", type); + WFSKRN_ACL_ASSERT(0); + return; + } + file->tba.pAreaInfo = (AreaInfo*) area; // area + file->tba.nBlkAdr = parentBlock; // parent directory + file->tba.pTransInfo = pTransInfo; + file->nBlkDepth = 0; // search from the root block. + file->ppDnsRootParent = 0; +} + +WFSResult SetFileName(WFSFileName *pFileName, const utf8 *sFileName) { + WFSKRN_ACL_ASSERT(sFileName); + u32 nStrLen = STRNLEN(sFileName, WFS_MAX_FILE_NAME_SIZE); + WFSKRN_ACL_ASSERT(nStrLen < WFS_MAX_FILE_NAME_SIZE); + pFileName->nLen = (WFSFileNameLengthType) nStrLen; + memmove(pFileName->sStr, sFileName, nStrLen+1); + return WFS_RESULT_OK; +} + +static inline WFSResult SetFileNameLen(WFSFileName *pFileName) { + u32 nStrLen = STRNLEN(pFileName->sStr, WFS_MAX_FILE_NAME_SIZE); + WFSKRN_ACL_ASSERT(nStrLen < WFS_MAX_FILE_NAME_SIZE); + pFileName->nLen = (WFSFileNameLengthType) nStrLen; + return WFS_RESULT_OK; +} + +// +// IOP Utilities +// + +static WFSKrnResult AclDirFindRaw(DirItr* pDi) +{ + return DirFind(&pDi->name, pDi, DIR_MAX_BLK_DEPTH, DIR_FIND_MODE_NORMAL); +} + +static WFSResult CreateFile(const AreaInfo* area, const AclFileInfo* fileInfo, WFSAclFileHandle fh) +{ + WFSKrnResult result; + TransInfo* pTransInfo = 0; // [check] pTransInfo must be passed from WFSSrv APIs as an argument. NYI. + + AclDirIterOpen(area, &FILEHANDLE_DI(fh), FILEHANDLE_TYPE(fh), pTransInfo); + + result = DirInsertRaw(FILEHANDLE_NAME(fh), &FILEHANDLE_DI(fh), 256 + 8); // [check] size + if (result != WFSKRN_RESULT_ALREADY_EXISTS && + result != WFSKRN_RESULT_OK) + { + return WFS_RESULT_INVALID; + } + + if (result == WFSKRN_RESULT_OK) + { + FILEHANDLE_DI(fh).pAttrHdr->file.nSize = 0; + +#ifdef _DEBUG + switch (fileInfo->type) + { + case ACL_TYPE_NAMEFILE: + case ACL_TYPE_INDEXLIST: + // must not be overwritten. + WFSKRN_ACL_ASSERT(AclBlock(area) != FILEHANDLE_DI(fh).tba.nBlkAdr); + break; + case ACL_TYPE_ACLFILE: + WFSKRN_ACL_ASSERT(NameBlock(area) != FILEHANDLE_DI(fh).tba.nBlkAdr); + break; + } +#endif // _DEBUG + } + + return WFS_RESULT_OK; +} + +static WFSResult OpenFile(const AreaInfo* area, WFSAclFileHandle fh) +{ + WFSKrnResult result; + TransInfo* pTransInfo = 0; // [check] pTransInfo must be passed from WFSSrv APIs as an argument. NYI. + + AclDirIterOpen(area, &FILEHANDLE_DI(fh), FILEHANDLE_TYPE(fh), pTransInfo); + + result = AclDirFindRaw(&FILEHANDLE_DI(fh)); + if (result != WFSKRN_RESULT_DIR_ENTRY_FOUND) + { + WFSKRN_ACL_ASSERT(result == WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND || + result == WFSKRN_RESULT_DIR_NODE_STRING_MISMATCH); + return WFS_RESULT_NOT_FOUND; + } + return WFS_RESULT_OK; +} + +static WFSResult CloseFile(WFSAclFileHandle fh) +{ + DirItrClose(&FILEHANDLE_DI(fh)); // [check] error handling. + return WFS_RESULT_OK; +} + +static WFSResult DeleteFile(const AreaInfo* area, WFSAclFileHandle fh) +{ + WFSResult result; + result = OpenFile(area, fh); + if (result == WFS_RESULT_OK) + { + TransGetBlk(&FILEHANDLE_DI(fh).tba, TRANS_FLAG_RW_BLK, 0); // set read/write before delete. // [check] error handling. + result = (WFSResult) DirDeleteEntry(&FILEHANDLE_DI(fh)); + } + CloseFile(fh); + + return result; +} + +static int GetNamefile(const AreaInfo* area, WFSKrnAclHandle handle, AclFileInfo* fileInfo, WFSAclFileHandle* pFh) +{ + int ret; + fileInfo->type = ACL_TYPE_NAMEFILE; + ret = osSNPrintf(ACL_FILEINFO_NAME(fileInfo), ACL_NAMEFILE_LEN, "%08x", handle); + if (ret <= 0 || ACL_NAMEFILE_LEN < ret) + { + return -1; + } + + // set file handle. + *pFh = fileInfo; + FILEHANDLE_TYPE(*pFh) = ACL_TYPE_NAMEFILE; + return 0; +} + +int CreateNamefile(const AreaInfo* area, WFSKrnAclHandle handle, const AclNameFileHeader* header, const utf8* filename) +{ + WFSAclFileHandle fh; + AclFileInfo aclFile; + + if (GetNamefile(area, handle, &aclFile, &fh) < 0) + { + return -1; + } + + if (AclCreateFile(area, &aclFile, (WFSBool) TRUE, &fh) != WFS_RESULT_OK) + { + return -1; + } + + if (AclWriteFile(area, fh, header, sizeof(AclNameFileHeader), 0) != WFS_RESULT_OK) + { +#ifdef WIN32 + WFSKRN_ACL_REPORT("CreateNamefile(%d) Error %ld\n", handle, GetLastError()); +#endif // WIN32 + return -1; + } + + if (AclWriteFile(area, fh, filename, STRNLEN(filename, WFS_MAX_FILE_NAME_SIZE)+1, sizeof(AclNameFileHeader)) != WFS_RESULT_OK) + { +#ifdef WIN32 + WFSKRN_ACL_REPORT("CreateNamefile(%d) Error %ld\n", handle, GetLastError()); +#endif // WIN32 + return -1; + } + return 0; +} + +int ReadNamefile(const AreaInfo* area, WFSKrnAclHandle handle, void* buf, WFSFileSize size, WFSFileSize offset) +{ + WFSAclFileHandle fh; + AclFileInfo aclFile; + + if ((handle & ACL_TYPE_MASK) == 0) + { + handle = 0; // handle 0 represents both file 0 and directory 0x80000000. + } + if (GetNamefile(area, handle, &aclFile, &fh) < 0) + { + return -1; + } + SetFileNameLen(FILEHANDLE_NAME(fh)); + if (AclReadFile(area, fh, buf, size, offset) < 0) + { + return -1; + } + return 0; +} + +int WriteNamefile(const AreaInfo* area, WFSKrnAclHandle handle, const void* buf, WFSFileSize size, WFSFileSize offset) +{ + WFSAclFileHandle fh; + AclFileInfo aclFile; + if (GetNamefile(area, handle, &aclFile, &fh) < 0) + { + return -1; + } + SetFileNameLen(FILEHANDLE_NAME(fh)); + if (AclWriteFile(area, fh, buf, size, offset) < 0) + { + return -1; + } + return 0; +} + +int DeleteNamefile(const AreaInfo* area, WFSKrnAclHandle handle) +{ + WFSAclFileHandle fh; + AclFileInfo aclFile; + if (GetNamefile(area, handle, &aclFile, &fh) < 0) + { + return -1; + } + SetFileNameLen(FILEHANDLE_NAME(fh)); + if (DeleteFile(area, fh) != WFS_RESULT_OK) + { +#ifdef WIN32 + WFSKRN_ACL_REPORT("DeleteNamefile(%d) Error %ld\n", handle, GetLastError()); +#endif // WIN32 + return -1; + } + return 0; +} + +/* + * WFSKrnAccessListDirectoryInit() allocates blocks, which contain + * an indexlist, accesslist files and accesslist name files (). + */ + +int WFSKrnAccessListDirectoryInit(AreaInfo* area) +{ + DirBlkHdr* pDbh; + TransBlkAdr tba; + WFSKrnResult ret; + TransInfo* pTransInfo = 0; // [check] transInfo muset be passed from WFSSrvAPIs. NYI. + + // [check] how to check if acl and name blocks already exist in the area? + + // allocate a disk block for acl directory. + ret = AreaAllocBlks((AreaInfo*) area, 0, area->ah.nLog2BlkSize, 1, &AclBlock(area), sizeof(WFSBlkAdr)); + if (ret != WFSKRN_RESULT_OK) + { + return -1; + } + + // allocate a disk block for name directory. + ret = AreaAllocBlks((AreaInfo*) area, 0, area->ah.nLog2BlkSize, 1, &NameBlock(area), sizeof(WFSBlkAdr)); + if (ret != WFSKRN_RESULT_OK) + { + AreaFreeBlks((AreaInfo*) area, area->ah.nLog2BlkSize, 1, &AclBlock(area), sizeof(WFSBlkAdr)); + return -1; + } + + // initialize acl directory. + tba.pAreaInfo = (AreaInfo*) area; + tba.nBlkAdr = AclBlock(area); + tba.pTransInfo = pTransInfo; + + WFSKrnReturnOnError( DirCreateAndInitNewBlk(&tba, (WFSMetaDataFlags)(WFS_MDF_DIR_LEAF_BLK | WFS_MDF_DIR_ROOT_BLK), &pDbh) ); + DirBlkCreateRootNode(pDbh); + ret = TransUnpinBlk(&tba); + if (ret != WFSKRN_RESULT_OK) + { + return -1; + } + + // initialize name directory. + tba.pAreaInfo = (AreaInfo*) area; + tba.nBlkAdr = NameBlock(area); + tba.pTransInfo = pTransInfo; + + WFSKrnReturnOnError( DirCreateAndInitNewBlk(&tba, (WFSMetaDataFlags)(WFS_MDF_DIR_LEAF_BLK | WFS_MDF_DIR_ROOT_BLK), &pDbh) ); + DirBlkCreateRootNode(pDbh); + ret = TransUnpinBlk(&tba); + if (ret != WFSKRN_RESULT_OK) + { + return -1; + } + + return 0; +} + +// +// Wrapper +// + +WFSResult AclGetFileSize(const AreaInfo* area, WFSAclFileHandle fh, WFSFileSize* fileSize) +{ + WFSResult result = OpenFile(area, fh); + if (result == WFS_RESULT_OK) + { + // [check] file? + *fileSize = FILEHANDLE_DI(fh).pAttrHdr->file.nSize; + } + CloseFile(fh); + return result; +} + +WFSResult AclWriteFile(const AreaInfo* area, WFSAclFileHandle fh, const void *pFileData, WFSFileSize nSize, WFSFileSize offset) +{ + WFSResult result = WFS_RESULT_INVALID; + WFSKrnResult ret; + DirFilePos fpos; + + if (OpenFile(area, fh) == WFS_RESULT_OK) + { + if (nSize + offset <= FILEHANDLE_DI(fh).pAttrHdr->nAllocSize) + { + TransGetBlk(&FILEHANDLE_DI(fh).tba, TRANS_FLAG_RW_BLK, 0); // set read/write. // [check] error handling. + ret = DirFindFilePos(&FILEHANDLE_DI(fh), offset, &fpos, TRANS_FLAG_RW_BLK); + WFSKRN_ACL_ASSERT(ret == WFSKRN_RESULT_OK); + memcpy(fpos.pDataPtr, pFileData, nSize); + + if (FILEHANDLE_DI(fh).pAttrHdr->file.nSize < nSize + offset) + { + FILEHANDLE_DI(fh).pAttrHdr->file.nSize = nSize + offset; + } + result = WFS_RESULT_OK; + } + } + CloseFile(fh); + +#ifdef _DEBUG + if (result == WFS_RESULT_OK) + { + // [check] for debug. + WFSResult result; + + result = OpenFile(area, fh); + WFSKRN_ACL_ASSERT(result == WFS_RESULT_OK); + CloseFile(fh); + + if (nSize == sizeof(u32)) + { + u32 buf; + AclReadFile(area, fh, &buf, sizeof(u32), offset); + WFSKRN_ACL_ASSERT(buf == *((u32*) pFileData)); + } + } +#endif // DEBUG + return result; +} + +s32 AclReadFile(const AreaInfo* area, WFSAclFileHandle fh, void *pFileDataBuffer, s32 nSize, WFSFileSize offset) +{ + s32 result = -1; + WFSKrnResult ret; + DirFilePos fpos; + + if (OpenFile(area, fh) == WFS_RESULT_OK) + { + if (offset < FILEHANDLE_DI(fh).pAttrHdr->nAllocSize) + { + ret = DirFindFilePos(&FILEHANDLE_DI(fh), offset, &fpos, TRANS_FLAG_READ_BLK); + WFSKRN_ACL_ASSERT(ret == WFSKRN_RESULT_OK); + + if (FILEHANDLE_DI(fh).pAttrHdr->file.nSize < offset) + { + result = 0; + } + else + { + if (FILEHANDLE_DI(fh).pAttrHdr->file.nSize < nSize + offset) + { + nSize = FILEHANDLE_DI(fh).pAttrHdr->file.nSize - offset; + } + memcpy(pFileDataBuffer, fpos.pDataPtr, nSize); + result = nSize; + } + } + } + CloseFile(fh); + +#ifdef _DEBUG + if (0 <= result) + { + // [check] for debug. + WFSResult result; + result = OpenFile(area, fh); + WFSKRN_ACL_ASSERT(result == WFS_RESULT_OK); + CloseFile(fh); + } +#endif // DEBUG + + return result; +} + +WFSResult AclCreateAccessListFile(const AreaInfo* area, + const AclFileInfo* aclFile, WFSBool create, WFSAclFileHandle *pFh) +{ + WFSKRN_ACL_ASSERT(aclFile->type == ACL_TYPE_ACLFILE); + + *pFh = (WFSAclFileHandle) aclFile; + FILEHANDLE_TYPE(*pFh) = ACL_TYPE_ACLFILE; + return AclCreateFile(area, aclFile, create, pFh); +} + +WFSResult AclCreateFile(const AreaInfo* area, const AclFileInfo* fileInfo, WFSBool create, WFSAclFileHandle *pFh) +{ + if (!create && (AclAccessListAlreadyExist(area, fileInfo) == (WFSBool) TRUE)) + { + return WFS_RESULT_OK; + } + + SetFileNameLen(FILEHANDLE_NAME(*pFh)); + if (CreateFile(area, fileInfo, *pFh) != WFS_RESULT_OK) + { + CloseFile(*pFh); + return WFS_RESULT_INVALID; + } + CloseFile(*pFh); + +#ifdef _DEBUG + { + // [check] for debug. + WFSResult result; + result = OpenFile(area, *pFh); + WFSKRN_ACL_ASSERT(result == WFS_RESULT_OK); + CloseFile(*pFh); + } +#endif // _DEBUG + + return WFS_RESULT_OK; +} + +WFSResult AclDeleteAccessListFile(const AreaInfo* area, const AclFileInfo* aclFile) +{ + WFSResult result; + WFSAclFileHandle fh = (WFSAclFileHandle) aclFile; + FILEHANDLE_TYPE(fh) = aclFile->type; + + SetFileNameLen(FILEHANDLE_NAME(fh)); + result = DeleteFile(area, fh); + if (result != WFS_RESULT_OK) + { + WFSKRN_ACL_REPORT("AclDeleteAccessListFile(%d) Error %d\n", result); + return WFS_RESULT_INVALID; // [check] error code. + } + return WFS_RESULT_OK; +} + +WFSResult AclCloseFile(WFSAclFileHandle fh) +{ + return CloseFile(fh); +} + +WFSBool AclAccessListAlreadyExist(const AreaInfo* area, const AclFileInfo* aclFile) +{ + WFSResult ret; + WFSAclFileHandle fh = (WFSAclFileHandle) aclFile; + FILEHANDLE_TYPE(fh) = aclFile->type; + + SetFileNameLen(FILEHANDLE_NAME(fh)); + + ret = OpenFile(area, fh); + CloseFile(fh); + if (ret == WFS_RESULT_OK) + { + return (WFSBool) TRUE; + } + return (WFSBool) FALSE; +} + +#ifdef _DEBUG + +s32 AclGetNumDirEntry(const AreaInfo* area, WFSBlkAdr block) +{ + WFSKrnResult result; + s32 num = 0; + DirItr di; + + SetFileName(&di.name, ""); + + di.tba.pAreaInfo = (AreaInfo*) area; // area + di.tba.nBlkAdr = block; // parent directory + di.tba.pTransInfo = 0; // used for journaling. + di.nBlkDepth = 0; // search from the root block. + di.ppDnsRootParent = 0; + + result = DirFind(&di.name, &di, DIR_MAX_BLK_DEPTH, + DIR_FIND_MODE_PREFIX_SEARCH); + + while (result == WFSKRN_RESULT_OK) + { + ++num; + result = DirNextRaw(&di.name, &di); + } + DirItrClose(&di); + + if (result != WFSKRN_RESULT_NOT_FOUND && + result != WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND) + { + // unexpected error. + num = (s32) result; + } + return num; +} + +s32 AclDirList(const AreaInfo* area, WFSBlkAdr block) +{ + WFSKrnResult result; + s32 num = 0; + DirItr di; + + SetFileName(&di.name, ""); + + di.tba.pAreaInfo = (AreaInfo*) area; // area + di.tba.nBlkAdr = block; // parent directory + di.tba.pTransInfo = 0; // used for journaling. + di.nBlkDepth = 0; // search from the root block. + di.ppDnsRootParent = 0; + + result = DirFind(&di.name, &di, DIR_MAX_BLK_DEPTH, + DIR_FIND_MODE_PREFIX_SEARCH); + + while (result == WFSKRN_RESULT_OK) + { + ++num; + if (block == NameBlock(area)) + { + osTPrintf("%s\n", di.name.sStr); + } + else + { + utf8* p = di.name.sStr; + int count = (int) STRNLEN(p, WFS_MAX_FILE_NAME_SIZE); + while (count--) + { + osTPrintf("%02x", (u8) *p++); + } + osTPrintf("\n"); + } + result = DirNextRaw(&di.name, &di); + } + DirItrClose(&di); + + if (result != WFSKRN_RESULT_NOT_FOUND && + result != WFSKRN_RESULT_DIR_NODE_CHOICE_NOT_FOUND) + { + // unexpected error. + num = (s32) result; + } + return num; +} + +WFSKrnResult AclCheckDisk(const AreaInfo* area) +{ + WFSKrnAclHandle handle; + IndexListEntry entry; + int ret; + int i; + WFSKrnResult result; + int num; + AclFileInfo aclFile; + + WFSAclFileHandle indexListHandle; + AclFileInfo indexListInfo; + + if (OpenIndexList(area, &indexListHandle, &indexListInfo) < 0) + { + return WFSKRN_RESULT_ACL_FILE; + } + + num = 0; + for (i = 0; i < WFSKRN_ACCESSLIST_INDEXLIST_MAX_PAGE * WFSKRN_ACCESSLIST_INDEXES_IN_PAGE; ++i) + { + handle = (WFSKrnAclHandle) i; + ret = GetAccessListIndex(area, indexListHandle, handle, &entry); + if (ret < 0) + { + break; + } + if (entry.location != WFSKRN_ACCESSLIST_FREEINDEX) + { + AclNameFileHeader header; + if (ReadNamefile(area, handle, &header, sizeof(header), 0) < 0) + { + result = WFSKRN_RESULT_NOT_FOUND; + goto CHECK_DISK_ERROR; + } + if (ReadNamefile(area, handle, ACL_FILEINFO_NAME(&aclFile), WFS_MAX_FILE_NAME_SIZE, sizeof(AclNameFileHeader)) < 0) + { + result = WFSKRN_RESULT_ACL_FILENAME; + goto CHECK_DISK_ERROR; + } + aclFile.type = ACL_TYPE_ACLFILE; + if (!AclAccessListAlreadyExist(area, &aclFile)) + { + result = WFSKRN_RESULT_ACL_FILE; + goto CHECK_DISK_ERROR; + } + ++num; + } + else + { + AclNameFileHeader header; + if (ReadNamefile(area, handle, &header, sizeof(header), 0) == 0) + { + result = WFSKRN_RESULT_ALREADY_EXISTS; + goto CHECK_DISK_ERROR; + } + } + } + + if (AclGetNumDirEntry(area, AclBlock(area)) != num) + { + result = WFSKRN_RESULT_ACL_ACLDIR_INCONSISTENT; + goto CHECK_DISK_ERROR; + } + if (AclGetNumDirEntry(area, NameBlock(area)) != num + 1) + { + result = WFSKRN_RESULT_ACL_NAMEDIR_INCONSISTENT; + goto CHECK_DISK_ERROR; + } + + CloseIndexList(area, indexListHandle); + return WFSKRN_RESULT_OK; + +CHECK_DISK_ERROR: + + /* [check] debug code. + osTPrintf("--------- Acl Directory ----------\n"); + AclDirList(area, AclBlock(area)); + osTPrintf("--------- Name file directory ----------\n"); + AclDirList(area, nameBlock(area)); + osTPrintf("\n"); + */ + + CloseIndexList(area, indexListHandle); + return result; +} +#endif // _DEBUG + +#endif // ifndef WFSDEV diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission_Win32.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission_Win32.cpp new file mode 100644 index 0000000..5cf0d79 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Permission_Win32.cpp @@ -0,0 +1,610 @@ +/*---------------------------------------------------------------------------* + Project: wfsKrn + File: wfsKrn_Permission.cpp - Functions for permissions. + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Permission_Win32.cpp,v $ + Revision 1.13 2008/09/24 07:33:21 ueno + Added AclHdr{} to AreaHdr{} to save configuration of accesslists in a disk. + + Revision 1.12 2008/06/24 18:20:00 ueno + Modified to reserve accesslist index 0 as the default (empty) accesslist. + + Revision 1.11 2008/05/19 10:11:52 ueno + Revised not to use hardlink. + + Revision 1.10 2008/05/19 05:30:50 ueno + Defined accesslist meta-data types. + + Revision 1.9 2008/05/15 13:31:54 ueno + Updated. + + Revision 1.8 2008/05/08 08:07:44 ueno + Revised AclReadFile() and AclWriteFile() to set offset. + + Revision 1.7 2008/05/06 03:17:57 ueno + Added AclGetFileSize() to wrap Windows API.. + + Revision 1.6 2008/05/06 02:26:03 ueno + Fixed ifdef. + + Revision 1.5 2008/04/29 06:25:20 ueno + Cleanup. + + Revision 1.4 2008/04/25 07:49:17 ueno + Cleanup. + + Revision 1.3 2008/04/25 06:22:55 ueno + Cleanup. + + Revision 1.2 2008/04/25 04:40:07 ueno + Added support for WFSDEV. + + Revision 1.20 2008/04/23 08:59:46 ueno + Replaced WFSAreaHdr by AreaInfo. + Revised directory permission (change -> add). + + Revision 1.19 2008/04/11 06:16:47 ueno + Defined WFSAclFileHandle. + + Revision 1.18 2008/04/08 06:39:31 ueno + Cleanup. + + Revision 1.17 2008/04/07 09:19:21 ueno + Modified WFSKrnAccessListDirectoryInit() to return an integer. + + Revision 1.16 2008/04/03 11:40:43 ueno + Replaced accesslist index by accesslist handle. + + Revision 1.15 2008/03/19 10:17:38 ueno + Fixed Win32 content <-> filename conversion. + + Revision 1.14 2008/03/14 08:02:53 ueno + Revised API prefixes (WFS -> WFSKrn). + + Revision 1.13 2008/03/11 11:10:57 ueno + Moved accesslist functions into wfskrn_Permission_AccessList.cpp. + + Revision 1.12 2008/03/11 10:48:22 ueno + Cleanup. + + Revision 1.11 2008/03/11 09:51:54 ueno + Fixed EscapeAccessList() to make a filename from UTF-16 characters (0x3300-0x33ff). + + Revision 1.10 2008/03/11 06:53:06 ueno + Added WFSAccessListSetPermission() and GetPermission(). + + Revision 1.9 2008/03/07 05:32:07 ueno + Modified WFSCreateAccessList() to be able to create an accesslist for directories. + + Revision 1.8 2008/03/06 10:45:28 ueno + Added debug codes. + + Revision 1.7 2008/02/29 07:29:10 ueno + Added Windows api wrappers. + + Revision 1.6 2008/02/28 13:11:01 ueno + Revised to keep accesslist cache and indexlist handle in WFSAreaHdr{}. + + Revision 1.5 2008/02/28 04:36:32 ueno + Cleanup. + + Revision 1.4 2008/02/27 13:12:32 ueno + Revised to store a filename of an accesslist in a file (*.name). + + Revision 1.3 2008/02/27 11:17:41 ueno + Cleanup. + + Revision 1.2 2008/02/27 10:05:36 ueno + Revised to use WFSAreaHdr{} to specifiy WFS area. + + Revision 1.1 2008/02/22 05:16:14 ueno + Initial Check-in. + + +*---------------------------------------------------------------------------*/ +#include "wfs_Defs.h" +#include "wfskrn_Permission_AccessList.h" +#include "wfskrn_Permission_Win32.h" +#include "wfskrn_Permission_File.h" + +// +// Win32 Utilities +// +#if _WIN32 +#ifdef WFSDEV + +#include "wfsDev/wfsdev_api.h" +#include + +WFSBool AlreadyExist(const LPWSTR path) +{ + DWORD attr = GetFileAttributesW(path); + if (attr != -1) + { + return TRUE; + } + return FALSE; +} + +// source string must be null-terminated. +int AclUtf8ToWchar(const utf8* utf8, LPWSTR wPath, u32 bytes) +{ + int ret; + if (bytes < sizeof(LONGPATH_PREFIX) + sizeof(WCHAR)) + { + return -1; + } + + u32 maxWchar = bytes/sizeof(WCHAR); + int prefixLen = 0; + // add prefix \\?\ to enable long pathname. + prefixLen = _snwprintf(wPath, maxWchar, L"%s", LONGPATH_PREFIX); + if (prefixLen < 0) + { + return -1; + } + + wPath += prefixLen; + maxWchar -= prefixLen; + + ret = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wPath, maxWchar); + if (0 < ret) + { + return ret + prefixLen; + } + WFSKRN_ACL_REPORT("Utf8ToWchar() Error %ld\n", GetLastError()); + return -1; +} + +// source string must be null-terminated. +int AclWcharToUtf8(const LPWSTR wPath, utf8* utf8, u32 bytes) +{ + size_t count = wcslen(LONGPATH_PREFIX); + if (wcsncmp(wPath, LONGPATH_PREFIX, count) != 0) + { + count = 0; + } + + int ret = WideCharToMultiByte(CP_UTF8, 0, wPath + count, -1, utf8, bytes, 0, 0); + if (0 < ret) + { + return ret; + } + WFSKRN_ACL_REPORT("WcharToUtf8() Error %ld\n", GetLastError()); + return -1; +} + +// Get the directory which contains accesslists. +int GetAccessListPath(const AreaInfo* area, AclFileInfo* aclFile) +{ + WFSResult result = wfsdev_api::_getAccessListFolder(aclFile->path, area); + if (WFS_RESULT_OK == result) + { + WFSKRN_ACL_ASSERT(strlen(aclFile->path) < WFSKRN_ACCESSLIST_MAX_PATH_LEN); + return strlen(aclFile->path); + } + return -1; +} + +// convert to little endian UTF-16 for Windows. +static int ConvertToUTF16(const utf8* accessListName, LPWSTR wPath, u32 size) +{ + const utf8* src = accessListName; + utf8* p = (utf8*) wPath; + const utf8* tail = p + size; + WFSKRN_ACL_ASSERT(2 < size); + + while (*src && (p < tail - 2)) + { + if (*src == ESCAPE) + { + *p++ = ESCAPE; + *p++ = ESCAPE; + *p++ = *(src+1); + *p++ = ESCAPE; + src += 2; + } + else + { + *p++ = *src++; + *p++ = ESCAPE; + } + } + + if (tail <= p + 2) + { + return -1; + } + *p++ = 0; + *p++ = 0; + + return 0; +} + +int Utf8ToWcharAccessList(const AreaInfo* area, const utf8* path, LPWSTR wPath, u32 wPathLen) +{ + AclFileInfo dir; + u32 dirLen; + int len; + + if (WFSKrnAccessListGetAclFileInfo(area, "", ACL_TYPE_ACLFILE, &dir) < 0) + { + return -1; + } + + dirLen = strlen(dir.path); + if (memcmp(path, dir.path, dirLen) != 0) + { + return -1; + } + + len = AclUtf8ToWchar(dir.path, wPath, wPathLen); + if (len <= 0) + { + return -1; + } + + if (ConvertToUTF16(&path[dirLen], &wPath[len-1], wPathLen - len) < 0) + { + return -1; + } + + return 0; +} + +static int GetLinkFilename(const AreaInfo* area, WFSKrnAclHandle handle, LPWSTR linkFile) +{ + utf8 filename[WFSKRN_ACCESSLIST_MAX_PATH_LEN]; + AclFileInfo fileInfo; + _snprintf(filename, sizeof(filename), "%x", handle); + + if (WFSKrnAccessListGetAclFileInfo(area, filename, ACL_TYPE_NAMEFILE, &fileInfo) < 0) + { + return -1; + } + + if (AclUtf8ToWchar(fileInfo.path, linkFile, WFSKRN_ACCESSLIST_MAX_PATH_LEN) < 0) + { + return -1; + } + return 0; +} + +static int GetNamefile(const AreaInfo* area, WFSKrnAclHandle handle, LPWSTR nameFile) +{ + utf8 name[WFS_MAX_FILE_NAME_SIZE]; + AclFileInfo fileInfo; + _snprintf(name, sizeof(name), "%08x", handle); + + if (WFSKrnAccessListGetAclFileInfo(area, name, ACL_TYPE_NAMEFILE, &fileInfo) < 0 || + AclUtf8ToWchar(fileInfo.path, nameFile, WFSKRN_ACCESSLIST_MAX_PATH_LEN) < 0) + { + return -1; + } + return 0; +} + +int CreateNamefile(const AreaInfo* area, WFSKrnAclHandle handle, const AclNameFileHeader* header, const utf8* filename) +{ + WCHAR wPath[WFSKRN_ACCESSLIST_MAX_PATH_LEN]; + WFSAclFileHandle hFile; + DWORD written; + + if (GetNamefile(area, handle, wPath) < 0) + { + return -1; + } + + hFile = CreateFileW(wPath, GENERIC_READ | GENERIC_WRITE, 0, + NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + return -1; + } + + if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER || + WriteFile(hFile, header, sizeof(AclNameFileHeader), &written, NULL) == 0 || + sizeof(AclNameFileHeader) != written) + { + WFSKRN_ACL_REPORT("CreateNamefile(%d) Error %ld\n", handle, GetLastError()); + CloseHandle(hFile); + return -1; + } + + if (SetFilePointer(hFile, sizeof(AclNameFileHeader), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER || + WriteFile(hFile, filename, strlen(filename)+1, &written, NULL) == 0 || + strlen(filename)+1 != written) + { + WFSKRN_ACL_REPORT("CreateNamefile(%d) Error %ld\n", handle, GetLastError()); + CloseHandle(hFile); + return -1; + } + CloseHandle(hFile); + + return 0; +} + +int ReadNamefile(const AreaInfo* area, WFSKrnAclHandle handle, void* buf, WFSFileSize size, WFSFileSize offset) +{ + WCHAR wPath[WFSKRN_ACCESSLIST_MAX_PATH_LEN]; + WFSAclFileHandle hFile; + DWORD bytesRead; + + if ((handle & ACL_TYPE_MASK) == 0) + { + handle = 0; // handle 0 represents both file 0 and directory 0x80000000. + } + if (GetNamefile(area, handle, wPath) < 0) + { + return -1; + } + + hFile = CreateFileW(wPath, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + return -1; + } + + if (SetFilePointer(hFile, offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER || + !ReadFile(hFile, buf, size, &bytesRead, NULL)) + { + WFSKRN_ACL_REPORT("ReadNamefile(%d) Error %ld\n", handle, GetLastError()); + CloseHandle(hFile); + return -1; + } + CloseHandle(hFile); + + return 0; +} + +int WriteNamefile(const AreaInfo* area, WFSKrnAclHandle handle, const void* buf, WFSFileSize size, WFSFileSize offset) +{ + WCHAR wPath[WFSKRN_ACCESSLIST_MAX_PATH_LEN]; + WFSAclFileHandle hFile; + DWORD written; + + if (GetNamefile(area, handle, wPath) < 0) + { + return -1; + } + + hFile = CreateFileW(wPath, GENERIC_WRITE, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + return -1; + } + + if (SetFilePointer(hFile, offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER || + WriteFile(hFile, buf, size, &written, NULL) == 0 || written != size) + { + WFSKRN_ACL_REPORT("WriteNamefile(%d) Error %ld\n", handle, GetLastError()); + CloseHandle(hFile); + return -1; + } + CloseHandle(hFile); + + return 0; +} + +int DeleteNamefile(const AreaInfo* area, WFSKrnAclHandle handle) +{ + WCHAR wPath[WFSKRN_ACCESSLIST_MAX_PATH_LEN]; + + if (GetNamefile(area, handle, wPath) < 0) + { + return -1; + } + + if (!DeleteFileW(wPath)) + { + WFSKRN_ACL_REPORT("DeleteNamefile(%d) Error %ld\n", handle, GetLastError()); + return -1; + } + + return 0; +} + +static int CreateNameDir(const AreaInfo* area) +{ + WCHAR wPath[WFSKRN_ACCESSLIST_MAX_PATH_LEN]; + AclFileInfo fileInfo; + + if (WFSKrnAccessListGetAclFileInfo(area, "", ACL_TYPE_NAMEFILE, &fileInfo) < 0) + { + return -1; + } + + if (AclUtf8ToWchar(fileInfo.path, wPath, WFSKRN_ACCESSLIST_MAX_PATH_LEN) < 0) + { + return -1; + } + + if (CreateDirectoryW(wPath, 0)) + { + return 0; + } + + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + return 0; + } + return -1; +} + +int WFSKrnAccessListDirectoryInit(AreaInfo* area) +{ + WFSResult result = _createAccessListFolder( area ); + if (result != WFS_RESULT_OK) + { + return -1; + } + return CreateNameDir(area); +} + +// +// Wrapper +// +WFSResult AclGetFileSize(const AreaInfo* area, WFSAclFileHandle fh, WFSFileSize* fileSize) +{ + DWORD size = GetFileSize(fh, NULL); + if (size < 0) + { + return WFS_RESULT_INVALID; // [check] + } + *fileSize = (WFSFileSize) size; + return WFS_RESULT_OK; +} + +WFSResult AclWriteFile(const AreaInfo* area, WFSAclFileHandle fh, const void *pFileData, WFSFileSize nSize, WFSFileSize offset) +{ + DWORD written; + if (SetFilePointer(fh, (u32) offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + { + WFSKRN_ACL_REPORT("SetFilePointer: Error %ld\n", GetLastError()); + return WFS_RESULT_INVALID; + } + + if (WriteFile(fh, pFileData, nSize, &written, NULL) == 0 || written != nSize) + { + WFSKRN_ACL_REPORT("WFSKrnAccessListWriteFile(): Error %ld\n", GetLastError()); + return WFS_RESULT_INVALID; // [check] error code. + } + return WFS_RESULT_OK; +} + +s32 AclReadFile(const AreaInfo* area, WFSAclFileHandle fh, void *pFileDataBuffer, s32 nSize, WFSFileSize offset) +{ + DWORD bytesRead; + if (SetFilePointer(fh, (u32) offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + { + WFSKRN_ACL_REPORT("SetFilePointer: Error %ld\n", GetLastError()); + return WFS_RESULT_INVALID; + } + + if (!ReadFile(fh, pFileDataBuffer, nSize, &bytesRead, NULL)) + { + WFSKRN_ACL_REPORT("WFSKrnAccessListReadFile(): Error %ld\n", GetLastError()); + return WFS_RESULT_INVALID; // [check] error code. + } + return bytesRead; +} + +WFSResult AclCreateAccessListFile(const AreaInfo* area, + const AclFileInfo* aclFile, WFSBool create, WFSAclFileHandle *pFh) +{ + WCHAR wPath[WFSKRN_ACCESSLIST_MAX_PATH_LEN]; + WFSAclFileHandle hFile; + DWORD dwCreationDisposition; + + if (Utf8ToWcharAccessList(area, aclFile->path, wPath, sizeof(wPath)) < 0) + { + return WFS_RESULT_INVALID; // [check] error code. + } + + if (create) + { + dwCreationDisposition = OPEN_ALWAYS; + } + else + { + dwCreationDisposition = OPEN_EXISTING; + } + + hFile = CreateFileW(wPath, GENERIC_READ | GENERIC_WRITE, 0, + NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + return WFS_RESULT_INVALID; // [check] error code. + } + + *pFh = hFile; + return WFS_RESULT_OK; +} + +WFSResult AclCreateFile(const AreaInfo* area, const AclFileInfo* fileInfo, WFSBool create, WFSAclFileHandle *pFh) +{ + WCHAR wPath[WFSKRN_ACCESSLIST_MAX_PATH_LEN]; + WFSAclFileHandle hFile; + DWORD dwCreationDisposition; + + if (AclUtf8ToWchar(fileInfo->path, wPath, sizeof(wPath)) < 0) + { + return WFS_RESULT_INVALID; // [check] error code. + } + + if (create) + { + dwCreationDisposition = OPEN_ALWAYS; + } + else + { + dwCreationDisposition = OPEN_EXISTING; + } + + hFile = CreateFileW(wPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, + NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + return WFS_RESULT_INVALID; // [check] error code. + } + + *pFh = hFile; + return WFS_RESULT_OK; +} + +WFSResult AclDeleteAccessListFile(const AreaInfo* area, const AclFileInfo* aclFile) +{ + WCHAR wPath[WFSKRN_ACCESSLIST_MAX_PATH_LEN]; + + if (Utf8ToWcharAccessList(area, aclFile->path, wPath, sizeof(wPath)) < 0) + { + return WFS_RESULT_INVALID; // [check] error code. + } + + if (!DeleteFileW(wPath)) + { + return WFS_RESULT_INVALID; // [check] error code. + } + return WFS_RESULT_OK; +} + +WFSResult AclCloseFile(WFSAclFileHandle fh) +{ + if (CloseHandle(fh)) + { + return WFS_RESULT_OK; + } + return WFS_RESULT_INVALID; // [check] error code. +} + +WFSBool AclAccessListAlreadyExist(const AreaInfo* area, const AclFileInfo* aclFile) +{ + WCHAR wPath[WFSKRN_ACCESSLIST_MAX_PATH_LEN]; + + if (Utf8ToWcharAccessList(area, aclFile->path, wPath, sizeof(wPath)) < 0) + { + return (WFSBool) FALSE; + } + + if (AlreadyExist(wPath)) + { + return (WFSBool) TRUE; + } + return (WFSBool) FALSE; +} + +#endif // WFSDEV +#endif // _WIN32 + diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_SubBlkAlloc.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_SubBlkAlloc.cpp new file mode 100644 index 0000000..d5d6428 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_SubBlkAlloc.cpp @@ -0,0 +1,499 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_SubBlkAlloc.cpp + + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_SubBlkAlloc.cpp,v $ + Revision 1.8 2008/10/17 08:51:10 kondo_masahiro + Added the new MEDIUM size category (40KB-320KB) + + Revision 1.7 2008/08/27 23:23:28 ooizumi + Fixed newline to CR+LF(Windows format). + + Revision 1.6 2008/08/27 09:42:37 paul + Removed nTotalFree from block header + + Revision 1.5 2008/07/09 00:50:19 paul + Minor changes + + Revision 1.4 2008/06/09 17:24:21 paul + Changed SbaBlkInit() to support blocks with different header sizes + + Revision 1.3 2008/05/10 03:59:44 kondo_masahiro + Merged and fixed code to accept RM compiler + + Revision 1.2 2008/04/25 17:28:50 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.5 2008/04/22 22:19:42 paul + Fixed a bug in SbaAllocSubBlk + + Revision 1.4 2008/04/19 05:50:28 kondo_masahiro + Fixed code to accept RM compiler + + Revision 1.3 2008/04/04 23:36:33 paul + Added free space checking function. Some identifier name changes. + + Revision 1.2 2008/02/28 06:29:17 kondo_masahiro + Fixed code to accept PPC compiler + + Revision 1.1 2008/02/21 00:05:49 paul + *** empty log message *** + + + *---------------------------------------------------------------------------*/ + + +#include "wfskrn_SubBlkAlloc.h" +#include "wfskrn_Dir.h" +#include "wfskrn_Area.h" +#include "wfskrn_BitField.h" +#include "wfskrn_Heap.h" +#include "wfskrn_Api.h" +#include "wfskrn_Mutex.h" + +#undef dbg +#if _DEBUG_SUB_BLK_ALLOC + #include "randomlib.h" + #define dbg(s) s +#else + #define dbg(s) +#endif + +void SbaCheckOfs(u16 nOfs) { + // Check the intra block offset to ensure it is within the right range and properly aligned. + if ((nOfs==0) || + //(nOfs>=wkg.areaInfoRoot.nBlkSize) || + (nOfs&((1<nMagic = 0; + WFSSubBlkFreeHdr *pPrev = (WFSSubBlkFreeHdr*)&((u8*)pBlkHdr)[pSubBlkHdr->nPrev]; + WFSSubBlkFreeHdr *pNext = (WFSSubBlkFreeHdr*)&((u8*)pBlkHdr)[pSubBlkHdr->nNext]; + pPrev->nNext = pSubBlkHdr->nNext; + pNext->nPrev = pSubBlkHdr->nPrev; + pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nNumFree--; + pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nFirstFree = pSubBlkHdr->nNext; +} + +u16 SbaAllocSubBlk(WFSSubBlkAllocHdr *pBlkHdr, u32 nLog2Size) { + // This function allocates a contiguous sub block of size (1<aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nNumFree == 0) { + // Find a larger block and split it + u32 nI = nLog2Size; + do { + ++nI; + if (nI > SBA_MAX_LOG2_SUB_BLK_SIZE) { + return 0; // Unable to find a block + } + } while(pBlkHdr->aSubBlkList[nI - SBA_MIN_LOG2_SUB_BLK_SIZE].nNumFree == 0); +#if _DEBUG_SUB_BLK_ALLOC + pBlkHdr->nTotalFree -= 1<aSubBlkList[nI - SBA_MIN_LOG2_SUB_BLK_SIZE].nFirstFree; // Get offset to first free block of size (1<nNext = 0; + // Split the block in half repeatedly until we get a block of the requested size. + // Starts as |aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| where 'a' is the free block + // Ends as |RRRRddddccccccccbbbbbbbbbbbbbbbb| where 'R' is the newly allocated block, and 'b', 'c', 'd' are newly created free blocks + u32 nOfsJ = nOfs; + nOfsJ += (1<nMagic = SBA_FREE_SUB_BLK_MAGIC; + pFreeSubBlkHdr->nLog2Size = (u16)nJ; + WFSSubBlkList *pSubBlkListJ = &pBlkHdr->aSubBlkList[nJ - SBA_MIN_LOG2_SUB_BLK_SIZE]; + // This is the first free block of this size, so make a circular list with one element + pFreeSubBlkHdr->nNext = // continued on next line + pFreeSubBlkHdr->nPrev = (u16)((size_t)pFreeSubBlkHdr - (size_t)pBlkHdr); + pSubBlkListJ->nFirstFree = (u16)nOfsJ; + pSubBlkListJ->nNumFree = 1; + nOfsJ += (1<nTotalFree -= 1<aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nFirstFree; + SbaRemoveSubBlkFromFreeList(pBlkHdr, nOfs, nLog2Size); // Remove this free block from the list + return (u16)nOfs; +} + + +WFSKrnResult SbaAllocSubBlks(WFSSubBlkAllocHdr *pBlkHdr, u32 nLog2Size, u16 *pSubBlkOfs, u32 nNumSubBlks) { + // This function allocs multiple sub blocks of the same size at once. If it cannot alloc all blocks, it does not alloc any. + u32 nNumFreeBlks = pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nNumFree; + u32 nL2S = nLog2Size + 1; + u32 nMultiple = 2; + while(nNumFreeBlks < nNumSubBlks) { + if (nL2S > SBA_MAX_LOG2_SUB_BLK_SIZE) { + return WFSKRN_RESULT_OUT_OF_MEMORY; + } + nNumFreeBlks += nMultiple * pBlkHdr->aSubBlkList[nL2S - SBA_MIN_LOG2_SUB_BLK_SIZE].nNumFree; + nMultiple += nMultiple; + ++nL2S; + } + /* Enough free space was found to satisfy the request + u16 nOfs; + --nL2S; + WFSSubBlkList *pSubBlkList = &pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE]; + u32 nOfsStep = (1<nNumFree) { + nNumSubBlks -= pSubBlkList->nNumFree * nMultiple; + nOfs = pBlkHdr->aSubBlkList[nJ - SBA_MIN_LOG2_SUB_BLK_SIZE].nFirstFree; + WFSSubBlkFreeHdr *pFreeSubBlkHdr; + do { + pFreeSubBlkHdr = (WFSSubBlkFreeHdr*)&((u8*)pBlkHdr)[nOfs]; + u32 nI = nMultiple; + *pSubBlkOfs++ = nOfs; + while(--nI) { + nOfs += nOfsStep; + *pSubBlkOfs++ = nOfs; + } + nOfs = *pSubBlkOfs = pFreeSubBlkHdr->nNext; + } while(--pSubBlkList->nNumFree); + } + nOfsStep += nOfsStep; + nMultiple += nMultiple; + ++nJ; + }*/ + while(nNumSubBlks--) { + *pSubBlkOfs++ = SbaAllocSubBlk(pBlkHdr, nLog2Size); + } + return WFSKRN_RESULT_OK; +} + + +void SbaFreeSubBlk(WFSSubBlkAllocHdr *pBlkHdr, u16 nOfs, u32 nLog2Size) { +#if _DEBUG_SUB_BLK_ALLOC + memset(((u8*)pBlkHdr)+nOfs, 0xAA, 1<nTotalFree += 1<nMagic!=SBA_FREE_SUB_BLK_MAGIC) || (pBuddy->nLog2Size!=nLog2Size)) { + break; + } + // Remove the buddy sub-block from its free list + WFSSubBlkFreeHdr *pPrev = (WFSSubBlkFreeHdr*)&((u8*)pBlkHdr)[pBuddy->nPrev]; + WFSSubBlkFreeHdr *pNext = (WFSSubBlkFreeHdr*)&((u8*)pBlkHdr)[pBuddy->nNext]; + pPrev->nNext = pBuddy->nNext; + pNext->nPrev = pBuddy->nPrev; + pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nNumFree--; + pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nFirstFree = pBuddy->nNext; + if (nOfs > nNeigbourOfs) { + nOfs = nNeigbourOfs; + } + nLog2Size++; + } + WFSSubBlkFreeHdr *pSubBlkHdr = (WFSSubBlkFreeHdr*)&((u8*)pBlkHdr)[nOfs]; + if (pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nNumFree) { + u32 nNext = pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nFirstFree; + WFSSubBlkFreeHdr *pNext = (WFSSubBlkFreeHdr*)&((u8*)pBlkHdr)[nNext]; + pSubBlkHdr->nPrev = pNext->nPrev; + pSubBlkHdr->nNext = (u16)nNext; + WFSSubBlkFreeHdr *pPrev = (WFSSubBlkFreeHdr*)&((u8*)pBlkHdr)[pNext->nPrev]; + pNext->nPrev = pPrev->nNext = (u16)nOfs; + pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nNumFree++; + } else { + pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nNumFree = 1; + pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nFirstFree = (u16)nOfs; + pSubBlkHdr->nNext = pSubBlkHdr->nPrev = (u16)nOfs; + } + pSubBlkHdr->nMagic = SBA_FREE_SUB_BLK_MAGIC; + pSubBlkHdr->nLog2Size = (u16)nLog2Size; +} + +void SbaReduceSubBlkSize(WFSSubBlkAllocHdr *pBlkHdr, u16 nOfs, u32 nOldLog2Size, u32 nNewLog2Size) { + // This function reduces the size of an allocated block to a smaller power of 2. + // The start portion of the block will be retained. + // As an alternative to this function, it is usually better to copy the old block + // to a new block, then remove the old one. This function can be used when that method + // fails because there is not enough space to allocate a new block. + nOfs += (1<nNext = (u16)(((nI+1)&(nNumMaxSizeBlks-1))<nPrev = (u16)(((nI-1)&(nNumMaxSizeBlks-1))<nLog2Size = SBA_MAX_LOG2_SUB_BLK_SIZE; + } + pBlkHdr->aSubBlkList[SBA_NUM_SUB_BLK_SIZES-1].nNumFree = (u16)nNumMaxSizeBlks; +#if _DEBUG_SUB_BLK_ALLOC + pBlkHdr->nTotalFree = (u16)(1<aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nNumFree; + nTotalFree += (1<nTotalFree) { + WFSKrnOutputErrorStr("TotalFree Size Error!"); + } +#endif + return nTotalFree; +} + + +u32 SbaCheckFreeSpace(WFSSubBlkAllocHdr *pBlkHdr, u32 *aUtilization) { + u32 nLog2Size, nTotalFree=0; + for(nLog2Size=SBA_MIN_LOG2_SUB_BLK_SIZE; nLog2Size<=SBA_MAX_LOG2_SUB_BLK_SIZE; nLog2Size++) { + u32 nNumFreeSubBlks = pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nNumFree; + if (nNumFreeSubBlks) { + u32 nFirstOfs = pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nFirstFree; + u32 nOfs = nFirstOfs; + WFSSubBlkFreeHdr *pFreeSubBlk = (WFSSubBlkFreeHdr*)&((u8*)pBlkHdr)[nOfs]; + u32 nI; + for(nI=0; nI<=nNumFreeSubBlks; nI++) { + u32 nPrevOfs = nOfs; + nOfs = pFreeSubBlk->nNext; + SbaCheckOfs(nOfs); + pFreeSubBlk = (WFSSubBlkFreeHdr*)&((u8*)pBlkHdr)[nOfs]; + if (nI>0) { + nTotalFree += 1<nPrev != nPrevOfs) { + WFSKrnOutputErrorStr("Free List Error!\n"); + } + if ((nI==nNumFreeSubBlks)^(nPrevOfs==nFirstOfs)) { + WFSKrnOutputErrorStr("Free List Error!\n"); + } + if (WfsTestAndSetBitField((unsigned *)aUtilization, (int)(nOfs>>SBA_MIN_LOG2_SUB_BLK_SIZE), 1<<(nLog2Size-SBA_MIN_LOG2_SUB_BLK_SIZE))) { + WFSKrnOutputErrorStr("Overlap!"); + } + } + } + } + } +#if _DEBUG_SUB_BLK_ALLOC + if (nTotalFree != pBlkHdr->nTotalFree) { + WFSKrnOutputErrorStr("TotalFree Size Error!"); + } +#endif + return nTotalFree; +} + + +#if _DEBUG_SUB_BLK_ALLOC + + typedef struct { + u16 nOfs; + u16 nL2S; + } DirSubBlk; + + static + int CompareOfs(const void *pA, const void *pB) { + return (int)((DirSubBlk*)pA)->nOfs - (int)((DirSubBlk*)pB)->nOfs; + } + + + static + void SbaDebugPrintAllocs(AreaInfo *pAreaInfo, WFSSubBlkAllocHdr *pBlkHdr, u32 nNumAllocs, DirSubBlk *aSubBlk) { + u8 aMap[1<<(WFS_LOG2_MEDIUM_BLK_SIZE-SBA_MIN_LOG2_SUB_BLK_SIZE)]; + u32 nOfs, nAlloc=0; + u8 aChar[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + u8 *pMap = aMap; + u32 nTotalAllocated = 1<>SBA_MIN_LOG2_SUB_BLK_SIZE]; + if (aSubBlk[nAlloc].nL2S) { + nTotalAllocated += 1<aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nNumFree; + if (nNumFreeSubBlks) { + u32 nFirstOfs = pBlkHdr->aSubBlkList[nLog2Size - SBA_MIN_LOG2_SUB_BLK_SIZE].nFirstFree; + nOfs = nFirstOfs; + WFSSubBlkFreeHdr *pFreeSubBlk = (WFSSubBlkFreeHdr*)&((u8*)pBlkHdr)[nOfs]; + u32 nI; + for(nI=0; nI<=nNumFreeSubBlks; nI++) { + u32 nPrevOfs = nOfs; + nOfs = pFreeSubBlk->nNext; + pFreeSubBlk = (WFSSubBlkFreeHdr*)&((u8*)pBlkHdr)[nOfs]; + if (nI>0) { + nTotalFree += 1<nPrev != nPrevOfs) { + WFSKrnOutputErrorStr("Free List Error!\n"); + } + if ((nI==nNumFreeSubBlks)^(nPrevOfs==nFirstOfs)) { + WFSKrnOutputErrorStr("Free List Error!\n"); + } + pMap = &aMap[nOfs>>SBA_MIN_LOG2_SUB_BLK_SIZE]; + u32 nMapOfs; + for(nMapOfs=nPrevOfs; nMapOfsnBlkSize) { + MyOSReport("TotalFree(%d) + TotalAllocated(%d) != BlkSize(%d)%d\n", nTotalFree, nTotalAllocated, pAreaInfo->nBlkSize); + } + for(nOfs=0; nOfsnBlkSize; nOfs+=(1<>SBA_MIN_LOG2_SUB_BLK_SIZE]; + u8 cTemp = *pLineEnd; + *pLineEnd = 0; + MyOSReport("%s\n", &aMap[nOfs>>SBA_MIN_LOG2_SUB_BLK_SIZE]); + *pLineEnd = cTemp; + } + MyOSReport("\n"); + } + + static + void SbaTestAllocFree(AreaInfo *pAreaInfo, WFSSubBlkAllocHdr *pBlkHdr) { + // Test making random allocs and frees of sub blocks + DirSubBlk aSubBlk[1<<(WFS_LOG2_MEDIUM_BLK_SIZE-SBA_MIN_LOG2_SUB_BLK_SIZE)]; + u32 aNumAllocsPerSize[WFS_LOG2_MEDIUM_BLK_SIZE+2]; + //u32 nMaxSubBlksPerBlk = (u32)(1<<(pAreaInfo->ah.nLog2BlkSize - SBA_MIN_LOG2_SUB_BLK_SIZE)); // unused + u32 nTotalAllocated = 1< nNumAllocs) { + nNumFrees = nNumAllocs; + } + while(nNumFrees) { + u32 nHalfNumFrees = (nNumFrees+1)>>1; + u32 nFree=0; + while(nFreelink); + wkg.pActiveTransListAnchor->link.pNext = wkg.pActiveTransListAnchor->link.pPrev = wkg.pActiveTransListAnchor; + TransInfo *pTransInfo = wkg.pTransInfoFreeList = wkg.aTransInfo; + TransInfo *pTransEnd = (TransInfo *)((u8*)pTransInfo + sizeof(wkg.aTransInfo)); + for(; pTransInfolink.pNext = pTransInfo+1; + } + pTransInfo[-1].link.pNext = NULL; +} + + +WFSTitleId WfsGetRequestorTitleId() { +#if _WIN32 || PERM_TEST + return wkg.nDebugTitleId; +#elif _IOP + //return IOS_GetTitleId(); + return IOS_GetGid(); // ??? must be fixed +#endif +} + + +void TransAddToActiveList(TransInfo *pTransInfo) { + pTransInfo->link.pNext = wkg.pActiveTransListAnchor->link.pNext; + pTransInfo->link.pNext->link.pPrev = pTransInfo; + wkg.pActiveTransListAnchor->link.pNext = pTransInfo; + pTransInfo->link.pPrev = wkg.pActiveTransListAnchor; +} + + +void TransRemoveFromActiveList(TransInfo *pTransInfo) { + pTransInfo->link.pPrev->link.pNext = pTransInfo->link.pNext; + pTransInfo->link.pNext->link.pPrev = pTransInfo->link.pPrev; +} + + +TransInfo *TransBegin() { + TransInfo *pTransInfo = wkg.pTransInfoFreeList; + wkg.pTransInfoFreeList = pTransInfo->link.pNext; + pTransInfo->nTitleId = WfsGetRequestorTitleId(); + TransAddToActiveList(pTransInfo); + return pTransInfo; +} + + +void TransEnd(TransInfo *pTransInfo) { + TransRemoveFromActiveList(pTransInfo); + pTransInfo->link.pNext = wkg.pTransInfoFreeList; + wkg.pTransInfoFreeList = pTransInfo; +} + + +WFSKrnResult TransGetBlk5(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo, u32 nFlags, void **ppBlkPtr) { + if (!pAreaInfo) + { + return WFSKRN_RESULT_INVALID; // [check] workaround to avoid exception when DirGetBlk() is called for "/". + } + u32 nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + nBlkAdr; + +#if AREA_ENABLE_BLK_CACHE + BCacheEntry* pBce; + WFSKrnResult nResult = BCacheAllocMetaBlk(pAreaInfo->pVolInfo, nAbsBlkAdr, nFlags, &pBce); + if(ppBlkPtr && nResult == WFSKRN_RESULT_OK) + { + *ppBlkPtr = pBce->pBlkPtr; + } + return nResult; +#else //AREA_ENABLE_BLK_CACHE + *ppBlkPtr = AreaGetPhysicalBlk(pAreaInfo, nAbsBlkAdr); + return WFSKRN_RESULT_OK; +#endif //AREA_ENABLE_BLK_CACHE +} + + +WFSKrnResult TransGetAndPinBlk5(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo, u32 nFlags, void **ppBlkPtr) { + if (!pAreaInfo) + { + return WFSKRN_RESULT_INVALID; // [check] workaournd in case DirGetBlk() is called for "/". + } + // ToDo: Perform a mapping from physical block to remapped block as seen by a particular transaction + u32 nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + nBlkAdr; +#if AREA_ENABLE_BLK_CACHE + BCacheEntry* pBce; + WFSKrnResult nResult = BCacheAllocMetaBlk(pAreaInfo->pVolInfo, nAbsBlkAdr, nFlags | BCACHE_FLAG_PINNED, &pBce); + if(ppBlkPtr) *ppBlkPtr = pBce->pBlkPtr; + return nResult; +#else //AREA_ENABLE_BLK_CACHE + return AreaGetPhysicalBlk(pAreaInfo, nAbsBlkAdr); +#endif //AREA_ENABLE_BLK_CACHE +} + + +WFSKrnResult TransSetChainId4(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo, u32 nChainId){ + if (!pAreaInfo){ + return WFSKRN_RESULT_INVALID; // [check] workaournd in case DirGetBlk() is called for "/". + } + u32 nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + nBlkAdr; + return BCacheSetChainId(pAreaInfo->pVolInfo, nAbsBlkAdr, nChainId); +} + + +WFSKrnResult TransGetChainId4(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo, u32 *pChainId){ + if (!pAreaInfo){ + return WFSKRN_RESULT_INVALID; // [check] workaournd in case DirGetBlk() is called for "/". + } + u32 nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + nBlkAdr; + return BCacheGetChainId(pAreaInfo->pVolInfo, nAbsBlkAdr, pChainId); +} + + + +WFSKrnResult TransUnpinBlk3(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo) { +#if AREA_ENABLE_BLK_CACHE + u32 nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + nBlkAdr; + WFSKrnResult nResult = BCacheUnpin(pAreaInfo->pVolInfo, nAbsBlkAdr); + #if _CHECK_BLK_USAGE + // if nPinCount becomes 0, the cache data is flushed. (for debug) + if(!BCacheGetPinCount(pAreaInfo->pVolInfo, nAbsBlkAdr)){ + if(DeviceDebugGetPseudoDetachDevice() == 0){ + DeviceDebugSetPseudoDetachDevice(1); + } + if(DeviceDebugGetPseudoHashInconsistent() == 0){ + DeviceDebugSetPseudoHashInconsistent(1); + } + nResult = AreaBlkFlush(pAreaInfo, nBlkAdr); + } + #endif + return nResult; +#else //AREA_ENABLE_BLK_CACHE + return WFSKRN_RESULT_OK; +#endif //AREA_ENABLE_BLK_CACHE +} + + +WFSKrnResult TransDirtyBlk3(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo) { +#if AREA_ENABLE_BLK_CACHE + u32 nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + nBlkAdr; + WFSKrnResult nResult = BCacheDirty(pAreaInfo->pVolInfo, nAbsBlkAdr); + return nResult; +#else //AREA_ENABLE_BLK_CACHE + return WFSKRN_RESULT_OK; +#endif //AREA_ENABLE_BLK_CACHE +} + + +#include "wfskrn_Volume.h" + +WFSKrnResult TransFreeBlks6(AreaInfo *pAreaInfo, u32 nLog2BlkSize, u32 nNumBlks, WFSBlkAdr *pBlkAdr, s32 nStride, TransInfo *pTransInfo) { + // This function frees the transaction blocks passed in. + WFSKrnResult nResult = WFSKRN_RESULT_OK; +#if AREA_ENABLE_BLK_CACHE + AreaFreeBlks(pAreaInfo, nLog2BlkSize, nNumBlks, pBlkAdr, nStride); +#else //AREA_ENABLE_BLK_CACHE + u32 nI; + for(nI=0; nIah.nFirstFreeBlkAdr; + pAreaInfo->ah.nFirstFreeBlkAdr = *pBlkAdr; + pBlkAdr = (WFSBlkAdr*)((size_t)pBlkAdr + nStride); + } +#endif //AREA_ENABLE_BLK_CACHE + return nResult; +} + + +WFSKrnResult TransUnpinAndFreeBlks(AreaInfo *pAreaInfo, u32 nLog2BlkSize, u32 nNumBlks, WFSBlkAdr aBlkAdr[], TransInfo *pTransInfo) { + // This function frees the transaction blocks passed in. + WFSKrnResult nResult = WFSKRN_RESULT_OK; + u32 nI; +#if AREA_ENABLE_BLK_CACHE + for(nI=0; nIah.nFirstFreeBlkAdr; + pAreaInfo->ah.nFirstFreeBlkAdr = aBlkAdr[nI]; + } +#endif //AREA_ENABLE_BLK_CACHE + return nResult; +} + + +WFSKrnResult TransStoreBlk3(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo) { + WFSKrnResult nResult = WFSKRN_RESULT_OK; +#if AREA_ENABLE_BLK_CACHE + nResult = AreaBlkStore (pAreaInfo, nBlkAdr); +#endif //AREA_ENABLE_BLK_CACHE + return nResult; +} + + +WFSKrnResult TransFlushBlk3(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo) { + WFSKrnResult nResult = WFSKRN_RESULT_OK; +#if AREA_ENABLE_BLK_CACHE + nResult = AreaBlkFlush (pAreaInfo, nBlkAdr); +#endif //AREA_ENABLE_BLK_CACHE + return nResult; +} + + +WFSKrnResult TransInvalidate3(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo) { + WFSKrnResult nResult = WFSKRN_RESULT_OK; +#if AREA_ENABLE_BLK_CACHE + nResult = AreaBlkInvalidate(pAreaInfo, nBlkAdr); +#endif //AREA_ENABLE_BLK_CACHE + return nResult; +} + + +WFSKrnResult TransSetValidSize4(AreaInfo *pAreaInfo, WFSBlkAdr nBlkAdr, TransInfo *pTransInfo, u32 nValidSize){ + WFSKrnResult nResult = WFSKRN_RESULT_OK; +#if AREA_ENABLE_BLK_CACHE + nResult = AreaBlkSetValidSize(pAreaInfo, nBlkAdr, nValidSize); +#endif //AREA_ENABLE_BLK_CACHE + return nResult; +} + + +WFSKrnResult TransRemapCache6(AreaInfo *pAreaInfo, WFSBlkAdr nSrcBlkAdr, TransInfo *pTransInfo, WFSBlkAdr nDstBlkAdr, WFSBlkAdr nHashBlkAdr, u32 nHashOfs) +{ + WFSKrnResult nResult = WFSKRN_RESULT_OK; +#if AREA_ENABLE_BLK_CACHE + nResult = AreaBlkRemapCache(pAreaInfo, nSrcBlkAdr, nDstBlkAdr, nHashBlkAdr, nHashOfs); +#endif //AREA_ENABLE_BLK_CACHE + return nResult; +} + + +WFSKrnResult TransGetAndPinFileBlk8(AreaInfo *pAreaInfo, WFSBlkAdr nParentBlkAdr, u16 nHashOfs, WFSBlkAdr nFileBlkAdr, TransInfo *pTransInfo, u32 nFlags, u32 nValidSize, u32 nBCacheGroupId, void **ppBlkPtr) { + // This function ensures the file block and its parent meta data block are in cache, and pins the + // It returns the address of + // Arguments: + // pAreaInfo [In] .. Pointer to the AreaInfo struct which contains the blocks to be written + // nParentBlkAdr [In] .. Block address of the parent meta data block + // nHashOfs [In] .. Offset to the hash code within the parent meta data block + // nFileBlkAdr [In] .. Block address of the file block + // pTransInfo [In] .. Pointer to a TransInfo struct for the transaction (may be used to remap blocks). + // nFlags [In] .. Flags TRANS_FLAG_* and BCACHE_FLAG_* + // ppBlkPtr [Out] .. pointer to variable which will be overwritten with the address of the file block in the cache + + // ***ToDo: Implement this function properly including necessary changes to block cache*** + + // ToDo: Perform a mapping from physical block to remapped block as seen by a particular transaction + u32 nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + nFileBlkAdr; + u32 nHashBlkAdr = pAreaInfo->nAbsStartBlkAdr + nParentBlkAdr; +#if AREA_ENABLE_BLK_CACHE + BCacheEntry* pBce; + WFSKrnResult nResult = BCacheAlloc(pAreaInfo->pVolInfo, nAbsBlkAdr, nFlags | BCACHE_FLAG_PINNED, nValidSize, nBCacheGroupId, nHashBlkAdr, nHashOfs, &pBce); + if(nResult == WFS_RESULT_OK && ppBlkPtr){ + *ppBlkPtr = pBce->pBlkPtr; + } + return nResult; +#else //AREA_ENABLE_BLK_CACHE + return AreaGetPhysicalBlk(pAreaInfo, nAbsBlkAdr); +#endif //AREA_ENABLE_BLK_CACHE + +} + + +WFSKrnResult TransReadFileBlks7(u8 *pAlignedPtr, AreaInfo *pAreaInfo, u32 nLog2BlkSize, u32 nSize, WFSFileBlkPtr *pFileBlkPtr, s32 nStride, TransInfo *pTransInfo) { + // This function reads, decrypts and hash checks a set of file blocks directly to a specified aligned buffer + // Arguments: + // pAlignedPtr [Out] .. Address of aligned buffer to overwrite with data from file blocks. (must be aligned to WFS_STATIC_MEM_ALIGNMENT bytes) + // pAreaInfo [In] .. Pointer to the AreaInfo struct which contains the blocks to be written + // nNumBlks [In] .. The number of blocks to read + // pFileBlkPtr [In] .. Pointer to the first WFSFileBlkPtr struct, which specifies the address and hash code of the file block + // nStride [In] .. How to get from the first WFSFileBlkPtr to the next one + // pTransInfo [In] .. Pointer to a TransInfo struct for the transaction (may be used to remap blocks). + // + + // ToDo: Check if any blocks have been remapped for this transaction + // ToDo: Check if any (remapped) blocks are already in block cache, and read from there if so + // ToDo: Determine how many blocks are sequential (after optional remapping), so they can be read with a single combined read + + DeviceInfo *pDevInfo = pAreaInfo->pVolInfo->pDevInfo; + ASSERT(nSize); + ASSERT(!(nSize&(pDevInfo->dh.nLog2SectorSize-1))); + u32 nLog2SectorsPerBlk = pAreaInfo->ah.nLog2BlkSize - pDevInfo->dh.nLog2SectorSize; + u32 nLog2SectorsPerReadBlk = nLog2BlkSize - pDevInfo->dh.nLog2SectorSize; + u32 nLog2BlkPerReadBlk = nLog2SectorsPerReadBlk - nLog2SectorsPerBlk; + u32 nNumBlks = ((nSize-1)>>nLog2BlkSize)+1; + u32 nEndBlkSector = (nSize>>pDevInfo->dh.nLog2SectorSize)-((nNumBlks-1)<nBlkAdr != pStartFileBlkPtr->nBlkAdr + (nRunLength<nAbsStartBlkAdr + pStartFileBlkPtr->nBlkAdr; +#if _DEBUG_BREAK_POINT + if(nAbsBlkAdr == 32248){ + int a; a=0; + } +#endif + u32 nReadSector; + if(nStartIdx + nRunLength == nNumBlks){ + nReadSector = ((nRunLength-1)<hash, nLog2SectorsPerReadBlk, 0, nStride, 0); + if(nResult == WFSKRN_RESULT_DEVICE_HASH_INCONSISTENT){ + osTPrintf("User Block Hash Error: %d\n", nAbsBlkAdr); + } + pAlignedPtr += nReadSector << pDevInfo->dh.nLog2SectorSize; + nStartIdx += nRunLength; + } + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult TransWriteFileBlks7(u8 *pAlignedPtr, AreaInfo *pAreaInfo, u32 nLog2BlkSize, u32 nSize, WFSFileBlkPtr *pFileBlkPtr, s32 nStride, TransInfo *pTransInfo, bool bDecryption) { + // This function reads, decrypts and hash checs a set of file blocks directly to a specified aligned buffer + // Arguments: + // pAlignedPtr [Out] .. Address of aligned buffer to overwrite with data from file blocks. (must be aligned to WFS_STATIC_MEM_ALIGNMENT bytes) + // pAreaInfo [In] .. Pointer to the AreaInfo struct which contains the blocks to be written + // nNumBlks [In] .. The number of blocks to read + // pFileBlkPtr [In] .. Pointer to the first WFSFileBlkPtr struct, which specifies the address and hash code of the file block + // nStride [In] .. How to get from the first WFSFileBlkPtr to the next one + // pTransInfo [In] .. Pointer to a TransInfo struct for the transaction (may be used to remap blocks). + + // ToDo: Check if any blocks have been remapped for this transaction, and write to the remapped blocks + // ToDo: First, invalidate the (remapped) blocks we are writing to directly, to ensure we don't get stale data in the block cache + // ToDo: Determine how many blocks are sequential (after optional remapping), so they can be written with a single combined write + + DeviceInfo *pDevInfo = pAreaInfo->pVolInfo->pDevInfo; + ASSERT(nSize); + ASSERT(!(nSize&(pDevInfo->dh.nLog2SectorSize-1))); + u32 nLog2SectorsPerBlk = pAreaInfo->ah.nLog2BlkSize - pDevInfo->dh.nLog2SectorSize; + u32 nLog2SectorsPerWriteBlk = nLog2BlkSize - pDevInfo->dh.nLog2SectorSize; + u32 nLog2BlkPerWriteBlk = nLog2SectorsPerWriteBlk - nLog2SectorsPerBlk; + u32 nNumBlks = ((nSize-1)>>nLog2BlkSize)+1; + u32 nEndBlkSector = (nSize>>pDevInfo->dh.nLog2SectorSize)-((nNumBlks-1)<nBlkAdr == 0x1c5a){ + int a; a=0; + } +#endif + if (pFileBlkPtr->nBlkAdr != pStartFileBlkPtr->nBlkAdr + (nRunLength<nAbsStartBlkAdr + pStartFileBlkPtr->nBlkAdr; +#if _DEBUG_BREAK_POINT + if(nAbsBlkAdr == 32248){ + int a; a=0; + } +#endif + u32 nWriteSector; + if(nStartIdx + nRunLength == nNumBlks){ + nWriteSector = ((nRunLength-1)<pVolInfo, nAbsBlkAdr, (nRunLength<hash, nLog2SectorsPerWriteBlk, 0, nStride, 0, bDecryption)); + pAlignedPtr += nWriteSector << pDevInfo->dh.nLog2SectorSize; + nStartIdx += nRunLength; + } + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult TransReadFileLargeBlks (u8 *pAlignedPtr, AreaInfo *pAreaInfo, u32 nSize, u32 nOffsetBlks, + WFSFileLargeBlkPtr *pFileLargeBlkPtr, s32 nStride, TransInfo *pTransInfo) +{ + // This function reads, decrypts and hash checks a set of file blocks directly to a specified aligned buffer + // Arguments: + // pAlignedPtr [Out] .. Address of aligned buffer to overwrite with data from file blocks. (must be aligned to WFS_STATIC_MEM_ALIGNMENT bytes) + // pAreaInfo [In] .. Pointer to the AreaInfo struct which contains the blocks to be written + // nNumBlks [In] .. The number of blocks to read + // nOffsetBlks [In] .. The number of offset blocks for first read block + // pFileBlkPtr [In] .. Pointer to the first WFSFileBlkPtr struct, which specifies the address and hash code of the file block + // nStride [In] .. How to get from the first WFSFileLargeBlkPtr to the next one + // pTransInfo [In] .. Pointer to a TransInfo struct for the transaction (may be used to remap blocks). + + DeviceInfo *pDevInfo = pAreaInfo->pVolInfo->pDevInfo; + ASSERT(nSize); + ASSERT(!(nSize&(pDevInfo->dh.nLog2SectorSize-1))); + u32 nLog2SectorsPerBlk = pAreaInfo->ah.nLog2BlkSize - pDevInfo->dh.nLog2SectorSize; + u32 nLog2SectorsPerMaxHashBlk = pAreaInfo->ah.nLog2MediumBlkSize - pDevInfo->dh.nLog2SectorSize; + u32 nNumBlks = ((nSize-1)>>pAreaInfo->ah.nLog2MediumBlkSize)+1; + u32 nEndBlkSector = (nSize>>pDevInfo->dh.nLog2SectorSize)-((nNumBlks-1)< (1<nLog2MediumBlkPerLargeBlk)){ + nRunLength += (1<nLog2MediumBlkPerLargeBlk) - nOffsetBlksTmp; + nNumBlks -= (1<nLog2MediumBlkPerLargeBlk) - nOffsetBlksTmp; + nReadSector = nRunLength<nBlkAdr == pStartFileLargeBlkPtr->nBlkAdr + ((nRunLength + nOffsetBlks)<nLog2BlksPerMediumBlk)); + // Read (nRunLength) blocks from the device to the destination buffer, then do decryption & hash check on each block + WFSBlkAdr nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + pStartFileLargeBlkPtr->nBlkAdr + (nOffsetBlks<nLog2BlksPerMediumBlk); + WFSKrnResult nResult = DeviceRead(pDevInfo, nAbsBlkAdr<aHash[nOffsetBlks], + nLog2SectorsPerMaxHashBlk, nOffsetBlks, sizeof(WFSHashCode), nStride-sizeof(pStartFileLargeBlkPtr->aHash)); + if(nResult == WFSKRN_RESULT_DEVICE_HASH_INCONSISTENT){ + osTPrintf("User Block Hash Error (Large): %d\n", nAbsBlkAdr); + } + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + pAlignedPtr += nReadSector << pDevInfo->dh.nLog2SectorSize; + nStartIdx += nRunLength; + nOffsetBlks = 0; + } + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult TransWriteFileLargeBlks(u8 *pAlignedPtr, AreaInfo *pAreaInfo, u32 nSize, u32 nOffsetBlks, + WFSFileLargeBlkPtr *pFileLargeBlkPtr, s32 nStride, TransInfo *pTransInfo, bool bDecryption) +{ + // This function reads, decrypts and hash checs a set of file blocks directly to a specified aligned buffer + // Arguments: + // pAlignedPtr [Out] .. Address of aligned buffer to overwrite with data from file blocks. (must be aligned to WFS_STATIC_MEM_ALIGNMENT bytes) + // pAreaInfo [In] .. Pointer to the AreaInfo struct which contains the blocks to be written + // nNumBlks [In] .. The number of blocks to write + // nOffsetBlks [In] .. The number of offset blocks for first write block + // pFileBlkPtr [In] .. Pointer to the first WFSFileBlkPtr struct, which specifies the address and hash code of the file block + // nStride [In] .. How to get from the first WFSFileBlkPtr to the next one + // pTransInfo [In] .. Pointer to a TransInfo struct for the transaction (may be used to remap blocks). + + DeviceInfo *pDevInfo = pAreaInfo->pVolInfo->pDevInfo; + ASSERT(nSize); + ASSERT(!(nSize&(pDevInfo->dh.nLog2SectorSize-1))); + u32 nLog2SectorsPerBlk = pAreaInfo->ah.nLog2BlkSize - pDevInfo->dh.nLog2SectorSize; + u32 nLog2SectorsPerMaxHashBlk = pAreaInfo->ah.nLog2MediumBlkSize - pDevInfo->dh.nLog2SectorSize; + u32 nNumBlks = ((nSize-1)>>pAreaInfo->ah.nLog2MediumBlkSize)+1; + u32 nEndBlkSector = (nSize>>pDevInfo->dh.nLog2SectorSize)-((nNumBlks-1)< (1<nLog2MediumBlkPerLargeBlk)){ + nRunLength += (1<nLog2MediumBlkPerLargeBlk) - nOffsetBlksTmp; + nNumBlks -= (1<nLog2MediumBlkPerLargeBlk) - nOffsetBlksTmp; + nWriteSector = nRunLength<nBlkAdr == pStartFileLargeBlkPtr->nBlkAdr + ((nRunLength + nOffsetBlks)<nLog2BlksPerMediumBlk) ); + // Write (nRunLength) blocks from the device to the destination buffer, then do decryption & hash check on each block + WFSBlkAdr nAbsBlkAdr = pAreaInfo->nAbsStartBlkAdr + pStartFileLargeBlkPtr->nBlkAdr + (nOffsetBlks<nLog2BlksPerMediumBlk); +#if _DEBUG_BREAK_POINT + if(nAbsBlkAdr == 0x2880){ + int a; a=0; + } +#endif + // The caches of the written blocks have to be Invalidated because BCache data would be old. + WFSKrnReturnOnError(BCacheInvalidateBlks(pAreaInfo->pVolInfo, nAbsBlkAdr, nRunLength<nLog2BlksPerMediumBlk)); + WFSKrnReturnOnError(DeviceWrite(pDevInfo, nAbsBlkAdr<aHash[nOffsetBlks], + nLog2SectorsPerMaxHashBlk, nOffsetBlks, sizeof(WFSHashCode), nStride-sizeof(pStartFileLargeBlkPtr->aHash), bDecryption)); + pAlignedPtr += nWriteSector << pDevInfo->dh.nLog2SectorSize; + nStartIdx += nRunLength; + nOffsetBlks = 0; + } + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult TransTrancateFileBlk(TransBlkAdr *pTba, WFSBlkAdr nParentBlkAdr, u16 nHashOfs, WFSBlkAdr nFileBlkAdr, u32 nOldSize, u32 nNewSize) +{ + nOldSize = WFS_ROUND_UP(nOldSize, pTba->pAreaInfo->pVolInfo->pDevInfo->nSectorSize); + nNewSize = WFS_ROUND_UP(nNewSize, pTba->pAreaInfo->pVolInfo->pDevInfo->nSectorSize); + ASSERT(nOldSize<=pTba->pAreaInfo->nBlkSize && nNewSize<=pTba->pAreaInfo->nBlkSize); + u8 *pBlkPtr; + if(!nNewSize){ + WFSKrnReturnOnError(TransInvalidate3(pTba->pAreaInfo, nFileBlkAdr, pTba->pTransInfo)) + } else if(nNewSize != nOldSize) { + WFSKrnReturnOnError(TransGetAndPinFileBlk(pTba, nParentBlkAdr, nHashOfs, nFileBlkAdr, TRANS_FLAG_RW_BLK, nOldSize, (void**)&pBlkPtr)); + WFSKrnReturnOnError(TransSetValidSize4(pTba->pAreaInfo, nFileBlkAdr, pTba->pTransInfo, nNewSize)); + WFSKrnReturnOnError(TransStoreBlk3(pTba->pAreaInfo, nFileBlkAdr, pTba->pTransInfo)); + WFSKrnReturnOnError(TransUnpinBlk3(pTba->pAreaInfo, nFileBlkAdr, pTba->pTransInfo)); + } + return WFSKRN_RESULT_OK; +} + + +WFSKrnResult TransTrancateFileMediumBlk(TransBlkAdr *pTba, WFSBlkAdr nParentBlkAdr, u16 nHashOfs, WFSBlkAdr nFileBlkAdr, u32 nOldSize, u32 nNewSize) +{ + nOldSize = WFS_ROUND_UP(nOldSize, pTba->pAreaInfo->pVolInfo->pDevInfo->nSectorSize); + nNewSize = WFS_ROUND_UP(nNewSize, pTba->pAreaInfo->pVolInfo->pDevInfo->nSectorSize); + ASSERT(nOldSize<=pTba->pAreaInfo->nMediumBlkSize && nNewSize<=pTba->pAreaInfo->nMediumBlkSize); + u8 *pBlkPtr; + if(!nNewSize){ + WFSKrnReturnOnError(TransInvalidate3(pTba->pAreaInfo, nFileBlkAdr, pTba->pTransInfo)); + } else if(nNewSize != nOldSize){ + WFSKrnReturnOnError(TransGetAndPinFileMediumBlk(pTba, nParentBlkAdr, nHashOfs, nFileBlkAdr, TRANS_FLAG_RW_BLK, nOldSize, (void**)&pBlkPtr)); + WFSKrnReturnOnError(TransSetValidSize4(pTba->pAreaInfo, nFileBlkAdr, pTba->pTransInfo, nNewSize)); + WFSKrnReturnOnError(TransStoreBlk3(pTba->pAreaInfo, nFileBlkAdr, pTba->pTransInfo)); + WFSKrnReturnOnError(TransUnpinBlk3(pTba->pAreaInfo, nFileBlkAdr, pTba->pTransInfo)); + } + return WFSKRN_RESULT_OK; +} + diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Utils.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Utils.cpp new file mode 100644 index 0000000..e5bf9e9 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Utils.cpp @@ -0,0 +1,77 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Utils.cpp + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Utils.cpp,v $ + Revision 1.2 2008/12/19 05:45:08 saito_tomoya + Modified _qsort() to sort correctly. + + Revision 1.1 2008/12/03 00:10:21 kondo_masahiro + Initial check-in. + + +*---------------------------------------------------------------------------*/ + +#include "wfskrn_Utils.h" + +#define SWAP(type,a,b) { type temp = a; a = b; b = temp; } + + +static +void exchangeValues(void *x , void *y, size_t size) { + while(size >= 4){ + SWAP(u32, *(u32*)x, *(u32*)y) + x = (void*)((size_t)x+4); + y = (void*)((size_t)y+4); + size -= 4; + } + while(size){ + SWAP(u8, *(u8*)x, *(u8*)y) + x = (void*)((size_t)x+1); + y = (void*)((size_t)y+1); + --size; + } +} + + +void _qsort(void *base, size_t num, size_t size, int (*compare)(const void*, const void*) ){ + int i = 0, j = (num-1), key = ((num-1)/2); + while(1) { + while( compare( (const void*)((size_t)base+i*size), (const void*)((size_t)base+key*size)) < 0 ){ + ++i; + } + while( compare( (const void*)((size_t)base+key*size), (const void*)((size_t)base+j*size)) < 0 ){ + --j; + } + if (i >= j) break; + exchangeValues( (void*)((size_t)base+i*size), (void*)((size_t)base+j*size), size ); + if(i==key) key = j; + else if(j==key) key = i; + i++; j--; + } + if (0 < i-1) _qsort( base, i, size, compare); + if ((num-1) > j+1) _qsort((void*)((size_t)base+(j+1)*size), num-j-1, size, compare); +} + + +int CompareBlkAdrForward(const void *pA, const void *pB) { + WFSBlkAdr *pBlkAdrA = (WFSBlkAdr *)pA; + WFSBlkAdr *pBlkAdrB = (WFSBlkAdr *)pB; + return (int)(*pBlkAdrA - *pBlkAdrB); +} + + +int CompareBlkAdrReverse(const void *pA, const void *pB) { + WFSBlkAdr *pBlkAdrA = (WFSBlkAdr *)pA; + WFSBlkAdr *pBlkAdrB = (WFSBlkAdr *)pB; + return (int)(*pBlkAdrB - *pBlkAdrA); +} + diff --git a/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Volume.cpp b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Volume.cpp new file mode 100644 index 0000000..2f63866 --- /dev/null +++ b/trunk/firmware/build/libraries/nfs/common/src/wfskrn_Volume.cpp @@ -0,0 +1,195 @@ +/*---------------------------------------------------------------------------* + Project: wfs + File: wfskrn_Volume.cpp - Volume MR initialization and obtaining the MR. + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfskrn_Volume.cpp,v $ + Revision 1.6 2008/09/28 23:32:04 kondo_masahiro + Fixed codes to use medium size user block. + + Revision 1.5 2008/08/05 03:56:08 kondo_masahiro + Added error handling for hash error and detach device. + + Revision 1.4 2008/07/17 05:33:46 kondo_masahiro + Fixed codes for porting IOP. + + Revision 1.3 2008/07/09 00:56:32 paul + Moved volume handling code from wfskrn_Api.cpp to here. Integrates volumes with path cache and block cache. + + Revision 1.2 2008/05/12 19:17:50 paul + Merged in Wayne's previous changes + + Revision 1.1 2008/04/22 04:39:08 kondo_masahiro + Fixed code to transfer the wfskrn project to RM_SDK tree + + Revision 1.6 2008/04/26 01:28:27 wayne.wong + Moved area allocation functionality from Volume to Area module. + Changed API appropriately. + + Revision 1.5 2008/04/18 01:59:14 wayne.wong + Created separate Area types for persistent (hdr) and non-persistent (info) types. + Changed function names to be consistent with kernel naming convention. + Defines are included to support the previous naming, but will be deleted in + the future. + + Revision 1.4 2008/03/24 10:17:40 wayne.wong + Fixed a bug with area free that was not recursively coalescing correctly. + + Revision 1.3 2008/03/19 09:17:36 wayne.wong + Fixed an allocation bug. Initial test set works correctly now. + + Revision 1.2 2008/03/19 07:43:50 wayne.wong + Checkpoint. Added initial alloc/free area functions. + + Revision 1.1 2008/03/11 03:25:05 wayne.wong + Checkpoint. Preliminary version. + + +*---------------------------------------------------------------------------*/ + +#include "wfskrn_Volume.h" +#include "wfskrn_BCache.h" +#include "wfskrn_Api.h" +#include "randomlib.h" + + +void VolumeModuleInit() { + dbgv(OS_TPrintf("VolumeModuleInit()\n")); + // Mounted list is doubly linked and circular + // Free list is singly linked and NULL terminated + wkg.pMountedVolListAnchor = (VolumeInfo *)((u8*)&wkg.mountedVolListAnchor - (size_t)&((VolumeInfo *)0)->vl); + wkg.pMountedVolListAnchor->vl.pNext = wkg.pMountedVolListAnchor->vl.pPrev = wkg.pMountedVolListAnchor; + VolumeInfo *pVolInfo = wkg.pFreeVolList = wkg.aVolInfo; + VolumeInfo *pVolEnd = &pVolInfo[WFSKRN_MAX_VOLUMES]; + for(; pVolInfovl.pNext = pVolInfo+1; + } + pVolInfo[-1].vl.pNext = NULL; +} + + +VolumeInfo *VolumeAlloc() { + dbgv(OS_TPrintf("VolumeAlloc()\n")); + VolumeInfo *pVolInfo = wkg.pFreeVolList; + wkg.pFreeVolList = wkg.pFreeVolList->vl.pNext; + return pVolInfo; +} + + +void VolumeFree(VolumeInfo *pVolInfo) { + dbgv(OS_TPrintf("VolumeFree()\n")); +#if _DEBUG + memset(pVolInfo, 0, sizeof(*pVolInfo)); +#endif + pVolInfo->vl.pNext = wkg.pFreeVolList; + wkg.pFreeVolList = pVolInfo; +} + + +void VolumeAddToMountedList(VolumeInfo *pVolInfo) { + dbgv(OS_TPrintf("VolumeAddToMountedList()\n")); + pVolInfo->vl.pNext = wkg.pMountedVolListAnchor->vl.pNext; + pVolInfo->vl.pNext->vl.pPrev = pVolInfo; + wkg.pMountedVolListAnchor->vl.pNext = pVolInfo; + pVolInfo->vl.pPrev = wkg.pMountedVolListAnchor; +} + + +void VolumeRemoveFromMountedList(VolumeInfo *pVolInfo) { + dbgv(OS_TPrintf("VolumeRemoveFromMountedList()\n")); + pVolInfo->vl.pPrev->vl.pNext = pVolInfo->vl.pNext; + pVolInfo->vl.pNext->vl.pPrev = pVolInfo->vl.pPrev; +} + + +WFSKrnResult VolumeInitRootArea(VolumeInfo *pVolInfo, u8 nLog2SmallBlkSize) { + dbgv(OS_TPrintf("VolumeInitRootArea()\n")); + pVolInfo->rootAreaInfo.pParent = 0; + pVolInfo->rootAreaInfo.nRelStartBlkAdr = 0; + pVolInfo->rootAreaInfo.ah.nLog2BlkSize = nLog2SmallBlkSize; + pVolInfo->rootAreaInfo.pVolInfo = pVolInfo; + return AreaInit(&pVolInfo->rootAreaInfo); // for debug wfskrn +} + + +void VolumeConvertU32ToVolId(WFSVolumeId *pVolId, u32 nVolId) { + dbgv(OS_TPrintf("VolumeConvertU32ToVolId()\n")); + utf8 *pStr = pVolId->sStr; + u32 nI; + for(nI=0; nI<7; nI++) { + *pStr++ = "23456789abcdefghjklmnpqrstuvwxyz"[nVolId>>27]; // String has 32 characters + nVolId<<=5; + } + *pStr = 0; + pVolId->nLen = 7; +} + + +WFSKrnResult VolumeInit(VolumeInfo *pVolInfo, u32 nLog2BlkSize, u32 nNumBlks) { + dbgv(OS_TPrintf("VolumeInit()\n")); + // Arguments: + // pVolInfo [OUT] .. A pointer to the VolumeInfo struct to initialize. + // nVolumeId [IN] .. The randomly assigned volume identifier. + // nLog2BlkSize [IN] .. Size of small blocks (and meta-data blocks) in the root area. + // nNumBlks [IN] .. The total number of samll blocks contained in the volume. + // Synopsis: + // Initializes a new volume, updating the volume header on disk. + // Note: BCache module should have been already enabled. + pVolInfo->vh.mdh.nFlags = WFS_MDF_VOLUME_HDR; + pVolInfo->vh.nWfsVersion = (u16)((WFS_VERSION_MAJOR<<8) + WFS_VERSION_MINOR); + pVolInfo->vh.nBuildDate = BUILD_DATE; // ToDo: each module should supply a build date, so that the latest can be chosen - otherwise we only get the date this particular source file was compiled + utf8 sVolPath[WFS_MAX_VOLUME_ID_SIZE + 6]; + RxtItr rxi; + rxi.pStrPtr = sVolPath; + WFSVolumeId volId; + do { + pVolInfo->vh.nVolId = RandomU32(); // ToDo: Write a kernel specific random number generator which attempts to collect entropy from I/O, timing or other sources. + VolumeConvertU32ToVolId(&volId, pVolInfo->vh.nVolId); + osSNPrintf(sVolPath, WFS_MAX_VOLUME_ID_SIZE + 6, "/vol/%s", volId.sStr); + } while(PathCacheFind1(&rxi)); + BCacheEntry* pBce; + WFSKrnResult nResult = BCacheAllocMetaBlk(pVolInfo, VOLUME_HDR_BLK_ADR, BCACHE_FLAG_PINNED | BCACHE_FLAG_DIRTY, &pBce); + if(nResult < WFSKRN_RESULT_OK){ + return nResult; + } + VolumeHdr *pVh = (VolumeHdr*)pBce->pBlkPtr; +#if _DEBUG + if (!pVh) { + OS_TPrintf("Error: VolumeInit() WFSKRN_RESULT_VOLUME_BCACHE_ALLOC\n"); + return WFSKRN_RESULT_VOLUME_BCACHE_ALLOC; + } + if (nLog2BlkSize < pVolInfo->pDevInfo->dh.nLog2SectorSize) { + OS_TPrintf("Error: VolumeInit() WFSKRN_RESULT_VOLUME_INVALID_PARAMETER\n"); + return WFSKRN_RESULT_VOLUME_INVALID_PARAMETER; + } +#endif + *pVh = pVolInfo->vh; + BCacheUnpin(pVolInfo, VOLUME_HDR_BLK_ADR); +#if _DEBUG + pVolInfo->volId = volId; +#endif + pVolInfo->rootAreaInfo.pVolInfo = pVolInfo; + pVolInfo->rootAreaInfo.pParent = 0; + pVolInfo->rootAreaInfo.nRelStartBlkAdr = 0; + pVolInfo->rootAreaInfo.ah.nLog2BlkSize = nLog2BlkSize; + pVolInfo->rootAreaInfo.ah.nNumBlks = nNumBlks; + return AreaInit(&pVolInfo->rootAreaInfo); // for debug wfskrn +} + + +WFSKrnResult VolumeUnmount(VolumeInfo *pVolInfo) { + dbgv(OS_TPrintf("VolumeUnmount()\n")); + AreaClose(&pVolInfo->rootAreaInfo); + BCacheFlushVolume(pVolInfo); + pVolInfo->pDevInfo->pVolInfo = 0; + VolumeRemoveFromMountedList(pVolInfo); + VolumeFree(pVolInfo); + return WFSKRN_RESULT_OK; +} diff --git a/trunk/firmware/include/firm/fatfs/rtfs.h b/trunk/firmware/include/firm/fatfs/rtfs.h index 0b2f8dc..4873874 100644 --- a/trunk/firmware/include/firm/fatfs/rtfs.h +++ b/trunk/firmware/include/firm/fatfs/rtfs.h @@ -1014,7 +1014,7 @@ BOOLEAN pc_parsepath(byte *atopath, byte *afilename, byte *afileext, byte *apath void pc_ascii_strn2upper(byte *to, byte *from, int n); void pc_byte2upper(byte *to, byte *from); void pc_ascii_str2upper(byte *to, byte *from); -BOOLEAN pc_cs_malias(byte *alias, byte *input_file, int try); +BOOLEAN pc_cs_malias(byte *alias, byte *input_file, int try_); int unicode_cmp_to_ascii_char(byte *p, byte c); void unicode_assign_ascii_char(byte *p, byte c); byte *unicode_make_printable(byte *p); @@ -1034,7 +1034,7 @@ BOOLEAN validate_8_3_name(byte * name,int len); BOOLEAN validate_filename(byte * name, byte * ext); BOOLEAN pc_valid_sfn(byte *filename); BOOLEAN pc_valid_lfn(byte *filename); -BOOLEAN pc_cs_malias(byte *alias, byte *input_file, int try); +BOOLEAN pc_cs_malias(byte *alias, byte *input_file, int try_); BOOLEAN pc_ascii_fileparse(byte *fname, byte *fext, byte *alias); @@ -1048,7 +1048,7 @@ void pc_str2upper(byte *to, byte *from); BOOLEAN validate_filename(byte * name, byte * fext); BOOLEAN validate_8_3_name(byte * name,int len); BOOLEAN pc_valid_sfn(byte *filename); -BOOLEAN pc_cs_malias(byte *alias, byte *input_file, int try); +BOOLEAN pc_cs_malias(byte *alias, byte *input_file, int try_); byte *pc_cs_mfile(byte *to, byte *filename, byte *ext); byte *pc_ascii_mfile(byte *to, byte *filename, byte *ext); int rtfs_cs_strcmp(byte * s1, byte * s2); diff --git a/trunk/firmware/include/firm/nfs/revolution.h b/trunk/firmware/include/firm/nfs/revolution.h new file mode 100644 index 0000000..066e9de --- /dev/null +++ b/trunk/firmware/include/firm/nfs/revolution.h @@ -0,0 +1,17 @@ +#ifndef __REVOLUTION_H__ +#define __REVOLUTION_H__ + +#include +#include +#include +//#include +//#include + +typedef u32 OSPriority; + +#define ASSERT SDK_ASSERT + +//typedef BOOL bool; +//typedef BOOL WFSBool; + +#endif // __REVOLUTION_H__ diff --git a/trunk/firmware/include/firm/nfs/revolution/wfs.h b/trunk/firmware/include/firm/nfs/revolution/wfs.h new file mode 100644 index 0000000..2429392 --- /dev/null +++ b/trunk/firmware/include/firm/nfs/revolution/wfs.h @@ -0,0 +1,1444 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFS library + File: wfs.h - Provides a standard interface to the Wii file system + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfs.h,v $ + Revision 1.104 2008/12/03 00:14:21 kondo_masahiro + Added a argument of WFSFlush(). + + Revision 1.103 2008/10/21 10:46:43 kondo_masahiro + Added new function WFSWriteFileAndDiscard + + Revision 1.102 2008/08/05 02:16:15 paul + removed unused error message WFS_RESULT_DIRECTORY_FULL + + Revision 1.101 2008/07/10 10:27:30 nakanose_jin + bye inheritance & dev_full error + + Revision 1.100 2008/07/02 06:52:43 nakanose_jin + bye inheritance & dev_full error + + Revision 1.99 2008/06/20 18:38:47 paul + Changed comment for WFSCreateDirectory + + Revision 1.98 2008/04/25 17:26:30 paul + Removed WFSExitAsync remnants. Updated nCidx comment. Updated nQuota comment. + + Revision 1.97 2008/04/08 18:19:58 paul + Moved permissions-related declarations to wfsPerm.h. Moved callback definitions to wfsTypes.h. Moved error-related definitions to wfsError.h. + + Revision 1.96 2008/03/31 14:04:02 ueno + Modified WFS_DP_*_EDIT and WFS_DP_INHERIT_DP_* bits to check if permissions are editable, easily. + Added permission masks. + + Revision 1.95 2008/03/26 02:06:19 ueno + Fixed typos. + + Revision 1.94 2008/03/25 09:11:49 ueno + Revised permission flags and permission APIs. + + Revision 1.93 2008/03/25 00:26:21 ueno + Added permission APIs. + + Revision 1.92 2008/02/08 09:50:22 paul + Added WFS_RESULT_DEV_IN_USE + + Revision 1.91 2008/02/08 04:39:05 paul + Changed bForce parameter of WFSUnmountVolume to WFSBool + + Revision 1.90 2008/02/08 01:32:24 nakanose_jin + WFSUnmountVolume : add force-closing option + + Revision 1.89 2008/02/07 13:02:47 nakanose_jin + WFSUnmountVolume : Add force-close option (but only in detach condition) + + Revision 1.88 2008/02/06 01:11:19 paul + Added new error code, WFS_RESULT_NOT_DIRECTORY for WFSSetCurrentDirectory and WFSSetHomeDirectory. + + Revision 1.87 2008/01/28 05:46:02 paul + Clarified the comment about file access permission during WFSCreateAndOpenFile + + Revision 1.86 2008/01/17 07:51:59 ooizumi + Moved several definitions to wfstypes.h. + + Revision 1.85 2008/01/10 09:34:35 nakanose_jin + bye - WFSExitAsync + + Revision 1.84 2007/12/12 19:58:56 paul + Clarified WFSSearchDirectoryFirst spec - handle is not created when an error occurs. + + Revision 1.83 2007/12/12 07:45:08 paul + Added WFSGetFileSizeAsync - WFSGetFileSize is no longer implemented on the client side + + Revision 1.82 2007/12/08 00:01:57 paul + Updated the comment for WFS_RESULT_LIB_NOT_INITIALIZED + + Revision 1.81 2007/11/27 02:58:20 nakanose_jin + add extern "C" + + Revision 1.80 2007/11/22 09:40:05 nakanose_jin + Add WFS_RESULT_NOT_FILE for WFSFileOpen + + Revision 1.79 2007/11/22 01:48:29 paul + Added nFileSize to WFSCloseFileAsync + + Revision 1.78 2007/11/21 22:15:41 paul + Added WFS_RESULT_ALREADY_MOUNTED + + Revision 1.77 2007/11/20 00:16:34 paul + Removed WFS_RESULT_BUSY from WFSGetFilePosition, WFSSetFilePosition, WFSGetFileSize. + + Revision 1.76 2007/11/16 13:12:04 nakanose_jin + modify comment for NOT_FOUND + + Revision 1.75 2007/11/16 02:33:57 paul + Changed error code for WFSMountDevice(). Now, trying to mount the same device twice results in WFS_RESULT_ALREADY_EXISTS error. + + Revision 1.74 2007/11/16 01:29:21 paul + Added WFSFlush() + + Revision 1.73 2007/11/15 23:40:42 paul + Updated device name errors to WFS_RESULT_NOT_FOUND + + Revision 1.72 2007/11/09 01:18:37 paul + Updated validation error checks for several functions + Updated max path depth + + Revision 1.71 2007/11/02 00:34:38 paul + now logging updates. + Changed WFSReadFileAsync, WFSWriteFileAsync to require explicit start position + +*---------------------------------------------------------------------------*/ + +#ifndef __WFS_H__ +#define __WFS_H__ + +// --------------------------------------------------------------------- +// wfs.h - Wii File System (WFS) API +// --------------------------------------------------------------------- + +// Provides a standard interface to the Wii file system + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + + +//------------------------------------------------------------------------------------------------------ +// WFS Path Names +//------------------------------------------------------------------------------------------------------ +// Throughout the WFS API, path names can be absolute, or relative to the CurrentDirectory. +// +// The following conventions are used: +// File names are read and written case-sensitively, but compared case-insensitively. +// File names can use any characters except * ? / +// WFS uses forwards slashes / as directory separators. +// * and ? are used to specify wild card patterns to directory search. +// Non-ascii file names are supported using the multi-byte utf-8 format. +// Path names must be NULL terminated. +// +// File names including . or ~ are possible, except: +// The following names have special meanings, and cannot be used as file names: "~", ".", ".." +// "" or "." refers to the current directory. +// ".." refers to the parent directory. +// "~" refers to a title's home directory. +// +// Path names starting with "/" are absolute. +// Path names starting with "~/" are relative to the title's home directory, +// otherwise they are relative to CurrentDirectory. +// +// All devices have a device name entry in "/dev". If the WFSDevType (obtained via WFSGetDeviceInfo) +// of the device is WFS_DEVTYPE_SD or WFS_DEVTYPE_USB_MSC, the device may or may not have +// a WFS volume. A WFS volume can be created on the device with WFSInitializeDevice. At volume +// creation time, the volume is assigned a (relatively) unique Volume Id. The device's WFS volume +// is made accessible by mounting it. After a volume is mounted, it is accessible as +// "/vol/VolumeId" where VolumeId is the volume's unique Id. The "/vol" directory has an entry for +// each mounted WFS volume. Even with mounted devices, a device name entry for mounted volumes +// remains in "/dev" for that device. +//------------------------------------------------------------------------------------------------------ + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSInit +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSInit(void *pWorkSpaceBuffer, u32 nWorkSpaceSize); +// Arguments: +// ---------- +// pWorkSpaceBuffer .. Points to a workspace buffer that will be used by WFS as workspace. Must be 64 Byte aligned. +// nWorkSpaceSize .. The size of the workspace buffer. Must be >= WFS_MIN_WORK_SPACE_SIZE. +// +// Return Values: +// -------------- +// Possible return values for WFSSetCurrentDirectory: +// WFS_RESULT_OK .. WFS has been successfully initialized +// WFS_RESULT_LIB_ALREADY_INITIALIZED .. WFS library has already been initialized. +// WFS_RESULT_INVALID .. The input parameters are invalid +// +// Description: +// ------------ +// Call this function to initialize the WFS library. +// NOTE: If an attach callback has been registered using WFSSetAttachDeviceCallback, +// it will be called for any existing attached devices during the processing of WFSInit + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSExit +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSExit(); +// Arguments: +// ---------- +// none +// +// Return Values: +// -------------- + +// Possible return values for WFSExit: +// WFS_RESULT_OK .. Successfully mounted the device. VolumeId has been added to the "/vol" directory. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_LIB_NOT_INITIALIZED .. The WFS library has not been initialized. +// +// Description: +// ------------ +// Waits until all outstanding operations have been completed, then closes the library and frees up +// the workspace memory specified in WFSInit. No further WFS calls can be made until the library +// is re-initialized. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSetAttachDeviceCallback +//-------------------------------------------------------------------------------------------------------------- +void WFSSetAttachDeviceCallback(utf8 *sDeviceNameBuffer, WFSDeviceCallback cbAttachDevice, void *pUserData); +// Arguments: +// ---------- +// sDeviceNameBuffer .. A pointer to a buffer of at least WFS_MAX_DEVICE_NAME_SIZE+1 bytes which will be overwritten with the +// NULL terminated device name, and passed to the callback. (output) +// cbAttachDevice .. A pointer to the function to call when a storage device is attached. +// pUserData .. Arbitrary user data that is passed to the callback function. +// +// Return Values: +// -------------- +// None. +// +// Description: +// ------------ +// This function is used to register callback functions for notification of storage devices or +// storage media being attached. +// +// NOTE: Already attached devices can be enumerated by passing "/dev/*" as the search pattern to WFSSearchDirectoryFirst. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetAttachDeviceCallback +//-------------------------------------------------------------------------------------------------------------- +void WFSGetAttachDeviceCallback(utf8 **psDeviceName, WFSDeviceCallback *pCbAttachDevice, void **ppUserData); +// Arguments: +// ---------- +// psDeviceName .. A pointer to a variable to receive the current value of the sDeviceNameBuffer pointer +// that was previously set using WFSSetAttachDeviceCallback. +// pCbAttachDevice .. A pointer to a variable to receive the current callback function pointer. +// ppUserData .. A pointer to a variable to receive the current user data pointer. +// +// Return Values: +// -------------- +// None. +// +// Description: +// ------------ +// This function is used to get information about the existing callback functions for notification of +// storage devices or storage media being attached. The information can be saved and restored later, +// or can be used to implement callback chaining. +// ("Callback chaining" means calling the old callback function from within the new callback function). + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSetDetachDeviceCallback +//-------------------------------------------------------------------------------------------------------------- +void WFSSetDetachDeviceCallback(utf8 *sDeviceNameBuffer, WFSDeviceCallback cbDetachDevice, void *pUserData); +// Arguments: +// ---------- +// sDeviceName .. A pointer to a buffer of at least WFS_MAX_DEVICE_NAME_SIZE+1 bytes, which is overwritten +// with the NULL terminated device name, and passed to the callback. (output) +// cbDetachDevice .. A pointer to the function to call when a storage device is detached. +// pUserData .. Arbitrary user data that is passed to the callback function. +// +// Return Values: +// -------------- +// None. +// +// Description: +// ------------ +// This function is used to register callback functions for notification of storage devices or +// storage media being detached. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetDetachDeviceCallback +//-------------------------------------------------------------------------------------------------------------- +void WFSGetDetachDeviceCallback(utf8 **psDeviceName, WFSDeviceCallback *pCbDetachDevice, void **ppUserData); +// Arguments: +// ---------- +// psDeviceName .. A pointer to a variable to receive the current value of the sDeviceName pointer +// that was previously set using WFSSetDetachDeviceCallback. +// pCbDetachDevice .. A pointer to a variable to receive the current callback function pointer. +// ppUserData .. A pointer to a variable to receive the current user data pointer. +// +// Return Values: +// -------------- +// None. +// +// Description: +// ------------ +// This function is used to get information about the existing callback functions for notification of +// storage devices or storage media being detached. The information can be saved and restored later, +// or can be used to implement callback chaining. +// ("Callback chaining" means calling the old callback function from within the new callback function). + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetDeviceInfo, WFSGetDeviceInfoAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSGetDeviceInfo (const utf8 *sDeviceName, WFSDeviceInfo *pDi); +WFSResult WFSGetDeviceInfoAsync(const utf8 *sDeviceName, WFSDeviceInfo *pDi, void *pUserData, WFSDeviceInfoCallback cb); +// Arguments: +// ---------- +// sDeviceName .. A pointer to the NULL terminated device name. (input) +// pDi .. A pointer to a WFSDeviceInfo struct to receive the requested device information. (output) +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a device callback function. +// +// Return Values: +// -------------- +// Possible return values for WFSGetDeviceInfo: +// WFS_RESULT_OK .. Successfully retrieved the device information. *pDi has been updated. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// Possible immediate return values for WFSGetDeviceInfoAsync: +// WFS_RESULT_OK .. GetDeviceInfo request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid. +// Possible values of nResult passed to WFSGetDeviceInfoAsync callback: +// WFS_RESULT_OK .. Successfully retrieved the device information. *pDi has been updated. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// +// Description: +// ------------ +// These functions return the device information associated with a device name. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSMountDevice, WFSMountDeviceAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSMountDevice (const utf8 *sDeviceName, utf8 *sVolumeIdBuffer); +WFSResult WFSMountDeviceAsync(const utf8 *sDeviceName, utf8 *sVolumeIdBuffer, void *pUserData, WFSDeviceVolumeCallback cb); +// Arguments: +// ---------- +// sDeviceName .. A pointer to the NULL terminated device name. (input) +// sVolumeIdBuffer .. A pointer to a buffer of at least WFS_MAX_VOLUME_ID+1 bytes which will be overwritten with the +// NULL terminated volume id. (output) +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a device callback function. +// +// Return Values: +// -------------- +// Possible return values for WFSMountDevice: +// WFS_RESULT_OK .. Successfully mounted the device. VolumeId has been added to the "/vol" directory. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sDeviceName is too long, sVolumeIdBuffer is NULL. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_DEV_UNUSABLE .. Device is not accessible, e.g. because it is an unsupported device, or has an unknown format. +// WFS_RESULT_DEV_NOT_INITIALIZED .. Device not formatted, or does not yet contain a WFS volume +// WFS_RESULT_VOL_ID_ERROR .. Device has the same Id as an already mounted device. (This could happen if the User backs up an entire WFS volume using a PC) +// WFS_RESULT_ALREADY_MOUNTED .. The device is already mounted. +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// Possible immediate return values for WFSMountDeviceAsync: +// WFS_RESULT_OK .. WFSMountDevice request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sDeviceName is too long, sVolumeIdBuffer is NULL. +// Possible values of nResult passed to WFSMountDeviceAsync callback: +// WFS_RESULT_OK .. Successfully mounted the device. VolumeId has been added to the "/vol" directory. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_DEV_UNUSABLE .. Device is not accessible, e.g. because it is an unsupported device, or has an unknown format. +// WFS_RESULT_DEV_NOT_INITIALIZED .. Device not formatted, or does not yet contain a WFS volume +// WFS_RESULT_VOL_ID_ERROR .. Device has the same Id as an already mounted device. (This could happen if the User backs up an entire WFS volume using a PC) +// WFS_RESULT_ALREADY_MOUNTED .. The device is already mounted. +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName +// +// Description: +// ------------ +// These functions are used to mount a WFS volume. +// The mount point is "/vol/VolumeId" as described in "WFS Path Names". + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSUnmountVolume, WFSUnmountVolumeAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSUnmountVolume (const utf8 *sVolumeId, WFSBool bForce); +WFSResult WFSUnmountVolumeAsync(const utf8 *sVolumeId, WFSBool bForce, void *pUserData, WFSUnmountVolumeCallback cb); +// Arguments: +// ---------- +// sVolumeId .. pointer to a string buffer containing the mounted Volume Id. +// bForce .. If set to TRUE, forces the volume to be unmounted regardless of open files. +// NOTE: This flag is only valid if the device is currently detached. Un-flushed data will be lost. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a device callback function. +// +// Return Values: +// -------------- +// Possible return values for WFSUnmountVolume: +// WFS_RESULT_OK .. Successfully unmounted the device. The Volume Id has been removed from the "/vol" directory. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. sVolumeId is too long, or NULL. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_FILE_OPEN .. The volume cannot be closed because one or more files within it are currently open. +// WFS_RESULT_NOT_FOUND .. No mounted volume exists which matches sVolumeId. +// Possible immediate return values for WFSUnmountVolumeAsync: +// WFS_RESULT_OK .. WFSMountDevice request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. sVolumeId is too long, or NULL. +// Possible values of nResult passed to WFSUnmountVolumeAsync callback: +// WFS_RESULT_OK .. Successfully unmounted the device. The Volume Id has been removed from the "/vol" directory. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_FILE_OPEN .. The volume cannot be closed because one or more files within it are currently open. +// WFS_RESULT_NOT_FOUND .. No mounted volume exists which matches sVolumeId +// +// Description: +// ------------ +// These functions are used to unmount a WFS volume. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSInitializeDevice, WFSInitializeDeviceAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSInitializeDevice (const utf8 *sDeviceName); +WFSResult WFSInitializeDeviceAsync(const utf8 *sDeviceName, void *pUserData, WFSInitializeDeviceCallback cb); +// Arguments: +// ---------- +// sDeviceName .. A pointer to the NULL terminated device name. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a device callback function. +// +// Return Values: +// -------------- +// Possible return values for WFSInitializeDevice: +// WFS_RESULT_OK .. Initialization was successful. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid. e.g. sDeviceName is too long, or NULL. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_DEV_UNUSABLE .. Unable to initialize device. +// WFS_RESULT_DEV_IN_USE .. Trying to initialize a device which is in use (mounted) by one or more clients. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. The device may not be initialized by the calling application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// Possible immediate return values for WFSInitializeDeviceAsync: +// WFS_RESULT_OK .. Initialization request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid. e.g. sDeviceName is too long, or NULL. +// Possible values of nResult passed to WFSInitializeDeviceAsync callback: +// WFS_RESULT_OK .. Initialization was successful. +// WFS_RESULT_DEV_UNUSABLE .. Unable to initialize device. +// WFS_RESULT_DEV_IN_USE .. Trying to initialize a device which is in use (mounted) by one or more clients. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. The device may not be initialized by the calling application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// +// Description: +// ------------ +// These functions can be used to initialize a device (format, and create a WFS volume on the device). +// When the volume is created it is assigned a (relatively) unique Volume Id. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetVolumeId, WFSGetVolumeIdAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSGetVolumeId (const utf8 *sDeviceName, utf8 *sVolumeIdBuffer); +WFSResult WFSGetVolumeIdAsync(const utf8 *sDeviceName, utf8 *sVolumeIdBuffer, void *pUserData, WFSDeviceVolumeCallback cb); +// Arguments: +// ---------- +// sDeviceName .. A pointer to the NULL terminated device name. (input) +// sVolumeIdBuffer .. A pointer to a buffer of at least WFS_MAX_VOLUME_ID+1 bytes which will be overwritten with the volume id. (output) +// pDi .. A pointer to a WFSDeviceInfo struct to receive the requested device information. (output) +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a device callback function. +// +// Return Values: +// -------------- +// Possible return values for WFSGetVolumeId: +// WFS_RESULT_OK .. Successfully retrieved the device information. *sVolumeId has been updated. (In all other cases sVolumeId is unchanged) +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid. e.g. sDeviceName is too long or NULL, sVolumeIdBuffer is NULL. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_DEV_NOT_INITIALIZED .. No WFS volume exists on the device. +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// Possible immediate return values for WFSGetVolumeIdAsync: +// WFS_RESULT_OK .. GetDeviceInfo request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sDeviceName is too long or NULL, sVolumeIdBuffer is NULL. +// Possible values of nResult passed to WFSGetVolumeIdAsync callback: +// WFS_RESULT_OK .. Successfully retrieved the device information. *sVolumeId has been updated. (In all other cases sVolumeId is unchanged) +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_DEV_NOT_INITIALIZED .. No WFS volume exists on the device. +// WFS_RESULT_NOT_FOUND .. No attached device exists which matches sDeviceName. +// +// Description: +// ------------ +// These functions can be used to determine if a volume exists, and if so retrieve the volume id. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetFreeSpaceSize, WFSGetFreeSpaceSizeAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSGetFreeSpaceSize (const utf8 *sPathName, u64 *pSize); +WFSResult WFSGetFreeSpaceSizeAsync(const utf8 *sPathName, void *pUserData, WFSGetFreeSpaceCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of a file or directory. +// See "WFS Path Names" for rules about path names. +// pSize .. A pointer to a u64 to receive the free space size value. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSGetFreeSpaceSizeAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSGetFreeSpaceSize +// WFS_RESULT_OK .. Successfully calculated the free space size. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sPathName is too long, too deep, or NULL; or pSize is NULL. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_PERMISSION .. you have no list permission on this object. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_NOT_FOUND .. The specified path does not exist. +// Possible immediate return values for WFSGetFreeSpaceSizeAsync: +// WFS_RESULT_OK .. GetDeviceInfo request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sPathName is too long, too deep, or NULL. +// Possible values of nResult passed to WFSGetDeviceInfoAsync callback: +// WFS_RESULT_OK .. Successfully calculated the free space size. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the operation completed. +// WFS_RESULT_PERMISSION .. you have no list permission on this object. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_NOT_FOUND .. The specified path does not exist. +// +// Description: +// ------------ +// Use this function to calculate the number of bytes free on the device associated with a path name. +// The result also depends on the TitleId of the calling process, since titles would typically have +// a fixed storage quota assigned. +// +// Examples: +// Applying these functions to "/vol/VolumeId/tmp" would return the remaining free space quota +// of the shared tmp directory. +// Applying these functions to "/vol/VolumeId/titles/CompanyId/TitleId", would +// return the remaining free space quota of the title's home directory. +// Applying these functions to "/vol/VolumeId/" would return the sum of the +// free space quotas of the shared tmp directory, and the title's home directory. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSetHomeDirectory, WFSSetHomeDirectoryAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSetHomeDirectory (const utf8 *sAbsPathName); +WFSResult WFSSetHomeDirectoryAsync(const utf8 *sAbsPathName, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sAbsPathName .. absolute path name to a valid directory. +// pUserData .. arbitrary user data that is passed to the callback function. +// cb .. pointer to a callback function to receive the result of WFSCreateDirectoryAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSetHomeDirectory: +// WFS_RESULT_OK .. The directory is valid, and prepared for access. Only in this case is the home directory changed. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. sAbsPathName was invalid: e.g. too long, too deep, or NULL. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. This function is only available to SYSTEM. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to access directory. +// WFS_RESULT_NOT_FOUND .. The specified directory does not exist. +// WFS_RESULT_NOT_DIRECTORY .. The specified path is not a directory. +// Possible immediate return values for WFSSetHomeDirectoryAsync: +// WFS_RESULT_OK .. SetCurrentDirectory request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. sAbsPathName was invalid: e.g. too long, too deep, or NULL. +// Possible values of nResult passed to WFSSetHomeDirectoryAsync callback: +// WFS_RESULT_OK .. The directory is valid, and prepared for access. Only in this case is the home directory changed. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. This function is only available to SYSTEM. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to access directory. +// WFS_RESULT_NOT_FOUND .. The specified directory does not exist. +// WFS_RESULT_NOT_DIRECTORY .. The specified path is not a directory. +// +// Description: +// ------------ +// Sets the internal home directory which can be used at the start of relative path names as ~/ +// This function will check that the specified directory exists. +// This function is intended for use by the application launcher. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSetCurrentDirectory, WFSSetCurrentDirectoryAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSetCurrentDirectory (const utf8 *sPathName); +WFSResult WFSSetCurrentDirectoryAsync(const utf8 *sPathName, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. absolute or relative path name to a valid directory. +// See "WFS Path Names" for rules about path names. +// pUserData .. arbitrary user data that is passed to the callback function. +// cb .. pointer to a callback function to receive the result of WFSCreateDirectoryAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSetCurrentDirectory: +// WFS_RESULT_OK .. The directory is valid, and prepared for access. Only in this case is the current directory changed. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. sPathName was invalid: e.g. too long, too deep, or NULL. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. you have no list permission on this object. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to access directory. +// WFS_RESULT_NOT_FOUND .. The specified directory does not exist. +// WFS_RESULT_NOT_DIRECTORY .. The specified path is not a directory. +// Possible immediate return values for WFSSetCurrentDirectoryAsync: +// WFS_RESULT_OK .. SetCurrentDirectory request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. sPathName was invalid: e.g. too long, too deep, or NULL. +// Possible values of nResult passed to WFSSetCurrentDirectoryAsync callback: +// WFS_RESULT_OK .. The directory is valid, and prepared for access. Only in this case is the current directory changed. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. you have no list permission on this object. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to access directory. +// WFS_RESULT_NOT_FOUND .. The specified directory does not exist. +// WFS_RESULT_NOT_DIRECTORY .. The specified path is not a directory. +// +// Description: +// ------------ +// Sets the internal current directory which is used to resolve relative path names. +// This function will check that the specified directory exists and is accessable to the current application. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetCurrentDirectory +//-------------------------------------------------------------------------------------------------------------- +s32 WFSGetCurrentDirectory(utf8 *sAbsPathNameBuffer, s32 nBufferSize); +// Arguments: +// ---------- +// sAbsPathNameBuffer .. A pointer to a buffer to receive a copy of the absolute path name of the Current Directory. +// nBufferSize .. size of the buffer. +// +// Return Values: +// -------------- +// >0 .. nBufferSize was not large enough. This is the number of bytes required to hold +// the path name of the current directory including the terminating NULL character. +// WFS_RESULT_OK .. The absolute path name of the current directory was copied to the user buffer. +// WFS_RESULT_INVALID .. The input parameters were invalid, e.g. sAbsPathNameBuffer is NULL. +// WFS_RESULT_LIB_NOT_INITIALIZED .. The WFS library has not been initialized. Please call WFSInit(..) +// +// Description: +// ------------ +// Copies the current directory to the buffer pointed to by sAbsPathName. +// nBufferSize should contain the size of the buffer including terminating NULL character. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSCreateDirectory, WFSCreateDirectoryAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSCreateDirectory (const utf8 *sPathName, u32 nFlags, u64 nQuota); +WFSResult WFSCreateDirectoryAsync(const utf8 *sPathName, u32 nFlags, u64 nQuota, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of the directory that is to be created. +// See "WFS Path Names" for rules about path names. +// nFlags .. should be a combination of the permission or wfs flags: WFS_FLAG_* or WFS_PERM_* (see wfsPerm.h) +// Note: WFS_FLAG_DIRECTORY will be set whether it is included or not. +// nQuota .. This parameter can be used to restrict the total size of the hierarchy beneath the new directory. +// The quota includes space for meta-data, so the total usable data size will be less than the quota. +// A quota of 0 means there is no size restriction, i.e. the quota is Infinity. +// Otherwise the quota must be >= WFS_MIN_DIRECTORY_QUOTA. +// The directory will be allocated as a contiguous area if (nFlags & WFS_FLAG_CONTIGUOUS_AREA) && (nQuota >= WFS_MIN_DIRECTORY_QUOTA) +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSCreateDirectoryAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSCreateDirectory: +// WFS_RESULT_OK .. The directory was created. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Path is too deep. (For directories the depth limit is 1 less than for files). +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the parent directory do not permit WRITE access to this application. +// WFS_RESULT_AUTHENTICATION .. Could occur when writing to a directory belonging to another App, whose access key no longer exists. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to create the directory. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_ALREADY_EXISTS .. A directory or file with the same name already exists. +// WFS_RESULT_NOT_FOUND .. Could not find the parent directory specified in the path name. +// Possible immediate return values for WFSCreateDirectoryAsync: +// WFS_RESULT_OK .. CreateDirectory request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Path is too deep. (For directories the depth limit is 1 less than for files). +// Possible values of nResult passed to WFSCreateDirectoryAsync callback: +// WFS_RESULT_OK .. The directory was created. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the parent directory do not permit WRITE access to this application. +// WFS_RESULT_AUTHENTICATION .. Could occur when writing to a directory belonging to another App, whose access key no longer exists. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to create the directory. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_ALREADY_EXISTS .. A directory or file with the same name already exists. +// WFS_RESULT_NOT_FOUND .. Could not find the parent directory specified in the path name. +// +// Description: +// ------------ +// Use these functions to create directories. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSCreateAndOpenFile, WFSCreateAndOpenFileAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSCreateAndOpenFile (const utf8 *sPathName, u32 nFlags, WFSContentIdx nCidx, WFSFileSize nPreAllocateSize, WFSFileHandle *pFh); +WFSResult WFSCreateAndOpenFileAsync(const utf8 *sPathName, u32 nFlags, WFSContentIdx nCidx, WFSFileSize nPreAllocateSize, void *pUserData, WFSFileOpCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of the file that is to be created and opened. +// See "WFS Path Names" for rules about path names. +// nFlags .. should be a combination of the permission flags: WFS_PERM_* (see wfsPerm.h) +// Note: This function will always open the file for writing, even if nFlags==WFS_PERM_OWNER_READ_ONLY. +// The specified permissions only take effect after the file is closed, and opened again. +// nCidx .. The content idx of the file being created. Content idx is the unit of access control for purchased content. +// For game-save or temporary files, set nCidx to 0. Files having nCidx >0 is referred to as "Content". +// nPreAllocateSize .. The amount of disk-space to pre-allocate for the file. This can be used to assist the file system +// with reducing disk fragamentation. If the eventual size is unknown, set nPreAllocateSize to 0. +// nPreAllocateSize can be used in conjunction with the NO_CHANGE_SIZE flag to allocate a fixed size file. +// pFh .. A pointer to a file handle which is passed back by the library. +// The file handle should be used to specify this file in subsequent file operations. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSCreateAndOpenFileAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSCreateAndOpenFile: +// WFS_RESULT_OK .. The file was created. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Filename is too long, Path is too deep. +// WFS_RESULT_MAX_HANDLES .. Maximum number of concurrent file handles already in use. (Too many files open). +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the parent directory do not permit WRITE access to this application. +// WFS_RESULT_AUTHENTICATION .. Could occur when writing to a directory belonging to another App, whose access key no longer exists. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to create the file. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_ALREADY_EXISTS .. A directory or file with the same name already exists. +// WFS_RESULT_NOT_FOUND .. Could not find the parent directory specified in the path name. +// Possible immediate return values for WFSCreateAndOpenFileAsync: +// WFS_RESULT_OK .. CreateAndOpen request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Filename is too long, Path is too deep. +// Possible values of nResult passed to WFSCreateAndOpenFileAsync callback: +// WFS_RESULT_OK .. The file was created. +// WFS_RESULT_MAX_HANDLES .. Maximum number of concurrent file handles already in use. (Too many files open). +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the parent directory do not permit WRITE access to this application. +// WFS_RESULT_AUTHENTICATION .. Could occur when writing to a directory belonging to another App, whose access key no longer exists. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to create the file. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_ALREADY_EXISTS .. A directory or file with the same name already exists. +// WFS_RESULT_NOT_FOUND .. Could not find the parent directory specified in the path name. +// +// Description: +// ------------ +// Use these functions to create and open new files. +// These functions cannot be used to overwrite existing files (or directories). Use WFSDelete first. +// Note: This function will always open the file with WFS_ACCESS_RW access permission, even if +// nFlags==WFS_PERM_OWNER_READ_ONLY. The specified permission flags only take effect after +// the file is closed, and opened again. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetAttributes, WFSGetAttributesAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSGetAttributes (const utf8 *sPathName, WFSFileAttributes *pFa); +WFSResult WFSGetAttributesAsync(const utf8 *sPathName, WFSFileAttributes *pFa, void *pUserData, WFSGetAttributesCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of a file or directory. +// See "WFS Path Names" for rules about path names. +// pFa .. A pointer to a WFSFileAttributes struct which will be overwritten with the details of the specified file or directory. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSGetAttributesAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSGetAttributes: +// WFS_RESULT_OK .. The specified file or directory was found. Details are returned in *pFi. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// Possible immediate return values for WFSGetAttributesAsync: +// WFS_RESULT_OK .. The request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// Possible values of nResult passed to WFSGetAttributesAsync callback: +// WFS_RESULT_OK .. The specified file or directory was found. Details are returned in *pFi. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// +// Description: +// ------------ +// Use these functions to read the attributes of a file or directory. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSDelete, WFSDeleteAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSDelete (const utf8 *sPathName); +WFSResult WFSDeleteAsync(const utf8 *sPathName, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of the file or directory which is to be deleted. +// See "WFS Path Names" for rules about path names. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSChangePermissionsAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSDelete: +// WFS_RESULT_OK .. Target was deleted successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the delete operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the parent directory does not permit WFS_PERM_D_CHANGE access from this application, or permission flags of the target do not allow WFS_PERM_*_DELETE_MOVE access. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory does not exist. +// WFS_RESULT_NOT_EMPTY .. Cannot delete a directory that is not empty. +// WFS_RESULT_FILE_OPEN .. Cannot delete an open file. +// Possible immediate return values for WFSDeleteAsync: +// WFS_RESULT_OK .. Delete request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// Possible values of nResult passed to WFSDeleteAsync callback: +// WFS_RESULT_OK .. Target was deleted successfully +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the delete operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the parent directory does not permit WFS_PERM_D_CHANGE access from this application, or permission flags of the target do not allow WFS_PERM_*_DELETE_MOVE access. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory does not exist. +// WFS_RESULT_NOT_EMPTY .. Cannot delete a directory that is not empty. +// WFS_RESULT_FILE_OPEN .. Cannot delete an open file. +// +// Description: +// ------------ +// Use these functions to delete files or directories. +// To delete a file, it must not be open. To delete a directory, it must be empty. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSMoveLocal, WFSMoveLocalAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSMoveLocal (const utf8 *sSrcPathName, const utf8 *sDstPathName); +WFSResult WFSMoveLocalAsync(const utf8 *sSrcPathName, const utf8 *sDstPathName, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sSrcPathName .. Relative or absolute path to the source file. +// sDstPathName .. Relative or absolute path to the destination file. +// See "WFS Path Names" for rules about path names. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSMoveLocalAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSMoveLocal: +// WFS_RESULT_OK .. Target was moved successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Trying to move between different devices, Trying to move a directory to it's own sub-directory, File name is too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the move operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the source or destination parent directories do not permit WFS_PERM_D_CHANGE access from this application, or permission flags of the target do not allow WFS_PERM_*_DELETE_MOVE access. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_ALREADY_EXISTS .. A directory or file with the same name as the destination path already exists. +// WFS_RESULT_NOT_FOUND .. The specified source file or path does not exist. +// WFS_RESULT_FILE_OPEN .. Cannot move or rename an open file, or a directory hirearchy which contains an open file, or open search handle. +// Possible immediate return values for WFSMoveLocalAsync: +// WFS_RESULT_OK .. Move request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Trying to move between different devices, Trying to move a directory to it's own sub-directory, File name is too long, Path is too deep. +// Possible values of nResult passed to WFSMoveLocalAsync callback: +// WFS_RESULT_INVALID .. After moving sSrcPathName to the new location, it's deepest descendent path name would be too long, or too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the move operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the source or destination parent directories do not permit WFS_PERM_D_CHANGE access from this application, or permission flags of the target do not allow WFS_PERM_*_DELETE_MOVE access. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_ALREADY_EXISTS .. A directory or file with the same name as the destination path already exists. +// WFS_RESULT_NOT_FOUND .. The specified source file or path does not exist. +// WFS_RESULT_FILE_OPEN .. Cannot move or rename an open file, or a directory hirearchy which contains an open file, or open search handle. +// +// Description: +//------------ +// Use these functions to move or rename files or directories within the same volume. +// NOTE 1: These functions cannot be used to move a file from one volume to a different volume. +// NOTE 2: Moving or Renaming a file may cause the number of blocks required to store the directory information to increase, +// therefore errors associated with capacity are possible. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSOpenFile, WFSOpenFileAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSOpenFile (const utf8 *sPathName, WFSAccess nDesiredAccess, WFSFileHandle *pFh); +WFSResult WFSOpenFileAsync(const utf8 *sPathName, WFSAccess nDesiredAccess, void *pUserData, WFSFileOpCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of the file which is to be opened. +// See "WFS Path Names" for rules about path names. +// nDesiredAccess .. The kind of access that is required: should be one of the WFS_ACCESS_* options. +// pFh .. A pointer to a file handle which is passed back by the library. +// The file handle should be used to specify this file in subsequent file operations. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSOpenAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSOpen: +// WFS_RESULT_OK .. File was opened successfuly. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// WFS_RESULT_MAX_HANDLES .. Maximum number of concurrent file handles already in use. (Too many files open). +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the open operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Trying to open a file for write access, but device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the target do not permit requested access from this application (WFS_PERM_*_READ or WFS_PERM_*_WRITE). +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to open the file. +// WFS_RESULT_NOT_FOUND .. The specified file or path does not exist. +// WFS_RESULT_NOT_FILE .. The specified file is a directory. +// WFS_RESULT_FILE_OPEN .. Cannot open a file more than once unless all opens are WFS_ACCESS_READ. +// Possible immediate return values for WFSOpenAsync: +// WFS_RESULT_OK .. Open request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// Possible values of nResult passed to WFSOpenAsync callback: +// WFS_RESULT_OK .. File was opened successfuly. +// WFS_RESULT_MAX_HANDLES .. Maximum number of concurrent file handles already in use. (Too many files open). +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the open operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Trying to open a file for write access, but device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Permission flags of the target do not permit requested access from this application (WFS_PERM_*_READ or WFS_PERM_*_WRITE). +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while trying to open the file. +// WFS_RESULT_NOT_FOUND .. The specified file or path does not exist. +// WFS_RESULT_FILE_OPEN .. Cannot open a file more than once unless all opens are WFS_ACCESS_READ. +// +// Description: +// ------------ +// Use these functions to open files for reading, writing, or both. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSetFilePosition +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSetFilePosition(WFSFileHandle fh, WFSFileSize nFilePosition); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// nFilePosition .. The absolute file position to set. +// +// Return Values: +// -------------- +// Possible return values for WFSSetFilePosition: +// WFS_RESULT_OK .. The file postion has been updated successfully. +// WFS_RESULT_INVALID .. Invalid file handle, or the position specified is beyond the end of the file. +// +// Description: +// ------------ +// This function can be used to set the absolute file position of an opened file (i.e. seek). No Async +// version is provided because this function does not need to access the storage device, and returns quickly. +// The file position is used and updated by WFSReadFile, WFSWriteFile, but not WFSReadFileAsync, WFSWriteFileAsync. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetFilePosition +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSGetFilePosition(WFSFileHandle fh, WFSFileSize *pFilePosition); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// pFilePosition .. A pointer to a variable which will be overwritten with the absolute file position. +// +// Return Values: +// -------------- +// Possible return values for WFSGetFilePosition: +// WFS_RESULT_OK .. Success. *pFilePosition contains the absolute file position. +// WFS_RESULT_INVALID .. Invalid file handle. +// +// Description: +// ------------ +// This function can be used to get the absolute file position of an opened file. No Async version +// is provided because this function does not need to access the storage device, and returns quickly. +// The file position is used and updated by WFSReadFile, WFSWriteFile, but not WFSReadFileAsync, WFSWriteFileAsync. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSGetFileSize, WFSGetFileSizeAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSGetFileSize (WFSFileHandle fh, WFSFileSize *pFileSize); +WFSResult WFSGetFileSizeAsync(WFSFileHandle fh, void *pUserData, WFSGetFileSizeCallback cb); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// pFileSize .. A pointer to a variable which will be overwritten with the file size (in Bytes). +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSGetFileSizeAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSetFileSize: +// WFS_RESULT_OK .. Success. *pFileSize contains the file size. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. Invalid file handle. +// Possible immediate return values for WFSGetFileSizeAsync: +// WFS_RESULT_OK .. The command was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_INVALID .. Invalid file handle. +// Possible values of nResult passed to WFSGetFileSizeAsync callback: +// WFS_RESULT_OK .. Success. The file size is passed in the nFileSize parameter of the callback. +// +// Description: +// ------------ +// These functions can be used to get the file size of an opened file. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSReadFile, WFSReadFileAsync +//-------------------------------------------------------------------------------------------------------------- +s32 WFSReadFile (WFSFileHandle fh, void *pFileDataBuffer, s32 nSize); +WFSResult WFSReadFileAsync(WFSFileHandle fh, void *pFileDataBuffer, WFSFileSize nStartPosition, s32 nSize, void *pUserData, WFSReadFileCallback cb); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// pFileDataBuffer .. Points to a buffer which will be overwritten with data from the file. +// nStartPosition .. The offset from the start of the file to start reading from. (Async version only). +// nSize .. The number of bytes to be read. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSReadAsync. +// +// Return Values: +// -------------- +// The return value is the number of bytes read, or one of the Error return values: +// Possible return values for WFSRead: +// >=0 .. Number of bytes read (May be less than requested if the end of the file is reached) +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle, pFileDataBuffer is NULL. +// WFS_RESULT_ACCESS .. The file was opened with WFS_ACCESS_WRITE_ONLY. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the read operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while reading the file. +// Possible immediate return values for WFSReadAsync (prior to start of read command): +// WFS_RESULT_OK .. Read request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle, pFileDataBuffer is NULL. +// WFS_RESULT_ACCESS .. The file was opened with WFS_ACCESS_WRITE_ONLY. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media has been removed since the file was opened. +// Possible values of nResult passed to WFSReadAsync callback: +// >=0 .. Number of bytes read (May be less than requested if the end of the file is reached). +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the read operation completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while reading the file. +// +// Description: +// ------------ +// This function is used to read data from a file that has been opened for reading. +// The file position will be advanced by the number of bytes read. +// Note: WFSReadFile automatically advances a file pointer stored within the library, whereas WFSReadFileAsync does not. +// WFSReadFileAsync requires the start position to be specified in the call. + + +//-------------------------------------------------------------------------------------------------------------- +// WFSWriteFile, WFSWriteFileAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSWriteFile (WFSFileHandle fh, const void *pFileData, WFSFileSize nSize); +WFSResult WFSWriteFileAsync(WFSFileHandle fh, const void *pFileData, WFSFileSize nStartPosition, WFSFileSize nSize, void *pUserData, WFSFileOpCallback cb); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// pFileData .. Points to the data to be written to the file. +// nStartPosition .. The offset from the start of the file to start writing to. (Async version only). +// nSize .. The number of bytes to be written. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSWriteAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSWrite: +// WFS_RESULT_OK .. Write completed successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle, pFileData is NULL. +// WFS_RESULT_ACCESS .. The file was opened with WFS_ACCESS_READ. +// WFS_RESULT_FILE_TOO_BIG .. This write operation would cause the file to go over the file size limit. +// WFS_RESULT_NO_CHANGE_SIZE .. This write operation would cause the file size to increase, but the WFS_PERM_NO_CHANGE_SIZE flag is set. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed since the file was opened +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the write completed. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while writing to the file. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// Possible immediate return values for WFSWriteAsync (prior to start of write command): +// WFS_RESULT_OK .. Write request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle, pFileData is NULL. +// WFS_RESULT_ACCESS .. The file was opened with WFS_ACCESS_READ. +// WFS_RESULT_FILE_TOO_BIG .. This write operation would cause the file to go over the file size limit. +// WFS_RESULT_NO_CHANGE_SIZE .. This write operation would cause the file size to increase, but the WFS_PERM_NO_CHANGE_SIZE flag is set. +// Possible values of nResult passed to WFSWriteAsync callback: +// WFS_RESULT_OK .. Write completed successfully. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the write operation completed. +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the write completed . +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while writing to the file. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// +// Description: +// ------------ +// This function is used to write data to a file that has been opened for writing. +// Data will be overwritten or appended to the file, starting from the current cursor position. +// Note: WFSWriteFile automatically advances a file pointer stored within the library, whereas WFSWriteFileAsync does not. +// WFSWriteFileAsync requires the start position to be specified in the call. + + +//-------------------------------------------------------------------------------------------------------------- +// WFSWriteFileAndDiscardData, WFSWriteFileAndDiscardDataAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSWriteFileAndDiscard (WFSFileHandle fh, const void *pFileData, WFSFileSize nSize); +WFSResult WFSWriteFileAndDiscardAsync(WFSFileHandle fh, const void *pFileData, WFSFileSize nStartPosition, WFSFileSize nSize, void *pUserData, WFSFileOpCallback cb); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// pFileData .. Points to the data to be written to the file. +// nStartPosition .. The offset from the start of the file to start writing to. (Async version only). +// nSize .. The number of bytes to be written. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSWriteAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSWrite: +// WFS_RESULT_OK .. Write completed successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle, pFileData is NULL. +// WFS_RESULT_ACCESS .. The file was opened with WFS_ACCESS_READ. +// WFS_RESULT_FILE_TOO_BIG .. This write operation would cause the file to go over the file size limit. +// WFS_RESULT_NO_CHANGE_SIZE .. This write operation would cause the file size to increase, but the WFS_PERM_NO_CHANGE_SIZE flag is set. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed since the file was opened +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the write completed. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while writing to the file. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// Possible immediate return values for WFSWriteAsync (prior to start of write command): +// WFS_RESULT_OK .. Write request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle, pFileData is NULL. +// WFS_RESULT_ACCESS .. The file was opened with WFS_ACCESS_READ. +// WFS_RESULT_FILE_TOO_BIG .. This write operation would cause the file to go over the file size limit. +// WFS_RESULT_NO_CHANGE_SIZE .. This write operation would cause the file size to increase, but the WFS_PERM_NO_CHANGE_SIZE flag is set. +// Possible values of nResult passed to WFSWriteAsync callback: +// WFS_RESULT_OK .. Write completed successfully. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the write operation completed. +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the write completed . +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while writing to the file. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// +// Description: +// ------------ +// This function is used to write data to a file that has been opened for writing. +// Data will be overwritten or appended to the file, starting from the current cursor position. +// This function is faster than WFSWriteFile. However the data buffer is overwritten by used as the work buffer. +// Note: WFSWriteFile automatically advances a file pointer stored within the library, whereas WFSWriteFileAsync does not. +// WFSWriteFileAsync requires the start position to be specified in the call. + + +//-------------------------------------------------------------------------------------------------------------- +// WFSCloseFile, WFSCloseFileAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSCloseFile (WFSFileHandle fh, WFSBool bTruncateFlag); +WFSResult WFSCloseFileAsync(WFSFileHandle fh, WFSBool bTruncateFlag, WFSFileSize nFileSize, void *pUserData, WFSFileOpCallback cb); +// Arguments: +// ---------- +// fh .. The file handle which was returned when the file was opened. +// bTruncateFlag .. If the file was opened for writing and this flag is set to TRUE, the file will be truncated. +// For WFSCloseFile, the current file position becomes the new file size. For WFSCloseFileAsync, nFileSize is used. +// If this flag is FALSE, the file will be closed without truncation. +// nFileSize .. If bTruncateFlag is TRUE, this is the new file size (WFSCloseFileAsync only). +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSCloseAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSClose: +// WFS_RESULT_OK .. Close completed successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. (Can also occur if there are outstanding async read/write operations on this file handle) +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle. +// WFS_RESULT_ACCESS .. Trying to truncate the file, but the file was opened with WFS_ACCESS_READ. +// WFS_RESULT_NO_CHANGE_SIZE .. Trying to truncate the file, but the file has the WFS_PERM_NO_CHANGE_SIZE flag set. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the close completed. +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the close completed. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while closing the file. +// Possible immediate return values for WFSCloseAsync: +// WFS_RESULT_OK .. Close request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. fh is not a valid file handle. +// WFS_RESULT_ACCESS .. Trying to truncate the file, but the file was opened with WFS_ACCESS_READ. +// WFS_RESULT_NO_CHANGE_SIZE .. Trying to truncate the file, but the file has the WFS_PERM_NO_CHANGE_SIZE flag set. +// Possible values of nResult passed to WFSCloseAsync callback: +// WFS_RESULT_OK .. Close completed successfully. +// WFS_RESULT_MEDIA_ERROR .. The storage device/media was removed before the close completed. +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the close completed. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while closing the file. +// +// Description: +// ------------ +// This function is used to close a file. +// If the file was opened for writing, it can be truncated by setting bTruncateFlag=TRUE + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSFlush, WFSFlushAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSFlush (const utf8 *sVolumeId); +WFSResult WFSFlushAsync(const utf8 *sVolumeId, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sVolumeId .. pointer to a string buffer containing the mounted Volume Id. +// +// Return Values: +// -------------- +// Possible return values for WFSFlush: +// WFS_RESULT_OK .. The updates made by the application have been successfully flushed to disk. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the flush completed. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while flushing the data. +// Possible immediate return values for WFSFlushAsync: +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// Possible values of nResult passed to WFSFlushAsync callback: +// WFS_RESULT_OK .. The updates made by the application have been successfully flushed to disk. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. User physically write protected the device before the flush completed. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while flushing the data. +// +// Description: +// ------------ +// This function can be used to guarantee that that operations which have previously completed, have been flushed to disk. +// Because this function can take a significant amount of time, indiscriminate use of this function may adversely affect performance. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSearchDirectoryFirst, WFSSearchDirectoryFirstAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSearchDirectoryFirst (const utf8 *sPattern, WFSSearchDirectoryHandle *pSdh, WFSFileInfo *pFi); +WFSResult WFSSearchDirectoryFirstAsync(const utf8 *sPattern, WFSFileInfo *pFi, void *pUserData, WFSSearchDirectoryCallback cb); +// Arguments: +// ---------- +// sPattern .. specifies the search pattern. It can be prefixed by a relative or absolute path specification. +// The file name portion (after the last directory separator) can include the following wildcard +// characters: +// * to match any sequence of 0 or more characters, +// ? to match any single character. +// +// pSdh .. A pointer to a WFSSearchDirectoryHandle which is passed back by the library. +// This handle should be passed to WFSSearchDirectoryNext or WFSSearchDirectoryNextAsync +// to continue the search, or WFSSearchDirectoryClose to finish the search. +// pFi .. A pointer to a WFSFileInfo struct which will be overwritten with the details of the +// first file which matches the search pattern. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSSearchDirectoryFirstAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSearchDirectoryFirst: +// WFS_RESULT_OK .. At least one file exists which matches the pattern. Details of the first file are returned in *pFi. Only in this case is a search directory handle created. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Directory name too long, Path is too deep. +// WFS_RESULT_MAX_HANDLES .. Maximum number of concurrent search handles already in use. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. This application does not have access to the base directory of the search. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while searching the directory. +// WFS_RESULT_NOT_FOUND .. No files were found which matched the search pattern. +// Possible immediate return values for WFSSearchDirectoryFirstAsync: +// WFS_RESULT_OK .. Search request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. Directory name too long, Path is too deep. +// Possible values of nResult passed to WFSSearchDirectoryFirstAsync callback: +// WFS_RESULT_OK .. At least one file exists which matches the pattern. Details of the first file are returned in *pFi. Only in this case is a search directory handle created. +// WFS_RESULT_MAX_HANDLES .. Maximum number of concurrent search handles already in use. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. This application does not have access to the base directory of the search. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while searching the directory. +// WFS_RESULT_NOT_FOUND .. No files were found which matched the search pattern. +// +// Description: +// ------------ +// Use these functions to search a directory for files matching a specific pattern. +// These functions can be used to enumerate attached devices, by passing "/dev/*" as the search pattern. // ToDo: Consider how to handle case of attachement/detachment during such device enumeration. +// These functions do not perform recursive searches of sub directories. +// NOTE: Don't forget to call WFSSearchDirectoryClose() when finished with the search. + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSearchDirectoryNext, WFSSearchDirectoryNextAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSearchDirectoryNext (WFSSearchDirectoryHandle sdh, WFSFileInfo *pFi); +WFSResult WFSSearchDirectoryNextAsync(WFSSearchDirectoryHandle sdh, WFSFileInfo *pFi, void *pUserData, WFSSearchDirectoryCallback cb); +// Arguments: +// ---------- +// sdh .. A WFSSearchDirectoryHandle which was created by WFSSearchDirectoryFirst. +// pFi .. A pointer to a WFSFileInfo struct which will be overwritten with the details of the +// next file which matches the search pattern. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSSearchDirectoryNextAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSearchDirectoryNext: +// WFS_RESULT_OK .. Another file/directory was found which matches the search pattern associated with sdh. It's details are returned in *pFi. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sdh is not a valid search handle. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. This application does not have access to the base directory of the search. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while searching the directory. +// WFS_RESULT_NOT_FOUND .. No more files could be found which matched the search pattern. +// Possible immediate return values for WFSSearchDirectoryNextAsync: +// WFS_RESULT_OK .. Search request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sdh is not a valid search handle. +// Possible values of nResult passed to WFSSearchDirectoryNextAsync callback: +// WFS_RESULT_OK .. Another file/directory was found which matches the search pattern associated with sdh. It's details are returned in *pFi. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. This application does not have access to the base directory of the search. +// WFS_RESULT_AUTHENTICATION .. Trying to access content on a different Wii, which does not have the required access rights. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered while searching the directory. +// WFS_RESULT_NOT_FOUND .. No more files were found which matched the search pattern. +// +// Description: +// ------------ +// Use these functions to search a directory for the next file matching a previously specified pattern. +// NOTE: Don't forget to call WFSSearchDirectoryClose() when finished with the search. + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSearchDirectoryClose, WFSSearchDirectoryCloseAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSearchDirectoryClose (WFSSearchDirectoryHandle sdh); +WFSResult WFSSearchDirectoryCloseAsync(WFSSearchDirectoryHandle sdh, void *pUserData, WFSSearchDirectoryCloseCallback cb); +// Arguments: +// ---------- +// sdh .. A WFSSearchDirectoryHandle which was returned by WFSSearchDirectoryFirst. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSSearchDirectoryCloseAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSearchDirectoryClose: +// WFS_RESULT_OK .. The search handle has been closed successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sdh is not a valid search handle. +// Possible immediate return values for WFSSearchDirectoryCloseAsync: +// WFS_RESULT_OK .. The close search handle request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. sdh is not a valid search handle. +// Possible values of nResult passed to WFSSearchDirectoryCloseAsync callback: +// WFS_RESULT_OK .. The search handle has been closed successfully. +// +// Description: +// ------------ +// These functions are used to close a directory search. +// This will free up the memory required to keep track of the search. + + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif //define __WFS_H__ diff --git a/trunk/firmware/include/firm/nfs/revolution/wfsError.h b/trunk/firmware/include/firm/nfs/revolution/wfsError.h new file mode 100644 index 0000000..77b4ab3 --- /dev/null +++ b/trunk/firmware/include/firm/nfs/revolution/wfsError.h @@ -0,0 +1,98 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFS library + File: wfserror.h + + Copyright 2007-2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfsError.h,v $ + Revision 1.6 2008/09/26 12:04:33 ueno + Changed WFS_RESULT_* to be equal to WFSKRN_RESULT_* to guarantee the casts. + + Revision 1.5 2008/07/11 19:02:21 paul + Removed WFS_RESULT_DIRECTORY_FULL. Fixed comments and reordered slightly. + + Revision 1.4 2008/07/10 07:03:19 nakanose_jin + add permissions API + + Revision 1.3 2008/07/02 06:52:43 nakanose_jin + bye inheritance & dev_full error + + Revision 1.2 2008/06/25 00:58:19 nakanose_jin + add control level error + + Revision 1.1 2008/04/08 18:25:40 paul + Moved error definitions from wfs.h to this header file. + + +*---------------------------------------------------------------------------*/ + +#ifndef __WFS_ERROR_H__ +#define __WFS_ERROR_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + + +// --------------------------------------------------------------------- +// WFS error codes +// --------------------------------------------------------------------- +typedef enum { + WFS_RESULT_OK = 0, // Success + + // Errors that can usually be detected early, and if detected, would result in the Async callback not being called: + WFS_RESULT_BUSY = -1, // Too many requests, try waiting then calling again. + WFS_RESULT_OUT_OF_MEMORY = -2, // The library does not have enough memory to complete the requested operation. (May be due to too many outstanding aysnc calls). + WFS_RESULT_INVALID = -3, // The function parameters were invalid, e.g. File name is too long, Path is too long or too deep. + WFS_RESULT_ACCESS = -4, // Trying to write to a file which was opened for read-only access, or vice versa. + WFS_RESULT_LIB_NOT_INITIALIZED = -5, // The WFS library has not been initialized. Please call WFSInit() (This error is checked in functions that require the library to be initialized, but only in the debug versions). + WFS_RESULT_LIB_ALREADY_INITIALIZED = -6, // The WFS library has already been initialized. + WFS_RESULT_FILE_TOO_BIG = -7, // The current write/append request would push the file over the size limit. + WFS_RESULT_NO_CHANGE_SIZE = -8, // The requested operation would cause the file size to change, but this file has WFS_PERM_NO_CHANGE_SIZE flag set. + + // Errors that cannot usually be detected early, and would be passed via nResult to the Async callbacks: + WFS_RESULT_MEDIA_ERROR = -9, // The device or media is not attached, or was removed before the requested operation could be completed. + WFS_RESULT_DEV_UNUSABLE = -10, // Attached device is not accessible, e.g. because it is an unsupported device, or has an unknown format. + WFS_RESULT_DEV_NOT_INITIALIZED = -11, // Device not formatted, or does not yet contain a WFS volume + WFS_RESULT_DEV_IN_USE = -12, // Trying to initialize a device which is in use (mounted) by one or more clients. + WFS_RESULT_VOL_ID_ERROR = -13, // Attempted to mount a volume with the same unique Id as an already mounted volume (This could happen if the User backs up an entire WFS volume using a PC) + WFS_RESULT_WRITE_PROTECTED = -14, // Device is physically write protected (e.g. USB Flash memory, SD Card) + WFS_RESULT_ALREADY_MOUNTED = -15, // The device is already mounted + + WFS_RESULT_PERMISSION = -16, // Permission flags do not permit the requested access from this application. + WFS_RESULT_PERMISSION_CL = -17, // Permission error caused by control level problems. + WFS_RESULT_ACL_FULL = -18, // The access list is full. + WFS_RESULT_ACL_ENTRY_NOT_FOUND = -19, // The specified entry does not exist in the access list. + WFS_RESULT_AUTHENTICATION = -20, // Trying to access content on a different Wii, which does not have the required access rights. + WFS_RESULT_CORRUPTION = -21, // A corrupted block was encountered which prevented the operation from being completed. + + WFS_RESULT_DIRECTORY_QUOTA = -22, // One of the ancestor directories would exceed its quota. + + WFS_RESULT_MAX_HANDLES = -23, // The maximum number of concurrent file handles / search handles are already in use. + WFS_RESULT_ALREADY_EXISTS = -24, // The file or directory being created already exists. + WFS_RESULT_NOT_FOUND = -25, // The specified file, directory or device does not exist. + WFS_RESULT_NOT_EMPTY = -26, // The specified directory cannot be deleted because it is not empty. + WFS_RESULT_NOT_FILE = -27, // The specified path is directory instead of a file. + WFS_RESULT_NOT_DIRECTORY = -28, // The specified path is a file instead of a directory. + WFS_RESULT_FILE_OPEN = -29, // The file is open. Cannot delete, move, rename, change permissions of an open file. Cannot open a file more than once unless all opens are WFS_ACCESS_READ. + WFS_RESULT_LOCKED = -30, // Cannot perform the requested operation since the file or directory is locked by an existing operation. + WFS_RESULT_RESOURCE_LIMIT_EXCEEDED = -31, // A resource limit prevents this function call. Try smaller values. + + WFS_RESULT_NOT_IMPLEMENTED = -1026, // The requested function has not yet been implemented //ToDo: This error should be removed from the final API + WFS_RESULT_UNKNOWN = -1027, // Unexpected error - could be caused by a bug in the file system. + WFS_RESULT_FATAL_ERROR = -1028 // May be caused by critical metadata corruption. + +} WFSResult; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif //define __WFS_ERROR_H__ diff --git a/trunk/firmware/include/firm/nfs/revolution/wfsPerm.h b/trunk/firmware/include/firm/nfs/revolution/wfsPerm.h new file mode 100644 index 0000000..7cd034f --- /dev/null +++ b/trunk/firmware/include/firm/nfs/revolution/wfsPerm.h @@ -0,0 +1,462 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFS library + File: wfsperm.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfsPerm.h,v $ + Revision 1.20 2008/09/18 10:26:24 nakanose_jin + fix comments + + Revision 1.19 2008/08/29 02:24:46 nakanose_jin + add comments + + Revision 1.18 2008/08/06 04:12:45 nakanose_jin + add PERMISSION_CL,ACL_ENTRY_NOT_FOUND,ACL_FULL comment + + Revision 1.17 2008/07/18 00:33:03 paul + Added descriptions of functions. Rename WFSDeletePermissions() -> WFSDeleteAccessListEntry(). + + Revision 1.16 2008/07/17 05:07:02 kondo_masahiro + inline -> static inline + + Revision 1.15 2008/07/15 08:28:47 nakanose_jin + change define value + + Revision 1.14 2008/07/14 07:22:51 ueno + Renamed WFSSetAccessList() by WFSSetAccessListEntry(). + + Revision 1.13 2008/07/11 09:46:03 ueno + Added async functions. + + Revision 1.12 2008/07/11 09:19:36 ueno + Fixed a typo. + + Revision 1.11 2008/07/10 07:03:18 nakanose_jin + add permissions API + + Revision 1.10 2008/07/02 06:52:43 nakanose_jin + bye inheritance & dev_full error + + Revision 1.9 2008/06/23 02:58:31 nakanose_jin + separate relative from absolute + + Revision 1.8 2008/06/16 18:23:50 ueno + Removed WFSCreateAccessList(). + + Revision 1.7 2008/06/05 14:08:06 ueno + Revised permission APIs. + + Revision 1.6 2008/05/08 11:41:02 nakanose_jin + move WFSDebugSetTitleID wfsPerm.h => wfs_Debug.h + + Revision 1.5 2008/05/07 13:26:55 nakanose_jin + fix ambiguous definision + + Revision 1.4 2008/04/29 01:14:52 ueno + Removed WFS_DEBUG_SYSTEM_PROCESS_ID. + Added WFS_ROOT_ID and WFS_EVERYONE_ID. + + Revision 1.3 2008/04/23 09:21:24 ueno + Revised directory permission (change -> add). + + Revision 1.2 2008/04/18 07:54:12 nakanose_jin + merging acl + + Revision 1.1 2008/04/08 18:27:19 paul + Moved permissions related declarations from wfs.h to this header file. Changed permissions API to support access lists. + + +*---------------------------------------------------------------------------*/ + +#ifndef __WFS_PERM_H__ +#define __WFS_PERM_H__ + +// Permission Flags Which apply to Files only: + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// permissions +#define WFS_PERM_CHANGE_SIZE 0x0001 +#define WFS_PERM_WRITE 0x0002 +#define WFS_PERM_READ 0x0004 +#define WFS_PERM_ADD_OR_DELETE_FILE 0x0008 +#define WFS_PERM_ADD_OR_DELETE_SUBDIR 0x0010 +#define WFS_PERM_LIST 0x0020 +#define WFS_PERM_DELETE_OR_MOVE 0x0040 + +// reserved +#define WFS_PERM_RESERVED0 0x0080 +#define WFS_PERM_RESERVED1 0x0100 +#define WFS_PERM_RESERVED2 0x0200 +#define WFS_PERM_RESERVED3 0x0400 +#define WFS_PERM_RESERVED4 0x0800 + +// control level +/* 古い定義 +#define WFS_PERM_CL0 0x0000 // 0 +#define WFS_PERM_CL_MINUS_1 0x7000 // -1 +#define WFS_PERM_CL_MINUS_2 0x6000 // -2 +#define WFS_PERM_CL_MINUS_3 0x5000 // -3 +#define WFS_PERM_CL_MINUS_4 0x4000 // -4 +#define WFS_PERM_CL_MASK 0x7000 +*/ +#define WFS_PERM_CL_MINUS_0 0xE000 // 0 +#define WFS_PERM_CL_MINUS_1 0xC000 // -1 +#define WFS_PERM_CL_MINUS_2 0xA000 // -2 +#define WFS_PERM_CL_MINUS_3 0x8000 // -3 +#define WFS_PERM_CL_0 0x0000 // 0 (absolute) +#define WFS_PERM_CL_1 0x2000 // 1 (absolute) +#define WFS_PERM_CL_2 0x4000 // 2 (absolute) +#define WFS_PERM_CL_3 0x6000 // 3 (absolute) + +#define WFS_PERM_CL_MASK 0xE000 +#define WFS_PERM_CL_SHIFT 13 +#define WFS_PERM_CL_RELATIVE_BIT 0x8000 + +static inline u32 WFS_PERM_GET_CL_ABSOLUTE(u32 perm) +{ + // ASSERT( 0 == (WFS_PERM_CL_RELATIVE_BIT & perm) ); + return ((perm & WFS_PERM_CL_MASK) >> WFS_PERM_CL_SHIFT); +} + +static inline u32 WFS_PERM_SET_CL_ABSOLUTE(u32 perm , s32 cl) +{ + // ASSERT( (cl >= 0) && (cl <= 3) ); + perm = (perm & ~WFS_PERM_CL_MASK) | (cl << WFS_PERM_CL_SHIFT); + return perm; +} + +static inline u32 WFS_PERM_SET_CL_RELATIVE(u32 perm , s32 cl) +{ + // ASSERT( (cl <= 0) && (cl >= -3) ); + perm = (perm & ~WFS_PERM_CL_MASK) | ((7 + cl) << WFS_PERM_CL_SHIFT); + return perm; +} + + +#define WFS_PERM_DIR_FULL (WFS_PERM_CHANGE_SIZE | WFS_PERM_WRITE | WFS_PERM_READ | \ + WFS_PERM_ADD_OR_DELETE_FILE | WFS_PERM_ADD_OR_DELETE_SUBDIR | \ + WFS_PERM_LIST | WFS_PERM_DELETE_OR_MOVE) +#define WFS_PERM_FILE_FULL (WFS_PERM_CHANGE_SIZE | WFS_PERM_WRITE | WFS_PERM_READ | WFS_PERM_DELETE_OR_MOVE) + +#define WFS_PERM_FULL 0xFFFF // this is special keyword. it will be converted to a appropriate value in internal + +typedef u32 WFSTitleId; +typedef u32 WFSGroupId; + +#define WFS_ROOT_ID 0UL +#define WFS_EVERYONE_ID 0x80000000 + +typedef struct WFSAccessListEntry { + u32 titleId; + u32 entryCreatorId; + u32 permissions; +} WFSAccessListEntry; + +#define WFS_ACL_ENTRY_NET_SIZE (sizeof(u32) + sizeof(u32) + sizeof(u16)) // smaller than sizeof(WFSKrnAccessListEntry). +#define WFS_ACL_MAX_ENTRIES (WFS_MAX_FILE_NAME_SIZE - sizeof(u32)*2)/(WFS_ACL_ENTRY_NET_SIZE*2) + +//-------------------------------------------------------------------------------------------------------------- +// WFSChangePermissions, WFSChangePermissionsAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSChangePermissions (const utf8 *sPathName, u32 nFlags, u32 nMask); +WFSResult WFSChangePermissionsAsync(const utf8 *sPathName, u32 nFlags, u32 nMask, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of the file or directory whose permissions are to be changed. +// See "WFS Path Names" for rules about path names. +// nFlags .. The new permissions flags that are to be set. Should be a combination of the permission flags: WFS_PERM_* +// nMask .. The mask determines which flags will be changed. NewAttributes = (OldAttributes & ~nMask) | (nFlags & nMask) +// NOTE: The mask bits for bits which are never allowed to be changed, such as WFS_FLAG_IS_A_DIRECTORY are automatically set to 0. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSChangePermissionsAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSChangePermissions: +// WFS_RESULT_OK .. The permissions were updated successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. The requested change was not allowed due to the existing permissions settings. +// WFS_RESULT_PERMISSION_CL .. You cant set the requested permission because you dont have a appropriate control level. +// WFS_RESULT_ACL_FULL .. You cant set the requested permission because the target access list is full. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory does not exist. +// WFS_RESULT_RESOURCE_LIMIT_EXCEEDED .. Too much accesslist variations generated , so quota resource are drained. +// Possible immediate return values for WFSChangePermissionsAsync: +// WFS_RESULT_OK .. Change permissions request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// Possible values of nResult passed to WFSChangePermissionsAsync callback: +// WFS_RESULT_OK .. The permissions were updated successfully. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Only the owner of a file or directory can change its permission flags. +// WFS_RESULT_PERMISSION_CL .. You cant set the requested permission because you dont have a appropriate control level. +// WFS_RESULT_ACL_FULL .. You cant set the requested permission because the target access list is full. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory does not exist. +// WFS_RESULT_RESOURCE_LIMIT_EXCEEDED .. Too much accesslist variations generated , so quota resource are drained. +// +// Description: +// ------------ +// These functions can be used to change one's own permissions to access a specified file or directory. +// However the permissions can only be set within the bounds granted by superior users. +// (The purpose is to allow a user to specify a file as read-only, which is common in existing file systems). + + + +//-------------------------------------------------------------------------------------------------------------- +// WFSSetPermissionsForUser, WFSSetPermissionsForUserAsync +//-------------------------------------------------------------------------------------------------------------- +WFSResult WFSSetPermissionsForUser (const utf8 *sPathName, u32 nFlags, u32 nMask, WFSTitleId titleId); +WFSResult WFSSetPermissionsForUserAsync(const utf8 *sPathName, u32 nFlags, u32 nMask, WFSTitleId titleId, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of the file or directory whose permissions are to be changed. +// See "WFS Path Names" for rules about path names. +// nFlags .. The new permissions flags that are to be set. Should be a combination of the permission flags: WFS_PERM_* +// nMask .. The mask determines which flags will be changed. NewAttributes = (OldAttributes & ~nMask) | (nFlags & nMask) +// titleId .. The title id of the application for which permissions are being set. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSSetPermissionsForUserAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSetPermissionsForUser: +// WFS_RESULT_OK .. The permissions were updated successfully. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. The requested change was not allowed due to the existing permissions settings. +// WFS_RESULT_PERMISSION_CL .. You cant set the requested permission because you dont have a appropriate control level. +// WFS_RESULT_ACL_FULL .. You cant set the requested permission because the target access list is full. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_NOT_FOUND .. The specified file or directory does not exist. +// WFS_RESULT_RESOURCE_LIMIT_EXCEEDED .. Too much accesslist variations generated , so quota resource are drained. +// Possible immediate return values for WFSSetPermissionsForUserAsync: +// WFS_RESULT_OK .. Change permissions request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name is too long, Path is too deep. +// Possible values of nResult passed to WFSSetPermissionsForUserAsync callback: +// WFS_RESULT_OK .. The permissions were updated successfully. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card). +// WFS_RESULT_PERMISSION .. Only the owner of a file or directory can change its permission flags. +// WFS_RESULT_PERMISSION_CL .. You cant set the requested permission because you dont have a appropriate control level. +// WFS_RESULT_ACL_FULL .. You cant set the requested permission because the target access list is full. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_NOT_FOUND .. The specified file or directory does not exist. +// WFS_RESULT_RESOURCE_LIMIT_EXCEEDED .. Too much accesslist variations generated , so quota resource are drained. +// +// Description: +// ------------ +// Use these functions to specify or change the permissions that a particular title id will have to access or modify the specified file or directory. +// NOTE: The permissions are specified as absolute values. However these are represented on access lists as permissions relative to the granter. +// This function operates in such a way as to only create access list entries when necessary, and remove them if possible. + + + +WFSResult WFSGetPermissionsForUser (const utf8 *sPathName, u32 *pFlags, WFSTitleId titleId); +WFSResult WFSGetPermissionsForUserAsync(const utf8 *sPathName, WFSTitleId titleId, void *pUserData, WFSGetPermissionsForUserCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of a file or directory. +// See "WFS Path Names" for rules about path names. +// pFlags .. A pointer to a u32 which will be overwritten with the permissions the specified title id has to +// access or modify the specified file or directory. +// titleId .. The title id of the application for which permissions are being set. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSGetPermissionsForUserAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSGetPermissionsForUser: +// WFS_RESULT_OK .. The specified file or directory was found. The permissions were calculated and copied to *pFlags. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// Possible immediate return values for WFSGetPermissionsForUserAsync: +// WFS_RESULT_OK .. The request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// Possible values of nResult passed to WFSGetPermissionsForUserAsync callback: +// WFS_RESULT_OK .. The specified file or directory was found and its permissions were calculated and passed as the nFlags parameter. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// +// Description: +// ------------ +// Use these functions to read the permissions of a file or directory for a particular user (title id). +// The permissions values returned are absolute values resulting from inheritance and permissions granted by superior users. + + + +s32 WFSGetAccessList (const utf8 *sPathName, WFSAccessListEntry *pAccessList, u32 nMaxEntries); +WFSResult WFSGetAccessListAsync(const utf8 *sPathName, WFSAccessListEntry *pAccessList, u32 nMaxEntries, void *pUserData, WFSGetAccessListCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of a file or directory. +// See "WFS Path Names" for rules about path names. +// pAccessList .. A pointer to an array of WFSAccessListEntry structs which will be overwritten with the access list entries. +// nMaxEntries .. The maximum number of access list entries that the array can hold. +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSGetAccessListAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSGetAccessList: +// >= 0 .. The number of access list entries that were successfully copied to the specified array. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// Possible immediate return values for WFSGetAccessListAsync: +// WFS_RESULT_OK .. The request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// Possible values of nResult passed to WFSGetAccessListAsync callback: +// >= 0 .. The number of access list entries that were successfully copied to the specified array. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// +// Description: +// ------------ +// Use these functions to read the raw access list for a file or directory. +// The raw access list contains only relative values of permissions and control level. (relative to the permission granter) +// The actual permission to access files and directories depends on the absolute values of permissions and control level, +// which are calculated by following inheritance and the permission-granting links back to root. + + + +WFSResult WFSSetAccessListEntry (const utf8 *sPathName, u32 nFlags, u32 nMask, WFSTitleId titleId); +WFSResult WFSSetAccessListEntryAsync(const utf8 *sPathName, u32 nFlags, u32 nMask, WFSTitleId titleId, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of a file or directory. +// See "WFS Path Names" for rules about path names. +// titleId .. The title id of the application for which permissions are being set. +// nFlags .. The new permissions flags that are to be set. Should be a combination of the permission flags: WFS_PERM_* +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSSetAccessListEntryAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSSetAccessListEntry: +// WFS_RESULT_OK .. The specified file or directory was found, and the specified access list entry was created or updated. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION_CL .. You cant set the requested permission because you dont have a appropriate control level. +// WFS_RESULT_ACL_FULL .. You cant set the requested permission because the target access list is full. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// WFS_RESULT_RESOURCE_LIMIT_EXCEEDED .. Too much accesslist variations generated , so quota resource are drained. +// Possible immediate return values for WFSSetAccessListEntryAsync: +// WFS_RESULT_OK .. The request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// Possible values of nResult passed to WFSSetAccessListEntryAsync callback: +// WFS_RESULT_OK .. The specified file or directory was found, and the specified access list entry was created or updated. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_DIRECTORY_QUOTA .. This operation would cause one of the ancestor directories to exceed its quota. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// +// Description: +// ------------ +// Use these functions to create or update a raw access list entry. +// Raw access list entries contain only relative values of permissions and control level. (relative to the permission granter) +// The actual permission to access files and directories depends on the absolute values of permissions and control level, +// which are calculated by following inheritance and the permission-granting links back to root. +// NOTE: SetPermissionsForUser() can be used to specify permissions using absolute values. + + + +WFSResult WFSDeleteAccessListEntry (const utf8 *sPathName, WFSTitleId titleId , WFSTitleId entryCreatorId); +WFSResult WFSDeleteAccessListEntryAsync(const utf8 *sPathName, WFSTitleId titleId , WFSTitleId entryCreatorId, void *pUserData, WFSResultCallback cb); +// Arguments: +// ---------- +// sPathName .. Absolute or relative path name of a file or directory. +// See "WFS Path Names" for rules about path names. +// titleId .. The title id of the application for which permissions are being removed. +// entryCreatorId .. The title id of the application which created the access list entry (the permission granter). +// pUserData .. Arbitrary user data that is passed to the callback function. +// cb .. Pointer to a callback function to receive the result of WFSDeletePermissionsAsync. +// +// Return Values: +// -------------- +// Possible return values for WFSDeletePermissions: +// WFS_RESULT_OK .. The specified file or directory was found. The permissions were calculated and copied to *pFlags. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_ACL_ENTRY_NOT_FOUND .. the target access list entry does not exist. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// Possible immediate return values for WFSDeletePermissionsAsync: +// WFS_RESULT_OK .. The request was dispatched successfully. The callback will be called in this case only. +// WFS_RESULT_BUSY .. Too many requests, try waiting then calling again. +// WFS_RESULT_OUT_OF_MEMORY .. The library does not have enough memory to dispatch the request. (May be due to too many outstanding aysnc calls). +// WFS_RESULT_INVALID .. The function parameters were invalid, e.g. File name too long, Path is too deep. +// Possible values of nResult passed to WFSDeletePermissionsAsync callback: +// WFS_RESULT_OK .. The specified file or directory was found and its permissions were calculated and passed as the nFlags parameter. +// WFS_RESULT_MEDIA_ERROR .. The device or media is not attached, or was removed before the requested operation could be completed. +// WFS_RESULT_WRITE_PROTECTED .. Device is physically write protected (e.g. USB Flash memory, SD Card. Note: Write errors can occur even for read operations). +// WFS_RESULT_PERMISSION .. Permission flags of the target or its parent directory do not permit requested access from this application. +// WFS_RESULT_CORRUPTION .. A corrupted block was encountered which prevented the operation from being completed. +// WFS_RESULT_NOT_FOUND .. The specified file or directory was not found. +// +// Description: +// ------------ +// Use these functions to delete a specified access list entry. + + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif //define __WFS_PERM_H__ diff --git a/trunk/firmware/include/firm/nfs/revolution/wfstypes.h b/trunk/firmware/include/firm/nfs/revolution/wfstypes.h new file mode 100644 index 0000000..957ba6e --- /dev/null +++ b/trunk/firmware/include/firm/nfs/revolution/wfstypes.h @@ -0,0 +1,209 @@ +/*---------------------------------------------------------------------------* + Project: Revolution WFS library + File: wfstypes.h + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: wfstypes.h,v $ + Revision 1.13 2008/12/10 06:55:11 kondo_masahiro + Added the new device types WFS_DEVTYPE_USB_MSC_??. + + Revision 1.12 2008/12/03 00:13:29 kondo_masahiro + Added WFS_MAX_WORK_SPACE_SIZE and fixed WFS_MIN_WORK_SPACE_SIZE + + Revision 1.11 2008/10/23 11:16:20 nakanose_jin + Open and Search should give a invalid file handle if he fails to execute. + + Revision 1.10 2008/09/26 09:32:36 kondo_masahiro + Marged with revision 1.8 + + Revision 1.9 2008/09/26 09:29:54 kondo_masahiro + Changed WFS_MIN_WORK_SPACE_SIZE. + + Revision 1.8 2008/07/30 03:57:46 paul + Fixed WFS_FLAG_CONTIGUOUS_AREA comment + + Revision 1.7 2008/07/25 09:46:56 ooizumi + Fixed WFSAccess definition. + + Revision 1.6 2008/07/11 09:46:03 ueno + Added async functions. + + Revision 1.5 2008/06/20 18:35:39 paul + Added WFS_MIN_DIRECTORY_QUOTA, WFS_FLAG_CONTIGUOUS_AREA + + Revision 1.4 2008/04/29 01:14:52 ueno + Removed WFS_DEBUG_SYSTEM_PROCESS_ID. + Added WFS_ROOT_ID and WFS_EVERYONE_ID. + + Revision 1.3 2008/04/08 18:24:30 paul + Moved callbacks and other type definitions from wfs.h into this header file. Moved permissions flags to wfsPerm.h + + Revision 1.2 2008/02/25 05:35:41 paul + Reduced WFS_MAX_FILE_NAME_SIZE and WFS_MAX_PATH_NAME_SIZE to make structs multiples of 32 bytes, and also allow space for a NULL terminator so we dont have to change existing code. + + Revision 1.1 2008/01/17 07:51:43 ooizumi + Moved several definitions from wfs.h. + + +*---------------------------------------------------------------------------*/ + +#ifndef __WFSTYPES_H__ +#define __WFSTYPES_H__ + + +// --------------------------------------------------------------------- +// wfstypes.h - Wii File System (WFS) API +// --------------------------------------------------------------------- + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +// --------------------------------------------------------------------- +// WFS attributes +// --------------------------------------------------------------------- +#define WFS_MAX_FILE_SIZE 4294967295 // ((u32)-1) +#define WFS_MAX_PATH_DEPTH 31 // (ToDo: Directories must keep track of their deepest sub-path, so we can validate directory move requests) + +// The following represent the maximum size of string fields in Bytes, not including the terminating NULL character. +#define WFS_MAX_FILE_NAME_SIZE 254 // Does not include the path, just the file name. +#define WFS_MAX_PATH_NAME_SIZE 509 // (ToDo: Directories must keep track of their longest sub-path, so we can validate directory move/rename requests) +#define WFS_MAX_DEVICE_NAME_SIZE 15 // maximum size of a device name +#define WFS_MAX_VOLUME_ID_SIZE 7 // maximum size of WFS Volume Id string (This is a randomly assigned string of characters, e.g., 1a2b3c4) + +#define WFS_MAX_WORK_SPACE_SIZE ((512+40+40) * 1024) // Used for user data cache, shim layer queueing parameters and async thread stack / queueing async parameters. +#define WFS_MIN_WORK_SPACE_SIZE ((144+40+40) * 1024) +#define WFS_MIN_DIRECTORY_QUOTA (1024 * 1024) +#define WFS_INVALID_HANDLE_VALUE ((u32)-1) + + +typedef char utf8; // ToDo: Perhaps utf8 should be changed to WFSChar? +typedef u32 WFSFileTime; // Time in seconds since 00:00, 1st January, 2000 +typedef u32 WFSFileSize; // Size of file +typedef u32 WFSContentIdx; // Used to identify files which belong to the same unit of purchased content, and control access to them +typedef u8 WFSBool; + + +// --------------------------------------------------------------------- +// WFS devices +// --------------------------------------------------------------------- + +// Possible WFS device states: +// 1. Valid - valid WFS volume exists +// 2. Unusable - bad device +// 3. Unknown format (e.g., FAT12, NTFS, HFS) +// 4. Uninitialized - recognized format (FAT32), but not enough free space for a WFS volume + +// Whenever a compatible device is attached, we check to see if a WFS volume already exists. If not, +// we try to create it automatically. If it is not created, then the device must not have enough space. + +#define WFS_DEVFLAG_UNUSABLE 1 // Device is unusable (e.g. unknown format, unsupported device) +#define WFS_DEVFLAG_WRITE_PROTECTED 2 // Device is physically write protected +#define WFS_DEVFLAG_NOT_INITIALIZED 4 // Device not formatted or does not yet contain a WFS volume +#define WFS_DEVFLAG_NOT_MOUNTED 8 // Device has not yet been mounted + +// ToDo: Can we force this enum to be u8? +typedef enum { + WFS_DEVTYPE_NONE = 0x00, + WFS_DEVTYPE_SD = 0x01, + WFS_DEVTYPE_USB_MSC_10 = 0x02, // MSC device with USB1.0 + WFS_DEVTYPE_USB_MSC_11 = 0x03, // MSC device with USB1.1 + WFS_DEVTYPE_USB_MSC_20 = 0x04, // MSC device with USB2.0 + WFS_DEVTYPE_EXT_SD = 0x05, + WFS_DEVTYPE_NAND = 0x06 +} WFSDevType; + +typedef struct { + u64 nDevTotalCapacity; // Total capacity of underlying device in bytes + u8 nDevType; // One of WFS_DEVTYPE_* + u8 nDevFlags; // Combination of WFS_DEVFLAG_* +} WFSDeviceInfo; + +// ToDo: Should consider the case of users making an exact copy of a WFS volume causing two devices to +// have the same "unique" device Id. This may be an unavoidable problem. +// We can return WFS_RESULT_VOL_ID_ERROR if we attempt to mount a device with the same Id as an existing device. + + +// --------------------------------------------------------------------- +// WFSFileHandle, WFSSearchDirectoryHandle +// --------------------------------------------------------------------- + +typedef u32 WFSFileHandle; +typedef u32 WFSSearchDirectoryHandle; + + +// --------------------------------------------------------------------- +// WFSFileInfo +// --------------------------------------------------------------------- + +typedef struct { + union { + WFSFileSize nFileSize; // Assuming this is a file + u32 nNumEntries; // Assuming this is a directory + }; + u32 nFlags; // Includes the permissions for the requesting user: WFS_PERM* and directory status flag: WFS_FLAG_IS_A_DIRECTORY + WFSContentIdx nCidx; + WFSFileTime timeCreated; + WFSFileTime timeUpdated; +} WFSFileAttributes; + +typedef struct { + WFSFileAttributes attr; + utf8 sFileName[WFS_MAX_FILE_NAME_SIZE+1]; +} WFSFileInfo; + + +// --------------------------------------------------------------------- +// WFS File Attributes +// --------------------------------------------------------------------- + +// The following flags are not stored per-title id, but they are included along with the permissions for the current title id in the nFlags field of WFSFileAttributes +#define WFS_FLAG_IS_A_DIRECTORY 0x80000000 // This flag can not be changed after creation. +#define WFS_FLAG_CONTIGUOUS_AREA 0x40000000 // Specifies that a directory has a contiguous set of blocks allocated to it, and is a self-contained area + + +// --------------------------------------------------------------------- +// WFSAccess +// --------------------------------------------------------------------- +typedef enum { + WFS_ACCESS_READ = 0x01, + WFS_ACCESS_WRITE = 0x02, + WFS_ACCESS_RW = 0x03 // WFS_ACCESS_READ | WFS_ACCESS_WRITE +} WFSAccess; + + +// --------------------------------------------------------------------- +// WFS callback types +// --------------------------------------------------------------------- +typedef void (*WFSResultCallback )(WFSResult nResult, void *pUserData); +typedef void (*WFSDeviceCallback )(const utf8 *sDeviceName, void *pUserData); // For attach/detach callbacks +typedef void (*WFSDeviceInfoCallback )(WFSResult nResult, const utf8 *sDeviceName, WFSDeviceInfo *pDi, void *pUserData); +typedef void (*WFSDeviceVolumeCallback )(WFSResult nResult, const utf8 *sDeviceName, utf8 *sVolumeId, void *pUserData); +typedef void (*WFSUnmountVolumeCallback )(WFSResult nResult, const utf8 *sVolumeId, void *pUserData); +typedef void (*WFSInitializeDeviceCallback)(WFSResult nResult, const utf8 *sDeviceName, void *pUserData); +typedef void (*WFSFileOpCallback )(WFSResult nResult, WFSFileHandle fh, void *pUserData); +typedef void (*WFSGetFileSizeCallback )(WFSResult nResult, u32 nFileSize, WFSFileHandle fh, void *pUserData); +typedef void (*WFSReadFileCallback )(s32 nResultOrNumBytesRead, WFSFileHandle fh, void *pUserData); +typedef void (*WFSGetFreeSpaceCallback )(WFSResult nResult, u64 nSize, void *pUserData); +typedef void (*WFSGetAttributesCallback )(WFSResult nResult, const WFSFileAttributes *pFa, void *pUserData); +typedef void (*WFSSearchDirectoryCallback )(WFSResult nResult, WFSSearchDirectoryHandle sdh, const WFSFileInfo *pFi, void *pUserData); +typedef void (*WFSSearchDirectoryCloseCallback)(WFSResult nResult, WFSSearchDirectoryHandle sdh, void *pUserData); +typedef void (*WFSGetPermissionsForUserCallback)(WFSResult nResult, u32 nFlags, void *pUserData); +typedef void (*WFSGetAccessListCallback )(s32 nResultOrNumAclEntries, void *pUserData); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif //define __WFSTYPES_H__