|  | // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | #ifndef RUNTIME_BIN_DIRECTORY_H_ | 
|  | #define RUNTIME_BIN_DIRECTORY_H_ | 
|  |  | 
|  | #include "bin/builtin.h" | 
|  | #include "bin/dartutils.h" | 
|  | #include "bin/namespace.h" | 
|  | #include "bin/reference_counting.h" | 
|  | #include "bin/thread.h" | 
|  | #include "platform/globals.h" | 
|  |  | 
|  | namespace dart { | 
|  | namespace bin { | 
|  |  | 
|  | enum ListType { | 
|  | kListFile = 0, | 
|  | kListDirectory = 1, | 
|  | kListLink = 2, | 
|  | kListError = 3, | 
|  | kListDone = 4 | 
|  | }; | 
|  |  | 
|  | class PathBuffer { | 
|  | public: | 
|  | PathBuffer(); | 
|  | ~PathBuffer(); | 
|  |  | 
|  | bool Add(const char* name); | 
|  | bool AddW(const wchar_t* name); | 
|  |  | 
|  | char* AsString() const; | 
|  | wchar_t* AsStringW() const; | 
|  |  | 
|  | // Makes a scope allocated copy of the string. | 
|  | const char* AsScopedString() const; | 
|  |  | 
|  | void Reset(intptr_t new_length); | 
|  |  | 
|  | intptr_t length() const { return length_; } | 
|  |  | 
|  | private: | 
|  | void* data_; | 
|  | intptr_t length_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(PathBuffer); | 
|  | }; | 
|  |  | 
|  | class DirectoryListing; | 
|  |  | 
|  | struct LinkList; | 
|  |  | 
|  | // DirectoryListingEntry is used as a stack item, when performing recursive | 
|  | // directory listing. By using DirectoryListingEntry as stack elements, a | 
|  | // directory listing can be paused e.g. when a buffer is full, and resumed | 
|  | // later on. | 
|  | // | 
|  | // The stack is managed by the DirectoryListing's PathBuffer. Each | 
|  | // DirectoryListingEntry stored a entry-length, that it'll reset the PathBuffer | 
|  | // to on each call to Next. | 
|  | class DirectoryListingEntry { | 
|  | public: | 
|  | explicit DirectoryListingEntry(DirectoryListingEntry* parent) | 
|  | : parent_(parent), fd_(-1), lister_(0), done_(false), link_(NULL) {} | 
|  |  | 
|  | ~DirectoryListingEntry(); | 
|  |  | 
|  | ListType Next(DirectoryListing* listing); | 
|  |  | 
|  | DirectoryListingEntry* parent() const { return parent_; } | 
|  |  | 
|  | LinkList* link() { return link_; } | 
|  |  | 
|  | void set_link(LinkList* link) { link_ = link; } | 
|  |  | 
|  | void ResetLink(); | 
|  |  | 
|  | private: | 
|  | DirectoryListingEntry* parent_; | 
|  | intptr_t fd_; | 
|  | intptr_t lister_; | 
|  | bool done_; | 
|  | int path_length_; | 
|  | LinkList* link_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(DirectoryListingEntry); | 
|  | }; | 
|  |  | 
|  | class DirectoryListing { | 
|  | public: | 
|  | DirectoryListing(Namespace* namespc, | 
|  | const char* dir_name, | 
|  | bool recursive, | 
|  | bool follow_links) | 
|  | : namespc_(namespc), | 
|  | top_(NULL), | 
|  | error_(false), | 
|  | recursive_(recursive), | 
|  | follow_links_(follow_links) { | 
|  | if (!path_buffer_.Add(dir_name)) { | 
|  | error_ = true; | 
|  | } | 
|  | Push(new DirectoryListingEntry(NULL)); | 
|  | } | 
|  |  | 
|  | virtual ~DirectoryListing() { PopAll(); } | 
|  |  | 
|  | virtual bool HandleDirectory(const char* dir_name) = 0; | 
|  | virtual bool HandleFile(const char* file_name) = 0; | 
|  | virtual bool HandleLink(const char* link_name) = 0; | 
|  | virtual bool HandleError() = 0; | 
|  | virtual void HandleDone() {} | 
|  |  | 
|  | void Push(DirectoryListingEntry* directory) { top_ = directory; } | 
|  |  | 
|  | void Pop() { | 
|  | ASSERT(!IsEmpty()); | 
|  | DirectoryListingEntry* current = top_; | 
|  | top_ = top_->parent(); | 
|  | delete current; | 
|  | } | 
|  |  | 
|  | bool IsEmpty() const { return top_ == NULL; } | 
|  |  | 
|  | void PopAll() { | 
|  | while (!IsEmpty()) { | 
|  | Pop(); | 
|  | } | 
|  | } | 
|  |  | 
|  | Namespace* namespc() const { return namespc_; } | 
|  |  | 
|  | DirectoryListingEntry* top() const { return top_; } | 
|  |  | 
|  | bool recursive() const { return recursive_; } | 
|  |  | 
|  | bool follow_links() const { return follow_links_; } | 
|  |  | 
|  | const char* CurrentPath() { return path_buffer_.AsScopedString(); } | 
|  |  | 
|  | PathBuffer& path_buffer() { return path_buffer_; } | 
|  |  | 
|  | bool error() const { return error_; } | 
|  |  | 
|  | private: | 
|  | PathBuffer path_buffer_; | 
|  | Namespace* namespc_; | 
|  | DirectoryListingEntry* top_; | 
|  | bool error_; | 
|  | bool recursive_; | 
|  | bool follow_links_; | 
|  | }; | 
|  |  | 
|  | class AsyncDirectoryListing : public ReferenceCounted<AsyncDirectoryListing>, | 
|  | public DirectoryListing { | 
|  | public: | 
|  | enum Response { | 
|  | kListFile = 0, | 
|  | kListDirectory = 1, | 
|  | kListLink = 2, | 
|  | kListError = 3, | 
|  | kListDone = 4 | 
|  | }; | 
|  |  | 
|  | AsyncDirectoryListing(Namespace* namespc, | 
|  | const char* dir_name, | 
|  | bool recursive, | 
|  | bool follow_links) | 
|  | : ReferenceCounted(), | 
|  | DirectoryListing(namespc, dir_name, recursive, follow_links), | 
|  | array_(NULL), | 
|  | index_(0), | 
|  | length_(0) {} | 
|  |  | 
|  | virtual bool HandleDirectory(const char* dir_name); | 
|  | virtual bool HandleFile(const char* file_name); | 
|  | virtual bool HandleLink(const char* file_name); | 
|  | virtual bool HandleError(); | 
|  | virtual void HandleDone(); | 
|  |  | 
|  | void SetArray(CObjectArray* array, intptr_t length) { | 
|  | ASSERT(length % 2 == 0); | 
|  | array_ = array; | 
|  | index_ = 0; | 
|  | length_ = length; | 
|  | } | 
|  |  | 
|  | intptr_t index() const { return index_; } | 
|  |  | 
|  | private: | 
|  | virtual ~AsyncDirectoryListing() {} | 
|  | bool AddFileSystemEntityToResponse(Response response, const char* arg); | 
|  | CObjectArray* array_; | 
|  | intptr_t index_; | 
|  | intptr_t length_; | 
|  |  | 
|  | friend class ReferenceCounted<AsyncDirectoryListing>; | 
|  | DISALLOW_IMPLICIT_CONSTRUCTORS(AsyncDirectoryListing); | 
|  | }; | 
|  |  | 
|  | class SyncDirectoryListing : public DirectoryListing { | 
|  | public: | 
|  | SyncDirectoryListing(Dart_Handle results, | 
|  | Namespace* namespc, | 
|  | const char* dir_name, | 
|  | bool recursive, | 
|  | bool follow_links) | 
|  | : DirectoryListing(namespc, dir_name, recursive, follow_links), | 
|  | results_(results), | 
|  | dart_error_(Dart_Null()) { | 
|  | add_string_ = DartUtils::NewString("add"); | 
|  | from_raw_path_string_ = DartUtils::NewString("fromRawPath"); | 
|  | directory_type_ = DartUtils::GetDartType(DartUtils::kIOLibURL, "Directory"); | 
|  | file_type_ = DartUtils::GetDartType(DartUtils::kIOLibURL, "File"); | 
|  | link_type_ = DartUtils::GetDartType(DartUtils::kIOLibURL, "Link"); | 
|  | } | 
|  | virtual ~SyncDirectoryListing() {} | 
|  | virtual bool HandleDirectory(const char* dir_name); | 
|  | virtual bool HandleFile(const char* file_name); | 
|  | virtual bool HandleLink(const char* file_name); | 
|  | virtual bool HandleError(); | 
|  |  | 
|  | Dart_Handle dart_error() { return dart_error_; } | 
|  |  | 
|  | private: | 
|  | Dart_Handle results_; | 
|  | Dart_Handle add_string_; | 
|  | Dart_Handle from_raw_path_string_; | 
|  | Dart_Handle directory_type_; | 
|  | Dart_Handle file_type_; | 
|  | Dart_Handle link_type_; | 
|  | Dart_Handle dart_error_; | 
|  |  | 
|  | DISALLOW_ALLOCATION() | 
|  | DISALLOW_IMPLICIT_CONSTRUCTORS(SyncDirectoryListing); | 
|  | }; | 
|  |  | 
|  | class Directory { | 
|  | public: | 
|  | enum ExistsResult { UNKNOWN, EXISTS, DOES_NOT_EXIST }; | 
|  |  | 
|  | static void List(DirectoryListing* listing); | 
|  | static ExistsResult Exists(Namespace* namespc, const char* path); | 
|  |  | 
|  | // Returns the current working directory. The caller must call | 
|  | // free() on the result. | 
|  | static char* CurrentNoScope(); | 
|  |  | 
|  | // Returns the current working directory. The returned string is allocated | 
|  | // with Dart_ScopeAllocate(). It lasts only as long as the current API scope. | 
|  | static const char* Current(Namespace* namespc); | 
|  | static const char* SystemTemp(Namespace* namespc); | 
|  | static const char* CreateTemp(Namespace* namespc, const char* path); | 
|  | // Set the system temporary directory. | 
|  | static void SetSystemTemp(const char* path); | 
|  | static bool SetCurrent(Namespace* namespc, const char* path); | 
|  | static bool Create(Namespace* namespc, const char* path); | 
|  | static bool Delete(Namespace* namespc, const char* path, bool recursive); | 
|  | static bool Rename(Namespace* namespc, | 
|  | const char* path, | 
|  | const char* new_path); | 
|  |  | 
|  | static CObject* CreateRequest(const CObjectArray& request); | 
|  | static CObject* DeleteRequest(const CObjectArray& request); | 
|  | static CObject* ExistsRequest(const CObjectArray& request); | 
|  | static CObject* CreateTempRequest(const CObjectArray& request); | 
|  | static CObject* CreateSystemTempRequest(const CObjectArray& request); | 
|  | static CObject* ListStartRequest(const CObjectArray& request); | 
|  | static CObject* ListNextRequest(const CObjectArray& request); | 
|  | static CObject* ListStopRequest(const CObjectArray& request); | 
|  | static CObject* RenameRequest(const CObjectArray& request); | 
|  |  | 
|  | private: | 
|  | static char* system_temp_path_override_; | 
|  | DISALLOW_ALLOCATION(); | 
|  | DISALLOW_IMPLICIT_CONSTRUCTORS(Directory); | 
|  | }; | 
|  |  | 
|  | }  // namespace bin | 
|  | }  // namespace dart | 
|  |  | 
|  | #endif  // RUNTIME_BIN_DIRECTORY_H_ |