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

Side by Side Diff: runtime/bin/directory_fuchsia.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_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 =
93 perror("opendir failed: "); 98 TEMP_FAILURE_RETRY(openat64(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(
163 fstatat64(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 =
180 TEMP_FAILURE_RETRY(fstatat64(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) {
233 // This also closes fd_.
186 VOID_NO_RETRY_EXPECTED(closedir(reinterpret_cast<DIR*>(lister_))); 234 VOID_NO_RETRY_EXPECTED(closedir(reinterpret_cast<DIR*>(lister_)));
187 } 235 }
188 } 236 }
189 237
190 void DirectoryListingEntry::ResetLink() { 238 void DirectoryListingEntry::ResetLink() {
191 if ((link_ != NULL) && ((parent_ == NULL) || (parent_->link_ != link_))) { 239 if ((link_ != NULL) && ((parent_ == NULL) || (parent_->link_ != link_))) {
192 delete link_; 240 delete link_;
193 link_ = NULL; 241 link_ = NULL;
194 } 242 }
195 if (parent_ != NULL) { 243 if (parent_ != NULL) {
196 link_ = parent_->link_; 244 link_ = parent_->link_;
197 } 245 }
198 } 246 }
199 247
200 Directory::ExistsResult Directory::Exists(const char* dir_name) { 248 Directory::ExistsResult Directory::Exists(Namespace* namespc,
201 struct stat entry_info; 249 const char* dir_name) {
202 int success = NO_RETRY_EXPECTED(stat(dir_name, &entry_info)); 250 NamespaceScope ns(namespc, dir_name);
251 struct stat64 entry_info;
252 const int success =
253 TEMP_FAILURE_RETRY(fstatat64(ns.fd(), ns.path(), &entry_info, 0));
203 if (success == 0) { 254 if (success == 0) {
204 if (S_ISDIR(entry_info.st_mode)) { 255 if (S_ISDIR(entry_info.st_mode)) {
205 return EXISTS; 256 return EXISTS;
206 } else { 257 } else {
207 // An OSError may be constructed based on the return value of this 258 // An OSError may be constructed based on the return value of this
208 // function, so set errno to something that makes sense. 259 // function, so set errno to something that makes sense.
209 errno = ENOTDIR; 260 errno = ENOTDIR;
210 return DOES_NOT_EXIST; 261 return DOES_NOT_EXIST;
211 } 262 }
212 } else { 263 } else {
213 if ((errno == EACCES) || (errno == EBADF) || (errno == EFAULT) || 264 if ((errno == EACCES) || (errno == EBADF) || (errno == EFAULT) ||
214 (errno == ENOMEM) || (errno == EOVERFLOW)) { 265 (errno == ENOMEM) || (errno == EOVERFLOW)) {
215 // Search permissions denied for one of the directories in the 266 // Search permissions denied for one of the directories in the
216 // path or a low level error occured. We do not know if the 267 // path or a low level error occured. We do not know if the
217 // directory exists. 268 // directory exists.
218 return UNKNOWN; 269 return UNKNOWN;
219 } 270 }
220 ASSERT((errno == ELOOP) || (errno == ENAMETOOLONG) || (errno == ENOENT) || 271 ASSERT((errno == ELOOP) || (errno == ENAMETOOLONG) || (errno == ENOENT) ||
221 (errno == ENOTDIR)); 272 (errno == ENOTDIR));
222 return DOES_NOT_EXIST; 273 return DOES_NOT_EXIST;
223 } 274 }
224 } 275 }
225 276
226 char* Directory::CurrentNoScope() { 277 char* Directory::CurrentNoScope() {
227 return getcwd(NULL, 0); 278 return getcwd(NULL, 0);
228 } 279 }
229 280
230 const char* Directory::Current() { 281 bool Directory::Create(Namespace* namespc, const char* dir_name) {
231 char buffer[PATH_MAX]; 282 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 283 // Create the directory with the permissions specified by the
244 // process umask. 284 // process umask.
245 int result = NO_RETRY_EXPECTED(mkdir(dir_name, 0777)); 285 const int result = NO_RETRY_EXPECTED(mkdirat(ns.fd(), ns.path(), 0777));
246 // If the directory already exists, treat it as a success. 286 // If the directory already exists, treat it as a success.
247 if ((result == -1) && (errno == EEXIST)) { 287 if ((result == -1) && (errno == EEXIST)) {
248 return (Exists(dir_name) == EXISTS); 288 return (Exists(namespc, dir_name) == EXISTS);
249 } 289 }
250 return (result == 0); 290 return (result == 0);
251 } 291 }
252 292
253 const char* Directory::SystemTemp() { 293 const char* Directory::SystemTemp(Namespace* namespc) {
254 PathBuffer path; 294 PathBuffer path;
255 const char* temp_dir = getenv("TMPDIR"); 295 const char* temp_dir = getenv("TMPDIR");
256 if (temp_dir == NULL) { 296 if (temp_dir == NULL) {
257 temp_dir = getenv("TMP"); 297 temp_dir = getenv("TMP");
258 } 298 }
259 if (temp_dir == NULL) { 299 if (temp_dir == NULL) {
260 temp_dir = "/tmp"; 300 temp_dir = "/tmp";
261 } 301 }
262 if (!path.Add(temp_dir)) { 302 NamespaceScope ns(namespc, temp_dir);
303 if (!path.Add(ns.path())) {
263 return NULL; 304 return NULL;
264 } 305 }
265 306
266 // Remove any trailing slash. 307 // Remove any trailing slash.
267 char* result = path.AsString(); 308 char* result = path.AsString();
268 int length = strlen(result); 309 int length = strlen(result);
269 if ((length > 1) && (result[length - 1] == '/')) { 310 if ((length > 1) && (result[length - 1] == '/')) {
270 result[length - 1] = '\0'; 311 result[length - 1] = '\0';
271 } 312 }
272 return path.AsScopedString(); 313 return path.AsScopedString();
273 } 314 }
274 315
275 const char* Directory::CreateTemp(const char* prefix) { 316 // Returns a new, unused directory name, adding characters to the end
276 // Returns a new, unused directory name, adding characters to the end 317 // of prefix. Creates the directory with the permissions specified
277 // of prefix. Creates the directory with the permissions specified 318 // by the process umask.
278 // by the process umask. 319 // The return value is Dart_ScopeAllocated.
279 // The return value is Dart_ScopeAllocated. 320 const char* Directory::CreateTemp(Namespace* namespc, const char* prefix) {
280 PathBuffer path; 321 PathBuffer path;
322 const int firstchar = 'A';
323 const int numchars = 'Z' - 'A' + 1;
324 uint8_t random_bytes[7];
325
326 // mkdtemp doesn't have an "at" variant, so we have to simulate it.
281 if (!path.Add(prefix)) { 327 if (!path.Add(prefix)) {
282 return NULL; 328 return NULL;
283 } 329 }
284 if (!path.Add("XXXXXX")) { 330 intptr_t prefix_length = path.length();
285 // Pattern has overflowed. 331 while (true) {
286 return NULL; 332 Crypto::GetRandomBytes(6, random_bytes);
333 for (intptr_t i = 0; i < 6; i++) {
334 random_bytes[i] = (random_bytes[i] % numchars) + firstchar;
335 }
336 random_bytes[6] = '\0';
337 if (!path.Add(reinterpret_cast<char*>(random_bytes))) {
338 return NULL;
339 }
340 NamespaceScope ns(namespc, path.AsString());
341 const int result = NO_RETRY_EXPECTED(mkdirat(ns.fd(), ns.path(), 0777));
342 if (result == 0) {
343 return path.AsScopedString();
344 } else if (errno == EEXIST) {
345 path.Reset(prefix_length);
346 } else {
347 return NULL;
348 }
287 } 349 }
288 char* result = mkdtemp(path.AsString());
289 if (result == NULL) {
290 return NULL;
291 }
292 return path.AsScopedString();
293 } 350 }
294 351
295 static bool DeleteRecursively(PathBuffer* path); 352 static bool DeleteRecursively(int dirfd, PathBuffer* path);
296 353
297 static bool DeleteFile(char* file_name, PathBuffer* path) { 354 static bool DeleteFile(int dirfd, char* file_name, PathBuffer* path) {
298 return path->Add(file_name) && 355 return path->Add(file_name) &&
299 (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0); 356 (NO_RETRY_EXPECTED(unlinkat(dirfd, path->AsString(), 0)) == 0);
300 } 357 }
301 358
302 static bool DeleteDir(char* dir_name, PathBuffer* path) { 359 static bool DeleteDir(int dirfd, char* dir_name, PathBuffer* path) {
303 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) { 360 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) {
304 return true; 361 return true;
305 } 362 }
306 return path->Add(dir_name) && DeleteRecursively(path); 363 return path->Add(dir_name) && DeleteRecursively(dirfd, path);
307 } 364 }
308 365
309 static bool DeleteRecursively(PathBuffer* path) { 366 static bool DeleteRecursively(int dirfd, PathBuffer* path) {
310 // Do not recurse into links for deletion. Instead delete the link. 367 // Do not recurse into links for deletion. Instead delete the link.
311 // If it's a file, delete it. 368 // If it's a file, delete it.
312 struct stat64 st; 369 struct stat64 st;
313 if (NO_RETRY_EXPECTED(lstat64(path->AsString(), &st)) == -1) { 370 if (TEMP_FAILURE_RETRY(
371 fstatat64(dirfd, path->AsString(), &st, AT_SYMLINK_NOFOLLOW)) == -1) {
314 return false; 372 return false;
315 } else if (!S_ISDIR(st.st_mode)) { 373 } else if (!S_ISDIR(st.st_mode)) {
316 return NO_RETRY_EXPECTED(unlink(path->AsString())) == 0; 374 return (NO_RETRY_EXPECTED(unlinkat(dirfd, path->AsString(), 0)) == 0);
317 } 375 }
318 376
319 if (!path->Add(File::PathSeparator())) { 377 if (!path->Add(File::PathSeparator())) {
320 return false; 378 return false;
321 } 379 }
322 380
323 // Not a link. Attempt to open as a directory and recurse into the 381 // Not a link. Attempt to open as a directory and recurse into the
324 // directory. 382 // directory.
325 DIR* dir_pointer = opendir(path->AsString()); 383 const int fd =
384 TEMP_FAILURE_RETRY(openat64(dirfd, path->AsString(), O_DIRECTORY));
385 if (fd < 0) {
386 return false;
387 }
388 DIR* dir_pointer;
389 do {
390 dir_pointer = fdopendir(fd);
391 } while ((dir_pointer == NULL) && (errno == EINTR));
326 if (dir_pointer == NULL) { 392 if (dir_pointer == NULL) {
393 FDUtils::SaveErrorAndClose(fd);
327 return false; 394 return false;
328 } 395 }
329 396
330 // Iterate the directory and delete all files and directories. 397 // Iterate the directory and delete all files and directories.
331 int path_length = path->length(); 398 int path_length = path->length();
332 while (true) { 399 while (true) {
333 // In case `readdir()` returns `NULL` we distinguish between end-of-stream 400 // In case `readdir()` returns `NULL` we distinguish between end-of-stream
334 // and error by looking if `errno` was updated. 401 // and error by looking if `errno` was updated.
335 errno = 0; 402 errno = 0;
336 // In glibc 2.24+, readdir_r is deprecated. 403 // In glibc 2.24+, readdir_r is deprecated.
337 // According to the man page for readdir: 404 // According to the man page for readdir:
338 // "readdir(3) is not required to be thread-safe. However, in modern 405 // "readdir(3) is not required to be thread-safe. However, in modern
339 // implementations (including the glibc implementation), concurrent calls to 406 // implementations (including the glibc implementation), concurrent calls to
340 // readdir(3) that specify different directory streams are thread-safe." 407 // readdir(3) that specify different directory streams are thread-safe."
341 dirent* entry = readdir(dir_pointer); 408 dirent* entry = readdir(dir_pointer);
342 if (entry == NULL) { 409 if (entry == NULL) {
343 // Failed to read next directory entry. 410 // Failed to read next directory entry.
344 if (errno != 0) { 411 if (errno != 0) {
345 break; 412 break;
346 } 413 }
347 // End of directory. 414 // End of directory.
348 return (NO_RETRY_EXPECTED(closedir(dir_pointer)) == 0) && 415 int status = NO_RETRY_EXPECTED(closedir(dir_pointer));
349 (NO_RETRY_EXPECTED(remove(path->AsString())) == 0); 416 FDUtils::SaveErrorAndClose(fd);
417 if (status != 0) {
418 return false;
419 }
420 status =
421 NO_RETRY_EXPECTED(unlinkat(dirfd, path->AsString(), AT_REMOVEDIR));
422 return status == 0;
350 } 423 }
351 bool ok = false; 424 bool ok = false;
352 if (!path->Add(entry->d_name)) { 425 switch (entry->d_type) {
353 break; 426 case DT_DIR:
354 } 427 ok = DeleteDir(dirfd, entry->d_name, path);
355 // TODO(MG-450): When entry->d_type is filled out correctly, we can avoid 428 break;
356 // this call to stat(). 429 case DT_BLK:
357 struct stat64 entry_info; 430 case DT_CHR:
358 if (NO_RETRY_EXPECTED(lstat64(path->AsString(), &entry_info)) == -1) { 431 case DT_FIFO:
359 break; 432 case DT_SOCK:
360 } 433 case DT_REG:
361 path->Reset(path_length); 434 case DT_LNK:
362 if (S_ISDIR(entry_info.st_mode)) { 435 // Treat all links as files. This will delete the link which
363 ok = DeleteDir(entry->d_name, path); 436 // is what we want no matter if the link target is a file or a
364 } else { 437 // directory.
365 // Treat links as files. This will delete the link which is 438 ok = DeleteFile(dirfd, entry->d_name, path);
366 // what we want no matter if the link target is a file or a 439 break;
367 // directory. 440 case DT_UNKNOWN: {
368 ok = DeleteFile(entry->d_name, path); 441 if (!path->Add(entry->d_name)) {
442 break;
443 }
444 // On some file systems the entry type is not determined by
445 // readdir. For those we use lstat to determine the entry
446 // type.
447 struct stat64 entry_info;
448 if (TEMP_FAILURE_RETRY(fstatat64(dirfd, path->AsString(), &entry_info,
449 AT_SYMLINK_NOFOLLOW)) == -1) {
450 break;
451 }
452 path->Reset(path_length);
453 if (S_ISDIR(entry_info.st_mode)) {
454 ok = DeleteDir(dirfd, entry->d_name, path);
455 } else {
456 // Treat links as files. This will delete the link which is
457 // what we want no matter if the link target is a file or a
458 // directory.
459 ok = DeleteFile(dirfd, entry->d_name, path);
460 }
461 break;
462 }
463 default:
464 // We should have covered all the bases. If not, let's get an error.
465 FATAL1("Unexpected d_type: %d\n", entry->d_type);
466 break;
369 } 467 }
370 if (!ok) { 468 if (!ok) {
371 break; 469 break;
372 } 470 }
373 path->Reset(path_length); 471 path->Reset(path_length);
374 } 472 }
375 // Only happens if there was an error. 473 // Only happens if an error.
376 ASSERT(errno != 0); 474 ASSERT(errno != 0);
377 int err = errno; 475 int err = errno;
378 VOID_NO_RETRY_EXPECTED(closedir(dir_pointer)); 476 VOID_NO_RETRY_EXPECTED(closedir(dir_pointer));
477 FDUtils::SaveErrorAndClose(fd);
379 errno = err; 478 errno = err;
380 return false; 479 return false;
381 } 480 }
382 481
383 bool Directory::Delete(const char* dir_name, bool recursive) { 482 bool Directory::Delete(Namespace* namespc,
483 const char* dir_name,
484 bool recursive) {
485 NamespaceScope ns(namespc, dir_name);
384 if (!recursive) { 486 if (!recursive) {
385 if ((File::GetType(dir_name, false) == File::kIsLink) && 487 if ((File::GetType(namespc, dir_name, false) == File::kIsLink) &&
386 (File::GetType(dir_name, true) == File::kIsDirectory)) { 488 (File::GetType(namespc, dir_name, true) == File::kIsDirectory)) {
387 return NO_RETRY_EXPECTED(unlink(dir_name)) == 0; 489 return NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0;
388 } 490 }
389 return NO_RETRY_EXPECTED(rmdir(dir_name)) == 0; 491 return NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), AT_REMOVEDIR)) == 0;
390 } else { 492 } else {
391 PathBuffer path; 493 PathBuffer path;
392 if (!path.Add(dir_name)) { 494 if (!path.Add(ns.path())) {
393 return false; 495 return false;
394 } 496 }
395 return DeleteRecursively(&path); 497 return DeleteRecursively(ns.fd(), &path);
396 } 498 }
397 } 499 }
398 500
399 bool Directory::Rename(const char* path, const char* new_path) { 501 bool Directory::Rename(Namespace* namespc,
400 ExistsResult exists = Exists(path); 502 const char* old_path,
503 const char* new_path) {
504 ExistsResult exists = Exists(namespc, old_path);
401 if (exists != EXISTS) { 505 if (exists != EXISTS) {
402 return false; 506 return false;
403 } 507 }
404 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); 508 NamespaceScope oldns(namespc, old_path);
509 NamespaceScope newns(namespc, new_path);
510 return (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(),
511 newns.path())) == 0);
405 } 512 }
406 513
407 } // namespace bin 514 } // namespace bin
408 } // namespace dart 515 } // namespace dart
409 516
410 #endif // defined(HOST_OS_FUCHSIA) 517 #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