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

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

Issue 3007703002: [dart:io] Namespaces for file IO (Closed)
Patch Set: 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
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) {
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 =
255 TEMP_FAILURE_RETRY(fstatat64(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(
373 fstatat64(dirfd, path->AsString(), &st, AT_SYMLINK_NOFOLLOW)) == -1) {
314 return false; 374 return false;
315 } else if (!S_ISDIR(st.st_mode)) { 375 } else if (!S_ISDIR(st.st_mode)) {
316 return NO_RETRY_EXPECTED(unlink(path->AsString())) == 0; 376 return (NO_RETRY_EXPECTED(unlinkat(dirfd, path->AsString(), 0)) == 0);
317 } 377 }
318 378
319 if (!path->Add(File::PathSeparator())) { 379 if (!path->Add(File::PathSeparator())) {
320 return false; 380 return false;
321 } 381 }
322 382
323 // Not a link. Attempt to open as a directory and recurse into the 383 // Not a link. Attempt to open as a directory and recurse into the
324 // directory. 384 // directory.
325 DIR* dir_pointer = opendir(path->AsString()); 385 const int fd =
386 TEMP_FAILURE_RETRY(openat64(dirfd, path->AsString(), O_DIRECTORY));
387 if (fd < 0) {
388 return false;
389 }
390 DIR* dir_pointer;
391 do {
392 dir_pointer = fdopendir(fd);
393 } while ((dir_pointer == NULL) && (errno == EINTR));
326 if (dir_pointer == NULL) { 394 if (dir_pointer == NULL) {
395 FDUtils::SaveErrorAndClose(fd);
327 return false; 396 return false;
328 } 397 }
329 398
330 // Iterate the directory and delete all files and directories. 399 // Iterate the directory and delete all files and directories.
331 int path_length = path->length(); 400 int path_length = path->length();
332 while (true) { 401 while (true) {
333 // In case `readdir()` returns `NULL` we distinguish between end-of-stream 402 // In case `readdir()` returns `NULL` we distinguish between end-of-stream
334 // and error by looking if `errno` was updated. 403 // and error by looking if `errno` was updated.
335 errno = 0; 404 errno = 0;
336 // In glibc 2.24+, readdir_r is deprecated. 405 // In glibc 2.24+, readdir_r is deprecated.
337 // According to the man page for readdir: 406 // According to the man page for readdir:
338 // "readdir(3) is not required to be thread-safe. However, in modern 407 // "readdir(3) is not required to be thread-safe. However, in modern
339 // implementations (including the glibc implementation), concurrent calls to 408 // implementations (including the glibc implementation), concurrent calls to
340 // readdir(3) that specify different directory streams are thread-safe." 409 // readdir(3) that specify different directory streams are thread-safe."
341 dirent* entry = readdir(dir_pointer); 410 dirent* entry = readdir(dir_pointer);
342 if (entry == NULL) { 411 if (entry == NULL) {
343 // Failed to read next directory entry. 412 // Failed to read next directory entry.
344 if (errno != 0) { 413 if (errno != 0) {
345 break; 414 break;
346 } 415 }
347 // End of directory. 416 // End of directory.
348 return (NO_RETRY_EXPECTED(closedir(dir_pointer)) == 0) && 417 int status = NO_RETRY_EXPECTED(closedir(dir_pointer));
349 (NO_RETRY_EXPECTED(remove(path->AsString())) == 0); 418 FDUtils::SaveErrorAndClose(fd);
419 if (status != 0) {
420 return false;
421 }
422 status =
423 NO_RETRY_EXPECTED(unlinkat(dirfd, path->AsString(), AT_REMOVEDIR));
424 return status == 0;
350 } 425 }
351 bool ok = false; 426 bool ok = false;
352 if (!path->Add(entry->d_name)) { 427 switch (entry->d_type) {
353 break; 428 case DT_DIR:
354 } 429 ok = DeleteDir(dirfd, entry->d_name, path);
355 // TODO(MG-450): When entry->d_type is filled out correctly, we can avoid 430 break;
356 // this call to stat(). 431 case DT_BLK:
357 struct stat64 entry_info; 432 case DT_CHR:
358 if (NO_RETRY_EXPECTED(lstat64(path->AsString(), &entry_info)) == -1) { 433 case DT_FIFO:
359 break; 434 case DT_SOCK:
360 } 435 case DT_REG:
361 path->Reset(path_length); 436 case DT_LNK:
362 if (S_ISDIR(entry_info.st_mode)) { 437 // Treat all links as files. This will delete the link which
363 ok = DeleteDir(entry->d_name, path); 438 // is what we want no matter if the link target is a file or a
364 } else { 439 // directory.
365 // Treat links as files. This will delete the link which is 440 ok = DeleteFile(dirfd, entry->d_name, path);
366 // what we want no matter if the link target is a file or a 441 break;
367 // directory. 442 case DT_UNKNOWN: {
368 ok = DeleteFile(entry->d_name, path); 443 if (!path->Add(entry->d_name)) {
444 break;
445 }
446 // On some file systems the entry type is not determined by
447 // readdir. For those we use lstat to determine the entry
448 // type.
449 struct stat64 entry_info;
450 if (TEMP_FAILURE_RETRY(fstatat64(dirfd, path->AsString(), &entry_info,
451 AT_SYMLINK_NOFOLLOW)) == -1) {
452 break;
453 }
454 path->Reset(path_length);
455 if (S_ISDIR(entry_info.st_mode)) {
456 ok = DeleteDir(dirfd, entry->d_name, path);
457 } else {
458 // Treat links as files. This will delete the link which is
459 // what we want no matter if the link target is a file or a
460 // directory.
461 ok = DeleteFile(dirfd, entry->d_name, path);
462 }
463 break;
464 }
465 default:
466 // We should have covered all the bases. If not, let's get an error.
467 FATAL1("Unexpected d_type: %d\n", entry->d_type);
468 break;
369 } 469 }
370 if (!ok) { 470 if (!ok) {
371 break; 471 break;
372 } 472 }
373 path->Reset(path_length); 473 path->Reset(path_length);
374 } 474 }
375 // Only happens if there was an error. 475 // Only happens if an error.
376 ASSERT(errno != 0); 476 ASSERT(errno != 0);
377 int err = errno; 477 int err = errno;
378 VOID_NO_RETRY_EXPECTED(closedir(dir_pointer)); 478 VOID_NO_RETRY_EXPECTED(closedir(dir_pointer));
479 FDUtils::SaveErrorAndClose(fd);
379 errno = err; 480 errno = err;
380 return false; 481 return false;
381 } 482 }
382 483
383 bool Directory::Delete(const char* dir_name, bool recursive) { 484 bool Directory::Delete(Namespace* namespc,
485 const char* dir_name,
486 bool recursive) {
487 NamespaceScope ns(namespc, dir_name);
384 if (!recursive) { 488 if (!recursive) {
385 if ((File::GetType(dir_name, false) == File::kIsLink) && 489 if ((File::GetType(namespc, dir_name, false) == File::kIsLink) &&
386 (File::GetType(dir_name, true) == File::kIsDirectory)) { 490 (File::GetType(namespc, dir_name, true) == File::kIsDirectory)) {
387 return NO_RETRY_EXPECTED(unlink(dir_name)) == 0; 491 return NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0;
388 } 492 }
389 return NO_RETRY_EXPECTED(rmdir(dir_name)) == 0; 493 return NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), AT_REMOVEDIR)) == 0;
390 } else { 494 } else {
391 PathBuffer path; 495 PathBuffer path;
392 if (!path.Add(dir_name)) { 496 if (!path.Add(ns.path())) {
393 return false; 497 return false;
394 } 498 }
395 return DeleteRecursively(&path); 499 return DeleteRecursively(ns.fd(), &path);
396 } 500 }
397 } 501 }
398 502
399 bool Directory::Rename(const char* path, const char* new_path) { 503 bool Directory::Rename(Namespace* namespc,
400 ExistsResult exists = Exists(path); 504 const char* old_path,
505 const char* new_path) {
506 ExistsResult exists = Exists(namespc, old_path);
401 if (exists != EXISTS) { 507 if (exists != EXISTS) {
402 return false; 508 return false;
403 } 509 }
404 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); 510 NamespaceScope oldns(namespc, old_path);
511 NamespaceScope newns(namespc, new_path);
512 return (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(),
513 newns.path())) == 0);
405 } 514 }
406 515
407 } // namespace bin 516 } // namespace bin
408 } // namespace dart 517 } // namespace dart
409 518
410 #endif // defined(HOST_OS_FUCHSIA) 519 #endif // defined(HOST_OS_FUCHSIA)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698