forked from 0ad/0ad
refactor file interface. requires workspace update
- separate file_system_util into vfs functions (-> vfs/vfs_util) and file_system (avoids ugly fs_util namespace prefix) - get rid of non-portable O_BINARY_NP etc. flags - use standard O_WRONLY etc. flags instead of LIO_WRITE; but avoid the need for specifying O_CREAT|O_TRUNC - only open files for aio when O_DIRECT is specified (which 0ad does not) - avoids wasting time and security issues - return file descriptor directly instead of via output param - waio: safer FCB mechanism that avoids mixing descriptors between lowio and aio This was SVN commit r9550.
This commit is contained in:
parent
ceea205782
commit
34186dd017
@ -187,7 +187,7 @@ bool CMapGeneratorWorker::LoadScripts(const std::wstring& libraryName)
|
||||
VfsPaths pathnames;
|
||||
|
||||
// Load all scripts in mapgen directory
|
||||
Status ret = fs_util::GetPathnames(g_VFS, path, L"*.js", pathnames);
|
||||
Status ret = vfs::GetPathnames(g_VFS, path, L"*.js", pathnames);
|
||||
if (ret == INFO::OK)
|
||||
{
|
||||
for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it)
|
||||
|
@ -117,7 +117,7 @@ void CTerrainTextureManager::DeleteTexture(CTerrainTextureEntry* entry)
|
||||
void CTerrainTextureManager::LoadTextures(const CTerrainPropertiesPtr& props, const VfsPath& path)
|
||||
{
|
||||
VfsPaths pathnames;
|
||||
if(fs_util::GetPathnames(g_VFS, path, 0, pathnames) < 0)
|
||||
if(vfs::GetPathnames(g_VFS, path, 0, pathnames) < 0)
|
||||
return;
|
||||
|
||||
// If we have any .cached.dds files then strip that extension to get the
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "lib/file/file_system_util.h"
|
||||
#include "lib/file/file_system.h"
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
#include "lib/file/io/io.h"
|
||||
#include "lib/allocators/shared_ptr.h"
|
||||
@ -53,9 +53,9 @@ class TestMeshManager : public CxxTest::TestSuite
|
||||
|
||||
// Make sure the required directories doesn't exist when we start,
|
||||
// in case the previous test aborted and left them full of junk
|
||||
if(fs_util::DirectoryExists(MOD_PATH))
|
||||
if(DirectoryExists(MOD_PATH))
|
||||
DeleteDirectory(MOD_PATH);
|
||||
if(fs_util::DirectoryExists(CACHE_PATH))
|
||||
if(DirectoryExists(CACHE_PATH))
|
||||
DeleteDirectory(CACHE_PATH);
|
||||
|
||||
g_VFS = CreateVfs(20*MiB);
|
||||
|
@ -432,7 +432,7 @@ class ArchiveReader_Zip : public IArchiveReader
|
||||
{
|
||||
public:
|
||||
ArchiveReader_Zip(const OsPath& pathname)
|
||||
: m_file(new File(pathname, LIO_READ))
|
||||
: m_file(new File(pathname, O_RDONLY))
|
||||
{
|
||||
FileInfo fileInfo;
|
||||
GetFileInfo(pathname, &fileInfo);
|
||||
@ -580,7 +580,7 @@ class ArchiveWriter_Zip : public IArchiveWriter
|
||||
{
|
||||
public:
|
||||
ArchiveWriter_Zip(const OsPath& archivePathname, bool noDeflate)
|
||||
: m_file(new File(archivePathname, LIO_WRITE)), m_fileSize(0)
|
||||
: m_file(new File(archivePathname, O_WRONLY)), m_fileSize(0)
|
||||
, m_numEntries(0), m_noDeflate(noDeflate)
|
||||
{
|
||||
THROW_STATUS_IF_ERR(pool_create(&m_cdfhPool, 10*MiB, 0));
|
||||
@ -620,7 +620,7 @@ public:
|
||||
return INFO::SKIPPED;
|
||||
|
||||
PFile file(new File);
|
||||
RETURN_STATUS_IF_ERR(file->Open(pathname, LIO_READ));
|
||||
RETURN_STATUS_IF_ERR(file->Open(pathname, O_RDONLY));
|
||||
|
||||
const size_t pathnameLength = pathnameInArchive.string().length();
|
||||
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "precompiled.h"
|
||||
#include "lib/file/file.h"
|
||||
|
||||
#include "lib/sysdep/filesystem.h" // O_*, S_*
|
||||
#include "lib/file/common/file_stats.h"
|
||||
|
||||
static const StatusDefinition fileStatusDefinitions[] = {
|
||||
@ -37,33 +36,20 @@ static const StatusDefinition fileStatusDefinitions[] = {
|
||||
STATUS_ADD_DEFINITIONS(fileStatusDefinitions);
|
||||
|
||||
|
||||
Status FileOpen(const OsPath& pathname, int opcode, int& fd)
|
||||
Status FileOpen(const OsPath& pathname, int oflag)
|
||||
{
|
||||
int oflag = 0;
|
||||
switch(opcode)
|
||||
{
|
||||
case LIO_READ:
|
||||
oflag = O_RDONLY;
|
||||
break;
|
||||
case LIO_WRITE:
|
||||
oflag = O_WRONLY|O_CREAT|O_TRUNC;
|
||||
break;
|
||||
default:
|
||||
DEBUG_WARN_ERR(ERR::LOGIC);
|
||||
break;
|
||||
}
|
||||
#if OS_WIN
|
||||
oflag |= O_BINARY_NP;
|
||||
#endif
|
||||
ENSURE((oflag & ~(O_RDONLY|O_WRONLY|O_DIRECT)) == 0);
|
||||
if(oflag & O_WRONLY)
|
||||
oflag |= O_CREAT|O_TRUNC;
|
||||
// prevent exploits by disallowing writes to our files by other users.
|
||||
// note that the system-wide installed cache is read-only.
|
||||
const mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; // 0644
|
||||
fd = wopen(pathname, oflag, mode);
|
||||
const int fd = wopen(pathname, oflag, mode);
|
||||
if(fd < 0)
|
||||
return StatusFromErrno(); // NOWARN
|
||||
|
||||
stats_open();
|
||||
return INFO::OK;
|
||||
return (Status)fd;
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#define INCLUDED_FILE
|
||||
|
||||
#include "lib/os_path.h"
|
||||
#include "lib/posix/posix_aio.h" // opcode: LIO_READ or LIO_WRITE
|
||||
#include "lib/sysdep/filesystem.h" // O_*, S_*
|
||||
|
||||
namespace ERR
|
||||
{
|
||||
@ -36,7 +36,10 @@ namespace ERR
|
||||
const Status FILE_NOT_FOUND = -110301;
|
||||
}
|
||||
|
||||
LIB_API Status FileOpen(const OsPath& pathname, int opcode, int& fd);
|
||||
// @param oflag: either O_RDONLY or O_WRONLY (in which case O_CREAT and
|
||||
// O_TRUNC are added), plus O_DIRECT if aio is desired
|
||||
// @return file descriptor or a negative Status
|
||||
LIB_API Status FileOpen(const OsPath& pathname, int oflag);
|
||||
LIB_API void FileClose(int& fd);
|
||||
|
||||
class File
|
||||
@ -47,9 +50,9 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
File(const OsPath& pathname, int opcode)
|
||||
File(const OsPath& pathname, int oflag)
|
||||
{
|
||||
(void)Open(pathname, opcode);
|
||||
(void)Open(pathname, oflag);
|
||||
}
|
||||
|
||||
~File()
|
||||
@ -57,11 +60,13 @@ public:
|
||||
Close();
|
||||
}
|
||||
|
||||
Status Open(const OsPath& pathname, int opcode)
|
||||
Status Open(const OsPath& pathname, int oflag)
|
||||
{
|
||||
RETURN_STATUS_IF_ERR(FileOpen(pathname, opcode, fd));
|
||||
Status ret = FileOpen(pathname, oflag);
|
||||
RETURN_STATUS_IF_ERR(ret);
|
||||
this->pathname = pathname;
|
||||
this->opcode = opcode;
|
||||
this->fd = (int)ret;
|
||||
this->oflag = oflag;
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
@ -80,15 +85,15 @@ public:
|
||||
return fd;
|
||||
}
|
||||
|
||||
int Opcode() const
|
||||
int Flags() const
|
||||
{
|
||||
return opcode;
|
||||
return oflag;
|
||||
}
|
||||
|
||||
private:
|
||||
OsPath pathname;
|
||||
int fd;
|
||||
int opcode;
|
||||
int oflag;
|
||||
};
|
||||
|
||||
typedef shared_ptr<File> PFile;
|
||||
|
@ -20,6 +20,10 @@
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* higher-level interface on top of sysdep/filesystem.h
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "lib/file/file_system.h"
|
||||
|
||||
@ -29,6 +33,48 @@
|
||||
|
||||
#include "lib/sysdep/filesystem.h"
|
||||
|
||||
|
||||
bool DirectoryExists(const OsPath& path)
|
||||
{
|
||||
WDIR* dir = wopendir(path);
|
||||
if(dir)
|
||||
{
|
||||
wclosedir(dir);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool FileExists(const OsPath& pathname)
|
||||
{
|
||||
struct stat s;
|
||||
const bool exists = wstat(pathname, &s) == 0;
|
||||
return exists;
|
||||
}
|
||||
|
||||
|
||||
u64 FileSize(const OsPath& pathname)
|
||||
{
|
||||
struct stat s;
|
||||
ENSURE(wstat(pathname, &s) == 0);
|
||||
return s.st_size;
|
||||
}
|
||||
|
||||
|
||||
Status GetFileInfo(const OsPath& pathname, FileInfo* pfileInfo)
|
||||
{
|
||||
errno = 0;
|
||||
struct stat s;
|
||||
memset(&s, 0, sizeof(s));
|
||||
if(wstat(pathname, &s) != 0)
|
||||
WARN_RETURN(StatusFromErrno());
|
||||
|
||||
*pfileInfo = FileInfo(pathname.Filename(), s.st_size, s.st_mtime);
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
|
||||
struct DirDeleter
|
||||
{
|
||||
void operator()(WDIR* osDir) const
|
||||
@ -84,19 +130,6 @@ Status GetDirectoryEntries(const OsPath& path, FileInfos* files, DirectoryNames*
|
||||
}
|
||||
|
||||
|
||||
Status GetFileInfo(const OsPath& pathname, FileInfo* pfileInfo)
|
||||
{
|
||||
errno = 0;
|
||||
struct stat s;
|
||||
memset(&s, 0, sizeof(s));
|
||||
if(wstat(pathname, &s) != 0)
|
||||
WARN_RETURN(StatusFromErrno());
|
||||
|
||||
*pfileInfo = FileInfo(pathname.Filename(), s.st_size, s.st_mtime);
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
|
||||
Status CreateDirectories(const OsPath& path, mode_t mode)
|
||||
{
|
||||
if(path.empty())
|
||||
|
@ -20,12 +20,23 @@
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* higher-level interface on top of sysdep/filesystem.h
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_FILE_SYSTEM
|
||||
#define INCLUDED_FILE_SYSTEM
|
||||
|
||||
#include "lib/os_path.h"
|
||||
#include "lib/posix/posix_filesystem.h" // mode_t
|
||||
|
||||
|
||||
LIB_API bool DirectoryExists(const OsPath& path);
|
||||
LIB_API bool FileExists(const OsPath& pathname);
|
||||
|
||||
LIB_API u64 FileSize(const OsPath& pathname);
|
||||
|
||||
|
||||
// (bundling size and mtime avoids a second expensive call to stat())
|
||||
class FileInfo
|
||||
{
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "lib/bits.h"
|
||||
#include "lib/file/file.h"
|
||||
#include "lib/sysdep/filesystem.h" // wtruncate
|
||||
#include "lib/posix/posix_aio.h" // LIO_READ, LIO_WRITE
|
||||
|
||||
#include "lib/allocators/unique_range.h"
|
||||
|
||||
@ -63,7 +64,7 @@ struct Operation
|
||||
// otherwise, it must be aligned and padded to the I/O alignment, e.g. via
|
||||
// io::Allocate.
|
||||
Operation(const File& file, void* buf, off_t size, off_t offset = 0)
|
||||
: fd(file.Descriptor()), opcode(file.Opcode())
|
||||
: fd(file.Descriptor()), opcode((file.Flags() & O_WRONLY)? LIO_WRITE : LIO_READ)
|
||||
, offset(offset), size(size), buf((void*)buf)
|
||||
{
|
||||
}
|
||||
@ -281,10 +282,10 @@ template<class CompletedHook, class IssueHook>
|
||||
static inline Status Store(const OsPath& pathname, const void* data, size_t size, const Parameters& p = Parameters(), const CompletedHook& completedHook = CompletedHook(), const IssueHook& issueHook = IssueHook())
|
||||
{
|
||||
File file;
|
||||
WARN_RETURN_STATUS_IF_ERR(file.Open(pathname, LIO_WRITE));
|
||||
WARN_RETURN_STATUS_IF_ERR(file.Open(pathname, O_WRONLY));
|
||||
io::Operation op(file, (void*)data, size);
|
||||
|
||||
#if OS_WIN && CONFIG2_FILE_ENABLE_AIO
|
||||
#if OS_WIN
|
||||
(void)waio_Preallocate(op.fd, (off_t)size);
|
||||
#endif
|
||||
|
||||
@ -317,7 +318,7 @@ template<class CompletedHook, class IssueHook>
|
||||
static inline Status Load(const OsPath& pathname, void* buf, size_t size, const Parameters& p = Parameters(), const CompletedHook& completedHook = CompletedHook(), const IssueHook& issueHook = IssueHook())
|
||||
{
|
||||
File file;
|
||||
RETURN_STATUS_IF_ERR(file.Open(pathname, LIO_READ));
|
||||
RETURN_STATUS_IF_ERR(file.Open(pathname, O_RDONLY));
|
||||
io::Operation op(file, buf, size);
|
||||
return io::Run(op, p, completedHook, issueHook);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
#include "lib/allocators/shared_ptr.h"
|
||||
#include "lib/posix/posix_pthread.h"
|
||||
#include "lib/file/file_system_util.h"
|
||||
#include "lib/file/file_system.h"
|
||||
#include "lib/file/common/file_stats.h"
|
||||
#include "lib/file/common/trace.h"
|
||||
#include "lib/file/archive/archive.h"
|
||||
@ -61,7 +61,7 @@ public:
|
||||
virtual Status Mount(const VfsPath& mountPoint, const OsPath& path, size_t flags /* = 0 */, size_t priority /* = 0 */)
|
||||
{
|
||||
ScopedLock s;
|
||||
if(!fs_util::DirectoryExists(path))
|
||||
if(!DirectoryExists(path))
|
||||
{
|
||||
if(flags & VFS_MOUNT_MUST_EXIST)
|
||||
return ERR::VFS_DIR_NOT_FOUND; // NOWARN
|
||||
|
@ -25,7 +25,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "lib/file/file_system_util.h"
|
||||
#include "lib/file/vfs/vfs_util.h"
|
||||
|
||||
#include <queue>
|
||||
#include <cstring>
|
||||
@ -35,35 +35,7 @@
|
||||
#include "lib/regex.h"
|
||||
|
||||
|
||||
namespace fs_util {
|
||||
|
||||
bool DirectoryExists(const OsPath& path)
|
||||
{
|
||||
WDIR* dir = wopendir(path);
|
||||
if(dir)
|
||||
{
|
||||
wclosedir(dir);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool FileExists(const OsPath& pathname)
|
||||
{
|
||||
struct stat s;
|
||||
const bool exists = wstat(pathname, &s) == 0;
|
||||
return exists;
|
||||
}
|
||||
|
||||
|
||||
u64 FileSize(const OsPath& pathname)
|
||||
{
|
||||
struct stat s;
|
||||
ENSURE(wstat(pathname, &s) == 0);
|
||||
return s.st_size;
|
||||
}
|
||||
|
||||
namespace vfs {
|
||||
|
||||
Status GetPathnames(const PIVFS& fs, const VfsPath& path, const wchar_t* filter, VfsPaths& pathnames)
|
||||
{
|
||||
@ -159,4 +131,4 @@ void NextNumberedFilename(const PIVFS& fs, const VfsPath& pathnameFormat, size_t
|
||||
while(fs->GetFileInfo(nextPathname, 0) == INFO::OK);
|
||||
}
|
||||
|
||||
} // namespace fs_util
|
||||
} // namespace vfs
|
@ -24,18 +24,13 @@
|
||||
* helper functions for directory access
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_FILE_SYSTEM_UTIL
|
||||
#define INCLUDED_FILE_SYSTEM_UTIL
|
||||
#ifndef INCLUDED_VFS_UTIL
|
||||
#define INCLUDED_VFS_UTIL
|
||||
|
||||
#include "lib/os_path.h"
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
|
||||
namespace fs_util {
|
||||
|
||||
LIB_API bool DirectoryExists(const OsPath& path);
|
||||
LIB_API bool FileExists(const OsPath& pathname);
|
||||
|
||||
LIB_API u64 FileSize(const OsPath& pathname);
|
||||
namespace vfs {
|
||||
|
||||
extern Status GetPathnames(const PIVFS& fs, const VfsPath& path, const wchar_t* filter, VfsPaths& pathnames);
|
||||
|
||||
@ -88,6 +83,6 @@ extern Status ForEachFile(const PIVFS& fs, const VfsPath& path, FileCallback cb,
|
||||
**/
|
||||
extern void NextNumberedFilename(const PIVFS& fs, const VfsPath& pathnameFormat, size_t& nextNumber, VfsPath& nextPathname);
|
||||
|
||||
} // namespace fs_util
|
||||
} // namespace vfs
|
||||
|
||||
#endif // #ifndef INCLUDED_FILE_SYSTEM_UTIL
|
||||
#endif // #ifndef INCLUDED_VFS_UTIL
|
@ -37,7 +37,6 @@
|
||||
#include "lib/timer.h"
|
||||
#include "lib/res/h_mgr.h"
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
extern PIVFS vfs;
|
||||
|
||||
static const StatusDefinition oglShaderStatusDefs[] = {
|
||||
{ ERR::SHDR_CREATE, L"Shader creation failed" },
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include "lib/byte_order.h"
|
||||
#include "lib/file/io/io.h"
|
||||
#include "lib/file/file_system_util.h"
|
||||
#include "lib/file/file_system.h"
|
||||
|
||||
|
||||
static Status LibErrorFromVorbis(int err)
|
||||
@ -52,7 +52,7 @@ class VorbisFileAdapter
|
||||
public:
|
||||
VorbisFileAdapter(const PFile& openedFile)
|
||||
: file(openedFile)
|
||||
, size(fs_util::FileSize(openedFile->Pathname()))
|
||||
, size(FileSize(openedFile->Pathname()))
|
||||
, offset(0)
|
||||
{
|
||||
}
|
||||
|
@ -24,8 +24,8 @@
|
||||
* wchar_t versions of POSIX filesystem functions
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_FILESYSTEM
|
||||
#define INCLUDED_FILESYSTEM
|
||||
#ifndef INCLUDED_SYSDEP_FILESYSTEM
|
||||
#define INCLUDED_SYSDEP_FILESYSTEM
|
||||
|
||||
#include "lib/os_path.h"
|
||||
#include "lib/posix/posix_filesystem.h" // mode_t
|
||||
@ -61,16 +61,16 @@ extern int wclosedir(WDIR*);
|
||||
// fcntl.h
|
||||
//
|
||||
|
||||
// Win32 _wsopen_s flags not specified by POSIX:
|
||||
#define O_TEXT_NP 0x4000 // file mode is text (translated)
|
||||
#define O_BINARY_NP 0x8000 // file mode is binary (untranslated)
|
||||
|
||||
// waio flags not specified by POSIX nor implemented by Win32 _wsopen_s:
|
||||
// do not open a separate AIO-capable handle.
|
||||
// (this can be used for small files where AIO overhead isn't worthwhile,
|
||||
// thus speeding up loading and reducing resource usage.)
|
||||
#define O_NO_AIO_NP 0x20000
|
||||
|
||||
// Win32 _wsopen_s does not open files in a manner compatible with waio.
|
||||
// if its aio_read/aio_write are to be used, waio_open must (also) be called.
|
||||
// calling both is possible but wasteful and unsafe, since it prevents
|
||||
// file sharing restrictions, which are the only way to prevent
|
||||
// exposing previous data as a side effect of waio_Preallocate.
|
||||
// applications shouldn't mix aio and synchronous I/O anyway, so we
|
||||
// want wopen to call either waio_open or _wsopen_s.
|
||||
// since waio requires callers to respect the FILE_FLAG_NO_BUFFERING
|
||||
// restrictions (sector alignment), and IRIX/BSD/Linux O_DIRECT imposes
|
||||
// similar semantics, we treat that flag as a request to enable aio.
|
||||
extern int wopen(const OsPath& pathname, int oflag);
|
||||
extern int wopen(const OsPath& pathname, int oflag, mode_t mode);
|
||||
extern int wclose(int fd);
|
||||
@ -114,4 +114,4 @@ LIB_API int wstat(const OsPath& pathname, struct stat* buf);
|
||||
|
||||
LIB_API int wmkdir(const OsPath& path, mode_t mode);
|
||||
|
||||
#endif // #ifndef INCLUDED_FILESYSTEM
|
||||
#endif // #ifndef INCLUDED_SYSDEP_FILESYSTEM
|
||||
|
@ -36,10 +36,11 @@
|
||||
#include "lib/alignment.h" // IsAligned
|
||||
#include "lib/module_init.h"
|
||||
#include "lib/sysdep/cpu.h" // cpu_AtomicAdd
|
||||
#include "lib/sysdep/filesystem.h" // O_NO_AIO_NP
|
||||
#include "lib/sysdep/filesystem.h" // O_DIRECT
|
||||
#include "lib/sysdep/os/win/wutil.h" // wutil_SetPrivilege
|
||||
#include "lib/sysdep/os/win/wiocp.h"
|
||||
#include "lib/sysdep/os/win/winit.h"
|
||||
#include "lib/sysdep/os/win/wposix/crt_posix.h" // _get_osfhandle
|
||||
|
||||
WINIT_REGISTER_MAIN_SHUTDOWN(waio_Shutdown);
|
||||
|
||||
@ -53,6 +54,81 @@ static WUTIL_FUNC(pSetFileValidData, BOOL, (HANDLE, LONGLONG));
|
||||
static HANDLE hIOCP;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// OpenFile
|
||||
|
||||
static DWORD DesiredAccess(int oflag)
|
||||
{
|
||||
switch(oflag & (O_RDONLY|O_WRONLY|O_RDWR))
|
||||
{
|
||||
case O_RDONLY:
|
||||
// (WinXP x64 requires FILE_WRITE_ATTRIBUTES for SetFileCompletionNotificationModes)
|
||||
return GENERIC_READ|FILE_WRITE_ATTRIBUTES;
|
||||
case O_WRONLY:
|
||||
return GENERIC_WRITE;
|
||||
case O_RDWR:
|
||||
return GENERIC_READ|GENERIC_WRITE;
|
||||
default:
|
||||
DEBUG_WARN_ERR(ERR::INVALID_PARAM);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD ShareMode(int oflag)
|
||||
{
|
||||
switch(oflag & (O_RDONLY|O_WRONLY|O_RDWR))
|
||||
{
|
||||
case O_RDONLY:
|
||||
return FILE_SHARE_READ;
|
||||
case O_WRONLY:
|
||||
return FILE_SHARE_WRITE;
|
||||
case O_RDWR:
|
||||
return FILE_SHARE_WRITE; // deny read access (c.f. waio_Preallocate)
|
||||
default:
|
||||
DEBUG_WARN_ERR(ERR::INVALID_PARAM);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD CreationDisposition(int oflag)
|
||||
{
|
||||
if(oflag & O_CREAT)
|
||||
return (oflag & O_EXCL)? CREATE_NEW : CREATE_ALWAYS;
|
||||
|
||||
if(oflag & O_TRUNC)
|
||||
return TRUNCATE_EXISTING;
|
||||
|
||||
return OPEN_EXISTING;
|
||||
}
|
||||
|
||||
static DWORD FlagsAndAttributes()
|
||||
{
|
||||
// - FILE_FLAG_SEQUENTIAL_SCAN is ignored when FILE_FLAG_NO_BUFFERING
|
||||
// is set (c.f. "Windows via C/C++", p. 324)
|
||||
// - FILE_FLAG_WRITE_THROUGH is ~5% slower (diskspd.cpp suggests it
|
||||
// disables hardware caching; the overhead may also be due to the
|
||||
// Windows cache manager)
|
||||
const DWORD flags = FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING;
|
||||
const DWORD attributes = FILE_ATTRIBUTE_NORMAL;
|
||||
return flags|attributes;
|
||||
}
|
||||
|
||||
static Status OpenFile(const OsPath& pathname, int oflag, HANDLE& hFile)
|
||||
{
|
||||
WinScopedPreserveLastError s;
|
||||
|
||||
const DWORD access = DesiredAccess(oflag);
|
||||
const DWORD share = ShareMode(oflag);
|
||||
const DWORD create = CreationDisposition(oflag);
|
||||
const DWORD flags = FlagsAndAttributes();
|
||||
hFile = CreateFileW(OsString(pathname).c_str(), access, share, 0, create, flags, 0);
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
WARN_RETURN(StatusFromWin());
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// OvlAllocator
|
||||
|
||||
@ -168,92 +244,124 @@ struct OvlAllocator // POD
|
||||
//-----------------------------------------------------------------------------
|
||||
// FileControlBlock
|
||||
|
||||
// (must correspond to static zero-initialization of fd)
|
||||
static const intptr_t FD_AVAILABLE = 0;
|
||||
|
||||
// information required to start asynchronous I/Os from a file
|
||||
// (aiocb stores a pointer to the originating FCB)
|
||||
struct FileControlBlock // POD
|
||||
{
|
||||
// search key, indicates the file descriptor with which this
|
||||
// FCB was associated (or FD_AVAILABLE if none).
|
||||
volatile intptr_t fd;
|
||||
|
||||
// second aio-enabled handle from waio_reopen
|
||||
HANDLE hFile;
|
||||
|
||||
OvlAllocator ovl;
|
||||
|
||||
Status Init()
|
||||
{
|
||||
fd = FD_AVAILABLE;
|
||||
hFile = INVALID_HANDLE_VALUE;
|
||||
return ovl.Init();
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
ENSURE(fd == FD_AVAILABLE);
|
||||
ENSURE(hFile == INVALID_HANDLE_VALUE);
|
||||
ovl.Shutdown();
|
||||
}
|
||||
|
||||
Status Open(const OsPath& pathname, int oflag)
|
||||
{
|
||||
RETURN_STATUS_IF_ERR(OpenFile(pathname, oflag, hFile));
|
||||
|
||||
ovl.Associate(hFile);
|
||||
|
||||
AttachToCompletionPort(hFile, hIOCP, (ULONG_PTR)this);
|
||||
|
||||
// minor optimization: avoid posting to IOCP in rare cases
|
||||
// where the I/O completes synchronously
|
||||
if(pSetFileCompletionNotificationModes)
|
||||
{
|
||||
// (for reasons as yet unknown, this fails when the file is
|
||||
// opened for read-only access)
|
||||
(void)pSetFileCompletionNotificationModes(hFile, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
|
||||
}
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
Status Close()
|
||||
{
|
||||
const BOOL ok = CloseHandle(hFile);
|
||||
hFile = INVALID_HANDLE_VALUE;
|
||||
if(!ok)
|
||||
WARN_RETURN(ERR::INVALID_HANDLE);
|
||||
return INFO::OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// NB: the Windows lowio file descriptor limit is 2048, but
|
||||
// our applications rarely open more than a few files at a time.
|
||||
static FileControlBlock fileControlBlocks[16];
|
||||
//-----------------------------------------------------------------------------
|
||||
// FileControlBlocks
|
||||
|
||||
|
||||
static FileControlBlock* AssociateFileControlBlock(int fd, HANDLE hFile)
|
||||
struct FileControlBlocks // POD
|
||||
{
|
||||
for(size_t i = 0; i < ARRAY_SIZE(fileControlBlocks); i++)
|
||||
// (we never open more than a few files at a time.)
|
||||
static const size_t maxFiles = 8;
|
||||
|
||||
// (our descriptors exceed _NHANDLE_ (2048) to ensure they are not
|
||||
// confused with lowio descriptors.)
|
||||
static const int firstDescriptor = 4000;
|
||||
|
||||
FileControlBlock fcbs[maxFiles];
|
||||
CACHE_ALIGNED volatile intptr_t inUse[maxFiles];
|
||||
|
||||
void Init()
|
||||
{
|
||||
FileControlBlock& fcb = fileControlBlocks[i];
|
||||
if(cpu_CAS(&fcb.fd, FD_AVAILABLE, fd)) // the FCB is now ours
|
||||
for(size_t i = 0; i < maxFiles; i++)
|
||||
{
|
||||
fcb.hFile = hFile;
|
||||
fcb.ovl.Associate(hFile);
|
||||
|
||||
AttachToCompletionPort(hFile, hIOCP, (ULONG_PTR)&fcb);
|
||||
|
||||
// minor optimization: avoid posting to IOCP in rare cases
|
||||
// where the I/O completes synchronously
|
||||
if(pSetFileCompletionNotificationModes)
|
||||
{
|
||||
// (for reasons as yet unknown, this fails when the file is
|
||||
// opened for read-only access)
|
||||
(void)pSetFileCompletionNotificationModes(fcb.hFile, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
|
||||
}
|
||||
|
||||
return &fcb;
|
||||
inUse[i] = 0;
|
||||
fcbs[i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void DissociateFileControlBlock(FileControlBlock* fcb)
|
||||
{
|
||||
fcb->hFile = INVALID_HANDLE_VALUE;
|
||||
fcb->fd = FD_AVAILABLE;
|
||||
}
|
||||
|
||||
|
||||
static FileControlBlock* FindFileControlBlock(int fd)
|
||||
{
|
||||
ENSURE(fd != FD_AVAILABLE);
|
||||
|
||||
for(size_t i = 0; i < ARRAY_SIZE(fileControlBlocks); i++)
|
||||
void Shutdown()
|
||||
{
|
||||
FileControlBlock& fcb = fileControlBlocks[i];
|
||||
if(fcb.fd == fd)
|
||||
return &fcb;
|
||||
for(size_t i = 0; i < maxFiles; i++)
|
||||
{
|
||||
ENSURE(inUse[i] == 0);
|
||||
fcbs[i].Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
FileControlBlock* Allocate()
|
||||
{
|
||||
for(size_t i = 0; i < maxFiles; i++)
|
||||
{
|
||||
if(cpu_CAS(&inUse[i], 0, 1))
|
||||
return &fcbs[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Deallocate(FileControlBlock* fcb)
|
||||
{
|
||||
const size_t index = fcb - &fcbs[0];
|
||||
inUse[index] = 0;
|
||||
}
|
||||
|
||||
int Descriptor(FileControlBlock* fcb) const
|
||||
{
|
||||
const size_t index = fcb - &fcbs[0];
|
||||
return firstDescriptor + (int)index;
|
||||
}
|
||||
|
||||
FileControlBlock* FromDescriptor(int descriptor)
|
||||
{
|
||||
const size_t index = size_t(descriptor - firstDescriptor);
|
||||
if(index >= maxFiles)
|
||||
return 0;
|
||||
if(!inUse[index])
|
||||
return 0;
|
||||
return &fcbs[index];
|
||||
}
|
||||
};
|
||||
|
||||
static FileControlBlocks fileControlBlocks;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -261,10 +369,10 @@ static FileControlBlock* FindFileControlBlock(int fd)
|
||||
|
||||
static ModuleInitState waio_initState;
|
||||
|
||||
// called from waio_Open (avoids overhead if this module is never used)
|
||||
static Status waio_Init()
|
||||
{
|
||||
for(size_t i = 0; i < ARRAY_SIZE(fileControlBlocks); i++)
|
||||
fileControlBlocks[i].Init();
|
||||
fileControlBlocks.Init();
|
||||
|
||||
WUTIL_IMPORT_KERNEL32(SetFileCompletionNotificationModes, pSetFileCompletionNotificationModes);
|
||||
|
||||
@ -287,8 +395,7 @@ static Status waio_Shutdown()
|
||||
if(waio_initState == 0) // we were never initialized
|
||||
return INFO::OK;
|
||||
|
||||
for(size_t i = 0; i < ARRAY_SIZE(fileControlBlocks); i++)
|
||||
fileControlBlocks[i].Shutdown();
|
||||
fileControlBlocks.Shutdown();
|
||||
|
||||
WARN_IF_FALSE(CloseHandle(hIOCP));
|
||||
|
||||
@ -296,129 +403,51 @@ static Status waio_Shutdown()
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// OpenFile
|
||||
|
||||
static DWORD DesiredAccess(int oflag)
|
||||
{
|
||||
switch(oflag & (O_RDONLY|O_WRONLY|O_RDWR))
|
||||
{
|
||||
case O_RDONLY:
|
||||
// (WinXP x64 requires FILE_WRITE_ATTRIBUTES for SetFileCompletionNotificationModes)
|
||||
return GENERIC_READ|FILE_WRITE_ATTRIBUTES;
|
||||
case O_WRONLY:
|
||||
return GENERIC_WRITE;
|
||||
case O_RDWR:
|
||||
return GENERIC_READ|GENERIC_WRITE;
|
||||
default:
|
||||
DEBUG_WARN_ERR(ERR::INVALID_PARAM);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD ShareMode(int oflag)
|
||||
{
|
||||
switch(oflag & (O_RDONLY|O_WRONLY|O_RDWR))
|
||||
{
|
||||
case O_RDONLY:
|
||||
return FILE_SHARE_READ;
|
||||
case O_WRONLY:
|
||||
return FILE_SHARE_WRITE;
|
||||
case O_RDWR:
|
||||
return FILE_SHARE_READ|FILE_SHARE_WRITE;
|
||||
default:
|
||||
DEBUG_WARN_ERR(ERR::INVALID_PARAM);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD CreationDisposition(int oflag)
|
||||
{
|
||||
if(oflag & O_CREAT)
|
||||
return (oflag & O_EXCL)? CREATE_NEW : CREATE_ALWAYS;
|
||||
|
||||
if(oflag & O_TRUNC)
|
||||
return TRUNCATE_EXISTING;
|
||||
|
||||
return OPEN_EXISTING;
|
||||
}
|
||||
|
||||
static DWORD FlagsAndAttributes()
|
||||
{
|
||||
// - FILE_FLAG_SEQUENTIAL_SCAN is ignored when FILE_FLAG_NO_BUFFERING
|
||||
// is set (c.f. "Windows via C/C++", p. 324)
|
||||
// - FILE_FLAG_WRITE_THROUGH is ~5% slower (diskspd.cpp suggests it
|
||||
// disables hardware caching; the overhead may also be due to the
|
||||
// Windows cache manager)
|
||||
const DWORD flags = FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING;
|
||||
const DWORD attributes = FILE_ATTRIBUTE_NORMAL;
|
||||
return flags|attributes;
|
||||
}
|
||||
|
||||
static Status OpenFile(const OsPath& pathname, int oflag, HANDLE& hFile)
|
||||
{
|
||||
WinScopedPreserveLastError s;
|
||||
|
||||
const DWORD access = DesiredAccess(oflag);
|
||||
const DWORD share = ShareMode(oflag);
|
||||
const DWORD create = CreationDisposition(oflag);
|
||||
const DWORD flags = FlagsAndAttributes();
|
||||
hFile = CreateFileW(OsString(pathname).c_str(), access, share, 0, create, flags, 0);
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
WARN_RETURN(StatusFromWin());
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Windows-only APIs
|
||||
|
||||
Status waio_reopen(int fd, const OsPath& pathname, int oflag, ...)
|
||||
Status waio_open(const OsPath& pathname, int oflag, ...)
|
||||
{
|
||||
ENSURE(fd > 2);
|
||||
ASSERT(oflag & O_DIRECT);
|
||||
ENSURE(!(oflag & O_APPEND)); // not supported
|
||||
|
||||
if(oflag & O_NO_AIO_NP)
|
||||
return INFO::SKIPPED;
|
||||
|
||||
RETURN_STATUS_IF_ERR(ModuleInit(&waio_initState, waio_Init));
|
||||
|
||||
HANDLE hFile;
|
||||
RETURN_STATUS_IF_ERR(OpenFile(pathname, oflag, hFile));
|
||||
|
||||
if(!AssociateFileControlBlock(fd, hFile))
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
FileControlBlock* fcb = fileControlBlocks.Allocate();
|
||||
if(!fcb)
|
||||
WARN_RETURN(ERR::LIMIT);
|
||||
}
|
||||
|
||||
return INFO::OK;
|
||||
RETURN_STATUS_IF_ERR(fcb->Open(pathname, oflag));
|
||||
return (Status)fileControlBlocks.Descriptor(fcb);
|
||||
}
|
||||
|
||||
|
||||
Status waio_close(int fd)
|
||||
{
|
||||
FileControlBlock* fcb = FindFileControlBlock(fd);
|
||||
FileControlBlock* fcb = fileControlBlocks.FromDescriptor(fd);
|
||||
if(!fcb)
|
||||
WARN_RETURN(ERR::INVALID_HANDLE);
|
||||
const HANDLE hFile = fcb->hFile;
|
||||
return ERR::INVALID_HANDLE; // NOWARN - fd might be from lowio
|
||||
|
||||
DissociateFileControlBlock(fcb);
|
||||
|
||||
if(!CloseHandle(hFile))
|
||||
WARN_RETURN(ERR::INVALID_HANDLE);
|
||||
|
||||
return INFO::OK;
|
||||
Status ret = fcb->Close();
|
||||
fileControlBlocks.Deallocate(fcb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Status waio_Preallocate(int fd, off_t size)
|
||||
{
|
||||
FileControlBlock* fcb = FindFileControlBlock(fd);
|
||||
if(!fcb)
|
||||
WARN_RETURN(ERR::INVALID_HANDLE);
|
||||
const HANDLE hFile = fcb->hFile;
|
||||
HANDLE hFile; // from FileControlBlock OR lowio
|
||||
{
|
||||
FileControlBlock* fcb = fileControlBlocks.FromDescriptor(fd);
|
||||
if(fcb)
|
||||
hFile = fcb->hFile;
|
||||
else
|
||||
{
|
||||
hFile = (HANDLE)_get_osfhandle(fd);
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
WARN_RETURN(ERR::INVALID_HANDLE);
|
||||
}
|
||||
}
|
||||
|
||||
// Windows requires sector alignment (see discussion in header)
|
||||
const off_t alignedSize = round_up(size, (off_t)maxSectorSize); // (Align<> cannot compute off_t)
|
||||
@ -460,16 +489,15 @@ static int Issue(aiocb* cb)
|
||||
ENSURE(IsAligned(cb->aio_buf, maxSectorSize));
|
||||
ENSURE(IsAligned(cb->aio_nbytes, maxSectorSize));
|
||||
|
||||
FileControlBlock* fcb = FindFileControlBlock(cb->aio_fildes);
|
||||
if(!fcb || fcb->hFile == INVALID_HANDLE_VALUE)
|
||||
FileControlBlock* fcb = fileControlBlocks.FromDescriptor(cb->aio_fildes);
|
||||
if(!fcb)
|
||||
{
|
||||
DEBUG_WARN_ERR(ERR::INVALID_HANDLE);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ENSURE(!cb->fcb && !cb->ovl); // SUSv3: aiocb must not be in use
|
||||
cb->fcb = fcb;
|
||||
ENSURE(!cb->ovl); // SUSv3: aiocb must not be in use
|
||||
cb->ovl = fcb->ovl.Allocate(cb->aio_offset);
|
||||
if(!cb->ovl)
|
||||
{
|
||||
@ -610,7 +638,7 @@ int aio_error(const struct aiocb* cb)
|
||||
|
||||
ssize_t aio_return(struct aiocb* cb)
|
||||
{
|
||||
FileControlBlock* fcb = (FileControlBlock*)cb->fcb;
|
||||
FileControlBlock* fcb = fileControlBlocks.FromDescriptor(cb->aio_fildes);
|
||||
OVERLAPPED* ovl = (OVERLAPPED*)cb->ovl;
|
||||
if(!fcb || !ovl)
|
||||
{
|
||||
@ -624,27 +652,25 @@ ssize_t aio_return(struct aiocb* cb)
|
||||
cb->ovl = 0; // prevent further calls to aio_error/aio_return
|
||||
COMPILER_FENCE;
|
||||
fcb->ovl.Deallocate(ovl);
|
||||
cb->fcb = 0; // allow reuse
|
||||
|
||||
return (status == ERROR_SUCCESS)? bytesTransferred : -1;
|
||||
}
|
||||
|
||||
|
||||
int aio_cancel(int UNUSED(fd), struct aiocb* cb)
|
||||
// Win32 limitation: cancel all I/Os this thread issued for the given file
|
||||
// (CancelIoEx can cancel individual operations, but is only
|
||||
// available starting with Vista)
|
||||
int aio_cancel(int fd, struct aiocb* UNUSED(cb))
|
||||
{
|
||||
// (faster than calling FindFileControlBlock)
|
||||
const HANDLE hFile = ((const FileControlBlock*)cb->fcb)->hFile;
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
FileControlBlock* fcb = fileControlBlocks.FromDescriptor(fd);
|
||||
if(!fcb)
|
||||
{
|
||||
WARN_IF_ERR(ERR::INVALID_HANDLE);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// cancel all I/Os this thread issued for the given file
|
||||
// (CancelIoEx can cancel individual operations, but is only
|
||||
// available starting with Vista)
|
||||
WARN_IF_FALSE(CancelIo(hFile));
|
||||
WARN_IF_FALSE(CancelIo(fcb->hFile));
|
||||
|
||||
return AIO_CANCELED;
|
||||
}
|
||||
|
@ -71,9 +71,8 @@ struct aiocb
|
||||
int aio_lio_opcode; // Operation to be performed.
|
||||
|
||||
// internal use only; must be zero-initialized before
|
||||
// calling the first aio_read/aio_write/lio_listio (aio_return also
|
||||
// zero-initializes them)
|
||||
void* fcb;
|
||||
// calling the first aio_read/aio_write/lio_listio
|
||||
// (aio_return resets it to 0)
|
||||
void* ovl;
|
||||
};
|
||||
|
||||
@ -113,23 +112,20 @@ extern int aio_cancel(int, struct aiocb*);
|
||||
|
||||
extern int aio_fsync(int, struct aiocb*);
|
||||
|
||||
// Windows doesn't allow aio unless the file is opened in asynchronous mode,
|
||||
// which is not possible with _wsopen_s. since we don't want to have to
|
||||
// provide a separate File class for aio-enabled files, our wopen wrapper
|
||||
// will also call this function to open a SECOND handle to the file (works
|
||||
// because CRT open() defaults to DENY_NONE sharing). the CRT's lowio
|
||||
// descriptor table remains unaffected, but our [w]aio_* functions are
|
||||
// notified of the file descriptor, which means e.g. read and aio_read can
|
||||
// both be used. this function must have been called before any
|
||||
// other [w]aio_* functions are used.
|
||||
extern Status waio_reopen(int fd, const OsPath& pathname, int oflag, ...);
|
||||
// open the file for aio (not possible via _wsopen_s since it cannot
|
||||
// set FILE_FLAG_NO_BUFFERING).
|
||||
//
|
||||
// @return the smallest available file descriptor. NB: these numbers
|
||||
// are not 0-based to avoid confusion with lowio descriptors and
|
||||
// must only be used with waio functions.
|
||||
extern Status waio_open(const OsPath& pathname, int oflag, ...);
|
||||
|
||||
// close our second aio-enabled handle to the file (called from wclose).
|
||||
extern Status waio_close(int fd);
|
||||
|
||||
// call this before writing a large file to preallocate clusters, thus
|
||||
// reducing fragmentation.
|
||||
//
|
||||
// @param fd file descriptor from _wsopen_s OR waio_open
|
||||
// @param size is rounded up to a multiple of maxSectorSize (required by
|
||||
// SetEndOfFile; this could be avoided by using the undocumented
|
||||
// NtSetInformationFile or SetFileInformationByHandle on Vista and later).
|
||||
@ -140,9 +136,8 @@ extern Status waio_close(int fd);
|
||||
// (http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B156932)
|
||||
// if Windows XP and the SE_MANAGE_VOLUME_NAME privileges are available,
|
||||
// this function sets the valid data length to avoid the synchronous zero-fill.
|
||||
// note that this exposes the previous disk contents (possibly even to
|
||||
// other users since the waio_reopen design cannot deny file sharing) until
|
||||
// the application successfully writes to the file.
|
||||
// to avoid exposing the previous disk contents until the application
|
||||
// successfully writes to the file, deny sharing when opening the file.
|
||||
LIB_API Status waio_Preallocate(int fd, off_t size);
|
||||
|
||||
#endif // #ifndef INCLUDED_WAIO
|
||||
|
@ -207,41 +207,49 @@ int wclosedir(WDIR* d)
|
||||
|
||||
int wopen(const OsPath& pathname, int oflag)
|
||||
{
|
||||
ENSURE(!(oflag & O_CREAT));
|
||||
ENSURE(!(oflag & O_CREAT)); // must specify mode_arg if O_CREAT
|
||||
return wopen(OsString(pathname).c_str(), oflag, _S_IREAD|_S_IWRITE);
|
||||
}
|
||||
|
||||
int wopen(const OsPath& pathname, int oflag, mode_t mode_arg)
|
||||
|
||||
int wopen(const OsPath& pathname, int oflag, mode_t mode)
|
||||
{
|
||||
mode_t mode = _S_IREAD|_S_IWRITE;
|
||||
if(oflag & O_CREAT)
|
||||
mode = mode_arg;
|
||||
|
||||
WinScopedPreserveLastError s; // _wsopen_s's CreateFileW
|
||||
int fd;
|
||||
errno_t ret = _wsopen_s(&fd, OsString(pathname).c_str(), oflag, _SH_DENYNO, mode);
|
||||
if(ret != 0)
|
||||
if(oflag & O_DIRECT)
|
||||
{
|
||||
errno = ret;
|
||||
return -1; // NOWARN
|
||||
Status ret = waio_open(pathname, oflag);
|
||||
if(ret < 0)
|
||||
{
|
||||
errno = ErrnoFromStatus(ret);
|
||||
return -1;
|
||||
}
|
||||
return (int)ret; // file descriptor
|
||||
}
|
||||
else
|
||||
{
|
||||
WinScopedPreserveLastError s; // _wsopen_s's CreateFileW
|
||||
int fd;
|
||||
oflag |= _O_BINARY;
|
||||
if(oflag & O_WRONLY)
|
||||
oflag |= O_CREAT|O_TRUNC;
|
||||
// NB: _wsopen_s ignores mode unless oflag & O_CREAT
|
||||
errno_t ret = _wsopen_s(&fd, OsString(pathname).c_str(), oflag, _SH_DENYRD, mode);
|
||||
if(ret != 0)
|
||||
{
|
||||
errno = ret;
|
||||
return -1; // NOWARN
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
if(waio_reopen(fd, pathname, oflag) != INFO::OK)
|
||||
return -1;
|
||||
|
||||
ASSERT(fd < 256); // CRT limitation
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
int wclose(int fd)
|
||||
{
|
||||
ENSURE(3 <= fd && fd < 256);
|
||||
ENSURE(fd >= 3); // not invalid nor stdin/out/err
|
||||
|
||||
(void)waio_close(fd); // no-op if fd wasn't opened for aio
|
||||
|
||||
return _close(fd);
|
||||
if(waio_close(fd) != 0)
|
||||
return _close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -53,6 +53,15 @@ typedef unsigned int mode_t; // defined by MinGW but not VC
|
||||
#define S_ISREG(m) (m & S_IFREG)
|
||||
|
||||
|
||||
//
|
||||
// <fcntl.h>
|
||||
|
||||
// transfer directly to/from user's buffer.
|
||||
// treated as a request to enable aio (see filesystem.h).
|
||||
// value does not conflict with any current Win32 _O_* flags.
|
||||
#define O_DIRECT 0x10000000
|
||||
|
||||
|
||||
//
|
||||
// <unistd.h>
|
||||
//
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "graphics/TextureManager.h"
|
||||
#include "lib/tex/tex_codec.h"
|
||||
#include "lib/file/archive/archive_zip.h"
|
||||
#include "lib/file/vfs/vfs_util.h"
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
|
||||
// Disable "'boost::algorithm::detail::is_classifiedF' : assignment operator could not be generated"
|
||||
@ -45,7 +46,7 @@ CArchiveBuilder::CArchiveBuilder(const OsPath& mod, const OsPath& tempdir) :
|
||||
m_VFS->Mount(L"", mod/"", VFS_MOUNT_MUST_EXIST);
|
||||
|
||||
// Collect the list of files before loading any base mods
|
||||
fs_util::ForEachFile(m_VFS, L"", &CollectFileCB, (uintptr_t)static_cast<void*>(this), 0, fs_util::DIR_RECURSIVE);
|
||||
vfs::ForEachFile(m_VFS, L"", &CollectFileCB, (uintptr_t)static_cast<void*>(this), 0, vfs::DIR_RECURSIVE);
|
||||
}
|
||||
|
||||
CArchiveBuilder::~CArchiveBuilder()
|
||||
|
@ -18,7 +18,7 @@
|
||||
#ifndef INCLUDED_ARCHIVEBUILDER
|
||||
#define INCLUDED_ARCHIVEBUILDER
|
||||
|
||||
#include "lib/file/file_system_util.h"
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
#include "ps/CStr.h"
|
||||
|
||||
/**
|
||||
|
@ -29,14 +29,9 @@ PIVFS g_VFS;
|
||||
|
||||
static std::vector<std::pair<FileReloadFunc, void*> > g_ReloadFuncs;
|
||||
|
||||
bool VfsFileExists(const PIVFS& vfs, const VfsPath& pathname)
|
||||
{
|
||||
return vfs->GetFileInfo(pathname, 0) == INFO::OK;
|
||||
}
|
||||
|
||||
bool VfsFileExists(const VfsPath& pathname)
|
||||
{
|
||||
return VfsFileExists(g_VFS, pathname);
|
||||
return g_VFS->GetFileInfo(pathname, 0) == INFO::OK;
|
||||
}
|
||||
|
||||
void RegisterFileReloadFunc(FileReloadFunc func, void* obj)
|
||||
|
@ -20,17 +20,14 @@
|
||||
|
||||
#include "lib/file/file.h"
|
||||
#include "lib/file/io/io.h"
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
#include "lib/file/file_system_util.h"
|
||||
#include "lib/file/io/write_buffer.h"
|
||||
#include "lib/file/vfs/vfs_util.h"
|
||||
|
||||
#include "ps/CStr.h"
|
||||
#include "ps/Errors.h"
|
||||
|
||||
extern PIVFS g_VFS;
|
||||
|
||||
extern bool VfsFileExists(const PIVFS& vfs, const VfsPath& pathname);
|
||||
|
||||
extern bool VfsFileExists(const VfsPath& pathname);
|
||||
|
||||
/**
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "precompiled.h"
|
||||
#include "Paths.h"
|
||||
|
||||
#include "lib/file/file_system_util.h"
|
||||
#include "lib/file/file_system.h"
|
||||
#include "lib/sysdep/sysdep.h" // sys_get_executable_name
|
||||
#include "lib/sysdep/filesystem.h" // wrealpath
|
||||
#if OS_WIN
|
||||
@ -83,7 +83,7 @@ Paths::Paths(const CmdLineArgs& args)
|
||||
}
|
||||
|
||||
// make sure it's valid
|
||||
if(!fs_util::FileExists(pathname))
|
||||
if(!FileExists(pathname))
|
||||
WARN_IF_ERR(StatusFromErrno());
|
||||
|
||||
for(size_t i = 0; i < 2; i++) // remove "system/name.exe"
|
||||
|
@ -233,7 +233,7 @@ void WriteScreenshot(const VfsPath& extension)
|
||||
const VfsPath basenameFormat(L"screenshots/screenshot%04d");
|
||||
const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension);
|
||||
VfsPath filename;
|
||||
fs_util::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename);
|
||||
vfs::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename);
|
||||
|
||||
const size_t w = (size_t)g_xres, h = (size_t)g_yres;
|
||||
const size_t bpp = 24;
|
||||
@ -287,7 +287,7 @@ void WriteBigScreenshot(const VfsPath& extension, int tiles)
|
||||
const VfsPath basenameFormat(L"screenshots/screenshot%04d");
|
||||
const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension);
|
||||
VfsPath filename;
|
||||
fs_util::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename);
|
||||
vfs::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename);
|
||||
|
||||
// Slightly ugly and inflexible: Always draw 640*480 tiles onto the screen, and
|
||||
// hope the screen is actually large enough for that.
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "scripting/ScriptingHost.h"
|
||||
#include "scripting/JSConversions.h"
|
||||
#include "ps/scripting/JSInterface_VFS.h"
|
||||
#include "lib/file/vfs/vfs_util.h"
|
||||
|
||||
// shared error handling code
|
||||
#define JS_CHECK_FILE_ERR(err)\
|
||||
@ -115,12 +116,12 @@ JSBool JSI_VFS::BuildDirEntList(JSContext* cx, uintN argc, jsval* vp)
|
||||
if (!ToPrimitive<bool> (cx, JS_ARGV(cx, vp)[2], recursive))
|
||||
return JS_FALSE;
|
||||
}
|
||||
int flags = recursive ? fs_util::DIR_RECURSIVE : 0;
|
||||
int flags = recursive ? vfs::DIR_RECURSIVE : 0;
|
||||
|
||||
|
||||
// build array in the callback function
|
||||
BuildDirEntListState state(cx);
|
||||
fs_util::ForEachFile(g_VFS, path, BuildDirEntListCB, (uintptr_t)&state, filter, flags);
|
||||
vfs::ForEachFile(g_VFS, path, BuildDirEntListCB, (uintptr_t)&state, filter, flags);
|
||||
|
||||
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(state.filename_array));
|
||||
return JS_TRUE;
|
||||
|
@ -825,7 +825,7 @@ bool ScriptInterface::LoadGlobalScript(const VfsPath& filename, const std::wstri
|
||||
|
||||
bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path)
|
||||
{
|
||||
if (!VfsFileExists(g_VFS, path))
|
||||
if (!VfsFileExists(path))
|
||||
{
|
||||
LOGERROR(L"File '%ls' does not exist", path.string().c_str());
|
||||
return false;
|
||||
@ -911,7 +911,7 @@ CScriptValRooted ScriptInterface::ParseJSON(const std::string& string_utf8)
|
||||
|
||||
CScriptValRooted ScriptInterface::ReadJSONFile(const VfsPath& path)
|
||||
{
|
||||
if (!VfsFileExists(g_VFS, path))
|
||||
if (!VfsFileExists(path))
|
||||
{
|
||||
LOGERROR(L"File '%ls' does not exist", path.string().c_str());
|
||||
return CScriptValRooted();
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "simulation2/components/ICmpTemplateManager.h"
|
||||
|
||||
#include "lib/timer.h"
|
||||
#include "lib/file/file_system_util.h"
|
||||
#include "lib/file/vfs/vfs_util.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
@ -142,7 +142,7 @@ public:
|
||||
bool CSimulation2Impl::LoadScripts(const VfsPath& path)
|
||||
{
|
||||
VfsPaths pathnames;
|
||||
if (fs_util::GetPathnames(g_VFS, path, L"*.js", pathnames) < 0)
|
||||
if (vfs::GetPathnames(g_VFS, path, L"*.js", pathnames) < 0)
|
||||
return false;
|
||||
|
||||
bool ok = true;
|
||||
@ -526,7 +526,7 @@ std::vector<std::string> CSimulation2::GetRMSData()
|
||||
std::vector<std::string> data;
|
||||
|
||||
// Find all ../maps/random/*.json
|
||||
Status ret = fs_util::GetPathnames(g_VFS, path, L"*.json", pathnames);
|
||||
Status ret = vfs::GetPathnames(g_VFS, path, L"*.json", pathnames);
|
||||
if (ret == INFO::OK)
|
||||
{
|
||||
for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it)
|
||||
@ -562,7 +562,7 @@ std::vector<std::string> CSimulation2::GetCivData()
|
||||
std::vector<std::string> data;
|
||||
|
||||
// Load all JSON files in civs directory
|
||||
Status ret = fs_util::GetPathnames(g_VFS, path, L"*.json", pathnames);
|
||||
Status ret = vfs::GetPathnames(g_VFS, path, L"*.json", pathnames);
|
||||
if (ret == INFO::OK)
|
||||
{
|
||||
for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it)
|
||||
@ -596,7 +596,7 @@ std::string CSimulation2::GetPlayerDefaults()
|
||||
|
||||
std::string data;
|
||||
|
||||
if (!VfsFileExists(g_VFS, path))
|
||||
if (!VfsFileExists(path))
|
||||
{
|
||||
LOGERROR(L"File '%ls' does not exist", path.string().c_str());
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ private:
|
||||
|
||||
// Load and execute *.js
|
||||
VfsPaths pathnames;
|
||||
fs_util::GetPathnames(g_VFS, L"simulation/ai/" + moduleName + L"/", L"*.js", pathnames);
|
||||
vfs::GetPathnames(g_VFS, L"simulation/ai/" + moduleName + L"/", L"*.js", pathnames);
|
||||
for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it)
|
||||
{
|
||||
if (!m_ScriptInterface.LoadGlobalScriptFile(*it))
|
||||
|
@ -414,13 +414,13 @@ std::vector<std::string> CCmpTemplateManager::FindAllTemplates(bool includeActor
|
||||
Status ok;
|
||||
|
||||
// Find all the normal entity templates first
|
||||
ok = fs_util::ForEachFile(g_VFS, TEMPLATE_ROOT, AddToTemplates, (uintptr_t)&templates, L"*.xml", fs_util::DIR_RECURSIVE);
|
||||
ok = vfs::ForEachFile(g_VFS, TEMPLATE_ROOT, AddToTemplates, (uintptr_t)&templates, L"*.xml", vfs::DIR_RECURSIVE);
|
||||
WARN_IF_ERR(ok);
|
||||
|
||||
if (includeActors)
|
||||
{
|
||||
// Add all the actors too
|
||||
ok = fs_util::ForEachFile(g_VFS, ACTOR_ROOT, AddActorToTemplates, (uintptr_t)&templates, L"*.xml", fs_util::DIR_RECURSIVE);
|
||||
ok = vfs::ForEachFile(g_VFS, ACTOR_ROOT, AddActorToTemplates, (uintptr_t)&templates, L"*.xml", vfs::DIR_RECURSIVE);
|
||||
WARN_IF_ERR(ok);
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
#include "simulation2/system/InterfaceScripted.h"
|
||||
|
||||
#include "lib/file/file_system_util.h"
|
||||
#include "lib/file/vfs/vfs_util.h"
|
||||
#include "ps/Filesystem.h"
|
||||
|
||||
BEGIN_INTERFACE_WRAPPER(AIManager)
|
||||
@ -42,7 +42,7 @@ public:
|
||||
|
||||
void Run()
|
||||
{
|
||||
fs_util::ForEachFile(g_VFS, L"simulation/ai/", Callback, (uintptr_t)this, L"*.json", fs_util::DIR_RECURSIVE);
|
||||
vfs::ForEachFile(g_VFS, L"simulation/ai/", Callback, (uintptr_t)this, L"*.json", vfs::DIR_RECURSIVE);
|
||||
}
|
||||
|
||||
static Status Callback(const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), const uintptr_t cbData)
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
}
|
||||
|
||||
VfsPaths paths;
|
||||
TS_ASSERT_OK(fs_util::GetPathnames(g_VFS, L"simulation/components/tests/", L"test_*.js", paths));
|
||||
TS_ASSERT_OK(vfs::GetPathnames(g_VFS, L"simulation/components/tests/", L"test_*.js", paths));
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
{
|
||||
CSimContext context;
|
||||
|
Loading…
Reference in New Issue
Block a user