2 Copyright (c) 2004-2011, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 /*! \file KM_fileio.cpp
28 \version $Id: KM_fileio.cpp,v 1.31 2011/03/08 19:03:47 jhurst Exp $
29 \brief portable file i/o
32 #include <KM_fileio.h>
43 #define _getcwd getcwd
44 #define _unlink unlink
51 typedef struct _stati64 fstat_t;
54 // win32 has WriteFileGather() and ReadFileScatter() but they
55 // demand page alignment and page sizing, making them unsuitable
56 // for use with arbitrary buffer sizes.
58 char* iov_base; // stupid iovec uses char*
62 # if defined(__linux__)
63 # include <sys/statfs.h>
65 # include <sys/param.h>
66 # include <sys/mount.h>
71 typedef struct stat fstat_t;
76 split(const std::string& str, char separator, std::list<std::string>& components)
78 const char* pstr = str.c_str();
79 const char* r = strchr(pstr, separator);
87 tmp_str.assign(pstr, (r - pstr));
88 components.push_back(tmp_str);
92 r = strchr(pstr, separator);
95 if( strlen(pstr) > 0 )
96 components.push_back(std::string(pstr));
101 static Kumu::Result_t
102 do_stat(const char* path, fstat_t* stat_info)
104 KM_TEST_NULL_STR_L(path);
105 KM_TEST_NULL_L(stat_info);
107 Kumu::Result_t result = Kumu::RESULT_OK;
110 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
112 if ( _stati64(path, stat_info) == (__int64)-1 )
113 result = Kumu::RESULT_FILEOPEN;
115 ::SetErrorMode( prev );
117 if ( stat(path, stat_info) == -1L )
118 result = Kumu::RESULT_FILEOPEN;
120 if ( (stat_info->st_mode & (S_IFREG|S_IFLNK|S_IFDIR)) == 0 )
121 result = Kumu::RESULT_FILEOPEN;
130 static Kumu::Result_t
131 do_fstat(FileHandle handle, fstat_t* stat_info)
133 KM_TEST_NULL_L(stat_info);
135 Kumu::Result_t result = Kumu::RESULT_OK;
137 if ( fstat(handle, stat_info) == -1L )
138 result = Kumu::RESULT_FILEOPEN;
140 if ( (stat_info->st_mode & (S_IFREG|S_IFLNK|S_IFDIR)) == 0 )
141 result = Kumu::RESULT_FILEOPEN;
151 Kumu::PathExists(const std::string& pathname)
153 if ( pathname.empty() )
158 if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
166 Kumu::PathIsFile(const std::string& pathname)
168 if ( pathname.empty() )
173 if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
175 if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
185 Kumu::PathIsDirectory(const std::string& pathname)
187 if ( pathname.empty() )
192 if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
194 if ( info.st_mode & S_IFDIR )
203 Kumu::FileSize(const std::string& pathname)
205 if ( pathname.empty() )
210 if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) )
212 if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
213 return(info.st_size);
220 static PathCompList_t&
221 s_PathMakeCanonical(PathCompList_t& CList, bool is_absolute)
223 PathCompList_t::iterator ci, ri; // component and removal iterators
225 for ( ci = CList.begin(); ci != CList.end(); ci++ )
227 if ( *ci == "." && ( CList.size() > 1 || is_absolute ) )
232 else if ( *ci == ".." && ci != CList.begin() )
251 Kumu::PathMakeCanonical(const std::string& Path, char separator)
253 PathCompList_t CList;
254 bool is_absolute = PathIsAbsolute(Path, separator);
255 s_PathMakeCanonical(PathToComponents(Path, CList, separator), is_absolute);
258 return ComponentsToAbsolutePath(CList, separator);
260 return ComponentsToPath(CList, separator);
265 Kumu::PathsAreEquivalent(const std::string& lhs, const std::string& rhs)
267 return PathMakeCanonical(lhs) == PathMakeCanonical(rhs);
271 Kumu::PathCompList_t&
272 Kumu::PathToComponents(const std::string& Path, PathCompList_t& CList, char separator)
274 split(Path, separator, CList);
280 Kumu::ComponentsToPath(const PathCompList_t& CList, char separator)
285 PathCompList_t::const_iterator ci = CList.begin();
286 std::string out_path = *ci;
288 for ( ci++; ci != CList.end(); ci++ )
289 out_path += separator + *ci;
296 Kumu::ComponentsToAbsolutePath(const PathCompList_t& CList, char separator)
298 std::string out_path;
301 out_path = separator;
304 PathCompList_t::const_iterator ci;
306 for ( ci = CList.begin(); ci != CList.end(); ci++ )
307 out_path += separator + *ci;
315 Kumu::PathHasComponents(const std::string& Path, char separator)
317 if ( strchr(Path.c_str(), separator) == 0 )
325 Kumu::PathIsAbsolute(const std::string& Path, char separator)
330 if ( Path[0] == separator)
338 Kumu::PathMakeAbsolute(const std::string& Path, char separator)
342 std::string out_path;
343 out_path = separator;
347 if ( PathIsAbsolute(Path, separator) )
350 char cwd_buf [MaxFilePath];
351 if ( _getcwd(cwd_buf, MaxFilePath) == 0 )
353 DefaultLogSink().Error("Error retrieving current working directory.");
357 PathCompList_t CList;
358 PathToComponents(cwd_buf, CList);
359 CList.push_back(Path);
361 return ComponentsToAbsolutePath(s_PathMakeCanonical(CList, true), separator);
366 Kumu::PathMakeLocal(const std::string& Path, const std::string& Parent)
368 size_t pos = Path.find(Parent);
370 if ( pos == 0 ) // Parent found at offset 0
371 return Path.substr(Parent.size()+1);
378 Kumu::PathBasename(const std::string& Path, char separator)
380 PathCompList_t CList;
381 PathToComponents(Path, CList, separator);
391 Kumu::PathDirname(const std::string& Path, char separator)
393 PathCompList_t CList;
394 bool is_absolute = PathIsAbsolute(Path, separator);
395 PathToComponents(Path, CList, separator);
398 return is_absolute ? "/" : "";
403 return ComponentsToAbsolutePath(CList, separator);
405 return ComponentsToPath(CList, separator);
410 Kumu::PathGetExtension(const std::string& Path)
412 std::string Basename = PathBasename(Path);
413 const char* p = strrchr(Basename.c_str(), '.');
423 Kumu::PathSetExtension(const std::string& Path, const std::string& Extension) // empty extension removes
425 std::string Basename = PathBasename(Path);
426 const char* p = strrchr(Basename.c_str(), '.');
429 Basename = Basename.substr(0, p - Basename.c_str());
431 if ( Extension.empty() )
434 return Basename + "." + Extension;
439 Kumu::PathJoin(const std::string& Path1, const std::string& Path2, char separator)
441 return Path1 + separator + Path2;
446 Kumu::PathJoin(const std::string& Path1, const std::string& Path2, const std::string& Path3, char separator)
448 return Path1 + separator + Path2 + separator + Path3;
453 Kumu::PathJoin(const std::string& Path1, const std::string& Path2,
454 const std::string& Path3, const std::string& Path4, char separator)
456 return Path1 + separator + Path2 + separator + Path3 + separator + Path4;
461 Kumu::FindInPaths(const IPathMatch& Pattern, const Kumu::PathList_t& SearchPaths,
462 Kumu::PathList_t& FoundPaths, bool one_shot, char separator)
464 PathList_t::const_iterator si;
465 for ( si = SearchPaths.begin(); si != SearchPaths.end(); si++ )
467 FindInPath(Pattern, *si, FoundPaths, one_shot, separator);
469 if ( one_shot && ! FoundPaths.empty() )
478 Kumu::FindInPath(const IPathMatch& Pattern, const std::string& SearchDir,
479 Kumu::PathList_t& FoundPaths, bool one_shot, char separator)
481 char name_buf[MaxFilePath];
484 if ( KM_SUCCESS(Dir.Open(SearchDir.c_str())) )
486 while ( KM_SUCCESS(Dir.GetNext(name_buf)) )
488 if ( name_buf[0] == '.' ) continue; // no hidden files
489 std::string tmp_path = SearchDir + separator + name_buf;
491 if ( PathIsDirectory(tmp_path.c_str()) )
492 FindInPath(Pattern, tmp_path, FoundPaths, one_shot, separator);
494 else if ( Pattern.Match(name_buf) )
496 FoundPaths.push_back(SearchDir + separator + name_buf);
510 Kumu::PathMatchRegex::PathMatchRegex(const std::string& s)
512 int result = regcomp(&m_regex, s.c_str(), REG_NOSUB); // (REG_EXTENDED|REG_NOSUB|REG_NEWLINE));
517 regerror(result, &m_regex, buf, 128);
518 DefaultLogSink().Error("PathMatchRegex: %s\n", buf);
523 Kumu::PathMatchRegex::PathMatchRegex(const PathMatchRegex& rhs) : IPathMatch() {
524 m_regex = rhs.m_regex;
527 Kumu::PathMatchRegex::~PathMatchRegex() {
532 Kumu::PathMatchRegex::Match(const std::string& s) const {
533 return ( regexec(&m_regex, s.c_str(), 0, 0, 0) == 0 );
539 Kumu::PathMatchGlob::PathMatchGlob(const std::string& glob)
541 std::string regex; // convert glob to regex
543 for ( const char* p = glob.c_str(); *p != 0; p++ )
547 case '.': regex += "\\."; break;
548 case '*': regex += ".*"; break;
549 case '?': regex += ".?"; break;
550 default: regex += *p;
555 int result = regcomp(&m_regex, regex.c_str(), REG_NOSUB);
560 regerror(result, &m_regex, buf, 128);
561 DefaultLogSink().Error("PathMatchRegex: %s\n", buf);
566 Kumu::PathMatchGlob::PathMatchGlob(const PathMatchGlob& rhs) : IPathMatch() {
567 m_regex = rhs.m_regex;
570 Kumu::PathMatchGlob::~PathMatchGlob() {
575 Kumu::PathMatchGlob::Match(const std::string& s) const {
576 return ( regexec(&m_regex, s.c_str(), 0, 0, 0) == 0 );
581 //------------------------------------------------------------------------------------------
582 // portable aspects of the file classes
584 const int IOVecMaxEntries = 32; // we never use more that 3, but that number seems somehow small...
587 class Kumu::FileWriter::h__iovec
591 struct iovec m_iovec[IOVecMaxEntries];
592 h__iovec() : m_Count(0) {}
599 Kumu::FileReader::Size() const
602 return FileSize(m_Filename.c_str());
606 if ( KM_SUCCESS(do_fstat(m_Handle, &info)) )
608 if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
609 return(info.st_size);
616 // these are declared here instead of in the header file
617 // because we have a mem_ptr that is managing a hidden class
618 Kumu::FileWriter::FileWriter()
622 Kumu::FileWriter::~FileWriter() {}
626 Kumu::FileWriter::Writev(const byte_t* buf, ui32_t buf_len)
628 assert( ! m_IOVec.empty() );
629 register h__iovec* iov = m_IOVec;
632 if ( iov->m_Count >= IOVecMaxEntries )
634 DefaultLogSink().Error("The iovec is full! Only %u entries allowed before a flush.\n",
636 return RESULT_WRITEFAIL;
639 iov->m_iovec[iov->m_Count].iov_base = (char*)buf; // stupid iovec uses char*
640 iov->m_iovec[iov->m_Count].iov_len = buf_len;
647 Kumu::FileWriter::StartHashing()
650 MD5_Init (&m_MD5Context);
654 Kumu::FileWriter::MaybeHash(void const * data, int size)
657 MD5_Update (&m_MD5Context, data, size);
662 Kumu::FileWriter::StopHashing()
666 unsigned char digest[MD5_DIGEST_LENGTH];
667 MD5_Final (digest, &m_MD5Context);
670 for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
671 s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]);
679 //------------------------------------------------------------------------------------------
683 Kumu::FileReader::OpenRead(const char* filename) const
685 KM_TEST_NULL_STR_L(filename);
686 const_cast<FileReader*>(this)->m_Filename = filename;
688 // suppress popup window on error
689 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
691 const_cast<FileReader*>(this)->m_Handle = ::CreateFileA(filename,
692 (GENERIC_READ), // open for reading
693 FILE_SHARE_READ, // share for reading
695 OPEN_EXISTING, // read
696 FILE_ATTRIBUTE_NORMAL, // normal file
697 NULL // no template file
700 ::SetErrorMode(prev);
702 return ( m_Handle == INVALID_HANDLE_VALUE ) ?
703 Kumu::RESULT_FILEOPEN : Kumu::RESULT_OK;
708 Kumu::FileReader::Close() const
710 if ( m_Handle == INVALID_HANDLE_VALUE )
711 return Kumu::RESULT_FILEOPEN;
713 // suppress popup window on error
714 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
715 BOOL result = ::CloseHandle(m_Handle);
716 ::SetErrorMode(prev);
717 const_cast<FileReader*>(this)->m_Handle = INVALID_HANDLE_VALUE;
719 return ( result == 0 ) ? Kumu::RESULT_FAIL : Kumu::RESULT_OK;
724 Kumu::FileReader::Seek(Kumu::fpos_t position, SeekPos_t whence) const
726 if ( m_Handle == INVALID_HANDLE_VALUE )
727 return Kumu::RESULT_STATE;
730 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
731 in.QuadPart = position;
732 in.LowPart = ::SetFilePointer(m_Handle, in.LowPart, &in.HighPart, whence);
733 HRESULT LastError = GetLastError();
734 ::SetErrorMode(prev);
736 if ( (LastError != NO_ERROR
737 && (in.LowPart == INVALID_SET_FILE_POINTER
738 || in.LowPart == ERROR_NEGATIVE_SEEK )) )
739 return Kumu::RESULT_READFAIL;
741 return Kumu::RESULT_OK;
746 Kumu::FileReader::Tell(Kumu::fpos_t* pos) const
750 if ( m_Handle == INVALID_HANDLE_VALUE )
751 return Kumu::RESULT_FILEOPEN;
754 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
755 in.QuadPart = (__int64)0;
756 in.LowPart = ::SetFilePointer(m_Handle, in.LowPart, &in.HighPart, FILE_CURRENT);
757 HRESULT LastError = GetLastError();
758 ::SetErrorMode(prev);
760 if ( (LastError != NO_ERROR
761 && (in.LowPart == INVALID_SET_FILE_POINTER
762 || in.LowPart == ERROR_NEGATIVE_SEEK )) )
763 return Kumu::RESULT_READFAIL;
765 *pos = (Kumu::fpos_t)in.QuadPart;
766 return Kumu::RESULT_OK;
771 Kumu::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const
774 Result_t result = Kumu::RESULT_OK;
778 if ( read_count == 0 )
779 read_count = &tmp_int;
783 if ( m_Handle == INVALID_HANDLE_VALUE )
784 return Kumu::RESULT_FILEOPEN;
786 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
787 if ( ::ReadFile(m_Handle, buf, buf_len, &tmp_count, NULL) == 0 )
788 result = Kumu::RESULT_READFAIL;
790 ::SetErrorMode(prev);
792 if ( tmp_count == 0 ) /* EOF */
793 result = Kumu::RESULT_ENDOFFILE;
795 if ( KM_SUCCESS(result) )
796 *read_count = tmp_count;
803 //------------------------------------------------------------------------------------------
808 Kumu::FileWriter::OpenWrite(const char* filename)
810 KM_TEST_NULL_STR_L(filename);
811 m_Filename = filename;
813 // suppress popup window on error
814 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
816 m_Handle = ::CreateFileA(filename,
817 (GENERIC_WRITE|GENERIC_READ), // open for reading
818 FILE_SHARE_READ, // share for reading
820 CREATE_ALWAYS, // overwrite (beware!)
821 FILE_ATTRIBUTE_NORMAL, // normal file
822 NULL // no template file
825 ::SetErrorMode(prev);
827 if ( m_Handle == INVALID_HANDLE_VALUE )
828 return Kumu::RESULT_FILEOPEN;
830 m_IOVec = new h__iovec;
831 return Kumu::RESULT_OK;
836 Kumu::FileWriter::OpenModify(const char* filename)
838 KM_TEST_NULL_STR_L(filename);
839 m_Filename = filename;
841 // suppress popup window on error
842 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
844 m_Handle = ::CreateFileA(filename,
845 (GENERIC_WRITE|GENERIC_READ), // open for reading
846 FILE_SHARE_READ, // share for reading
848 OPEN_ALWAYS, // don't truncate existing
849 FILE_ATTRIBUTE_NORMAL, // normal file
850 NULL // no template file
853 ::SetErrorMode(prev);
855 if ( m_Handle == INVALID_HANDLE_VALUE )
856 return Kumu::RESULT_FILEOPEN;
858 m_IOVec = new h__iovec;
859 return Kumu::RESULT_OK;
864 Kumu::FileWriter::Writev(ui32_t* bytes_written)
866 assert( ! m_IOVec.empty() );
867 register h__iovec* iov = m_IOVec;
870 if ( bytes_written == 0 )
871 bytes_written = &tmp_int;
873 if ( m_Handle == INVALID_HANDLE_VALUE )
874 return Kumu::RESULT_STATE;
877 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
878 Result_t result = Kumu::RESULT_OK;
880 // AFAIK, there is no writev() equivalent in the win32 API
881 for ( register int i = 0; i < iov->m_Count; i++ )
883 ui32_t tmp_count = 0;
884 BOOL wr_result = ::WriteFile(m_Handle,
885 iov->m_iovec[i].iov_base,
886 iov->m_iovec[i].iov_len,
890 if ( wr_result == 0 || tmp_count != iov->m_iovec[i].iov_len)
892 result = Kumu::RESULT_WRITEFAIL;
896 MaybeHash (iov->m_iovec[i].iov_base, iov->m_iovec[i].iov_len);
897 *bytes_written += tmp_count;
900 ::SetErrorMode(prev);
901 iov->m_Count = 0; // error nor not, all is lost
908 Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written)
913 if ( bytes_written == 0 )
914 bytes_written = &tmp_int;
916 if ( m_Handle == INVALID_HANDLE_VALUE )
917 return Kumu::RESULT_STATE;
919 // suppress popup window on error
920 UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
921 BOOL result = ::WriteFile(m_Handle, buf, buf_len, (DWORD*)bytes_written, NULL);
922 ::SetErrorMode(prev);
924 if ( result == 0 || *bytes_written != buf_len )
925 return Kumu::RESULT_WRITEFAIL;
927 MaybeHash (buf, buf_len);
929 return Kumu::RESULT_OK;
933 //------------------------------------------------------------------------------------------
938 Kumu::FileReader::OpenRead(const char* filename) const
940 KM_TEST_NULL_STR_L(filename);
941 const_cast<FileReader*>(this)->m_Filename = filename;
942 const_cast<FileReader*>(this)->m_Handle = open(filename, O_RDONLY, 0);
943 return ( m_Handle == -1L ) ? RESULT_FILEOPEN : RESULT_OK;
948 Kumu::FileReader::Close() const
950 if ( m_Handle == -1L )
951 return RESULT_FILEOPEN;
954 const_cast<FileReader*>(this)->m_Handle = -1L;
960 Kumu::FileReader::Seek(Kumu::fpos_t position, SeekPos_t whence) const
962 if ( m_Handle == -1L )
963 return RESULT_FILEOPEN;
965 if ( lseek(m_Handle, position, whence) == -1L )
966 return RESULT_BADSEEK;
973 Kumu::FileReader::Tell(Kumu::fpos_t* pos) const
977 if ( m_Handle == -1L )
978 return RESULT_FILEOPEN;
980 Kumu::fpos_t tmp_pos;
982 if ( (tmp_pos = lseek(m_Handle, 0, SEEK_CUR)) == -1 )
983 return RESULT_READFAIL;
991 Kumu::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const
997 if ( read_count == 0 )
998 read_count = &tmp_int;
1002 if ( m_Handle == -1L )
1003 return RESULT_FILEOPEN;
1005 if ( (tmp_count = read(m_Handle, buf, buf_len)) == -1L )
1006 return RESULT_READFAIL;
1008 *read_count = tmp_count;
1009 return (tmp_count == 0 ? RESULT_ENDOFFILE : RESULT_OK);
1013 //------------------------------------------------------------------------------------------
1018 Kumu::FileWriter::OpenWrite(const char* filename)
1020 KM_TEST_NULL_STR_L(filename);
1021 m_Filename = filename;
1022 m_Handle = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0664);
1024 if ( m_Handle == -1L )
1026 DefaultLogSink().Error("Error opening file %s: %s\n", filename, strerror(errno));
1027 return RESULT_FILEOPEN;
1030 m_IOVec = new h__iovec;
1036 Kumu::FileWriter::OpenModify(const char* filename)
1038 KM_TEST_NULL_STR_L(filename);
1039 m_Filename = filename;
1040 m_Handle = open(filename, O_RDWR|O_CREAT, 0664);
1042 if ( m_Handle == -1L )
1044 DefaultLogSink().Error("Error opening file %s: %s\n", filename, strerror(errno));
1045 return RESULT_FILEOPEN;
1048 m_IOVec = new h__iovec;
1054 Kumu::FileWriter::Writev(ui32_t* bytes_written)
1056 assert( ! m_IOVec.empty() );
1057 register h__iovec* iov = m_IOVec;
1060 if ( bytes_written == 0 )
1061 bytes_written = &tmp_int;
1063 if ( m_Handle == -1L )
1064 return RESULT_STATE;
1067 for ( int i = 0; i < iov->m_Count; i++ )
1068 total_size += iov->m_iovec[i].iov_len;
1070 int write_size = writev(m_Handle, iov->m_iovec, iov->m_Count);
1072 if ( write_size == -1L || write_size != total_size )
1073 return RESULT_WRITEFAIL;
1075 for (int i = 0; i < iov->m_Count; ++i) {
1076 MaybeHash (iov->m_iovec[i].iov_base, iov->m_iovec[i].iov_len);
1080 *bytes_written = write_size;
1086 Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written)
1088 KM_TEST_NULL_L(buf);
1091 if ( bytes_written == 0 )
1092 bytes_written = &tmp_int;
1094 if ( m_Handle == -1L )
1095 return RESULT_STATE;
1097 int write_size = write(m_Handle, buf, buf_len);
1098 MaybeHash (buf, buf_len);
1100 if ( write_size == -1L || (ui32_t)write_size != buf_len )
1101 return RESULT_WRITEFAIL;
1103 *bytes_written = write_size;
1110 //------------------------------------------------------------------------------------------
1115 Kumu::ReadFileIntoString(const char* filename, std::string& outString, ui32_t max_size)
1118 ui32_t read_size = 0;
1122 KM_TEST_NULL_STR_L(filename);
1124 Result_t result = File.OpenRead(filename);
1126 if ( KM_SUCCESS(result) )
1128 fsize = File.Size();
1130 if ( fsize > (Kumu::fpos_t)max_size )
1132 DefaultLogSink().Error("%s: exceeds available buffer size (%u)\n", filename, max_size);
1133 return RESULT_ALLOC;
1138 DefaultLogSink().Error("%s: zero file size\n", filename);
1139 return RESULT_READFAIL;
1142 result = ReadBuf.Capacity((ui32_t)fsize);
1145 if ( KM_SUCCESS(result) )
1146 result = File.Read(ReadBuf.Data(), ReadBuf.Capacity(), &read_size);
1148 if ( KM_SUCCESS(result) )
1149 outString.assign((const char*)ReadBuf.RoData(), read_size);
1157 Kumu::WriteStringIntoFile(const char* filename, const std::string& inString)
1160 ui32_t write_count = 0;
1161 KM_TEST_NULL_STR_L(filename);
1163 Result_t result = File.OpenWrite(filename);
1165 if ( KM_SUCCESS(result) )
1166 result = File.Write((byte_t*)inString.c_str(), inString.length(), &write_count);
1171 //------------------------------------------------------------------------------------------
1176 Kumu::ReadFileIntoObject(const std::string& Filename, Kumu::IArchive& Object, ui32_t)
1179 ui32_t file_size = static_cast<ui32_t>(FileSize(Filename));
1180 Result_t result = Buffer.Capacity(file_size);
1182 if ( KM_SUCCESS(result) )
1184 ui32_t read_count = 0;
1187 result = Reader.OpenRead(Filename.c_str());
1189 if ( KM_SUCCESS(result) )
1190 result = Reader.Read(Buffer.Data(), file_size, &read_count);
1192 if ( KM_SUCCESS(result) )
1194 assert(file_size == read_count);
1195 Buffer.Length(read_count);
1196 MemIOReader MemReader(&Buffer);
1197 result = Object.Unarchive(&MemReader) ? RESULT_OK : RESULT_READFAIL;
1206 Kumu::WriteObjectIntoFile(const Kumu::IArchive& Object, const std::string& Filename)
1209 Result_t result = Buffer.Capacity(Object.ArchiveLength());
1211 if ( KM_SUCCESS(result) )
1213 ui32_t write_count = 0;
1215 MemIOWriter MemWriter(&Buffer);
1217 result = Object.Archive(&MemWriter) ? RESULT_OK : RESULT_WRITEFAIL;
1219 if ( KM_SUCCESS(result) )
1221 Buffer.Length(MemWriter.Length());
1222 result = Writer.OpenWrite(Filename.c_str());
1225 if ( KM_SUCCESS(result) )
1226 result = Writer.Write(Buffer.RoData(), Buffer.Length(), &write_count);
1232 //------------------------------------------------------------------------------------------
1237 Kumu::ReadFileIntoBuffer(const std::string& Filename, Kumu::ByteString& Buffer, ui32_t)
1239 ui32_t file_size = FileSize(Filename);
1240 Result_t result = Buffer.Capacity(file_size);
1242 if ( KM_SUCCESS(result) )
1244 ui32_t read_count = 0;
1247 result = Reader.OpenRead(Filename.c_str());
1249 if ( KM_SUCCESS(result) )
1250 result = Reader.Read(Buffer.Data(), file_size, &read_count);
1252 if ( KM_SUCCESS(result) )
1254 if ( file_size != read_count)
1255 return RESULT_READFAIL;
1257 Buffer.Length(read_count);
1266 Kumu::WriteBufferIntoFile(const Kumu::ByteString& Buffer, const std::string& Filename)
1268 ui32_t write_count = 0;
1271 Result_t result = Writer.OpenWrite(Filename.c_str());
1273 if ( KM_SUCCESS(result) )
1274 result = Writer.Write(Buffer.RoData(), Buffer.Length(), &write_count);
1276 if ( KM_SUCCESS(result) && Buffer.Length() != write_count)
1277 return RESULT_WRITEFAIL;
1282 //------------------------------------------------------------------------------------------
1285 Kumu::DirScanner::DirScanner()
1291 Kumu::DirScanner::Open (const char* filename)
1293 KM_TEST_NULL_L (filename);
1295 if (!boost::filesystem::is_directory(filename)) {
1296 return RESULT_NOT_FOUND;
1299 _iterator = boost::filesystem::directory_iterator (filename);
1304 Kumu::DirScanner::GetNext (char* filename)
1306 KM_TEST_NULL_L (filename);
1308 if (_iterator == boost::filesystem::directory_iterator()) {
1309 return RESULT_ENDOFFILE;
1312 #if BOOST_FILESYSTEM_VERSION == 3
1313 std::string f = boost::filesystem::path(*_iterator).filename().generic_string();
1315 std::string f = boost::filesystem::path(*_iterator).filename();
1317 strncpy (filename, f.c_str(), MaxFilePath);
1322 //------------------------------------------------------------------------------------------
1325 // Attention Windows users: make sure to use the proper separator character
1326 // with these functions.
1329 // given a path string, create any missing directories so that PathIsDirectory(Path) is true.
1332 Kumu::CreateDirectoriesInPath(const std::string& Path)
1334 bool abs = PathIsAbsolute(Path);
1335 PathCompList_t PathComps, TmpPathComps;
1337 PathToComponents(Path, PathComps);
1339 while ( ! PathComps.empty() )
1341 TmpPathComps.push_back(PathComps.front());
1342 PathComps.pop_front();
1343 std::string tmp_path = abs ? ComponentsToAbsolutePath(TmpPathComps) : ComponentsToPath(TmpPathComps);
1345 if ( ! PathIsDirectory(tmp_path) )
1348 if ( _mkdir(tmp_path.c_str()) != 0 )
1350 if ( mkdir(tmp_path.c_str(), 0775) != 0 )
1353 DefaultLogSink().Error("CreateDirectoriesInPath mkdir %s: %s\n",
1354 tmp_path.c_str(), strerror(errno));
1355 return RESULT_DIR_CREATE;
1366 Kumu::DeleteFile(const std::string& filename)
1368 if ( _unlink(filename.c_str()) == 0 )
1374 case ENOTDIR: return RESULT_NOTAFILE;
1379 case EPERM: return RESULT_NO_PERM;
1382 DefaultLogSink().Error("DeleteFile %s: %s\n", filename.c_str(), strerror(errno));
1388 h__DeletePath(const std::string& pathname)
1390 if ( pathname.empty() )
1391 return RESULT_NULL_STR;
1393 Result_t result = RESULT_OK;
1395 if ( ! PathIsDirectory(pathname) )
1397 result = DeleteFile(pathname);
1403 char next_file[Kumu::MaxFilePath];
1404 result = TestDir.Open(pathname.c_str());
1406 while ( KM_SUCCESS(result) && KM_SUCCESS(TestDir.GetNext(next_file)) )
1408 if ( next_file[0] == '.' )
1410 if ( next_file[1] == 0 )
1411 continue; // don't delete 'this'
1413 if ( next_file[1] == '.' && next_file[2] == 0 )
1414 continue; // don't delete 'this' parent
1417 result = h__DeletePath(pathname + std::string("/") + next_file);
1421 if ( _rmdir(pathname.c_str()) != 0 )
1427 result = RESULT_NOTAFILE;
1434 result = RESULT_NO_PERM;
1438 DefaultLogSink().Error("DeletePath %s: %s\n", pathname.c_str(), strerror(errno));
1439 result = RESULT_FAIL;
1449 Kumu::DeletePath(const std::string& pathname)
1451 std::string c_pathname = PathMakeAbsolute(PathMakeCanonical(pathname));
1452 DefaultLogSink().Debug("DeletePath (%s) c(%s)\n", pathname.c_str(), c_pathname.c_str());
1453 return h__DeletePath(c_pathname);
1457 //------------------------------------------------------------------------------------------
1462 Kumu::FreeSpaceForPath(const std::string& path, Kumu::fsize_t& free_space, Kumu::fsize_t& total_space)
1465 ULARGE_INTEGER lTotalNumberOfBytes;
1466 ULARGE_INTEGER lTotalNumberOfFreeBytes;
1468 BOOL fResult = ::GetDiskFreeSpaceExA(path.c_str(), NULL, &lTotalNumberOfBytes, &lTotalNumberOfFreeBytes);
1470 free_space = static_cast<Kumu::fsize_t>(lTotalNumberOfFreeBytes.QuadPart);
1471 total_space = static_cast<Kumu::fsize_t>(lTotalNumberOfBytes.QuadPart);
1474 HRESULT LastError = ::GetLastError();
1476 DefaultLogSink().Error("FreeSpaceForPath GetDiskFreeSpaceEx %s: %lu\n", path.c_str(), ::GetLastError());
1481 if ( statfs(path.c_str(), &s) == 0 )
1483 if ( s.f_blocks < 1 )
1485 DefaultLogSink().Error("File system %s has impossible size: %ld\n",
1486 path.c_str(), s.f_blocks);
1490 free_space = (Kumu::fsize_t)s.f_bsize * (Kumu::fsize_t)s.f_bavail;
1491 total_space = (Kumu::fsize_t)s.f_bsize * (Kumu::fsize_t)s.f_blocks;
1498 case ENOTDIR: return RESULT_NOTAFILE;
1499 case EACCES: return RESULT_NO_PERM;
1502 DefaultLogSink().Error("FreeSpaceForPath statfs %s: %s\n", path.c_str(), strerror(errno));
1509 // end KM_fileio.cpp