blob: aaa53ce0772300c8aa7aa141302649860b0832b2 [file] [log] [blame]
Zachary Turnerc00cf4a2014-08-15 22:04:21 +00001//===-- FileSystem.cpp ------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/Host/FileSystem.h"
11
12// C includes
Chaoren Lin226937e2015-06-27 23:11:34 +000013#include <dirent.h>
Greg Clayton736888c2015-02-23 23:47:09 +000014#include <sys/mount.h>
15#include <sys/param.h>
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000016#include <sys/stat.h>
17#include <sys/types.h>
Vince Harron294aeb92015-02-24 05:14:49 +000018#ifdef __linux__
Vince Harron294aeb92015-02-24 05:14:49 +000019#include <linux/magic.h>
Kate Stoneb9c1b512016-09-06 20:57:50 +000020#include <sys/mount.h>
21#include <sys/statfs.h>
Vince Harron294aeb92015-02-24 05:14:49 +000022#endif
Stephane Sezer851f23d2015-09-09 01:19:05 +000023#if defined(__NetBSD__)
24#include <sys/statvfs.h>
25#endif
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000026
27// lldb Includes
28#include "lldb/Core/Error.h"
29#include "lldb/Core/StreamString.h"
30#include "lldb/Host/Host.h"
31
32using namespace lldb;
33using namespace lldb_private;
34
Kate Stoneb9c1b512016-09-06 20:57:50 +000035const char *FileSystem::DEV_NULL = "/dev/null";
Zachary Turner4eff2d32015-10-14 21:37:36 +000036
Kate Stoneb9c1b512016-09-06 20:57:50 +000037FileSpec::PathSyntax FileSystem::GetNativePathSyntax() {
38 return FileSpec::ePathSyntaxPosix;
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000039}
40
Kate Stoneb9c1b512016-09-06 20:57:50 +000041Error FileSystem::MakeDirectory(const FileSpec &file_spec,
42 uint32_t file_permissions) {
43 if (file_spec) {
44 Error error;
45 if (::mkdir(file_spec.GetCString(), file_permissions) == -1) {
46 error.SetErrorToErrno();
47 errno = 0;
48 switch (error.GetError()) {
49 case ENOENT: {
50 // Parent directory doesn't exist, so lets make it if we can
51 // Make the parent directory and try again
52 FileSpec parent_file_spec{file_spec.GetDirectory().GetCString(), false};
53 error = MakeDirectory(parent_file_spec, file_permissions);
54 if (error.Fail())
55 return error;
56 // Try and make the directory again now that the parent directory was
57 // made successfully
58 if (::mkdir(file_spec.GetCString(), file_permissions) == -1) {
59 error.SetErrorToErrno();
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000060 }
Chaoren Lind3173f32015-05-29 19:52:29 +000061 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +000062 } break;
63 case EEXIST: {
64 if (file_spec.IsDirectory())
65 return Error(); // It is a directory and it already exists
66 } break;
67 }
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000068 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000069 return error;
70 }
71 return Error("empty path");
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000072}
73
Kate Stoneb9c1b512016-09-06 20:57:50 +000074Error FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse) {
75 Error error;
76 if (file_spec) {
77 if (recurse) {
78 // Save all sub directories in a list so we don't recursively call this
79 // function
80 // and possibly run out of file descriptors if the directory is too deep.
81 std::vector<FileSpec> sub_directories;
Greg Clayton58c65f02015-06-29 18:29:00 +000082
Kate Stoneb9c1b512016-09-06 20:57:50 +000083 FileSpec::ForEachItemInDirectory(
84 file_spec.GetCString(),
85 [&error, &sub_directories](
86 FileSpec::FileType file_type,
87 const FileSpec &spec) -> FileSpec::EnumerateDirectoryResult {
88 if (file_type == FileSpec::eFileTypeDirectory) {
89 // Save all directorires and process them after iterating through
90 // this directory
91 sub_directories.push_back(spec);
92 } else {
93 // Update sub_spec to point to the current file and delete it
94 error = FileSystem::Unlink(spec);
Chaoren Lin226937e2015-06-27 23:11:34 +000095 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000096 // If anything went wrong, stop iterating, else process the next
97 // file
98 if (error.Fail())
99 return FileSpec::eEnumerateDirectoryResultQuit;
100 else
101 return FileSpec::eEnumerateDirectoryResultNext;
102 });
103
104 if (error.Success()) {
105 // Now delete all sub directories with separate calls that aren't
106 // recursively calling into this function _while_ this function is
107 // iterating through the current directory.
108 for (const auto &sub_directory : sub_directories) {
109 error = DeleteDirectory(sub_directory, recurse);
110 if (error.Fail())
111 break;
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000112 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113 }
114 }
Greg Clayton58c65f02015-06-29 18:29:00 +0000115
Kate Stoneb9c1b512016-09-06 20:57:50 +0000116 if (error.Success()) {
117 if (::rmdir(file_spec.GetCString()) != 0)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000118 error.SetErrorToErrno();
119 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000120 } else {
121 error.SetErrorString("empty path");
122 }
123 return error;
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000124}
125
Kate Stoneb9c1b512016-09-06 20:57:50 +0000126Error FileSystem::GetFilePermissions(const FileSpec &file_spec,
127 uint32_t &file_permissions) {
128 Error error;
129 struct stat file_stats;
130 if (::stat(file_spec.GetCString(), &file_stats) == 0) {
131 // The bits in "st_mode" currently match the definitions
132 // for the file mode bits in unix.
133 file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
134 } else {
135 error.SetErrorToErrno();
136 }
137 return error;
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000138}
139
Kate Stoneb9c1b512016-09-06 20:57:50 +0000140Error FileSystem::SetFilePermissions(const FileSpec &file_spec,
141 uint32_t file_permissions) {
142 Error error;
143 if (::chmod(file_spec.GetCString(), file_permissions) != 0)
144 error.SetErrorToErrno();
145 return error;
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000146}
147
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148lldb::user_id_t FileSystem::GetFileSize(const FileSpec &file_spec) {
149 return file_spec.GetByteSize();
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000150}
151
Kate Stoneb9c1b512016-09-06 20:57:50 +0000152bool FileSystem::GetFileExists(const FileSpec &file_spec) {
153 return file_spec.Exists();
Oleksiy Vyalova9ea0712015-05-08 23:54:34 +0000154}
155
Kate Stoneb9c1b512016-09-06 20:57:50 +0000156Error FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) {
157 Error error;
158 if (::link(dst.GetCString(), src.GetCString()) == -1)
159 error.SetErrorToErrno();
160 return error;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000161}
162
Kate Stoneb9c1b512016-09-06 20:57:50 +0000163int FileSystem::GetHardlinkCount(const FileSpec &file_spec) {
164 struct stat file_stat;
165 if (::stat(file_spec.GetCString(), &file_stat) == 0)
166 return file_stat.st_nlink;
167
168 return -1;
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000169}
170
Kate Stoneb9c1b512016-09-06 20:57:50 +0000171Error FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) {
172 Error error;
173 if (::symlink(dst.GetCString(), src.GetCString()) == -1)
174 error.SetErrorToErrno();
175 return error;
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000176}
177
Kate Stoneb9c1b512016-09-06 20:57:50 +0000178Error FileSystem::Unlink(const FileSpec &file_spec) {
179 Error error;
180 if (::unlink(file_spec.GetCString()) == -1)
181 error.SetErrorToErrno();
182 return error;
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000183}
Greg Clayton736888c2015-02-23 23:47:09 +0000184
Kate Stoneb9c1b512016-09-06 20:57:50 +0000185Error FileSystem::Readlink(const FileSpec &src, FileSpec &dst) {
186 Error error;
187 char buf[PATH_MAX];
188 ssize_t count = ::readlink(src.GetCString(), buf, sizeof(buf) - 1);
189 if (count < 0)
190 error.SetErrorToErrno();
191 else {
192 buf[count] = '\0'; // Success
193 dst.SetFile(buf, false);
194 }
195 return error;
196}
197
198Error FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) {
199 char resolved_path[PATH_MAX];
200 if (!src.GetPath(resolved_path, sizeof(resolved_path))) {
201 return Error("Couldn't get the canonical path for %s", src.GetCString());
202 }
203
204 char real_path[PATH_MAX + 1];
205 if (realpath(resolved_path, real_path) == nullptr) {
206 Error err;
207 err.SetErrorToErrno();
208 return err;
209 }
210
211 dst = FileSpec(real_path, false);
212
213 return Error();
Sean Callanan9077e9f2015-09-18 22:24:57 +0000214}
215
Stephane Sezer851f23d2015-09-09 01:19:05 +0000216#if defined(__NetBSD__)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000217static bool IsLocal(const struct statvfs &info) {
218 return (info.f_flag & MNT_LOCAL) != 0;
Stephane Sezer851f23d2015-09-09 01:19:05 +0000219}
220#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000221static bool IsLocal(const struct statfs &info) {
Vince Harron294aeb92015-02-24 05:14:49 +0000222#ifdef __linux__
Kate Stoneb9c1b512016-09-06 20:57:50 +0000223#define CIFS_MAGIC_NUMBER 0xFF534D42
224 switch ((uint32_t)info.f_type) {
225 case NFS_SUPER_MAGIC:
226 case SMB_SUPER_MAGIC:
227 case CIFS_MAGIC_NUMBER:
228 return false;
229 default:
230 return true;
231 }
Vince Harron294aeb92015-02-24 05:14:49 +0000232#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000233 return (info.f_flags & MNT_LOCAL) != 0;
Vince Harron294aeb92015-02-24 05:14:49 +0000234#endif
235}
Stephane Sezer851f23d2015-09-09 01:19:05 +0000236#endif
Vince Harron294aeb92015-02-24 05:14:49 +0000237
Stephane Sezer851f23d2015-09-09 01:19:05 +0000238#if defined(__NetBSD__)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000239bool FileSystem::IsLocal(const FileSpec &spec) {
240 struct statvfs statfs_info;
241 std::string path(spec.GetPath());
242 if (statvfs(path.c_str(), &statfs_info) == 0)
243 return ::IsLocal(statfs_info);
244 return false;
Stephane Sezer851f23d2015-09-09 01:19:05 +0000245}
246#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000247bool FileSystem::IsLocal(const FileSpec &spec) {
248 struct statfs statfs_info;
249 std::string path(spec.GetPath());
250 if (statfs(path.c_str(), &statfs_info) == 0)
251 return ::IsLocal(statfs_info);
252 return false;
Greg Clayton736888c2015-02-23 23:47:09 +0000253}
Stephane Sezer851f23d2015-09-09 01:19:05 +0000254#endif
Zachary Turner190fadc2016-03-22 17:58:09 +0000255
Kate Stoneb9c1b512016-09-06 20:57:50 +0000256FILE *FileSystem::Fopen(const char *path, const char *mode) {
257 return ::fopen(path, mode);
Zachary Turner190fadc2016-03-22 17:58:09 +0000258}
259
Kate Stoneb9c1b512016-09-06 20:57:50 +0000260int FileSystem::Stat(const char *path, struct stat *stats) {
261 return ::stat(path, stats);
Zachary Turner190fadc2016-03-22 17:58:09 +0000262}