X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2FKM_fileio.cpp;h=b9257abda88d7d9c87bd929cbce7a9bd806c47c7;hb=f6382ee078c3d7de2dbf3a01f5624345d2c61e4a;hp=57b28a88482b8b070f66c8003d59e12824317f53;hpb=7827a7e7572601440568788cb028ee883498fa15;p=asdcplib.git diff --git a/src/KM_fileio.cpp b/src/KM_fileio.cpp index 57b28a8..b9257ab 100644 --- a/src/KM_fileio.cpp +++ b/src/KM_fileio.cpp @@ -1,5 +1,5 @@ /* -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 @@ -32,7 +32,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include + #include + #ifdef KM_WIN32 #include #endif @@ -52,6 +54,14 @@ struct iovec { int iov_len; }; #else +# if defined(__linux__) +# include +# else +# include +# include +# endif + +#include #include typedef struct stat fstat_t; #endif @@ -69,7 +79,6 @@ split(const std::string& str, char separator, std::list& components if ( r > pstr ) { std::string tmp_str; - assert(r - pstr < 100); tmp_str.assign(pstr, (r - pstr)); components.push_back(tmp_str); } @@ -114,7 +123,7 @@ do_stat(const char* path, fstat_t* stat_info) // 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); @@ -204,7 +213,7 @@ Kumu::FileSize(const std::string& pathname) // 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 @@ -238,7 +247,7 @@ Kumu::PathMakeCanonical(const std::string& Path, char separator) { 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); @@ -341,10 +350,10 @@ Kumu::PathMakeAbsolute(const std::string& Path, char 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); } // @@ -420,6 +429,28 @@ Kumu::PathSetExtension(const std::string& Path, const std::string& Extension) // 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, @@ -677,7 +708,7 @@ Kumu::FileReader::Tell(Kumu::fpos_t* pos) const { KM_TEST_NULL_L(pos); - if ( m_Handle == (HANDLE)-1L ) + if ( m_Handle == INVALID_HANDLE_VALUE ) return Kumu::RESULT_FILEOPEN; LARGE_INTEGER in; @@ -1062,14 +1093,128 @@ Kumu::WriteStringIntoFile(const char* filename, const std::string& inString) 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(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 @@ -1155,6 +1300,9 @@ Kumu::DirScanner::GetNext(char* filename) // POSIX directory scanner +// +Kumu::DirScanner::DirScanner(void) : m_Handle(NULL) {} + // Result_t Kumu::DirScanner::Open(const char* filename) @@ -1165,11 +1313,23 @@ 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; @@ -1183,8 +1343,17 @@ Kumu::DirScanner::Close() 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; @@ -1218,6 +1387,191 @@ Kumu::DirScanner::GetNext(char* filename) #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(lTotalNumberOfFreeBytes.QuadPart); + total_space = static_cast(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