git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@577 0109f412-320b-0410-ab79-c3e0c5ffbbe6
4354 lines
105 KiB
C++
4354 lines
105 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: I/O for Netware OS
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1998-2003,2005-2006 Novell, Inc. All Rights Reserved.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of version 2 of the GNU General Public
|
|
// License as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, contact Novell, Inc.
|
|
//
|
|
// To contact Novell about this file by physical or electronic mail,
|
|
// you may find current contact information at www.novell.com
|
|
//
|
|
// $Id: fnlm.cpp 12362 2006-03-09 12:11:37 -0700 (Thu, 09 Mar 2006) dsanders $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "ftksys.h"
|
|
#include "ftknlm.h"
|
|
|
|
#if defined( FLM_NLM)
|
|
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
#define zMAX_COMPONENT_NAME 256
|
|
#define zGET_INFO_VARIABLE_DATA_SIZE (zMAX_COMPONENT_NAME * 2)
|
|
|
|
#define zOK 0 // the operation succeeded
|
|
#define zERR_NO_MEMORY 20000 // insufficent memory to complete the request
|
|
#define zERR_NOT_SUPPORTED 20011 // the operation is not supported
|
|
#define zERR_CONNECTION_NOT_LOGGED_IN 20007 // the connection has not been logged in
|
|
#define zERR_END_OF_FILE 20100 // read past the end of file
|
|
#define zERR_OUT_OF_SPACE 20103 // no available disk space is left
|
|
#define zERR_BAD_FILE_HANDLE 20401 // the file handle is out of range, bad instance, or doesn't exist
|
|
#define zERR_INVALID_NAME 20403 // path name is invalid -- bad syntax
|
|
#define zERR_INVALID_CHAR_IN_NAME 20404 // path name had an invalid character
|
|
#define zERR_INVALID_PATH 20405 // the path is syntactically incorrect
|
|
#define zERR_NAME_NOT_FOUND_IN_DIRECTORY 20407 // name does not exist in the direcory being searched
|
|
#define zERR_NO_NAMES_IN_PATH 20409 // a NULL file name was given
|
|
#define zERR_NO_MORE_NAMES_IN_PATH 20410 // doing a wild search but ran out of names to search
|
|
#define zERR_PATH_MUST_BE_FULLY_QUALIFIED 20411 // path name must be fully qualified in this context
|
|
#define zERR_FILE_ALREADY_EXISTS 20412 // the given file already exists
|
|
#define zERR_NAME_NO_LONGER_VALID 20413 // the dir/file name is no longer valid
|
|
#define zERR_DIRECTORY_NOT_EMPTY 20417 // the directory still has files in it
|
|
#define zERR_NO_FILES_FOUND 20424 // no files matched the given wildcard pattern
|
|
#define zERR_DIR_CANNOT_BE_OPENED 20435 // the requested parent was not found
|
|
#define zERR_NO_OPEN_PRIVILEGE 20438 // no the right privileges to open the file
|
|
#define zERR_NO_MORE_CONTEXT_HANDLE_IDS 20439 // there are no more available context handle IDs
|
|
#define zERR_INVALID_PATH_FORMAT 20441 // the pathFormat is either invalid or unsupported
|
|
#define zERR_ALL_FILES_IN_USE 20500 // all files were in use
|
|
#define zERR_SOME_FILES_IN_USE 20501 // some of the files were in use
|
|
#define zERR_ALL_FILES_READ_ONLY 20502 // all files were READONLY
|
|
#define zERR_SOME_FILES_READ_ONLY 20503 // some of the files were READONLY
|
|
#define zERR_ALL_NAMES_EXIST 20504 // all of the names already existed
|
|
#define zERR_SOME_NAMES_EXIST 20505 // some of the names already existed
|
|
#define zERR_NO_RENAME_PRIVILEGE 20506 // you do not have privilege to rename the file
|
|
#define zERR_RENAME_DIR_INVALID 20507 // the selected directory may not be renamed
|
|
#define zERR_RENAME_TO_OTHER_VOLUME 20508 // a rename/move may not move the beast to a different volume
|
|
#define zERR_CANT_RENAME_DATA_STREAMS 20509 // not allowed to rename a data stream
|
|
#define zERR_FILE_RENAME_IN_PROGRESS 20510 // the file is already being renamed by a different process
|
|
#define zERR_CANT_RENAME_TO_DELETED 20511 // only deleted files may be renamed to a deleted state
|
|
#define zERR_HOLE_IN_DIO_FILE 20651 // DIO files cannot have holes
|
|
#define zERR_BEYOND_EOF 20652 // DIO files cannot be read beyond EOF
|
|
#define zERR_INVALID_PATH_SEPARATOR 20704 // the name space does not support the requested path separator type
|
|
#define zERR_VOLUME_SEPARATOR_NOT_SUPPORTED 20705 // the name space does not support volume separators
|
|
#define zERR_BAD_VOLUME_NAME 20800 // the given volume name is syntactically incorrect
|
|
#define zERR_VOLUME_NOT_FOUND 20801 // the given volume name could not be found
|
|
#define zERR_NO_SET_PRIVILEGE 20850 // does not have rights to modify metadata
|
|
#define zERR_NO_CREATE_PRIVILEGE 20851 // does not have rights to create an object
|
|
#define zERR_ACCESS_DENIED 20859 // authorization/attributes denied access
|
|
#define zERR_NO_WRITE_PRIVILEGE 20860 // no granted write privileges
|
|
#define zERR_NO_READ_PRIVILEGE 20861 // no granted read privileges
|
|
#define zERR_NO_DELETE_PRIVILEGE 20862 // no delete privileges
|
|
#define zERR_SOME_NO_DELETE_PRIVILEGE 20863 // on wildcard some do not have delete privileges
|
|
#define zERR_NO_SUCH_OBJECT 20867 // no such object in the naming services
|
|
#define zERR_CANT_DELETE_OPEN_FILE 20868 // cant delete an open file without rights
|
|
#define zERR_NO_CREATE_DELETE_PRIVILEGE 20869 // no delete on create privileges
|
|
#define zERR_NO_SALVAGE_PRIVILEGE 20870 // no privileges to salvage this file
|
|
#define zERR_FILE_READ_LOCKED 20905 // cant grant read access to the file
|
|
#define zERR_FILE_WRITE_LOCKED 20906 // cant grant write access to the file
|
|
|
|
#define zRR_READ_ACCESS 0x00000001
|
|
#define zRR_WRITE_ACCESS 0x00000002
|
|
#define zRR_DENY_READ 0x00000004
|
|
#define zRR_DENY_WRITE 0x00000008
|
|
#define zRR_SCAN_ACCESS 0x00000010
|
|
#define zRR_ENABLE_IO_ON_COMPRESSED_DATA 0x00000100
|
|
#define zRR_LEAVE_FILE_COMPRESSED 0x00000200
|
|
#define zRR_DELETE_FILE_ON_CLOSE 0x00000400
|
|
#define zRR_FLUSH_ON_CLOSE 0x00000800
|
|
#define zRR_PURGE_IMMEDIATE_ON_CLOSE 0x00001000
|
|
#define zRR_DIO_MODE 0x00002000
|
|
#define zRR_ALLOW_SECURE_DIRECTORY_ACCESS 0x00020000
|
|
#define zRR_TRANSACTION_ACTIVE 0x00100000
|
|
#define zRR_READ_ACCESS_TO_SNAPSHOT 0x04000000
|
|
#define zRR_DENY_RW_OPENER_CAN_REOPEN 0x08000000
|
|
#define zRR_CREATE_WITHOUT_READ_ACCESS 0x10000000
|
|
#define zRR_OPENER_CAN_DELETE_WHILE_OPEN 0x20000000
|
|
#define zRR_CANT_DELETE_WHILE_OPEN 0x40000000
|
|
#define zRR_DONT_UPDATE_ACCESS_TIME 0x80000000
|
|
|
|
#define zFA_READ_ONLY 0x00000001
|
|
#define zFA_HIDDEN 0x00000002
|
|
#define zFA_SYSTEM 0x00000004
|
|
#define zFA_EXECUTE 0x00000008
|
|
#define zFA_SUBDIRECTORY 0x00000010
|
|
#define zFA_ARCHIVE 0x00000020
|
|
#define zFA_SHAREABLE 0x00000080
|
|
#define zFA_SMODE_BITS 0x00000700
|
|
#define zFA_NO_SUBALLOC 0x00000800
|
|
#define zFA_TRANSACTION 0x00001000
|
|
#define zFA_NOT_VIRTUAL_FILE 0x00002000
|
|
#define zFA_IMMEDIATE_PURGE 0x00010000
|
|
#define zFA_RENAME_INHIBIT 0x00020000
|
|
#define zFA_DELETE_INHIBIT 0x00040000
|
|
#define zFA_COPY_INHIBIT 0x00080000
|
|
#define zFA_IS_ADMIN_LINK 0x00100000
|
|
#define zFA_IS_LINK 0x00200000
|
|
#define zFA_REMOTE_DATA_INHIBIT 0x00800000
|
|
#define zFA_COMPRESS_FILE_IMMEDIATELY 0x02000000
|
|
#define zFA_DATA_STREAM_IS_COMPRESSED 0x04000000
|
|
#define zFA_DO_NOT_COMPRESS_FILE 0x08000000
|
|
#define zFA_CANT_COMPRESS_DATA_STREAM 0x20000000
|
|
#define zFA_ATTR_ARCHIVE 0x40000000
|
|
#define zFA_VOLATILE 0x80000000
|
|
|
|
#define zNSPACE_DOS 0
|
|
#define zNSPACE_MAC 1
|
|
#define zNSPACE_UNIX 2
|
|
#define zNSPACE_LONG 4
|
|
#define zNSPACE_DATA_STREAM 6
|
|
#define zNSPACE_EXTENDED_ATTRIBUTE 7
|
|
#define zNSPACE_INVALID (-1)
|
|
#define zNSPACE_DOS_MASK (1 << zNSPACE_DOS)
|
|
#define zNSPACE_MAC_MASK (1 << zNSPACE_MAC)
|
|
#define zNSPACE_UNIX_MASK (1 << zNSPACE_UNIX)
|
|
#define zNSPACE_LONG_MASK (1 << zNSPACE_LONG)
|
|
#define zNSPACE_DATA_STREAM_MASK (1 << zNSPACE_DATA_STREAM)
|
|
#define zNSPACE_EXTENDED_ATTRIBUTE_MASK (1 << zNSPACE_EXTENDED_ATTRIBUTE)
|
|
#define zNSPACE_ALL_MASK (0xffffffff)
|
|
|
|
#define zMODE_VOLUME_ID 0x80000000
|
|
#define zMODE_UTF8 0x40000000
|
|
#define zMODE_DELETED 0x20000000
|
|
#define zMODE_LINK 0x10000000
|
|
|
|
#define zCREATE_OPEN_IF_THERE 0x00000001
|
|
#define zCREATE_TRUNCATE_IF_THERE 0x00000002
|
|
#define zCREATE_DELETE_IF_THERE 0x00000004
|
|
|
|
#define zMATCH_ALL_DERIVED_TYPES 0x00000001
|
|
#define zMATCH_HIDDEN 0x1
|
|
#define zMATCH_NON_HIDDEN 0x2
|
|
#define zMATCH_DIRECTORY 0x4
|
|
#define zMATCH_NON_DIRECTORY 0x8
|
|
#define zMATCH_SYSTEM 0x10
|
|
#define zMATCH_NON_SYSTEM 0x20
|
|
#define zMATCH_ALL (~0)
|
|
|
|
#define zSETSIZE_NON_SPARSE_FILE 0x00000001
|
|
#define zSETSIZE_NO_ZERO_FILL 0x00000002
|
|
#define zSETSIZE_UNDO_ON_ERR 0x00000004
|
|
#define zSETSIZE_PHYSICAL_ONLY 0x00000008
|
|
#define zSETSIZE_LOGICAL_ONLY 0x00000010
|
|
#define zSETSIZE_COMPRESSED 0x00000020
|
|
|
|
#define zMOD_FILE_ATTRIBUTES 0x00000001
|
|
#define zMOD_CREATED_TIME 0x00000002
|
|
#define zMOD_ARCHIVED_TIME 0x00000004
|
|
#define zMOD_MODIFIED_TIME 0x00000008
|
|
#define zMOD_ACCESSED_TIME 0x00000010
|
|
#define zMOD_METADATA_MODIFIED_TIME 0x00000020
|
|
#define zMOD_OWNER_ID 0x00000040
|
|
#define zMOD_ARCHIVER_ID 0x00000080
|
|
#define zMOD_MODIFIER_ID 0x00000100
|
|
#define zMOD_METADATA_MODIFIER_ID 0x00000200
|
|
#define zMOD_PRIMARY_NAMESPACE 0x00000400
|
|
#define zMOD_DELETED_INFO 0x00000800
|
|
#define zMOD_MAC_METADATA 0x00001000
|
|
#define zMOD_UNIX_METADATA 0x00002000
|
|
#define zMOD_EXTATTR_FLAGS 0x00004000
|
|
#define zMOD_VOL_ATTRIBUTES 0x00008000
|
|
#define zMOD_VOL_NDS_OBJECT_ID 0x00010000
|
|
#define zMOD_VOL_MIN_KEEP_SECONDS 0x00020000
|
|
#define zMOD_VOL_MAX_KEEP_SECONDS 0x00040000
|
|
#define zMOD_VOL_LOW_WATER_MARK 0x00080000
|
|
#define zMOD_VOL_HIGH_WATER_MARK 0x00100000
|
|
#define zMOD_POOL_ATTRIBUTES 0x00200000
|
|
#define zMOD_POOL_NDS_OBJECT_ID 0x00400000
|
|
#define zMOD_VOL_DATA_SHREDDING_COUNT 0x00800000
|
|
#define zMOD_VOL_QUOTA 0x01000000
|
|
|
|
/***************************************************************************
|
|
Desc:
|
|
***************************************************************************/
|
|
enum zGetInfoMask_t
|
|
{
|
|
zGET_STD_INFO = 0x1,
|
|
zGET_NAME = 0x2,
|
|
zGET_ALL_NAMES = 0x4,
|
|
zGET_PRIMARY_NAMESPACE = 0x8,
|
|
zGET_TIMES_IN_SECS = 0x10,
|
|
zGET_TIMES_IN_MICROS = 0x20,
|
|
zGET_IDS = 0x40,
|
|
zGET_STORAGE_USED = 0x80,
|
|
zGET_BLOCK_SIZE = 0x100,
|
|
zGET_COUNTS = 0x200,
|
|
zGET_EXTENDED_ATTRIBUTE_INFO = 0x400,
|
|
zGET_DATA_STREAM_INFO = 0x800,
|
|
zGET_DELETED_INFO = 0x1000,
|
|
zGET_MAC_METADATA = 0x2000,
|
|
zGET_UNIX_METADATA = 0x4000,
|
|
zGET_EXTATTR_FLAGS = 0x8000,
|
|
zGET_VOLUME_INFO = 0x10000,
|
|
zGET_VOL_SALVAGE_INFO = 0x20000,
|
|
zGET_POOL_INFO = 0x40000
|
|
};
|
|
|
|
/***************************************************************************
|
|
Desc:
|
|
***************************************************************************/
|
|
enum
|
|
{
|
|
zINFO_VERSION_A = 1
|
|
};
|
|
|
|
/***************************************************************************
|
|
Desc:
|
|
***************************************************************************/
|
|
typedef enum FileType_t
|
|
{
|
|
zFILE_UNKNOWN,
|
|
zFILE_REGULAR,
|
|
zFILE_EXTENDED_ATTRIBUTE,
|
|
zFILE_NAMED_DATA_STREAM,
|
|
zFILE_PIPE,
|
|
zFILE_VOLUME,
|
|
zFILE_POOL,
|
|
zFILE_MAX
|
|
} FileType_t;
|
|
|
|
/***************************************************************************
|
|
Desc:
|
|
***************************************************************************/
|
|
typedef struct GUID_t
|
|
{
|
|
LONG timeLow;
|
|
WORD timeMid;
|
|
WORD timeHighAndVersion;
|
|
BYTE clockSeqHighAndReserved;
|
|
BYTE clockSeqLow;
|
|
BYTE node[ 6];
|
|
} GUID_t;
|
|
|
|
/***************************************************************************
|
|
Desc:
|
|
***************************************************************************/
|
|
typedef struct zMacInfo_s
|
|
{
|
|
BYTE finderInfo[32];
|
|
BYTE proDOSInfo[6];
|
|
BYTE filler[2];
|
|
LONG dirRightsMask;
|
|
} zMacInfo_s;
|
|
|
|
/***************************************************************************
|
|
Desc:
|
|
***************************************************************************/
|
|
typedef struct zUnixInfo_s
|
|
{
|
|
LONG fMode;
|
|
LONG rDev;
|
|
LONG myFlags;
|
|
LONG nfsUID;
|
|
LONG nfsGID;
|
|
LONG nwUID;
|
|
LONG nwGID;
|
|
LONG nwEveryone;
|
|
LONG nwUIDRights;
|
|
LONG nwGIDRights;
|
|
LONG nwEveryoneRights;
|
|
BYTE acsFlags;
|
|
BYTE firstCreated;
|
|
FLMINT16 variableSize;
|
|
} zUnixInfo_s;
|
|
|
|
typedef struct zVolumeInfo_s
|
|
{
|
|
GUID_t volumeID;
|
|
GUID_t ndsObjectID;
|
|
LONG volumeState;
|
|
LONG nameSpaceMask;
|
|
|
|
struct
|
|
{
|
|
FLMUINT64 enabled;
|
|
FLMUINT64 enableModMask;
|
|
FLMUINT64 supported;
|
|
} features;
|
|
|
|
FLMUINT64 maximumFileSize;
|
|
FLMUINT64 totalSpaceQuota;
|
|
FLMUINT64 numUsedBytes;
|
|
FLMUINT64 numObjects;
|
|
FLMUINT64 numFiles;
|
|
LONG authModelID;
|
|
LONG dataShreddingCount;
|
|
|
|
struct
|
|
{
|
|
FLMUINT64 purgeableBytes;
|
|
FLMUINT64 nonPurgeableBytes;
|
|
FLMUINT64 numDeletedFiles;
|
|
FLMUINT64 oldestDeletedTime;
|
|
LONG minKeepSeconds;
|
|
LONG maxKeepSeconds;
|
|
LONG lowWaterMark;
|
|
LONG highWaterMark;
|
|
} salvage;
|
|
|
|
struct
|
|
{
|
|
FLMUINT64 numCompressedFiles;
|
|
FLMUINT64 numCompDelFiles;
|
|
FLMUINT64 numUncompressibleFiles;
|
|
FLMUINT64 numPreCompressedBytes;
|
|
FLMUINT64 numCompressedBytes;
|
|
} comp;
|
|
|
|
} zVolumeInfo_s;
|
|
|
|
/***************************************************************************
|
|
Desc:
|
|
***************************************************************************/
|
|
typedef struct zPoolInfo_s
|
|
{
|
|
GUID_t poolID;
|
|
GUID_t ndsObjectID;
|
|
LONG poolState;
|
|
LONG nameSpaceMask;
|
|
|
|
struct
|
|
{
|
|
FLMUINT64 enabled;
|
|
FLMUINT64 enableModMask;
|
|
FLMUINT64 supported;
|
|
} features;
|
|
|
|
FLMUINT64 totalSpace;
|
|
FLMUINT64 numUsedBytes;
|
|
FLMUINT64 purgeableBytes;
|
|
FLMUINT64 nonPurgeableBytes;
|
|
} zPoolInfo_s;
|
|
|
|
/***************************************************************************
|
|
Desc:
|
|
***************************************************************************/
|
|
typedef struct zInfo_s
|
|
{
|
|
LONG infoVersion;
|
|
FLMINT totalBytes;
|
|
FLMINT nextByte;
|
|
LONG padding;
|
|
FLMUINT64 retMask;
|
|
|
|
struct
|
|
{
|
|
FLMUINT64 zid;
|
|
FLMUINT64 dataStreamZid;
|
|
FLMUINT64 parentZid;
|
|
FLMUINT64 logicalEOF;
|
|
GUID_t volumeID;
|
|
LONG fileType;
|
|
LONG fileAttributes;
|
|
LONG fileAttributesModMask;
|
|
LONG padding;
|
|
} std;
|
|
|
|
struct
|
|
{
|
|
FLMUINT64 physicalEOF;
|
|
FLMUINT64 dataBytes;
|
|
FLMUINT64 metaDataBytes;
|
|
} storageUsed;
|
|
|
|
LONG primaryNameSpaceID;
|
|
LONG nameStart;
|
|
|
|
struct
|
|
{
|
|
LONG numEntries;
|
|
LONG fileNameArray;
|
|
} names;
|
|
|
|
struct
|
|
{
|
|
FLMUINT64 created;
|
|
FLMUINT64 archived;
|
|
FLMUINT64 modified;
|
|
FLMUINT64 accessed;
|
|
FLMUINT64 metaDataModified;
|
|
} time;
|
|
|
|
struct
|
|
{
|
|
GUID_t owner;
|
|
GUID_t archiver;
|
|
GUID_t modifier;
|
|
GUID_t metaDataModifier;
|
|
} id;
|
|
|
|
struct
|
|
{
|
|
LONG size;
|
|
LONG sizeShift;
|
|
} blockSize;
|
|
|
|
struct
|
|
{
|
|
LONG open;
|
|
LONG hardLink;
|
|
} count;
|
|
|
|
struct
|
|
{
|
|
LONG count;
|
|
LONG totalNameSize;
|
|
FLMUINT64 totalDataSize;
|
|
} dataStream;
|
|
|
|
struct
|
|
{
|
|
LONG count;
|
|
LONG totalNameSize;
|
|
FLMUINT64 totalDataSize;
|
|
} extAttr;
|
|
|
|
struct
|
|
{
|
|
FLMUINT64 time;
|
|
GUID_t id;
|
|
} deleted;
|
|
|
|
struct
|
|
{
|
|
zMacInfo_s info;
|
|
} macNS;
|
|
|
|
struct
|
|
{
|
|
zUnixInfo_s info;
|
|
LONG offsetToData;
|
|
} unixNS;
|
|
|
|
zVolumeInfo_s vol;
|
|
zPoolInfo_s pool;
|
|
LONG extAttrUserFlags;
|
|
BYTE variableData[zGET_INFO_VARIABLE_DATA_SIZE];
|
|
|
|
} zInfo_s;
|
|
|
|
RCODE DfsMapError(
|
|
LONG lResult,
|
|
RCODE defaultRc);
|
|
|
|
FLMUINT f_getNSSOpenFlags(
|
|
FLMUINT uiAccess,
|
|
FLMBOOL bDoDirectIo);
|
|
|
|
typedef FLMINT (* zROOT_KEY_FUNC)(
|
|
FLMUINT connectionID,
|
|
FLMINT64 * retRootKey);
|
|
|
|
typedef FLMINT (* zCLOSE_FUNC)(
|
|
FLMINT64 key);
|
|
|
|
typedef FLMINT (* zCREATE_FUNC)(
|
|
FLMINT64 key,
|
|
FLMUINT taskID,
|
|
FLMUINT64 xid,
|
|
FLMUINT nameSpace,
|
|
const void * path,
|
|
FLMUINT fileType,
|
|
FLMUINT64 fileAttributes,
|
|
FLMUINT createFlags,
|
|
FLMUINT requestedRights,
|
|
FLMINT64 * retKey);
|
|
|
|
typedef FLMINT (* zOPEN_FUNC)(
|
|
FLMINT64 key,
|
|
FLMUINT taskID,
|
|
FLMUINT nameSpace,
|
|
const void * path,
|
|
FLMUINT requestedRights,
|
|
FLMINT64 * retKey);
|
|
|
|
typedef FLMINT (* zDELETE_FUNC)(
|
|
FLMINT64 key,
|
|
FLMUINT64 xid,
|
|
FLMUINT nameSapce,
|
|
const void * path,
|
|
FLMUINT match,
|
|
FLMUINT deleteFlags);
|
|
|
|
typedef FLMINT (* zREAD_FUNC)(
|
|
FLMINT64 key,
|
|
FLMUINT64 xid,
|
|
FLMUINT64 startingOffset,
|
|
FLMUINT bytesToRead,
|
|
void * retBuffer,
|
|
FLMUINT * retBytesRead);
|
|
|
|
typedef FLMINT (* zDIO_READ_FUNC)(
|
|
FLMINT64 key,
|
|
FLMUINT64 unitOffset,
|
|
FLMUINT unitsToRead,
|
|
FLMUINT callbackData,
|
|
void (*dioReadCallBack)(
|
|
FLMUINT reserved,
|
|
FLMUINT callbackData,
|
|
FLMUINT retStatus),
|
|
void * retBuffer);
|
|
|
|
typedef FLMINT (* zGET_INFO_FUNC)(
|
|
FLMINT64 key,
|
|
FLMUINT64 getInfoMask,
|
|
FLMUINT sizeRetGetInfo,
|
|
FLMUINT infoVersion,
|
|
zInfo_s * retGetInfo);
|
|
|
|
typedef FLMINT (* zMODIFY_INFO_FUNC)(
|
|
FLMINT64 key,
|
|
FLMUINT64 xid,
|
|
FLMUINT64 modifyInfoMask,
|
|
FLMUINT sizeModifyInfo,
|
|
FLMUINT infoVersion,
|
|
const zInfo_s * modifyInfo);
|
|
|
|
typedef FLMINT (* zSET_EOF_FUNC)(
|
|
FLMINT64 key,
|
|
FLMUINT64 xid,
|
|
FLMUINT64 startingOffset,
|
|
FLMUINT flags);
|
|
|
|
typedef FLMINT (* zWRITE_FUNC)(
|
|
FLMINT64 key,
|
|
FLMUINT64 xid,
|
|
FLMUINT64 startingOffset,
|
|
FLMUINT bytesToWrite,
|
|
const void * buffer,
|
|
FLMUINT * retBytesWritten);
|
|
|
|
typedef FLMINT (* zDIO_WRITE_FUNC)(
|
|
FLMINT64 key,
|
|
FLMUINT64 unitOffset,
|
|
FLMUINT unitsToWrite,
|
|
FLMUINT callbackData,
|
|
void (*dioWriteCallBack)(
|
|
FLMUINT reserved,
|
|
FLMUINT callbackData,
|
|
FLMUINT retStatus),
|
|
const void * buffer);
|
|
|
|
typedef FLMINT (* zRENAME_FUNC)(
|
|
FLMINT64 key,
|
|
FLMUINT64 xid,
|
|
FLMUINT srcNameSpace,
|
|
const void * srcPath,
|
|
FLMUINT srcMatchAttributes,
|
|
FLMUINT dstNameSpace,
|
|
const void * dstPath,
|
|
FLMUINT renameFlags);
|
|
|
|
typedef BOOL (* zIS_NSS_VOLUME_FUNC)(
|
|
const char * path);
|
|
|
|
FSTATIC zIS_NSS_VOLUME_FUNC gv_zIsNSSVolumeFunc = NULL;
|
|
FSTATIC zROOT_KEY_FUNC gv_zRootKeyFunc = NULL;
|
|
FSTATIC zCLOSE_FUNC gv_zCloseFunc = NULL;
|
|
FSTATIC zCREATE_FUNC gv_zCreateFunc = NULL;
|
|
FSTATIC zOPEN_FUNC gv_zOpenFunc = NULL;
|
|
FSTATIC zDELETE_FUNC gv_zDeleteFunc = NULL;
|
|
FSTATIC zREAD_FUNC gv_zReadFunc = NULL;
|
|
FSTATIC zDIO_READ_FUNC gv_zDIOReadFunc = NULL;
|
|
FSTATIC zGET_INFO_FUNC gv_zGetInfoFunc = NULL;
|
|
FSTATIC zMODIFY_INFO_FUNC gv_zModifyInfoFunc = NULL;
|
|
FSTATIC zSET_EOF_FUNC gv_zSetEOFFunc = NULL;
|
|
FSTATIC zWRITE_FUNC gv_zWriteFunc = NULL;
|
|
FSTATIC zDIO_WRITE_FUNC gv_zDIOWriteFunc = NULL;
|
|
FSTATIC zRENAME_FUNC gv_zRenameFunc = NULL;
|
|
|
|
static void * gv_MyModuleHandle = NULL;
|
|
static FLMATOMIC gv_NetWareStartupCount = 0;
|
|
rtag_t gv_lAllocRTag = 0;
|
|
|
|
static FLMINT64 gv_NssRootKey;
|
|
static FLMBOOL gv_bNSSKeyInitialized = FALSE;
|
|
static SEMAPHORE gv_lFlmSyncSem = 0;
|
|
static FLMBOOL gv_bUnloadCalled = FALSE;
|
|
static FLMBOOL gv_bMainRunning = FALSE;
|
|
static F_EXIT_FUNC gv_fnExit = NULL;
|
|
|
|
#if !defined( __MWERKS__)
|
|
extern unsigned long ReadInternalClock(void);
|
|
#else
|
|
unsigned long ReadInternalClock(void);
|
|
#endif
|
|
|
|
FSTATIC void ConvertToQualifiedNWPath(
|
|
const char * pInputPath,
|
|
char * pQualifiedPath);
|
|
|
|
FSTATIC RCODE nssTurnOffRenameInhibit(
|
|
const char * pszFileName);
|
|
|
|
FSTATIC LONG ConvertPathToLNameFormat(
|
|
const char * pPath,
|
|
LONG * plVolumeID,
|
|
FLMBOOL * pbNssVolume,
|
|
FLMBYTE * pLNamePath,
|
|
LONG * plLNamePathCount);
|
|
|
|
FSTATIC void DirectIONoWaitCallBack(
|
|
LONG unknownAlwaysZero,
|
|
LONG callbackData,
|
|
LONG completionCode);
|
|
|
|
FSTATIC void nssDioCallback(
|
|
FLMUINT reserved,
|
|
FLMUINT UserData,
|
|
FLMUINT retStatus);
|
|
|
|
FSTATIC RCODE MapNSSError(
|
|
FLMINT lStatus,
|
|
RCODE defaultRc);
|
|
|
|
extern "C" int nlm_main(
|
|
int iArgC,
|
|
char ** ppszArgV);
|
|
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
Desc:
|
|
***************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
#if !defined( __MWERKS__)
|
|
#pragma aux ReadInternalClock = \
|
|
0x0F 0x31 \
|
|
modify exact [EAX EDX];
|
|
#else
|
|
unsigned long ReadInternalClock(void)
|
|
{
|
|
__asm
|
|
{
|
|
rdtsc
|
|
ret
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
Desc: Initialize the root NSS key.
|
|
***************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE f_nssInitialize( void)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLMINT lStatus;
|
|
|
|
if (!gv_bNSSKeyInitialized)
|
|
{
|
|
// Import the required NSS functions
|
|
|
|
if( (gv_zIsNSSVolumeFunc = (zIS_NSS_VOLUME_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x0C" "zIsNSSVolume")) == NULL)
|
|
{
|
|
// NSS is not available on this server. Jump to exit.
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zRootKeyFunc = (zROOT_KEY_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x08" "zRootKey")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zCloseFunc = (zCLOSE_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x06" "zClose")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zCreateFunc = (zCREATE_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x07" "zCreate")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zOpenFunc = (zOPEN_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x05" "zOpen")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zDeleteFunc = (zDELETE_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x07" "zDelete")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zReadFunc = (zREAD_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x05" "zRead")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zDIOReadFunc = (zDIO_READ_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x08" "zDIORead")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zGetInfoFunc = (zGET_INFO_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x08" "zGetInfo")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zModifyInfoFunc = (zMODIFY_INFO_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x0B" "zModifyInfo")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zSetEOFFunc = (zSET_EOF_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x07" "zSetEOF")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zWriteFunc = (zWRITE_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x06" "zWrite")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zDIOWriteFunc = (zDIO_WRITE_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x09" "zDIOWrite")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (gv_zRenameFunc = (zRENAME_FUNC)ImportPublicSymbol(
|
|
(unsigned long)f_getNLMHandle(),
|
|
(unsigned char *)"\x07" "zRename")) == NULL)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
// Get the NSS root key
|
|
|
|
if ((lStatus = gv_zRootKeyFunc( 0, &gv_NssRootKey)) != zOK)
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
gv_bNSSKeyInitialized = TRUE;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
Desc: Close the root NSS key.
|
|
***************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
void f_nssUninitialize( void)
|
|
{
|
|
if (gv_bNSSKeyInitialized)
|
|
{
|
|
(void)gv_zCloseFunc( gv_NssRootKey);
|
|
gv_bNSSKeyInitialized = FALSE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
Desc: Maps NSS errors to IO errors.
|
|
***************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
FSTATIC RCODE MapNSSError(
|
|
FLMINT lStatus,
|
|
RCODE defaultRc)
|
|
{
|
|
RCODE rc;
|
|
|
|
switch (lStatus)
|
|
{
|
|
case zERR_FILE_ALREADY_EXISTS:
|
|
case zERR_DIRECTORY_NOT_EMPTY:
|
|
case zERR_DIR_CANNOT_BE_OPENED:
|
|
case zERR_NO_SET_PRIVILEGE:
|
|
case zERR_NO_CREATE_PRIVILEGE:
|
|
case zERR_ACCESS_DENIED:
|
|
case zERR_NO_WRITE_PRIVILEGE:
|
|
case zERR_NO_READ_PRIVILEGE:
|
|
case zERR_NO_DELETE_PRIVILEGE:
|
|
case zERR_SOME_NO_DELETE_PRIVILEGE:
|
|
case zERR_CANT_DELETE_OPEN_FILE:
|
|
case zERR_NO_CREATE_DELETE_PRIVILEGE:
|
|
case zERR_NO_SALVAGE_PRIVILEGE:
|
|
case zERR_FILE_READ_LOCKED:
|
|
case zERR_FILE_WRITE_LOCKED:
|
|
rc = RC_SET( NE_FLM_IO_ACCESS_DENIED);
|
|
break;
|
|
|
|
case zERR_BAD_FILE_HANDLE:
|
|
rc = RC_SET( NE_FLM_IO_BAD_FILE_HANDLE);
|
|
break;
|
|
|
|
case zERR_OUT_OF_SPACE:
|
|
rc = RC_SET( NE_FLM_IO_DISK_FULL);
|
|
break;
|
|
|
|
case zERR_NO_OPEN_PRIVILEGE:
|
|
rc = RC_SET( NE_FLM_IO_OPEN_ERR);
|
|
break;
|
|
|
|
case zERR_NAME_NOT_FOUND_IN_DIRECTORY:
|
|
case zERR_NO_FILES_FOUND:
|
|
case zERR_VOLUME_NOT_FOUND:
|
|
case zERR_NO_SUCH_OBJECT:
|
|
case zERR_INVALID_NAME:
|
|
case zERR_INVALID_CHAR_IN_NAME:
|
|
case zERR_INVALID_PATH:
|
|
case zERR_NO_NAMES_IN_PATH:
|
|
case zERR_NO_MORE_NAMES_IN_PATH:
|
|
case zERR_PATH_MUST_BE_FULLY_QUALIFIED:
|
|
case zERR_NAME_NO_LONGER_VALID:
|
|
case zERR_INVALID_PATH_FORMAT:
|
|
case zERR_INVALID_PATH_SEPARATOR:
|
|
case zERR_VOLUME_SEPARATOR_NOT_SUPPORTED:
|
|
case zERR_BAD_VOLUME_NAME:
|
|
rc = RC_SET( NE_FLM_IO_PATH_NOT_FOUND);
|
|
break;
|
|
|
|
case zERR_NO_MORE_CONTEXT_HANDLE_IDS:
|
|
rc = RC_SET( NE_FLM_IO_TOO_MANY_OPEN_FILES);
|
|
break;
|
|
case zERR_ALL_FILES_IN_USE:
|
|
case zERR_SOME_FILES_IN_USE:
|
|
case zERR_ALL_FILES_READ_ONLY:
|
|
case zERR_SOME_FILES_READ_ONLY:
|
|
case zERR_ALL_NAMES_EXIST:
|
|
case zERR_SOME_NAMES_EXIST:
|
|
case zERR_NO_RENAME_PRIVILEGE:
|
|
case zERR_RENAME_DIR_INVALID:
|
|
case zERR_RENAME_TO_OTHER_VOLUME:
|
|
case zERR_CANT_RENAME_DATA_STREAMS:
|
|
case zERR_FILE_RENAME_IN_PROGRESS:
|
|
case zERR_CANT_RENAME_TO_DELETED:
|
|
rc = RC_SET( NE_FLM_IO_RENAME_FAILURE);
|
|
break;
|
|
|
|
case zERR_CONNECTION_NOT_LOGGED_IN:
|
|
rc = RC_SET( NE_FLM_IO_CONNECT_ERROR);
|
|
break;
|
|
case zERR_NO_MEMORY:
|
|
rc = RC_SET( NE_FLM_MEM);
|
|
break;
|
|
case zERR_NOT_SUPPORTED:
|
|
rc = RC_SET( NE_FLM_NOT_IMPLEMENTED);
|
|
break;
|
|
case zERR_END_OF_FILE:
|
|
case zERR_BEYOND_EOF:
|
|
rc = RC_SET( NE_FLM_IO_END_OF_FILE);
|
|
break;
|
|
|
|
default:
|
|
rc = RC_SET( defaultRc);
|
|
break;
|
|
}
|
|
|
|
return( rc );
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
Desc: Maps direct IO errors to IO errors.
|
|
fix: we shouldn't have 2 copies of this function. this is just temporary.
|
|
long term, we need to make the FDFS.CPP version public.
|
|
***************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE DfsMapError(
|
|
LONG lResult,
|
|
RCODE defaultRc)
|
|
{
|
|
switch (lResult)
|
|
{
|
|
case DFSHoleInFileError:
|
|
case DFSOperationBeyondEndOfFile:
|
|
return( RC_SET( NE_FLM_IO_END_OF_FILE));
|
|
case DFSHardIOError:
|
|
case DFSInvalidFileHandle:
|
|
return( RC_SET( NE_FLM_IO_BAD_FILE_HANDLE));
|
|
case DFSNoReadPrivilege:
|
|
return( RC_SET( NE_FLM_IO_ACCESS_DENIED));
|
|
case DFSInsufficientMemory:
|
|
return( RC_SET( NE_FLM_MEM));
|
|
default:
|
|
return( RC_SET( defaultRc));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Map flaim I/O flags to NDS I/O flags for NSS volumes
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
FLMUINT f_getNSSOpenFlags(
|
|
FLMUINT uiAccess,
|
|
FLMBOOL bDoDirectIo)
|
|
{
|
|
FLMUINT lFlags = zRR_ALLOW_SECURE_DIRECTORY_ACCESS |
|
|
zRR_CANT_DELETE_WHILE_OPEN;
|
|
|
|
if (uiAccess & (FLM_IO_RDONLY | FLM_IO_RDWR))
|
|
{
|
|
lFlags |= zRR_READ_ACCESS;
|
|
}
|
|
if (uiAccess & FLM_IO_RDWR)
|
|
{
|
|
lFlags |= zRR_WRITE_ACCESS;
|
|
}
|
|
|
|
if (uiAccess & FLM_IO_SH_DENYRW)
|
|
{
|
|
lFlags |= zRR_DENY_READ;
|
|
}
|
|
if (uiAccess & (FLM_IO_SH_DENYWR | FLM_IO_SH_DENYRW))
|
|
{
|
|
lFlags |= zRR_DENY_WRITE;
|
|
}
|
|
if (bDoDirectIo)
|
|
{
|
|
lFlags |= zRR_DIO_MODE;
|
|
}
|
|
return( lFlags );
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Map flaim I/O flags to NetWare I/O flags
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
LONG f_getNWOpenFlags(
|
|
FLMUINT uiAccess,
|
|
FLMBOOL bDoDirectIo)
|
|
{
|
|
LONG lFlags = 0;
|
|
|
|
if (uiAccess & (FLM_IO_RDONLY | FLM_IO_RDWR))
|
|
{
|
|
lFlags |= READ_ACCESS_BIT;
|
|
}
|
|
|
|
if (uiAccess & FLM_IO_RDWR)
|
|
{
|
|
lFlags |= WRITE_ACCESS_BIT;
|
|
}
|
|
|
|
if (uiAccess & FLM_IO_SH_DENYRW )
|
|
{
|
|
lFlags |= DENY_READ_BIT;
|
|
}
|
|
|
|
if (uiAccess & (FLM_IO_SH_DENYWR | FLM_IO_SH_DENYRW))
|
|
{
|
|
lFlags |= DENY_WRITE_BIT;
|
|
}
|
|
|
|
if (bDoDirectIo)
|
|
{
|
|
lFlags |= NEVER_READ_AHEAD_BIT;
|
|
}
|
|
|
|
return( lFlags );
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Default Constructor for F_FileHdl class
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
F_FileHdl::F_FileHdl()
|
|
{
|
|
m_bFileOpened = FALSE;
|
|
m_bDeleteOnClose = FALSE;
|
|
m_bOpenedExclusive = FALSE;
|
|
m_bOpenedReadOnly = FALSE;
|
|
m_lFileHandle = -1;
|
|
m_lOpenAttr = 0;
|
|
m_uiCurrentPos = 0;
|
|
m_lVolumeID = F_NW_DEFAULT_VOLUME_NUMBER;
|
|
m_bDoSuballocation = FALSE;
|
|
m_lLNamePathCount = 0;
|
|
m_pszIoPath = NULL;
|
|
m_uiExtendSize = 0;
|
|
m_uiMaxFileSize = f_getMaxFileSize();
|
|
m_uiMaxAutoExtendSize = m_uiMaxFileSize;
|
|
m_bDoDirectIO = FALSE;
|
|
m_lSectorsPerBlock = 0;
|
|
m_lMaxBlocks = 0;
|
|
m_NssKey = 0;
|
|
m_bNSS = FALSE;
|
|
m_bNSSFileOpen = FALSE;
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
Desc:
|
|
***************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
F_FileHdl::~F_FileHdl( void)
|
|
{
|
|
if( m_bFileOpened)
|
|
{
|
|
(void)close();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
Desc: Open or create a file.
|
|
***************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::openOrCreate(
|
|
const char * pFileName,
|
|
FLMUINT uiAccess,
|
|
FLMBOOL bCreateFlag)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LONG unused;
|
|
void * unused2;
|
|
char * pszQualifiedPath = NULL;
|
|
LONG lErrorCode;
|
|
FLMBYTE * pTmpLNamePath;
|
|
char * pSaveFileName;
|
|
FLMBYTE * pLNamePath;
|
|
LONG * plLNamePathCount;
|
|
LONG LNamePathCount;
|
|
struct VolumeInformationStructure *
|
|
pVolumeInfo;
|
|
char * pszTemp;
|
|
char * pIoDirPath;
|
|
FLMBOOL bNssVolume = FALSE;
|
|
IF_FileSystem * pFileSystem = f_getFileSysPtr();
|
|
|
|
m_bDoDirectIO = (uiAccess & FLM_IO_DIRECT) ? TRUE : FALSE;
|
|
|
|
if( uiAccess & FLM_IO_DELETE_ON_RELEASE)
|
|
{
|
|
if( !m_pszIoPath)
|
|
{
|
|
if( RC_BAD( rc = f_alloc( F_PATH_MAX_SIZE, &m_pszIoPath)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
f_strcpy( m_pszIoPath, pFileName);
|
|
m_bDeleteOnClose = TRUE;
|
|
}
|
|
else
|
|
{
|
|
m_bDeleteOnClose = FALSE;
|
|
}
|
|
|
|
if (RC_BAD( rc = f_alloc(
|
|
(FLMUINT)(F_PATH_MAX_SIZE +
|
|
F_PATH_MAX_SIZE +
|
|
F_PATH_MAX_SIZE +
|
|
F_PATH_MAX_SIZE +
|
|
sizeof( struct VolumeInformationStructure) +
|
|
F_PATH_MAX_SIZE),
|
|
&pszQualifiedPath)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pTmpLNamePath = (((FLMBYTE *)pszQualifiedPath) + F_PATH_MAX_SIZE);
|
|
pSaveFileName = (((char *)pTmpLNamePath) + F_PATH_MAX_SIZE);
|
|
pIoDirPath = (((char *)pSaveFileName) + F_PATH_MAX_SIZE);
|
|
pVolumeInfo = (struct VolumeInformationStructure *)
|
|
(((char *)pIoDirPath) + F_PATH_MAX_SIZE);
|
|
pszTemp = (char *)(((char *)(pVolumeInfo)) +
|
|
sizeof( struct VolumeInformationStructure));
|
|
|
|
|
|
// Save the file name in case we have to create the directory
|
|
|
|
if((bCreateFlag) && (uiAccess & FLM_IO_CREATE_DIR))
|
|
{
|
|
f_strcpy( pSaveFileName, pFileName);
|
|
}
|
|
|
|
if( !m_pszIoPath)
|
|
{
|
|
pLNamePath = pTmpLNamePath;
|
|
plLNamePathCount = &LNamePathCount;
|
|
}
|
|
else
|
|
{
|
|
pLNamePath = (FLMBYTE *)m_pszIoPath;
|
|
plLNamePathCount = &m_lLNamePathCount;
|
|
}
|
|
|
|
ConvertToQualifiedNWPath( pFileName, pszQualifiedPath);
|
|
|
|
lErrorCode = ConvertPathToLNameFormat(
|
|
pszQualifiedPath,
|
|
&m_lVolumeID,
|
|
&bNssVolume,
|
|
pLNamePath,
|
|
plLNamePathCount);
|
|
if( lErrorCode != 0)
|
|
{
|
|
rc = f_mapPlatformError( lErrorCode, NE_FLM_PARSING_FILE_NAME);
|
|
goto Exit;
|
|
}
|
|
|
|
// Determine if the volume is NSS or not
|
|
|
|
if (gv_bNSSKeyInitialized && bNssVolume)
|
|
{
|
|
m_bNSS = TRUE;
|
|
}
|
|
|
|
if ( m_bDoDirectIO )
|
|
{
|
|
if (!m_bNSS)
|
|
{
|
|
lErrorCode =
|
|
ReturnVolumeMappingInformation( m_lVolumeID, pVolumeInfo);
|
|
if (lErrorCode != 0)
|
|
{
|
|
rc = DfsMapError( lErrorCode, NE_FLM_INITIALIZING_IO_SYSTEM);
|
|
goto Exit;
|
|
}
|
|
|
|
m_lSectorsPerBlock = (LONG)(pVolumeInfo->VolumeAllocationUnitSizeInBytes /
|
|
FLM_NLM_SECTOR_SIZE);
|
|
m_lMaxBlocks = (LONG)(m_uiMaxFileSize /
|
|
(FLMUINT)pVolumeInfo->VolumeAllocationUnitSizeInBytes);
|
|
}
|
|
else
|
|
{
|
|
m_lMaxBlocks = (LONG)(m_uiMaxFileSize / (FLMUINT)65536);
|
|
}
|
|
}
|
|
|
|
// Set up the file characteristics requested by caller.
|
|
|
|
if (bCreateFlag)
|
|
{
|
|
|
|
// File is to be created
|
|
|
|
if (f_netwareTestIfFileExists( pszQualifiedPath ) == NE_FLM_OK)
|
|
{
|
|
if (uiAccess & FLM_IO_EXCL)
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_ACCESS_DENIED);
|
|
goto Exit;
|
|
}
|
|
|
|
(void)f_netwareDeleteFile( pszQualifiedPath);
|
|
}
|
|
}
|
|
|
|
// Try to create or open the file
|
|
|
|
if (m_bNSS)
|
|
{
|
|
FLMINT lStatus;
|
|
|
|
if (bCreateFlag)
|
|
{
|
|
FLMUINT64 qFileAttr;
|
|
|
|
qFileAttr = (FLMUINT64)(((m_bDoSuballocation)
|
|
? (FLMUINT)(zFA_DO_NOT_COMPRESS_FILE)
|
|
: (FLMUINT)(zFA_NO_SUBALLOC |
|
|
zFA_DO_NOT_COMPRESS_FILE)) |
|
|
zFA_IMMEDIATE_PURGE);
|
|
|
|
Retry_NSS_Create:
|
|
|
|
m_lOpenAttr = f_getNSSOpenFlags( uiAccess, m_bDoDirectIO);
|
|
if ((lStatus = gv_zCreateFunc( gv_NssRootKey, 1, 0,
|
|
zNSPACE_LONG | zMODE_UTF8, pszQualifiedPath, zFILE_REGULAR,
|
|
qFileAttr, zCREATE_DELETE_IF_THERE, (FLMUINT)m_lOpenAttr,
|
|
&m_NssKey)) != zOK)
|
|
{
|
|
if (uiAccess & FLM_IO_CREATE_DIR)
|
|
{
|
|
uiAccess &= ~FLM_IO_CREATE_DIR;
|
|
|
|
// Remove the file name for which we are creating the directory.
|
|
|
|
if( pFileSystem->pathReduce( pSaveFileName,
|
|
pIoDirPath, pszTemp) == NE_FLM_OK)
|
|
{
|
|
if (RC_OK( pFileSystem->createDir( pIoDirPath)))
|
|
{
|
|
goto Retry_NSS_Create;
|
|
}
|
|
}
|
|
}
|
|
|
|
rc = MapNSSError( lStatus,
|
|
(RCODE)(m_bDoDirectIO
|
|
? (RCODE)NE_FLM_DIRECT_CREATING_FILE
|
|
: (RCODE)NE_FLM_CREATING_FILE));
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_lOpenAttr = f_getNSSOpenFlags( uiAccess, m_bDoDirectIO);
|
|
if ((lStatus = gv_zOpenFunc( gv_NssRootKey, 1,
|
|
zNSPACE_LONG | zMODE_UTF8, pszQualifiedPath, (FLMUINT)m_lOpenAttr,
|
|
&m_NssKey)) != zOK)
|
|
{
|
|
rc = MapNSSError( lStatus,
|
|
(RCODE)(m_bDoDirectIO
|
|
? (RCODE)NE_FLM_DIRECT_OPENING_FILE
|
|
: (RCODE)NE_FLM_OPENING_FILE));
|
|
goto Exit;
|
|
}
|
|
}
|
|
m_bNSSFileOpen = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (bCreateFlag)
|
|
{
|
|
m_lOpenAttr = (LONG)(((m_bDoSuballocation)
|
|
? (LONG)(DO_NOT_COMPRESS_FILE_BIT)
|
|
: (LONG)(NO_SUBALLOC_BIT |
|
|
DO_NOT_COMPRESS_FILE_BIT)) |
|
|
IMMEDIATE_PURGE_BIT);
|
|
|
|
Retry_Create:
|
|
lErrorCode = CreateFile( 0, 1, m_lVolumeID, 0, (BYTE *)pLNamePath,
|
|
*plLNamePathCount, LONGNameSpace, m_lOpenAttr, 0xff,
|
|
PrimaryDataStream, &m_lFileHandle, &unused, &unused2
|
|
);
|
|
|
|
if ((lErrorCode != 0) && (uiAccess & FLM_IO_CREATE_DIR))
|
|
{
|
|
uiAccess &= ~FLM_IO_CREATE_DIR;
|
|
|
|
// Remove the file name for which we are creating the directory
|
|
|
|
if( pFileSystem->pathReduce( pSaveFileName,
|
|
pIoDirPath, pszTemp) == NE_FLM_OK)
|
|
{
|
|
if( RC_OK( pFileSystem->createDir( pIoDirPath)))
|
|
{
|
|
goto Retry_Create;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Too many error codes map to 255, so we put in a special
|
|
// case check here.
|
|
|
|
if( lErrorCode == 255)
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_ACCESS_DENIED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_lOpenAttr = f_getNWOpenFlags(uiAccess, m_bDoDirectIO);
|
|
lErrorCode = OpenFile( 0, 1, m_lVolumeID, 0, (BYTE *)pLNamePath,
|
|
*plLNamePathCount, LONGNameSpace, 0, m_lOpenAttr,
|
|
PrimaryDataStream, &m_lFileHandle, &unused, &unused2);
|
|
|
|
// Too many error codes map to 255, so we put in a special
|
|
// case check here.
|
|
|
|
if( lErrorCode == 255)
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_PATH_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Check if the file operation was successful
|
|
|
|
if ( lErrorCode != 0)
|
|
{
|
|
rc = f_mapPlatformError( lErrorCode,
|
|
(RCODE)(bCreateFlag
|
|
? (RCODE)(m_bDoDirectIO
|
|
? (RCODE)NE_FLM_DIRECT_CREATING_FILE
|
|
: (RCODE)NE_FLM_CREATING_FILE)
|
|
: (RCODE)(m_bDoDirectIO
|
|
? (RCODE)NE_FLM_DIRECT_OPENING_FILE
|
|
: (RCODE)NE_FLM_OPENING_FILE)));
|
|
goto Exit;
|
|
}
|
|
|
|
if (bCreateFlag)
|
|
{
|
|
// Revoke the file handle rights and close the file
|
|
// (signified by passing 2 for the QueryFlag parameter).
|
|
// If this call fails and returns a 255 error, it may
|
|
// indicate that the FILESYS.NLM being used on the server
|
|
// does not implement option 2 for the QueryFlag parameter.
|
|
// In this case, we will default to our old behavior
|
|
// and simply call CloseFile. This, potentially, will
|
|
// not free all of the lock objects and could result in
|
|
// a memory leak in filesys.nlm. However, we want to
|
|
// at least make sure that there is a corresponding
|
|
// RevokeFileHandleRights or CloseFile call for every
|
|
// file open / create call.
|
|
|
|
if( (lErrorCode = RevokeFileHandleRights( 0, 1,
|
|
m_lFileHandle, 2, m_lOpenAttr & 0x0000000F, &unused)) == 0xFF)
|
|
{
|
|
lErrorCode = CloseFile( 0, 1, m_lFileHandle);
|
|
}
|
|
m_lOpenAttr = 0;
|
|
|
|
if ( lErrorCode != 0 )
|
|
{
|
|
rc = f_mapPlatformError(lErrorCode, NE_FLM_CLOSING_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
m_lOpenAttr = f_getNWOpenFlags(uiAccess, m_bDoDirectIO);
|
|
lErrorCode = OpenFile( 0, 1, m_lVolumeID, 0, (BYTE *)pLNamePath,
|
|
*plLNamePathCount, LONGNameSpace, 0, m_lOpenAttr,
|
|
PrimaryDataStream, &m_lFileHandle, &unused, &unused2);
|
|
|
|
if ( lErrorCode != 0 )
|
|
{
|
|
// Too many error codes map to 255, so we put in a special
|
|
// case check here.
|
|
|
|
if( lErrorCode == 255)
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_PATH_NOT_FOUND);
|
|
}
|
|
else
|
|
{
|
|
rc = f_mapPlatformError( lErrorCode,
|
|
(RCODE)(m_bDoDirectIO
|
|
? (RCODE)NE_FLM_DIRECT_OPENING_FILE
|
|
: (RCODE)NE_FLM_OPENING_FILE));
|
|
}
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if ( m_bDoDirectIO)
|
|
{
|
|
lErrorCode = SwitchToDirectFileMode(0, m_lFileHandle);
|
|
if (lErrorCode != 0)
|
|
{
|
|
if (RevokeFileHandleRights( 0, 1,
|
|
m_lFileHandle, 2, m_lOpenAttr & 0x0000000F, &unused) == 0xFF)
|
|
{
|
|
(void)CloseFile( 0, 1, m_lFileHandle);
|
|
}
|
|
rc = f_mapPlatformError( lErrorCode,
|
|
(RCODE)(bCreateFlag
|
|
? (RCODE)NE_FLM_DIRECT_CREATING_FILE
|
|
: (RCODE)NE_FLM_DIRECT_OPENING_FILE));
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (RC_BAD( rc))
|
|
{
|
|
m_lFileHandle = -1;
|
|
m_lOpenAttr = 0;
|
|
m_bNSSFileOpen = FALSE;
|
|
}
|
|
|
|
if (pszQualifiedPath)
|
|
{
|
|
f_free( &pszQualifiedPath);
|
|
}
|
|
|
|
return( rc );
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Create a file
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::create(
|
|
const char * pIoPath,
|
|
FLMUINT uiIoFlags)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
flmAssert( m_bFileOpened == FALSE);
|
|
|
|
if( RC_BAD( rc = openOrCreate( pIoPath, uiIoFlags, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_bFileOpened = TRUE;
|
|
m_uiCurrentPos = 0;
|
|
m_bOpenedExclusive = (uiIoFlags & FLM_IO_SH_DENYRW) ? TRUE : FALSE;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::createUnique(
|
|
char * pIoPath,
|
|
const char * pszFileExtension,
|
|
FLMUINT uiIoFlags)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
char * pszTmp;
|
|
FLMBOOL bModext = TRUE;
|
|
FLMUINT uiBaseTime = 0;
|
|
FLMBYTE ucHighByte = 0;
|
|
char ucFileName[ F_FILENAME_SIZE];
|
|
char szDirPath[ F_PATH_MAX_SIZE];
|
|
char szTmpPath[ F_PATH_MAX_SIZE];
|
|
FLMUINT uiCount;
|
|
IF_FileSystem * pFileSystem = f_getFileSysPtr();
|
|
|
|
f_memset( ucFileName, 0, sizeof( ucFileName));
|
|
|
|
flmAssert( m_bFileOpened == FALSE);
|
|
|
|
f_strcpy( szDirPath, pIoPath);
|
|
|
|
// Search backwards replacing trailing spaces with NULLs.
|
|
|
|
pszTmp = szDirPath;
|
|
pszTmp += (f_strlen( pszTmp) - 1);
|
|
while ((*pszTmp == 0x20) && pszTmp >= szDirPath)
|
|
{
|
|
*pszTmp = 0;
|
|
pszTmp--;
|
|
}
|
|
|
|
// Append a backslash if one isn't already there
|
|
|
|
if (pszTmp >= szDirPath && *pszTmp != '\\')
|
|
{
|
|
pszTmp++;
|
|
*pszTmp++ = '\\';
|
|
}
|
|
else
|
|
{
|
|
pszTmp++;
|
|
}
|
|
*pszTmp = 0;
|
|
|
|
if ((pszFileExtension) && (f_strlen( pszFileExtension) >= 3))
|
|
{
|
|
bModext = FALSE;
|
|
}
|
|
|
|
uiCount = 0;
|
|
do
|
|
{
|
|
pFileSystem->pathCreateUniqueName( &uiBaseTime, ucFileName,
|
|
pszFileExtension, &ucHighByte, bModext);
|
|
|
|
f_strcpy( szTmpPath, szDirPath);
|
|
pFileSystem->pathAppend( szTmpPath, ucFileName);
|
|
|
|
rc = create( szTmpPath, uiIoFlags | FLM_IO_EXCL);
|
|
|
|
if (rc == NE_FLM_IO_DISK_FULL)
|
|
{
|
|
(void)f_netwareDeleteFile( szTmpPath);
|
|
goto Exit;
|
|
}
|
|
|
|
if ((rc == NE_FLM_IO_PATH_NOT_FOUND) || (rc == NE_FLM_IO_INVALID_PASSWORD))
|
|
{
|
|
goto Exit;
|
|
}
|
|
} while ((rc != NE_FLM_OK) && (uiCount++ < 10));
|
|
|
|
// Check if the path was created
|
|
|
|
if ((uiCount >= 10) && (rc != NE_FLM_OK))
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_PATH_CREATE_FAILURE);
|
|
goto Exit;
|
|
}
|
|
|
|
m_bFileOpened = TRUE;
|
|
m_bOpenedExclusive = (uiIoFlags & FLM_IO_SH_DENYRW) ? TRUE : FALSE;
|
|
|
|
// Created file name needs to be returned.
|
|
|
|
f_strcpy( pIoPath, szTmpPath);
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Open a file
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::open(
|
|
const char * pIoPath,
|
|
FLMUINT uiIoFlags)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLMUINT uiStartTime;
|
|
FLMUINT ui15Secs;
|
|
FLMUINT uiCurrTime;
|
|
|
|
flmAssert( m_bFileOpened == FALSE);
|
|
|
|
ui15Secs = FLM_SECS_TO_TIMER_UNITS( 15);
|
|
uiStartTime = FLM_GET_TIMER();
|
|
|
|
do
|
|
{
|
|
if( RC_OK( rc = openOrCreate( pIoPath, uiIoFlags, FALSE)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( rc != NE_FLM_IO_TOO_MANY_OPEN_FILES)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_sleep( 50);
|
|
uiCurrTime = FLM_GET_TIMER();
|
|
} while( FLM_ELAPSED_TIME( uiCurrTime, uiStartTime) < ui15Secs);
|
|
|
|
if ( RC_BAD(rc) )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_bFileOpened = TRUE;
|
|
m_uiCurrentPos = 0;
|
|
m_bOpenedReadOnly = (uiIoFlags & FLM_IO_RDONLY) ? TRUE : FALSE;
|
|
m_bOpenedExclusive = (uiIoFlags & FLM_IO_SH_DENYRW) ? TRUE : FALSE;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Close a file
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI F_FileHdl::close()
|
|
{
|
|
LONG unused;
|
|
FLMBOOL bDeleteAllowed = TRUE;
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if( !m_bFileOpened)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (m_bNSS)
|
|
{
|
|
if (m_bNSSFileOpen)
|
|
{
|
|
(void)gv_zCloseFunc( m_NssKey);
|
|
m_bNSSFileOpen = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Revoke the file handle rights and close the file
|
|
// (signified by passing 2 for the QueryFlag parameter).
|
|
// If this call fails and returns a 255 error, it may
|
|
// indicate that the FILESYS.NLM being used on the server
|
|
// does not implement option 2 for the QueryFlag parameter.
|
|
// In this case, we will default to our old behavior
|
|
// and simply call CloseFile. This, potentially, will
|
|
// not free all of the lock objects and could result in
|
|
// a memory leak in filesys.nlm. However, we want to
|
|
// at least make sure that there is a corresponding
|
|
// RevokeFileHandleRights or CloseFile call for every
|
|
// file open / create call.
|
|
|
|
if( RevokeFileHandleRights( 0, 1,
|
|
m_lFileHandle, 2, m_lOpenAttr & 0x0000000F, &unused) == 0xFF)
|
|
{
|
|
(void)CloseFile( 0, 1, m_lFileHandle);
|
|
}
|
|
}
|
|
|
|
m_lOpenAttr = 0;
|
|
m_lFileHandle = -1;
|
|
m_bFileOpened = m_bOpenedReadOnly = m_bOpenedExclusive = FALSE;
|
|
|
|
if( m_bDeleteOnClose)
|
|
{
|
|
if( bDeleteAllowed)
|
|
{
|
|
if (m_bNSS)
|
|
{
|
|
(void)gv_zDeleteFunc( gv_NssRootKey, 0, zNSPACE_LONG | zMODE_UTF8,
|
|
m_pszIoPath, zMATCH_ALL, 0);
|
|
}
|
|
else
|
|
{
|
|
(void)EraseFile( 0, 1, m_lVolumeID, 0, (BYTE *)m_pszIoPath,
|
|
m_lLNamePathCount, LONGNameSpace, 0);
|
|
}
|
|
}
|
|
|
|
m_bDeleteOnClose = FALSE;
|
|
m_lLNamePathCount = 0;
|
|
}
|
|
|
|
if( m_pszIoPath)
|
|
{
|
|
f_free( &m_pszIoPath);
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Read from a file
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI F_FileHdl::read(
|
|
FLMUINT64 ui64Offset,
|
|
FLMUINT uiLength,
|
|
void * pvBuffer,
|
|
FLMUINT * puiBytesRead)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if ( m_bDoDirectIO)
|
|
{
|
|
if( RC_BAD( rc = _directIORead( (FLMUINT)ui64Offset, uiLength,
|
|
pvBuffer, puiBytesRead)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = _read( (FLMUINT)ui64Offset, uiLength,
|
|
pvBuffer, puiBytesRead)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Read from a file
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::_read(
|
|
FLMUINT uiReadOffset,
|
|
FLMUINT uiBytesToRead,
|
|
void * pvBuffer,
|
|
FLMUINT * puiBytesReadRV)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FCBType * fcb;
|
|
LONG lBytesRead;
|
|
LONG lErr;
|
|
|
|
flmAssert( m_bFileOpened == TRUE);
|
|
|
|
if( puiBytesReadRV)
|
|
{
|
|
*puiBytesReadRV = 0;
|
|
}
|
|
|
|
if (uiReadOffset == FLM_IO_CURRENT_POS)
|
|
uiReadOffset = m_uiCurrentPos;
|
|
|
|
if (m_bNSS)
|
|
{
|
|
FLMINT lStatus;
|
|
FLMUINT nBytesRead;
|
|
|
|
if ((lStatus = gv_zReadFunc( m_NssKey, 0, (FLMUINT64)uiReadOffset,
|
|
(FLMUINT)uiBytesToRead, pvBuffer,
|
|
&nBytesRead)) != zOK)
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
if( puiBytesReadRV)
|
|
{
|
|
*puiBytesReadRV = (FLMUINT)nBytesRead;
|
|
}
|
|
|
|
if ((FLMUINT)nBytesRead < uiBytesToRead)
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_END_OF_FILE);
|
|
}
|
|
m_uiCurrentPos = uiReadOffset + (FLMUINT)nBytesRead;
|
|
}
|
|
else
|
|
{
|
|
lErr = MapFileHandleToFCB( m_lFileHandle, &fcb );
|
|
if ( lErr != 0 )
|
|
{
|
|
rc = f_mapPlatformError( lErr, NE_FLM_SETTING_UP_FOR_READ);
|
|
goto Exit;
|
|
}
|
|
lErr = ReadFile( fcb->Station, m_lFileHandle, uiReadOffset,
|
|
uiBytesToRead, &lBytesRead, pvBuffer);
|
|
if ( lErr == 0 )
|
|
{
|
|
if( puiBytesReadRV)
|
|
{
|
|
*puiBytesReadRV = (FLMUINT) lBytesRead;
|
|
}
|
|
|
|
if (lBytesRead < (LONG)uiBytesToRead)
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_END_OF_FILE);
|
|
}
|
|
m_uiCurrentPos = uiReadOffset + lBytesRead;
|
|
}
|
|
else
|
|
{
|
|
rc = f_mapPlatformError(lErr, NE_FLM_READING_FILE);
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Returns m_uiCurrentPos
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI F_FileHdl::tell(
|
|
FLMUINT64 * pui64Offset)
|
|
{
|
|
*pui64Offset = m_uiCurrentPos;
|
|
return( NE_FLM_OK);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Calls the Direct IO-style read routine
|
|
Note: Where possible, the caller should attempt to read on sector
|
|
boundaries and full sectors. This routine will do the
|
|
necessary work if this is not done, but it will be less
|
|
efficient.
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::_directIORead(
|
|
FLMUINT uiReadOffset,
|
|
FLMUINT uiBytesToRead,
|
|
void * pvBuffer,
|
|
FLMUINT * puiBytesReadRV)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
|
|
LONG lStartSector;
|
|
LONG lSectorCount;
|
|
LONG lResult;
|
|
BYTE ucSectorBuf [FLM_NLM_SECTOR_SIZE];
|
|
FLMUINT uiBytesToCopy;
|
|
FLMUINT uiSectorOffset;
|
|
FLMUINT uiTotal;
|
|
FLMINT lStatus;
|
|
|
|
flmAssert( m_bFileOpened == TRUE);
|
|
|
|
if( puiBytesReadRV)
|
|
{
|
|
*puiBytesReadRV = 0;
|
|
}
|
|
|
|
if (uiReadOffset == FLM_IO_CURRENT_POS)
|
|
uiReadOffset = m_uiCurrentPos;
|
|
|
|
// Calculate the starting sector.
|
|
|
|
lStartSector = uiReadOffset / FLM_NLM_SECTOR_SIZE;
|
|
|
|
// See if the offset is on a sector boundary. If not, we must read
|
|
// into the local sector buffer and then copy into the buffer.
|
|
// We must also read into the local buffer if our read size is less
|
|
// than the sector size.
|
|
|
|
if ((uiReadOffset % FLM_NLM_SECTOR_SIZE != 0) ||
|
|
(uiBytesToRead < FLM_NLM_SECTOR_SIZE))
|
|
{
|
|
if (m_bNSS)
|
|
{
|
|
if ((lStatus = gv_zDIOReadFunc( m_NssKey,
|
|
(FLMUINT64)lStartSector, 1,
|
|
(FLMUINT)0, NULL, ucSectorBuf)) != zOK)
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_DIRECT_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lResult = DirectReadFile(
|
|
0,
|
|
m_lFileHandle,
|
|
lStartSector,
|
|
1,
|
|
ucSectorBuf
|
|
);
|
|
if (lResult != 0)
|
|
{
|
|
rc = DfsMapError( lResult, NE_FLM_DIRECT_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Copy the part of the sector that was requested into the buffer.
|
|
|
|
uiSectorOffset = uiReadOffset % FLM_NLM_SECTOR_SIZE;
|
|
|
|
if ((uiBytesToCopy = uiBytesToRead) > FLM_NLM_SECTOR_SIZE - uiSectorOffset)
|
|
uiBytesToCopy = FLM_NLM_SECTOR_SIZE - uiSectorOffset;
|
|
f_memcpy( pucBuffer, &ucSectorBuf [uiSectorOffset], uiBytesToCopy);
|
|
pucBuffer += uiBytesToCopy;
|
|
uiBytesToRead -= (FLMUINT)uiBytesToCopy;
|
|
m_uiCurrentPos += (FLMUINT)uiBytesToCopy;
|
|
|
|
if( puiBytesReadRV)
|
|
{
|
|
(*puiBytesReadRV) += (FLMUINT)uiBytesToCopy;
|
|
}
|
|
|
|
// See if we got everything we wanted to with this read.
|
|
|
|
if (!uiBytesToRead)
|
|
goto Exit;
|
|
|
|
// Go to the next sector boundary
|
|
|
|
lStartSector++;
|
|
}
|
|
|
|
// At this point, we are poised to read on a sector boundary. See if we
|
|
// have at least one full sector to read. If so, we can read it directly
|
|
// into the provided buffer. If not, we must use the temporary sector
|
|
// buffer.
|
|
|
|
if (uiBytesToRead >= FLM_NLM_SECTOR_SIZE)
|
|
{
|
|
lSectorCount = (LONG)(uiBytesToRead / FLM_NLM_SECTOR_SIZE);
|
|
Try_Read:
|
|
if (m_bNSS)
|
|
{
|
|
if ((lStatus = gv_zDIOReadFunc( m_NssKey,
|
|
(FLMUINT64)lStartSector,
|
|
(FLMUINT)lSectorCount,
|
|
(FLMUINT)0, NULL, pucBuffer)) != zOK)
|
|
{
|
|
if ((lStatus == zERR_END_OF_FILE || lStatus == zERR_BEYOND_EOF) &&
|
|
(lSectorCount > 1))
|
|
{
|
|
|
|
// See if we can read one less sector. We will return
|
|
// NE_FLM_IO_END_OF_FILE in this case.
|
|
|
|
lSectorCount--;
|
|
rc = RC_SET( NE_FLM_IO_END_OF_FILE);
|
|
goto Try_Read;
|
|
}
|
|
rc = MapNSSError( lStatus, NE_FLM_DIRECT_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lResult = DirectReadFile( 0, m_lFileHandle, lStartSector,
|
|
lSectorCount, pucBuffer);
|
|
|
|
if (lResult != 0)
|
|
{
|
|
if ((lResult == DFSOperationBeyondEndOfFile) &&
|
|
(lSectorCount > 1))
|
|
{
|
|
|
|
// See if we can read one less sector. We will return
|
|
// NE_FLM_IO_END_OF_FILE in this case.
|
|
|
|
lSectorCount--;
|
|
rc = RC_SET( NE_FLM_IO_END_OF_FILE);
|
|
goto Try_Read;
|
|
}
|
|
rc = DfsMapError( lResult, NE_FLM_DIRECT_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
uiTotal = (FLMUINT)(lSectorCount * FLM_NLM_SECTOR_SIZE);
|
|
pucBuffer += uiTotal;
|
|
m_uiCurrentPos += uiTotal;
|
|
|
|
if( puiBytesReadRV)
|
|
{
|
|
(*puiBytesReadRV) += uiTotal;
|
|
}
|
|
uiBytesToRead -= uiTotal;
|
|
|
|
// See if we got everything we wanted to or could with this read.
|
|
|
|
if ((!uiBytesToRead) || (rc == NE_FLM_IO_END_OF_FILE))
|
|
goto Exit;
|
|
|
|
// Go to the next sector after the ones we just read
|
|
|
|
lStartSector += lSectorCount;
|
|
}
|
|
|
|
// At this point, we have less than a sector's worth to read, so we must
|
|
// read it into a local buffer.
|
|
|
|
if (m_bNSS)
|
|
{
|
|
if ((lStatus = gv_zDIOReadFunc( m_NssKey,
|
|
(FLMUINT64)lStartSector, 1,
|
|
(FLMUINT)0, NULL, ucSectorBuf)) != zOK)
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_DIRECT_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lResult = DirectReadFile( 0, m_lFileHandle, lStartSector, 1, ucSectorBuf);
|
|
if (lResult != 0)
|
|
{
|
|
rc = DfsMapError( lResult, NE_FLM_DIRECT_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Copy the part of the sector that was requested into the buffer.
|
|
|
|
m_uiCurrentPos += uiBytesToRead;
|
|
|
|
if( puiBytesReadRV)
|
|
{
|
|
(*puiBytesReadRV) += uiBytesToRead;
|
|
}
|
|
|
|
f_memcpy( pucBuffer, ucSectorBuf, uiBytesToRead);
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Might call the direct IO routine in the future
|
|
Note: This function assumes that the pvBuffer that is passed in is
|
|
a multiple of a sector size (512 bytes).
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI F_FileHdl::sectorRead(
|
|
FLMUINT64 ui64ReadOffset,
|
|
FLMUINT uiBytesToRead,
|
|
void * pvBuffer,
|
|
FLMUINT * puiBytesReadRV)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if( m_bDoDirectIO)
|
|
{
|
|
if( RC_BAD( rc = _directIOSectorRead( (FLMUINT)ui64ReadOffset,
|
|
uiBytesToRead, pvBuffer, puiBytesReadRV)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = _read( (FLMUINT)ui64ReadOffset, uiBytesToRead,
|
|
pvBuffer, puiBytesReadRV)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Calls the direct IO Read routine
|
|
Note: This function assumes that the pvBuffer that is passed in is
|
|
a multiple of a sector size (512 bytes).
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::_directIOSectorRead(
|
|
FLMUINT uiReadOffset,
|
|
FLMUINT uiBytesToRead,
|
|
void * pvBuffer,
|
|
FLMUINT * puiBytesReadRV)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LONG lStartSector;
|
|
LONG lSectorCount;
|
|
LONG lResult;
|
|
FLMINT lStatus;
|
|
|
|
flmAssert( m_bFileOpened == TRUE);
|
|
|
|
if (uiReadOffset == FLM_IO_CURRENT_POS)
|
|
uiReadOffset = m_uiCurrentPos;
|
|
|
|
if (uiReadOffset % FLM_NLM_SECTOR_SIZE != 0)
|
|
{
|
|
rc = _read( uiReadOffset, uiBytesToRead, pvBuffer, puiBytesReadRV);
|
|
goto Exit;
|
|
}
|
|
|
|
// Calculate the starting sector
|
|
|
|
lStartSector = uiReadOffset / FLM_NLM_SECTOR_SIZE;
|
|
lSectorCount = (LONG)(uiBytesToRead / FLM_NLM_SECTOR_SIZE);
|
|
if (uiBytesToRead % FLM_NLM_SECTOR_SIZE != 0)
|
|
lSectorCount++;
|
|
|
|
Try_Read:
|
|
|
|
if (m_bNSS)
|
|
{
|
|
if ((lStatus = gv_zDIOReadFunc( m_NssKey,
|
|
(FLMUINT64)lStartSector,
|
|
(FLMUINT)lSectorCount,
|
|
(FLMUINT)0, NULL, pvBuffer)) != zOK)
|
|
{
|
|
if ((lStatus == zERR_END_OF_FILE || lStatus == zERR_BEYOND_EOF) &&
|
|
(lSectorCount > 1))
|
|
{
|
|
|
|
// See if we can read one less sector. We will return
|
|
// NE_FLM_IO_END_OF_FILE in this case.
|
|
|
|
lSectorCount--;
|
|
uiBytesToRead = (FLMUINT)(lSectorCount * FLM_NLM_SECTOR_SIZE);
|
|
rc = RC_SET( NE_FLM_IO_END_OF_FILE);
|
|
goto Try_Read;
|
|
}
|
|
uiBytesToRead = 0;
|
|
rc = MapNSSError( lStatus, NE_FLM_DIRECT_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lResult = DirectReadFile( 0, m_lFileHandle,
|
|
lStartSector, lSectorCount,(BYTE *)pvBuffer);
|
|
if (lResult != 0)
|
|
{
|
|
if ((lResult == DFSOperationBeyondEndOfFile) &&
|
|
(lSectorCount > 1))
|
|
{
|
|
// See if we can read one less sector. We will return
|
|
// NE_FLM_IO_END_OF_FILE in this case.
|
|
|
|
lSectorCount--;
|
|
uiBytesToRead = (FLMUINT)(lSectorCount * FLM_NLM_SECTOR_SIZE);
|
|
rc = RC_SET( NE_FLM_IO_END_OF_FILE);
|
|
goto Try_Read;
|
|
}
|
|
uiBytesToRead = 0;
|
|
rc = DfsMapError( lResult, NE_FLM_DIRECT_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
m_uiCurrentPos += uiBytesToRead;
|
|
|
|
Exit:
|
|
|
|
if( puiBytesReadRV)
|
|
{
|
|
*puiBytesReadRV = uiBytesToRead;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Sets current position of file.
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI F_FileHdl::seek(
|
|
FLMUINT64 ui64Offset,
|
|
FLMINT iWhence,
|
|
FLMUINT64 * pui64NewOffset)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
switch (iWhence)
|
|
{
|
|
case FLM_IO_SEEK_CUR:
|
|
m_uiCurrentPos += (FLMUINT)ui64Offset;
|
|
break;
|
|
|
|
case FLM_IO_SEEK_SET:
|
|
m_uiCurrentPos = (FLMUINT)ui64Offset;
|
|
break;
|
|
|
|
case FLM_IO_SEEK_END:
|
|
if( RC_BAD( rc = size( &ui64Offset)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
m_uiCurrentPos = (FLMUINT)ui64Offset;
|
|
break;
|
|
|
|
default:
|
|
rc = RC_SET( NE_FLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
*pui64NewOffset = m_uiCurrentPos;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Return the size of the file
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI F_FileHdl::size(
|
|
FLMUINT64 * pui64Size)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LONG lErr;
|
|
LONG lSize;
|
|
|
|
if (m_bNSS)
|
|
{
|
|
FLMINT lStatus;
|
|
zInfo_s Info;
|
|
|
|
if ((lStatus = gv_zGetInfoFunc( m_NssKey,
|
|
zGET_STORAGE_USED,
|
|
sizeof( Info), zINFO_VERSION_A,
|
|
&Info)) != zOK)
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_GETTING_FILE_INFO);
|
|
goto Exit;
|
|
}
|
|
flmAssert( Info.infoVersion == zINFO_VERSION_A);
|
|
*pui64Size = (FLMUINT64)Info.std.logicalEOF;
|
|
}
|
|
else
|
|
{
|
|
lErr = GetFileSize( 0, m_lFileHandle, &lSize);
|
|
if ( lErr != 0 )
|
|
{
|
|
rc = f_mapPlatformError( lErr, NE_FLM_GETTING_FILE_SIZE);
|
|
}
|
|
*pui64Size = (FLMUINT64)lSize;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Truncate the file to the indicated size
|
|
WARNING: Direct IO methods are calling this method. Make sure that all
|
|
changes to this method work in direct IO mode.
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI F_FileHdl::truncate(
|
|
FLMUINT64 ui64Size)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LONG lErr;
|
|
|
|
flmAssert( m_bFileOpened == TRUE);
|
|
|
|
if (m_bNSS)
|
|
{
|
|
FLMINT lStatus;
|
|
|
|
if ((lStatus = gv_zSetEOFFunc( m_NssKey, 0, ui64Size,
|
|
zSETSIZE_NON_SPARSE_FILE |
|
|
zSETSIZE_NO_ZERO_FILL |
|
|
zSETSIZE_UNDO_ON_ERR)) != zOK)
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_TRUNCATING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((lErr = SetFileSize( 0, m_lFileHandle, (FLMUINT)ui64Size, TRUE)) != 0)
|
|
{
|
|
rc = f_mapPlatformError( lErr, NE_FLM_TRUNCATING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (m_uiCurrentPos > ui64Size)
|
|
{
|
|
m_uiCurrentPos = (FLMUINT)ui64Size;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Write to a file
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI F_FileHdl::write(
|
|
FLMUINT64 ui64Offset,
|
|
FLMUINT uiLength,
|
|
const void * pvBuffer,
|
|
FLMUINT * puiBytesWritten)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if( m_bDoDirectIO)
|
|
{
|
|
if( RC_BAD( rc = _directIOWrite( (FLMUINT)ui64Offset, uiLength,
|
|
pvBuffer, puiBytesWritten)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = _write( (FLMUINT)ui64Offset, uiLength,
|
|
pvBuffer, puiBytesWritten)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Write to a file
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::_write(
|
|
FLMUINT uiWriteOffset,
|
|
FLMUINT uiBytesToWrite,
|
|
const void * pvBuffer,
|
|
FLMUINT * puiBytesWrittenRV)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LONG lErr;
|
|
FCBType * fcb;
|
|
|
|
flmAssert( m_bFileOpened == TRUE);
|
|
|
|
*puiBytesWrittenRV = 0;
|
|
|
|
if (uiWriteOffset == FLM_IO_CURRENT_POS)
|
|
{
|
|
uiWriteOffset = m_uiCurrentPos;
|
|
}
|
|
else
|
|
{
|
|
m_uiCurrentPos = uiWriteOffset;
|
|
}
|
|
|
|
if( m_bNSS)
|
|
{
|
|
FLMINT lStatus;
|
|
FLMUINT nBytesWritten;
|
|
|
|
if( (lStatus = gv_zWriteFunc( m_NssKey, 0, (FLMUINT64)uiWriteOffset,
|
|
(FLMUINT)uiBytesToWrite, pvBuffer, &nBytesWritten)) != zOK)
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_WRITING_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
if( nBytesWritten != (FLMUINT)uiBytesToWrite)
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_DISK_FULL);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( (lErr = MapFileHandleToFCB( m_lFileHandle, &fcb )) != 0)
|
|
{
|
|
rc = f_mapPlatformError( lErr, NE_FLM_SETTING_UP_FOR_WRITE);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (lErr = WriteFile( fcb->Station, m_lFileHandle, uiWriteOffset,
|
|
uiBytesToWrite, (void *)pvBuffer)) != 0)
|
|
{
|
|
rc = f_mapPlatformError( lErr, NE_FLM_WRITING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
*puiBytesWrittenRV = uiBytesToWrite;
|
|
m_uiCurrentPos = uiWriteOffset + uiBytesToWrite;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Calls the direct IO Write routine.
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::_directIOWrite(
|
|
FLMUINT uiWriteOffset,
|
|
FLMUINT uiBytesToWrite,
|
|
const void * pvBuffer,
|
|
FLMUINT * puiBytesWrittenRV)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
|
|
LONG lStartSector;
|
|
LONG lSectorCount;
|
|
LONG lResult;
|
|
BYTE ucSectorBuf[ FLM_NLM_SECTOR_SIZE];
|
|
FLMUINT uiBytesToCopy;
|
|
FLMUINT uiSectorOffset;
|
|
FLMUINT uiTotal;
|
|
FLMINT lStatus;
|
|
|
|
flmAssert( m_bFileOpened == TRUE);
|
|
|
|
*puiBytesWrittenRV = 0;
|
|
|
|
if( uiWriteOffset == FLM_IO_CURRENT_POS)
|
|
{
|
|
uiWriteOffset = m_uiCurrentPos;
|
|
}
|
|
else
|
|
{
|
|
m_uiCurrentPos = uiWriteOffset;
|
|
}
|
|
|
|
// Calculate the starting sector
|
|
|
|
lStartSector = uiWriteOffset / FLM_NLM_SECTOR_SIZE;
|
|
|
|
// See if the offset is on a sector boundary. If not, we must first read
|
|
// the sector into memory, overwrite it with data from the input
|
|
// buffer and write it back out again.
|
|
|
|
if( (uiWriteOffset % FLM_NLM_SECTOR_SIZE != 0) ||
|
|
(uiBytesToWrite < FLM_NLM_SECTOR_SIZE))
|
|
{
|
|
if( m_bNSS)
|
|
{
|
|
if( (lStatus = gv_zDIOReadFunc( m_NssKey,
|
|
(FLMUINT64)lStartSector,
|
|
(FLMUINT)1, (FLMUINT)0, NULL, ucSectorBuf)) != zOK)
|
|
{
|
|
if (lStatus == zERR_END_OF_FILE || lStatus == zERR_BEYOND_EOF)
|
|
{
|
|
f_memset( ucSectorBuf, 0, sizeof( ucSectorBuf));
|
|
|
|
// Expand the file
|
|
|
|
if( RC_BAD( rc = expand( lStartSector, 1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_DIRECT_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lResult = DirectReadFile( 0, m_lFileHandle, lStartSector,
|
|
1, ucSectorBuf);
|
|
|
|
if( lResult == DFSHoleInFileError ||
|
|
lResult == DFSOperationBeyondEndOfFile )
|
|
{
|
|
f_memset( ucSectorBuf, 0, sizeof( ucSectorBuf));
|
|
|
|
// Expand the file
|
|
|
|
if( RC_BAD( rc = expand( lStartSector, 1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( lResult != 0)
|
|
{
|
|
rc = DfsMapError( lResult, NE_FLM_DIRECT_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Copy the part of the buffer that is being written back into
|
|
// the sector buffer.
|
|
|
|
uiSectorOffset = uiWriteOffset % FLM_NLM_SECTOR_SIZE;
|
|
|
|
if( (uiBytesToCopy = uiBytesToWrite) > FLM_NLM_SECTOR_SIZE - uiSectorOffset)
|
|
{
|
|
uiBytesToCopy = FLM_NLM_SECTOR_SIZE - uiSectorOffset;
|
|
}
|
|
|
|
f_memcpy( &ucSectorBuf [uiSectorOffset], pucBuffer, uiBytesToCopy);
|
|
pucBuffer += uiBytesToCopy;
|
|
uiBytesToWrite -= (FLMUINT)uiBytesToCopy;
|
|
m_uiCurrentPos += (FLMUINT)uiBytesToCopy;
|
|
(*puiBytesWrittenRV) += (FLMUINT)uiBytesToCopy;
|
|
|
|
// Write the sector buffer back out
|
|
|
|
if( RC_BAD( rc = writeSectors( &ucSectorBuf [0], lStartSector, 1, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// See if we wrote everything we wanted to with this write
|
|
|
|
if (!uiBytesToWrite)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Go to the next sector boundary
|
|
|
|
lStartSector++;
|
|
}
|
|
|
|
// At this point, we are poised to write on a sector boundary. See if we
|
|
// have at least one full sector to write. If so, we can write it directly
|
|
// from the provided buffer. If not, we must use the temporary sector
|
|
// buffer.
|
|
|
|
if( uiBytesToWrite >= FLM_NLM_SECTOR_SIZE)
|
|
{
|
|
lSectorCount = (LONG)(uiBytesToWrite / FLM_NLM_SECTOR_SIZE);
|
|
|
|
if( RC_BAD( rc = writeSectors( (void *)pucBuffer, lStartSector,
|
|
lSectorCount, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiTotal = (FLMUINT)(lSectorCount * FLM_NLM_SECTOR_SIZE);
|
|
pucBuffer += uiTotal;
|
|
m_uiCurrentPos += uiTotal;
|
|
(*puiBytesWrittenRV) += uiTotal;
|
|
uiBytesToWrite -= uiTotal;
|
|
|
|
// See if we wrote everything we wanted to with this write
|
|
|
|
if( !uiBytesToWrite)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Go to the next sector after the ones we just wrote
|
|
|
|
lStartSector += lSectorCount;
|
|
}
|
|
|
|
// At this point, we have less than a sector's worth to write, so we must
|
|
// first read the sector from disk, alter it, and then write it back out.
|
|
|
|
if( m_bNSS)
|
|
{
|
|
if( (lStatus = gv_zDIOReadFunc( m_NssKey, (FLMUINT64)lStartSector,
|
|
(FLMUINT)1, (FLMUINT)0, NULL, ucSectorBuf)) != zOK)
|
|
{
|
|
if( lStatus == zERR_END_OF_FILE || lStatus == zERR_BEYOND_EOF)
|
|
{
|
|
f_memset( ucSectorBuf, 0, sizeof( ucSectorBuf));
|
|
|
|
// Expand the file
|
|
|
|
if( RC_BAD( rc = expand( lStartSector, 1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_DIRECT_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lResult = DirectReadFile( 0, m_lFileHandle, lStartSector,
|
|
1, ucSectorBuf);
|
|
|
|
if( lResult == DFSHoleInFileError)
|
|
{
|
|
f_memset( ucSectorBuf, 0, sizeof( ucSectorBuf));
|
|
|
|
// Expand the file
|
|
|
|
if( RC_BAD( rc = expand( lStartSector, 1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( lResult != 0)
|
|
{
|
|
rc = DfsMapError( lResult, NE_FLM_DIRECT_READING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Copy the rest of the output buffer into the sector buffer
|
|
|
|
f_memcpy( ucSectorBuf, pucBuffer, uiBytesToWrite);
|
|
|
|
// Write the sector back to disk
|
|
|
|
if( RC_BAD( rc = writeSectors( &ucSectorBuf [0], lStartSector, 1, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_uiCurrentPos += uiBytesToWrite;
|
|
(*puiBytesWrittenRV) += uiBytesToWrite;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
Desc: Expand a file for writing.
|
|
***************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::expand(
|
|
LONG lStartSector,
|
|
LONG lSectorsToAlloc)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LONG lResult;
|
|
LONG lBlockNumber;
|
|
LONG lStartBlockNumber;
|
|
LONG lNumBlocksToAlloc;
|
|
LONG lNumBlocksAllocated;
|
|
LONG lMinToAlloc;
|
|
LONG lLastBlockNumber;
|
|
LONG lTotalToAlloc;
|
|
LONG lExtendSize;
|
|
FLMUINT uiFileSize;
|
|
FLMUINT uiRequestedExtendSize = m_uiExtendSize;
|
|
FLMBOOL bVerifyFileSize = FALSE;
|
|
|
|
// If the requested extend size is the "special" value of ~0,
|
|
// we will set the requested size to 0, so that we will use the
|
|
// minimum default below. This allows us to somewhat emulate what
|
|
// the Window's code does.
|
|
|
|
if( uiRequestedExtendSize == (FLMUINT)(~0))
|
|
{
|
|
uiRequestedExtendSize = 0;
|
|
}
|
|
|
|
if( m_bNSS)
|
|
{
|
|
lStartBlockNumber = lStartSector / (65536 / FLM_NLM_SECTOR_SIZE);
|
|
lLastBlockNumber = (lStartSector + lSectorsToAlloc) / (65536 / FLM_NLM_SECTOR_SIZE);
|
|
lExtendSize = uiRequestedExtendSize / 65536;
|
|
}
|
|
else
|
|
{
|
|
lStartBlockNumber = lStartSector / m_lSectorsPerBlock;
|
|
lLastBlockNumber = (lStartSector + lSectorsToAlloc) / m_lSectorsPerBlock;
|
|
lExtendSize = uiRequestedExtendSize / (m_lSectorsPerBlock * FLM_NLM_SECTOR_SIZE);
|
|
}
|
|
|
|
// Last block number better be greater than or equal to
|
|
// start block number.
|
|
|
|
flmAssert( lLastBlockNumber >= lStartBlockNumber);
|
|
lMinToAlloc = (lLastBlockNumber - lStartBlockNumber) + 1;
|
|
|
|
if( lExtendSize < 5)
|
|
{
|
|
lExtendSize = 5;
|
|
}
|
|
|
|
// Allocate up to lExtendSize blocks at a time - hopefully this will be
|
|
// more efficient.
|
|
|
|
if( lMinToAlloc < lExtendSize)
|
|
{
|
|
lTotalToAlloc = lExtendSize;
|
|
}
|
|
else if( lMinToAlloc % lExtendSize == 0)
|
|
{
|
|
lTotalToAlloc = lMinToAlloc;
|
|
}
|
|
else
|
|
{
|
|
// Keep the total blocks to allocate a multiple of lExtendSize.
|
|
|
|
lTotalToAlloc = lMinToAlloc -
|
|
(lMinToAlloc % lExtendSize) + lExtendSize;
|
|
}
|
|
|
|
lNumBlocksToAlloc = lTotalToAlloc;
|
|
lBlockNumber = lStartBlockNumber;
|
|
lNumBlocksAllocated = 0;
|
|
|
|
// Must not go over maximum file size.
|
|
|
|
if( lStartBlockNumber + lTotalToAlloc > m_lMaxBlocks)
|
|
{
|
|
lNumBlocksToAlloc = lTotalToAlloc = m_lMaxBlocks - lStartBlockNumber;
|
|
|
|
if( lTotalToAlloc < lMinToAlloc)
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_DISK_FULL);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( m_bNSS)
|
|
{
|
|
FLMINT lStatus;
|
|
|
|
for( ;;)
|
|
{
|
|
if( (lStatus = gv_zSetEOFFunc( m_NssKey, 0,
|
|
(FLMUINT64)lBlockNumber * 65536 + lNumBlocksToAlloc * 65536,
|
|
zSETSIZE_NO_ZERO_FILL | zSETSIZE_NON_SPARSE_FILE)) != zOK)
|
|
{
|
|
if( lStatus == zERR_OUT_OF_SPACE)
|
|
{
|
|
if( lNumBlocksToAlloc > lMinToAlloc)
|
|
{
|
|
lNumBlocksToAlloc--;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
rc = MapNSSError( lStatus, NE_FLM_EXPANDING_FILE);
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (;;)
|
|
{
|
|
lResult = ExpandFileInContiguousBlocks( 0, m_lFileHandle,
|
|
lBlockNumber, lNumBlocksToAlloc, -1, -1);
|
|
|
|
// If we couldn't allocate space, see if we can free some of
|
|
// the limbo space on the volume.
|
|
|
|
if( lResult == DFSInsufficientSpace || lResult == DFSBoundryError)
|
|
{
|
|
// May not have been able to get contiguous space for
|
|
// multiple blocks. If we were asking for more than
|
|
// one, reduce the number we are asking for and try
|
|
// again.
|
|
|
|
if( lNumBlocksToAlloc > 1)
|
|
{
|
|
lNumBlocksToAlloc--;
|
|
continue;
|
|
}
|
|
|
|
// If we could not even get one block, it is time to
|
|
// try and free some limbo space.
|
|
|
|
lResult = FreeLimboVolumeSpace( (LONG)m_lVolumeID, 1);
|
|
if( lResult == DFSInsufficientLimboFileSpace)
|
|
{
|
|
// It is not an error to be out of space if
|
|
// we successfully allocated at least the minimum
|
|
// number of blocks needed.
|
|
|
|
if( lNumBlocksAllocated >= lMinToAlloc)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_DISK_FULL);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else if( lResult == DFSOverlapError)
|
|
{
|
|
lResult = 0;
|
|
bVerifyFileSize = TRUE;
|
|
|
|
// If lNumBlocksToAlloc is greater than one, we
|
|
// don't know exactly where the hole is, so we need
|
|
// to try filling exactly one block right where
|
|
// we are at.
|
|
|
|
// If lNumBlocksToAlloc is exactly one, we know that
|
|
// we have a block right where we are at, so we let
|
|
// the code fall through as if the expand had
|
|
// succeeded.
|
|
|
|
if( lNumBlocksToAlloc > 1)
|
|
{
|
|
// If we have an overlap, try getting one block at
|
|
// the current block number - need to make sure this
|
|
// is not where the hole is at.
|
|
|
|
lNumBlocksToAlloc = 1;
|
|
continue;
|
|
}
|
|
}
|
|
else if (lResult != 0)
|
|
{
|
|
rc = DfsMapError( lResult, NE_FLM_EXPANDING_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
lNumBlocksAllocated += lNumBlocksToAlloc;
|
|
lBlockNumber += lNumBlocksToAlloc;
|
|
|
|
if( lNumBlocksAllocated >= lTotalToAlloc)
|
|
{
|
|
break;
|
|
}
|
|
else if( lNumBlocksToAlloc > lTotalToAlloc - lNumBlocksAllocated)
|
|
{
|
|
lNumBlocksToAlloc = lTotalToAlloc - lNumBlocksAllocated;
|
|
}
|
|
}
|
|
|
|
// If bVerifyFileSize is TRUE, we had an overlap error, which means
|
|
// that we may have had a hole in the file. In that case, we
|
|
// do NOT want to truncate the file to an incorrect size, so we
|
|
// get the current file size to make sure we are not reducing it
|
|
// down inappropriately. NOTE: This is not foolproof - if we have
|
|
// a hole that is exactly the size we asked for, we will not verify
|
|
// the file size.
|
|
|
|
uiFileSize = (FLMUINT)(lStartBlockNumber + lNumBlocksAllocated) *
|
|
(FLMUINT)m_lSectorsPerBlock * (FLMUINT)FLM_NLM_SECTOR_SIZE;
|
|
|
|
if( bVerifyFileSize)
|
|
{
|
|
LONG lCurrFileSize;
|
|
|
|
lResult = GetFileSize( 0, m_lFileHandle, &lCurrFileSize);
|
|
|
|
if( lResult != DFSNormalCompletion)
|
|
{
|
|
rc = DfsMapError( lResult, NE_FLM_GETTING_FILE_SIZE);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (FLMUINT)lCurrFileSize > uiFileSize)
|
|
{
|
|
uiFileSize = (FLMUINT)lCurrFileSize;
|
|
}
|
|
}
|
|
|
|
// This call of SetFileSize is done to force the directory entry file size
|
|
// to account for the newly allocated blocks. It also forces the directory
|
|
// entry to be updated on disk. If we didn't do this here, the directory
|
|
// entry's file size on disk would not account for this block.
|
|
// Thus, if we crashed after writing data to this
|
|
// newly allocated block, we would lose the data in the block.
|
|
|
|
lResult = SetFileSize( 0, m_lFileHandle, uiFileSize, FALSE);
|
|
|
|
if( lResult != DFSNormalCompletion)
|
|
{
|
|
rc = DfsMapError( lResult, NE_FLM_TRUNCATING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Calls the direct IO Write routine. Handles both asynchronous writes
|
|
and synchronous writes.
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::writeSectors(
|
|
void * pvBuffer,
|
|
LONG lStartSector,
|
|
LONG lSectorCount,
|
|
IF_IOBuffer * pBufferObj,
|
|
FLMBOOL * pbDidAsync)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LONG lResult;
|
|
FLMBOOL bAlreadyExpanded = FALSE;
|
|
FLMINT lStatus;
|
|
FLMBOOL bMadePending;
|
|
|
|
// Keep trying write until we succeed or get an error we can't deal with.
|
|
// Actually, this will NOT loop forever. At most, it will try twice -
|
|
// and then it is only when we get a hole in the file error.
|
|
|
|
bMadePending = FALSE;
|
|
for (;;)
|
|
{
|
|
if (m_bNSS)
|
|
{
|
|
if( pBufferObj)
|
|
{
|
|
if (!bMadePending)
|
|
{
|
|
flmAssert( pbDidAsync);
|
|
pBufferObj->makePending();
|
|
bMadePending = TRUE;
|
|
}
|
|
lStatus = gv_zDIOWriteFunc( m_NssKey,
|
|
(FLMUINT64)lStartSector,
|
|
(FLMUINT)lSectorCount,
|
|
(FLMUINT)pBufferObj,
|
|
nssDioCallback,
|
|
pvBuffer);
|
|
}
|
|
else
|
|
{
|
|
lStatus = gv_zDIOWriteFunc( m_NssKey,
|
|
(FLMUINT64)lStartSector,
|
|
(FLMUINT)lSectorCount, (FLMUINT)0, NULL, pvBuffer);
|
|
}
|
|
|
|
// We may need to allocate space to do this write
|
|
|
|
if (lStatus == zERR_END_OF_FILE ||
|
|
lStatus == zERR_BEYOND_EOF ||
|
|
lStatus == zERR_HOLE_IN_DIO_FILE)
|
|
{
|
|
if (bAlreadyExpanded)
|
|
{
|
|
flmAssert( 0);
|
|
rc = MapNSSError( lStatus, NE_FLM_DIRECT_WRITING_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
// Expand the file
|
|
|
|
if (RC_BAD( rc = expand( lStartSector, lSectorCount)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bAlreadyExpanded = TRUE;
|
|
continue;
|
|
}
|
|
else if (lStatus != 0)
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_DIRECT_WRITING_FILE);
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
if (pBufferObj)
|
|
{
|
|
*pbDidAsync = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LONG lSize;
|
|
FLMBOOL bNeedToWriteEOF;
|
|
|
|
// Determine if this write will change the EOF. If so, pre-expand
|
|
// the file.
|
|
|
|
lResult = GetFileSize( 0, m_lFileHandle, &lSize);
|
|
if (lResult != 0)
|
|
{
|
|
rc = f_mapPlatformError( lResult, NE_FLM_GETTING_FILE_SIZE);
|
|
goto Exit;
|
|
}
|
|
|
|
bNeedToWriteEOF = (lSize < (lStartSector + lSectorCount) * FLM_NLM_SECTOR_SIZE)
|
|
? TRUE
|
|
: FALSE;
|
|
|
|
if( pBufferObj)
|
|
{
|
|
if (!bMadePending)
|
|
{
|
|
flmAssert( pbDidAsync);
|
|
pBufferObj->makePending();
|
|
bMadePending = TRUE;
|
|
}
|
|
|
|
lResult = DirectWriteFileNoWait( 0, m_lFileHandle,
|
|
lStartSector,lSectorCount,
|
|
(BYTE *)pvBuffer, DirectIONoWaitCallBack,
|
|
(LONG)pBufferObj);
|
|
}
|
|
else
|
|
{
|
|
lResult = DirectWriteFile( 0, m_lFileHandle,
|
|
lStartSector, lSectorCount, (BYTE *)pvBuffer);
|
|
}
|
|
|
|
// We may need to allocate space to do this write
|
|
|
|
if( lResult == DFSHoleInFileError ||
|
|
lResult == DFSOperationBeyondEndOfFile)
|
|
{
|
|
if( bAlreadyExpanded)
|
|
{
|
|
flmAssert( 0);
|
|
rc = DfsMapError( lResult, NE_FLM_DIRECT_WRITING_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
// Expand the file
|
|
|
|
if( RC_BAD( rc = expand( lStartSector, lSectorCount)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bAlreadyExpanded = TRUE;
|
|
|
|
// The Expand method forces the file EOF in the directory
|
|
// entry to be written to disk.
|
|
|
|
bNeedToWriteEOF = FALSE;
|
|
continue;
|
|
}
|
|
else if (lResult != 0)
|
|
{
|
|
rc = DfsMapError( lResult, NE_FLM_DIRECT_WRITING_FILE);
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
if( pBufferObj)
|
|
{
|
|
*pbDidAsync = TRUE;
|
|
}
|
|
|
|
// If bNeedToWriteEOF is TRUE, we need to force EOF to disk.
|
|
|
|
if( bNeedToWriteEOF)
|
|
{
|
|
LONG lFileSizeInSectors;
|
|
LONG lExtraSectors;
|
|
|
|
// Set the EOF to the nearest block boundary - so we don't
|
|
// have to do this very often.
|
|
|
|
lFileSizeInSectors = lStartSector + lSectorCount;
|
|
lExtraSectors = lFileSizeInSectors % m_lSectorsPerBlock;
|
|
|
|
if (lExtraSectors)
|
|
{
|
|
lFileSizeInSectors += (m_lSectorsPerBlock - lExtraSectors);
|
|
}
|
|
|
|
if ((lResult = SetFileSize( 0, m_lFileHandle,
|
|
(FLMUINT)lFileSizeInSectors * FLM_NLM_SECTOR_SIZE,
|
|
FALSE)) != 0)
|
|
{
|
|
rc = DfsMapError( lResult, NE_FLM_TRUNCATING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Legacy async I/O completion callback
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
FSTATIC void DirectIONoWaitCallBack(
|
|
LONG unknownAlwaysZero,
|
|
LONG callbackData,
|
|
LONG completionCode)
|
|
{
|
|
IF_IOBuffer * pIOBuffer = (IF_IOBuffer *)callbackData;
|
|
|
|
F_UNREFERENCED_PARM( unknownAlwaysZero);
|
|
|
|
pIOBuffer->signalComplete(
|
|
(RCODE)(completionCode == DFSNormalCompletion
|
|
? NE_FLM_OK
|
|
: DfsMapError( completionCode, NE_FLM_DIRECT_WRITING_FILE)));
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: NSS async I/O completion callback
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
FSTATIC void nssDioCallback(
|
|
FLMUINT reserved,
|
|
FLMUINT callbackData,
|
|
FLMUINT completionCode)
|
|
{
|
|
IF_IOBuffer * pIOBuffer = (IF_IOBuffer *)callbackData;
|
|
|
|
F_UNREFERENCED_PARM( reserved);
|
|
|
|
pIOBuffer->signalComplete(
|
|
(RCODE)(completionCode == zOK
|
|
? NE_FLM_OK
|
|
: MapNSSError( completionCode, NE_FLM_DIRECT_WRITING_FILE)));
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Might call the direct IO Write routine in the future
|
|
Note: This routine assumes that the size of pvBuffer is a multiple of
|
|
sector size (512 bytes) and can be used to write out full
|
|
sectors. Even if uiBytesToWrite does not account for full sectors,
|
|
data from the buffer will still be written out - a partial sector
|
|
on disk will not be preserved.
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI F_FileHdl::sectorWrite(
|
|
FLMUINT64 ui64WriteOffset,
|
|
FLMUINT uiBytesToWrite,
|
|
const void * pvBuffer,
|
|
IF_IOBuffer * pBufferObj,
|
|
FLMUINT * puiBytesWrittenRV)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if( m_bDoDirectIO)
|
|
{
|
|
if( RC_BAD( rc = _directIOSectorWrite( (FLMUINT)ui64WriteOffset,
|
|
uiBytesToWrite, pvBuffer, pBufferObj, puiBytesWrittenRV)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flmAssert( !pBufferObj);
|
|
|
|
if( RC_BAD( rc = _write( (FLMUINT)ui64WriteOffset,
|
|
uiBytesToWrite, pvBuffer, puiBytesWrittenRV)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Calls the direct IO-style write routine.
|
|
Note: This routine assumes that the size of pvBuffer is a multiple of
|
|
sector size (512 bytes) and can be used to write out full
|
|
sectors. Even if uiBytesToWrite does not account for full sectors,
|
|
data from the buffer will still be written out - a partial sector
|
|
on disk will not be preserved.
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::_directIOSectorWrite(
|
|
FLMUINT uiWriteOffset,
|
|
FLMUINT uiBytesToWrite,
|
|
const void * pvBuffer,
|
|
IF_IOBuffer * pBufferObj,
|
|
FLMUINT * puiBytesWrittenRV)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LONG lStartSector;
|
|
LONG lSectorCount;
|
|
FLMBOOL bDidAsync = FALSE;
|
|
|
|
flmAssert( m_bFileOpened == TRUE);
|
|
|
|
if (uiWriteOffset == FLM_IO_CURRENT_POS)
|
|
{
|
|
uiWriteOffset = m_uiCurrentPos;
|
|
}
|
|
else
|
|
{
|
|
m_uiCurrentPos = uiWriteOffset;
|
|
}
|
|
|
|
if (uiWriteOffset % FLM_NLM_SECTOR_SIZE != 0)
|
|
{
|
|
rc = write( uiWriteOffset, uiBytesToWrite, pvBuffer,
|
|
puiBytesWrittenRV);
|
|
goto Exit;
|
|
}
|
|
|
|
// Calculate the starting sector and number of sectors to write
|
|
|
|
lStartSector = uiWriteOffset / FLM_NLM_SECTOR_SIZE;
|
|
lSectorCount = (LONG)(uiBytesToWrite / FLM_NLM_SECTOR_SIZE);
|
|
if (uiBytesToWrite % FLM_NLM_SECTOR_SIZE != 0)
|
|
{
|
|
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
|
|
|
|
lSectorCount++;
|
|
|
|
// Zero out the part of the buffer that was not included in
|
|
// uiBytesToWrite - because it will still be written to disk.
|
|
|
|
f_memset( &pucBuffer [uiBytesToWrite], 0,
|
|
(FLMUINT)(FLM_NLM_SECTOR_SIZE - (uiBytesToWrite % FLM_NLM_SECTOR_SIZE)));
|
|
}
|
|
|
|
if( RC_BAD( rc = writeSectors( (void *)pvBuffer, lStartSector, lSectorCount,
|
|
pBufferObj, &bDidAsync)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_uiCurrentPos += uiBytesToWrite;
|
|
|
|
if( puiBytesWrittenRV)
|
|
{
|
|
*puiBytesWrittenRV = uiBytesToWrite;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( !bDidAsync && pBufferObj)
|
|
{
|
|
pBufferObj->notifyComplete( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE F_FileHdl::flush( void)
|
|
{
|
|
return( NE_FLM_OK);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
FLMBOOL F_FileHdl::canDoAsync( void)
|
|
{
|
|
return( m_bDoDirectIO);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI F_FileHdl::lock( void)
|
|
{
|
|
return( RC_SET_AND_ASSERT( NE_FLM_NOT_IMPLEMENTED));
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI F_FileHdl::unlock( void)
|
|
{
|
|
return( RC_SET_AND_ASSERT( NE_FLM_NOT_IMPLEMENTED));
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Determine if a file or directory exists
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE f_netwareTestIfFileExists(
|
|
const char * pPath)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LONG unused;
|
|
FLMBYTE ucPseudoLNamePath[ F_PATH_MAX_SIZE + 1];
|
|
FLMBYTE ucLNamePath[ F_PATH_MAX_SIZE];
|
|
LONG lVolumeID;
|
|
LONG lPathID;
|
|
LONG lLNamePathCount;
|
|
LONG lDirectoryID;
|
|
LONG lErrorCode;
|
|
|
|
f_strcpy( (char *)&ucPseudoLNamePath[1], pPath);
|
|
ucPseudoLNamePath[0] = (char)f_strlen( pPath);
|
|
|
|
if( (lErrorCode = ConvertPathString( 0, 0, ucPseudoLNamePath, &lVolumeID,
|
|
&lPathID, ucLNamePath, &lLNamePathCount)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (lErrorCode = MapPathToDirectoryNumber( 0, lVolumeID, 0, ucLNamePath,
|
|
lLNamePathCount, LONGNameSpace, &lDirectoryID, &unused)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( lErrorCode == 255 || lErrorCode == 156)
|
|
{
|
|
// Too many error codes map to 255, so we put in a special
|
|
// case check here
|
|
|
|
rc = RC_SET( NE_FLM_IO_PATH_NOT_FOUND);
|
|
}
|
|
else if( lErrorCode )
|
|
{
|
|
rc = f_mapPlatformError( lErrorCode, NE_FLM_CHECKING_FILE_EXISTENCE);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Delete a file
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE f_netwareDeleteFile(
|
|
const char * pPath)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LONG lErrorCode;
|
|
char pszQualifiedPath[ F_PATH_MAX_SIZE];
|
|
FLMBYTE ucLNamePath[ F_PATH_MAX_SIZE + 1];
|
|
LONG lLNamePathCount;
|
|
LONG lVolumeID;
|
|
FLMBOOL bNssVolume = FALSE;
|
|
|
|
ConvertToQualifiedNWPath( pPath, pszQualifiedPath);
|
|
|
|
if( (lErrorCode = ConvertPathToLNameFormat( pszQualifiedPath, &lVolumeID,
|
|
&bNssVolume, ucLNamePath, &lLNamePathCount)) != 0)
|
|
{
|
|
rc = f_mapPlatformError( lErrorCode, NE_FLM_RENAMING_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
if( gv_bNSSKeyInitialized && bNssVolume)
|
|
{
|
|
if( (lErrorCode = gv_zDeleteFunc( gv_NssRootKey, 0,
|
|
zNSPACE_LONG | zMODE_UTF8,
|
|
pszQualifiedPath, zMATCH_ALL, 0)) != zOK)
|
|
{
|
|
rc = MapNSSError( lErrorCode, NE_FLM_IO_DELETING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( (lErrorCode = EraseFile( 0, 1, lVolumeID, 0, ucLNamePath,
|
|
lLNamePathCount, LONGNameSpace, 0)) != 0)
|
|
{
|
|
// Too many error codes map to 255, so we put in a special
|
|
// case check here.
|
|
|
|
if( lErrorCode == 255)
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_PATH_NOT_FOUND);
|
|
}
|
|
else
|
|
{
|
|
rc = f_mapPlatformError( lErrorCode, NE_FLM_IO_DELETING_FILE);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Turn off the rename inhibit bit for a file in an NSS volume.
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
FSTATIC RCODE nssTurnOffRenameInhibit(
|
|
const char * pszFileName)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
zInfo_s Info;
|
|
FLMINT64 NssKey;
|
|
FLMBOOL bFileOpened = FALSE;
|
|
FLMINT lStatus;
|
|
FLMUINT nOpenAttr;
|
|
|
|
nOpenAttr = f_getNSSOpenFlags( (FLMUINT)(FLM_IO_RDWR |
|
|
FLM_IO_SH_DENYNONE), FALSE);
|
|
|
|
if( (lStatus = gv_zOpenFunc( gv_NssRootKey, 1, zNSPACE_LONG | zMODE_UTF8,
|
|
pszFileName, nOpenAttr, &NssKey)) != zOK)
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_OPENING_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
bFileOpened = TRUE;
|
|
|
|
// Get the file attributes.
|
|
|
|
if( (lStatus = gv_zGetInfoFunc( NssKey, zGET_STD_INFO, sizeof( Info),
|
|
zINFO_VERSION_A, &Info)) != zOK)
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_GETTING_FILE_INFO);
|
|
goto Exit;
|
|
}
|
|
|
|
flmAssert( Info.infoVersion == zINFO_VERSION_A);
|
|
|
|
// See if the rename inhibit bit is set.
|
|
|
|
if( Info.std.fileAttributes & zFA_RENAME_INHIBIT)
|
|
{
|
|
// Turn bit off
|
|
|
|
Info.std.fileAttributes = 0;
|
|
|
|
// Specify which bits to modify - only rename inhibit in this case
|
|
|
|
Info.std.fileAttributesModMask = zFA_RENAME_INHIBIT;
|
|
|
|
if( (lStatus = gv_zModifyInfoFunc( NssKey, 0, zMOD_FILE_ATTRIBUTES,
|
|
sizeof( Info), zINFO_VERSION_A, &Info)) != zOK)
|
|
{
|
|
rc = MapNSSError( lStatus, NE_FLM_SETTING_FILE_INFO);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bFileOpened)
|
|
{
|
|
(void)gv_zCloseFunc( NssKey);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Rename a file
|
|
Notes: Currently, this function doesn't support moving the file from one
|
|
volume to another. (There is a CopyFileToFile function that could
|
|
be used to do the move.) The toolkit function does appear to
|
|
support moving (copy/delete) the file.
|
|
|
|
This function does support renaming directories.
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE f_netwareRenameFile(
|
|
const char * pOldFilePath,
|
|
const char * pNewFilePath)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
LONG unused;
|
|
FLMBYTE ucOldLNamePath[ F_PATH_MAX_SIZE + 1];
|
|
LONG lOldLNamePathCount;
|
|
FLMBYTE ucNewLNamePath[ F_PATH_MAX_SIZE + 1];
|
|
LONG lNewLNamePathCount;
|
|
LONG lVolumeID;
|
|
LONG lErrorCode;
|
|
FLMBYTE ucPseudoLNamePath[ F_PATH_MAX_SIZE + 1];
|
|
LONG lPathID;
|
|
LONG lIsFile;
|
|
FLMBOOL bIsDirectory;
|
|
struct ModifyStructure modifyStruct;
|
|
LONG lDirectoryID;
|
|
LONG lFileAttributes;
|
|
LONG lMatchBits;
|
|
FLMBOOL bNssVolume =
|
|
(FLMBOOL)(gv_zIsNSSVolumeFunc
|
|
? (gv_zIsNSSVolumeFunc( (const char *)pOldFilePath)
|
|
? TRUE
|
|
: FALSE)
|
|
: FALSE);
|
|
|
|
if( gv_bNSSKeyInitialized && bNssVolume)
|
|
{
|
|
FLMINT lStatus;
|
|
FLMBOOL bTurnedOffRenameInhibit = FALSE;
|
|
|
|
Retry_Nss_Rename:
|
|
|
|
if( (lStatus = gv_zRenameFunc( gv_NssRootKey, 0,
|
|
zNSPACE_LONG | zMODE_UTF8, pOldFilePath, zMATCH_ALL,
|
|
zNSPACE_LONG | zMODE_UTF8, pNewFilePath, 0)) != zOK)
|
|
{
|
|
if( lStatus == zERR_NO_RENAME_PRIVILEGE && !bTurnedOffRenameInhibit)
|
|
{
|
|
// Attempt to turn off rename inhibit. This isn't always the
|
|
// reason for zERR_NO_RENAME_PRIVILEGE, but it is one we
|
|
// definitely need to take care of.
|
|
|
|
if( RC_BAD( rc = nssTurnOffRenameInhibit( pOldFilePath)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bTurnedOffRenameInhibit = TRUE;
|
|
goto Retry_Nss_Rename;
|
|
}
|
|
|
|
rc = MapNSSError( lStatus, NE_FLM_RENAMING_FILE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
f_strcpy( (char *)&ucPseudoLNamePath[1], pOldFilePath);
|
|
ucPseudoLNamePath[0] = (char)f_strlen( (const char *)&ucPseudoLNamePath[1] );
|
|
|
|
if( (lErrorCode = ConvertPathString( 0, 0, ucPseudoLNamePath, &lVolumeID,
|
|
&lPathID, (BYTE *)ucOldLNamePath, &lOldLNamePathCount)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (lErrorCode = MapPathToDirectoryNumber( 0, lVolumeID, 0,
|
|
(BYTE *)ucOldLNamePath, lOldLNamePathCount, LONGNameSpace,
|
|
&lDirectoryID, &lIsFile)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( lIsFile)
|
|
{
|
|
bIsDirectory = FALSE;
|
|
lMatchBits = 0;
|
|
}
|
|
else
|
|
{
|
|
bIsDirectory = TRUE;
|
|
lMatchBits = SUBDIRECTORY_BIT;
|
|
}
|
|
|
|
f_strcpy( (char *)&ucPseudoLNamePath[1], pNewFilePath);
|
|
ucPseudoLNamePath[0] = (char)f_strlen( (const char *)&ucPseudoLNamePath[1]);
|
|
|
|
if( (lErrorCode = ConvertPathString( 0, 0, ucPseudoLNamePath, &unused,
|
|
&lPathID, (BYTE *)ucNewLNamePath, &lNewLNamePathCount)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
{
|
|
struct DirectoryStructure * pFileInfo;
|
|
|
|
if( (lErrorCode = VMGetDirectoryEntry( lVolumeID,
|
|
lDirectoryID & 0x00ffffff, &pFileInfo)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
lFileAttributes = pFileInfo->DFileAttributes;
|
|
}
|
|
|
|
if( lFileAttributes & RENAME_INHIBIT_BIT )
|
|
{
|
|
f_memset(&modifyStruct, 0, sizeof(modifyStruct));
|
|
modifyStruct.MFileAttributesMask = RENAME_INHIBIT_BIT;
|
|
|
|
if( (lErrorCode = ModifyDirectoryEntry( 0, 1, lVolumeID, 0,
|
|
(BYTE *)ucOldLNamePath, lOldLNamePathCount, LONGNameSpace,
|
|
lMatchBits, LONGNameSpace, &modifyStruct,
|
|
MFileAttributesBit, 0)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
lErrorCode = RenameEntry( 0, 1, lVolumeID, 0, ucOldLNamePath,
|
|
lOldLNamePathCount, LONGNameSpace, lMatchBits,
|
|
(BYTE)bIsDirectory ? 1 : 0, 0, ucNewLNamePath, lNewLNamePathCount,
|
|
TRUE, TRUE);
|
|
|
|
if( lFileAttributes & RENAME_INHIBIT_BIT )
|
|
{
|
|
FLMBYTE * pFileName;
|
|
|
|
if( lErrorCode )
|
|
{
|
|
pFileName = ucOldLNamePath;
|
|
lNewLNamePathCount = lOldLNamePathCount;
|
|
}
|
|
else
|
|
{
|
|
pFileName = ucNewLNamePath;
|
|
}
|
|
|
|
// Turn the RENAME_INHIBIT_BIT back on
|
|
|
|
f_memset(&modifyStruct, 0, sizeof(modifyStruct));
|
|
modifyStruct.MFileAttributes = RENAME_INHIBIT_BIT;
|
|
modifyStruct.MFileAttributesMask = RENAME_INHIBIT_BIT;
|
|
|
|
(void)ModifyDirectoryEntry( 0, 1, lVolumeID, 0, (BYTE *)pFileName,
|
|
lNewLNamePathCount, LONGNameSpace, lMatchBits, LONGNameSpace,
|
|
&modifyStruct, MFileAttributesBit, 0);
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( !gv_bNSSKeyInitialized || !bNssVolume)
|
|
{
|
|
if( lErrorCode )
|
|
{
|
|
// Too many error codes map to 255, so we put in a special
|
|
// case check here.
|
|
|
|
if( lErrorCode == 255)
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_PATH_NOT_FOUND);
|
|
}
|
|
else
|
|
{
|
|
rc = f_mapPlatformError( lErrorCode, NE_FLM_RENAMING_FILE);
|
|
}
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Convert the given path to NetWare LName format.
|
|
Input: pPath = qualified netware path of the format:
|
|
volume:directory_1\...\directory_n\filename.ext
|
|
Output: plVolumeID = NetWare volume ID
|
|
pLNamePath = NetWare LName format path
|
|
|
|
Netware expects paths to be in LName format:
|
|
<L1><C1><L2><C2>...<Ln><Cn>
|
|
where <Lx> is a one-byte length and <Cx> is a path component.
|
|
|
|
Example: 6SYSTEM4Fred
|
|
note that the 6 and 4 are binary, not ASCII
|
|
|
|
plLNamePathCount = number of path components in pLNamePath
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
FSTATIC LONG ConvertPathToLNameFormat(
|
|
const char * pPath,
|
|
LONG * plVolumeID,
|
|
FLMBOOL * pbNssVolume,
|
|
FLMBYTE * pLNamePath,
|
|
LONG * plLNamePathCount)
|
|
{
|
|
FLMBYTE ucPseudoLNamePath[ F_PATH_MAX_SIZE + 1];
|
|
LONG lPathID;
|
|
LONG lErrorCode = 0;
|
|
|
|
*pLNamePath = 0;
|
|
*plLNamePathCount = 0;
|
|
|
|
*pbNssVolume = (FLMBOOL)(gv_zIsNSSVolumeFunc
|
|
? (gv_zIsNSSVolumeFunc( (const char *)pPath)
|
|
? TRUE
|
|
: FALSE)
|
|
: FALSE);
|
|
|
|
if( gv_bNSSKeyInitialized && *pbNssVolume)
|
|
{
|
|
f_strcpy( (char *)pLNamePath, pPath);
|
|
*plLNamePathCount = 1;
|
|
}
|
|
else
|
|
{
|
|
f_strcpy( (char *)&ucPseudoLNamePath[1], pPath);
|
|
ucPseudoLNamePath[0] = (FLMBYTE)f_strlen( (const char *)&ucPseudoLNamePath[1]);
|
|
|
|
if( (lErrorCode = ConvertPathString( 0, 0, ucPseudoLNamePath, plVolumeID,
|
|
&lPathID, (BYTE *)pLNamePath, plLNamePathCount)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( lErrorCode );
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Convert the given path to a NetWare format. The format isn't
|
|
critical, it just needs to be consistent. See below for a
|
|
description of the format chosen.
|
|
Input: pInputPath = a path to a file
|
|
Output: pszQualifiedPath = qualified netware path of the format:
|
|
volume:directory_1\...\directory_n\filename.ext
|
|
|
|
If no volume is given, "SYS:" is the default.
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
FSTATIC void ConvertToQualifiedNWPath(
|
|
const char * pInputPath,
|
|
char * pszQualifiedPath)
|
|
{
|
|
char ucFileName [F_FILENAME_SIZE];
|
|
char ucVolume [MAX_NETWARE_VOLUME_NAME+1];
|
|
char ucPath [F_PATH_MAX_SIZE + 1];
|
|
IF_FileSystem * pFileSystem = f_getFileSysPtr();
|
|
|
|
// Separate path into its components: volume, path...
|
|
|
|
pFileSystem->pathParse( pInputPath, NULL, ucVolume, ucPath, ucFileName);
|
|
|
|
// Rebuild path to a standard, fully-qualified format, defaulting the
|
|
// volume if one isn't specified.
|
|
|
|
*pszQualifiedPath = 0;
|
|
if( ucVolume [0])
|
|
{
|
|
// Append the volume specified by the user.
|
|
|
|
f_strcat( pszQualifiedPath, ucVolume );
|
|
}
|
|
else
|
|
{
|
|
// No volume specified, use the default
|
|
|
|
f_strcat( pszQualifiedPath, "SYS:");
|
|
}
|
|
|
|
if( ucPath [0])
|
|
{
|
|
// User specified a path...
|
|
|
|
if( ucPath[0] == '\\' || ucPath[0] == '/' )
|
|
{
|
|
// Append the path to the volume without the leading slash
|
|
|
|
f_strcat( pszQualifiedPath, &ucPath [1]);
|
|
}
|
|
else
|
|
{
|
|
// Append the path to the volume
|
|
|
|
f_strcat( pszQualifiedPath, ucPath);
|
|
}
|
|
}
|
|
|
|
if( ucFileName [0])
|
|
{
|
|
// Append the file name to the path
|
|
|
|
pFileSystem->pathAppend( pszQualifiedPath, ucFileName);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
void FLMAPI f_yieldCPU( void)
|
|
{
|
|
kYieldIfTimeSliceUp();
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Function that must be called within a NLM's startup routine.
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE f_netwareStartup( void)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if( f_atomicInc( &gv_NetWareStartupCount) != 1)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
gv_MyModuleHandle = CFindLoadModuleHandle( (void *)f_netwareShutdown);
|
|
|
|
// Allocate the needed resource tags
|
|
|
|
if( (gv_lAllocRTag = AllocateResourceTag( gv_MyModuleHandle,
|
|
"FLAIM Memory", AllocSignature)) == NULL)
|
|
{
|
|
rc = RC_SET( NE_FLM_MEM);
|
|
goto Exit;
|
|
}
|
|
|
|
// Initialize NSS
|
|
|
|
if( RC_BAD( rc = f_nssInitialize()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
f_netwareShutdown();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Closes (Frees) any resources used by FLAIM's clib patches layer.
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
void f_netwareShutdown( void)
|
|
{
|
|
// Call exit function.
|
|
|
|
if( f_atomicDec( &gv_NetWareStartupCount) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_nssUninitialize();
|
|
|
|
if( gv_lAllocRTag)
|
|
{
|
|
ReturnResourceTag( gv_lAllocRTag, 1);
|
|
gv_lAllocRTag = 0;
|
|
}
|
|
|
|
gv_MyModuleHandle = NULL;
|
|
|
|
Exit:
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
void * f_getNLMHandle( void)
|
|
{
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
return( gv_MyModuleHandle);
|
|
#else
|
|
return( getnlmhandle());
|
|
#endif
|
|
}
|
|
|
|
/**********************************************************************
|
|
Desc:
|
|
**********************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI f_chdir(
|
|
const char * pszDir)
|
|
{
|
|
F_UNREFERENCED_PARM( pszDir);
|
|
return( RC_SET( NE_FLM_NOT_IMPLEMENTED));
|
|
}
|
|
#endif
|
|
|
|
/**********************************************************************
|
|
Desc:
|
|
**********************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
RCODE FLMAPI f_getcwd(
|
|
char * pszDir)
|
|
{
|
|
*pszDir = NULL;
|
|
return( RC_SET( NE_FLM_NOT_IMPLEMENTED));
|
|
}
|
|
#endif
|
|
|
|
|
|
/**********************************************************************
|
|
Desc:
|
|
**********************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
extern "C" void f_fatalRuntimeError( void)
|
|
{
|
|
EnterDebugger();
|
|
}
|
|
#endif
|
|
|
|
/********************************************************************
|
|
Desc: Startup routine for the NLM - that gets the main going in
|
|
its own thread.
|
|
*********************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
extern "C" void * f_nlmMainStub(
|
|
void * hThread,
|
|
void * pData)
|
|
{
|
|
ARG_DATA * pArgData = (ARG_DATA *)pData;
|
|
struct LoadDefinitionStructure * moduleHandle = pArgData->moduleHandle;
|
|
|
|
(void)hThread;
|
|
|
|
(void)kSetThreadName( (void *)kCurrentThread(),
|
|
(BYTE *)pArgData->pszThreadName);
|
|
|
|
nlm_main( pArgData->iArgC, pArgData->ppszArgV);
|
|
|
|
Free( pArgData->ppszArgV);
|
|
Free( pArgData->pszArgs);
|
|
Free( pArgData->pszThreadName);
|
|
Free( pArgData);
|
|
|
|
gv_bMainRunning = FALSE;
|
|
|
|
if( !gv_bUnloadCalled)
|
|
{
|
|
KillMe( moduleHandle);
|
|
}
|
|
|
|
kExitThread( NULL);
|
|
return( NULL);
|
|
}
|
|
#endif
|
|
|
|
/********************************************************************
|
|
Desc: Signals the f_nlmEntryPoint thread to release the console.
|
|
*********************************************************************/
|
|
void SynchronizeStart( void)
|
|
{
|
|
if (gv_lFlmSyncSem)
|
|
{
|
|
(void)kSemaphoreSignal( gv_lFlmSyncSem);
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
Desc: Startup routine for the NLM.
|
|
*********************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
extern "C" LONG f_nlmEntryPoint(
|
|
struct LoadDefinitionStructure * moduleHandle,
|
|
struct ScreenStruct * initScreen,
|
|
char * commandLine,
|
|
char * loadDirectoryPath,
|
|
LONG uninitializedDataLength,
|
|
LONG fileHandle,
|
|
LONG (*ReadRoutine)
|
|
(LONG handle,
|
|
LONG offset,
|
|
char * buffer,
|
|
LONG length),
|
|
LONG customDataOffset,
|
|
LONG customDataSize)
|
|
{
|
|
char * pszTmp;
|
|
char * pszArgStart;
|
|
int iArgC;
|
|
int iTotalArgChars;
|
|
int iArgSize;
|
|
char ** ppszArgV = NULL;
|
|
char * pszArgs = NULL;
|
|
char * pszDestArg;
|
|
bool bFirstPass = true;
|
|
char cEnd;
|
|
ARG_DATA * pArgData = NULL;
|
|
LONG sdRet = 0;
|
|
char * pszThreadName;
|
|
char * pszModuleName;
|
|
int iModuleNameLen;
|
|
int iThreadNameLen;
|
|
int iLoadDirPathSize;
|
|
void * hThread = NULL;
|
|
|
|
(void)initScreen;
|
|
(void)uninitializedDataLength;
|
|
(void)fileHandle;
|
|
(void)ReadRoutine;
|
|
(void)customDataOffset;
|
|
(void)customDataSize;
|
|
|
|
if( f_atomicInc( &gv_NetWareStartupCount) != 1)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
gv_MyModuleHandle = moduleHandle;
|
|
gv_bUnloadCalled = FALSE;
|
|
|
|
// Allocate the needed resource tags
|
|
|
|
if( (gv_lAllocRTag = AllocateResourceTag( gv_MyModuleHandle,
|
|
"FLAIM Memory", AllocSignature)) == NULL)
|
|
{
|
|
sdRet = 1;
|
|
goto Exit;
|
|
}
|
|
|
|
// Syncronized start
|
|
|
|
if (moduleHandle->LDFlags & 4)
|
|
{
|
|
gv_lFlmSyncSem = kSemaphoreAlloc( (BYTE *)"FLAIM_SYNC", 0);
|
|
}
|
|
|
|
// Initialize NSS
|
|
|
|
if( RC_BAD( f_nssInitialize()))
|
|
{
|
|
sdRet = 1;
|
|
goto Exit;
|
|
}
|
|
|
|
pszModuleName = (char *)(&moduleHandle->LDFileName[ 1]);
|
|
iModuleNameLen = (int)(moduleHandle->LDFileName[ 0]);
|
|
|
|
// First pass: Count the arguments in the command line
|
|
// and determine how big of a buffer we will need.
|
|
// Second pass: Put argments into allocated buffer.
|
|
|
|
Parse_Args:
|
|
|
|
iTotalArgChars = 0;
|
|
iArgC = 0;
|
|
|
|
iLoadDirPathSize = f_strlen( (const char *)loadDirectoryPath);
|
|
iArgSize = iLoadDirPathSize + iModuleNameLen;
|
|
|
|
if( !bFirstPass)
|
|
{
|
|
ppszArgV[ iArgC] = pszDestArg;
|
|
f_memcpy( pszDestArg, loadDirectoryPath, iLoadDirPathSize);
|
|
f_memcpy( &pszDestArg[ iLoadDirPathSize], pszModuleName, iModuleNameLen);
|
|
pszDestArg[ iArgSize] = 0;
|
|
pszDestArg += (iArgSize + 1);
|
|
}
|
|
|
|
iArgC++;
|
|
iTotalArgChars += iArgSize;
|
|
pszTmp = commandLine;
|
|
|
|
for (;;)
|
|
{
|
|
// Skip leading blanks.
|
|
|
|
while( *pszTmp && *pszTmp == ' ')
|
|
{
|
|
pszTmp++;
|
|
}
|
|
|
|
if( *pszTmp == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( *pszTmp == '"' || *pszTmp == '\'')
|
|
{
|
|
cEnd = *pszTmp;
|
|
pszTmp++;
|
|
}
|
|
else
|
|
{
|
|
cEnd = ' ';
|
|
}
|
|
|
|
pszArgStart = pszTmp;
|
|
iArgSize = 0;
|
|
|
|
// Count the characters in the parameter.
|
|
|
|
while( *pszTmp && *pszTmp != cEnd)
|
|
{
|
|
iArgSize++;
|
|
pszTmp++;
|
|
}
|
|
|
|
if( !iArgSize && cEnd == ' ')
|
|
{
|
|
break;
|
|
}
|
|
|
|
// If 2nd pass, save the argument.
|
|
|
|
if( !bFirstPass)
|
|
{
|
|
ppszArgV[ iArgC] = pszDestArg;
|
|
|
|
if( iArgSize)
|
|
{
|
|
f_memcpy( pszDestArg, pszArgStart, iArgSize);
|
|
}
|
|
|
|
pszDestArg[ iArgSize] = 0;
|
|
pszDestArg += (iArgSize + 1);
|
|
}
|
|
|
|
iArgC++;
|
|
iTotalArgChars += iArgSize;
|
|
|
|
// Skip trailing quote or blank.
|
|
|
|
if( *pszTmp)
|
|
{
|
|
pszTmp++;
|
|
}
|
|
}
|
|
|
|
if( bFirstPass)
|
|
{
|
|
if ((ppszArgV = (char **)Alloc( sizeof( char *) * iArgC,
|
|
gv_lAllocRTag)) == NULL)
|
|
{
|
|
sdRet = 1;
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pszArgs = (char *)Alloc( iTotalArgChars + iArgC,
|
|
gv_lAllocRTag)) == NULL)
|
|
{
|
|
sdRet = 1;
|
|
goto Exit;
|
|
}
|
|
|
|
pszDestArg = pszArgs;
|
|
bFirstPass = false;
|
|
goto Parse_Args;
|
|
}
|
|
|
|
iThreadNameLen = (int)(moduleHandle->LDName[ 0]);
|
|
|
|
if( (pszThreadName = (char *)Alloc( iThreadNameLen + 1, gv_lAllocRTag)) == NULL)
|
|
{
|
|
sdRet = 1;
|
|
goto Exit;
|
|
}
|
|
|
|
f_memcpy( pszThreadName, (char *)(&moduleHandle->LDName[ 1]), iThreadNameLen);
|
|
pszThreadName[ iThreadNameLen] = 0;
|
|
|
|
if( (pArgData = (ARG_DATA *)Alloc( sizeof( ARG_DATA),
|
|
gv_lAllocRTag)) == NULL)
|
|
{
|
|
sdRet = 1;
|
|
goto Exit;
|
|
}
|
|
|
|
pArgData->ppszArgV = ppszArgV;
|
|
pArgData->pszArgs = pszArgs;
|
|
pArgData->iArgC = iArgC;
|
|
pArgData->moduleHandle = moduleHandle;
|
|
pArgData->pszThreadName = pszThreadName;
|
|
|
|
gv_bMainRunning = TRUE;
|
|
|
|
if( (hThread = kCreateThread( (BYTE *)"FTK main",
|
|
f_nlmMainStub, NULL, 32768, (void *)pArgData)) == NULL)
|
|
{
|
|
gv_bMainRunning = FALSE;
|
|
sdRet = 2;
|
|
goto Exit;
|
|
}
|
|
|
|
if( kSetThreadLoadHandle( hThread, (LONG)moduleHandle) != 0)
|
|
{
|
|
(void)kDestroyThread( hThread);
|
|
gv_bMainRunning = FALSE;
|
|
sdRet = 2;
|
|
goto Exit;
|
|
}
|
|
|
|
if( kScheduleThread( hThread) != 0)
|
|
{
|
|
(void)kDestroyThread( hThread);
|
|
gv_bMainRunning = FALSE;
|
|
sdRet = 2;
|
|
goto Exit;
|
|
}
|
|
|
|
// Synchronized start
|
|
|
|
if( moduleHandle->LDFlags & 4)
|
|
{
|
|
(void)kSemaphoreWait( gv_lFlmSyncSem);
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( sdRet != 0)
|
|
{
|
|
f_atomicDec( &gv_NetWareStartupCount);
|
|
|
|
if( ppszArgV)
|
|
{
|
|
Free( ppszArgV);
|
|
}
|
|
|
|
if( pszArgs)
|
|
{
|
|
Free( pszArgs);
|
|
}
|
|
|
|
if( pszThreadName)
|
|
{
|
|
Free( pszThreadName);
|
|
}
|
|
|
|
if( pArgData)
|
|
{
|
|
Free( pArgData);
|
|
}
|
|
|
|
if( gv_lFlmSyncSem)
|
|
{
|
|
kSemaphoreFree( gv_lFlmSyncSem);
|
|
gv_lFlmSyncSem = 0;
|
|
}
|
|
|
|
if( !gv_bUnloadCalled)
|
|
{
|
|
KillMe( moduleHandle);
|
|
}
|
|
}
|
|
|
|
return( sdRet);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
extern "C" void f_nlmExitPoint(void)
|
|
{
|
|
if( f_atomicDec( &gv_NetWareStartupCount) > 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
gv_bUnloadCalled = TRUE;
|
|
|
|
if( gv_fnExit)
|
|
{
|
|
(*gv_fnExit)();
|
|
gv_fnExit = NULL;
|
|
}
|
|
|
|
while( gv_bMainRunning)
|
|
{
|
|
kYieldThread();
|
|
}
|
|
|
|
f_nssUninitialize();
|
|
|
|
if( gv_lFlmSyncSem)
|
|
{
|
|
kSemaphoreFree( gv_lFlmSyncSem);
|
|
gv_lFlmSyncSem = 0;
|
|
}
|
|
|
|
if( gv_lAllocRTag)
|
|
{
|
|
ReturnResourceTag( gv_lAllocRTag, 1);
|
|
gv_lAllocRTag = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
extern "C" void exit(
|
|
int exitCode)
|
|
{
|
|
(void)exitCode;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#if defined( FLM_RING_ZERO_NLM)
|
|
extern "C" int atexit(
|
|
F_EXIT_FUNC fnExit)
|
|
{
|
|
gv_fnExit = fnExit;
|
|
return( 0);
|
|
}
|
|
#endif
|
|
|
|
#endif // FLM_NLM
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#if defined( FLM_OSX)
|
|
void gv_fnlm()
|
|
{
|
|
}
|
|
#endif
|