| 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_MACOS) | 6 #if defined(TARGET_OS_MACOS) | 
| 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/dartutils.h" | 
| 17 #include "bin/file.h" | 18 #include "bin/file.h" | 
| 18 #include "bin/platform.h" | 19 #include "bin/platform.h" | 
| 19 |  | 
| 20 #include "platform/signal_blocker.h" | 20 #include "platform/signal_blocker.h" | 
| 21 | 21 | 
| 22 |  | 
| 23 namespace dart { | 22 namespace dart { | 
| 24 namespace bin { | 23 namespace bin { | 
| 25 | 24 | 
|  | 25 PathBuffer::PathBuffer() : length_(0) { | 
|  | 26   data_ = calloc(PATH_MAX + 1, sizeof(char));  // NOLINT | 
|  | 27 } | 
| 26 | 28 | 
| 27 PathBuffer::PathBuffer() : length_(0) { | 29 | 
| 28   data_ = calloc(PATH_MAX + 1,  sizeof(char));  // NOLINT | 30 PathBuffer::~PathBuffer() { | 
|  | 31   free(data_); | 
| 29 } | 32 } | 
| 30 | 33 | 
|  | 34 | 
| 31 bool PathBuffer::AddW(const wchar_t* name) { | 35 bool PathBuffer::AddW(const wchar_t* name) { | 
| 32   UNREACHABLE(); | 36   UNREACHABLE(); | 
| 33   return false; | 37   return false; | 
| 34 } | 38 } | 
| 35 | 39 | 
|  | 40 | 
| 36 char* PathBuffer::AsString() const { | 41 char* PathBuffer::AsString() const { | 
| 37   return reinterpret_cast<char*>(data_); | 42   return reinterpret_cast<char*>(data_); | 
| 38 } | 43 } | 
| 39 | 44 | 
|  | 45 | 
| 40 wchar_t* PathBuffer::AsStringW() const { | 46 wchar_t* PathBuffer::AsStringW() const { | 
| 41   UNREACHABLE(); | 47   UNREACHABLE(); | 
| 42   return NULL; | 48   return NULL; | 
| 43 } | 49 } | 
| 44 | 50 | 
|  | 51 | 
|  | 52 const char* PathBuffer::AsScopedString() const { | 
|  | 53   return DartUtils::ScopedCopyCString(AsString()); | 
|  | 54 } | 
|  | 55 | 
|  | 56 | 
| 45 bool PathBuffer::Add(const char* name) { | 57 bool PathBuffer::Add(const char* name) { | 
| 46   char* data = AsString(); | 58   char* data = AsString(); | 
| 47   int written = snprintf(data + length_, | 59   int written = snprintf(data + length_, | 
| 48                          PATH_MAX - length_, | 60                          PATH_MAX - length_, | 
| 49                          "%s", | 61                          "%s", | 
| 50                          name); | 62                          name); | 
| 51   data[PATH_MAX] = '\0'; | 63   data[PATH_MAX] = '\0'; | 
| 52   if (written <= PATH_MAX - length_ && | 64   if ((written <= PATH_MAX - length_) && | 
| 53       written >= 0 && | 65       (written >= 0) && | 
| 54       static_cast<size_t>(written) == strlen(name)) { | 66       (static_cast<size_t>(written) == strlen(name))) { | 
| 55     length_ += written; | 67     length_ += written; | 
| 56     return true; | 68     return true; | 
| 57   } else { | 69   } else { | 
| 58     errno = ENAMETOOLONG; | 70     errno = ENAMETOOLONG; | 
| 59     return false; | 71     return false; | 
| 60   } | 72   } | 
| 61 } | 73 } | 
| 62 | 74 | 
| 63 void PathBuffer::Reset(int new_length) { | 75 | 
|  | 76 void PathBuffer::Reset(intptr_t new_length) { | 
| 64   length_ = new_length; | 77   length_ = new_length; | 
| 65   AsString()[length_] = '\0'; | 78   AsString()[length_] = '\0'; | 
| 66 } | 79 } | 
| 67 | 80 | 
| 68 | 81 | 
| 69 // A linked list of symbolic links, with their unique file system identifiers. | 82 // A linked list of symbolic links, with their unique file system identifiers. | 
| 70 // These are scanned to detect loops while doing a recursive directory listing. | 83 // These are scanned to detect loops while doing a recursive directory listing. | 
| 71 struct LinkList { | 84 struct LinkList { | 
| 72   dev_t dev; | 85   dev_t dev; | 
| 73   ino_t ino; | 86   ino_t ino; | 
| 74   LinkList* next; | 87   LinkList* next; | 
| 75 }; | 88 }; | 
| 76 | 89 | 
| 77 | 90 | 
| 78 ListType DirectoryListingEntry::Next(DirectoryListing* listing) { | 91 ListType DirectoryListingEntry::Next(DirectoryListing* listing) { | 
| 79   if (done_) { | 92   if (done_) { | 
| 80     return kListDone; | 93     return kListDone; | 
| 81   } | 94   } | 
| 82 | 95 | 
| 83   if (lister_ == 0) { | 96   if (lister_ == 0) { | 
| 84     do { | 97     do { | 
| 85       lister_ = reinterpret_cast<intptr_t>( | 98       lister_ = reinterpret_cast<intptr_t>( | 
| 86           opendir(listing->path_buffer().AsString())); | 99           opendir(listing->path_buffer().AsString())); | 
| 87     } while (lister_ == 0 && errno == EINTR); | 100     } while ((lister_ == 0) && (errno == EINTR)); | 
| 88 | 101 | 
| 89     if (lister_ == 0) { | 102     if (lister_ == 0) { | 
| 90       done_ = true; | 103       done_ = true; | 
| 91       return kListError; | 104       return kListError; | 
| 92     } | 105     } | 
| 93     if (parent_ != NULL) { | 106     if (parent_ != NULL) { | 
| 94       if (!listing->path_buffer().Add(File::PathSeparator())) { | 107       if (!listing->path_buffer().Add(File::PathSeparator())) { | 
| 95         return kListError; | 108         return kListError; | 
| 96       } | 109       } | 
| 97     } | 110     } | 
| 98     path_length_ = listing->path_buffer().length(); | 111     path_length_ = listing->path_buffer().length(); | 
| 99   } | 112   } | 
| 100   // Reset. | 113   // Reset. | 
| 101   listing->path_buffer().Reset(path_length_); | 114   listing->path_buffer().Reset(path_length_); | 
| 102   ResetLink(); | 115   ResetLink(); | 
| 103 | 116 | 
| 104   // Iterate the directory and post the directories and files to the | 117   // Iterate the directory and post the directories and files to the | 
| 105   // ports. | 118   // ports. | 
| 106   int status = 0; | 119   int status = 0; | 
| 107   dirent entry; | 120   dirent entry; | 
| 108   dirent* result; | 121   dirent* result; | 
| 109   if ((status = NO_RETRY_EXPECTED(readdir_r(reinterpret_cast<DIR*>(lister_), | 122   status = NO_RETRY_EXPECTED(readdir_r( | 
| 110                                             &entry, | 123       reinterpret_cast<DIR*>(lister_), &entry, &result)); | 
| 111                                             &result))) == 0 && | 124   if ((status == 0) && (result != NULL)) { | 
| 112       result != NULL) { |  | 
| 113     if (!listing->path_buffer().Add(entry.d_name)) { | 125     if (!listing->path_buffer().Add(entry.d_name)) { | 
| 114       done_ = true; | 126       done_ = true; | 
| 115       return kListError; | 127       return kListError; | 
| 116     } | 128     } | 
| 117     switch (entry.d_type) { | 129     switch (entry.d_type) { | 
| 118       case DT_DIR: | 130       case DT_DIR: | 
| 119         if (strcmp(entry.d_name, ".") == 0) return Next(listing); | 131         if ((strcmp(entry.d_name, ".") == 0) || | 
| 120         if (strcmp(entry.d_name, "..") == 0) return Next(listing); | 132             (strcmp(entry.d_name, "..") == 0)) { | 
|  | 133           return Next(listing); | 
|  | 134         } | 
| 121         return kListDirectory; | 135         return kListDirectory; | 
| 122       case DT_REG: | 136       case DT_REG: | 
| 123         return kListFile; | 137         return kListFile; | 
| 124       case DT_LNK: | 138       case DT_LNK: | 
| 125         if (!listing->follow_links()) { | 139         if (!listing->follow_links()) { | 
| 126           return kListLink; | 140           return kListLink; | 
| 127         } | 141         } | 
| 128         // Else fall through to next case. | 142         // Else fall through to next case. | 
| 129         // Fall through. | 143         // Fall through. | 
| 130       case DT_UNKNOWN: { | 144       case DT_UNKNOWN: { | 
| 131         // On some file systems the entry type is not determined by | 145         // On some file systems the entry type is not determined by | 
| 132         // readdir_r. For those and for links we use stat to determine | 146         // readdir_r. For those and for links we use stat to determine | 
| 133         // the actual entry type. Notice that stat returns the type of | 147         // the actual entry type. Notice that stat returns the type of | 
| 134         // the file pointed to. | 148         // the file pointed to. | 
| 135         struct stat entry_info; | 149         struct stat entry_info; | 
| 136         int stat_success; | 150         int stat_success; | 
| 137         stat_success = NO_RETRY_EXPECTED( | 151         stat_success = NO_RETRY_EXPECTED( | 
| 138             lstat(listing->path_buffer().AsString(), &entry_info)); | 152             lstat(listing->path_buffer().AsString(), &entry_info)); | 
| 139         if (stat_success == -1) { | 153         if (stat_success == -1) { | 
| 140           return kListError; | 154           return kListError; | 
| 141         } | 155         } | 
| 142         if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) { | 156         if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) { | 
| 143           // Check to see if we are in a loop created by a symbolic link. | 157           // Check to see if we are in a loop created by a symbolic link. | 
| 144           LinkList current_link = { entry_info.st_dev, | 158           LinkList current_link = { entry_info.st_dev, | 
| 145                                     entry_info.st_ino, | 159                                     entry_info.st_ino, | 
| 146                                     link_ }; | 160                                     link_ }; | 
| 147           LinkList* previous = link_; | 161           LinkList* previous = link_; | 
| 148           while (previous != NULL) { | 162           while (previous != NULL) { | 
| 149             if (previous->dev == current_link.dev && | 163             if ((previous->dev == current_link.dev) && | 
| 150                 previous->ino == current_link.ino) { | 164                 (previous->ino == current_link.ino)) { | 
| 151               // Report the looping link as a link, rather than following it. | 165               // Report the looping link as a link, rather than following it. | 
| 152               return kListLink; | 166               return kListLink; | 
| 153             } | 167             } | 
| 154             previous = previous->next; | 168             previous = previous->next; | 
| 155           } | 169           } | 
| 156           stat_success = NO_RETRY_EXPECTED( | 170           stat_success = NO_RETRY_EXPECTED( | 
| 157               stat(listing->path_buffer().AsString(), &entry_info)); | 171               stat(listing->path_buffer().AsString(), &entry_info)); | 
| 158           if (stat_success == -1) { | 172           if (stat_success == -1) { | 
| 159             // Report a broken link as a link, even if follow_links is true. | 173             // Report a broken link as a link, even if follow_links is true. | 
| 160             return kListLink; | 174             return kListLink; | 
| 161           } | 175           } | 
| 162           if (S_ISDIR(entry_info.st_mode)) { | 176           if (S_ISDIR(entry_info.st_mode)) { | 
| 163             // Recurse into the subdirectory with current_link added to the | 177             // Recurse into the subdirectory with current_link added to the | 
| 164             // linked list of seen file system links. | 178             // linked list of seen file system links. | 
| 165             link_ = new LinkList(current_link); | 179             link_ = new LinkList(current_link); | 
| 166             if (strcmp(entry.d_name, ".") == 0) return Next(listing); | 180             if ((strcmp(entry.d_name, ".") == 0) || | 
| 167             if (strcmp(entry.d_name, "..") == 0) return Next(listing); | 181                 (strcmp(entry.d_name, "..") == 0)) { | 
|  | 182               return Next(listing); | 
|  | 183             } | 
| 168             return kListDirectory; | 184             return kListDirectory; | 
| 169           } | 185           } | 
| 170         } | 186         } | 
| 171         if (S_ISDIR(entry_info.st_mode)) { | 187         if (S_ISDIR(entry_info.st_mode)) { | 
| 172           if (strcmp(entry.d_name, ".") == 0) return Next(listing); | 188           if ((strcmp(entry.d_name, ".") == 0) || | 
| 173           if (strcmp(entry.d_name, "..") == 0) return Next(listing); | 189               (strcmp(entry.d_name, "..") == 0)) { | 
|  | 190             return Next(listing); | 
|  | 191           } | 
| 174           return kListDirectory; | 192           return kListDirectory; | 
| 175         } else if (S_ISREG(entry_info.st_mode)) { | 193         } else if (S_ISREG(entry_info.st_mode)) { | 
| 176           return kListFile; | 194           return kListFile; | 
| 177         } else if (S_ISLNK(entry_info.st_mode)) { | 195         } else if (S_ISLNK(entry_info.st_mode)) { | 
| 178           return kListLink; | 196           return kListLink; | 
| 179         } | 197         } | 
| 180       } | 198       } | 
| 181 | 199 | 
| 182       default: | 200       default: | 
| 183         break; | 201         break; | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 196 | 214 | 
| 197 DirectoryListingEntry::~DirectoryListingEntry() { | 215 DirectoryListingEntry::~DirectoryListingEntry() { | 
| 198   ResetLink(); | 216   ResetLink(); | 
| 199   if (lister_ != 0) { | 217   if (lister_ != 0) { | 
| 200     closedir(reinterpret_cast<DIR*>(lister_)); | 218     closedir(reinterpret_cast<DIR*>(lister_)); | 
| 201   } | 219   } | 
| 202 } | 220 } | 
| 203 | 221 | 
| 204 | 222 | 
| 205 void DirectoryListingEntry::ResetLink() { | 223 void DirectoryListingEntry::ResetLink() { | 
| 206   if (link_ != NULL && (parent_ == NULL || parent_->link_ != link_)) { | 224   if ((link_ != NULL) && ((parent_ == NULL) || (parent_->link_ != link_))) { | 
| 207     delete link_; | 225     delete link_; | 
| 208     link_ = NULL; | 226     link_ = NULL; | 
| 209   } | 227   } | 
| 210   if (parent_ != NULL) { | 228   if (parent_ != NULL) { | 
| 211     link_ = parent_->link_; | 229     link_ = parent_->link_; | 
| 212   } | 230   } | 
| 213 } | 231 } | 
| 214 | 232 | 
| 215 | 233 | 
| 216 static bool DeleteRecursively(PathBuffer* path); | 234 static bool DeleteRecursively(PathBuffer* path); | 
| 217 | 235 | 
| 218 | 236 | 
| 219 static bool DeleteFile(char* file_name, | 237 static bool DeleteFile(char* file_name, | 
| 220                        PathBuffer* path) { | 238                        PathBuffer* path) { | 
| 221   return path->Add(file_name) && unlink(path->AsString()) == 0; | 239   return path->Add(file_name) && (unlink(path->AsString()) == 0); | 
| 222 } | 240 } | 
| 223 | 241 | 
| 224 | 242 | 
| 225 static bool DeleteDir(char* dir_name, | 243 static bool DeleteDir(char* dir_name, | 
| 226                       PathBuffer* path) { | 244                       PathBuffer* path) { | 
| 227   if (strcmp(dir_name, ".") == 0) return true; | 245   if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) { | 
| 228   if (strcmp(dir_name, "..") == 0) return true; | 246     return true; | 
|  | 247   } | 
| 229   return path->Add(dir_name) && DeleteRecursively(path); | 248   return path->Add(dir_name) && DeleteRecursively(path); | 
| 230 } | 249 } | 
| 231 | 250 | 
| 232 | 251 | 
| 233 static bool DeleteRecursively(PathBuffer* path) { | 252 static bool DeleteRecursively(PathBuffer* path) { | 
| 234   // Do not recurse into links for deletion. Instead delete the link. | 253   // Do not recurse into links for deletion. Instead delete the link. | 
| 235   // If it's a file, delete it. | 254   // If it's a file, delete it. | 
| 236   struct stat st; | 255   struct stat st; | 
| 237   if (NO_RETRY_EXPECTED(lstat(path->AsString(), &st)) == -1) { | 256   if (NO_RETRY_EXPECTED(lstat(path->AsString(), &st)) == -1) { | 
| 238     return false; | 257     return false; | 
| 239   } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { | 258   } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { | 
| 240     return (unlink(path->AsString()) == 0); | 259     return (unlink(path->AsString()) == 0); | 
| 241   } | 260   } | 
| 242 | 261 | 
| 243   if (!path->Add(File::PathSeparator())) return false; | 262   if (!path->Add(File::PathSeparator())) { | 
|  | 263     return false; | 
|  | 264   } | 
| 244 | 265 | 
| 245   // Not a link. Attempt to open as a directory and recurse into the | 266   // Not a link. Attempt to open as a directory and recurse into the | 
| 246   // directory. | 267   // directory. | 
| 247   DIR* dir_pointer; | 268   DIR* dir_pointer; | 
| 248   do { | 269   do { | 
| 249     dir_pointer = opendir(path->AsString()); | 270     dir_pointer = opendir(path->AsString()); | 
| 250   } while (dir_pointer == NULL && errno == EINTR); | 271   } while ((dir_pointer == NULL) && (errno == EINTR)); | 
| 251   if (dir_pointer == NULL) { | 272   if (dir_pointer == NULL) { | 
| 252     return false; | 273     return false; | 
| 253   } | 274   } | 
| 254 | 275 | 
| 255   // Iterate the directory and delete all files and directories. | 276   // Iterate the directory and delete all files and directories. | 
| 256   int path_length = path->length(); | 277   int path_length = path->length(); | 
| 257   dirent entry; | 278   dirent entry; | 
| 258   dirent* result; | 279   dirent* result; | 
| 259   while (NO_RETRY_EXPECTED(readdir_r(dir_pointer, &entry, &result)) == 0) { | 280   while (NO_RETRY_EXPECTED(readdir_r(dir_pointer, &entry, &result)) == 0) { | 
| 260     if (result == NULL) { | 281     if (result == NULL) { | 
| 261       // End of directory. | 282       // End of directory. | 
| 262       return NO_RETRY_EXPECTED(closedir(dir_pointer)) == 0 && | 283       return (NO_RETRY_EXPECTED(closedir(dir_pointer)) == 0) && | 
| 263           NO_RETRY_EXPECTED(remove(path->AsString())) == 0; | 284              (NO_RETRY_EXPECTED(remove(path->AsString())) == 0); | 
| 264     } | 285     } | 
| 265     bool ok = false; | 286     bool ok = false; | 
| 266     switch (entry.d_type) { | 287     switch (entry.d_type) { | 
| 267       case DT_DIR: | 288       case DT_DIR: | 
| 268         ok = DeleteDir(entry.d_name, path); | 289         ok = DeleteDir(entry.d_name, path); | 
| 269         break; | 290         break; | 
| 270       case DT_REG: | 291       case DT_REG: | 
| 271       case DT_LNK: | 292       case DT_LNK: | 
| 272         // Treat all links as files. This will delete the link which | 293         // Treat all links as files. This will delete the link which | 
| 273         // is what we want no matter if the link target is a file or a | 294         // is what we want no matter if the link target is a file or a | 
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 316 Directory::ExistsResult Directory::Exists(const char* dir_name) { | 337 Directory::ExistsResult Directory::Exists(const char* dir_name) { | 
| 317   struct stat entry_info; | 338   struct stat entry_info; | 
| 318   int success = NO_RETRY_EXPECTED(stat(dir_name, &entry_info)); | 339   int success = NO_RETRY_EXPECTED(stat(dir_name, &entry_info)); | 
| 319   if (success == 0) { | 340   if (success == 0) { | 
| 320     if (S_ISDIR(entry_info.st_mode)) { | 341     if (S_ISDIR(entry_info.st_mode)) { | 
| 321       return EXISTS; | 342       return EXISTS; | 
| 322     } else { | 343     } else { | 
| 323       return DOES_NOT_EXIST; | 344       return DOES_NOT_EXIST; | 
| 324     } | 345     } | 
| 325   } else { | 346   } else { | 
| 326     if (errno == EACCES || | 347     if ((errno == EACCES) || | 
| 327         errno == EBADF || | 348         (errno == EBADF) || | 
| 328         errno == EFAULT || | 349         (errno == EFAULT) || | 
| 329         errno == ENOMEM || | 350         (errno == ENOMEM) || | 
| 330         errno == EOVERFLOW) { | 351         (errno == EOVERFLOW)) { | 
| 331       // Search permissions denied for one of the directories in the | 352       // Search permissions denied for one of the directories in the | 
| 332       // path or a low level error occured. We do not know if the | 353       // path or a low level error occured. We do not know if the | 
| 333       // directory exists. | 354       // directory exists. | 
| 334       return UNKNOWN; | 355       return UNKNOWN; | 
| 335     } | 356     } | 
| 336     ASSERT(errno == ELOOP || | 357     ASSERT((errno == ELOOP) || | 
| 337            errno == ENAMETOOLONG || | 358            (errno == ENAMETOOLONG) || | 
| 338            errno == ENOENT || | 359            (errno == ENOENT) || | 
| 339            errno == ENOTDIR); | 360            (errno == ENOTDIR)); | 
| 340     return DOES_NOT_EXIST; | 361     return DOES_NOT_EXIST; | 
| 341   } | 362   } | 
| 342 } | 363 } | 
| 343 | 364 | 
| 344 | 365 | 
| 345 char* Directory::Current() { | 366 char* Directory::CurrentNoScope() { | 
| 346   return getcwd(NULL, 0); | 367   return getcwd(NULL, 0); | 
| 347 } | 368 } | 
| 348 | 369 | 
| 349 | 370 | 
|  | 371 const char* Directory::Current() { | 
|  | 372   char* result = DartUtils::ScopedCString(PATH_MAX); | 
|  | 373   ASSERT(result != NULL); | 
|  | 374   return getcwd(result, PATH_MAX); | 
|  | 375 } | 
|  | 376 | 
|  | 377 | 
| 350 bool Directory::SetCurrent(const char* path) { | 378 bool Directory::SetCurrent(const char* path) { | 
| 351   int result = NO_RETRY_EXPECTED(chdir(path)); | 379   int result = NO_RETRY_EXPECTED(chdir(path)); | 
| 352   return result == 0; | 380   return result == 0; | 
| 353 } | 381 } | 
| 354 | 382 | 
| 355 | 383 | 
| 356 bool Directory::Create(const char* dir_name) { | 384 bool Directory::Create(const char* dir_name) { | 
| 357   // Create the directory with the permissions specified by the | 385   // Create the directory with the permissions specified by the | 
| 358   // process umask. | 386   // process umask. | 
| 359   int result = NO_RETRY_EXPECTED(mkdir(dir_name, 0777)); | 387   int result = NO_RETRY_EXPECTED(mkdir(dir_name, 0777)); | 
| 360   // If the directory already exists, treat it as a success. | 388   // If the directory already exists, treat it as a success. | 
| 361   if (result == -1 && errno == EEXIST) { | 389   if ((result == -1) && (errno == EEXIST)) { | 
| 362     return (Exists(dir_name) == EXISTS); | 390     return (Exists(dir_name) == EXISTS); | 
| 363   } | 391   } | 
| 364   return (result == 0); | 392   return (result == 0); | 
| 365 } | 393 } | 
| 366 | 394 | 
| 367 | 395 | 
| 368 char* Directory::SystemTemp() { | 396 const char* Directory::SystemTemp() { | 
|  | 397   PathBuffer path; | 
| 369   const char* temp_dir = getenv("TMPDIR"); | 398   const char* temp_dir = getenv("TMPDIR"); | 
| 370   if (temp_dir == NULL) { | 399   if (temp_dir == NULL) { | 
| 371     temp_dir = getenv("TMP"); | 400     temp_dir = getenv("TMP"); | 
| 372   } | 401   } | 
| 373   if (temp_dir == NULL) { | 402   if (temp_dir == NULL) { | 
| 374     temp_dir = "/tmp"; | 403     temp_dir = "/tmp"; | 
| 375   } | 404   } | 
| 376   char* result = strdup(temp_dir); | 405   if (!path.Add(temp_dir)) { | 
|  | 406     return NULL; | 
|  | 407   } | 
| 377   // Remove any trailing slash. | 408   // Remove any trailing slash. | 
|  | 409   char* result = path.AsString(); | 
| 378   int length = strlen(result); | 410   int length = strlen(result); | 
| 379   if (length > 1 && result[length - 1] == '/') { | 411   if ((length > 1) && (result[length - 1] == '/')) { | 
| 380     result[length - 1] = '\0'; | 412     result[length - 1] = '\0'; | 
| 381   } | 413   } | 
| 382   return result; | 414   return path.AsScopedString(); | 
| 383 } | 415 } | 
| 384 | 416 | 
| 385 | 417 | 
| 386 char* Directory::CreateTemp(const char* prefix) { | 418 const char* Directory::CreateTemp(const char* prefix) { | 
| 387   // Returns a new, unused directory name, adding characters to the end | 419   // Returns a new, unused directory name, adding characters to the end | 
| 388   // of prefix.  Creates the directory with the permissions specified | 420   // of prefix.  Creates the directory with the permissions specified | 
| 389   // by the process umask. | 421   // by the process umask. | 
| 390   // The return value must be freed by the caller. | 422   // The return value is Dart_ScopeAllocated. | 
| 391   PathBuffer path; | 423   PathBuffer path; | 
| 392   path.Add(prefix); | 424   if (!path.Add(prefix)) { | 
|  | 425     return NULL; | 
|  | 426   } | 
| 393   if (!path.Add("XXXXXX")) { | 427   if (!path.Add("XXXXXX")) { | 
| 394     // Pattern has overflowed. | 428     // Pattern has overflowed. | 
| 395     return NULL; | 429     return NULL; | 
| 396   } | 430   } | 
| 397   char* result; | 431   char* result; | 
| 398   do { | 432   do { | 
| 399     result = mkdtemp(path.AsString()); | 433     result = mkdtemp(path.AsString()); | 
| 400   } while (result == NULL && errno == EINTR); | 434   } while ((result == NULL) && (errno == EINTR)); | 
| 401   if (result == NULL) { | 435   if (result == NULL) { | 
| 402     return NULL; | 436     return NULL; | 
| 403   } | 437   } | 
| 404   return strdup(result); | 438   return path.AsScopedString(); | 
| 405 } | 439 } | 
| 406 | 440 | 
| 407 | 441 | 
| 408 bool Directory::Delete(const char* dir_name, bool recursive) { | 442 bool Directory::Delete(const char* dir_name, bool recursive) { | 
| 409   if (!recursive) { | 443   if (!recursive) { | 
| 410     if (File::GetType(dir_name, false) == File::kIsLink && | 444     if ((File::GetType(dir_name, false) == File::kIsLink) && | 
| 411         File::GetType(dir_name, true) == File::kIsDirectory) { | 445         (File::GetType(dir_name, true) == File::kIsDirectory)) { | 
| 412       return (NO_RETRY_EXPECTED(unlink(dir_name)) == 0); | 446       return (NO_RETRY_EXPECTED(unlink(dir_name)) == 0); | 
| 413     } | 447     } | 
| 414     return (NO_RETRY_EXPECTED(rmdir(dir_name)) == 0); | 448     return (NO_RETRY_EXPECTED(rmdir(dir_name)) == 0); | 
| 415   } else { | 449   } else { | 
| 416     PathBuffer path; | 450     PathBuffer path; | 
| 417     if (!path.Add(dir_name)) { | 451     if (!path.Add(dir_name)) { | 
| 418       return false; | 452       return false; | 
| 419     } | 453     } | 
| 420     return DeleteRecursively(&path); | 454     return DeleteRecursively(&path); | 
| 421   } | 455   } | 
| 422 } | 456 } | 
| 423 | 457 | 
| 424 | 458 | 
| 425 bool Directory::Rename(const char* path, const char* new_path) { | 459 bool Directory::Rename(const char* path, const char* new_path) { | 
| 426   ExistsResult exists = Exists(path); | 460   ExistsResult exists = Exists(path); | 
| 427   if (exists != EXISTS) return false; | 461   if (exists != EXISTS) { | 
|  | 462     return false; | 
|  | 463   } | 
| 428   return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); | 464   return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); | 
| 429 } | 465 } | 
| 430 | 466 | 
| 431 }  // namespace bin | 467 }  // namespace bin | 
| 432 }  // namespace dart | 468 }  // namespace dart | 
| 433 | 469 | 
| 434 #endif  // defined(TARGET_OS_MACOS) | 470 #endif  // defined(TARGET_OS_MACOS) | 
| OLD | NEW | 
|---|