// 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/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), 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 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() { 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(); } } 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_; DirectoryListingEntry* top_; bool error_; bool recursive_; bool follow_links_; }; class AsyncDirectoryListing : public ReferenceCounted, 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) : ReferenceCounted(), DirectoryListing(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; 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), dart_error_(Dart_Null()) { 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(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 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(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(); static const char* SystemTemp(); static const char* CreateTemp(const char* path); // Set the system temporary directory. static void SetSystemTemp(const char* path); static bool SetCurrent(const char* path); static bool Create(const char* path); static bool Delete(const char* path, bool recursive); static bool Rename(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_