OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
6 #if defined(HOST_OS_FUCHSIA) | 6 #if defined(HOST_OS_FUCHSIA) |
7 | 7 |
8 #include "bin/directory.h" | 8 #include "bin/directory.h" |
9 | 9 |
10 #include <dirent.h> // NOLINT | 10 #include <dirent.h> // NOLINT |
11 #include <errno.h> // NOLINT | 11 #include <errno.h> // NOLINT |
12 #include <stdlib.h> // NOLINT | 12 #include <stdlib.h> // NOLINT |
13 #include <string.h> // NOLINT | 13 #include <string.h> // NOLINT |
14 #include <sys/param.h> // NOLINT | 14 #include <sys/param.h> // NOLINT |
15 #include <sys/stat.h> // NOLINT | 15 #include <sys/stat.h> // NOLINT |
16 #include <unistd.h> // NOLINT | 16 #include <unistd.h> // NOLINT |
17 | 17 |
18 #include "bin/dartutils.h" | 18 #include "bin/dartutils.h" |
19 #include "bin/file.h" | 19 #include "bin/file.h" |
20 #include "bin/platform.h" | 20 #include "bin/platform.h" |
21 #include "platform/signal_blocker.h" | 21 #include "platform/signal_blocker.h" |
22 | 22 |
23 namespace dart { | 23 namespace dart { |
24 namespace bin { | 24 namespace bin { |
25 | 25 |
26 PathBuffer::PathBuffer() : length_(0) { | 26 PathBuffer::PathBuffer() : length_(0) { |
27 data_ = calloc(PATH_MAX + 1, sizeof(char)); // NOLINT | 27 data_ = calloc(PATH_MAX + 1, sizeof(char)); // NOLINT |
28 } | 28 } |
29 | 29 |
30 | |
31 PathBuffer::~PathBuffer() { | 30 PathBuffer::~PathBuffer() { |
32 free(data_); | 31 free(data_); |
33 } | 32 } |
34 | 33 |
35 | |
36 bool PathBuffer::AddW(const wchar_t* name) { | 34 bool PathBuffer::AddW(const wchar_t* name) { |
37 UNREACHABLE(); | 35 UNREACHABLE(); |
38 return false; | 36 return false; |
39 } | 37 } |
40 | 38 |
41 | |
42 char* PathBuffer::AsString() const { | 39 char* PathBuffer::AsString() const { |
43 return reinterpret_cast<char*>(data_); | 40 return reinterpret_cast<char*>(data_); |
44 } | 41 } |
45 | 42 |
46 | |
47 wchar_t* PathBuffer::AsStringW() const { | 43 wchar_t* PathBuffer::AsStringW() const { |
48 UNREACHABLE(); | 44 UNREACHABLE(); |
49 return NULL; | 45 return NULL; |
50 } | 46 } |
51 | 47 |
52 | |
53 const char* PathBuffer::AsScopedString() const { | 48 const char* PathBuffer::AsScopedString() const { |
54 return DartUtils::ScopedCopyCString(AsString()); | 49 return DartUtils::ScopedCopyCString(AsString()); |
55 } | 50 } |
56 | 51 |
57 | |
58 bool PathBuffer::Add(const char* name) { | 52 bool PathBuffer::Add(const char* name) { |
59 const intptr_t name_length = strnlen(name, PATH_MAX + 1); | 53 const intptr_t name_length = strnlen(name, PATH_MAX + 1); |
60 if (name_length == 0) { | 54 if (name_length == 0) { |
61 errno = EINVAL; | 55 errno = EINVAL; |
62 return false; | 56 return false; |
63 } | 57 } |
64 char* data = AsString(); | 58 char* data = AsString(); |
65 int written = snprintf(data + length_, PATH_MAX - length_, "%s", name); | 59 int written = snprintf(data + length_, PATH_MAX - length_, "%s", name); |
66 data[PATH_MAX] = '\0'; | 60 data[PATH_MAX] = '\0'; |
67 if ((written <= (PATH_MAX - length_)) && (written > 0) && | 61 if ((written <= (PATH_MAX - length_)) && (written > 0) && |
68 (static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1))) { | 62 (static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1))) { |
69 length_ += written; | 63 length_ += written; |
70 return true; | 64 return true; |
71 } else { | 65 } else { |
72 errno = ENAMETOOLONG; | 66 errno = ENAMETOOLONG; |
73 return false; | 67 return false; |
74 } | 68 } |
75 } | 69 } |
76 | 70 |
77 | |
78 void PathBuffer::Reset(intptr_t new_length) { | 71 void PathBuffer::Reset(intptr_t new_length) { |
79 length_ = new_length; | 72 length_ = new_length; |
80 AsString()[length_] = '\0'; | 73 AsString()[length_] = '\0'; |
81 } | 74 } |
82 | 75 |
83 | |
84 // A linked list of symbolic links, with their unique file system identifiers. | 76 // A linked list of symbolic links, with their unique file system identifiers. |
85 // These are scanned to detect loops while doing a recursive directory listing. | 77 // These are scanned to detect loops while doing a recursive directory listing. |
86 struct LinkList { | 78 struct LinkList { |
87 dev_t dev; | 79 dev_t dev; |
88 ino64_t ino; | 80 ino64_t ino; |
89 LinkList* next; | 81 LinkList* next; |
90 }; | 82 }; |
91 | 83 |
92 | |
93 ListType DirectoryListingEntry::Next(DirectoryListing* listing) { | 84 ListType DirectoryListingEntry::Next(DirectoryListing* listing) { |
94 if (done_) { | 85 if (done_) { |
95 return kListDone; | 86 return kListDone; |
96 } | 87 } |
97 | 88 |
98 if (lister_ == 0) { | 89 if (lister_ == 0) { |
99 lister_ = | 90 lister_ = |
100 reinterpret_cast<intptr_t>(opendir(listing->path_buffer().AsString())); | 91 reinterpret_cast<intptr_t>(opendir(listing->path_buffer().AsString())); |
101 if (lister_ == 0) { | 92 if (lister_ == 0) { |
102 perror("opendir failed: "); | 93 perror("opendir failed: "); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 } | 173 } |
183 done_ = true; | 174 done_ = true; |
184 | 175 |
185 if (errno != 0) { | 176 if (errno != 0) { |
186 return kListError; | 177 return kListError; |
187 } | 178 } |
188 | 179 |
189 return kListDone; | 180 return kListDone; |
190 } | 181 } |
191 | 182 |
192 | |
193 DirectoryListingEntry::~DirectoryListingEntry() { | 183 DirectoryListingEntry::~DirectoryListingEntry() { |
194 ResetLink(); | 184 ResetLink(); |
195 if (lister_ != 0) { | 185 if (lister_ != 0) { |
196 VOID_NO_RETRY_EXPECTED(closedir(reinterpret_cast<DIR*>(lister_))); | 186 VOID_NO_RETRY_EXPECTED(closedir(reinterpret_cast<DIR*>(lister_))); |
197 } | 187 } |
198 } | 188 } |
199 | 189 |
200 | |
201 void DirectoryListingEntry::ResetLink() { | 190 void DirectoryListingEntry::ResetLink() { |
202 if ((link_ != NULL) && ((parent_ == NULL) || (parent_->link_ != link_))) { | 191 if ((link_ != NULL) && ((parent_ == NULL) || (parent_->link_ != link_))) { |
203 delete link_; | 192 delete link_; |
204 link_ = NULL; | 193 link_ = NULL; |
205 } | 194 } |
206 if (parent_ != NULL) { | 195 if (parent_ != NULL) { |
207 link_ = parent_->link_; | 196 link_ = parent_->link_; |
208 } | 197 } |
209 } | 198 } |
210 | 199 |
211 | |
212 Directory::ExistsResult Directory::Exists(const char* dir_name) { | 200 Directory::ExistsResult Directory::Exists(const char* dir_name) { |
213 struct stat entry_info; | 201 struct stat entry_info; |
214 int success = NO_RETRY_EXPECTED(stat(dir_name, &entry_info)); | 202 int success = NO_RETRY_EXPECTED(stat(dir_name, &entry_info)); |
215 if (success == 0) { | 203 if (success == 0) { |
216 if (S_ISDIR(entry_info.st_mode)) { | 204 if (S_ISDIR(entry_info.st_mode)) { |
217 return EXISTS; | 205 return EXISTS; |
218 } else { | 206 } else { |
219 // An OSError may be constructed based on the return value of this | 207 // An OSError may be constructed based on the return value of this |
220 // function, so set errno to something that makes sense. | 208 // function, so set errno to something that makes sense. |
221 errno = ENOTDIR; | 209 errno = ENOTDIR; |
222 return DOES_NOT_EXIST; | 210 return DOES_NOT_EXIST; |
223 } | 211 } |
224 } else { | 212 } else { |
225 if ((errno == EACCES) || (errno == EBADF) || (errno == EFAULT) || | 213 if ((errno == EACCES) || (errno == EBADF) || (errno == EFAULT) || |
226 (errno == ENOMEM) || (errno == EOVERFLOW)) { | 214 (errno == ENOMEM) || (errno == EOVERFLOW)) { |
227 // Search permissions denied for one of the directories in the | 215 // Search permissions denied for one of the directories in the |
228 // path or a low level error occured. We do not know if the | 216 // path or a low level error occured. We do not know if the |
229 // directory exists. | 217 // directory exists. |
230 return UNKNOWN; | 218 return UNKNOWN; |
231 } | 219 } |
232 ASSERT((errno == ELOOP) || (errno == ENAMETOOLONG) || (errno == ENOENT) || | 220 ASSERT((errno == ELOOP) || (errno == ENAMETOOLONG) || (errno == ENOENT) || |
233 (errno == ENOTDIR)); | 221 (errno == ENOTDIR)); |
234 return DOES_NOT_EXIST; | 222 return DOES_NOT_EXIST; |
235 } | 223 } |
236 } | 224 } |
237 | 225 |
238 | |
239 char* Directory::CurrentNoScope() { | 226 char* Directory::CurrentNoScope() { |
240 return getcwd(NULL, 0); | 227 return getcwd(NULL, 0); |
241 } | 228 } |
242 | 229 |
243 | |
244 const char* Directory::Current() { | 230 const char* Directory::Current() { |
245 char buffer[PATH_MAX]; | 231 char buffer[PATH_MAX]; |
246 if (getcwd(buffer, PATH_MAX) == NULL) { | 232 if (getcwd(buffer, PATH_MAX) == NULL) { |
247 return NULL; | 233 return NULL; |
248 } | 234 } |
249 return DartUtils::ScopedCopyCString(buffer); | 235 return DartUtils::ScopedCopyCString(buffer); |
250 } | 236 } |
251 | 237 |
252 | |
253 bool Directory::SetCurrent(const char* path) { | 238 bool Directory::SetCurrent(const char* path) { |
254 return (NO_RETRY_EXPECTED(chdir(path)) == 0); | 239 return (NO_RETRY_EXPECTED(chdir(path)) == 0); |
255 } | 240 } |
256 | 241 |
257 | |
258 bool Directory::Create(const char* dir_name) { | 242 bool Directory::Create(const char* dir_name) { |
259 // Create the directory with the permissions specified by the | 243 // Create the directory with the permissions specified by the |
260 // process umask. | 244 // process umask. |
261 int result = NO_RETRY_EXPECTED(mkdir(dir_name, 0777)); | 245 int result = NO_RETRY_EXPECTED(mkdir(dir_name, 0777)); |
262 // If the directory already exists, treat it as a success. | 246 // If the directory already exists, treat it as a success. |
263 if ((result == -1) && (errno == EEXIST)) { | 247 if ((result == -1) && (errno == EEXIST)) { |
264 return (Exists(dir_name) == EXISTS); | 248 return (Exists(dir_name) == EXISTS); |
265 } | 249 } |
266 return (result == 0); | 250 return (result == 0); |
267 } | 251 } |
268 | 252 |
269 | |
270 const char* Directory::SystemTemp() { | 253 const char* Directory::SystemTemp() { |
271 PathBuffer path; | 254 PathBuffer path; |
272 const char* temp_dir = getenv("TMPDIR"); | 255 const char* temp_dir = getenv("TMPDIR"); |
273 if (temp_dir == NULL) { | 256 if (temp_dir == NULL) { |
274 temp_dir = getenv("TMP"); | 257 temp_dir = getenv("TMP"); |
275 } | 258 } |
276 if (temp_dir == NULL) { | 259 if (temp_dir == NULL) { |
277 temp_dir = "/tmp"; | 260 temp_dir = "/tmp"; |
278 } | 261 } |
279 if (!path.Add(temp_dir)) { | 262 if (!path.Add(temp_dir)) { |
280 return NULL; | 263 return NULL; |
281 } | 264 } |
282 | 265 |
283 // Remove any trailing slash. | 266 // Remove any trailing slash. |
284 char* result = path.AsString(); | 267 char* result = path.AsString(); |
285 int length = strlen(result); | 268 int length = strlen(result); |
286 if ((length > 1) && (result[length - 1] == '/')) { | 269 if ((length > 1) && (result[length - 1] == '/')) { |
287 result[length - 1] = '\0'; | 270 result[length - 1] = '\0'; |
288 } | 271 } |
289 return path.AsScopedString(); | 272 return path.AsScopedString(); |
290 } | 273 } |
291 | 274 |
292 | |
293 const char* Directory::CreateTemp(const char* prefix) { | 275 const char* Directory::CreateTemp(const char* prefix) { |
294 // Returns a new, unused directory name, adding characters to the end | 276 // Returns a new, unused directory name, adding characters to the end |
295 // of prefix. Creates the directory with the permissions specified | 277 // of prefix. Creates the directory with the permissions specified |
296 // by the process umask. | 278 // by the process umask. |
297 // The return value is Dart_ScopeAllocated. | 279 // The return value is Dart_ScopeAllocated. |
298 PathBuffer path; | 280 PathBuffer path; |
299 if (!path.Add(prefix)) { | 281 if (!path.Add(prefix)) { |
300 return NULL; | 282 return NULL; |
301 } | 283 } |
302 if (!path.Add("XXXXXX")) { | 284 if (!path.Add("XXXXXX")) { |
303 // Pattern has overflowed. | 285 // Pattern has overflowed. |
304 return NULL; | 286 return NULL; |
305 } | 287 } |
306 char* result = mkdtemp(path.AsString()); | 288 char* result = mkdtemp(path.AsString()); |
307 if (result == NULL) { | 289 if (result == NULL) { |
308 return NULL; | 290 return NULL; |
309 } | 291 } |
310 return path.AsScopedString(); | 292 return path.AsScopedString(); |
311 } | 293 } |
312 | 294 |
313 | |
314 static bool DeleteRecursively(PathBuffer* path); | 295 static bool DeleteRecursively(PathBuffer* path); |
315 | 296 |
316 | |
317 static bool DeleteFile(char* file_name, PathBuffer* path) { | 297 static bool DeleteFile(char* file_name, PathBuffer* path) { |
318 return path->Add(file_name) && | 298 return path->Add(file_name) && |
319 (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0); | 299 (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0); |
320 } | 300 } |
321 | 301 |
322 | |
323 static bool DeleteDir(char* dir_name, PathBuffer* path) { | 302 static bool DeleteDir(char* dir_name, PathBuffer* path) { |
324 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) { | 303 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) { |
325 return true; | 304 return true; |
326 } | 305 } |
327 return path->Add(dir_name) && DeleteRecursively(path); | 306 return path->Add(dir_name) && DeleteRecursively(path); |
328 } | 307 } |
329 | 308 |
330 | |
331 static bool DeleteRecursively(PathBuffer* path) { | 309 static bool DeleteRecursively(PathBuffer* path) { |
332 // Do not recurse into links for deletion. Instead delete the link. | 310 // Do not recurse into links for deletion. Instead delete the link. |
333 // If it's a file, delete it. | 311 // If it's a file, delete it. |
334 struct stat64 st; | 312 struct stat64 st; |
335 if (NO_RETRY_EXPECTED(lstat64(path->AsString(), &st)) == -1) { | 313 if (NO_RETRY_EXPECTED(lstat64(path->AsString(), &st)) == -1) { |
336 return false; | 314 return false; |
337 } else if (!S_ISDIR(st.st_mode)) { | 315 } else if (!S_ISDIR(st.st_mode)) { |
338 return NO_RETRY_EXPECTED(unlink(path->AsString())) == 0; | 316 return NO_RETRY_EXPECTED(unlink(path->AsString())) == 0; |
339 } | 317 } |
340 | 318 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 path->Reset(path_length); | 373 path->Reset(path_length); |
396 } | 374 } |
397 // Only happens if there was an error. | 375 // Only happens if there was an error. |
398 ASSERT(errno != 0); | 376 ASSERT(errno != 0); |
399 int err = errno; | 377 int err = errno; |
400 VOID_NO_RETRY_EXPECTED(closedir(dir_pointer)); | 378 VOID_NO_RETRY_EXPECTED(closedir(dir_pointer)); |
401 errno = err; | 379 errno = err; |
402 return false; | 380 return false; |
403 } | 381 } |
404 | 382 |
405 | |
406 bool Directory::Delete(const char* dir_name, bool recursive) { | 383 bool Directory::Delete(const char* dir_name, bool recursive) { |
407 if (!recursive) { | 384 if (!recursive) { |
408 if ((File::GetType(dir_name, false) == File::kIsLink) && | 385 if ((File::GetType(dir_name, false) == File::kIsLink) && |
409 (File::GetType(dir_name, true) == File::kIsDirectory)) { | 386 (File::GetType(dir_name, true) == File::kIsDirectory)) { |
410 return NO_RETRY_EXPECTED(unlink(dir_name)) == 0; | 387 return NO_RETRY_EXPECTED(unlink(dir_name)) == 0; |
411 } | 388 } |
412 return NO_RETRY_EXPECTED(rmdir(dir_name)) == 0; | 389 return NO_RETRY_EXPECTED(rmdir(dir_name)) == 0; |
413 } else { | 390 } else { |
414 PathBuffer path; | 391 PathBuffer path; |
415 if (!path.Add(dir_name)) { | 392 if (!path.Add(dir_name)) { |
416 return false; | 393 return false; |
417 } | 394 } |
418 return DeleteRecursively(&path); | 395 return DeleteRecursively(&path); |
419 } | 396 } |
420 } | 397 } |
421 | 398 |
422 | |
423 bool Directory::Rename(const char* path, const char* new_path) { | 399 bool Directory::Rename(const char* path, const char* new_path) { |
424 ExistsResult exists = Exists(path); | 400 ExistsResult exists = Exists(path); |
425 if (exists != EXISTS) { | 401 if (exists != EXISTS) { |
426 return false; | 402 return false; |
427 } | 403 } |
428 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); | 404 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); |
429 } | 405 } |
430 | 406 |
431 } // namespace bin | 407 } // namespace bin |
432 } // namespace dart | 408 } // namespace dart |
433 | 409 |
434 #endif // defined(HOST_OS_FUCHSIA) | 410 #endif // defined(HOST_OS_FUCHSIA) |
OLD | NEW |