52230ca22b
The native ports use the snapshot reader to create the dart objects. Added support for reading external arrays from snapshots but no support for writing them. The only way an external array is written to a snapshot is through the api message writer. This allows dart:io to avoid one copy of data read from files and sockets. This change only contains one use of the new API. R=asiva@google.com,iposva@google.com BUG= TEST= Review URL: https://chromiumcodereview.appspot.com//10698011 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@9281 260f80e4-7a28-3924-810f-c04153c831b5
243 lines
5.1 KiB
C++
243 lines
5.1 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.
|
|
|
|
#include "bin/file.h"
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <libgen.h>
|
|
|
|
#include "bin/builtin.h"
|
|
|
|
class FileHandle {
|
|
public:
|
|
explicit FileHandle(int fd) : fd_(fd) { }
|
|
~FileHandle() { }
|
|
int fd() const { return fd_; }
|
|
void set_fd(int fd) { fd_ = fd; }
|
|
|
|
private:
|
|
int fd_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(FileHandle);
|
|
};
|
|
|
|
|
|
File::~File() {
|
|
// Close the file (unless it's a standard stream).
|
|
if (handle_->fd() > STDERR_FILENO) {
|
|
Close();
|
|
}
|
|
delete handle_;
|
|
}
|
|
|
|
|
|
void File::Close() {
|
|
ASSERT(handle_->fd() >= 0);
|
|
int err = TEMP_FAILURE_RETRY(close(handle_->fd()));
|
|
if (err != 0) {
|
|
const int kBufferSize = 1024;
|
|
char error_message[kBufferSize];
|
|
strerror_r(errno, error_message, kBufferSize);
|
|
fprintf(stderr, "%s\n", error_message);
|
|
}
|
|
handle_->set_fd(kClosedFd);
|
|
}
|
|
|
|
|
|
bool File::IsClosed() {
|
|
return handle_->fd() == kClosedFd;
|
|
}
|
|
|
|
|
|
int64_t File::Read(void* buffer, int64_t num_bytes) {
|
|
ASSERT(handle_->fd() >= 0);
|
|
return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes));
|
|
}
|
|
|
|
|
|
int64_t File::Write(const void* buffer, int64_t num_bytes) {
|
|
ASSERT(handle_->fd() >= 0);
|
|
return TEMP_FAILURE_RETRY(write(handle_->fd(), buffer, num_bytes));
|
|
}
|
|
|
|
|
|
off_t File::Position() {
|
|
ASSERT(handle_->fd() >= 0);
|
|
return TEMP_FAILURE_RETRY(lseek(handle_->fd(), 0, SEEK_CUR));
|
|
}
|
|
|
|
|
|
bool File::SetPosition(int64_t position) {
|
|
ASSERT(handle_->fd() >= 0);
|
|
return TEMP_FAILURE_RETRY(lseek(handle_->fd(), position, SEEK_SET) != -1);
|
|
}
|
|
|
|
|
|
bool File::Truncate(int64_t length) {
|
|
ASSERT(handle_->fd() >= 0);
|
|
return TEMP_FAILURE_RETRY(ftruncate(handle_->fd(), length) != -1);
|
|
}
|
|
|
|
|
|
bool File::Flush() {
|
|
ASSERT(handle_->fd() >= 0);
|
|
return TEMP_FAILURE_RETRY(fsync(handle_->fd()) != -1);
|
|
}
|
|
|
|
|
|
off_t File::Length() {
|
|
ASSERT(handle_->fd() >= 0);
|
|
struct stat st;
|
|
if (TEMP_FAILURE_RETRY(fstat(handle_->fd(), &st)) == 0) {
|
|
return st.st_size;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
File* File::Open(const char* name, FileOpenMode mode) {
|
|
// Report errors for non-regular files.
|
|
struct stat st;
|
|
if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
|
|
if (!S_ISREG(st.st_mode)) {
|
|
errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
|
|
return NULL;
|
|
}
|
|
}
|
|
int flags = O_RDONLY;
|
|
if ((mode & kWrite) != 0) {
|
|
flags = (O_RDWR | O_CREAT);
|
|
}
|
|
if ((mode & kTruncate) != 0) {
|
|
flags = flags | O_TRUNC;
|
|
}
|
|
int fd = TEMP_FAILURE_RETRY(open(name, flags, 0666));
|
|
if (fd < 0) {
|
|
return NULL;
|
|
}
|
|
if (((mode & kWrite) != 0) && ((mode & kTruncate) == 0)) {
|
|
int position = TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_END));
|
|
if (position < 0) {
|
|
return NULL;
|
|
}
|
|
}
|
|
return new File(name, new FileHandle(fd));
|
|
}
|
|
|
|
|
|
File* File::OpenStdio(int fd) {
|
|
if (fd < 0 || 2 < fd) return NULL;
|
|
return new File(NULL, new FileHandle(fd));
|
|
}
|
|
|
|
|
|
bool File::Exists(const char* name) {
|
|
struct stat st;
|
|
if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
|
|
return S_ISREG(st.st_mode);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
bool File::Create(const char* name) {
|
|
int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CREAT, 0666));
|
|
if (fd < 0) {
|
|
return false;
|
|
}
|
|
return (close(fd) == 0);
|
|
}
|
|
|
|
|
|
bool File::Delete(const char* name) {
|
|
int status = TEMP_FAILURE_RETRY(remove(name));
|
|
if (status == -1) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
off_t File::LengthFromName(const char* name) {
|
|
struct stat st;
|
|
if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
|
|
return st.st_size;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
time_t File::LastModified(const char* name) {
|
|
struct stat st;
|
|
if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
|
|
return st.st_mtime;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
bool File::IsAbsolutePath(const char* pathname) {
|
|
return (pathname != NULL && pathname[0] == '/');
|
|
}
|
|
|
|
|
|
char* File::GetCanonicalPath(const char* pathname) {
|
|
char* abs_path = NULL;
|
|
if (pathname != NULL) {
|
|
do {
|
|
abs_path = realpath(pathname, NULL);
|
|
} while (abs_path == NULL && errno == EINTR);
|
|
ASSERT(abs_path == NULL || IsAbsolutePath(abs_path));
|
|
}
|
|
return abs_path;
|
|
}
|
|
|
|
|
|
char* File::GetContainingDirectory(char* pathname) {
|
|
// Report errors for non-regular files.
|
|
struct stat st;
|
|
if (TEMP_FAILURE_RETRY(stat(pathname, &st)) == 0) {
|
|
if (!S_ISREG(st.st_mode)) {
|
|
errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
|
|
return NULL;
|
|
}
|
|
} else {
|
|
return NULL;
|
|
}
|
|
char* path = NULL;
|
|
do {
|
|
path = dirname(pathname);
|
|
} while (path == NULL && errno == EINTR);
|
|
return GetCanonicalPath(path);
|
|
}
|
|
|
|
|
|
const char* File::PathSeparator() {
|
|
return "/";
|
|
}
|
|
|
|
|
|
const char* File::StringEscapedPathSeparator() {
|
|
return "/";
|
|
}
|
|
|
|
|
|
File::StdioHandleType File::GetStdioHandleType(int fd) {
|
|
ASSERT(0 <= fd && fd <= 2);
|
|
struct stat buf;
|
|
int result = fstat(fd, &buf);
|
|
if (result == -1) {
|
|
FATAL2("Failed stat on file descriptor %d: %s", fd, strerror(errno));
|
|
}
|
|
if (S_ISCHR(buf.st_mode)) return kTerminal;
|
|
if (S_ISFIFO(buf.st_mode)) return kPipe;
|
|
if (S_ISSOCK(buf.st_mode)) return kSocket;
|
|
if (S_ISREG(buf.st_mode)) return kFile;
|
|
return kOther;
|
|
}
|