| // 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 BIN_DIRECTORY_H_ |
| #define BIN_DIRECTORY_H_ |
| |
| #include "bin/builtin.h" |
| #include "bin/dartutils.h" |
| #include "bin/native_service.h" |
| #include "platform/globals.h" |
| #include "platform/thread.h" |
| |
| |
| namespace dart { |
| namespace bin { |
| |
| enum ListType { |
| kListFile = 0, |
| kListDirectory = 1, |
| kListLink = 2, |
| kListError = 3, |
| kListDone = 4 |
| }; |
| |
| class PathBuffer { |
| public: |
| PathBuffer(); |
| ~PathBuffer() { |
| free(data_); |
| } |
| |
| bool Add(const char* name); |
| bool AddW(const wchar_t* name); |
| |
| char* AsString() const; |
| wchar_t* AsStringW() const; |
| |
| void Reset(int new_length); |
| |
| int length() const { |
| return length_; |
| } |
| |
| private: |
| void* data_; |
| int 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), lister_(0), done_(false), link_(NULL) {} |
| |
| ~DirectoryListingEntry() { |
| ResetLink(); |
| } |
| |
| 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 lister_; |
| bool done_; |
| int path_length_; |
| LinkList* link_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DirectoryListingEntry); |
| }; |
| |
| class DirectoryListing { |
| public: |
| DirectoryListing(const char* dir_name, bool recursive, bool follow_links) |
| : top_(NULL), |
| error_(false), |
| recursive_(recursive), |
| follow_links_(follow_links) { |
| if (!path_buffer_.Add(dir_name)) { |
| error_ = true; |
| } |
| Push(new DirectoryListingEntry(NULL)); |
| } |
| |
| virtual ~DirectoryListing() { |
| while (!IsEmpty()) { |
| Pop(); |
| } |
| } |
| |
| virtual bool HandleDirectory(char* dir_name) = 0; |
| virtual bool HandleFile(char* file_name) = 0; |
| virtual bool HandleLink(char* link_name) = 0; |
| virtual bool HandleError(const char* dir_name) = 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; |
| } |
| |
| DirectoryListingEntry* top() const { |
| return top_; |
| } |
| |
| bool recursive() const { |
| return recursive_; |
| } |
| |
| bool follow_links() const { |
| return follow_links_; |
| } |
| |
| char* CurrentPath() { |
| return path_buffer_.AsString(); |
| } |
| |
| PathBuffer& path_buffer() { |
| return path_buffer_; |
| } |
| |
| bool error() const { |
| return error_; |
| } |
| |
| private: |
| PathBuffer path_buffer_; |
| DirectoryListingEntry* top_; |
| bool error_; |
| bool recursive_; |
| bool follow_links_; |
| }; |
| |
| |
| class AsyncDirectoryListing : public DirectoryListing { |
| public: |
| enum Response { |
| kListFile = 0, |
| kListDirectory = 1, |
| kListLink = 2, |
| kListError = 3, |
| kListDone = 4 |
| }; |
| |
| AsyncDirectoryListing(const char* dir_name, |
| bool recursive, |
| bool follow_links) |
| : DirectoryListing(dir_name, recursive, follow_links) {} |
| |
| virtual ~AsyncDirectoryListing() {} |
| virtual bool HandleDirectory(char* dir_name); |
| virtual bool HandleFile(char* file_name); |
| virtual bool HandleLink(char* file_name); |
| virtual bool HandleError(const char* dir_name); |
| 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: |
| bool AddFileSystemEntityToResponse(Response response, char* arg); |
| CObjectArray* array_; |
| intptr_t index_; |
| intptr_t length_; |
| |
| DISALLOW_IMPLICIT_CONSTRUCTORS(AsyncDirectoryListing); |
| }; |
| |
| |
| class SyncDirectoryListing: public DirectoryListing { |
| public: |
| SyncDirectoryListing(Dart_Handle results, |
| const char* dir_name, |
| bool recursive, |
| bool follow_links) |
| : DirectoryListing(dir_name, recursive, follow_links), |
| results_(results) { |
| add_string_ = DartUtils::NewString("add"); |
| 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(char* dir_name); |
| virtual bool HandleFile(char* file_name); |
| virtual bool HandleLink(char* file_name); |
| virtual bool HandleError(const char* dir_name); |
| |
| private: |
| Dart_Handle results_; |
| Dart_Handle add_string_; |
| Dart_Handle directory_type_; |
| Dart_Handle file_type_; |
| Dart_Handle link_type_; |
| |
| DISALLOW_IMPLICIT_CONSTRUCTORS(SyncDirectoryListing); |
| }; |
| |
| |
| class Directory { |
| public: |
| enum ExistsResult { |
| UNKNOWN, |
| EXISTS, |
| DOES_NOT_EXIST |
| }; |
| |
| // This enum must be kept in sync with the request values in |
| // directory_impl.dart. |
| enum DirectoryRequest { |
| kCreateRequest = 0, |
| kDeleteRequest = 1, |
| kExistsRequest = 2, |
| kCreateTempRequest = 3, |
| kListStartRequest = 4, |
| kListNextRequest = 5, |
| kListStopRequest = 6, |
| kRenameRequest = 7 |
| }; |
| |
| static void List(DirectoryListing* listing); |
| static ExistsResult Exists(const char* path); |
| static char* Current(); |
| static bool SetCurrent(const char* path); |
| static bool Create(const char* path); |
| static char* CreateTemp(const char* const_template); |
| static bool Delete(const char* path, bool recursive); |
| static bool Rename(const char* path, const char* new_path); |
| static Dart_Port GetServicePort(); |
| |
| private: |
| static NativeService directory_service_; |
| |
| DISALLOW_ALLOCATION(); |
| DISALLOW_IMPLICIT_CONSTRUCTORS(Directory); |
| }; |
| |
| } // namespace bin |
| } // namespace dart |
| |
| #endif // BIN_DIRECTORY_H_ |