diff options
| author | Carl Hetherington <cth@carlh.net> | 2016-01-05 15:32:10 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2016-01-05 15:32:10 +0000 |
| commit | 3ec4338ce90ea0549409312f24f8b28c07a5d2da (patch) | |
| tree | 09aaaff66dd860abbeacc20793145e1a27f4defd /asdcplib/src/KM_fileio.cpp | |
| parent | 342aad2ddf893aaaafa9a2c9980579d2dc4ec125 (diff) | |
asdcplib 2.5.11
Diffstat (limited to 'asdcplib/src/KM_fileio.cpp')
| -rw-r--r-- | asdcplib/src/KM_fileio.cpp | 746 |
1 files changed, 502 insertions, 244 deletions
diff --git a/asdcplib/src/KM_fileio.cpp b/asdcplib/src/KM_fileio.cpp index b20ff7f7..459a08d9 100644 --- a/asdcplib/src/KM_fileio.cpp +++ b/asdcplib/src/KM_fileio.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004-2011, John Hurst +Copyright (c) 2004-2014, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -25,15 +25,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*! \file KM_fileio.cpp - \version $Id: KM_fileio.cpp,v 1.31 2011/03/08 19:03:47 jhurst Exp $ + \version $Id: KM_fileio.cpp,v 1.40 2015/10/07 16:58:03 jhurst Exp $ \brief portable file i/o */ #include <KM_fileio.h> #include <KM_log.h> #include <fcntl.h> -#include <sstream> -#include <iomanip> #include <assert.h> @@ -45,12 +43,18 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define _rmdir rmdir #endif +// only needed by GetExecutablePath() +#if defined(KM_MACOSX) +#include <mach-o/dyld.h> +#endif + using namespace Kumu; #ifdef KM_WIN32 typedef struct _stati64 fstat_t; #define S_IFLNK 0 + // win32 has WriteFileGather() and ReadFileScatter() but they // demand page alignment and page sizing, making them unsuitable // for use with arbitrary buffer sizes. @@ -71,31 +75,6 @@ struct iovec { typedef struct stat fstat_t; #endif -// -static void -split(const std::string& str, char separator, std::list<std::string>& components) -{ - const char* pstr = str.c_str(); - const char* r = strchr(pstr, separator); - - while ( r != 0 ) - { - assert(r >= pstr); - if ( r > pstr ) - { - std::string tmp_str; - tmp_str.assign(pstr, (r - pstr)); - components.push_back(tmp_str); - } - - pstr = r + 1; - r = strchr(pstr, separator); - } - - if( strlen(pstr) > 0 ) - components.push_back(std::string(pstr)); -} - // static Kumu::Result_t @@ -109,18 +88,9 @@ do_stat(const char* path, fstat_t* stat_info) #ifdef KM_WIN32 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); - int const wn = MultiByteToWideChar (CP_UTF8, 0, path, -1, 0, 0); - wchar_t* buffer = new wchar_t[wn]; - if (MultiByteToWideChar (CP_UTF8, 0, path, -1, buffer, wn) == 0) { - delete[] buffer; - return Kumu::RESULT_FAIL; - } - - if ( _wstati64(buffer, stat_info) == (__int64)-1 ) + if ( _stati64(path, stat_info) == (__int64)-1 ) result = Kumu::RESULT_FILEOPEN; - delete[] buffer; - ::SetErrorMode( prev ); #else if ( stat(path, stat_info) == -1L ) @@ -226,62 +196,66 @@ Kumu::FileSize(const std::string& pathname) } // -static PathCompList_t& -s_PathMakeCanonical(PathCompList_t& CList, bool is_absolute) +static void +make_canonical_list(const PathCompList_t& in_list, PathCompList_t& out_list) { - PathCompList_t::iterator ci, ri; // component and removal iterators - - for ( ci = CList.begin(); ci != CList.end(); ci++ ) + PathCompList_t::const_iterator i; + for ( i = in_list.begin(); i != in_list.end(); ++i ) { - if ( *ci == "." && ( CList.size() > 1 || is_absolute ) ) - { - ri = ci++; - CList.erase(ri); - } - else if ( *ci == ".." && ci != CList.begin() ) + if ( *i == ".." ) { - ri = ci; - ri--; - - if ( *ri != ".." ) + if ( ! out_list.empty() ) { - CList.erase(ri); - ri = ci++; - CList.erase(ri); - } - } + out_list.pop_back(); + } + } + else if ( *i != "." ) + { + out_list.push_back(*i); + } } - - return CList; } // std::string Kumu::PathMakeCanonical(const std::string& Path, char separator) { - PathCompList_t CList; + PathCompList_t in_list, out_list; bool is_absolute = PathIsAbsolute(Path, separator); - s_PathMakeCanonical(PathToComponents(Path, CList, separator), is_absolute); + PathToComponents(Path, in_list, separator); + make_canonical_list(in_list, out_list); if ( is_absolute ) - return ComponentsToAbsolutePath(CList, separator); + return ComponentsToAbsolutePath(out_list, separator); - return ComponentsToPath(CList, separator); + return ComponentsToPath(out_list, separator); } // bool Kumu::PathsAreEquivalent(const std::string& lhs, const std::string& rhs) { - return PathMakeCanonical(lhs) == PathMakeCanonical(rhs); + return PathMakeAbsolute(lhs) == PathMakeAbsolute(rhs); } // Kumu::PathCompList_t& -Kumu::PathToComponents(const std::string& Path, PathCompList_t& CList, char separator) +Kumu::PathToComponents(const std::string& path, PathCompList_t& component_list, char separator) { - split(Path, separator, CList); - return CList; + std::string s; + s = separator; + PathCompList_t tmp_list = km_token_split(path, std::string(s)); + PathCompList_t::const_iterator i; + + for ( i = tmp_list.begin(); i != tmp_list.end(); ++i ) + { + if ( ! i->empty() ) + { + component_list.push_back(*i); + } + } + + return component_list; } // @@ -344,18 +318,8 @@ Kumu::PathIsAbsolute(const std::string& Path, char separator) // std::string -Kumu::PathMakeAbsolute(const std::string& Path, char separator) +Kumu::PathCwd() { - if ( Path.empty() ) - { - std::string out_path; - out_path = separator; - return out_path; - } - - if ( PathIsAbsolute(Path, separator) ) - return Path; - char cwd_buf [MaxFilePath]; if ( _getcwd(cwd_buf, MaxFilePath) == 0 ) { @@ -363,11 +327,28 @@ Kumu::PathMakeAbsolute(const std::string& Path, char separator) return ""; } - PathCompList_t CList; - PathToComponents(cwd_buf, CList); - CList.push_back(Path); + return cwd_buf; +} + +// +std::string +Kumu::PathMakeAbsolute(const std::string& Path, char separator) +{ + if ( Path.empty() ) + { + std::string tmpstr; + tmpstr = separator; + return tmpstr; + } + + if ( PathIsAbsolute(Path, separator) ) + return PathMakeCanonical(Path); - return ComponentsToAbsolutePath(s_PathMakeCanonical(CList, true), separator); + PathCompList_t in_list, out_list; + PathToComponents(PathJoin(PathCwd(), Path), in_list); + make_canonical_list(in_list, out_list); + + return ComponentsToAbsolutePath(out_list); } // @@ -465,6 +446,69 @@ Kumu::PathJoin(const std::string& Path1, const std::string& Path2, return Path1 + separator + Path2 + separator + Path3 + separator + Path4; } +#ifndef KM_WIN32 +// returns false if link cannot be read +// +bool +Kumu::PathResolveLinks(const std::string& link_path, std::string& resolved_path, char separator) +{ + PathCompList_t in_list, out_list; + PathToComponents(PathMakeCanonical(link_path), in_list, separator); + PathCompList_t::iterator i; + char link_buf[MaxFilePath]; + + for ( i = in_list.begin(); i != in_list.end(); ++i ) + { + assert ( *i != ".." && *i != "." ); + out_list.push_back(*i); + + for (;;) + { + std::string next_link = ComponentsToAbsolutePath(out_list, separator); + ssize_t link_size = readlink(next_link.c_str(), link_buf, MaxFilePath); + + if ( link_size == -1 ) + { + if ( errno == EINVAL ) + break; + + DefaultLogSink().Error("%s: readlink: %s\n", next_link.c_str(), strerror(errno)); + return false; + } + + assert(link_size < MaxFilePath); + link_buf[link_size] = 0; + std::string tmp_path; + out_list.clear(); + + if ( PathIsAbsolute(link_buf) ) + { + tmp_path = link_buf; + } + else + { + tmp_path = PathJoin(PathDirname(next_link), link_buf); + } + + PathToComponents(PathMakeCanonical(tmp_path), out_list, separator); + } + } + + resolved_path = ComponentsToAbsolutePath(out_list, separator); + return true; +} + +#else // KM_WIN32 +// TODO: is there a reasonable equivalent to be written for win32? +// +bool +Kumu::PathResolveLinks(const std::string& link_path, std::string& resolved_path, char separator) +{ + resolved_path = link_path; + return true; +} +#endif + // Kumu::PathList_t& Kumu::FindInPaths(const IPathMatch& Pattern, const Kumu::PathList_t& SearchPaths, @@ -587,6 +631,55 @@ Kumu::PathMatchGlob::Match(const std::string& s) const { #endif + +//------------------------------------------------------------------------------------------ + +#define X_BUFSIZE 1024 + +// +std::string +Kumu::GetExecutablePath(const std::string& default_path) +{ + char path[X_BUFSIZE] = {0}; + bool success = false; + +#if defined(KM_WIN32) + DWORD size = X_BUFSIZE; + DWORD rc = GetModuleFileName(0, path, size); + success = ( rc != 0 ); +#elif defined(KM_MACOSX) + uint32_t size = X_BUFSIZE; + int rc = _NSGetExecutablePath(path, &size); + success = ( rc != -1 ); +#elif defined(__linux__) + size_t size = X_BUFSIZE; + ssize_t rc = readlink("/proc/self/exe", path, size); + success = ( rc != -1 ); +#elif defined(__OpenBSD__) || defined(__FreeBSD__) + size_t size = X_BUFSIZE; + ssize_t rc = readlink("/proc/curproc/file", path, size); + success = ( rc != -1 ); +#elif defined(__FreeBSD__) + size_t size = X_BUFSIZE; + ssize_t rc = readlink("/proc/curproc/file", path, size); + success = ( rc != -1 ); +#elif defined(__NetBSD__) + size_t size = X_BUFSIZE; + ssize_t rc = readlink("/proc/curproc/file", path, size); + success = ( rc != -1 ); +#else +#error GetExecutablePath --> Create a method for obtaining the executable name +#endif + + if ( success ) + { + return Kumu::PathMakeCanonical(path); + } + + return default_path; +} + + //------------------------------------------------------------------------------------------ // portable aspects of the file classes @@ -624,10 +717,7 @@ Kumu::FileReader::Size() const // these are declared here instead of in the header file // because we have a mem_ptr that is managing a hidden class -Kumu::FileWriter::FileWriter() - : m_Hashing (false) -{} - +Kumu::FileWriter::FileWriter() {} Kumu::FileWriter::~FileWriter() {} // @@ -652,59 +742,20 @@ Kumu::FileWriter::Writev(const byte_t* buf, ui32_t buf_len) return RESULT_OK; } -void -Kumu::FileWriter::StartHashing() -{ - m_Hashing = true; - MD5_Init (&m_MD5Context); -} - -void -Kumu::FileWriter::MaybeHash(void const * data, int size) -{ - if (m_Hashing) { - MD5_Update (&m_MD5Context, data, size); - } -} - -std::string -Kumu::FileWriter::StopHashing() -{ - m_Hashing = false; - - unsigned char digest[MD5_DIGEST_LENGTH]; - MD5_Final (digest, &m_MD5Context); - - std::stringstream s; - for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) { - s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]); - } - - return s.str (); -} - #ifdef KM_WIN32 //------------------------------------------------------------------------------------------ // -/** @param filename File name (UTF-8 encoded) */ Kumu::Result_t -Kumu::FileReader::OpenRead(const char* filename) const +Kumu::FileReader::OpenRead(const std::string& filename) const { - KM_TEST_NULL_STR_L(filename); const_cast<FileReader*>(this)->m_Filename = filename; // suppress popup window on error UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); - int const wn = MultiByteToWideChar (CP_UTF8, 0, filename, -1, 0, 0); - wchar_t* buffer = new wchar_t[wn]; - if (MultiByteToWideChar (CP_UTF8, 0, filename, -1, buffer, wn) == 0) { - delete[] buffer; - return Kumu::RESULT_FAIL; - } - const_cast<FileReader*>(this)->m_Handle = ::CreateFileW(buffer, + const_cast<FileReader*>(this)->m_Handle = ::CreateFileA(filename.c_str(), (GENERIC_READ), // open for reading FILE_SHARE_READ, // share for reading NULL, // no security @@ -713,8 +764,6 @@ Kumu::FileReader::OpenRead(const char* filename) const NULL // no template file ); - delete[] buffer; - ::SetErrorMode(prev); return ( m_Handle == INVALID_HANDLE_VALUE ) ? @@ -821,24 +870,16 @@ Kumu::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const //------------------------------------------------------------------------------------------ // -/** @param filename File name (UTF-8 encoded) */ +// Kumu::Result_t -Kumu::FileWriter::OpenWrite(const char* filename) +Kumu::FileWriter::OpenWrite(const std::string& filename) { - KM_TEST_NULL_STR_L(filename); m_Filename = filename; // suppress popup window on error UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); - int const wn = MultiByteToWideChar (CP_UTF8, 0, filename, -1, 0, 0); - wchar_t* buffer = new wchar_t[wn]; - if (MultiByteToWideChar (CP_UTF8, 0, filename, -1, buffer, wn) == 0) { - delete[] buffer; - return Kumu::RESULT_FAIL; - } - - m_Handle = ::CreateFileW(buffer, + m_Handle = ::CreateFileA(filename.c_str(), (GENERIC_WRITE|GENERIC_READ), // open for reading FILE_SHARE_READ, // share for reading NULL, // no security @@ -847,45 +888,6 @@ Kumu::FileWriter::OpenWrite(const char* filename) NULL // no template file ); - delete[] buffer; - - ::SetErrorMode(prev); - - if ( m_Handle == INVALID_HANDLE_VALUE ) - return Kumu::RESULT_FILEOPEN; - - m_IOVec = new h__iovec; - return Kumu::RESULT_OK; -} - -/** @param filename File name (UTF-8 encoded) */ -Kumu::Result_t -Kumu::FileWriter::OpenModify(const char* filename) -{ - KM_TEST_NULL_STR_L(filename); - m_Filename = filename; - - // suppress popup window on error - UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); - - int const wn = MultiByteToWideChar (CP_UTF8, 0, filename, -1, 0, 0); - wchar_t* buffer = new wchar_t[wn]; - if (MultiByteToWideChar (CP_UTF8, 0, filename, -1, buffer, wn) == 0) { - delete[] buffer; - return Kumu::RESULT_FAIL; - } - - m_Handle = ::CreateFileW(buffer, - (GENERIC_WRITE|GENERIC_READ), // open for reading - FILE_SHARE_READ, // share for reading - NULL, // no security - OPEN_ALWAYS, // don't truncate existing - FILE_ATTRIBUTE_NORMAL, // normal file - NULL // no template file - ); - - delete[] buffer; - ::SetErrorMode(prev); if ( m_Handle == INVALID_HANDLE_VALUE ) @@ -929,7 +931,6 @@ Kumu::FileWriter::Writev(ui32_t* bytes_written) break; } - MaybeHash (iov->m_iovec[i].iov_base, iov->m_iovec[i].iov_len); *bytes_written += tmp_count; } @@ -960,8 +961,6 @@ Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written if ( result == 0 || *bytes_written != buf_len ) return Kumu::RESULT_WRITEFAIL; - MaybeHash (buf, buf_len); - return Kumu::RESULT_OK; } @@ -971,11 +970,10 @@ Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written // Kumu::Result_t -Kumu::FileReader::OpenRead(const char* filename) const +Kumu::FileReader::OpenRead(const std::string& filename) const { - KM_TEST_NULL_STR_L(filename); const_cast<FileReader*>(this)->m_Filename = filename; - const_cast<FileReader*>(this)->m_Handle = open(filename, O_RDONLY, 0); + const_cast<FileReader*>(this)->m_Handle = open(filename.c_str(), O_RDONLY, 0); return ( m_Handle == -1L ) ? RESULT_FILEOPEN : RESULT_OK; } @@ -1051,15 +1049,14 @@ Kumu::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const // Kumu::Result_t -Kumu::FileWriter::OpenWrite(const char* filename) +Kumu::FileWriter::OpenWrite(const std::string& filename) { - KM_TEST_NULL_STR_L(filename); m_Filename = filename; - m_Handle = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0664); + m_Handle = open(filename.c_str(), O_RDWR|O_CREAT|O_TRUNC, 0664); if ( m_Handle == -1L ) { - DefaultLogSink().Error("Error opening file %s: %s\n", filename, strerror(errno)); + DefaultLogSink().Error("Error opening file %s: %s\n", filename.c_str(), strerror(errno)); return RESULT_FILEOPEN; } @@ -1069,15 +1066,14 @@ Kumu::FileWriter::OpenWrite(const char* filename) // Kumu::Result_t -Kumu::FileWriter::OpenModify(const char* filename) +Kumu::FileWriter::OpenModify(const std::string& filename) { - KM_TEST_NULL_STR_L(filename); m_Filename = filename; - m_Handle = open(filename, O_RDWR|O_CREAT, 0664); + m_Handle = open(filename.c_str(), O_RDWR|O_CREAT, 0664); if ( m_Handle == -1L ) { - DefaultLogSink().Error("Error opening file %s: %s\n", filename, strerror(errno)); + DefaultLogSink().Error("Error opening file %s: %s\n", filename.c_str(), strerror(errno)); return RESULT_FILEOPEN; } @@ -1108,10 +1104,6 @@ Kumu::FileWriter::Writev(ui32_t* bytes_written) if ( write_size == -1L || write_size != total_size ) return RESULT_WRITEFAIL; - for (int i = 0; i < iov->m_Count; ++i) { - MaybeHash (iov->m_iovec[i].iov_base, iov->m_iovec[i].iov_len); - } - iov->m_Count = 0; *bytes_written = write_size; return RESULT_OK; @@ -1131,7 +1123,6 @@ Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written return RESULT_STATE; int write_size = write(m_Handle, buf, buf_len); - MaybeHash (buf, buf_len); if ( write_size == -1L || (ui32_t)write_size != buf_len ) return RESULT_WRITEFAIL; @@ -1141,22 +1132,20 @@ Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written } -#endif +#endif // KM_WIN32 //------------------------------------------------------------------------------------------ // Kumu::Result_t -Kumu::ReadFileIntoString(const char* filename, std::string& outString, ui32_t max_size) +Kumu::ReadFileIntoString(const std::string& filename, std::string& outString, ui32_t max_size) { fsize_t fsize = 0; ui32_t read_size = 0; FileReader File; ByteString ReadBuf; - KM_TEST_NULL_STR_L(filename); - Result_t result = File.OpenRead(filename); if ( KM_SUCCESS(result) ) @@ -1165,13 +1154,13 @@ Kumu::ReadFileIntoString(const char* filename, std::string& outString, ui32_t ma if ( fsize > (Kumu::fpos_t)max_size ) { - DefaultLogSink().Error("%s: exceeds available buffer size (%u)\n", filename, max_size); + DefaultLogSink().Error("%s: exceeds available buffer size (%u)\n", filename.c_str(), max_size); return RESULT_ALLOC; } if ( fsize == 0 ) { - DefaultLogSink().Error("%s: zero file size\n", filename); + DefaultLogSink().Error("%s: zero file size\n", filename.c_str()); return RESULT_READFAIL; } @@ -1190,11 +1179,10 @@ Kumu::ReadFileIntoString(const char* filename, std::string& outString, ui32_t ma // Kumu::Result_t -Kumu::WriteStringIntoFile(const char* filename, const std::string& inString) +Kumu::WriteStringIntoFile(const std::string& filename, const std::string& inString) { FileWriter File; ui32_t write_count = 0; - KM_TEST_NULL_STR_L(filename); Result_t result = File.OpenWrite(filename); @@ -1209,7 +1197,7 @@ Kumu::WriteStringIntoFile(const char* filename, const std::string& inString) // Kumu::Result_t -Kumu::ReadFileIntoObject(const std::string& Filename, Kumu::IArchive& Object, ui32_t) +Kumu::ReadFileIntoObject(const std::string& Filename, Kumu::IArchive& Object, ui32_t max_size) { ByteString Buffer; ui32_t file_size = static_cast<ui32_t>(FileSize(Filename)); @@ -1220,7 +1208,7 @@ Kumu::ReadFileIntoObject(const std::string& Filename, Kumu::IArchive& Object, ui ui32_t read_count = 0; FileWriter Reader; - result = Reader.OpenRead(Filename.c_str()); + result = Reader.OpenRead(Filename); if ( KM_SUCCESS(result) ) result = Reader.Read(Buffer.Data(), file_size, &read_count); @@ -1255,7 +1243,7 @@ Kumu::WriteObjectIntoFile(const Kumu::IArchive& Object, const std::string& Filen if ( KM_SUCCESS(result) ) { Buffer.Length(MemWriter.Length()); - result = Writer.OpenWrite(Filename.c_str()); + result = Writer.OpenWrite(Filename); } if ( KM_SUCCESS(result) ) @@ -1270,7 +1258,7 @@ Kumu::WriteObjectIntoFile(const Kumu::IArchive& Object, const std::string& Filen // Result_t -Kumu::ReadFileIntoBuffer(const std::string& Filename, Kumu::ByteString& Buffer, ui32_t) +Kumu::ReadFileIntoBuffer(const std::string& Filename, Kumu::ByteString& Buffer, ui32_t max_size) { ui32_t file_size = FileSize(Filename); Result_t result = Buffer.Capacity(file_size); @@ -1280,7 +1268,7 @@ Kumu::ReadFileIntoBuffer(const std::string& Filename, Kumu::ByteString& Buffer, ui32_t read_count = 0; FileWriter Reader; - result = Reader.OpenRead(Filename.c_str()); + result = Reader.OpenRead(Filename); if ( KM_SUCCESS(result) ) result = Reader.Read(Buffer.Data(), file_size, &read_count); @@ -1304,7 +1292,7 @@ Kumu::WriteBufferIntoFile(const Kumu::ByteString& Buffer, const std::string& Fil ui32_t write_count = 0; FileWriter Writer; - Result_t result = Writer.OpenWrite(Filename.c_str()); + Result_t result = Writer.OpenWrite(Filename); if ( KM_SUCCESS(result) ) result = Writer.Write(Buffer.RoData(), Buffer.Length(), &write_count); @@ -1318,43 +1306,286 @@ Kumu::WriteBufferIntoFile(const Kumu::ByteString& Buffer, const std::string& Fil //------------------------------------------------------------------------------------------ // -Kumu::DirScanner::DirScanner() + +// Win32 directory scanner +// +#ifdef KM_WIN32 + +// +Kumu::DirScanner::DirScanner(void) : m_Handle(-1) {} + +// +// +Result_t +Kumu::DirScanner::Open(const std::string& filename) +{ + // we need to append a '*' to read the entire directory + ui32_t fn_len = filename.size(); + char* tmp_file = (char*)malloc(fn_len + 8); + + if ( tmp_file == 0 ) + return RESULT_ALLOC; + + strcpy(tmp_file, filename.c_str()); + char* p = &tmp_file[fn_len] - 1; + + if ( *p != '/' && *p != '\\' ) + { + p++; + *p++ = '/'; + } + + *p++ = '*'; + *p = 0; + // whew... + + m_Handle = _findfirsti64(tmp_file, &m_FileInfo); + Result_t result = RESULT_OK; + + if ( m_Handle == -1 ) + result = RESULT_NOT_FOUND; + + return result; +} + + +// +// +Result_t +Kumu::DirScanner::Close() { + if ( m_Handle == -1 ) + return RESULT_FILEOPEN; + + if ( _findclose((long)m_Handle) == -1 ) + return RESULT_FAIL; + m_Handle = -1; + return RESULT_OK; } + +// This sets filename param to the same per-instance buffer every time, so +// the value will change on the next call Result_t -Kumu::DirScanner::Open (const char* filename) +Kumu::DirScanner::GetNext(char* filename) { - KM_TEST_NULL_L (filename); + KM_TEST_NULL_L(filename); + + if ( m_Handle == -1 ) + return RESULT_FILEOPEN; + + if ( m_FileInfo.name[0] == '\0' ) + return RESULT_ENDOFFILE; + + strncpy(filename, m_FileInfo.name, MaxFilePath); + Result_t result = RESULT_OK; + + if ( _findnexti64((long)m_Handle, &m_FileInfo) == -1 ) + { + m_FileInfo.name[0] = '\0'; + + if ( errno != ENOENT ) + result = RESULT_FAIL; + } - if (!boost::filesystem::is_directory(filename)) { - return RESULT_NOT_FOUND; + return result; +} + + +#else // KM_WIN32 + +// POSIX directory scanner + +// +Kumu::DirScanner::DirScanner(void) : m_Handle(NULL) {} + +// +Result_t +Kumu::DirScanner::Open(const std::string& dirname) +{ + Result_t result = RESULT_OK; + + if ( ( m_Handle = opendir(dirname.c_str()) ) == NULL ) + { + switch ( errno ) + { + case ENOENT: + case ENOTDIR: + result = RESULT_NOTAFILE; + case EACCES: + result = RESULT_NO_PERM; + case ELOOP: + case ENAMETOOLONG: + result = RESULT_PARAM; + case EMFILE: + case ENFILE: + result = RESULT_STATE; + default: + DefaultLogSink().Error("DirScanner::Open(%s): %s\n", dirname.c_str(), strerror(errno)); + result = RESULT_FAIL; } - - _iterator = boost::filesystem::directory_iterator (filename); - return RESULT_OK; + } + + return result; } + +// Result_t -Kumu::DirScanner::GetNext (char* filename) +Kumu::DirScanner::Close() { - KM_TEST_NULL_L (filename); - - if (_iterator == boost::filesystem::directory_iterator()) { - return RESULT_ENDOFFILE; + if ( m_Handle == NULL ) + return RESULT_FILEOPEN; + + if ( closedir(m_Handle) == -1 ) { + switch ( errno ) + { + case EBADF: + case EINTR: + return RESULT_STATE; + default: + DefaultLogSink().Error("DirScanner::Close(): %s\n", strerror(errno)); + return RESULT_FAIL; + } + } + + m_Handle = NULL; + return RESULT_OK; +} + + +// +Result_t +Kumu::DirScanner::GetNext(char* filename) +{ + KM_TEST_NULL_L(filename); + + if ( m_Handle == NULL ) + return RESULT_FILEOPEN; + + struct dirent* entry; + + for (;;) + { + if ( ( entry = readdir(m_Handle)) == NULL ) + return RESULT_ENDOFFILE; + + break; + } + + strncpy(filename, entry->d_name, MaxFilePath); + return RESULT_OK; +} + + +// +Kumu::DirScannerEx::DirScannerEx() : m_Handle(0) {} + +// +Result_t +Kumu::DirScannerEx::Open(const std::string& dirname) +{ + Result_t result = RESULT_OK; + + if ( ( m_Handle = opendir(dirname.c_str()) ) == 0 ) + { + switch ( errno ) + { + case ENOENT: + case ENOTDIR: + result = RESULT_NOTAFILE; + case EACCES: + result = RESULT_NO_PERM; + case ELOOP: + case ENAMETOOLONG: + result = RESULT_PARAM; + case EMFILE: + case ENFILE: + result = RESULT_STATE; + default: + DefaultLogSink().Error("DirScanner::Open(%s): %s\n", dirname.c_str(), strerror(errno)); + result = RESULT_FAIL; } + } -#if BOOST_FILESYSTEM_VERSION == 3 - std::string f = boost::filesystem::path(*_iterator).filename().generic_string(); -#else - std::string f = boost::filesystem::path(*_iterator).filename(); -#endif - strncpy (filename, f.c_str(), MaxFilePath); - ++_iterator; - return RESULT_OK; + if ( KM_SUCCESS(result) ) + m_Dirname = dirname; + + KM_RESULT_STATE_TEST_IMPLICIT(); + return result; +} + +// +Result_t +Kumu::DirScannerEx::Close() +{ + if ( m_Handle == NULL ) + return RESULT_FILEOPEN; + + if ( closedir(m_Handle) == -1 ) + { + switch ( errno ) + { + case EBADF: + case EINTR: + KM_RESULT_STATE_HERE(); + return RESULT_STATE; + + default: + DefaultLogSink().Error("DirScanner::Close(): %s\n", strerror(errno)); + return RESULT_FAIL; + } + } + + m_Handle = 0; + return RESULT_OK; +} + +// +Result_t +Kumu::DirScannerEx::GetNext(std::string& next_item_name, DirectoryEntryType_t& next_item_type) +{ + if ( m_Handle == 0 ) + return RESULT_FILEOPEN; + + struct dirent* entry; + + for (;;) + { + if ( ( entry = readdir(m_Handle) ) == 0 ) + return RESULT_ENDOFFILE; + + break; + } + + next_item_name.assign(entry->d_name, strlen(entry->d_name)); + + switch ( entry->d_type ) + { + case DT_DIR: + next_item_type = DET_DIR; + break; + + case DT_REG: + next_item_type = DET_FILE; + break; + + case DT_LNK: + next_item_type = DET_LINK; + break; + + default: + next_item_type = DET_DEV; + } + + return RESULT_OK; } + +#endif // KM_WIN32 + + //------------------------------------------------------------------------------------------ // @@ -1484,12 +1715,37 @@ h__DeletePath(const std::string& pathname) Result_t Kumu::DeletePath(const std::string& pathname) { - std::string c_pathname = PathMakeAbsolute(PathMakeCanonical(pathname)); + std::string c_pathname = PathMakeCanonical(PathMakeAbsolute(pathname)); DefaultLogSink().Debug("DeletePath (%s) c(%s)\n", pathname.c_str(), c_pathname.c_str()); return h__DeletePath(c_pathname); } +// +Result_t +Kumu::DeleteDirectoryIfEmpty(const std::string& path) +{ + DirScanner source_dir; + char next_file[Kumu::MaxFilePath]; + + Result_t result = source_dir.Open(path); + + if ( KM_FAILURE(result) ) + return result; + + while ( KM_SUCCESS(source_dir.GetNext(next_file)) ) + { + if ( ( next_file[0] == '.' && next_file[1] == 0 ) + || ( next_file[0] == '.' && next_file[1] == '.' && next_file[2] == 0 ) ) + continue; + + return RESULT_NOT_EMPTY; // anything other than "." and ".." indicates a non-empty directory + } + + return DeletePath(path); +} + + //------------------------------------------------------------------------------------------ // @@ -1498,19 +1754,21 @@ Result_t Kumu::FreeSpaceForPath(const std::string& path, Kumu::fsize_t& free_space, Kumu::fsize_t& total_space) { #ifdef KM_WIN32 - ULARGE_INTEGER lTotalNumberOfBytes; - ULARGE_INTEGER lTotalNumberOfFreeBytes; + ULARGE_INTEGER lTotalNumberOfBytes; + ULARGE_INTEGER lTotalNumberOfFreeBytes; - BOOL fResult = ::GetDiskFreeSpaceExA(path.c_str(), NULL, &lTotalNumberOfBytes, &lTotalNumberOfFreeBytes); - if (fResult) { + BOOL fResult = ::GetDiskFreeSpaceExA(path.c_str(), NULL, &lTotalNumberOfBytes, &lTotalNumberOfFreeBytes); + if ( fResult ) + { free_space = static_cast<Kumu::fsize_t>(lTotalNumberOfFreeBytes.QuadPart); total_space = static_cast<Kumu::fsize_t>(lTotalNumberOfBytes.QuadPart); return RESULT_OK; - } - HRESULT LastError = ::GetLastError(); + } - DefaultLogSink().Error("FreeSpaceForPath GetDiskFreeSpaceEx %s: %lu\n", path.c_str(), ::GetLastError()); - return RESULT_FAIL; + HRESULT last_error = ::GetLastError(); + + DefaultLogSink().Error("FreeSpaceForPath GetDiskFreeSpaceEx %s: %lu\n", path.c_str(), last_error); + return RESULT_FAIL; #else // KM_WIN32 struct statfs s; |
