Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: runtime/bin/directory_linux.cc

Issue 3007703002: [dart:io] Namespaces for file IO (Closed)
Patch Set: Remove namespace_unsupported.cc Created 3 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/bin/directory_fuchsia.cc ('k') | runtime/bin/directory_macos.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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_LINUX) 6 #if defined(HOST_OS_LINUX)
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 <fcntl.h> // NOLINT
12 #include <stdlib.h> // NOLINT 13 #include <stdlib.h> // NOLINT
13 #include <string.h> // NOLINT 14 #include <string.h> // NOLINT
14 #include <sys/param.h> // NOLINT 15 #include <sys/param.h> // NOLINT
15 #include <sys/stat.h> // NOLINT 16 #include <sys/stat.h> // NOLINT
16 #include <unistd.h> // NOLINT 17 #include <unistd.h> // NOLINT
17 18
19 #include "bin/crypto.h"
18 #include "bin/dartutils.h" 20 #include "bin/dartutils.h"
21 #include "bin/fdutils.h"
19 #include "bin/file.h" 22 #include "bin/file.h"
23 #include "bin/namespace.h"
20 #include "bin/platform.h" 24 #include "bin/platform.h"
21 #include "platform/signal_blocker.h" 25 #include "platform/signal_blocker.h"
22 26
23 namespace dart { 27 namespace dart {
24 namespace bin { 28 namespace bin {
25 29
26 PathBuffer::PathBuffer() : length_(0) { 30 PathBuffer::PathBuffer() : length_(0) {
27 data_ = calloc(PATH_MAX + 1, sizeof(char)); // NOLINT 31 data_ = calloc(PATH_MAX + 1, sizeof(char)); // NOLINT
28 } 32 }
29 33
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 dev_t dev; 78 dev_t dev;
75 ino64_t ino; 79 ino64_t ino;
76 LinkList* next; 80 LinkList* next;
77 }; 81 };
78 82
79 ListType DirectoryListingEntry::Next(DirectoryListing* listing) { 83 ListType DirectoryListingEntry::Next(DirectoryListing* listing) {
80 if (done_) { 84 if (done_) {
81 return kListDone; 85 return kListDone;
82 } 86 }
83 87
88 if (fd_ == -1) {
89 ASSERT(lister_ == 0);
90 NamespaceScope ns(listing->namespc(), listing->path_buffer().AsString());
91 const int listingfd =
92 TEMP_FAILURE_RETRY(openat64(ns.fd(), ns.path(), O_DIRECTORY));
93 if (listingfd < 0) {
94 done_ = true;
95 return kListError;
96 }
97 fd_ = listingfd;
98 }
99
84 if (lister_ == 0) { 100 if (lister_ == 0) {
85 do { 101 do {
86 lister_ = reinterpret_cast<intptr_t>( 102 lister_ = reinterpret_cast<intptr_t>(fdopendir(fd_));
87 opendir(listing->path_buffer().AsString()));
88 } while ((lister_ == 0) && (errno == EINTR)); 103 } while ((lister_ == 0) && (errno == EINTR));
89
90 if (lister_ == 0) { 104 if (lister_ == 0) {
91 done_ = true; 105 done_ = true;
92 return kListError; 106 return kListError;
93 } 107 }
94 if (parent_ != NULL) { 108 if (parent_ != NULL) {
95 if (!listing->path_buffer().Add(File::PathSeparator())) { 109 if (!listing->path_buffer().Add(File::PathSeparator())) {
96 return kListError; 110 return kListError;
97 } 111 }
98 } 112 }
99 path_length_ = listing->path_buffer().length(); 113 path_length_ = listing->path_buffer().length();
(...skipping 28 matching lines...) Expand all
128 if (!listing->follow_links()) { 142 if (!listing->follow_links()) {
129 return kListLink; 143 return kListLink;
130 } 144 }
131 // Else fall through to next case. 145 // Else fall through to next case.
132 // Fall through. 146 // Fall through.
133 case DT_UNKNOWN: { 147 case DT_UNKNOWN: {
134 // On some file systems the entry type is not determined by 148 // On some file systems the entry type is not determined by
135 // readdir. For those and for links we use stat to determine 149 // readdir. For those and for links we use stat to determine
136 // the actual entry type. Notice that stat returns the type of 150 // the actual entry type. Notice that stat returns the type of
137 // the file pointed to. 151 // the file pointed to.
152 NamespaceScope ns(listing->namespc(),
153 listing->path_buffer().AsString());
138 struct stat64 entry_info; 154 struct stat64 entry_info;
139 int stat_success; 155 int stat_success;
140 stat_success = TEMP_FAILURE_RETRY( 156 stat_success = TEMP_FAILURE_RETRY(
141 lstat64(listing->path_buffer().AsString(), &entry_info)); 157 fstatat64(ns.fd(), ns.path(), &entry_info, AT_SYMLINK_NOFOLLOW));
142 if (stat_success == -1) { 158 if (stat_success == -1) {
143 return kListError; 159 return kListError;
144 } 160 }
145 if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) { 161 if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) {
146 // Check to see if we are in a loop created by a symbolic link. 162 // Check to see if we are in a loop created by a symbolic link.
147 LinkList current_link = {entry_info.st_dev, entry_info.st_ino, link_}; 163 LinkList current_link = {entry_info.st_dev, entry_info.st_ino, link_};
148 LinkList* previous = link_; 164 LinkList* previous = link_;
149 while (previous != NULL) { 165 while (previous != NULL) {
150 if ((previous->dev == current_link.dev) && 166 if ((previous->dev == current_link.dev) &&
151 (previous->ino == current_link.ino)) { 167 (previous->ino == current_link.ino)) {
152 // Report the looping link as a link, rather than following it. 168 // Report the looping link as a link, rather than following it.
153 return kListLink; 169 return kListLink;
154 } 170 }
155 previous = previous->next; 171 previous = previous->next;
156 } 172 }
157 stat_success = TEMP_FAILURE_RETRY( 173 stat_success =
158 stat64(listing->path_buffer().AsString(), &entry_info)); 174 TEMP_FAILURE_RETRY(fstatat64(ns.fd(), ns.path(), &entry_info, 0));
159 if (stat_success == -1) { 175 if (stat_success == -1) {
160 // Report a broken link as a link, even if follow_links is true. 176 // Report a broken link as a link, even if follow_links is true.
161 return kListLink; 177 return kListLink;
162 } 178 }
163 if (S_ISDIR(entry_info.st_mode)) { 179 if (S_ISDIR(entry_info.st_mode)) {
164 // Recurse into the subdirectory with current_link added to the 180 // Recurse into the subdirectory with current_link added to the
165 // linked list of seen file system links. 181 // linked list of seen file system links.
166 link_ = new LinkList(current_link); 182 link_ = new LinkList(current_link);
167 if ((strcmp(entry->d_name, ".") == 0) || 183 if ((strcmp(entry->d_name, ".") == 0) ||
168 (strcmp(entry->d_name, "..") == 0)) { 184 (strcmp(entry->d_name, "..") == 0)) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 if (errno != 0) { 217 if (errno != 0) {
202 return kListError; 218 return kListError;
203 } 219 }
204 220
205 return kListDone; 221 return kListDone;
206 } 222 }
207 223
208 DirectoryListingEntry::~DirectoryListingEntry() { 224 DirectoryListingEntry::~DirectoryListingEntry() {
209 ResetLink(); 225 ResetLink();
210 if (lister_ != 0) { 226 if (lister_ != 0) {
227 // This also closes fd_.
211 VOID_NO_RETRY_EXPECTED(closedir(reinterpret_cast<DIR*>(lister_))); 228 VOID_NO_RETRY_EXPECTED(closedir(reinterpret_cast<DIR*>(lister_)));
212 } 229 }
213 } 230 }
214 231
215 void DirectoryListingEntry::ResetLink() { 232 void DirectoryListingEntry::ResetLink() {
216 if ((link_ != NULL) && ((parent_ == NULL) || (parent_->link_ != link_))) { 233 if ((link_ != NULL) && ((parent_ == NULL) || (parent_->link_ != link_))) {
217 delete link_; 234 delete link_;
218 link_ = NULL; 235 link_ = NULL;
219 } 236 }
220 if (parent_ != NULL) { 237 if (parent_ != NULL) {
221 link_ = parent_->link_; 238 link_ = parent_->link_;
222 } 239 }
223 } 240 }
224 241
225 static bool DeleteRecursively(PathBuffer* path); 242 static bool DeleteRecursively(int dirfd, PathBuffer* path);
226 243
227 static bool DeleteFile(char* file_name, PathBuffer* path) { 244 static bool DeleteFile(int dirfd, char* file_name, PathBuffer* path) {
228 return path->Add(file_name) && 245 return path->Add(file_name) &&
229 (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0); 246 (NO_RETRY_EXPECTED(unlinkat(dirfd, path->AsString(), 0)) == 0);
230 } 247 }
231 248
232 static bool DeleteDir(char* dir_name, PathBuffer* path) { 249 static bool DeleteDir(int dirfd, char* dir_name, PathBuffer* path) {
233 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) { 250 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) {
234 return true; 251 return true;
235 } 252 }
236 return path->Add(dir_name) && DeleteRecursively(path); 253 return path->Add(dir_name) && DeleteRecursively(dirfd, path);
237 } 254 }
238 255
239 static bool DeleteRecursively(PathBuffer* path) { 256 static bool DeleteRecursively(int dirfd, PathBuffer* path) {
240 // Do not recurse into links for deletion. Instead delete the link. 257 // Do not recurse into links for deletion. Instead delete the link.
241 // If it's a file, delete it. 258 // If it's a file, delete it.
242 struct stat64 st; 259 struct stat64 st;
243 if (TEMP_FAILURE_RETRY(lstat64(path->AsString(), &st)) == -1) { 260 if (TEMP_FAILURE_RETRY(
261 fstatat64(dirfd, path->AsString(), &st, AT_SYMLINK_NOFOLLOW)) == -1) {
244 return false; 262 return false;
245 } else if (!S_ISDIR(st.st_mode)) { 263 } else if (!S_ISDIR(st.st_mode)) {
246 return (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0); 264 return (NO_RETRY_EXPECTED(unlinkat(dirfd, path->AsString(), 0)) == 0);
247 } 265 }
248 266
249 if (!path->Add(File::PathSeparator())) { 267 if (!path->Add(File::PathSeparator())) {
250 return false; 268 return false;
251 } 269 }
252 270
253 // Not a link. Attempt to open as a directory and recurse into the 271 // Not a link. Attempt to open as a directory and recurse into the
254 // directory. 272 // directory.
273 const int fd =
274 TEMP_FAILURE_RETRY(openat64(dirfd, path->AsString(), O_DIRECTORY));
275 if (fd < 0) {
276 return false;
277 }
255 DIR* dir_pointer; 278 DIR* dir_pointer;
256 do { 279 do {
257 dir_pointer = opendir(path->AsString()); 280 dir_pointer = fdopendir(fd);
258 } while ((dir_pointer == NULL) && (errno == EINTR)); 281 } while ((dir_pointer == NULL) && (errno == EINTR));
259 if (dir_pointer == NULL) { 282 if (dir_pointer == NULL) {
283 FDUtils::SaveErrorAndClose(fd);
260 return false; 284 return false;
261 } 285 }
262 286
263 // Iterate the directory and delete all files and directories. 287 // Iterate the directory and delete all files and directories.
264 int path_length = path->length(); 288 int path_length = path->length();
265 while (true) { 289 while (true) {
266 // In case `readdir()` returns `NULL` we distinguish between end-of-stream 290 // In case `readdir()` returns `NULL` we distinguish between end-of-stream
267 // and error by looking if `errno` was updated. 291 // and error by looking if `errno` was updated.
268 errno = 0; 292 errno = 0;
269 // In glibc 2.24+, readdir_r is deprecated. 293 // In glibc 2.24+, readdir_r is deprecated.
270 // According to the man page for readdir: 294 // According to the man page for readdir:
271 // "readdir(3) is not required to be thread-safe. However, in modern 295 // "readdir(3) is not required to be thread-safe. However, in modern
272 // implementations (including the glibc implementation), concurrent calls to 296 // implementations (including the glibc implementation), concurrent calls to
273 // readdir(3) that specify different directory streams are thread-safe." 297 // readdir(3) that specify different directory streams are thread-safe."
274 dirent* entry = readdir(dir_pointer); 298 dirent* entry = readdir(dir_pointer);
275 if (entry == NULL) { 299 if (entry == NULL) {
276 // Failed to read next directory entry. 300 // Failed to read next directory entry.
277 if (errno != 0) { 301 if (errno != 0) {
278 break; 302 break;
279 } 303 }
280 // End of directory. 304 // End of directory.
281 return (NO_RETRY_EXPECTED(closedir(dir_pointer)) == 0) && 305 int status = NO_RETRY_EXPECTED(closedir(dir_pointer));
282 (NO_RETRY_EXPECTED(remove(path->AsString())) == 0); 306 FDUtils::SaveErrorAndClose(fd);
307 if (status != 0) {
308 return false;
309 }
310 status =
311 NO_RETRY_EXPECTED(unlinkat(dirfd, path->AsString(), AT_REMOVEDIR));
312 return status == 0;
283 } 313 }
284 bool ok = false; 314 bool ok = false;
285 switch (entry->d_type) { 315 switch (entry->d_type) {
286 case DT_DIR: 316 case DT_DIR:
287 ok = DeleteDir(entry->d_name, path); 317 ok = DeleteDir(dirfd, entry->d_name, path);
288 break; 318 break;
289 case DT_BLK: 319 case DT_BLK:
290 case DT_CHR: 320 case DT_CHR:
291 case DT_FIFO: 321 case DT_FIFO:
292 case DT_SOCK: 322 case DT_SOCK:
293 case DT_REG: 323 case DT_REG:
294 case DT_LNK: 324 case DT_LNK:
295 // Treat all links as files. This will delete the link which 325 // Treat all links as files. This will delete the link which
296 // is what we want no matter if the link target is a file or a 326 // is what we want no matter if the link target is a file or a
297 // directory. 327 // directory.
298 ok = DeleteFile(entry->d_name, path); 328 ok = DeleteFile(dirfd, entry->d_name, path);
299 break; 329 break;
300 case DT_UNKNOWN: { 330 case DT_UNKNOWN: {
301 if (!path->Add(entry->d_name)) { 331 if (!path->Add(entry->d_name)) {
302 break; 332 break;
303 } 333 }
304 // On some file systems the entry type is not determined by 334 // On some file systems the entry type is not determined by
305 // readdir. For those we use lstat to determine the entry 335 // readdir. For those we use lstat to determine the entry
306 // type. 336 // type.
307 struct stat64 entry_info; 337 struct stat64 entry_info;
308 if (TEMP_FAILURE_RETRY(lstat64(path->AsString(), &entry_info)) == -1) { 338 if (TEMP_FAILURE_RETRY(fstatat64(dirfd, path->AsString(), &entry_info,
339 AT_SYMLINK_NOFOLLOW)) == -1) {
309 break; 340 break;
310 } 341 }
311 path->Reset(path_length); 342 path->Reset(path_length);
312 if (S_ISDIR(entry_info.st_mode)) { 343 if (S_ISDIR(entry_info.st_mode)) {
313 ok = DeleteDir(entry->d_name, path); 344 ok = DeleteDir(dirfd, entry->d_name, path);
314 } else { 345 } else {
315 // Treat links as files. This will delete the link which is 346 // Treat links as files. This will delete the link which is
316 // what we want no matter if the link target is a file or a 347 // what we want no matter if the link target is a file or a
317 // directory. 348 // directory.
318 ok = DeleteFile(entry->d_name, path); 349 ok = DeleteFile(dirfd, entry->d_name, path);
319 } 350 }
320 break; 351 break;
321 } 352 }
322 default: 353 default:
323 // We should have covered all the bases. If not, let's get an error. 354 // We should have covered all the bases. If not, let's get an error.
324 FATAL1("Unexpected d_type: %d\n", entry->d_type); 355 FATAL1("Unexpected d_type: %d\n", entry->d_type);
325 break; 356 break;
326 } 357 }
327 if (!ok) { 358 if (!ok) {
328 break; 359 break;
329 } 360 }
330 path->Reset(path_length); 361 path->Reset(path_length);
331 } 362 }
332 // Only happens if an error. 363 // Only happens if an error.
333 ASSERT(errno != 0); 364 ASSERT(errno != 0);
334 int err = errno; 365 int err = errno;
335 VOID_NO_RETRY_EXPECTED(closedir(dir_pointer)); 366 VOID_NO_RETRY_EXPECTED(closedir(dir_pointer));
367 FDUtils::SaveErrorAndClose(fd);
336 errno = err; 368 errno = err;
337 return false; 369 return false;
338 } 370 }
339 371
340 Directory::ExistsResult Directory::Exists(const char* dir_name) { 372 Directory::ExistsResult Directory::Exists(Namespace* namespc,
373 const char* dir_name) {
374 NamespaceScope ns(namespc, dir_name);
341 struct stat64 entry_info; 375 struct stat64 entry_info;
342 int success = TEMP_FAILURE_RETRY(stat64(dir_name, &entry_info)); 376 int success =
377 TEMP_FAILURE_RETRY(fstatat64(ns.fd(), ns.path(), &entry_info, 0));
343 if (success == 0) { 378 if (success == 0) {
344 if (S_ISDIR(entry_info.st_mode)) { 379 if (S_ISDIR(entry_info.st_mode)) {
345 return EXISTS; 380 return EXISTS;
346 } else { 381 } else {
347 // An OSError may be constructed based on the return value of this 382 // An OSError may be constructed based on the return value of this
348 // function, so set errno to something that makes sense. 383 // function, so set errno to something that makes sense.
349 errno = ENOTDIR; 384 errno = ENOTDIR;
350 return DOES_NOT_EXIST; 385 return DOES_NOT_EXIST;
351 } 386 }
352 } else { 387 } else {
353 if ((errno == EACCES) || (errno == EBADF) || (errno == EFAULT) || 388 if ((errno == EACCES) || (errno == EBADF) || (errno == EFAULT) ||
354 (errno == ENOMEM) || (errno == EOVERFLOW)) { 389 (errno == ENOMEM) || (errno == EOVERFLOW)) {
355 // Search permissions denied for one of the directories in the 390 // Search permissions denied for one of the directories in the
356 // path or a low level error occured. We do not know if the 391 // path or a low level error occured. We do not know if the
357 // directory exists. 392 // directory exists.
358 return UNKNOWN; 393 return UNKNOWN;
359 } 394 }
360 ASSERT((errno == ELOOP) || (errno == ENAMETOOLONG) || (errno == ENOENT) || 395 ASSERT((errno == ELOOP) || (errno == ENAMETOOLONG) || (errno == ENOENT) ||
361 (errno == ENOTDIR)); 396 (errno == ENOTDIR));
362 return DOES_NOT_EXIST; 397 return DOES_NOT_EXIST;
363 } 398 }
364 } 399 }
365 400
366 char* Directory::CurrentNoScope() { 401 char* Directory::CurrentNoScope() {
367 return getcwd(NULL, 0); 402 return getcwd(NULL, 0);
368 } 403 }
369 404
370 const char* Directory::Current() { 405 bool Directory::Create(Namespace* namespc, const char* dir_name) {
371 char buffer[PATH_MAX]; 406 NamespaceScope ns(namespc, dir_name);
372 if (getcwd(buffer, PATH_MAX) == NULL) {
373 return NULL;
374 }
375 return DartUtils::ScopedCopyCString(buffer);
376 }
377
378 bool Directory::SetCurrent(const char* path) {
379 return (NO_RETRY_EXPECTED(chdir(path)) == 0);
380 }
381
382 bool Directory::Create(const char* dir_name) {
383 // Create the directory with the permissions specified by the 407 // Create the directory with the permissions specified by the
384 // process umask. 408 // process umask.
385 int result = NO_RETRY_EXPECTED(mkdir(dir_name, 0777)); 409 const int result = NO_RETRY_EXPECTED(mkdirat(ns.fd(), ns.path(), 0777));
386 // If the directory already exists, treat it as a success. 410 // If the directory already exists, treat it as a success.
387 if ((result == -1) && (errno == EEXIST)) { 411 if ((result == -1) && (errno == EEXIST)) {
388 return (Exists(dir_name) == EXISTS); 412 return (Exists(namespc, dir_name) == EXISTS);
389 } 413 }
390 return (result == 0); 414 return (result == 0);
391 } 415 }
392 416
393 const char* Directory::SystemTemp() { 417 const char* Directory::SystemTemp(Namespace* namespc) {
394 PathBuffer path; 418 PathBuffer path;
395 const char* temp_dir = getenv("TMPDIR"); 419 const char* temp_dir = getenv("TMPDIR");
396 if (temp_dir == NULL) { 420 if (temp_dir == NULL) {
397 temp_dir = getenv("TMP"); 421 temp_dir = getenv("TMP");
398 } 422 }
399 if (temp_dir == NULL) { 423 if (temp_dir == NULL) {
400 temp_dir = "/tmp"; 424 temp_dir = "/tmp";
401 } 425 }
402 if (!path.Add(temp_dir)) { 426 NamespaceScope ns(namespc, temp_dir);
427 if (!path.Add(ns.path())) {
403 return NULL; 428 return NULL;
404 } 429 }
405 430
406 // Remove any trailing slash. 431 // Remove any trailing slash.
407 char* result = path.AsString(); 432 char* result = path.AsString();
408 int length = strlen(result); 433 int length = strlen(result);
409 if ((length > 1) && (result[length - 1] == '/')) { 434 if ((length > 1) && (result[length - 1] == '/')) {
410 result[length - 1] = '\0'; 435 result[length - 1] = '\0';
411 } 436 }
412 return path.AsScopedString(); 437 return path.AsScopedString();
413 } 438 }
414 439
415 const char* Directory::CreateTemp(const char* prefix) { 440 // Returns a new, unused directory name, adding characters to the end
416 // Returns a new, unused directory name, adding characters to the end 441 // of prefix. Creates the directory with the permissions specified
417 // of prefix. Creates the directory with the permissions specified 442 // by the process umask.
418 // by the process umask. 443 // The return value is Dart_ScopeAllocated.
419 // The return value is Dart_ScopeAllocated. 444 const char* Directory::CreateTemp(Namespace* namespc, const char* prefix) {
420 PathBuffer path; 445 PathBuffer path;
446 const int firstchar = 'A';
447 const int numchars = 'Z' - 'A' + 1;
448 uint8_t random_bytes[7];
449
450 // mkdtemp doesn't have an "at" variant, so we have to simulate it.
421 if (!path.Add(prefix)) { 451 if (!path.Add(prefix)) {
422 return NULL; 452 return NULL;
423 } 453 }
424 if (!path.Add("XXXXXX")) { 454 intptr_t prefix_length = path.length();
425 // Pattern has overflowed. 455 while (true) {
426 return NULL; 456 Crypto::GetRandomBytes(6, random_bytes);
427 } 457 for (intptr_t i = 0; i < 6; i++) {
428 char* result; 458 random_bytes[i] = (random_bytes[i] % numchars) + firstchar;
429 do {
430 result = mkdtemp(path.AsString());
431 } while ((result == NULL) && (errno == EINTR));
432 if (result == NULL) {
433 return NULL;
434 }
435 return path.AsScopedString();
436 }
437
438 bool Directory::Delete(const char* dir_name, bool recursive) {
439 if (!recursive) {
440 if ((File::GetType(dir_name, false) == File::kIsLink) &&
441 (File::GetType(dir_name, true) == File::kIsDirectory)) {
442 return NO_RETRY_EXPECTED(unlink(dir_name)) == 0;
443 } 459 }
444 return NO_RETRY_EXPECTED(rmdir(dir_name)) == 0; 460 random_bytes[6] = '\0';
445 } else { 461 if (!path.Add(reinterpret_cast<char*>(random_bytes))) {
446 PathBuffer path; 462 return NULL;
447 if (!path.Add(dir_name)) {
448 return false;
449 } 463 }
450 return DeleteRecursively(&path); 464 NamespaceScope ns(namespc, path.AsString());
465 const int result = NO_RETRY_EXPECTED(mkdirat(ns.fd(), ns.path(), 0777));
466 if (result == 0) {
467 return path.AsScopedString();
468 } else if (errno == EEXIST) {
469 path.Reset(prefix_length);
470 } else {
471 return NULL;
472 }
451 } 473 }
452 } 474 }
453 475
454 bool Directory::Rename(const char* path, const char* new_path) { 476 bool Directory::Delete(Namespace* namespc,
455 ExistsResult exists = Exists(path); 477 const char* dir_name,
478 bool recursive) {
479 NamespaceScope ns(namespc, dir_name);
480 if (!recursive) {
481 if ((File::GetType(namespc, dir_name, false) == File::kIsLink) &&
482 (File::GetType(namespc, dir_name, true) == File::kIsDirectory)) {
483 return NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0;
484 }
485 return NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), AT_REMOVEDIR)) == 0;
486 } else {
487 PathBuffer path;
488 if (!path.Add(ns.path())) {
489 return false;
490 }
491 return DeleteRecursively(ns.fd(), &path);
492 }
493 }
494
495 bool Directory::Rename(Namespace* namespc,
496 const char* old_path,
497 const char* new_path) {
498 ExistsResult exists = Exists(namespc, old_path);
456 if (exists != EXISTS) { 499 if (exists != EXISTS) {
457 return false; 500 return false;
458 } 501 }
459 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); 502 NamespaceScope oldns(namespc, old_path);
503 NamespaceScope newns(namespc, new_path);
504 return (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(),
505 newns.path())) == 0);
460 } 506 }
461 507
462 } // namespace bin 508 } // namespace bin
463 } // namespace dart 509 } // namespace dart
464 510
465 #endif // defined(HOST_OS_LINUX) 511 #endif // defined(HOST_OS_LINUX)
OLDNEW
« no previous file with comments | « runtime/bin/directory_fuchsia.cc ('k') | runtime/bin/directory_macos.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698