blob: 1f2e7db0e1e4e5baf61e844f69c18dfee12c9244 [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__
19#include <sys/statfs.h>
20#include <sys/mount.h>
21#include <linux/magic.h>
22#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
Zachary Turner4eff2d32015-10-14 21:37:36 +000035const char *
36FileSystem::DEV_NULL = "/dev/null";
37
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000038FileSpec::PathSyntax
39FileSystem::GetNativePathSyntax()
40{
41 return FileSpec::ePathSyntaxPosix;
42}
43
44Error
Chaoren Lind3173f32015-05-29 19:52:29 +000045FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000046{
Chaoren Lind3173f32015-05-29 19:52:29 +000047 if (file_spec)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000048 {
Chaoren Lind3173f32015-05-29 19:52:29 +000049 Error error;
50 if (::mkdir(file_spec.GetCString(), file_permissions) == -1)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000051 {
52 error.SetErrorToErrno();
Chaoren Lind3173f32015-05-29 19:52:29 +000053 errno = 0;
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000054 switch (error.GetError())
55 {
56 case ENOENT:
57 {
58 // Parent directory doesn't exist, so lets make it if we can
Chaoren Lind3173f32015-05-29 19:52:29 +000059 // Make the parent directory and try again
60 FileSpec parent_file_spec{file_spec.GetDirectory().GetCString(), false};
61 error = MakeDirectory(parent_file_spec, file_permissions);
62 if (error.Fail())
63 return error;
64 // Try and make the directory again now that the parent directory was made successfully
65 if (::mkdir(file_spec.GetCString(), file_permissions) == -1)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000066 {
Chaoren Lind3173f32015-05-29 19:52:29 +000067 error.SetErrorToErrno();
68 return error;
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000069 }
70 }
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000071 case EEXIST:
72 {
Chaoren Lind3173f32015-05-29 19:52:29 +000073 if (file_spec.IsDirectory())
74 return Error{}; // It is a directory and it already exists
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000075 }
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000076 }
77 }
Chaoren Lind3173f32015-05-29 19:52:29 +000078 return error;
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000079 }
Chaoren Lind3173f32015-05-29 19:52:29 +000080 return Error{"empty path"};
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000081}
82
83Error
Chaoren Lind3173f32015-05-29 19:52:29 +000084FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000085{
86 Error error;
Chaoren Lind3173f32015-05-29 19:52:29 +000087 if (file_spec)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +000088 {
89 if (recurse)
90 {
Greg Clayton58c65f02015-06-29 18:29:00 +000091 // Save all sub directories in a list so we don't recursively call this function
92 // and possibly run out of file descriptors if the directory is too deep.
93 std::vector<FileSpec> sub_directories;
94
95 FileSpec::ForEachItemInDirectory (file_spec.GetCString(), [&error, &sub_directories](FileSpec::FileType file_type, const FileSpec &spec) -> FileSpec::EnumerateDirectoryResult {
96 if (file_type == FileSpec::eFileTypeDirectory)
97 {
98 // Save all directorires and process them after iterating through this directory
99 sub_directories.push_back(spec);
100 }
101 else
102 {
103 // Update sub_spec to point to the current file and delete it
104 error = FileSystem::Unlink(spec);
105 }
106 // If anything went wrong, stop iterating, else process the next file
107 if (error.Fail())
108 return FileSpec::eEnumerateDirectoryResultQuit;
109 else
110 return FileSpec::eEnumerateDirectoryResultNext;
111 });
112
113 if (error.Success())
Chaoren Lin226937e2015-06-27 23:11:34 +0000114 {
Greg Clayton58c65f02015-06-29 18:29:00 +0000115 // Now delete all sub directories with separate calls that aren't
116 // recursively calling into this function _while_ this function is
117 // iterating through the current directory.
118 for (const auto &sub_directory : sub_directories)
119 {
120 error = DeleteDirectory(sub_directory, recurse);
121 if (error.Fail())
122 break;
123 }
Chaoren Lin226937e2015-06-27 23:11:34 +0000124 }
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000125 }
Greg Clayton58c65f02015-06-29 18:29:00 +0000126
127 if (error.Success())
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000128 {
Chaoren Lind3173f32015-05-29 19:52:29 +0000129 if (::rmdir(file_spec.GetCString()) != 0)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000130 error.SetErrorToErrno();
131 }
132 }
133 else
134 {
135 error.SetErrorString("empty path");
136 }
137 return error;
138}
139
140Error
Chaoren Lind3173f32015-05-29 19:52:29 +0000141FileSystem::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000142{
143 Error error;
144 struct stat file_stats;
Chaoren Lind3173f32015-05-29 19:52:29 +0000145 if (::stat(file_spec.GetCString(), &file_stats) == 0)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000146 {
147 // The bits in "st_mode" currently match the definitions
148 // for the file mode bits in unix.
149 file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
150 }
151 else
152 {
153 error.SetErrorToErrno();
154 }
155 return error;
156}
157
158Error
Chaoren Lind3173f32015-05-29 19:52:29 +0000159FileSystem::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000160{
161 Error error;
Chaoren Lind3173f32015-05-29 19:52:29 +0000162 if (::chmod(file_spec.GetCString(), file_permissions) != 0)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000163 error.SetErrorToErrno();
164 return error;
165}
166
167lldb::user_id_t
168FileSystem::GetFileSize(const FileSpec &file_spec)
169{
170 return file_spec.GetByteSize();
171}
172
173bool
174FileSystem::GetFileExists(const FileSpec &file_spec)
175{
176 return file_spec.Exists();
177}
178
179Error
Chaoren Lind3173f32015-05-29 19:52:29 +0000180FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst)
Oleksiy Vyalova9ea0712015-05-08 23:54:34 +0000181{
182 Error error;
Chaoren Lind3173f32015-05-29 19:52:29 +0000183 if (::link(dst.GetCString(), src.GetCString()) == -1)
Oleksiy Vyalova9ea0712015-05-08 23:54:34 +0000184 error.SetErrorToErrno();
185 return error;
186}
187
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000188int
189FileSystem::GetHardlinkCount(const FileSpec &file_spec)
190{
191 struct stat file_stat;
192 if (::stat(file_spec.GetCString(), &file_stat) == 0)
193 return file_stat.st_nlink;
194
195 return -1;
196}
197
Oleksiy Vyalova9ea0712015-05-08 23:54:34 +0000198Error
Chaoren Lind3173f32015-05-29 19:52:29 +0000199FileSystem::Symlink(const FileSpec &src, const FileSpec &dst)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000200{
201 Error error;
Chaoren Lind3173f32015-05-29 19:52:29 +0000202 if (::symlink(dst.GetCString(), src.GetCString()) == -1)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000203 error.SetErrorToErrno();
204 return error;
205}
206
207Error
Chaoren Lind3173f32015-05-29 19:52:29 +0000208FileSystem::Unlink(const FileSpec &file_spec)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000209{
210 Error error;
Chaoren Lind3173f32015-05-29 19:52:29 +0000211 if (::unlink(file_spec.GetCString()) == -1)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000212 error.SetErrorToErrno();
213 return error;
214}
215
216Error
Chaoren Lind3173f32015-05-29 19:52:29 +0000217FileSystem::Readlink(const FileSpec &src, FileSpec &dst)
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000218{
219 Error error;
Chaoren Lind3173f32015-05-29 19:52:29 +0000220 char buf[PATH_MAX];
221 ssize_t count = ::readlink(src.GetCString(), buf, sizeof(buf) - 1);
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000222 if (count < 0)
223 error.SetErrorToErrno();
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000224 else
Chaoren Lind3173f32015-05-29 19:52:29 +0000225 {
226 buf[count] = '\0'; // Success
227 dst.SetFile(buf, false);
228 }
Zachary Turnerc00cf4a2014-08-15 22:04:21 +0000229 return error;
230}
Greg Clayton736888c2015-02-23 23:47:09 +0000231
Sean Callanan9077e9f2015-09-18 22:24:57 +0000232Error
233FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst)
234{
235 char resolved_path[PATH_MAX];
236 if (!src.GetPath (resolved_path, sizeof (resolved_path)))
237 {
238 return Error("Couldn't get the canonical path for %s", src.GetCString());
239 }
240
241 char real_path[PATH_MAX + 1];
242 if (realpath(resolved_path, real_path) == nullptr)
243 {
244 Error err;
245 err.SetErrorToErrno();
246 return err;
247 }
248
249 dst = FileSpec(real_path, false);
250
251 return Error();
252}
253
Stephane Sezer851f23d2015-09-09 01:19:05 +0000254#if defined(__NetBSD__)
255static bool IsLocal(const struct statvfs& info)
256{
257 return (info.f_flag & MNT_LOCAL) != 0;
258}
259#else
Vince Harron294aeb92015-02-24 05:14:49 +0000260static bool IsLocal(const struct statfs& info)
261{
262#ifdef __linux__
263 #define CIFS_MAGIC_NUMBER 0xFF534D42
Omair Javaida77ca512015-04-27 12:01:59 +0000264 switch ((uint32_t)info.f_type)
Vince Harron294aeb92015-02-24 05:14:49 +0000265 {
266 case NFS_SUPER_MAGIC:
267 case SMB_SUPER_MAGIC:
268 case CIFS_MAGIC_NUMBER:
269 return false;
270 default:
271 return true;
272 }
273#else
274 return (info.f_flags & MNT_LOCAL) != 0;
275#endif
276}
Stephane Sezer851f23d2015-09-09 01:19:05 +0000277#endif
Vince Harron294aeb92015-02-24 05:14:49 +0000278
Stephane Sezer851f23d2015-09-09 01:19:05 +0000279#if defined(__NetBSD__)
280bool
281FileSystem::IsLocal(const FileSpec &spec)
282{
283 struct statvfs statfs_info;
284 std::string path (spec.GetPath());
285 if (statvfs(path.c_str(), &statfs_info) == 0)
286 return ::IsLocal(statfs_info);
287 return false;
288}
289#else
Greg Clayton736888c2015-02-23 23:47:09 +0000290bool
291FileSystem::IsLocal(const FileSpec &spec)
292{
293 struct statfs statfs_info;
294 std::string path (spec.GetPath());
Vince Harronf7839222015-02-24 05:24:12 +0000295 if (statfs(path.c_str(), &statfs_info) == 0)
Vince Harron294aeb92015-02-24 05:14:49 +0000296 return ::IsLocal(statfs_info);
Greg Clayton736888c2015-02-23 23:47:09 +0000297 return false;
298}
Stephane Sezer851f23d2015-09-09 01:19:05 +0000299#endif