Browse Source

Added make/remove directory functionality.

Branimir Karadžić 8 years ago
parent
commit
fbb1e453b6
5 changed files with 179 additions and 7 deletions
  1. 16 0
      include/bx/filepath.h
  2. 143 3
      src/filepath.cpp
  3. 4 4
      src/settings.cpp
  4. 6 0
      src/string.cpp
  5. 10 0
      tests/filepath_test.cpp

+ 16 - 0
include/bx/filepath.h

@@ -6,8 +6,12 @@
 #ifndef BX_FILEPATH_H_HEADER_GUARD
 #define BX_FILEPATH_H_HEADER_GUARD
 
+#include "error.h"
 #include "string.h"
 
+BX_ERROR_RESULT(BX_ERROR_ACCESS,        BX_MAKEFOURCC('b', 'x', 0, 0) );
+BX_ERROR_RESULT(BX_ERROR_NOT_DIRECTORY, BX_MAKEFOURCC('b', 'x', 0, 1) );
+
 namespace bx
 {
 	const int32_t kMaxFilePath = 1024;
@@ -87,6 +91,18 @@ namespace bx
 		char m_filePath[kMaxFilePath];
 	};
 
+	/// Creates a directory named `_filePath`.
+	bool make(const FilePath& _filePath, Error* _err);
+
+	/// Creates a directory named `_filePath` along with all necessary parents.
+	bool makeAll(const FilePath& _filePath, Error* _err);
+
+	/// Removes file or directory.
+	bool remove(const FilePath& _filePath, Error* _err);
+
+	/// Removes file or directory recursivelly.
+	bool removeAll(const FilePath& _filePath, Error* _err);
+
 } // namespace bx
 
 #endif // BX_FILEPATH_H_HEADER_GUARD

+ 143 - 3
src/filepath.cpp

@@ -8,10 +8,14 @@
 #include <bx/os.h>
 #include <bx/readerwriter.h>
 
+#include <stdio.h>  // remove
+#include <dirent.h> // opendir
+
 #if BX_CRT_MSVC
-#	include <direct.h> // _getcwd
+#	include <direct.h>   // _getcwd
 #else
-#	include <unistd.h> // getcwd
+#	include <sys/stat.h> // mkdir
+#	include <unistd.h>   // getcwd
 #endif // BX_CRT_MSVC
 
 #if BX_PLATFORM_WINDOWS
@@ -175,7 +179,7 @@ namespace bx
 		BX_UNUSED(_buffer, _size);
 		return NULL;
 #elif BX_CRT_MSVC
-		return ::_getcwd(_buffer, (int)_size);
+		return ::_getcwd(_buffer, (int32_t)_size);
 #else
 		return ::getcwd(_buffer, _size);
 #endif // BX_COMPILER_
@@ -380,4 +384,140 @@ namespace bx
 			;
 	}
 
