summaryrefslogtreecommitdiff
path: root/asdcplib/src/KM_fileio.cpp
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2016-01-05 15:32:10 +0000
committerCarl Hetherington <cth@carlh.net>2016-01-05 15:32:10 +0000
commit3ec4338ce90ea0549409312f24f8b28c07a5d2da (patch)
tree09aaaff66dd860abbeacc20793145e1a27f4defd /asdcplib/src/KM_fileio.cpp
parent342aad2ddf893aaaafa9a2c9980579d2dc4ec125 (diff)
asdcplib 2.5.11
Diffstat (limited to 'asdcplib/src/KM_fileio.cpp')
-rw-r--r--asdcplib/src/KM_fileio.cpp746
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;