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

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

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

Powered by Google App Engine
This is Rietveld 408576698