fix handling of non-CP1252 characters in paths
(added wide-character versions of posix opendir etc. - on Windows, we must not convert to UTF8) This was SVN commit r7243.
This commit is contained in:
parent
33ab686128
commit
97db62c944
@ -539,13 +539,13 @@ public:
|
||||
|
||||
(void)pool_destroy(&m_cdfhPool);
|
||||
|
||||
const fs::path pathname = path_from_wpath(m_file->Pathname()); // for truncate()
|
||||
const fs::wpath pathname = m_file->Pathname(); // for truncate()
|
||||
m_file.reset();
|
||||
|
||||
m_fileSize += off_t(cd_size+sizeof(ECDR));
|
||||
|
||||
// remove padding added by UnalignedWriter
|
||||
truncate(pathname.string().c_str(), m_fileSize);
|
||||
wtruncate(pathname.string().c_str(), m_fileSize);
|
||||
}
|
||||
|
||||
LibError AddFile(const fs::wpath& pathname)
|
||||
|
@ -67,8 +67,7 @@ LibError RealDirectory::Store(const std::wstring& name, const shared_ptr<u8>& fi
|
||||
// length. ftruncate can't be used because Windows' FILE_FLAG_NO_BUFFERING
|
||||
// only allows resizing to sector boundaries, so the file must first
|
||||
// be closed.
|
||||
const fs::path pathname_c(path_from_wpath(pathname));
|
||||
truncate(pathname_c.string().c_str(), size);
|
||||
wtruncate(pathname.string().c_str(), size);
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ LibError Open(const fs::wpath& pathname, wchar_t mode, int& fd)
|
||||
#if OS_WIN
|
||||
oflag |= O_BINARY_NP;
|
||||
#endif
|
||||
fd = sys_wopen(pathname.string().c_str(), oflag, S_IRWXO|S_IRWXU|S_IRWXG);
|
||||
fd = wopen(pathname.string().c_str(), oflag, S_IRWXO|S_IRWXU|S_IRWXG);
|
||||
if(fd < 0)
|
||||
WARN_RETURN(ERR::FILE_ACCESS);
|
||||
|
||||
@ -65,7 +65,7 @@ void Close(int& fd)
|
||||
{
|
||||
if(fd)
|
||||
{
|
||||
close(fd);
|
||||
wclose(fd);
|
||||
fd = 0;
|
||||
}
|
||||
}
|
||||
|
@ -29,9 +29,9 @@
|
||||
|
||||
struct DirDeleter
|
||||
{
|
||||
void operator()(DIR* osDir) const
|
||||
void operator()(WDIR* osDir) const
|
||||
{
|
||||
const int ret = closedir(osDir);
|
||||
const int ret = wclosedir(osDir);
|
||||
debug_assert(ret == 0);
|
||||
}
|
||||
};
|
||||
@ -46,19 +46,17 @@ static bool IsDummyDirectory(const std::wstring& name)
|
||||
|
||||
LibError GetDirectoryEntries(const fs::wpath& path, FileInfos* files, DirectoryNames* subdirectoryNames)
|
||||
{
|
||||
fs::path path_c = path_from_wpath(path);
|
||||
|
||||
// open directory
|
||||
errno = 0;
|
||||
DIR* pDir = opendir(path_c.string().c_str());
|
||||
WDIR* pDir = wopendir(path.string().c_str());
|
||||
if(!pDir)
|
||||
return LibError_from_errno(false);
|
||||
shared_ptr<DIR> osDir(pDir, DirDeleter());
|
||||
shared_ptr<WDIR> osDir(pDir, DirDeleter());
|
||||
|
||||
for(;;)
|
||||
{
|
||||
errno = 0;
|
||||
struct dirent* osEnt = readdir(osDir.get());
|
||||
struct wdirent* osEnt = wreaddir(osDir.get());
|
||||
if(!osEnt)
|
||||
{
|
||||
// no error, just no more entries to return
|
||||
@ -67,21 +65,19 @@ LibError GetDirectoryEntries(const fs::wpath& path, FileInfos* files, DirectoryN
|
||||
return LibError_from_errno();
|
||||
}
|
||||
|
||||
const std::wstring name = wstring_from_utf8(osEnt->d_name);
|
||||
const std::wstring name(osEnt->d_name);
|
||||
RETURN_ERR(path_component_validate(name.c_str()));
|
||||
|
||||
// get file information (mode, size, mtime)
|
||||
struct stat s;
|
||||
#if OS_WIN
|
||||
// .. wposix readdir has enough information to return dirent
|
||||
// status directly (much faster than calling stat).
|
||||
RETURN_ERR(readdir_stat_np(osDir.get(), &s));
|
||||
// .. return wdirent directly (much faster than calling stat).
|
||||
RETURN_ERR(wreaddir_stat_np(osDir.get(), &s));
|
||||
#else
|
||||
// .. call regular stat().
|
||||
errno = 0;
|
||||
const fs::wpath pathname(path/name);
|
||||
const fs::path pathname_c = path_from_wpath(pathname);
|
||||
if(stat(pathname_c.string().c_str(), &s) != 0)
|
||||
if(wstat(pathname.string().c_str(), &s) != 0)
|
||||
return LibError_from_errno();
|
||||
#endif
|
||||
|
||||
@ -95,11 +91,10 @@ LibError GetDirectoryEntries(const fs::wpath& path, FileInfos* files, DirectoryN
|
||||
|
||||
LibError GetFileInfo(const fs::wpath& pathname, FileInfo* pfileInfo)
|
||||
{
|
||||
fs::path pathname_c = path_from_wpath(pathname);
|
||||
errno = 0;
|
||||
struct stat s;
|
||||
memset(&s, 0, sizeof(s));
|
||||
if(stat(pathname_c.string().c_str(), &s) != 0)
|
||||
if(wstat(pathname.string().c_str(), &s) != 0)
|
||||
return LibError_from_errno();
|
||||
|
||||
*pfileInfo = FileInfo(pathname.leaf(), s.st_size, s.st_mtime);
|
||||
@ -123,9 +118,8 @@ LibError CreateDirectories(const fs::wpath& path, mode_t mode)
|
||||
|
||||
RETURN_ERR(CreateDirectories(path.branch_path(), mode));
|
||||
|
||||
const fs::path path_c = path_from_wpath(path);
|
||||
errno = 0;
|
||||
if(mkdir(path_c.string().c_str(), mode) != 0)
|
||||
if(wmkdir(path.string().c_str(), mode) != 0)
|
||||
return LibError_from_errno();
|
||||
|
||||
return INFO::OK;
|
||||
@ -144,9 +138,8 @@ LibError DeleteDirectory(const fs::wpath& path)
|
||||
for(size_t i = 0; i < files.size(); i++)
|
||||
{
|
||||
const fs::wpath pathname(path/files[i].Name());
|
||||
const fs::path pathname_c = path_from_wpath(pathname);
|
||||
errno = 0;
|
||||
if(unlink(pathname_c.string().c_str()) != 0)
|
||||
if(wunlink(pathname.string().c_str()) != 0)
|
||||
return LibError_from_errno();
|
||||
}
|
||||
|
||||
@ -154,9 +147,8 @@ LibError DeleteDirectory(const fs::wpath& path)
|
||||
for(size_t i = 0; i < subdirectoryNames.size(); i++)
|
||||
RETURN_ERR(DeleteDirectory(path/subdirectoryNames[i]));
|
||||
|
||||
const fs::path path_c = path_from_wpath(path);
|
||||
errno = 0;
|
||||
if(rmdir(path_c.string().c_str()) != 0)
|
||||
if(wrmdir(path.string().c_str()) != 0)
|
||||
return LibError_from_errno();
|
||||
|
||||
return INFO::OK;
|
||||
|
@ -69,8 +69,7 @@ LibError vfs_Lookup(const VfsPath& pathname, VfsDirectory* startDirectory, VfsDi
|
||||
currentPath = directory->AssociatedDirectory()->Path();
|
||||
currentPath /= subdirectoryName;
|
||||
|
||||
fs::path currentPath_c = path_from_wpath(currentPath);
|
||||
const int ret = mkdir(currentPath_c.string().c_str(), S_IRWXU);
|
||||
const int ret = wmkdir(currentPath.string().c_str(), S_IRWXU);
|
||||
if(ret == 0)
|
||||
{
|
||||
PRealDirectory realDirectory(new RealDirectory(currentPath, 0, 0));
|
||||
|
@ -24,3 +24,5 @@
|
||||
#endif
|
||||
|
||||
#include "posix_errno.h" // for user convenience
|
||||
|
||||
#include "lib/sysdep/filesystem.h"
|
||||
|
100
source/lib/sysdep/filesystem.h
Normal file
100
source/lib/sysdep/filesystem.h
Normal file
@ -0,0 +1,100 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* wchar_t versions of POSIX filesystem functions
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_FILESYSTEM
|
||||
#define INCLUDED_FILESYSTEM
|
||||
|
||||
|
||||
//
|
||||
// dirent.h
|
||||
//
|
||||
|
||||
struct WDIR;
|
||||
|
||||
struct wdirent
|
||||
{
|
||||
// note: SUSv3 describes this as a "char array" but of unspecified size.
|
||||
// since that precludes using sizeof(), we may as well declare as a
|
||||
// pointer to avoid copying in the implementation.
|
||||
wchar_t* d_name;
|
||||
};
|
||||
|
||||
extern WDIR* wopendir(const wchar_t* path);
|
||||
|
||||
extern struct wdirent* wreaddir(WDIR*);
|
||||
|
||||
// return status for the file returned by the last successful
|
||||
// wreaddir call from the given directory stream.
|
||||
// currently sets st_size, st_mode, and st_mtime; the rest are zeroed.
|
||||
// non-portable, but considerably faster than stat(). used by dir_ForEachSortedEntry.
|
||||
extern int wreaddir_stat_np(WDIR*, struct stat*);
|
||||
|
||||
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
|
||||
|
||||
// POSIX flags not supported by the underlying Win32 _wsopen_s:
|
||||
#define O_NONBLOCK 0x1000000
|
||||
|
||||
extern int wopen(const wchar_t* pathname, int oflag, ...);
|
||||
extern int wclose(int fd);
|
||||
|
||||
|
||||
//
|
||||
// unistd.h
|
||||
//
|
||||
|
||||
LIB_API int wtruncate(const wchar_t* pathname, off_t length);
|
||||
|
||||
LIB_API int wunlink(const wchar_t* pathname);
|
||||
|
||||
LIB_API int wrmdir(const wchar_t* path);
|
||||
|
||||
|
||||
//
|
||||
// stdlib.h
|
||||
//
|
||||
|
||||
LIB_API wchar_t* wrealpath(const wchar_t* pathname, wchar_t* resolved);
|
||||
|
||||
|
||||
//
|
||||
// sys/stat.h
|
||||
//
|
||||
|
||||
LIB_API int wstat(const wchar_t* pathname, struct stat* buf);
|
||||
|
||||
LIB_API int wmkdir(const wchar_t* path, mode_t mode);
|
||||
|
||||
#endif // #ifndef INCLUDED_FILESYSTEM
|
129
source/lib/sysdep/os/unix/ufilesystem.cpp
Normal file
129
source/lib/sysdep/os/unix/ufilesystem.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Unix implementation of wchar_t versions of POSIX filesystem functions
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "lib/posix/posix_filesystem.h"
|
||||
|
||||
#include "lib/wchar.h"
|
||||
#include "lib/path_util.h"
|
||||
|
||||
struct DIR;
|
||||
|
||||
struct WDIR
|
||||
{
|
||||
DIR* d;
|
||||
wchar_t name[300];
|
||||
wdirent ent;
|
||||
};
|
||||
|
||||
WDIR* wopendir(const wchar_t* path)
|
||||
{
|
||||
fs::path path_c(path_from_wpath(path));
|
||||
DIR* d = opendir(path_c.string().c_str());
|
||||
if(!d)
|
||||
return 0;
|
||||
WDIR* wd = new WDIR;
|
||||
wd->d = d;
|
||||
wd->name[0] = '\0';
|
||||
wd->ent.d_name = wd->name;
|
||||
return wd;
|
||||
}
|
||||
|
||||
struct wdirent* wreaddir(WDIR* wd)
|
||||
{
|
||||
dirent* ent = readdir(wd->d);
|
||||
if(!ent)
|
||||
return 0;
|
||||
std::wstring name = wstring_from_utf8(ent->d_name);
|
||||
wcscpy_s(wd->name, ARRAY_SIZE(wd->name), name.c_str());
|
||||
return &wd->ent;
|
||||
}
|
||||
|
||||
int wclosedir(WDIR* wd)
|
||||
{
|
||||
int ret = closedir(wd->d);
|
||||
delete wd;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int wopen(const wchar_t* pathname, int oflag, ...)
|
||||
{
|
||||
mode_t mode = S_IRWXG|S_IRWXO|S_IRWXU;
|
||||
if(oflag & O_CREAT)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, oflag);
|
||||
mode = va_arg(args, mode_t);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
fs::path pathname_c(path_from_wpath(pathname));
|
||||
return open(pathname_c.string().c_str(), oflag, mode);
|
||||
}
|
||||
|
||||
int wclose(int fd)
|
||||
{
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
|
||||
int wtruncate(const wchar_t* pathname, off_t length)
|
||||
{
|
||||
fs::path pathname_c(path_from_wpath(pathname));
|
||||
return truncate(pathname_c.string().c_str(), length);
|
||||
}
|
||||
|
||||
int wunlink(const wchar_t* pathname)
|
||||
{
|
||||
fs::path pathname_c(path_from_wpath(pathname));
|
||||
return unlink(pathname_c.string().c_str());
|
||||
}
|
||||
|
||||
int wrmdir(const wchar_t* path)
|
||||
{
|
||||
fs::path path_c(path_from_wpath(path));
|
||||
return rmdir(path_c.string().c_str());
|
||||
}
|
||||
|
||||
wchar_t* wrealpath(const wchar_t* pathname, wchar_t* resolved)
|
||||
{
|
||||
char resolved_buf[PATH_MAX];
|
||||
fs::path pathname_c(path_from_wpath(pathname));
|
||||
const char* resolved_c = realpath(pathname_c.string().c_str(), resolved_buf);
|
||||
if(!resolved_c)
|
||||
return 0;
|
||||
std::wstring resolved_s = wstring_from_utf8(resolved_c);
|
||||
wcscpy_s(resolved, PATH_MAX, resolved_s.c_str());
|
||||
return resolved;
|
||||
}
|
||||
|
||||
int wstat(const wchar_t* pathname, struct stat* buf)
|
||||
{
|
||||
fs::path pathname_c(path_from_wpath(pathname));
|
||||
return stat(pathname_c.string().c_str(), buf);
|
||||
}
|
||||
|
||||
int wmkdir(const wchar_t* path, mode_t mode)
|
||||
{
|
||||
fs::path path_c(path_from_wpath(path));
|
||||
return mkdir(path_c.string().c_str(), mode);
|
||||
}
|
@ -97,8 +97,28 @@ private:
|
||||
static HandleManager* handleManager;
|
||||
|
||||
|
||||
// do we want to open a second aio-capable handle?
|
||||
static bool IsAioPossible(int fd, bool is_com_port, int oflag)
|
||||
{
|
||||
// stdin/stdout/stderr
|
||||
if(fd <= 2)
|
||||
return false;
|
||||
|
||||
// COM port - we don't currently need aio access for those, and
|
||||
// aio_reopen's CreateFileW would fail with "access denied".
|
||||
if(is_com_port)
|
||||
return false;
|
||||
|
||||
// caller is requesting we skip it (see open())
|
||||
if(oflag & O_NO_AIO_NP)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// (re)open file in asynchronous mode and associate handle with fd.
|
||||
static LibError aio_reopen(int fd, const wchar_t* pathname, int oflag, ...)
|
||||
// (this works because the files default to DENY_NONE sharing)
|
||||
LibError waio_reopen(int fd, const wchar_t* pathname, int oflag, ...)
|
||||
{
|
||||
WinScopedPreserveLastError s; // CreateFile
|
||||
|
||||
@ -119,6 +139,9 @@ static LibError aio_reopen(int fd, const wchar_t* pathname, int oflag, ...)
|
||||
if(oflag & O_CREAT)
|
||||
create = (oflag & O_EXCL)? CREATE_NEW : CREATE_ALWAYS;
|
||||
|
||||
if(!IsAioPossible(fd, false, oflag))
|
||||
return INFO::SKIPPED;
|
||||
|
||||
// open file
|
||||
const DWORD flags = FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING|FILE_FLAG_SEQUENTIAL_SCAN;
|
||||
const HANDLE hFile = CreateFileW(pathname, access, share, 0, create, flags, 0);
|
||||
@ -133,7 +156,7 @@ static LibError aio_reopen(int fd, const wchar_t* pathname, int oflag, ...)
|
||||
}
|
||||
|
||||
|
||||
static LibError aio_close(int fd)
|
||||
LibError waio_close(int fd)
|
||||
{
|
||||
HANDLE hFile;
|
||||
{
|
||||
@ -151,72 +174,6 @@ static LibError aio_close(int fd)
|
||||
}
|
||||
|
||||
|
||||
// do we want to open a second aio-capable handle?
|
||||
static bool IsAioPossible(int fd, bool is_com_port, int oflag)
|
||||
{
|
||||
// stdin/stdout/stderr
|
||||
if(fd <= 2)
|
||||
return false;
|
||||
|
||||
// COM port - we don't currently need aio access for those, and
|
||||
// aio_reopen's CreateFileW would fail with "access denied".
|
||||
if(is_com_port)
|
||||
return false;
|
||||
|
||||
// caller is requesting we skip it (see open())
|
||||
if(oflag & O_NO_AIO_NP)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int sys_wopen(const wchar_t* pathname, int oflag, ...)
|
||||
{
|
||||
mode_t mode = _S_IREAD|_S_IWRITE;
|
||||
if(oflag & O_CREAT)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, oflag);
|
||||
mode = va_arg(args, mode_t);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
WinScopedPreserveLastError s; // _wsopen_s's CreateFileW
|
||||
int fd;
|
||||
errno_t ret = _wsopen_s(&fd, pathname, oflag, _SH_DENYNO, mode);
|
||||
if(ret != 0)
|
||||
{
|
||||
errno = ret;
|
||||
WARN_ERR(LibError_from_errno());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if possible, re-open the file for aio (this works because
|
||||
// the initial _wopen defaults to DENY_NONE sharing)
|
||||
if(IsAioPossible(fd, false, oflag))
|
||||
WARN_ERR(aio_reopen(fd, pathname, oflag));
|
||||
|
||||
// CRT doesn't like more than 255 files open.
|
||||
// warn now, so that we notice why so many are open.
|
||||
#ifndef NDEBUG
|
||||
if(fd > 256)
|
||||
WARN_ERR(ERR::LIMIT);
|
||||
#endif
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
int close(int fd)
|
||||
{
|
||||
debug_assert(3 <= fd && fd < 256);
|
||||
|
||||
(void)aio_close(fd); // no-op if fd wasn't opened for aio
|
||||
|
||||
return _close(fd);
|
||||
}
|
||||
|
||||
|
||||
// we don't want to #define read to _read, since that's a fairly common
|
||||
// identifier. therefore, translate from MS CRT names via thunk functions.
|
||||
// efficiency is less important, and the overhead could be optimized away.
|
||||
@ -236,17 +193,6 @@ off_t lseek(int fd, off_t ofs, int whence)
|
||||
return _lseeki64(fd, ofs, whence);
|
||||
}
|
||||
|
||||
int truncate(const char* path, off_t length)
|
||||
{
|
||||
HANDLE hFile = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
|
||||
debug_assert(hFile != INVALID_HANDLE_VALUE);
|
||||
LARGE_INTEGER ofs; ofs.QuadPart = length;
|
||||
WARN_IF_FALSE(SetFilePointerEx(hFile, ofs, 0, FILE_BEGIN));
|
||||
WARN_IF_FALSE(SetEndOfFile(hFile));
|
||||
WARN_IF_FALSE(CloseHandle(hFile));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -51,29 +51,6 @@ struct sigevent // unused
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// <fcntl.h>
|
||||
//
|
||||
|
||||
// Win32 _wopen 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 _wopen:
|
||||
// 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
|
||||
|
||||
// POSIX flags not supported by the underlying Win32 _wopen:
|
||||
#define O_NONBLOCK 0x1000000
|
||||
|
||||
// note: we use the sys_wopen interface because there is no
|
||||
// standardized wide-character open().
|
||||
|
||||
extern int close(int);
|
||||
|
||||
|
||||
//
|
||||
// <unistd.h>
|
||||
//
|
||||
@ -81,10 +58,6 @@ extern int close(int);
|
||||
extern int read (int fd, void* buf, size_t nbytes); // thunk
|
||||
extern int write(int fd, void* buf, size_t nbytes); // thunk
|
||||
extern off_t lseek(int fd, off_t ofs, int whence); // thunk
|
||||
// portable code for truncating files can use truncate or ftruncate.
|
||||
// we'd like to use wchar_t pathnames, but neither truncate nor open have
|
||||
// portable wchar_t variants. callers will have to use multi-byte strings.
|
||||
LIB_API int truncate(const char* path, off_t length);
|
||||
|
||||
|
||||
//
|
||||
@ -132,4 +105,11 @@ extern int aio_suspend(const struct aiocb* const[], int, const struct timespec*)
|
||||
extern int aio_write(struct aiocb*);
|
||||
extern int lio_listio(int, struct aiocb* const[], int, struct sigevent*);
|
||||
|
||||
// for use by wposix_wchar's wopen/wclose:
|
||||
|
||||
// (re)open file in asynchronous mode and associate handle with fd.
|
||||
// (this works because the files default to DENY_NONE sharing)
|
||||
extern LibError waio_reopen(int fd, const wchar_t* pathname, int oflag, ...);
|
||||
extern LibError waio_close(int fd);
|
||||
|
||||
#endif // #ifndef INCLUDED_WAIO
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -20,6 +20,7 @@
|
||||
|
||||
#include "lib/allocators/allocators.h" // single_calloc
|
||||
#include "wposix_internal.h"
|
||||
#include "waio.h"
|
||||
#include "wtime_internal.h" // wtime_utc_filetime_to_time_t
|
||||
#include "crt_posix.h" // _rmdir, _access
|
||||
|
||||
@ -130,80 +131,11 @@ static time_t filetime_to_time_t(FILETIME* ft)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// currently only sets st_mode (file or dir) and st_size.
|
||||
int stat(const char* fn, struct stat* s)
|
||||
{
|
||||
memset(s, 0, sizeof(struct stat));
|
||||
|
||||
WIN32_FILE_ATTRIBUTE_DATA fad;
|
||||
if(!GetFileAttributesEx(fn, GetFileExInfoStandard, &fad))
|
||||
return -1;
|
||||
|
||||
s->st_mtime = filetime_to_time_t(fad.ftLastAccessTime)
|
||||
|
||||
// dir
|
||||
if(fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
s->st_mode = S_IFDIR;
|
||||
else
|
||||
{
|
||||
s->st_mode = S_IFREG;
|
||||
s->st_size = (off_t)u64_from_u32(fad.nFileSizeHigh, fad.nFileSizeLow);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
int access(const char* path, int mode)
|
||||
{
|
||||
return _access(path, mode);
|
||||
}
|
||||
|
||||
|
||||
#ifndef HAVE_MKDIR
|
||||
static int ErrnoFromCreateDirectory()
|
||||
{
|
||||
switch(GetLastError())
|
||||
{
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
return EEXIST;
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
return ENOENT;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
return EACCES;
|
||||
case ERROR_WRITE_PROTECT:
|
||||
return EROFS;
|
||||
case ERROR_DIRECTORY:
|
||||
return ENOTDIR;
|
||||
default:
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int mkdir(const char* path, mode_t UNUSED(mode))
|
||||
{
|
||||
if(!CreateDirectory(path, (LPSECURITY_ATTRIBUTES)NULL))
|
||||
{
|
||||
errno = ErrnoFromCreateDirectory();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int rmdir(const char* path)
|
||||
{
|
||||
return _rmdir(path);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// readdir
|
||||
// dirent.h
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// note: we avoid opening directories or returning entries that have
|
||||
@ -216,15 +148,15 @@ struct WDIR
|
||||
{
|
||||
HANDLE hFind;
|
||||
|
||||
// the dirent returned by readdir.
|
||||
// the wdirent returned by readdir.
|
||||
// note: having only one global instance is not possible because
|
||||
// multiple independent opendir/readdir sequences must be supported.
|
||||
struct dirent ent;
|
||||
// multiple independent wopendir/wreaddir sequences must be supported.
|
||||
struct wdirent ent;
|
||||
|
||||
WIN32_FIND_DATA fd;
|
||||
WIN32_FIND_DATAW fd;
|
||||
|
||||
// since opendir calls FindFirstFile, we need a means of telling the
|
||||
// first call to readdir that we already have a file.
|
||||
// since wopendir calls FindFirstFileW, we need a means of telling the
|
||||
// first call to wreaddir that we already have a file.
|
||||
// that's the case iff this is == 0; we use a counter rather than a
|
||||
// flag because that allows keeping statistics.
|
||||
int num_entries_scanned;
|
||||
@ -253,9 +185,9 @@ static inline void wdir_free(WDIR* d)
|
||||
static const DWORD hs = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
|
||||
|
||||
// make sure path exists and is a normal (according to attributes) directory.
|
||||
static bool is_normal_dir(const char* path)
|
||||
static bool is_normal_dir(const wchar_t* path)
|
||||
{
|
||||
const DWORD fa = GetFileAttributes(path);
|
||||
const DWORD fa = GetFileAttributesW(path);
|
||||
|
||||
// path not found
|
||||
if(fa == INVALID_FILE_ATTRIBUTES)
|
||||
@ -276,7 +208,7 @@ static bool is_normal_dir(const char* path)
|
||||
}
|
||||
|
||||
|
||||
DIR* opendir(const char* path)
|
||||
WDIR* wopendir(const wchar_t* path)
|
||||
{
|
||||
if(!is_normal_dir(path))
|
||||
{
|
||||
@ -291,16 +223,16 @@ DIR* opendir(const char* path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// build search path for FindFirstFile. note: "path\\dir" only returns
|
||||
// build search path for FindFirstFileW. note: "path\\dir" only returns
|
||||
// information about that directory; trailing slashes aren't allowed.
|
||||
// for dir entries to be returned, we have to append "\\*".
|
||||
char search_path[PATH_MAX];
|
||||
sprintf_s(search_path, ARRAY_SIZE(search_path), "%s\\*", path);
|
||||
wchar_t search_path[PATH_MAX];
|
||||
swprintf_s(search_path, ARRAY_SIZE(search_path), L"%ls\\*", path);
|
||||
|
||||
// note: we could store search_path and defer FindFirstFile until
|
||||
// readdir. this way is a bit more complex but required for
|
||||
// note: we could store search_path and defer FindFirstFileW until
|
||||
// wreaddir. this way is a bit more complex but required for
|
||||
// correctness (we must return a valid DIR iff <path> is valid).
|
||||
d->hFind = FindFirstFileA(search_path, &d->fd);
|
||||
d->hFind = FindFirstFileW(search_path, &d->fd);
|
||||
if(d->hFind == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// not an error - the directory is just empty.
|
||||
@ -323,14 +255,12 @@ DIR* opendir(const char* path)
|
||||
}
|
||||
|
||||
|
||||
struct dirent* readdir(DIR* d_)
|
||||
struct wdirent* wreaddir(WDIR* d)
|
||||
{
|
||||
WDIR* const d = (WDIR*)d_;
|
||||
|
||||
// avoid polluting the last error.
|
||||
DWORD prev_err = GetLastError();
|
||||
|
||||
// first call - skip FindNextFile (see opendir).
|
||||
// first call - skip FindNextFileW (see wopendir).
|
||||
if(d->num_entries_scanned == 0)
|
||||
{
|
||||
// this directory is empty.
|
||||
@ -342,7 +272,7 @@ struct dirent* readdir(DIR* d_)
|
||||
// until end of directory or a valid entry was found:
|
||||
for(;;)
|
||||
{
|
||||
if(!FindNextFileA(d->hFind, &d->fd))
|
||||
if(!FindNextFileW(d->hFind, &d->fd))
|
||||
goto fail;
|
||||
already_have_file:
|
||||
|
||||
@ -359,24 +289,18 @@ already_have_file:
|
||||
return &d->ent;
|
||||
|
||||
fail:
|
||||
// FindNextFile failed; determine why and bail.
|
||||
// FindNextFileW failed; determine why and bail.
|
||||
// .. legit, end of dir reached. don't pollute last error code.
|
||||
if(GetLastError() == ERROR_NO_MORE_FILES)
|
||||
SetLastError(prev_err);
|
||||
else
|
||||
debug_assert(0); // readdir: FindNextFile failed
|
||||
WARN_ERR(LibError_from_GLE());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// return status for the dirent returned by the last successful
|
||||
// readdir call from the given directory stream.
|
||||
// currently sets st_size, st_mode, and st_mtime; the rest are zeroed.
|
||||
// non-portable, but considerably faster than stat(). used by dir_ForEachSortedEntry.
|
||||
int readdir_stat_np(DIR* d_, struct stat* s)
|
||||
int wreaddir_stat_np(WDIR* d, struct stat* s)
|
||||
{
|
||||
WDIR* d = (WDIR*)d_;
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->st_size = (off_t)u64_from_u32(d->fd.nFileSizeHigh, d->fd.nFileSizeLow);
|
||||
s->st_mode = (unsigned short)((d->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG);
|
||||
@ -385,10 +309,8 @@ int readdir_stat_np(DIR* d_, struct stat* s)
|
||||
}
|
||||
|
||||
|
||||
int closedir(DIR* d_)
|
||||
int wclosedir(WDIR* d)
|
||||
{
|
||||
WDIR* const d = (WDIR*)d_;
|
||||
|
||||
FindClose(d->hFind);
|
||||
|
||||
wdir_free(d);
|
||||
@ -396,11 +318,122 @@ int closedir(DIR* d_)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// fcntl.h
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
char* realpath(const char* fn, char* path)
|
||||
int wopen(const wchar_t* pathname, int oflag, ...)
|
||||
{
|
||||
if(!GetFullPathName(fn, PATH_MAX, path, 0))
|
||||
return 0;
|
||||
return path;
|
||||
mode_t mode = _S_IREAD|_S_IWRITE;
|
||||
if(oflag & O_CREAT)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, oflag);
|
||||
mode = va_arg(args, mode_t);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
WinScopedPreserveLastError s; // _wsopen_s's CreateFileW
|
||||
int fd;
|
||||
errno_t ret = _wsopen_s(&fd, pathname, oflag, _SH_DENYNO, mode);
|
||||
if(ret != 0)
|
||||
{
|
||||
errno = ret;
|
||||
WARN_ERR(LibError_from_errno());
|
||||
return -1;
|
||||
}
|
||||
|
||||
WARN_ERR(waio_reopen(fd, pathname, oflag));
|
||||
|
||||
// CRT doesn't like more than 255 files open.
|
||||
// warn now, so that we notice why so many are open.
|
||||
#ifndef NDEBUG
|
||||
if(fd > 256)
|
||||
WARN_ERR(ERR::LIMIT);
|
||||
#endif
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
int wclose(int fd)
|
||||
{
|
||||
debug_assert(3 <= fd && fd < 256);
|
||||
|
||||
(void)waio_close(fd); // no-op if fd wasn't opened for aio
|
||||
|
||||
return _close(fd);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// unistd.h
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int wtruncate(const wchar_t* pathname, off_t length)
|
||||
{
|
||||
HANDLE hFile = CreateFileW(pathname, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
|
||||
debug_assert(hFile != INVALID_HANDLE_VALUE);
|
||||
LARGE_INTEGER ofs; ofs.QuadPart = length;
|
||||
WARN_IF_FALSE(SetFilePointerEx(hFile, ofs, 0, FILE_BEGIN));
|
||||
WARN_IF_FALSE(SetEndOfFile(hFile));
|
||||
WARN_IF_FALSE(CloseHandle(hFile));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wunlink(const wchar_t* pathname)
|
||||
{
|
||||
return _wunlink(pathname);
|
||||
}
|
||||
|
||||
|
||||
int wrmdir(const wchar_t* path)
|
||||
{
|
||||
return _wrmdir(path);
|
||||
}
|
||||
|
||||
|
||||
wchar_t* wrealpath(const wchar_t* pathname, wchar_t* resolved)
|
||||
{
|
||||
if(!GetFullPathNameW(pathname, PATH_MAX, resolved, 0))
|
||||
return 0;
|
||||
return resolved;
|
||||
}
|
||||
|
||||
|
||||
static int ErrnoFromCreateDirectory()
|
||||
{
|
||||
switch(GetLastError())
|
||||
{
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
return EEXIST;
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
return ENOENT;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
return EACCES;
|
||||
case ERROR_WRITE_PROTECT:
|
||||
return EROFS;
|
||||
case ERROR_DIRECTORY:
|
||||
return ENOTDIR;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int wmkdir(const wchar_t* path, mode_t UNUSED(mode))
|
||||
{
|
||||
if(!CreateDirectoryW(path, (LPSECURITY_ATTRIBUTES)NULL))
|
||||
{
|
||||
errno = ErrnoFromCreateDirectory();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wstat(const wchar_t* pathname, struct stat* buf)
|
||||
{
|
||||
return _wstat64(pathname, buf);
|
||||
}
|
||||
|
@ -1,39 +1,32 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_WFILESYSTEM
|
||||
#define INCLUDED_WFILESYSTEM
|
||||
|
||||
#include "no_crt_posix.h"
|
||||
|
||||
|
||||
//
|
||||
// sys/stat.h
|
||||
//
|
||||
|
||||
// (use VC8's stat because it defines helpful inline macros)
|
||||
#include <sys/stat.h>
|
||||
#include <sys/stat.h> // for S_IFREG etc.
|
||||
|
||||
#if MSC_VERSION
|
||||
// defined by MinGW but not VC
|
||||
typedef unsigned int mode_t;
|
||||
|
||||
// we need 64-bit st_size and time_t currently defaults to 64-bit
|
||||
#define stat _stat64
|
||||
typedef unsigned int mode_t; // defined by MinGW but not VC
|
||||
#define stat _stat64 // we need 64-bit st_size and time_t
|
||||
#endif
|
||||
|
||||
// permission masks when creating files (_wsopen_s doesn't distinguish
|
||||
@ -45,63 +38,4 @@ typedef unsigned int mode_t;
|
||||
#define S_ISDIR(m) (m & S_IFDIR)
|
||||
#define S_ISREG(m) (m & S_IFREG)
|
||||
|
||||
// we need to emulate this on VC7 (not included) and VC8 (deprecated)
|
||||
#if MSC_VERSION
|
||||
# define EMULATE_MKDIR 1
|
||||
#else
|
||||
# define EMULATE_MKDIR 0
|
||||
#endif
|
||||
|
||||
#if EMULATE_MKDIR
|
||||
extern int mkdir(const char* path, mode_t mode);
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// dirent.h
|
||||
//
|
||||
|
||||
typedef void DIR;
|
||||
|
||||
struct dirent
|
||||
{
|
||||
// note: SUSv3 describes this as a "char array" but of unspecified size.
|
||||
// since that precludes using sizeof(), we may as well declare as a
|
||||
// pointer to avoid copying in the implementation.
|
||||
char* d_name;
|
||||
};
|
||||
|
||||
extern DIR* opendir(const char* name);
|
||||
extern struct dirent* readdir(DIR*);
|
||||
extern int closedir(DIR*);
|
||||
|
||||
// return status for the file returned by the last successful
|
||||
// readdir call from the given directory stream.
|
||||
// currently sets st_size, st_mode, and st_mtime; the rest are zeroed.
|
||||
// non-portable, but considerably faster than stat(). used by dir_ForEachSortedEntry.
|
||||
extern int readdir_stat_np(DIR*, struct stat*);
|
||||
|
||||
|
||||
//
|
||||
// <stdlib.h>
|
||||
//
|
||||
|
||||
extern char* realpath(const char*, char*);
|
||||
|
||||
|
||||
//
|
||||
// <unistd.h>
|
||||
//
|
||||
|
||||
// values from MS _access() implementation. do not change.
|
||||
#define F_OK 0
|
||||
#define R_OK 4
|
||||
#define W_OK 2
|
||||
// .. MS implementation doesn't support this distinction.
|
||||
// hence, the file is reported executable if it exists.
|
||||
#define X_OK 0
|
||||
|
||||
extern int access(const char* path, int mode);
|
||||
extern int rmdir(const char* path);
|
||||
|
||||
#endif // #ifndef INCLUDED_WFILESYSTEM
|
||||
|
@ -68,8 +68,6 @@ extern ErrorReaction sys_display_error(const wchar_t* text, size_t flags);
|
||||
**/
|
||||
extern int sys_vswprintf(wchar_t* buffer, size_t count, const wchar_t* format, va_list argptr);
|
||||
|
||||
extern int sys_wopen(const wchar_t* pathname, int oflag, ...);
|
||||
|
||||
/**
|
||||
* describe the current OS error state.
|
||||
*
|
||||
|
@ -90,9 +90,8 @@ public:
|
||||
// Check it's absolute
|
||||
TSM_ASSERT(std::wstring(L"Path: ")+path.string(), path_is_absolute(path.string().c_str()));
|
||||
// Check the file exists
|
||||
fs::path path_c = path_from_wpath(path);
|
||||
struct stat s;
|
||||
TSM_ASSERT_EQUALS(std::wstring(L"Path: ")+path.string(), stat(path_c.string().c_str(), &s), 0);
|
||||
TSM_ASSERT_EQUALS(std::wstring(L"Path: ")+path.string(), wstat(path.string().c_str(), &s), 0);
|
||||
|
||||
// Do some platform-specific tests, based on the
|
||||
// implementations of sys_get_executable_name:
|
||||
|
@ -15,8 +15,8 @@
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_FILESYSTEM
|
||||
#define INCLUDED_FILESYSTEM
|
||||
#ifndef INCLUDED_PS_FILESYSTEM
|
||||
#define INCLUDED_PS_FILESYSTEM
|
||||
|
||||
#include "lib/path_util.h"
|
||||
#include "lib/file/file.h"
|
||||
@ -66,4 +66,4 @@ private:
|
||||
size_t m_BufferSize;
|
||||
};
|
||||
|
||||
#endif // #ifndef INCLUDED_FILESYSTEM
|
||||
#endif // #ifndef INCLUDED_PS_FILESYSTEM
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "lib/path_util.h"
|
||||
#include "lib/wchar.h"
|
||||
#include "lib/sysdep/filesystem.h" // wrealpath
|
||||
#include "lib/sysdep/sysdep.h" // sys_get_executable_name
|
||||
#if OS_WIN
|
||||
# include "lib/sysdep/os/win/wutil.h" // wutil_AppdataPath
|
||||
@ -28,7 +29,7 @@
|
||||
|
||||
Paths::Paths(const CmdLineArgs& args)
|
||||
{
|
||||
m_root = Root(args.GetArg0());
|
||||
m_root = Root(wstring_from_utf8(args.GetArg0()));
|
||||
m_rdata = m_root/L"data/";
|
||||
const wchar_t* subdirectoryName = args.Has("writableRoot")? 0 : L"0ad";
|
||||
|
||||
@ -61,7 +62,7 @@ Paths::Paths(const CmdLineArgs& args)
|
||||
}
|
||||
|
||||
|
||||
/*static*/ fs::wpath Paths::Root(const CStr& argv0)
|
||||
/*static*/ fs::wpath Paths::Root(const std::wstring& argv0)
|
||||
{
|
||||
// get full path to executable
|
||||
fs::wpath pathname;
|
||||
@ -69,11 +70,11 @@ Paths::Paths(const CmdLineArgs& args)
|
||||
if(sys_get_executable_name(pathname) != INFO::OK)
|
||||
{
|
||||
// .. failed; use argv[0]
|
||||
char pathname_c[PATH_MAX];
|
||||
wchar_t pathname_buf[PATH_MAX];
|
||||
errno = 0;
|
||||
if(!realpath(argv0.c_str(), pathname_c))
|
||||
if(!wrealpath(argv0.c_str(), pathname_buf))
|
||||
WARN_ERR(LibError_from_errno(false));
|
||||
pathname = wpath_from_path(pathname_c);
|
||||
pathname = pathname_buf;
|
||||
}
|
||||
|
||||
// make sure it's valid
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static fs::wpath Root(const CStr& argv0);
|
||||
static fs::wpath Root(const std::wstring& argv0);
|
||||
static fs::wpath XDG_Path(const char* envname, const fs::wpath& home, const fs::wpath& defaultPath);
|
||||
|
||||
// read-only directories, fixed paths relative to executable
|
||||
|
Loading…
Reference in New Issue
Block a user