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

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

Powered by Google App Engine
This is Rietveld 408576698