/*
-Copyright (c) 2004-2014, John Hurst
+Copyright (c) 2004-2016, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
#define _rmdir rmdir
#endif
+// only needed by GetExecutablePath()
+#if defined(KM_MACOSX)
+#include <mach-o/dyld.h>
+#endif
+
+#if defined(__OpenBSD__)
+#include <sys/sysctl.h>
+#endif
+
using namespace Kumu;
#ifdef KM_WIN32
typedef struct stat fstat_t;
#endif
+#if defined(__sun) && defined(__SVR4)
+#include <sys/statfs.h>
+#endif
//
static Kumu::Result_t
#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__)
+ // This fails if the CWD changes after the program has started but before the
+ // call to GetExecutablePath(). For least surprise, call GetExecutablePath()
+ // immediately in main() and save the value for later use.
+ const char* p = getenv("_");
+ if ( p )
+ {
+ return Kumu::PathMakeAbsolute(p);
+ }
+#elif defined(__FreeBSD__)
+ // requires procfs
+ 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/exe", path, size);
+ success = ( rc != -1 );
+#elif defined(__sun) && defined(__SVR4)
+ size_t size = X_BUFSIZE;
+ char program[MAXPATHLEN];
+ snprintf(program, MAXPATHLEN, "/proc/%d/path/a.out", getpid());
+ ssize_t rc = readlink(program, path, size);
+#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
#ifdef KM_WIN32
+#ifdef KM_WIN32_UTF8
+
+//
+Kumu::Result_t
+Kumu::wbstr_to_utf8(const Kumu::ByteString& in, std::string& out)
+{
+ out.erase();
+ assert(in.Length()%sizeof(wchar_t)==0);
+ const wchar_t* p = (const wchar_t*)in.RoData();
+
+ int stringLength = static_cast<int>( in.Length() );
+ int len = WideCharToMultiByte(CP_UTF8, 0, p, stringLength, NULL, 0, NULL, NULL);
+ char *mb_buf = new char[len];
+ WideCharToMultiByte(CP_UTF8, 0, p, stringLength, mb_buf, len, NULL, NULL);
+ out = mb_buf;
+ delete [] mb_buf;
+ return RESULT_OK;
+}
+
+//
+Kumu::Result_t
+Kumu::utf8_to_wbstr(const std::string& in, Kumu::ByteString& out)
+{
+ Result_t result = out.Capacity((in.size()+1)*sizeof(wchar_t));
+
+ if ( KM_FAILURE(result) )
+ {
+ return result;
+ }
+
+ assert(in.size()*sizeof(wchar_t)<=out.Capacity());
+ const char* read_pos = in.c_str();
+ wchar_t character, *write_pos = (wchar_t*)out.Data();
+
+ int stringLength = static_cast<int>( in.length() ) + 1;
+ int len = MultiByteToWideChar(CP_UTF8, 0, in.c_str(), stringLength, 0, 0);
+ result = out.Capacity(len*sizeof(wchar_t));
+ if ( KM_FAILURE(result) )
+ {
+ return result;
+ }
+ MultiByteToWideChar(CP_UTF8, 0, in.c_str(), stringLength, write_pos, len);
+ out.Length(len*sizeof(wchar_t));
+
+ return RESULT_OK;
+}
+
+#endif // KM_WIN32_UTF8
+
//------------------------------------------------------------------------------------------
//
Kumu::FileReader::OpenRead(const std::string& filename) const
{
const_cast<FileReader*>(this)->m_Filename = filename;
-
+#ifdef KM_WIN32_UTF8
+ ByteString wb_filename;
+ Result_t result = utf8_to_wbstr(m_Filename, wb_filename);
+
+ if ( KM_FAILURE(result) )
+ {
+ return result;
+ }
+#endif
+
// suppress popup window on error
UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+#ifdef KM_WIN32_UTF8
+ const_cast<FileReader*>(this)->m_Handle =
+ ::CreateFileW((wchar_t*)wb_filename.RoData(),
+#else
const_cast<FileReader*>(this)->m_Handle = ::CreateFileA(filename.c_str(),
+#endif
(GENERIC_READ), // open for reading
FILE_SHARE_READ, // share for reading
NULL, // no security
//------------------------------------------------------------------------------------------
//
+
//
Kumu::Result_t
Kumu::FileWriter::OpenWrite(const std::string& filename)
{
m_Filename = filename;
-
+#ifdef KM_WIN32_UTF8
+ ByteString wb_filename;
+ Result_t result = utf8_to_wbstr(m_Filename, wb_filename);
+
+ if ( KM_FAILURE(result) )
+ {
+ return result;
+ }
+#endif
+
// suppress popup window on error
UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+#ifdef KM_WIN32_UTF8
+ m_Handle = ::CreateFileW((wchar_t*)wb_filename.RoData(),
+#else
m_Handle = ::CreateFileA(filename.c_str(),
+#endif
(GENERIC_WRITE|GENERIC_READ), // open for reading
FILE_SHARE_READ, // share for reading
NULL, // no security
Kumu::FileWriter::OpenWrite(const std::string& filename)
{
m_Filename = filename;
- m_Handle = open(filename.c_str(), O_RDWR|O_CREAT|O_TRUNC, 0664);
+ m_Handle = open(filename.c_str(), O_RDWR|O_CREAT|O_TRUNC, 0666);
if ( m_Handle == -1L )
{
Kumu::FileWriter::OpenModify(const std::string& filename)
{
m_Filename = filename;
- m_Handle = open(filename.c_str(), O_RDWR|O_CREAT, 0664);
+ m_Handle = open(filename.c_str(), O_RDWR|O_CREAT, 0666);
if ( m_Handle == -1L )
{
if ( KM_SUCCESS(result) )
{
ui32_t read_count = 0;
- FileWriter Reader;
+ FileReader Reader;
result = Reader.OpenRead(Filename);
if ( KM_SUCCESS(result) )
{
ui32_t read_count = 0;
- FileWriter Reader;
+ FileReader Reader;
result = Reader.OpenRead(Filename);
//
-// 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::GetNext(char* 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;
- }
-
- return result;
-}
-
-
-#else // KM_WIN32
-
-// POSIX directory scanner
-
//
Kumu::DirScanner::DirScanner(void) : m_Handle(NULL) {}
return RESULT_OK;
}
+//------------------------------------------------------------------------------------------
//
Kumu::DirScannerEx::DirScannerEx() : m_Handle(0) {}
if ( m_Handle == 0 )
return RESULT_FILEOPEN;
+#if defined(__sun) && defined(__SVR4)
+ struct stat s;
+#endif
struct dirent* entry;
for (;;)
next_item_name.assign(entry->d_name, strlen(entry->d_name));
+#if defined(__sun) && defined(__SVR4)
+
+ stat(entry->d_name, &s);
+
+ switch ( s.st_mode )
+ {
+ case S_IFDIR:
+ next_item_type = DET_DIR;
+ break;
+
+ case S_IFREG:
+ next_item_type = DET_FILE;
+ break;
+
+ case S_IFLNK:
+ next_item_type = DET_LINK;
+ break;
+
+ default:
+ next_item_type = DET_DEV;
+ }
+#else // __sun
switch ( entry->d_type )
{
case DT_DIR:
default:
next_item_type = DET_DEV;
}
-
+#endif // __sun
return RESULT_OK;
}
-#endif // KM_WIN32
-
-
//------------------------------------------------------------------------------------------
//
#ifdef KM_WIN32
if ( _mkdir(tmp_path.c_str()) != 0 )
#else // KM_WIN32
- if ( mkdir(tmp_path.c_str(), 0775) != 0 )
+ if ( mkdir(tmp_path.c_str(), 0777) != 0 )
#endif // KM_WIN32
{
DefaultLogSink().Error("CreateDirectoriesInPath mkdir %s: %s\n",
#else // KM_WIN32
struct statfs s;
+#if defined(__sun) && defined(__SVR4)
+ if ( statfs(path.c_str(), &s, s.f_bsize, s.f_fstyp ) == 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_bfree;
+ total_space = (Kumu::fsize_t)s.f_bsize * (Kumu::fsize_t)s.f_blocks;
+ return RESULT_OK;
+ }
+#else
if ( statfs(path.c_str(), &s) == 0 )
{
if ( s.f_blocks < 1 )
DefaultLogSink().Error("FreeSpaceForPath statfs %s: %s\n", path.c_str(), strerror(errno));
return RESULT_FAIL;
+#endif // __sun
#endif // KM_WIN32
}