// // VMime library (http://www.vmime.org) // Copyright (C) 2002-2013 Vincent Richard // // This program 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 3 of // the License, or (at your option) any later version. // // This program 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 this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // // Linking this library statically or dynamically with other modules is making // a combined work based on this library. Thus, the terms and conditions of // the GNU General Public License cover the whole combination. // #include "vmime/config.hpp" #if VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_FILESYSTEM_FEATURES #include "vmime/platforms/windows/windowsFile.hpp" #include #include #include "vmime/exception.hpp" #include "vmime/utility/stringUtils.hpp" namespace vmime { namespace platforms { namespace windows { shared_ptr windowsFileSystemFactory::create(const vmime::utility::file::path& path) const { return make_shared (path); } const vmime::utility::file::path windowsFileSystemFactory::stringToPath(const vmime::string& str) const { return (stringToPathImpl(str)); } const vmime::string windowsFileSystemFactory::pathToString(const vmime::utility::file::path& path) const { return (pathToStringImpl(path)); } const vmime::utility::file::path windowsFileSystemFactory::stringToPathImpl(const vmime::string& str) { vmime::string::size_type offset = 0; vmime::string::size_type prev = 0; vmime::utility::file::path path; while ((offset = str.find_first_of("\\", offset)) != vmime::string::npos) { if (offset != prev) path.appendComponent(vmime::string(str.begin() + prev, str.begin() + offset)); prev = offset + 1; offset++; } if (prev < str.length()) path.appendComponent(vmime::string(str.begin() + prev, str.end())); return (path); } const vmime::string windowsFileSystemFactory::pathToStringImpl(const vmime::utility::file::path& path) { vmime::string native = ""; for (int i = 0 ; i < path.getSize() ; ++i) { if (i > 0) native += "\\"; native += path[i].getBuffer(); } return (native); } bool windowsFileSystemFactory::isValidPathComponent(const vmime::utility::file::path::component& comp) const { return isValidPathComponent(comp, false); } bool windowsFileSystemFactory::isValidPathComponent( const vmime::utility::file::path::component& comp, bool firstComponent) const { const string& buffer = comp.getBuffer(); // If first component, check if component is a drive if (firstComponent && (buffer.length() == 2) && (buffer[1] == ':')) { char drive = tolower(buffer[0]); if ((drive >= 'a') && (drive <= 'z')) return true; } // Check for invalid characters for (string::size_type i = 0 ; i < buffer.length() ; ++i) { const unsigned char c = buffer[i]; switch (c) { // Reserved characters case '<': case '>': case ':': case '"': case '/': case '\\': case '|': case '$': case '*': return false; default: if (c <= 31) return false; } } string upperBuffer = vmime::utility::stringUtils::toUpper(buffer); // Check for reserved names if (upperBuffer.length() == 3) { if (upperBuffer == "CON" || buffer == "PRN" || buffer == "AUX" || buffer == "NUL") return false; } else if (upperBuffer.length() == 4) { if ((upperBuffer.substr(0, 3) == "COM") && // COM0 to COM9 (upperBuffer[3] >= '0') && (upperBuffer[3] <= '9')) { return false; } else if ((upperBuffer.substr(0, 3) == "LPT") && // LPT0 to LPT9 (upperBuffer[3] >= '0') && (upperBuffer[3] <= '9')) { return false; } } return true; } bool windowsFileSystemFactory::isValidPath(const vmime::utility::file::path& path) const { for (int i = 0 ; i < path.getSize() ; ++i) { if (!isValidPathComponent(path[i], (i==0))) return false; } return true; } void windowsFileSystemFactory::reportError(const vmime::utility::path& path, const int err) { vmime::string desc; LPVOID lpMsgBuf; if (FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL )) { desc = (char*)lpMsgBuf; LocalFree( lpMsgBuf ); } throw vmime::exceptions::filesystem_exception(desc, path); } windowsFile::windowsFile(const vmime::utility::file::path& path) : m_path(path), m_nativePath(windowsFileSystemFactory::pathToStringImpl(path)) { } void windowsFile::createFile() { HANDLE hFile = CreateFile( m_nativePath.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) windowsFileSystemFactory::reportError(m_path, GetLastError()); CloseHandle(hFile); } void windowsFile::createDirectory(const bool createAll) { createDirectoryImpl(m_path, m_path, createAll); } bool windowsFile::isFile() const { DWORD dwFileAttribute = GetFileAttributes(m_nativePath.c_str()); if (dwFileAttribute == INVALID_FILE_ATTRIBUTES) return false; return (dwFileAttribute & FILE_ATTRIBUTE_DIRECTORY) == 0; } bool windowsFile::isDirectory() const { DWORD dwFileAttribute = GetFileAttributes(m_nativePath.c_str()); if (dwFileAttribute == INVALID_FILE_ATTRIBUTES) return false; return (dwFileAttribute & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY; } bool windowsFile::canRead() const { HANDLE hFile = CreateFile( m_nativePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return false; CloseHandle(hFile); return true; } bool windowsFile::canWrite() const { HANDLE hFile = CreateFile( m_nativePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return false; CloseHandle(hFile); return true; } windowsFile::length_type windowsFile::getLength() { HANDLE hFile = CreateFile( m_nativePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) windowsFileSystemFactory::reportError(m_path, GetLastError()); DWORD dwSize = GetFileSize(hFile, NULL); CloseHandle(hFile); return dwSize; } const vmime::utility::path& windowsFile::getFullPath() const { return m_path; } bool windowsFile::exists() const { WIN32_FIND_DATA findData; HANDLE hFind = FindFirstFile(m_nativePath.c_str(), &findData); if (hFind != INVALID_HANDLE_VALUE) { FindClose(hFind); return true; } return false; } shared_ptr windowsFile::getParent() const { if (m_path.isEmpty()) return NULL; else return make_shared (m_path.getParent()); } void windowsFile::rename(const path& newName) { const vmime::string newNativeName = windowsFileSystemFactory::pathToStringImpl(newName); if (MoveFile(m_nativePath.c_str(), newNativeName.c_str())) { m_path = newName; m_nativePath = newNativeName; } else windowsFileSystemFactory::reportError(m_path, GetLastError()); } void windowsFile::remove() { if (!DeleteFile(m_nativePath.c_str())) windowsFileSystemFactory::reportError(m_path, GetLastError()); } shared_ptr windowsFile::getFileWriter() { return make_shared (m_path, m_nativePath); } shared_ptr windowsFile::getFileReader() { return make_shared (m_path, m_nativePath); } shared_ptr windowsFile::getFiles() const { return make_shared (m_path, m_nativePath); } void windowsFile::createDirectoryImpl(const vmime::utility::file::path& fullPath, const vmime::utility::file::path& path, const bool recursive) { const vmime::string nativePath = windowsFileSystemFactory::pathToStringImpl(path); windowsFile tmp(fullPath); if (tmp.isDirectory()) return; if (!path.isEmpty() && recursive) createDirectoryImpl(fullPath, path.getParent(), true); if (!CreateDirectory(nativePath.c_str(), NULL)) windowsFileSystemFactory::reportError(fullPath, GetLastError()); } windowsFileIterator::windowsFileIterator(const vmime::utility::file::path& path, const vmime::string& nativePath) : m_path(path), m_nativePath(nativePath), m_moreElements(false), m_hFind(INVALID_HANDLE_VALUE) { findFirst(); } windowsFileIterator::~windowsFileIterator() { if (m_hFind != INVALID_HANDLE_VALUE) FindClose(m_hFind); } bool windowsFileIterator::hasMoreElements() const { return m_moreElements; } shared_ptr windowsFileIterator::nextElement() { shared_ptr pFile = make_shared (m_path / vmime::utility::file::path::component(m_findData.cFileName)); findNext(); return pFile; } void windowsFileIterator::findFirst() { m_hFind = FindFirstFile(m_nativePath.c_str(), &m_findData); if (m_hFind == INVALID_HANDLE_VALUE) { m_moreElements = false; return; } m_moreElements = true; if (isCurrentOrParentDir()) findNext(); } void windowsFileIterator::findNext() { do { if (!FindNextFile(m_hFind, &m_findData)) { m_moreElements = false; return; } } while (isCurrentOrParentDir()); } bool windowsFileIterator::isCurrentOrParentDir() const { vmime::string s(m_findData.cFileName); if ((s == ".") || (s == "..")) return true; return false; } windowsFileReader::windowsFileReader(const vmime::utility::file::path& path, const vmime::string& nativePath) : m_path(path), m_nativePath(nativePath) { } shared_ptr windowsFileReader::getInputStream() { HANDLE hFile = CreateFile( m_nativePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) windowsFileSystemFactory::reportError(m_path, GetLastError()); return make_shared (m_path, hFile); } windowsFileReaderInputStream::windowsFileReaderInputStream(const vmime::utility::file::path& path, HANDLE hFile) : m_path(path), m_hFile(hFile) { } windowsFileReaderInputStream::~windowsFileReaderInputStream() { CloseHandle(m_hFile); } bool windowsFileReaderInputStream::eof() const { DWORD dwSize = GetFileSize(m_hFile, NULL); DWORD dwPosition = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT); return (dwSize == dwPosition); } void windowsFileReaderInputStream::reset() { SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN); } vmime::utility::stream::size_type windowsFileReaderInputStream::read(value_type* const data, const size_type count) { DWORD dwBytesRead; if (!ReadFile(m_hFile, (LPVOID)data, (DWORD)count, &dwBytesRead, NULL)) windowsFileSystemFactory::reportError(m_path, GetLastError()); return dwBytesRead; } vmime::utility::stream::size_type windowsFileReaderInputStream::skip(const size_type count) { DWORD dwCurPos = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT); DWORD dwNewPos = SetFilePointer(m_hFile, (LONG)count, NULL, FILE_CURRENT); return (dwNewPos - dwCurPos); } vmime::utility::stream::size_type windowsFileReaderInputStream::getPosition() const { DWORD dwCurPos = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT); if (dwCurPos == INVALID_SET_FILE_POINTER) windowsFileSystemFactory::reportError(m_path, GetLastError()); return static_cast (dwCurPos); } void windowsFileReaderInputStream::seek(const size_type pos) { DWORD dwNewPos = SetFilePointer(m_hFile, (LONG)pos, NULL, FILE_BEGIN); if (dwNewPos == INVALID_SET_FILE_POINTER) windowsFileSystemFactory::reportError(m_path, GetLastError()); } windowsFileWriter::windowsFileWriter(const vmime::utility::file::path& path, const vmime::string& nativePath) : m_path(path), m_nativePath(nativePath) { } shared_ptr windowsFileWriter::getOutputStream() { HANDLE hFile = CreateFile( m_nativePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) windowsFileSystemFactory::reportError(m_path, GetLastError()); return make_shared (m_path, hFile); } windowsFileWriterOutputStream::windowsFileWriterOutputStream(const vmime::utility::file::path& path, HANDLE hFile) : m_path(path), m_hFile(hFile) { } windowsFileWriterOutputStream::~windowsFileWriterOutputStream() { CloseHandle(m_hFile); } void windowsFileWriterOutputStream::write(const value_type* const data, const size_type count) { DWORD dwBytesWritten; if (!WriteFile(m_hFile, data, (DWORD)count, &dwBytesWritten, NULL)) windowsFileSystemFactory::reportError(m_path, GetLastError()); } void windowsFileWriterOutputStream::flush() { // TODO } } // windows } // platforms } // vmime #endif // VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_FILESYSTEM_FEATURES