aboutsummaryrefslogtreecommitdiff
path: root/source/Host/posix/FileSystem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Host/posix/FileSystem.cpp')
-rw-r--r--source/Host/posix/FileSystem.cpp181
1 files changed, 111 insertions, 70 deletions
diff --git a/source/Host/posix/FileSystem.cpp b/source/Host/posix/FileSystem.cpp
index 571316811142..52698039b46e 100644
--- a/source/Host/posix/FileSystem.cpp
+++ b/source/Host/posix/FileSystem.cpp
@@ -10,8 +10,16 @@
#include "lldb/Host/FileSystem.h"
// C includes
+#include <dirent.h>
+#include <sys/mount.h>
+#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
+#ifdef __linux__
+#include <sys/statfs.h>
+#include <sys/mount.h>
+#include <linux/magic.h>
+#endif
// lldb Includes
#include "lldb/Core/Error.h"
@@ -28,70 +36,91 @@ FileSystem::GetNativePathSyntax()
}
Error
-FileSystem::MakeDirectory(const char *path, uint32_t file_permissions)
+FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions)
{
- Error error;
- if (path && path[0])
+ if (file_spec)
{
- if (::mkdir(path, file_permissions) != 0)
+ Error error;
+ if (::mkdir(file_spec.GetCString(), file_permissions) == -1)
{
error.SetErrorToErrno();
+ errno = 0;
switch (error.GetError())
{
case ENOENT:
{
// Parent directory doesn't exist, so lets make it if we can
- FileSpec spec(path, false);
- if (spec.GetDirectory() && spec.GetFilename())
+ // Make the parent directory and try again
+ FileSpec parent_file_spec{file_spec.GetDirectory().GetCString(), false};
+ error = MakeDirectory(parent_file_spec, file_permissions);
+ if (error.Fail())
+ return error;
+ // Try and make the directory again now that the parent directory was made successfully
+ if (::mkdir(file_spec.GetCString(), file_permissions) == -1)
{
- // Make the parent directory and try again
- Error error2 = MakeDirectory(spec.GetDirectory().GetCString(), file_permissions);
- if (error2.Success())
- {
- // Try and make the directory again now that the parent directory was made successfully
- if (::mkdir(path, file_permissions) == 0)
- error.Clear();
- else
- error.SetErrorToErrno();
- }
+ error.SetErrorToErrno();
+ return error;
}
}
- break;
-
case EEXIST:
{
- FileSpec path_spec(path, false);
- if (path_spec.IsDirectory())
- error.Clear(); // It is a directory and it already exists
+ if (file_spec.IsDirectory())
+ return Error{}; // It is a directory and it already exists
}
- break;
}
}
+ return error;
}
- else
- {
- error.SetErrorString("empty path");
- }
- return error;
+ return Error{"empty path"};
}
Error
-FileSystem::DeleteDirectory(const char *path, bool recurse)
+FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse)
{
Error error;
- if (path && path[0])
+ if (file_spec)
{
if (recurse)
{
- StreamString command;
- command.Printf("rm -rf \"%s\"", path);
- int status = ::system(command.GetString().c_str());
- if (status != 0)
- error.SetError(status, eErrorTypeGeneric);
+ // Save all sub directories in a list so we don't recursively call this function
+ // and possibly run out of file descriptors if the directory is too deep.
+ std::vector<FileSpec> sub_directories;
+
+ FileSpec::ForEachItemInDirectory (file_spec.GetCString(), [&error, &sub_directories](FileSpec::FileType file_type, const FileSpec &spec) -> FileSpec::EnumerateDirectoryResult {
+ if (file_type == FileSpec::eFileTypeDirectory)
+ {
+ // Save all directorires and process them after iterating through this directory
+ sub_directories.push_back(spec);
+ }
+ else
+ {
+ // Update sub_spec to point to the current file and delete it
+ error = FileSystem::Unlink(spec);
+ }
+ // If anything went wrong, stop iterating, else process the next file
+ if (error.Fail())
+ return FileSpec::eEnumerateDirectoryResultQuit;
+ else
+ return FileSpec::eEnumerateDirectoryResultNext;
+ });
+
+ if (error.Success())
+ {
+ // Now delete all sub directories with separate calls that aren't
+ // recursively calling into this function _while_ this function is
+ // iterating through the current directory.
+ for (const auto &sub_directory : sub_directories)
+ {
+ error = DeleteDirectory(sub_directory, recurse);
+ if (error.Fail())
+ break;
+ }
+ }
}
- else
+
+ if (error.Success())
{
- if (::rmdir(path) != 0)
+ if (::rmdir(file_spec.GetCString()) != 0)
error.SetErrorToErrno();
}
}
@@ -103,11 +132,11 @@ FileSystem::DeleteDirectory(const char *path, bool recurse)
}
Error
-FileSystem::GetFilePermissions(const char *path, uint32_t &file_permissions)
+FileSystem::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions)
{
Error error;
struct stat file_stats;
- if (::stat(path, &file_stats) == 0)
+ if (::stat(file_spec.GetCString(), &file_stats) == 0)
{
// The bits in "st_mode" currently match the definitions
// for the file mode bits in unix.
@@ -121,10 +150,10 @@ FileSystem::GetFilePermissions(const char *path, uint32_t &file_permissions)
}
Error
-FileSystem::SetFilePermissions(const char *path, uint32_t file_permissions)
+FileSystem::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions)
{
Error error;
- if (::chmod(path, file_permissions) != 0)
+ if (::chmod(file_spec.GetCString(), file_permissions) != 0)
error.SetErrorToErrno();
return error;
}
@@ -142,60 +171,72 @@ FileSystem::GetFileExists(const FileSpec &file_spec)
}
Error
-FileSystem::Symlink(const char *src, const char *dst)
+FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst)
{
Error error;
- if (::symlink(dst, src) == -1)
+ if (::link(dst.GetCString(), src.GetCString()) == -1)
error.SetErrorToErrno();
return error;
}
Error
-FileSystem::Unlink(const char *path)
+FileSystem::Symlink(const FileSpec &src, const FileSpec &dst)
{
Error error;
- if (::unlink(path) == -1)
+ if (::symlink(dst.GetCString(), src.GetCString()) == -1)
error.SetErrorToErrno();
return error;
}
Error
-FileSystem::Readlink(const char *path, char *buf, size_t buf_len)
+FileSystem::Unlink(const FileSpec &file_spec)
{
Error error;
- ssize_t count = ::readlink(path, buf, buf_len);
+ if (::unlink(file_spec.GetCString()) == -1)
+ error.SetErrorToErrno();
+ return error;
+}
+
+Error
+FileSystem::Readlink(const FileSpec &src, FileSpec &dst)
+{
+ Error error;
+ char buf[PATH_MAX];
+ ssize_t count = ::readlink(src.GetCString(), buf, sizeof(buf) - 1);
if (count < 0)
error.SetErrorToErrno();
- else if (static_cast<size_t>(count) < (buf_len - 1))
- buf[count] = '\0'; // Success
else
- error.SetErrorString("'buf' buffer is too small to contain link contents");
+ {
+ buf[count] = '\0'; // Success
+ dst.SetFile(buf, false);
+ }
return error;
}
-bool
-FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high)
+static bool IsLocal(const struct statfs& info)
{
-#if defined(__APPLE__)
- StreamString md5_cmd_line;
- md5_cmd_line.Printf("md5 -q '%s'", file_spec.GetPath().c_str());
- std::string hash_string;
- Error err = Host::RunShellCommand(md5_cmd_line.GetData(), NULL, NULL, NULL, &hash_string, 60);
- if (err.Fail())
- return false;
- // a correctly formed MD5 is 16-bytes, that is 32 hex digits
- // if the output is any other length it is probably wrong
- if (hash_string.size() != 32)
+#ifdef __linux__
+ #define CIFS_MAGIC_NUMBER 0xFF534D42
+ switch ((uint32_t)info.f_type)
+ {
+ case NFS_SUPER_MAGIC:
+ case SMB_SUPER_MAGIC:
+ case CIFS_MAGIC_NUMBER:
return false;
- std::string part1(hash_string, 0, 16);
- std::string part2(hash_string, 16);
- const char *part1_cstr = part1.c_str();
- const char *part2_cstr = part2.c_str();
- high = ::strtoull(part1_cstr, NULL, 16);
- low = ::strtoull(part2_cstr, NULL, 16);
- return true;
+ default:
+ return true;
+ }
#else
- // your own MD5 implementation here
- return false;
+ return (info.f_flags & MNT_LOCAL) != 0;
#endif
}
+
+bool
+FileSystem::IsLocal(const FileSpec &spec)
+{
+ struct statfs statfs_info;
+ std::string path (spec.GetPath());
+ if (statfs(path.c_str(), &statfs_info) == 0)
+ return ::IsLocal(statfs_info);
+ return false;
+}