+	bool make(const FilePath& _filePath, Error* _err)
+	{
+		BX_ERROR_SCOPE(_err);
+
+		if (!_err->isOk() )
+		{
+			return false;
+		}
+
+#if BX_CRT_MSVC
+		int32_t result = ::_mkdir(_filePath.get() );
+#else
+		int32_t result = ::mkdir(_filePath.get(), 0700);
+#endif // BX_CRT_MSVC
+
+		if (0 != result)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process.");
+			return false;
+		}
+
+		return true;
+	}
+
+	bool makeAll(const FilePath& _filePath, Error* _err)
+	{
+		BX_ERROR_SCOPE(_err);
+
+		if (!_err->isOk() )
+		{
+			return false;
+		}
+
+		FileInfo fi;
+
+		if (stat(_filePath, fi) )
+		{
+			if (FileInfo::Directory == fi.m_type)
+			{
+				return true;
+			}
+
+			BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory.");
+			return false;
+		}
+
+		const StringView dir = strRTrim(_filePath.get(), "/");
+		const char* slash = strRFind(dir, '/');
+
+		if (NULL != slash
+		&&  slash - dir.getPtr() > 1)
+		{
+			if (!makeAll(StringView(dir.getPtr(), slash), _err) )
+			{
+				return false;
+			}
+		}
+
+		FilePath path(dir);
+		return make(path, _err);
+	}
+
+	bool remove(const FilePath& _filePath, Error* _err)
+	{
+		BX_ERROR_SCOPE(_err);
+
+		if (!_err->isOk() )
+		{
+			return false;
+		}
+
+		int32_t result = ::remove(_filePath.get() );
+
+		if (0 != result)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process.");
+			return false;
+		}
+
+		return true;
+	}
+
+	bool removeAll(const FilePath& _filePath, Error* _err)
+	{
+		BX_ERROR_SCOPE(_err);
+
+		if (remove(_filePath, _err) )
+		{
+			return true;
+		}
+
+		_err->reset();
+
+		FileInfo fi;
+
+		if (!stat(_filePath, fi) )
+		{
+			BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process.");
+			return false;
+		}
+
+		if (FileInfo::Directory != fi.m_type)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory.");
+			return false;
+		}
+
+		DIR* dir = opendir(_filePath.get() );
+		if (NULL == dir)
+		{
+			BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory.");
+			return false;
+		}
+
+		for (dirent* item = readdir(dir); NULL != item; item = readdir(dir) )
+		{
+			if (0 == strCmp(item->d_name, ".")
+			||  0 == strCmp(item->d_name, "..") )
+			{
+				continue;
+			}
+
+			FilePath path(_filePath);
+			path.join(item->d_name);
+			if (!removeAll(path, _err) )
+			{
+				_err->reset();
+				break;
+			}
+		}
+
+		closedir(dir);
+
+		return remove(_filePath, _err);
+	}
+
 } // namespace bx

+ 4 - 4
src/settings.cpp

@@ -69,8 +69,8 @@ const char* Settings::get(const StringView& _name) const
 	ini_t* ini = INI_T(m_ini);
 
 	FilePath uri(_name);
-	const StringView  path     = strTrim(uri.getPath(), "/");
-	const StringView& fileName = uri.getFileName();
+	const StringView  path(strTrim(uri.getPath(), "/") );
+	const StringView& fileName(uri.getFileName() );
 	int32_t section = INI_GLOBAL_SECTION;
 
 	if (!path.isEmpty() )
@@ -96,8 +96,8 @@ void Settings::set(const StringView& _name, const StringView& _value)
 	ini_t* ini = INI_T(m_ini);
 
 	FilePath uri(_name);
-	const StringView  path     = strTrim(uri.getPath(), "/");
-	const StringView& fileName = uri.getFileName();
+	const StringView  path(strTrim(uri.getPath(), "/") );
+	const StringView& fileName(uri.getFileName() );
 
 	int32_t section = INI_GLOBAL_SECTION;
 

+ 6 - 0
src/string.cpp

@@ -446,6 +446,7 @@ namespace bx
 		const char* ptr   = _str.getPtr();
 		const char* chars = _chars.getPtr();
 		const uint32_t charsLen = _chars.getLength();
+
 		for (uint32_t ii = 0, len = _str.getLength(); ii < len; ++ii)
 		{
 			if (NULL == strFindUnsafe(chars, charsLen, ptr[ii]) )
@@ -459,6 +460,11 @@ namespace bx
 
 	StringView strRTrim(const StringView& _str, const StringView& _chars)
 	{
+		if (_str.isEmpty() )
+		{
+			return StringView();
+		}
+
 		const char* ptr   = _str.getPtr();
 		const char* chars = _chars.getPtr();
 		const uint32_t charsLen = _chars.getLength();

+ 10 - 0
tests/filepath_test.cpp

@@ -123,4 +123,14 @@ TEST_CASE("FilePath temp", "")
 {
 	bx::FilePath tmp(bx::Dir::Temp);
 	REQUIRE(0 != bx::strCmp(".", tmp.getPath().getPtr() ) );
+
+	bx::Error err;
+	tmp.join("test/abvgd/555333/test");
+	REQUIRE(bx::makeAll(tmp, &err) );
+	REQUIRE(err.isOk() );
+
+	tmp.set(bx::Dir::Temp);
+	tmp.join("test");
+	REQUIRE(bx::removeAll(tmp, &err) );
+	REQUIRE(err.isOk() );
 }