blob: 2aa852b1a18096a1f6141049a9746247bae99878 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define CDEV_CURRENT_FUNCTION _comment_
/**
* @file
* @ingroup Port
* @brief file
*/
#undef CDEV_CURRENT_FUNCTION
#include <windows.h>
#include <sys/stat.h>
#include <time.h>
#include "hyport.h"
#include "portpriv.h"
#include "hystdarg.h"
#include "portnls.h"
#include "ut_hyprt.h"
#define CDEV_CURRENT_FUNCTION _prototypes_private
static I_32 findError (I_32 errorCode);
void convert_path_to_unicode(struct HyPortLibrary * portLibrary, const char *path,
wchar_t **pathW);
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION findError
/**
* @internal
* Determines the proper portable error code to return given a native error code
*
* @param[in] errorCode The error code reported by the OS
*
* @return the (negative) portable error code
*/
static I_32
findError (I_32 errorCode)
{
switch (errorCode)
{
case ERROR_FILENAME_EXCED_RANGE:
return HYPORT_ERROR_FILE_NAMETOOLONG;
case ERROR_ACCESS_DENIED:
return HYPORT_ERROR_FILE_NOPERMISSION;
case ERROR_FILE_NOT_FOUND:
return HYPORT_ERROR_FILE_NOTFOUND;
case ERROR_DISK_FULL:
return HYPORT_ERROR_FILE_DISKFULL;
case ERROR_FILE_EXISTS:
case ERROR_ALREADY_EXISTS:
return HYPORT_ERROR_FILE_EXIST;
case ERROR_NOT_ENOUGH_MEMORY:
return HYPORT_ERROR_FILE_SYSTEMFULL;
case ERROR_LOCK_VIOLATION:
return HYPORT_ERROR_FILE_LOCKED;
default:
return HYPORT_ERROR_FILE_OPFAILED;
}
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_attr
/**
* Determine whether path is a file or directory.
*
* @param[in] portLibrary The port library
* @param[in] path file/path name being queried.
*
* @return EslsFile if a file, EslsDir if a directory, negative portable error code on failure.
*/
I_32 VMCALL
hyfile_attr (struct HyPortLibrary * portLibrary, const char *path)
{
DWORD result;
wchar_t *pathW;
convert_path_to_unicode(portLibrary, path, &pathW);
result = GetFileAttributesW ((LPCWSTR) pathW);
portLibrary->mem_free_memory(portLibrary, pathW);
if (result == 0xFFFFFFFF)
{
result = GetLastError ();
return portLibrary->error_set_last_error (portLibrary, result,
findError (result));
}
if (result & FILE_ATTRIBUTE_DIRECTORY)
{
return HyIsDir;
}
/* otherwise assume it's a normal file */
return HyIsFile;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_close
/**
* Closes a file descriptor.
*
* @param[in] portLibrary The port library
* @param[in] fd The file descriptor.
*
* @return 0 on success, -1 on failure.
* @internal @todo return negative portable return code on failure.
*/
I_32 VMCALL
hyfile_close (struct HyPortLibrary * portLibrary, IDATA fd)
{
if (CloseHandle ((HANDLE) fd))
{
return 0;
}
else
{
I_32 error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
return -1;
}
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_error_message
/**
* Return an error message describing the last OS error that occurred. The last
* error returned is not thread safe, it may not be related to the operation that
* failed for this thread.
*
* @param[in] portLibrary The port library
*
* @return error message describing the last OS error, may return NULL.
*
* @internal
* @note This function gets the last error code from the OS and then returns
* the corresponding string. It is here as a helper function for JCL. Once hyerror
* is integrated into the port library this function should probably disappear.
*/
const char *VMCALL
hyfile_error_message (struct HyPortLibrary *portLibrary)
{
return portLibrary->error_last_error_message (portLibrary);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_findclose
/**
* Close the handle returned from @ref hyfile_findfirst.
*
* @param[in] portLibrary The port library
* @param[in] findhandle Handle returned from @ref hyfile_findfirst.
*/
void VMCALL
hyfile_findclose (struct HyPortLibrary *portLibrary, UDATA findhandle)
{
if (0 == FindClose ((HANDLE) findhandle))
{
I_32 error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
}
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_findfirst
/**
* Find the first occurrence of a file identified by path. Answers a handle
* to be used in subsequent calls to @ref hyfile_findnext and @ref hyfile_findclose.
*
* @param[in] portLibrary The port library
* @param[in] path file/path name being queried.
* @param[out] resultbuf filename and path matching path.
*
* @return valid handle on success, -1 on failure.
*/
UDATA VMCALL
hyfile_findfirst (struct HyPortLibrary *portLibrary, const char *path,
char *resultbuf)
{
WIN32_FIND_DATAW lpFindFileDataW;
char newPath[HyMaxPath];
HANDLE result;
wchar_t *pathW;
strcpy (newPath, path);
strcat (newPath, "*");
convert_path_to_unicode(portLibrary, newPath, &pathW);
result = FindFirstFileW ((LPCWSTR) pathW, &lpFindFileDataW);
portLibrary->mem_free_memory(portLibrary, pathW);
if (result == INVALID_HANDLE_VALUE)
{
I_32 error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
return (UDATA) - 1;
}
WideCharToMultiByte(CP_UTF8, 0, lpFindFileDataW.cFileName, -1, resultbuf, HyMaxPath, NULL, NULL);
return (UDATA) result;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_findnext
/**
* Find the next filename and path matching a given handle.
*
* @param[in] portLibrary The port library
* @param[in] findhandle handle returned from @ref hyfile_findfirst.
* @param[out] resultbuf next filename and path matching findhandle.
*
* @return 0 on success, -1 on failure or if no matching entries.
* @internal @todo return negative portable return code on failure.
*/
I_32 VMCALL
hyfile_findnext (struct HyPortLibrary * portLibrary, UDATA findhandle,
char *resultbuf)
{
WIN32_FIND_DATAW lpFindFileDataW;
if (!FindNextFileW ((HANDLE) findhandle, &lpFindFileDataW))
{
I_32 error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
return -1;
}
WideCharToMultiByte(CP_UTF8, 0, lpFindFileDataW.cFileName, -1, resultbuf, HyMaxPath, NULL, NULL);
return 0;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_lastmod
/**
* Return the last modification time of the file path in milliseconds.
*
* @param[in] portLibrary The port library
* @param[in] path file/path name being queried.
*
* @return last modification time on success, -1 on failure.
*/
I_64 VMCALL
hyfile_lastmod (struct HyPortLibrary * portLibrary, const char *path)
{
FILETIME lastWriteTime;
HANDLE newHandle;
I_64 result, tempResult;
I_32 error;
wchar_t *pathW;
convert_path_to_unicode(portLibrary, path, &pathW);
newHandle = CreateFileW(pathW, FILE_READ_ATTRIBUTES,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
portLibrary->mem_free_memory(portLibrary, pathW);
if (newHandle == INVALID_HANDLE_VALUE)
{
error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
return -1;
}
if (0 == GetFileTime(newHandle, NULL, NULL, &lastWriteTime)) {
error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
return -1;
}
/*
* Search MSDN for 'Converting a time_t Value to a File Time' for following implementation.
*/
tempResult =
((I_64) lastWriteTime.dwHighDateTime << (I_64) 32) | (I_64) lastWriteTime.dwLowDateTime;
result = (tempResult - 116444736000000000) / 10000;
if (0 == CloseHandle (newHandle))
{
error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error, findError (error)); /* continue */
}
return result;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_length
/**
* Answer the length in bytes of the file.
*
* @param[in] portLibrary The port library
* @param[in] path file/path name being queried.
*
* @return Length in bytes of the file on success, negative portable error code on failure
*/
I_64 VMCALL
hyfile_length (struct HyPortLibrary * portLibrary, const char *path)
{
I_64 result;
I_32 error;
WIN32_FILE_ATTRIBUTE_DATA myStat;
wchar_t *pathW;
int ret;
convert_path_to_unicode(portLibrary, path, &pathW);
ret = GetFileAttributesExW(pathW,GetFileExInfoStandard,&myStat);
portLibrary->mem_free_memory(portLibrary, pathW);
if(ret == 0) {
error = GetLastError ();
return portLibrary->error_set_last_error (portLibrary, error, findError (error));
}
result = ((I_64) myStat.nFileSizeHigh) << 32;
result += (I_64) myStat.nFileSizeLow;
return result;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION is_device_name
/**
* Determines if the given file name is a reserved device name
* @param[in] path the path
* @return length of device name if given file name is a device name or
* 0 otherwise
*/
int
is_device_name(const char *path)
{
const char *reserved[] = {"con", "prn", "aux", "nul", "com", "lpt"};
char *fname = strrchr(path, '\\');
int i, len;
fname = fname ? (fname + 1) : (char *) path;
len = strlen(fname);
for (i = 0; i < 6; i++) {
if (i < 4 && len == 3 && !_stricmp(fname, reserved[i])) {
return 3;
} else if (i >= 4 && len == 4 && !_strnicmp(fname, reserved[i], 3) &&
isdigit(fname[3]) && fname[3] != '0') {
return 4;
}
}
return 0;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION convert_path_to_unicode
// Maximum length of path accepted by unicode versions of
// WinAPI functions is limited to 32767 characters;
// each character can take up to three bytes in UTF-8.
#define ABS_PATH_BUF_LEN 32767*3
/**
* Convert UTF-8 encoded path to UTF-16 so it can be used as an argument to
* unicode versions of WinAPI fucntions. This function also converts all
* relative paths to absolute ones.
*
* @param[in] portLibrary The port library
* @param[in] path UTF-8 encoded null-terminated path
* @param[out] pathW Pointer to wide characters array that contains converted
* path
*
* @note Sets *pathW to null and returns if path cannot be converted
*/
void
convert_path_to_unicode(struct HyPortLibrary * portLibrary, const char *path,
wchar_t **pathW)
{
int len;
int wlen;
wchar_t *wPath = 0;
wchar_t tmpPath[ABS_PATH_BUF_LEN];
if (!path) {
*pathW = (void*) 0;
return;
}
// check if given path is a name of device: nul, con, lpt1 and etc.
if (len = is_device_name(path)) {
wlen = MultiByteToWideChar(CP_UTF8, 0, path, -1, *pathW, 0);
*pathW = portLibrary->mem_allocate_memory(portLibrary, wlen*sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, path + strlen(path) - len, -1, *pathW, wlen);
return;
}
wlen = MultiByteToWideChar(CP_UTF8, 0, path, -1, wPath, 0);
wPath = portLibrary->mem_allocate_memory(portLibrary, wlen*sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, path, -1, wPath, wlen);
if (!GetFullPathNameW(wPath, ABS_PATH_BUF_LEN, tmpPath, (void*)0)) {
*pathW = (void*)0;
} else {
wlen = sizeof(tmpPath) + 5;
*pathW = portLibrary->mem_allocate_memory(portLibrary, wlen);
wcscpy(*pathW, L"\\\\?\\");
wcscat(*pathW, tmpPath);
}
portLibrary->mem_free_memory(portLibrary, wPath);
}
#undef ABS_PATH_BUF_LEN
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_mkdir
/**
* Create a directory.
*
* @param[in] portLibrary The port library
* @param[in] path Directory to be created.
*
* @return 0 on success, -1 on failure.
* @note Assumes all components of path up to the last directory already exist.
* @internal @todo return negative portable return code on failure.
*/
I_32 VMCALL
hyfile_mkdir (struct HyPortLibrary * portLibrary, const char *path)
{
int returnVar=0;
wchar_t *pathW;
convert_path_to_unicode(portLibrary, path, &pathW);
returnVar = CreateDirectoryW (pathW, 0);
portLibrary->mem_free_memory(portLibrary, pathW);
if (returnVar)
{
return 0;
}
else
{
I_32 error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
return -1;
}
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_move
/**
* Move the file pathExist to a new name pathNew.
*
* @param[in] portLibrary The port library
* @param[in] pathExist The existing file name.
* @param[in] pathNew The new file name.
*
* @return 0 on success, -1 on failure.
* @internal @todo return negative portable return code on failure.
*/
I_32 VMCALL
hyfile_move (struct HyPortLibrary * portLibrary, const char *pathExist,
const char *pathNew)
{
wchar_t *pathExistW, *pathNewW;
int ret;
convert_path_to_unicode(portLibrary, pathExist, &pathExistW);
convert_path_to_unicode(portLibrary, pathNew, &pathNewW);
ret = MoveFileW (pathExistW, pathNewW);
portLibrary->mem_free_memory(portLibrary, pathNewW);
portLibrary->mem_free_memory(portLibrary, pathExistW);
if (ret)
{
return 0;
}
else
{
I_32 error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
return -1;
}
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_open
/**
* Convert a pathname into a file descriptor.
*
* @param[in] portLibrary The port library
* @param[in] path Name of the file to be opened.
* @param[in] flags Portable file read/write attributes.
* @param[in] mode Platform file permissions.
*
* @return The file descriptor of the newly opened file, -1 on failure.
*/
IDATA VMCALL
hyfile_open (struct HyPortLibrary * portLibrary, const char *path, I_32 flags,
I_32 mode)
{
DWORD accessMode, shareMode, createMode, flagsAndAttributes;
HANDLE aHandle;
I_32 error;
wchar_t *pathW;
Trc_PRT_file_open_Entry (path, flags, mode);
accessMode = 0;
if (flags & HyOpenRead)
{
accessMode |= GENERIC_READ;
}
if (flags & HyOpenWrite)
{
accessMode |= GENERIC_WRITE;
}
shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
if ((flags & HyOpenCreate) == HyOpenCreate)
{
createMode = OPEN_ALWAYS;
}
else if ((flags & HyOpenCreateNew) == HyOpenCreateNew)
{
createMode = CREATE_NEW;
}
else
{
createMode = OPEN_EXISTING;
}
flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
if (flags & HyOpenSync) {
flagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
}
convert_path_to_unicode(portLibrary, path, &pathW);
aHandle =
CreateFileW (pathW, accessMode, shareMode, NULL, createMode,
flagsAndAttributes, NULL);
if (aHandle == INVALID_HANDLE_VALUE)
{
error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
portLibrary->mem_free_memory(portLibrary, pathW);
Trc_PRT_file_open_Exit2 (error, findError (error));
return -1;
}
if ((GetFileType(aHandle) == FILE_TYPE_DISK) && ((flags & HyOpenTruncate) == HyOpenTruncate))
{
if (0 == CloseHandle (aHandle))
{
error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error, findError (error)); /* continue */
}
aHandle =
CreateFileW (pathW, accessMode, shareMode, NULL, TRUNCATE_EXISTING,
flagsAndAttributes, NULL);
if (aHandle == INVALID_HANDLE_VALUE)
{
error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
portLibrary->mem_free_memory(portLibrary, pathW);
Trc_PRT_file_open_Exit3 (error, findError (error));
return -1;
}
}
if (flags & HyOpenAppend)
{
portLibrary->file_seek (portLibrary, (IDATA) aHandle, 0, HySeekEnd);
}
portLibrary->mem_free_memory(portLibrary, pathW);
Trc_PRT_file_open_Exit (aHandle);
return ((IDATA) aHandle);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_read
/**
* Read bytes from a file descriptor into a user provided buffer.
*
* @param[in] portLibrary The port library
* @param[in] fd The file descriptor.
* @param[in,out] buf Buffer to read into.
* @param[in] nbytes Size of buffer.
*
* @return The number of bytes read, or -1 on failure.
*/
IDATA VMCALL
hyfile_read (struct HyPortLibrary * portLibrary, IDATA fd, void *buf,
IDATA nbytes)
{
DWORD bytesRead;
if (nbytes == 0)
{
return 0;
}
if (!ReadFile ((HANDLE) fd, buf, nbytes, &bytesRead, NULL))
{
I_32 error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
return -1;
}
if (bytesRead == 0)
{
portLibrary->error_set_last_error (portLibrary, 0, 0);
return -1;
}
return bytesRead;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_seek
/**
* Repositions the offset of the file descriptor to a given offset as per directive whence.
*
* @param[in] portLibrary The port library
* @param[in] fd The file descriptor.
* @param[in] offset The offset in the file to position to.
* @param[in] whence Portable constant describing how to apply the offset.
*
* @return The resulting offset on success, -1 on failure.
* @note whence is one of HySeekSet (seek from beginning of file),
* HySeekCur (seek from current file pointer) or HySeekEnd (seek backwards from
* end of file).
* @internal @note seek operations return -1 on failure. Negative offsets
* can be returned when seeking beyond end of file.
*/
I_64 VMCALL
hyfile_seek (struct HyPortLibrary * portLibrary, IDATA fd, I_64 offset,
I_32 whence)
{
DWORD moveMethod, moveResult;
DWORD lowerOffset, upperOffset;
I_64 result;
I_32 error;
lowerOffset = (DWORD) (offset & 0xFFFFFFFF);
upperOffset = (DWORD) ((offset >> 32) & 0xFFFFFFFF);
if ((whence < HySeekSet) || (whence > HySeekEnd))
{
return -1;
}
if (whence == HySeekSet)
{
moveMethod = FILE_BEGIN;
}
if (whence == HySeekEnd)
{
moveMethod = FILE_END;
}
if (whence == HySeekCur)
{
moveMethod = FILE_CURRENT;
}
moveResult =
SetFilePointer ((HANDLE) fd, lowerOffset, &upperOffset, moveMethod);
if (-1 == moveResult)
{
error = GetLastError ();
if (error != NO_ERROR)
{
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
return -1;
}
}
result = (I_64) upperOffset << 32;
result |= moveResult;
return result;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_shutdown
/**
* PortLibrary shutdown.
*
* This function is called during shutdown of the portLibrary. Any resources that were created by @ref hyfile_startup
* should be destroyed here.
*
* @param[in] portLibrary The port library
*
* @note Most implementations will be empty.
*/
void VMCALL
hyfile_shutdown (struct HyPortLibrary *portLibrary)
{
/* empty */
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_startup
/**
* PortLibrary startup.
*
* This function is called during startup of the portLibrary. Any resources that are required for
* the file operations may be created here. All resources created here should be destroyed
* in @ref hyfile_shutdown.
*
* @param[in] portLibrary The port library
*
* @return 0 on success, negative error code on failure. Error code values returned are
* \arg HYPORT_ERROR_STARTUP_FILE
*
* @note Most implementations will simply return success.
*/
I_32 VMCALL
hyfile_startup (struct HyPortLibrary *portLibrary)
{
return 0;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_sync
/**
* Synchronize a file's state with the state on disk.
*
* @param[in] portLibrary The port library
* @param[in] fd The file descriptor.
*
* @return 0 on success, -1 on failure.
* @internal @todo return negative portable return code on failure.
*/
I_32 VMCALL
hyfile_sync (struct HyPortLibrary * portLibrary, IDATA fd)
{
if (FlushFileBuffers ((HANDLE) fd))
{
return 0;
}
else
{
I_32 error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
return -1;
}
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_unlink
/**
* Remove a file from the file system.
*
* @param[in] portLibrary The port library
* @param[in] path file/path name to remove.
*
* @return 0 on success, -1 on failure.
* @internal @todo return negative portable return code on failure.
*/
I_32 VMCALL
hyfile_unlink (struct HyPortLibrary * portLibrary, const char *path)
{
wchar_t *pathW;
int ret;
/* should be able to delete read-only dirs, so we set the file attribute back to normal */
convert_path_to_unicode(portLibrary, path, &pathW);
if (0 == SetFileAttributesW (pathW, FILE_ATTRIBUTE_NORMAL))
{
I_32 error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error, findError (error)); /* continue */
}
ret = DeleteFileW (pathW);
portLibrary->mem_free_memory(portLibrary, pathW);
if (ret)
{
return 0;
}
else
{
I_32 error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
return -1;
}
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_unlinkdir
/**
* Remove the trailing directory of the path. If the path is a symbolic link to a directory, remove
* the symbolic link.
*
* @param[in] portLibrary The port library
* @param[in] path directory name being removed.
*
* @return 0 on success, -1 on failure.
* @internal @todo return negative portable return code on failure..
*/
I_32 VMCALL
hyfile_unlinkdir (struct HyPortLibrary * portLibrary, const char *path)
{
wchar_t *pathW;
convert_path_to_unicode(portLibrary, path, &pathW);
/* should be able to delete read-only dirs, so we set the file attribute back to normal */
if (0 == SetFileAttributesW (pathW, FILE_ATTRIBUTE_NORMAL))
{
I_32 error = GetLastError ();
portLibrary->error_set_last_error (portLibrary, error, findError (error)); /* continue */
}
if (RemoveDirectoryW (pathW))
{
portLibrary->mem_free_memory(portLibrary, pathW);
return 0;
}
else
{
I_32 error = GetLastError ();
portLibrary->mem_free_memory(portLibrary, pathW);
portLibrary->error_set_last_error (portLibrary, error,
findError (error));
return -1;
}
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_vprintf
/**
* Write to a file.
*
* Writes formatted output to the file referenced by the file descriptor.
*
* @param[in] portLibrary The port library
* @param[in] fd File descriptor to write.
* @param[in] format The format String.
* @param[in] args Variable argument list.
*/
void VMCALL
hyfile_vprintf (struct HyPortLibrary *portLibrary, IDATA fd,
const char *format, va_list args)
{
char outputBuffer[256];
char *allocatedBuffer;
U_32 numberWritten;
va_list copyOfArgs;
/* Attempt to write output to stack buffer */
COPY_VA_LIST (copyOfArgs, args);
numberWritten =
portLibrary->str_vprintf (portLibrary, outputBuffer,
sizeof (outputBuffer), format, copyOfArgs);
/* str_vprintf always null terminates, returns number characters written excluding the null terminator */
if (sizeof (outputBuffer) > (numberWritten + 1))
{
/* write out the buffer */
portLibrary->file_write_text (portLibrary, fd, outputBuffer,
numberWritten);
return;
}
/* Either the buffer was too small, or it was the exact size. Unfortunately can't tell the difference,
* need to determine the size of the buffer (another call to str_vprintf) then print to the buffer,
* a third call to str_vprintf
*/
COPY_VA_LIST (copyOfArgs, args);
/* What is size of buffer required ? Does not include the \0 */
numberWritten =
portLibrary->str_vprintf (portLibrary, NULL, (U_32) (-1), format,
copyOfArgs);
numberWritten += 1;
allocatedBuffer =
portLibrary->mem_allocate_memory (portLibrary, numberWritten);
if (NULL == allocatedBuffer)
{
portLibrary->nls_printf (portLibrary, HYNLS_ERROR,
HYNLS_PORT_FILE_MEMORY_ALLOCATE_FAILURE);
return;
}
numberWritten =
portLibrary->str_vprintf (portLibrary, allocatedBuffer, numberWritten,
format, args);
portLibrary->file_write_text (portLibrary, fd, allocatedBuffer,
numberWritten);
portLibrary->mem_free_memory (portLibrary, allocatedBuffer);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_write
/**
* Write to a file.
*
* Writes up to nbytes from the provided buffer to the file referenced by the file descriptor.
*
* @param[in] portLibrary The port library
* @param[in] fd File descriptor to write.
* @param[in] buf Buffer to be written.
* @param[in] nbytes Size of buffer.
*
* @return Number of bytes written on success, -1 on failure.
* @internal @todo return negative portable return code on failure.
*/
IDATA VMCALL
hyfile_write (struct HyPortLibrary * portLibrary, IDATA fd, void *buf,
IDATA nbytes)
{
DWORD nCharsWritten;
IDATA toWrite, offset = 0;
I_32 errorCode;
HANDLE handle;
if (fd == HYPORT_TTY_OUT)
{
handle = PPG_tty_consoleOutputHd;
}
else if (fd == HYPORT_TTY_ERR)
{
handle = PPG_tty_consoleErrorHd;
}
else
{
handle = (HANDLE) fd;
}
toWrite = nbytes;
while (nbytes > 0)
{
if (toWrite > nbytes)
{
toWrite = nbytes;
}
if (!WriteFile
(handle, (char *) buf + offset, toWrite, &nCharsWritten, NULL))
{
errorCode = GetLastError ();
if (errorCode == ERROR_NOT_ENOUGH_MEMORY)
{
/* Use 48K chunks to get around out of memory problem */
if (toWrite > (48 * 1024))
{
toWrite = 48 * 1024;
}
else
{
toWrite /= 2;
}
/* If we can't write 128 bytes, just return */
if (toWrite >= 128)
{
continue;
}
}
return portLibrary->error_set_last_error (portLibrary, errorCode,
findError (errorCode));
}
offset += nCharsWritten;
nbytes -= nCharsWritten;
}
return (IDATA) offset;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_printf
/**
* Write to a file.
*
* Writes formatted output to the file referenced by the file descriptor.
*
* @param[in] portLibrary The port library
* @param[in] fd File descriptor to write to
* @param[in] format The format string to be output.
* @param[in] ... arguments for format.
*/
void VMCALL
hyfile_printf (struct HyPortLibrary *portLibrary, IDATA fd,
const char *format, ...)
{
va_list args;
va_start (args, format);
portLibrary->file_vprintf (portLibrary, fd, format, args);
va_end (args);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hyfile_set_length
/**
* Set the length of a file to a specified value.
*
* @param[in] portLibrary The port library
* @param[in] fd The file descriptor.
* @param[in] newLength Length to be set
*
* @return 0 on success, negative portable error code on failure
*/
I_32 VMCALL
hyfile_set_length (struct HyPortLibrary *portLibrary, IDATA fd,
I_64 newLength)
{
I_32 result, error;
I_32 lowValue, highValue;
lowValue = (I_32) (newLength & 0xFFFFFFFF);
highValue = (I_32) ((newLength >> 32) & 0x7FFFFFFF);
result = SetFilePointer ((HANDLE) fd, lowValue, &highValue, FILE_BEGIN);
error = GetLastError ();
if ((result == -1) && (error != NO_ERROR))
{
return portLibrary->error_set_last_error (portLibrary, error,
findError (error));
}
else
{
if (0 == SetEndOfFile ((HANDLE) fd))
{
error = GetLastError ();
return portLibrary->error_set_last_error (portLibrary, error,
findError (error));
}
/* Put pointer back to where it started */
result = SetFilePointer ((HANDLE) fd, result, &highValue, FILE_BEGIN);
error = GetLastError ();
if ((result == -1) && (error != NO_ERROR))
{
return portLibrary->error_set_last_error (portLibrary, error,
findError (error));
}
}
return 0;
}
#undef CDEV_CURRENT_FUNCTION