fileio-win.cpp revision 60ddef6545aaae0b1847daaa514c4ea9e273a681
/* $Id$ */
/** @file
* innotek Portable Runtime - File I/O, native implementation for the Windows host platform.
*/
/*
* Copyright (C) 2006-2007 innotek GmbH
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP RTLOGGROUP_DIR
#include <Windows.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** @def RT_DONT_CONVERT_FILENAMES
* Define this to pass UTF-8 unconverted to the kernel. */
#ifdef __DOXYGEN__
# define RT_DONT_CONVERT_FILENAMES 1
#endif
/**
* This is wrapper around the ugly SetFilePointer api.
*
* It's equivalent to SetFilePointerEx which we so unfortunately cannot use because of
* it not being present in NT4 GA.
*
* @returns Success indicator. Extended error information obtainable using GetLastError().
* @param File Filehandle.
* @param offSeek Offset to seek.
* @param poffNew Where to store the new file offset. NULL allowed.
* @param uMethod Seek method. (The windows one!)
*/
{
bool fRc;
#if 1
{
}
else
{
}
#else
#endif
return fRc;
}
/**
* This is a helper to check if an attempt was made to grow a file beyond the
* limit of the filesystem.
*
* @returns true for file size limit exceeded.
* @param File Filehandle.
* @param offSeek Offset to seek.
*/
{
bool fIsBeyondLimit = false;
/*
* Get the current file position and try set the new one.
* If it fails with a seek error it's because we hit the file system limit.
*/
/** @todo r=bird: I'd be very interested to know on which versions of windows and on which file systems
* this supposedly works. The fastfat sources in the latest WDK makes no limit checks during
* file seeking, only at the time of writing (and some other odd ones we cannot make use of). */
{
else /* Restore file pointer on success. */
}
return fIsBeyondLimit;
}
{
/*
* Validate input.
*/
if (!pFile)
{
AssertMsgFailed(("Invalid pFile\n"));
return VERR_INVALID_PARAMETER;
}
*pFile = NIL_RTFILE;
if (!pszFilename)
{
AssertMsgFailed(("Invalid pszFilename\n"));
return VERR_INVALID_PARAMETER;
}
/*
* Merge forced open flags and validate them.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Determine disposition, access, share mode, creation flags, and security attributes
* for the CreateFile API call.
*/
switch (fOpen & RTFILE_O_ACTION_MASK)
{
case RTFILE_O_OPEN:
break;
case RTFILE_O_OPEN_CREATE:
break;
case RTFILE_O_CREATE:
break;
case RTFILE_O_CREATE_REPLACE:
break;
default:
return VERR_INVALID_PARAMETER;
}
switch (fOpen & RTFILE_O_ACCESS_MASK)
{
default:
return VERR_INVALID_PARAMETER;
}
switch (fOpen & RTFILE_O_DENY_MASK)
{
case RTFILE_O_DENY_READWRITE: dwShareMode = 0; break;
case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_NONE: dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; break;
case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ: dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_WRITE; break;
case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE: dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_READ; break;
default:
return VERR_INVALID_PARAMETER;
}
if (fOpen & RTFILE_O_INHERIT)
{
}
if (fOpen & RTFILE_O_WRITE_THROUGH)
/*
*/
#ifdef RT_DONT_CONVERT_FILENAMES
NULL);
#else
if (RT_FAILURE(rc))
return rc;
NULL);
#endif
if (hFile != INVALID_HANDLE_VALUE)
{
/*
* Turn off indexing of directory through Windows Indexing Service.
*/
if ( fCreated
&& (fOpen & RTFILE_O_NOT_CONTENT_INDEXED))
{
#ifdef RT_DONT_CONVERT_FILENAMES
#else
#endif
}
/*
* Do we need to truncate the file?
*/
else if ( !fCreated
{
if (!SetEndOfFile(hFile))
}
if (RT_SUCCESS(rc))
{
#ifndef RT_DONT_CONVERT_FILENAMES
#endif
return VINF_SUCCESS;
}
}
else
#ifndef RT_DONT_CONVERT_FILENAMES
#endif
return rc;
}
{
return VINF_SUCCESS;
return RTErrConvertFromWin32(GetLastError());
}
{
static ULONG aulSeekRecode[] =
{
};
/*
* Validate input.
*/
if (uMethod > RTFILE_SEEK_END)
{
return VERR_INVALID_PARAMETER;
}
/*
* Execute the seek.
*/
return VINF_SUCCESS;
return RTErrConvertFromWin32(GetLastError());
}
{
if (cbToRead <= 0)
return VINF_SUCCESS;
{
if (pcbRead)
/* Caller can handle partial reads. */
else
{
/* Caller expects everything to be read. */
{
ULONG cbReadPart = 0;
return RTErrConvertFromWin32(GetLastError());
if (cbReadPart == 0)
return VERR_EOF;
cbRead += cbReadPart;
}
}
return VINF_SUCCESS;
}
return RTErrConvertFromWin32(GetLastError());
}
{
if (cbToWrite <= 0)
return VINF_SUCCESS;
{
if (pcbWritten)
/* Caller can handle partial writes. */
*pcbWritten = cbWritten;
else
{
/* Caller expects everything to be written. */
{
ULONG cbWrittenPart = 0;
if (!WriteFile((HANDLE)File, (char*)pvBuf + cbWritten, cbToWrite - cbWritten, &cbWrittenPart, NULL))
{
if ( rc == VERR_DISK_FULL
)
return rc;
}
if (cbWrittenPart == 0)
return VERR_WRITE_ERROR;
}
}
return VINF_SUCCESS;
}
if ( rc == VERR_DISK_FULL
)
return rc;
}
{
int rc;
{
rc = GetLastError();
return RTErrConvertFromWin32(rc);
}
return VINF_SUCCESS;
}
{
/*
* Get current file pointer.
*/
int rc;
{
/*
* Set new file pointer.
*/
{
/* file pointer setted */
{
/*
* Restore file pointer and return.
* If the old pointer was beyond the new file end, ignore failure.
*/
|| offCurrent > cbSize)
return VINF_SUCCESS;
}
/*
* Failed, try restore file pointer.
*/
rc = GetLastError();
}
else
rc = GetLastError();
}
else
rc = GetLastError();
return RTErrConvertFromWin32(rc);
}
{
{
return VINF_SUCCESS;
}
/* error exit */
return RTErrConvertFromWin32(GetLastError());
}
{
if (File != NIL_RTFILE)
{
switch (dwType)
{
case FILE_TYPE_CHAR:
case FILE_TYPE_DISK:
case FILE_TYPE_PIPE:
case FILE_TYPE_REMOTE:
return true;
case FILE_TYPE_UNKNOWN:
if (GetLastError() == NO_ERROR)
return true;
break;
}
}
return false;
}
{
/* Check arguments. */
if (fLock & ~RTFILE_LOCK_MASK)
{
return VERR_INVALID_PARAMETER;
}
/* Prepare flags. */
if (!(fLock & RTFILE_LOCK_WAIT))
/* Windows structure. */
/* Note: according to Microsoft, LockFileEx API call is available starting from NT 3.5 */
return VINF_SUCCESS;
return RTErrConvertFromWin32(GetLastError());
}
{
/* Check arguments. */
if (fLock & ~RTFILE_LOCK_MASK)
{
return VERR_INVALID_PARAMETER;
}
/* Remove old lock. */
if (RT_FAILURE(rc))
return rc;
/* Set new lock. */
if (RT_SUCCESS(rc))
return rc;
/* Try to restore old lock. */
unsigned fLockOld = (fLock & RTFILE_LOCK_WRITE) ? fLock & ~RTFILE_LOCK_WRITE : fLock | RTFILE_LOCK_WRITE;
if (RT_SUCCESS(rc))
return VERR_FILE_LOCK_VIOLATION;
else
return VERR_FILE_LOCK_LOST;
}
{
if (UnlockFile((HANDLE)File, LOW_DWORD(offLock), HIGH_DWORD(offLock), LOW_DWORD(cbLock), HIGH_DWORD(cbLock)))
return VINF_SUCCESS;
return RTErrConvertFromWin32(GetLastError());
}
RTR3DECL(int) RTFileQueryInfo(RTFILE File, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
{
/*
* Validate input.
*/
if (File == NIL_RTFILE)
{
return VERR_INVALID_PARAMETER;
}
if (!pObjInfo)
{
return VERR_INVALID_PARAMETER;
}
{
return VERR_INVALID_PARAMETER;
}
/*
* Query file info.
*/
return RTErrConvertFromWin32(GetLastError());
/*
* Setup the returned data.
*/
pObjInfo->Attr.fMode = rtFsModeFromDos((Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, "", 0);
/*
* Requested attributes (we cannot provide anything actually).
*/
switch (enmAdditionalAttribs)
{
case RTFSOBJATTRADD_EASIZE:
break;
case RTFSOBJATTRADD_UNIX:
break;
case RTFSOBJATTRADD_NOTHING:
break;
default:
AssertMsgFailed(("Impossible!\n"));
return VERR_INTERNAL_ERROR;
}
return VINF_SUCCESS;
}
{
return VINF_SUCCESS; /* NOP */
if (pBirthTime)
if (pAccessTime)
if (pModificationTime)
int rc = VINF_SUCCESS;
{
Log(("RTFileSetTimes(%RTfile, %p, %p, %p, %p): SetFileTime failed with lasterr %d (%Vrc)\n",
}
return rc;
}
{
/** @todo darn. this needs a full path; probably must be done if the file is closed
* It's quite possible that there is an NT API for this. NtSetInformationFile() for instance. */
return VINF_SUCCESS;
}
{
#ifdef RT_DONT_CONVERT_FILENAMES
if (DeleteFile(pszFilename))
return VINF_SUCCESS;
return RTErrConvertFromWin32(GetLastError());
#else
if (RT_SUCCESS(rc))
{
if (!DeleteFileW(pwszFilename))
}
return rc;
#endif
}
{
/*
* Validate input.
*/
AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
/*
* Hand it on to the worker.
*/
LogFlow(("RTFileMove(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
return rc;
}
{
/*
* Validate input.
*/
/*
* Hand it on to the worker.
*/
LogFlow(("RTFileMove(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n",
return rc;
}