blob: 4216e849d0aa5e0cdd473dce0122ffaa9c0cab81 [file] [log] [blame]
// 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.
#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 {
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_; }
void* data_;
intptr_t length_;
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 {
explicit DirectoryListingEntry(DirectoryListingEntry* parent)
: parent_(parent), fd_(-1), lister_(0), done_(false), link_(NULL) {}
ListType Next(DirectoryListing* listing);
DirectoryListingEntry* parent() const { return parent_; }
LinkList* link() { return link_; }
void set_link(LinkList* link) { link_ = link; }
void ResetLink();
DirectoryListingEntry* parent_;
intptr_t fd_;
intptr_t lister_;
bool done_;
int path_length_;
LinkList* link_;
class DirectoryListing {
DirectoryListing(Namespace* namespc,
const char* dir_name,
bool recursive,
bool follow_links)
: namespc_(namespc),
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() {
DirectoryListingEntry* current = top_;
top_ = top_->parent();
delete current;
bool IsEmpty() const { return top_ == NULL; }
void PopAll() {
while (!IsEmpty()) {
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_; }
PathBuffer path_buffer_;
Namespace* namespc_;
DirectoryListingEntry* top_;
bool error_;
bool recursive_;
bool follow_links_;
class AsyncDirectoryListing : public ReferenceCounted<AsyncDirectoryListing>,
public DirectoryListing {
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),
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_; }
virtual ~AsyncDirectoryListing() {}
bool AddFileSystemEntityToResponse(Response response, const char* arg);
CObjectArray* array_;
intptr_t index_;
intptr_t length_;
friend class ReferenceCounted<AsyncDirectoryListing>;
class SyncDirectoryListing : public DirectoryListing {
SyncDirectoryListing(Dart_Handle results,
Namespace* namespc,
const char* dir_name,
bool recursive,
bool follow_links)
: DirectoryListing(namespc, dir_name, recursive, follow_links),
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_; }
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_;
class Directory {
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);
static char* system_temp_path_override_;
} // namespace bin
} // namespace dart