Chromium Code Reviews| OLD | NEW |
|---|---|
| 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(TARGET_OS_LINUX) | 6 #if defined(TARGET_OS_LINUX) |
| 7 | 7 |
| 8 #include "bin/directory.h" | 8 #include "bin/directory.h" |
| 9 | 9 |
| 10 #include <dirent.h> // NOLINT | 10 #include <dirent.h> // NOLINT |
| 11 #include <errno.h> // NOLINT | 11 #include <errno.h> // NOLINT |
| 12 #include <string.h> // NOLINT | 12 #include <string.h> // NOLINT |
| 13 #include <sys/param.h> // NOLINT | 13 #include <sys/param.h> // NOLINT |
| 14 #include <sys/stat.h> // NOLINT | 14 #include <sys/stat.h> // NOLINT |
| 15 #include <unistd.h> // NOLINT | 15 #include <unistd.h> // NOLINT |
| 16 | 16 |
| 17 #include "bin/file.h" | 17 #include "bin/file.h" |
| 18 #include "bin/platform.h" | 18 #include "bin/platform.h" |
| 19 | 19 |
| 20 | 20 |
| 21 namespace dart { | 21 namespace dart { |
| 22 namespace bin { | 22 namespace bin { |
| 23 | 23 |
| 24 class PathBuffer { | 24 |
| 25 public: | 25 PathBuffer::PathBuffer() : length_(0) { |
| 26 PathBuffer() : length(0) { | 26 data_ = new char[PATH_MAX + 1]; |
| 27 data = new char[PATH_MAX + 1]; | 27 } |
| 28 | |
| 29 char* PathBuffer::AsString() const { | |
| 30 return reinterpret_cast<char*>(data_); | |
| 31 } | |
| 32 | |
| 33 bool PathBuffer::Add(const char* name) { | |
| 34 char* data = AsString(); | |
| 35 int written = snprintf(data + length_, | |
| 36 PATH_MAX - length_, | |
| 37 "%s", | |
| 38 name); | |
| 39 data[PATH_MAX] = '\0'; | |
| 40 if (written <= PATH_MAX - length_ && | |
| 41 written >= 0 && | |
| 42 static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1)) { | |
| 43 length_ += written; | |
| 44 return true; | |
| 45 } else { | |
| 46 errno = ENAMETOOLONG; | |
| 47 return false; | |
| 28 } | 48 } |
| 49 } | |
| 29 | 50 |
| 30 ~PathBuffer() { | 51 void PathBuffer::Reset(int new_length) { |
| 31 delete[] data; | 52 length_ = new_length; |
| 32 } | 53 AsString()[length_] = '\0'; |
| 33 | 54 } |
| 34 char* data; | |
| 35 int length; | |
| 36 | |
| 37 bool Add(const char* name) { | |
| 38 int written = snprintf(data + length, | |
| 39 PATH_MAX - length, | |
| 40 "%s", | |
| 41 name); | |
| 42 data[PATH_MAX] = '\0'; | |
| 43 if (written <= PATH_MAX - length && | |
| 44 written >= 0 && | |
| 45 static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1)) { | |
| 46 length += written; | |
| 47 return true; | |
| 48 } else { | |
| 49 errno = ENAMETOOLONG; | |
| 50 return false; | |
| 51 } | |
| 52 } | |
| 53 | |
| 54 void Reset(int new_length) { | |
| 55 length = new_length; | |
| 56 data[length] = '\0'; | |
| 57 } | |
| 58 }; | |
| 59 | 55 |
| 60 | 56 |
| 61 // A linked list of symbolic links, with their unique file system identifiers. | 57 // A linked list of symbolic links, with their unique file system identifiers. |
| 62 // These are scanned to detect loops while doing a recursive directory listing. | 58 // These are scanned to detect loops while doing a recursive directory listing. |
| 63 struct LinkList { | 59 struct LinkList { |
| 64 dev_t dev; | 60 dev_t dev; |
| 65 ino_t ino; | 61 ino_t ino; |
| 66 LinkList* next; | 62 LinkList* next; |
| 67 }; | 63 }; |
| 68 | 64 |
| 69 | 65 |
| 70 // Forward declarations. | 66 DirectoryListingEntry::DirectoryListingEntry(void* link) |
| 71 static bool ListRecursively(PathBuffer* path, | 67 : lister_(NULL), done_(false), link_(link) {} |
| 72 bool recursive, | |
| 73 bool follow_links, | |
| 74 LinkList* seen, | |
| 75 DirectoryListing* listing); | |
| 76 static bool DeleteRecursively(PathBuffer* path); | |
| 77 | 68 |
| 78 | 69 |
| 79 static void PostError(DirectoryListing *listing, | 70 ListType DirectoryListingEntry::Next(DirectoryListing* listing) { |
| 80 const char* dir_name) { | 71 if (done_) { |
| 81 listing->HandleError(dir_name); | 72 return kListDone; |
| 82 } | |
| 83 | |
| 84 | |
| 85 static bool HandleDir(char* dir_name, | |
| 86 PathBuffer* path, | |
| 87 bool recursive, | |
| 88 bool follow_links, | |
| 89 LinkList* seen, | |
| 90 DirectoryListing *listing) { | |
| 91 if (strcmp(dir_name, ".") == 0) return true; | |
| 92 if (strcmp(dir_name, "..") == 0) return true; | |
| 93 if (!path->Add(dir_name)) { | |
| 94 PostError(listing, path->data); | |
| 95 return false; | |
| 96 } | |
| 97 return listing->HandleDirectory(path->data) && | |
| 98 (!recursive || | |
| 99 ListRecursively(path, recursive, follow_links, seen, listing)); | |
| 100 } | |
| 101 | |
| 102 | |
| 103 static bool HandleFile(char* file_name, | |
| 104 PathBuffer* path, | |
| 105 DirectoryListing *listing) { | |
| 106 if (!path->Add(file_name)) { | |
| 107 PostError(listing, path->data); | |
| 108 return false; | |
| 109 } | |
| 110 return listing->HandleFile(path->data); | |
| 111 } | |
| 112 | |
| 113 | |
| 114 static bool HandleLink(char* link_name, | |
| 115 PathBuffer* path, | |
| 116 DirectoryListing *listing) { | |
| 117 if (!path->Add(link_name)) { | |
| 118 PostError(listing, path->data); | |
| 119 return false; | |
| 120 } | |
| 121 return listing->HandleLink(path->data); | |
| 122 } | |
| 123 | |
| 124 | |
| 125 static bool ListRecursively(PathBuffer* path, | |
| 126 bool recursive, | |
| 127 bool follow_links, | |
| 128 LinkList* seen, | |
| 129 DirectoryListing *listing) { | |
| 130 if (!path->Add(File::PathSeparator())) { | |
| 131 PostError(listing, path->data); | |
| 132 return false; | |
| 133 } | |
| 134 DIR* dir_pointer; | |
| 135 do { | |
| 136 dir_pointer = opendir(path->data); | |
| 137 } while (dir_pointer == NULL && errno == EINTR); | |
| 138 if (dir_pointer == NULL) { | |
| 139 PostError(listing, path->data); | |
| 140 return false; | |
| 141 } | 73 } |
| 142 | 74 |
| 75 if (lister_ == NULL) { | |
| 76 if (!listing->path_buffer().Add(File::PathSeparator())) { | |
| 77 done_ = true; | |
| 78 return kListError; | |
| 79 } | |
| 80 path_length_ = listing->path_buffer().length(); | |
| 81 do { | |
| 82 lister_ = opendir(listing->path_buffer().AsString()); | |
| 83 } while (lister_ == NULL && errno == EINTR); | |
| 84 | |
| 85 if (lister_ == NULL) { | |
| 86 done_ = true; | |
| 87 return kListError; | |
| 88 } | |
| 89 } | |
| 90 // Reset. | |
| 91 listing->path_buffer().Reset(path_length_); | |
| 92 if (parent_ != NULL && parent_->link_ != link_) { | |
| 93 delete reinterpret_cast<LinkList*>(link_); | |
| 94 link_ = parent_->link_; | |
| 95 } else if (parent_ == NULL && link_ != NULL) { | |
| 96 delete reinterpret_cast<LinkList*>(link_); | |
| 97 link_ = NULL; | |
| 98 } | |
| 143 // Iterate the directory and post the directories and files to the | 99 // Iterate the directory and post the directories and files to the |
| 144 // ports. | 100 // ports. |
| 145 int path_length = path->length; | |
| 146 int status = 0; | 101 int status = 0; |
| 147 bool success = true; | |
| 148 dirent entry; | 102 dirent entry; |
| 149 dirent* result; | 103 dirent* result; |
| 150 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, | 104 if ((status = TEMP_FAILURE_RETRY(readdir_r(reinterpret_cast<DIR*>(lister_), |
| 151 &entry, | 105 &entry, |
| 152 &result))) == 0 && | 106 &result))) == 0 && |
| 153 result != NULL) { | 107 result != NULL) { |
| 108 if (!listing->path_buffer().Add(entry.d_name)) { | |
| 109 done_ = true; | |
| 110 return kListError; | |
| 111 } | |
| 154 switch (entry.d_type) { | 112 switch (entry.d_type) { |
| 155 case DT_DIR: | 113 case DT_DIR: |
| 156 success = HandleDir(entry.d_name, | 114 if (strcmp(entry.d_name, ".") == 0) return Next(listing); |
| 157 path, | 115 if (strcmp(entry.d_name, "..") == 0) return Next(listing); |
| 158 recursive, | 116 return kListDirectory; |
| 159 follow_links, | |
| 160 seen, | |
| 161 listing) && success; | |
| 162 break; | |
| 163 case DT_REG: | 117 case DT_REG: |
| 164 success = HandleFile(entry.d_name, | 118 return kListFile; |
| 165 path, | |
| 166 listing) && success; | |
| 167 break; | |
| 168 case DT_LNK: | 119 case DT_LNK: |
| 169 if (!follow_links) { | 120 if (!listing->follow_links()) { |
| 170 success = HandleLink(entry.d_name, | 121 return kListLink; |
| 171 path, | |
| 172 listing) && success; | |
| 173 break; | |
| 174 } | 122 } |
| 175 // Else fall through to next case. | 123 // Else fall through to next case. |
| 176 // Fall through. | 124 // Fall through. |
| 177 case DT_UNKNOWN: { | 125 case DT_UNKNOWN: { |
| 178 // On some file systems the entry type is not determined by | 126 // On some file systems the entry type is not determined by |
| 179 // readdir_r. For those and for links we use stat to determine | 127 // readdir_r. For those and for links we use stat to determine |
| 180 // the actual entry type. Notice that stat returns the type of | 128 // the actual entry type. Notice that stat returns the type of |
| 181 // the file pointed to. | 129 // the file pointed to. |
| 182 struct stat entry_info; | 130 struct stat entry_info; |
| 183 if (!path->Add(entry.d_name)) { | 131 int stat_success; |
| 184 success = false; | 132 stat_success = TEMP_FAILURE_RETRY( |
| 185 break; | 133 lstat(listing->path_buffer().AsString(), &entry_info)); |
| 134 if (stat_success == -1) { | |
| 135 return kListError; | |
| 186 } | 136 } |
| 187 int stat_success; | 137 if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) { |
| 188 stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info)); | |
| 189 if (stat_success == -1) { | |
| 190 success = false; | |
| 191 PostError(listing, path->data); | |
| 192 break; | |
| 193 } | |
| 194 if (follow_links && S_ISLNK(entry_info.st_mode)) { | |
| 195 // Check to see if we are in a loop created by a symbolic link. | 138 // Check to see if we are in a loop created by a symbolic link. |
| 139 LinkList* previous = reinterpret_cast<LinkList*>(link_); | |
| 196 LinkList current_link = { entry_info.st_dev, | 140 LinkList current_link = { entry_info.st_dev, |
| 197 entry_info.st_ino, | 141 entry_info.st_ino, |
| 198 seen }; | 142 previous }; |
| 199 LinkList* previous = seen; | |
| 200 bool looping_link = false; | |
| 201 while (previous != NULL) { | 143 while (previous != NULL) { |
| 202 if (previous->dev == current_link.dev && | 144 if (previous->dev == current_link.dev && |
| 203 previous->ino == current_link.ino) { | 145 previous->ino == current_link.ino) { |
| 204 // Report the looping link as a link, rather than following it. | 146 // Report the looping link as a link, rather than following it. |
| 205 path->Reset(path_length); | 147 return kListLink; |
| 206 success = HandleLink(entry.d_name, | |
| 207 path, | |
| 208 listing) && success; | |
| 209 looping_link = true; | |
| 210 break; | |
| 211 } | 148 } |
| 212 previous = previous->next; | 149 previous = previous->next; |
| 213 } | 150 } |
| 214 if (looping_link) break; | 151 stat_success = TEMP_FAILURE_RETRY( |
| 215 stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info)); | 152 stat(listing->path_buffer().AsString(), &entry_info)); |
| 216 if (stat_success == -1) { | 153 if (stat_success == -1) { |
| 217 // Report a broken link as a link, even if follow_links is true. | 154 // Report a broken link as a link, even if follow_links is true. |
| 218 path->Reset(path_length); | 155 return kListLink; |
| 219 success = HandleLink(entry.d_name, | |
| 220 path, | |
| 221 listing) && success; | |
| 222 break; | |
| 223 } | 156 } |
| 224 if (S_ISDIR(entry_info.st_mode)) { | 157 if (S_ISDIR(entry_info.st_mode)) { |
| 225 // Recurse into the subdirectory with current_link added to the | 158 // Recurse into the subdirectory with current_link added to the |
| 226 // linked list of seen file system links. | 159 // linked list of seen file system links. |
| 227 path->Reset(path_length); | 160 link_ = new LinkList(current_link); |
| 228 success = HandleDir(entry.d_name, | 161 if (strcmp(entry.d_name, ".") == 0) return Next(listing); |
| 229 path, | 162 if (strcmp(entry.d_name, "..") == 0) return Next(listing); |
| 230 recursive, | 163 return kListDirectory; |
| 231 follow_links, | |
| 232 ¤t_link, | |
| 233 listing) && success; | |
| 234 break; | |
| 235 } | 164 } |
| 236 } | 165 } |
| 237 path->Reset(path_length); | |
| 238 if (S_ISDIR(entry_info.st_mode)) { | 166 if (S_ISDIR(entry_info.st_mode)) { |
| 239 success = HandleDir(entry.d_name, | 167 if (strcmp(entry.d_name, ".") == 0) return Next(listing); |
| 240 path, | 168 if (strcmp(entry.d_name, "..") == 0) return Next(listing); |
| 241 recursive, | 169 return kListDirectory; |
| 242 follow_links, | |
| 243 seen, | |
| 244 listing) && success; | |
| 245 } else if (S_ISREG(entry_info.st_mode)) { | 170 } else if (S_ISREG(entry_info.st_mode)) { |
| 246 success = HandleFile(entry.d_name, | 171 return kListFile; |
| 247 path, | |
| 248 listing) && success; | |
| 249 } else if (S_ISLNK(entry_info.st_mode)) { | 172 } else if (S_ISLNK(entry_info.st_mode)) { |
| 250 success = HandleLink(entry.d_name, | 173 return kListLink; |
| 251 path, | |
| 252 listing) && success; | |
| 253 } | 174 } |
| 254 break; | |
| 255 } | 175 } |
| 176 | |
| 256 default: | 177 default: |
| 257 break; | 178 break; |
| 258 } | 179 } |
| 259 path->Reset(path_length); | |
| 260 } | 180 } |
| 181 done_ = true; | |
| 261 | 182 |
| 262 if (status != 0) { | 183 if (status != 0) { |
| 263 errno = status; | 184 errno = status; |
| 264 success = false; | 185 return kListError; |
| 265 PostError(listing, path->data); | |
| 266 } | 186 } |
| 267 | 187 |
| 268 if (closedir(dir_pointer) == -1) { | 188 if (closedir(reinterpret_cast<DIR*>(lister_)) == -1) { |
| 269 success = false; | 189 return kListError; |
| 270 PostError(listing, path->data); | |
| 271 } | 190 } |
| 272 | 191 |
| 273 return success; | 192 return kListDone; |
| 274 } | 193 } |
| 275 | 194 |
| 276 | 195 |
| 196 static bool ListNext(DirectoryListing* listing) { | |
| 197 switch (listing->top()->Next(listing)) { | |
| 198 case kListFile: | |
| 199 return listing->HandleFile(listing->CurrentPath()); | |
| 200 | |
| 201 case kListLink: | |
| 202 return listing->HandleLink(listing->CurrentPath()); | |
| 203 | |
| 204 case kListDirectory: | |
| 205 if (listing->recursive()) { | |
| 206 listing->Push(new DirectoryListingEntry(listing->top()->link())); | |
| 207 } | |
| 208 return listing->HandleDirectory(listing->CurrentPath()); | |
| 209 | |
| 210 case kListError: | |
| 211 return listing->HandleError(listing->CurrentPath()); | |
| 212 | |
| 213 case kListDone: | |
| 214 listing->Pop(); | |
| 215 if (listing->IsEmpty()) { | |
| 216 listing->HandleDone(); | |
| 217 return false; | |
| 218 } else { | |
| 219 return true; | |
| 220 } | |
| 221 | |
| 222 default: | |
| 223 ASSERT(0); | |
|
Søren Gjesse
2013/06/12 12:52:41
UNREACHABLE();
Anders Johnsen
2013/06/13 08:38:24
Done.
| |
| 224 } | |
| 225 return false; | |
| 226 } | |
| 227 | |
| 228 | |
| 229 static bool DeleteRecursively(PathBuffer* path); | |
| 230 | |
| 231 | |
| 277 static bool DeleteFile(char* file_name, | 232 static bool DeleteFile(char* file_name, |
| 278 PathBuffer* path) { | 233 PathBuffer* path) { |
| 279 return path->Add(file_name) && unlink(path->data) == 0; | 234 return path->Add(file_name) && unlink(path->AsString()) == 0; |
| 280 } | 235 } |
| 281 | 236 |
| 282 | 237 |
| 283 static bool DeleteDir(char* dir_name, | 238 static bool DeleteDir(char* dir_name, |
| 284 PathBuffer* path) { | 239 PathBuffer* path) { |
| 285 if (strcmp(dir_name, ".") == 0) return true; | 240 if (strcmp(dir_name, ".") == 0) return true; |
| 286 if (strcmp(dir_name, "..") == 0) return true; | 241 if (strcmp(dir_name, "..") == 0) return true; |
| 287 return path->Add(dir_name) && DeleteRecursively(path); | 242 return path->Add(dir_name) && DeleteRecursively(path); |
| 288 } | 243 } |
| 289 | 244 |
| 290 | 245 |
| 291 static bool DeleteRecursively(PathBuffer* path) { | 246 static bool DeleteRecursively(PathBuffer* path) { |
| 292 // Do not recurse into links for deletion. Instead delete the link. | 247 // Do not recurse into links for deletion. Instead delete the link. |
| 293 // If it's a file, delete it. | 248 // If it's a file, delete it. |
| 294 struct stat st; | 249 struct stat st; |
| 295 if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) { | 250 if (TEMP_FAILURE_RETRY(lstat(path->AsString(), &st)) == -1) { |
| 296 return false; | 251 return false; |
| 297 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { | 252 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { |
| 298 return (unlink(path->data) == 0); | 253 return (unlink(path->AsString()) == 0); |
| 299 } | 254 } |
| 300 | 255 |
| 301 if (!path->Add(File::PathSeparator())) return false; | 256 if (!path->Add(File::PathSeparator())) return false; |
| 302 | 257 |
| 303 // Not a link. Attempt to open as a directory and recurse into the | 258 // Not a link. Attempt to open as a directory and recurse into the |
| 304 // directory. | 259 // directory. |
| 305 DIR* dir_pointer; | 260 DIR* dir_pointer; |
| 306 do { | 261 do { |
| 307 dir_pointer = opendir(path->data); | 262 dir_pointer = opendir(path->AsString()); |
| 308 } while (dir_pointer == NULL && errno == EINTR); | 263 } while (dir_pointer == NULL && errno == EINTR); |
| 309 | 264 |
| 310 if (dir_pointer == NULL) { | 265 if (dir_pointer == NULL) { |
| 311 return false; | 266 return false; |
| 312 } | 267 } |
| 313 | 268 |
| 314 // Iterate the directory and delete all files and directories. | 269 // Iterate the directory and delete all files and directories. |
| 315 int path_length = path->length; | 270 int path_length = path->length(); |
| 316 int read = 0; | 271 int read = 0; |
| 317 bool success = true; | 272 bool success = true; |
| 318 dirent entry; | 273 dirent entry; |
| 319 dirent* result; | 274 dirent* result; |
| 320 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, | 275 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, |
| 321 &entry, | 276 &entry, |
| 322 &result))) == 0 && | 277 &result))) == 0 && |
| 323 result != NULL && | 278 result != NULL && |
| 324 success) { | 279 success) { |
| 325 switch (entry.d_type) { | 280 switch (entry.d_type) { |
| 326 case DT_DIR: | 281 case DT_DIR: |
| 327 success = success && DeleteDir(entry.d_name, path); | 282 success = success && DeleteDir(entry.d_name, path); |
| 328 break; | 283 break; |
| 329 case DT_REG: | 284 case DT_REG: |
| 330 case DT_LNK: | 285 case DT_LNK: |
| 331 // Treat all links as files. This will delete the link which | 286 // Treat all links as files. This will delete the link which |
| 332 // is what we want no matter if the link target is a file or a | 287 // is what we want no matter if the link target is a file or a |
| 333 // directory. | 288 // directory. |
| 334 success = success && DeleteFile(entry.d_name, path); | 289 success = success && DeleteFile(entry.d_name, path); |
| 335 break; | 290 break; |
| 336 case DT_UNKNOWN: { | 291 case DT_UNKNOWN: { |
| 337 // On some file systems the entry type is not determined by | 292 // On some file systems the entry type is not determined by |
| 338 // readdir_r. For those we use lstat to determine the entry | 293 // readdir_r. For those we use lstat to determine the entry |
| 339 // type. | 294 // type. |
| 340 struct stat entry_info; | 295 struct stat entry_info; |
| 341 if (!path->Add(entry.d_name)) { | 296 if (!path->Add(entry.d_name)) { |
| 342 success = false; | 297 success = false; |
| 343 break; | 298 break; |
| 344 } | 299 } |
| 345 int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info)); | 300 int lstat_success = TEMP_FAILURE_RETRY( |
| 301 lstat(path->AsString(), &entry_info)); | |
| 346 if (lstat_success == -1) { | 302 if (lstat_success == -1) { |
| 347 success = false; | 303 success = false; |
| 348 break; | 304 break; |
| 349 } | 305 } |
| 350 path->Reset(path_length); | 306 path->Reset(path_length); |
| 351 if (S_ISDIR(entry_info.st_mode)) { | 307 if (S_ISDIR(entry_info.st_mode)) { |
| 352 success = success && DeleteDir(entry.d_name, path); | 308 success = success && DeleteDir(entry.d_name, path); |
| 353 } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) { | 309 } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) { |
| 354 // Treat links as files. This will delete the link which is | 310 // Treat links as files. This will delete the link which is |
| 355 // what we want no matter if the link target is a file or a | 311 // what we want no matter if the link target is a file or a |
| 356 // directory. | 312 // directory. |
| 357 success = success && DeleteFile(entry.d_name, path); | 313 success = success && DeleteFile(entry.d_name, path); |
| 358 } | 314 } |
| 359 break; | 315 break; |
| 360 } | 316 } |
| 361 default: | 317 default: |
| 362 break; | 318 break; |
| 363 } | 319 } |
| 364 path->Reset(path_length); | 320 path->Reset(path_length); |
| 365 } | 321 } |
| 366 | 322 |
| 367 if ((read != 0) || | 323 if ((read != 0) || |
| 368 (closedir(dir_pointer) == -1) || | 324 (closedir(dir_pointer) == -1) || |
| 369 (remove(path->data) == -1)) { | 325 (remove(path->AsString()) == -1)) { |
| 370 return false; | 326 return false; |
| 371 } | 327 } |
| 372 return success; | 328 return success; |
| 373 } | 329 } |
| 374 | 330 |
| 375 | 331 |
| 376 bool Directory::List(const char* dir_name, | |
| 377 bool recursive, | |
| 378 bool follow_links, | |
| 379 DirectoryListing *listing) { | |
| 380 PathBuffer path; | |
| 381 if (!path.Add(dir_name)) { | |
| 382 PostError(listing, dir_name); | |
| 383 return false; | |
| 384 } | |
| 385 return ListRecursively(&path, recursive, follow_links, NULL, listing); | |
| 386 } | |
| 387 | |
| 388 | |
| 389 Directory::ExistsResult Directory::Exists(const char* dir_name) { | 332 Directory::ExistsResult Directory::Exists(const char* dir_name) { |
| 390 struct stat entry_info; | 333 struct stat entry_info; |
| 391 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); | 334 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); |
| 392 if (success == 0) { | 335 if (success == 0) { |
| 393 if (S_ISDIR(entry_info.st_mode)) { | 336 if (S_ISDIR(entry_info.st_mode)) { |
| 394 return EXISTS; | 337 return EXISTS; |
| 395 } else { | 338 } else { |
| 396 return DOES_NOT_EXIST; | 339 return DOES_NOT_EXIST; |
| 397 } | 340 } |
| 398 } else { | 341 } else { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 449 } | 392 } |
| 450 | 393 |
| 451 | 394 |
| 452 char* Directory::CreateTemp(const char* const_template) { | 395 char* Directory::CreateTemp(const char* const_template) { |
| 453 // Returns a new, unused directory name, modifying the contents of | 396 // Returns a new, unused directory name, modifying the contents of |
| 454 // dir_template. Creates the directory with the permissions specified | 397 // dir_template. Creates the directory with the permissions specified |
| 455 // by the process umask. | 398 // by the process umask. |
| 456 // The return value must be freed by the caller. | 399 // The return value must be freed by the caller. |
| 457 PathBuffer path; | 400 PathBuffer path; |
| 458 path.Add(const_template); | 401 path.Add(const_template); |
| 459 if (path.length == 0) { | 402 if (path.length() == 0) { |
| 460 path.Add("/tmp/temp_dir1_"); | 403 path.Add("/tmp/temp_dir1_"); |
| 461 } else if ((path.data)[path.length - 1] == '/') { | 404 } else if ((path.AsString())[path.length() - 1] == '/') { |
| 462 path.Add("temp_dir_"); | 405 path.Add("temp_dir_"); |
| 463 } | 406 } |
| 464 if (!path.Add("XXXXXX")) { | 407 if (!path.Add("XXXXXX")) { |
| 465 // Pattern has overflowed. | 408 // Pattern has overflowed. |
| 466 return NULL; | 409 return NULL; |
| 467 } | 410 } |
| 468 char* result; | 411 char* result; |
| 469 do { | 412 do { |
| 470 result = mkdtemp(path.data); | 413 result = mkdtemp(path.AsString()); |
| 471 } while (result == NULL && errno == EINTR); | 414 } while (result == NULL && errno == EINTR); |
| 472 if (result == NULL) { | 415 if (result == NULL) { |
| 473 return NULL; | 416 return NULL; |
| 474 } | 417 } |
| 475 int length = strnlen(path.data, PATH_MAX); | 418 int length = strnlen(path.AsString(), PATH_MAX); |
| 476 result = static_cast<char*>(malloc(length + 1)); | 419 result = static_cast<char*>(malloc(length + 1)); |
| 477 strncpy(result, path.data, length); | 420 strncpy(result, path.AsString(), length); |
| 478 result[length] = '\0'; | 421 result[length] = '\0'; |
| 479 return result; | 422 return result; |
| 480 } | 423 } |
| 481 | 424 |
| 482 | 425 |
| 483 bool Directory::Delete(const char* dir_name, bool recursive) { | 426 bool Directory::Delete(const char* dir_name, bool recursive) { |
| 484 if (!recursive) { | 427 if (!recursive) { |
| 485 if (File::GetType(dir_name, false) == File::kIsLink && | 428 if (File::GetType(dir_name, false) == File::kIsLink && |
| 486 File::GetType(dir_name, true) == File::kIsDirectory) { | 429 File::GetType(dir_name, true) == File::kIsDirectory) { |
| 487 return (TEMP_FAILURE_RETRY(unlink(dir_name)) == 0); | 430 return (TEMP_FAILURE_RETRY(unlink(dir_name)) == 0); |
| 488 } | 431 } |
| 489 return (TEMP_FAILURE_RETRY(rmdir(dir_name)) == 0); | 432 return (TEMP_FAILURE_RETRY(rmdir(dir_name)) == 0); |
| 490 } else { | 433 } else { |
| 491 PathBuffer path; | 434 PathBuffer path; |
| 492 if (!path.Add(dir_name)) { | 435 if (!path.Add(dir_name)) { |
| 493 return false; | 436 return false; |
| 494 } | 437 } |
| 495 return DeleteRecursively(&path); | 438 return DeleteRecursively(&path); |
| 496 } | 439 } |
| 497 } | 440 } |
| 498 | 441 |
| 499 | 442 |
| 500 bool Directory::Rename(const char* path, const char* new_path) { | 443 bool Directory::Rename(const char* path, const char* new_path) { |
| 501 ExistsResult exists = Exists(path); | 444 ExistsResult exists = Exists(path); |
| 502 if (exists != EXISTS) return false; | 445 if (exists != EXISTS) return false; |
| 503 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); | 446 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); |
| 504 } | 447 } |
| 505 | 448 |
| 449 | |
| 450 void Directory::List(DirectoryListing* listing) { | |
| 451 if (listing->error()) { | |
| 452 listing->HandleError("Invalid path"); | |
| 453 listing->HandleDone(); | |
| 454 } else { | |
| 455 while (ListNext(listing)) {} | |
| 456 } | |
| 457 } | |
| 458 | |
| 506 } // namespace bin | 459 } // namespace bin |
| 507 } // namespace dart | 460 } // namespace dart |
| 508 | 461 |
| 509 #endif // defined(TARGET_OS_LINUX) | 462 #endif // defined(TARGET_OS_LINUX) |
| OLD | NEW |