mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-27 11:06:50 +01:00
fixed GH #1523: Long path names under Windows
This commit is contained in:
@@ -50,6 +50,19 @@ class Path;
|
|||||||
|
|
||||||
class Foundation_API File: private FileImpl
|
class Foundation_API File: private FileImpl
|
||||||
/// The File class provides methods for working with a file.
|
/// The File class provides methods for working with a file.
|
||||||
|
///
|
||||||
|
/// Regarding paths passed to the various methods, note that
|
||||||
|
/// platform-specific limitations regarding maximum length
|
||||||
|
/// of the entire path and its components apply.
|
||||||
|
///
|
||||||
|
/// On Windows, if compiled with UTF-8 support (POCO_WIN32_UTF8)
|
||||||
|
/// the implementation tries to work around the rather low
|
||||||
|
/// 260 characters MAX_PATH limit by adding the "\\?\" prefix if
|
||||||
|
/// a path is absolute and exceeds MAX_PATH characters in length.
|
||||||
|
/// Note that various limitations regarding usage of the "\\?\"
|
||||||
|
/// prefix apply in that case, e.g. the path must
|
||||||
|
/// not contain relative components ("." and "..") and must not
|
||||||
|
/// use the forward slash ("/") as directory separator.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef FileSizeImpl FileSize;
|
typedef FileSizeImpl FileSize;
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ protected:
|
|||||||
bool createFileImpl();
|
bool createFileImpl();
|
||||||
bool createDirectoryImpl();
|
bool createDirectoryImpl();
|
||||||
static void handleLastErrorImpl(const std::string& path);
|
static void handleLastErrorImpl(const std::string& path);
|
||||||
|
static void convertPath(const std::string& utf8Path, std::wstring& utf16Path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _path;
|
std::string _path;
|
||||||
@@ -68,6 +69,8 @@ private:
|
|||||||
friend class FileHandle;
|
friend class FileHandle;
|
||||||
friend class DirectoryIteratorImpl;
|
friend class DirectoryIteratorImpl;
|
||||||
friend class WindowsDirectoryWatcherStrategy;
|
friend class WindowsDirectoryWatcherStrategy;
|
||||||
|
friend class FileStreamBuf;
|
||||||
|
friend class LogFileImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ protected:
|
|||||||
bool createFileImpl();
|
bool createFileImpl();
|
||||||
bool createDirectoryImpl();
|
bool createDirectoryImpl();
|
||||||
static void handleLastErrorImpl(const std::string& path);
|
static void handleLastErrorImpl(const std::string& path);
|
||||||
|
static void convertPath(const std::string& utf8Path, std::wstring& utf16Path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _path;
|
std::string _path;
|
||||||
@@ -67,6 +68,8 @@ private:
|
|||||||
|
|
||||||
friend class FileHandle;
|
friend class FileHandle;
|
||||||
friend class DirectoryIteratorImpl;
|
friend class DirectoryIteratorImpl;
|
||||||
|
friend class FileStreamBuf;
|
||||||
|
friend class LogFileImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ DirectoryIteratorImpl::DirectoryIteratorImpl(const std::string& path): _fh(INVAL
|
|||||||
std::string findPath = p.toString();
|
std::string findPath = p.toString();
|
||||||
findPath.append("*");
|
findPath.append("*");
|
||||||
std::wstring uFindPath;
|
std::wstring uFindPath;
|
||||||
UnicodeConverter::toUTF16(findPath, uFindPath);
|
FileImpl::convertPath(findPath, uFindPath);
|
||||||
|
|
||||||
_fh = FindFirstFileW(uFindPath.c_str(), &_fd);
|
_fh = FindFirstFileW(uFindPath.c_str(), &_fd);
|
||||||
if (_fh == INVALID_HANDLE_VALUE)
|
if (_fh == INVALID_HANDLE_VALUE)
|
||||||
|
|||||||
@@ -26,9 +26,6 @@
|
|||||||
#include "Poco/Event.h"
|
#include "Poco/Event.h"
|
||||||
#include "Poco/Exception.h"
|
#include "Poco/Exception.h"
|
||||||
#include "Poco/Buffer.h"
|
#include "Poco/Buffer.h"
|
||||||
#if defined(POCO_WIN32_UTF8)
|
|
||||||
#include "Poco/UnicodeConverter.h"
|
|
||||||
#endif
|
|
||||||
#if POCO_OS == POCO_OS_LINUX
|
#if POCO_OS == POCO_OS_LINUX
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
@@ -186,7 +183,7 @@ public:
|
|||||||
std::string path(owner().directory().path());
|
std::string path(owner().directory().path());
|
||||||
#if defined(POCO_WIN32_UTF8)
|
#if defined(POCO_WIN32_UTF8)
|
||||||
std::wstring upath;
|
std::wstring upath;
|
||||||
Poco::UnicodeConverter::toUTF16(path.c_str(), upath);
|
FileImpl::convertPath(path.c_str(), upath);
|
||||||
HANDLE hChange = FindFirstChangeNotificationW(upath.c_str(), FALSE, filter);
|
HANDLE hChange = FindFirstChangeNotificationW(upath.c_str(), FALSE, filter);
|
||||||
#else
|
#else
|
||||||
HANDLE hChange = FindFirstChangeNotificationA(path.c_str(), FALSE, filter);
|
HANDLE hChange = FindFirstChangeNotificationA(path.c_str(), FALSE, filter);
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ void FileStreamBuf::open(const std::string& path, std::ios::openmode mode)
|
|||||||
|
|
||||||
#if defined (POCO_WIN32_UTF8)
|
#if defined (POCO_WIN32_UTF8)
|
||||||
std::wstring utf16Path;
|
std::wstring utf16Path;
|
||||||
UnicodeConverter::toUTF16(path, utf16Path);
|
FileImpl::convertPath(path, utf16Path);
|
||||||
_handle = CreateFileW(utf16Path.c_str(), access, shareMode, NULL, creationDisp, flags, NULL);
|
_handle = CreateFileW(utf16Path.c_str(), access, shareMode, NULL, creationDisp, flags, NULL);
|
||||||
#else
|
#else
|
||||||
_handle = CreateFileA(path.c_str(), access, shareMode, NULL, creationDisp, flags, NULL);
|
_handle = CreateFileA(path.c_str(), access, shareMode, NULL, creationDisp, flags, NULL);
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ FileImpl::FileImpl(const std::string& path): _path(path)
|
|||||||
{
|
{
|
||||||
_path.resize(n - 1);
|
_path.resize(n - 1);
|
||||||
}
|
}
|
||||||
UnicodeConverter::toUTF16(_path, _upath);
|
convertPath(_path, _upath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ void FileImpl::setPathImpl(const std::string& path)
|
|||||||
{
|
{
|
||||||
_path.resize(n - 1);
|
_path.resize(n - 1);
|
||||||
}
|
}
|
||||||
UnicodeConverter::toUTF16(_path, _upath);
|
convertPath(_path, _upath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -293,7 +293,7 @@ void FileImpl::copyToImpl(const std::string& path) const
|
|||||||
poco_assert (!_path.empty());
|
poco_assert (!_path.empty());
|
||||||
|
|
||||||
std::wstring upath;
|
std::wstring upath;
|
||||||
UnicodeConverter::toUTF16(path, upath);
|
convertPath(path, upath);
|
||||||
if (CopyFileW(_upath.c_str(), upath.c_str(), FALSE) == 0)
|
if (CopyFileW(_upath.c_str(), upath.c_str(), FALSE) == 0)
|
||||||
handleLastErrorImpl(_path);
|
handleLastErrorImpl(_path);
|
||||||
}
|
}
|
||||||
@@ -304,7 +304,7 @@ void FileImpl::renameToImpl(const std::string& path)
|
|||||||
poco_assert (!_path.empty());
|
poco_assert (!_path.empty());
|
||||||
|
|
||||||
std::wstring upath;
|
std::wstring upath;
|
||||||
UnicodeConverter::toUTF16(path, upath);
|
convertPath(path, upath);
|
||||||
if (MoveFileExW(_upath.c_str(), upath.c_str(), MOVEFILE_REPLACE_EXISTING) == 0)
|
if (MoveFileExW(_upath.c_str(), upath.c_str(), MOVEFILE_REPLACE_EXISTING) == 0)
|
||||||
handleLastErrorImpl(_path);
|
handleLastErrorImpl(_path);
|
||||||
}
|
}
|
||||||
@@ -406,4 +406,22 @@ void FileImpl::handleLastErrorImpl(const std::string& path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FileImpl::convertPath(const std::string& utf8Path, std::wstring& utf16Path)
|
||||||
|
{
|
||||||
|
UnicodeConverter::toUTF16(utf8Path, utf16Path);
|
||||||
|
if (utf16Path.size() > MAX_PATH - 12) // Note: CreateDirectory has a limit of MAX_PATH - 12 (room for 8.3 file name)
|
||||||
|
{
|
||||||
|
if (utf16Path[0] == '\\' || utf16Path[1] == ':')
|
||||||
|
{
|
||||||
|
if (utf16Path.compare(0, 4, L"\\\\?\\", 4) != 0)
|
||||||
|
{
|
||||||
|
if (utf16Path[1] == '\\')
|
||||||
|
utf16Path.insert(0, L"\\\\?\\UNC\\", 8);
|
||||||
|
else
|
||||||
|
utf16Path.insert(0, L"\\\\?\\", 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Poco
|
} // namespace Poco
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ FileImpl::FileImpl(const std::string& path): _path(path)
|
|||||||
{
|
{
|
||||||
_path.resize(n - 1);
|
_path.resize(n - 1);
|
||||||
}
|
}
|
||||||
UnicodeConverter::toUTF16(_path, _upath);
|
convertPath(_path, _upath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ void FileImpl::setPathImpl(const std::string& path)
|
|||||||
{
|
{
|
||||||
_path.resize(n - 1);
|
_path.resize(n - 1);
|
||||||
}
|
}
|
||||||
UnicodeConverter::toUTF16(_path, _upath);
|
convertPath(_path, _upath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -284,7 +284,7 @@ void FileImpl::copyToImpl(const std::string& path) const
|
|||||||
poco_assert (!_path.empty());
|
poco_assert (!_path.empty());
|
||||||
|
|
||||||
std::wstring upath;
|
std::wstring upath;
|
||||||
UnicodeConverter::toUTF16(path, upath);
|
convertPath(path, upath);
|
||||||
if (CopyFileW(_upath.c_str(), upath.c_str(), FALSE) == 0)
|
if (CopyFileW(_upath.c_str(), upath.c_str(), FALSE) == 0)
|
||||||
handleLastErrorImpl(_path);
|
handleLastErrorImpl(_path);
|
||||||
}
|
}
|
||||||
@@ -295,7 +295,7 @@ void FileImpl::renameToImpl(const std::string& path)
|
|||||||
poco_assert (!_path.empty());
|
poco_assert (!_path.empty());
|
||||||
|
|
||||||
std::wstring upath;
|
std::wstring upath;
|
||||||
UnicodeConverter::toUTF16(path, upath);
|
convertPath(path, upath);
|
||||||
if (MoveFileW(_upath.c_str(), upath.c_str()) == 0)
|
if (MoveFileW(_upath.c_str(), upath.c_str()) == 0)
|
||||||
handleLastErrorImpl(_path);
|
handleLastErrorImpl(_path);
|
||||||
}
|
}
|
||||||
@@ -396,4 +396,9 @@ void FileImpl::handleLastErrorImpl(const std::string& path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FileImpl::convertPath(const std::string& utf8Path, std::wstring& utf16Path)
|
||||||
|
{
|
||||||
|
UnicodeConverter::toUTF16(utf8Path, utf16Path);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Poco
|
} // namespace Poco
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ const std::string& LogFileImpl::pathImpl() const
|
|||||||
void LogFileImpl::createFile()
|
void LogFileImpl::createFile()
|
||||||
{
|
{
|
||||||
std::wstring upath;
|
std::wstring upath;
|
||||||
UnicodeConverter::toUTF16(_path, upath);
|
FileImpl::convertPath(_path, upath);
|
||||||
|
|
||||||
_hFile = CreateFileW(upath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
_hFile = CreateFileW(upath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
if (_hFile == INVALID_HANDLE_VALUE) throw OpenFileException(_path);
|
if (_hFile == INVALID_HANDLE_VALUE) throw OpenFileException(_path);
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
#include "Poco/NamedEvent.h"
|
#include "Poco/NamedEvent.h"
|
||||||
#include "Poco/UnicodeConverter.h"
|
#include "Poco/UnicodeConverter.h"
|
||||||
#include "Poco/Pipe.h"
|
#include "Poco/Pipe.h"
|
||||||
|
#include "Poco/File.h"
|
||||||
|
#include "Poco/Path.h"
|
||||||
|
#include "Poco/String.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
@@ -164,7 +167,7 @@ static std::string escapeArg(const std::string& arg)
|
|||||||
|
|
||||||
ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const ArgsImpl& args, const std::string& initialDirectory, Pipe* inPipe, Pipe* outPipe, Pipe* errPipe, const EnvImpl& env)
|
ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const ArgsImpl& args, const std::string& initialDirectory, Pipe* inPipe, Pipe* outPipe, Pipe* errPipe, const EnvImpl& env)
|
||||||
{
|
{
|
||||||
std::string commandLine = command;
|
std::string commandLine = escapeArg(command);
|
||||||
for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it)
|
for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it)
|
||||||
{
|
{
|
||||||
commandLine.append(" ");
|
commandLine.append(" ");
|
||||||
@@ -174,6 +177,19 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
|
|||||||
std::wstring ucommandLine;
|
std::wstring ucommandLine;
|
||||||
UnicodeConverter::toUTF16(commandLine, ucommandLine);
|
UnicodeConverter::toUTF16(commandLine, ucommandLine);
|
||||||
|
|
||||||
|
const wchar_t* applicationName = 0;
|
||||||
|
std::wstring uapplicationName;
|
||||||
|
if (command.size() > MAX_PATH)
|
||||||
|
{
|
||||||
|
Poco::Path p(command);
|
||||||
|
if (p.isAbsolute())
|
||||||
|
{
|
||||||
|
UnicodeConverter::toUTF16(command, uapplicationName);
|
||||||
|
if (p.getExtension().empty()) uapplicationName += L".EXE";
|
||||||
|
applicationName = uapplicationName.c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
STARTUPINFOW startupInfo;
|
STARTUPINFOW startupInfo;
|
||||||
GetStartupInfoW(&startupInfo); // take defaults from current process
|
GetStartupInfoW(&startupInfo); // take defaults from current process
|
||||||
startupInfo.cb = sizeof(STARTUPINFOW);
|
startupInfo.cb = sizeof(STARTUPINFOW);
|
||||||
@@ -253,7 +269,7 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
|
|||||||
PROCESS_INFORMATION processInfo;
|
PROCESS_INFORMATION processInfo;
|
||||||
DWORD creationFlags = GetConsoleWindow() ? 0 : CREATE_NO_WINDOW;
|
DWORD creationFlags = GetConsoleWindow() ? 0 : CREATE_NO_WINDOW;
|
||||||
BOOL rc = CreateProcessW(
|
BOOL rc = CreateProcessW(
|
||||||
NULL, // applicationName
|
applicationName,
|
||||||
const_cast<wchar_t*>(ucommandLine.c_str()),
|
const_cast<wchar_t*>(ucommandLine.c_str()),
|
||||||
NULL, // processAttributes
|
NULL, // processAttributes
|
||||||
NULL, // threadAttributes
|
NULL, // threadAttributes
|
||||||
|
|||||||
@@ -488,6 +488,30 @@ void FileTest::testRename()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FileTest::testLongPath()
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) && defined(POCO_WIN32_UTF8) && !defined(_WIN32_WCE)
|
||||||
|
Poco::Path p("longpathtest");
|
||||||
|
p.makeAbsolute();
|
||||||
|
std::string longpath(p.toString());
|
||||||
|
while (longpath.size() < MAX_PATH*4)
|
||||||
|
{
|
||||||
|
longpath.append("\\");
|
||||||
|
longpath.append(64, 'x');
|
||||||
|
}
|
||||||
|
|
||||||
|
Poco::File d(longpath);
|
||||||
|
d.createDirectories();
|
||||||
|
|
||||||
|
assert (d.exists());
|
||||||
|
assert (d.isDirectory());
|
||||||
|
|
||||||
|
Poco::File f(p.toString());
|
||||||
|
f.remove(true);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void FileTest::setUp()
|
void FileTest::setUp()
|
||||||
{
|
{
|
||||||
File f("testfile.dat");
|
File f("testfile.dat");
|
||||||
@@ -531,6 +555,7 @@ CppUnit::Test* FileTest::suite()
|
|||||||
CppUnit_addTest(pSuite, FileTest, testCopyDirectory);
|
CppUnit_addTest(pSuite, FileTest, testCopyDirectory);
|
||||||
CppUnit_addTest(pSuite, FileTest, testRename);
|
CppUnit_addTest(pSuite, FileTest, testRename);
|
||||||
CppUnit_addTest(pSuite, FileTest, testRootDir);
|
CppUnit_addTest(pSuite, FileTest, testRootDir);
|
||||||
|
CppUnit_addTest(pSuite, FileTest, testLongPath);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public:
|
|||||||
void testCopyDirectory();
|
void testCopyDirectory();
|
||||||
void testRename();
|
void testRename();
|
||||||
void testRootDir();
|
void testRootDir();
|
||||||
|
void testLongPath();
|
||||||
|
|
||||||
void setUp();
|
void setUp();
|
||||||
void tearDown();
|
void tearDown();
|
||||||
|
|||||||
Reference in New Issue
Block a user