/*
-Copyright (c) 2004-2007, John Hurst
+Copyright (c) 2004-2009, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
#include <KM_fileio.h>
#include <KM_log.h>
#include <fcntl.h>
+
#include <assert.h>
+
#ifdef KM_WIN32
#include <direct.h>
#endif
int iov_len;
};
#else
+# if defined(__linux__)
+# include <sys/statfs.h>
+# else
+# include <sys/param.h>
+# include <sys/mount.h>
+# endif
+
+#include <sys/stat.h>
#include <sys/uio.h>
typedef struct stat fstat_t;
#endif
//
static Kumu::Result_t
-do_fstat(HANDLE handle, fstat_t* stat_info)
+do_fstat(FileHandle handle, fstat_t* stat_info)
{
KM_TEST_NULL_L(stat_info);
//
static PathCompList_t&
-s_PathMakeCanonical(PathCompList_t& CList, char separator, bool is_absolute)
+s_PathMakeCanonical(PathCompList_t& CList, bool is_absolute)
{
PathCompList_t::iterator ci, ri; // component and removal iterators
{
PathCompList_t CList;
bool is_absolute = PathIsAbsolute(Path, separator);
- s_PathMakeCanonical(PathToComponents(Path, CList, separator), separator, is_absolute);
+ s_PathMakeCanonical(PathToComponents(Path, CList, separator), is_absolute);
if ( is_absolute )
return ComponentsToAbsolutePath(CList, separator);
}
PathCompList_t CList;
- CList.push_back(cwd_buf);
+ PathToComponents(cwd_buf, CList);
CList.push_back(Path);
- return ComponentsToAbsolutePath(s_PathMakeCanonical(CList, separator, true), separator);
+ return ComponentsToAbsolutePath(s_PathMakeCanonical(CList, true), separator);
}
//
return Basename + "." + Extension;
}
+//
+std::string
+Kumu::PathJoin(const std::string& Path1, const std::string& Path2, char separator)
+{
+ return Path1 + separator + Path2;
+}
+
+//
+std::string
+Kumu::PathJoin(const std::string& Path1, const std::string& Path2, const std::string& Path3, char separator)
+{
+ return Path1 + separator + Path2 + separator + Path3;
+}
+
+//
+std::string
+Kumu::PathJoin(const std::string& Path1, const std::string& Path2,
+ const std::string& Path3, const std::string& Path4, char separator)
+{
+ return Path1 + separator + Path2 + separator + Path3 + separator + Path4;
+}
+
//
Kumu::PathList_t&
Kumu::FindInPaths(const IPathMatch& Pattern, const Kumu::PathList_t& SearchPaths,
{
KM_TEST_NULL_L(pos);
- if ( m_Handle == (HANDLE)-1L )
+ if ( m_Handle == INVALID_HANDLE_VALUE )
return Kumu::RESULT_FILEOPEN;
LARGE_INTEGER in;
return result;
}
+//------------------------------------------------------------------------------------------
+
+
+//
+Kumu::Result_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));
+ Result_t result = Buffer.Capacity(file_size);
+
+ if ( KM_SUCCESS(result) )
+ {
+ ui32_t read_count = 0;
+ FileWriter Reader;
+
+ result = Reader.OpenRead(Filename.c_str());
+
+ if ( KM_SUCCESS(result) )
+ result = Reader.Read(Buffer.Data(), file_size, &read_count);
+
+ if ( KM_SUCCESS(result) )
+ {
+ assert(file_size == read_count);
+ Buffer.Length(read_count);
+ MemIOReader MemReader(&Buffer);
+ result = Object.Unarchive(&MemReader) ? RESULT_OK : RESULT_READFAIL;
+ }
+ }
+
+ return result;
+}
+
+//
+Kumu::Result_t
+Kumu::WriteObjectIntoFile(const Kumu::IArchive& Object, const std::string& Filename)
+{
+ ByteString Buffer;
+ Result_t result = Buffer.Capacity(Object.ArchiveLength());
+
+ if ( KM_SUCCESS(result) )
+ {
+ ui32_t write_count = 0;
+ FileWriter Writer;
+ MemIOWriter MemWriter(&Buffer);
+
+ result = Object.Archive(&MemWriter) ? RESULT_OK : RESULT_WRITEFAIL;
+
+ if ( KM_SUCCESS(result) )
+ {
+ Buffer.Length(MemWriter.Length());
+ result = Writer.OpenWrite(Filename.c_str());
+ }
+
+ if ( KM_SUCCESS(result) )
+ result = Writer.Write(Buffer.RoData(), Buffer.Length(), &write_count);
+ }
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------
+//
+
+//
+Result_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);
+
+ if ( KM_SUCCESS(result) )
+ {
+ ui32_t read_count = 0;
+ FileWriter Reader;
+
+ result = Reader.OpenRead(Filename.c_str());
+
+ if ( KM_SUCCESS(result) )
+ result = Reader.Read(Buffer.Data(), file_size, &read_count);
+
+ if ( KM_SUCCESS(result) )
+ {
+ if ( file_size != read_count)
+ return RESULT_READFAIL;
+
+ Buffer.Length(read_count);
+ }
+ }
+
+ return result;
+}
+
+//
+Result_t
+Kumu::WriteBufferIntoFile(const Kumu::ByteString& Buffer, const std::string& Filename)
+{
+ ui32_t write_count = 0;
+ FileWriter Writer;
+
+ Result_t result = Writer.OpenWrite(Filename.c_str());
+
+ if ( KM_SUCCESS(result) )
+ result = Writer.Write(Buffer.RoData(), Buffer.Length(), &write_count);
+
+ if ( KM_SUCCESS(result) && Buffer.Length() != write_count)
+ return RESULT_WRITEFAIL;
+
+ return result;
+}
//------------------------------------------------------------------------------------------
//
+
// Win32 directory scanner
//
#ifdef KM_WIN32
+//
+Kumu::DirScanner::DirScanner(void) : m_Handle(-1) {}
+
//
//
Result_t
// POSIX directory scanner
+//
+Kumu::DirScanner::DirScanner(void) : m_Handle(NULL) {}
+
//
Result_t
Kumu::DirScanner::Open(const char* filename)
if ( ( m_Handle = opendir(filename) ) == NULL )
{
- if ( errno == ENOENT )
- result = RESULT_ENDOFFILE;
-
- else
- result = RESULT_FAIL;
+ 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", filename, strerror(errno));
+ result = RESULT_FAIL;
+ }
}
return result;
if ( m_Handle == NULL )
return RESULT_FILEOPEN;
- if ( closedir(m_Handle) == -1 )
- return RESULT_FAIL;
+ 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;
#endif // KM_WIN32
+//------------------------------------------------------------------------------------------
+
+//
+// Attention Windows users: make sure to use the proper separator character
+// with these functions.
+//
+
+// given a path string, create any missing directories so that PathIsDirectory(Path) is true.
+//
+Result_t
+Kumu::CreateDirectoriesInPath(const std::string& Path)
+{
+ bool abs = PathIsAbsolute(Path);
+ PathCompList_t PathComps, TmpPathComps;
+
+ PathToComponents(Path, PathComps);
+
+ while ( ! PathComps.empty() )
+ {
+ TmpPathComps.push_back(PathComps.front());
+ PathComps.pop_front();
+ std::string tmp_path = abs ? ComponentsToAbsolutePath(TmpPathComps) : ComponentsToPath(TmpPathComps);
+
+ if ( ! PathIsDirectory(tmp_path) )
+ {
+#ifdef KM_WIN32
+ if ( mkdir(tmp_path.c_str()) != 0 )
+#else // KM_WIN32
+ if ( mkdir(tmp_path.c_str(), 0775) != 0 )
+#endif // KM_WIN32
+ {
+ DefaultLogSink().Error("CreateDirectoriesInPath mkdir %s: %s\n",
+ tmp_path.c_str(), strerror(errno));
+ return RESULT_DIR_CREATE;
+ }
+ }
+ }
+
+ return RESULT_OK;
+}
+
+
+//
+Result_t
+Kumu::DeleteFile(const std::string& filename)
+{
+ if ( unlink(filename.c_str()) == 0 )
+ return RESULT_OK;
+
+ switch ( errno )
+ {
+ case ENOENT:
+ case ENOTDIR: return RESULT_NOTAFILE;
+
+ case EROFS:
+ case EBUSY:
+ case EACCES:
+ case EPERM: return RESULT_NO_PERM;
+ }
+
+ DefaultLogSink().Error("DeleteFile %s: %s\n", filename.c_str(), strerror(errno));
+ return RESULT_FAIL;
+}
+
+//
+Result_t
+h__DeletePath(const std::string& pathname)
+{
+ if ( pathname.empty() )
+ return RESULT_NULL_STR;
+
+ Result_t result = RESULT_OK;
+
+ if ( ! PathIsDirectory(pathname) )
+ {
+ result = DeleteFile(pathname);
+ }
+ else
+ {
+ {
+ DirScanner TestDir;
+ char next_file[Kumu::MaxFilePath];
+ result = TestDir.Open(pathname.c_str());
+
+ while ( KM_SUCCESS(result) && KM_SUCCESS(TestDir.GetNext(next_file)) )
+ {
+ if ( next_file[0] == '.' )
+ {
+ if ( next_file[1] == 0 )
+ continue; // don't delete 'this'
+
+ if ( next_file[1] == '.' && next_file[2] == 0 )
+ continue; // don't delete 'this' parent
+ }
+
+ result = h__DeletePath(pathname + std::string("/") + next_file);
+ }
+ }
+
+ if ( rmdir(pathname.c_str()) != 0 )
+ {
+ switch ( errno )
+ {
+ case ENOENT:
+ case ENOTDIR:
+ result = RESULT_NOTAFILE;
+ break;
+
+ case EROFS:
+ case EBUSY:
+ case EACCES:
+ case EPERM:
+ result = RESULT_NO_PERM;
+ break;
+
+ default:
+ DefaultLogSink().Error("DeletePath %s: %s\n", pathname.c_str(), strerror(errno));
+ result = RESULT_FAIL;
+ }
+ }
+ }
+
+ return result;
+}
+
+//
+Result_t
+Kumu::DeletePath(const std::string& pathname)
+{
+ std::string c_pathname = PathMakeAbsolute(PathMakeCanonical(pathname));
+ DefaultLogSink().Debug("DeletePath (%s) c(%s)\n", pathname.c_str(), c_pathname.c_str());
+ return h__DeletePath(c_pathname);
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+
+
+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;
+
+ BOOL fResult = ::GetDiskFreeSpaceEx(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;
+#else // KM_WIN32
+ struct statfs s;
+
+ if ( statfs(path.c_str(), &s) == 0 )
+ {
+ if ( s.f_blocks < 1 )
+ {
+ DefaultLogSink().Error("File system %s has impossible size: %ld\n",
+ path.c_str(), s.f_blocks);
+ return RESULT_FAIL;
+ }
+
+ free_space = (Kumu::fsize_t)s.f_bsize * (Kumu::fsize_t)s.f_bavail;
+ total_space = (Kumu::fsize_t)s.f_bsize * (Kumu::fsize_t)s.f_blocks;
+ return RESULT_OK;
+ }
+
+ switch ( errno )
+ {
+ case ENOENT:
+ case ENOTDIR: return RESULT_NOTAFILE;
+ case EACCES: return RESULT_NO_PERM;
+ }
+
+ DefaultLogSink().Error("FreeSpaceForPath statfs %s: %s\n", path.c_str(), strerror(errno));
+ return RESULT_FAIL;
+#endif // KM_WIN32
+}
+
//
// end KM_fileio.cpp