mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-16 03:42:53 +01:00
fixed GH #1523: Long path names under Windows
This commit is contained in:
parent
d5ce48138c
commit
0fefd7d03a
@ -50,6 +50,19 @@ class Path;
|
||||
|
||||
class Foundation_API File: private FileImpl
|
||||
/// 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:
|
||||
typedef FileSizeImpl FileSize;
|
||||
|
@ -63,6 +63,7 @@ protected:
|
||||
FileSizeImpl usableSpaceImpl() const;
|
||||
FileSizeImpl freeSpaceImpl() const;
|
||||
static void handleLastErrorImpl(const std::string& path);
|
||||
static void convertPath(const std::string& utf8Path, std::wstring& utf16Path);
|
||||
|
||||
private:
|
||||
std::string _path;
|
||||
@ -71,6 +72,8 @@ private:
|
||||
friend class FileHandle;
|
||||
friend class DirectoryIteratorImpl;
|
||||
friend class WindowsDirectoryWatcherStrategy;
|
||||
friend class FileStreamBuf;
|
||||
friend class LogFileImpl;
|
||||
};
|
||||
|
||||
|
||||
|
@ -63,6 +63,7 @@ protected:
|
||||
FileSizeImpl usableSpaceImpl() const;
|
||||
FileSizeImpl freeSpaceImpl() const;
|
||||
static void handleLastErrorImpl(const std::string& path);
|
||||
static void convertPath(const std::string& utf8Path, std::wstring& utf16Path);
|
||||
|
||||
private:
|
||||
std::string _path;
|
||||
@ -70,6 +71,8 @@ private:
|
||||
|
||||
friend class FileHandle;
|
||||
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();
|
||||
findPath.append("*");
|
||||
std::wstring uFindPath;
|
||||
UnicodeConverter::toUTF16(findPath, uFindPath);
|
||||
FileImpl::convertPath(findPath, uFindPath);
|
||||
|
||||
_fh = FindFirstFileW(uFindPath.c_str(), &_fd);
|
||||
if (_fh == INVALID_HANDLE_VALUE)
|
||||
|
@ -29,9 +29,6 @@
|
||||
#include "Poco/Event.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/Buffer.h"
|
||||
#if defined(POCO_WIN32_UTF8)
|
||||
#include "Poco/UnicodeConverter.h"
|
||||
#endif
|
||||
#if POCO_OS == POCO_OS_LINUX
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/select.h>
|
||||
@ -200,7 +197,7 @@ public:
|
||||
std::string path(owner().directory().path());
|
||||
#if defined(POCO_WIN32_UTF8)
|
||||
std::wstring upath;
|
||||
Poco::UnicodeConverter::toUTF16(path.c_str(), upath);
|
||||
FileImpl::convertPath(path.c_str(), upath);
|
||||
HANDLE hChange = FindFirstChangeNotificationW(upath.c_str(), FALSE, filter);
|
||||
#else
|
||||
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)
|
||||
std::wstring utf16Path;
|
||||
UnicodeConverter::toUTF16(path, utf16Path);
|
||||
FileImpl::convertPath(path, utf16Path);
|
||||
_handle = CreateFileW(utf16Path.c_str(), access, shareMode, NULL, creationDisp, flags, NULL);
|
||||
#else
|
||||
_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);
|
||||
}
|
||||
UnicodeConverter::toUTF16(_path, _upath);
|
||||
convertPath(_path, _upath);
|
||||
}
|
||||
|
||||
|
||||
@ -87,7 +87,7 @@ void FileImpl::setPathImpl(const std::string& path)
|
||||
{
|
||||
_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());
|
||||
|
||||
std::wstring upath;
|
||||
UnicodeConverter::toUTF16(path, upath);
|
||||
convertPath(path, upath);
|
||||
if (CopyFileW(_upath.c_str(), upath.c_str(), FALSE) == 0)
|
||||
handleLastErrorImpl(_path);
|
||||
}
|
||||
@ -304,7 +304,7 @@ void FileImpl::renameToImpl(const std::string& path)
|
||||
poco_assert (!_path.empty());
|
||||
|
||||
std::wstring upath;
|
||||
UnicodeConverter::toUTF16(path, upath);
|
||||
convertPath(path, upath);
|
||||
if (MoveFileExW(_upath.c_str(), upath.c_str(), MOVEFILE_REPLACE_EXISTING) == 0)
|
||||
handleLastErrorImpl(_path);
|
||||
}
|
||||
@ -439,4 +439,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
|
||||
|
@ -64,7 +64,7 @@ FileImpl::FileImpl(const std::string& path): _path(path)
|
||||
{
|
||||
_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);
|
||||
}
|
||||
UnicodeConverter::toUTF16(_path, _upath);
|
||||
convertPath(_path, _upath);
|
||||
}
|
||||
|
||||
|
||||
@ -284,7 +284,7 @@ void FileImpl::copyToImpl(const std::string& path) const
|
||||
poco_assert (!_path.empty());
|
||||
|
||||
std::wstring upath;
|
||||
UnicodeConverter::toUTF16(path, upath);
|
||||
convertPath(path, upath);
|
||||
if (CopyFileW(_upath.c_str(), upath.c_str(), FALSE) == 0)
|
||||
handleLastErrorImpl(_path);
|
||||
}
|
||||
@ -295,7 +295,7 @@ void FileImpl::renameToImpl(const std::string& path)
|
||||
poco_assert (!_path.empty());
|
||||
|
||||
std::wstring upath;
|
||||
UnicodeConverter::toUTF16(path, upath);
|
||||
convertPath(path, upath);
|
||||
if (MoveFileW(_upath.c_str(), upath.c_str()) == 0)
|
||||
handleLastErrorImpl(_path);
|
||||
}
|
||||
@ -429,4 +429,9 @@ void FileImpl::handleLastErrorImpl(const std::string& path)
|
||||
}
|
||||
|
||||
|
||||
void FileImpl::convertPath(const std::string& utf8Path, std::wstring& utf16Path)
|
||||
{
|
||||
UnicodeConverter::toUTF16(utf8Path, utf16Path);
|
||||
}
|
||||
|
||||
} // namespace Poco
|
||||
|
@ -90,7 +90,7 @@ const std::string& LogFileImpl::pathImpl() const
|
||||
void LogFileImpl::createFile()
|
||||
{
|
||||
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);
|
||||
if (_hFile == INVALID_HANDLE_VALUE) throw OpenFileException(_path);
|
||||
|
@ -20,6 +20,9 @@
|
||||
#include "Poco/NamedEvent.h"
|
||||
#include "Poco/UnicodeConverter.h"
|
||||
#include "Poco/Pipe.h"
|
||||
#include "Poco/File.h"
|
||||
#include "Poco/Path.h"
|
||||
#include "Poco/String.h"
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
std::string commandLine = command;
|
||||
std::string commandLine = escapeArg(command);
|
||||
for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it)
|
||||
{
|
||||
commandLine.append(" ");
|
||||
@ -174,6 +177,19 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
|
||||
std::wstring 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;
|
||||
GetStartupInfoW(&startupInfo); // take defaults from current process
|
||||
startupInfo.cb = sizeof(STARTUPINFOW);
|
||||
@ -253,7 +269,7 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
|
||||
PROCESS_INFORMATION processInfo;
|
||||
DWORD creationFlags = GetConsoleWindow() ? 0 : CREATE_NO_WINDOW;
|
||||
BOOL rc = CreateProcessW(
|
||||
NULL, // applicationName
|
||||
applicationName,
|
||||
const_cast<wchar_t*>(ucommandLine.c_str()),
|
||||
NULL, // processAttributes
|
||||
NULL, // threadAttributes
|
||||
|
@ -524,6 +524,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()
|
||||
{
|
||||
File f("testfile.dat");
|
||||
@ -568,6 +592,7 @@ CppUnit::Test* FileTest::suite()
|
||||
CppUnit_addTest(pSuite, FileTest, testCopyDirectory);
|
||||
CppUnit_addTest(pSuite, FileTest, testRename);
|
||||
CppUnit_addTest(pSuite, FileTest, testRootDir);
|
||||
CppUnit_addTest(pSuite, FileTest, testLongPath);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ public:
|
||||
void testCopyDirectory();
|
||||
void testRename();
|
||||
void testRootDir();
|
||||
void testLongPath();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
Loading…
Reference in New Issue
Block a user