Files
sdk/runtime/bin/directory.h
T
Zachary Anderson d0295c873c [dart:io] Namespaces for file IO
Fuchsia requires the ability to sandbox Isolates w.r.t. file IO.
When a new Isolate starts, Fuchsia will pass the Isolate an object
called a namespace. We can translate the namespace object into a
file descriptor suitable for passing to the *at() family of
POSIX file system calls. The file system calls will then
have visibility only into the specified namespace.

We also plumb Namespaces through on all the other platforms as well to
make the change easier to test and so that in the future we can
implement e.g. per-isolate cwds.

This change adds a new internal class to dart:io called _Namespace,
which is implemented in a patch file. See:

sdk/lib/io/namespace_impl.dart
runtime/bin/namespace_patch.dart

The embedder can set up a non-default namespace by calling
_Namespace._setupNamespace during Isolate setup.

Instances of _Namespace have a native field that holds a pointer
to a native Namespace object. See:

runtime/bin/namespace.h

Calls from e.g. file_impl.dart are now also passed a
_Namespace object. The implementations in e.g. file.cc and
file_linux.cc then extract the namespace, and use it to compute a
file descriptor and path suitable for passing to e.g. openat().

related US-313

R=asiva@google.com, rmacnak@google.com

Review-Url: https://codereview.chromium.org/3007703002 .
2017-08-30 09:34:36 -07:00

283 lines
7.9 KiB
C++

// 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");
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(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_