Finish non-recursive synchronous directory listing on Linux and Mac.
Next steps: Testing, Windows support and using isolates to make listing async. We should probably change the API to not tie a Directory object to a given OS directory structure. When spawning an isolate to perform a listing operation, that will open the directory, list its contents and close the directory. That way we can do multiple listing operations with the same Directory object without having interference. R=sgjesse@google.com,iposva@google.com BUG= TEST= Review URL: https://chromereviews.googleplex.com/3511020 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@43 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
@@ -25,7 +25,7 @@ static const char Builtin_source_[] = {
|
||||
#define BUILTIN_NATIVE_LIST(V) \
|
||||
V(Logger_PrintString, 1) \
|
||||
V(Directory_Close, 2) \
|
||||
V(Directory_List, 7) \
|
||||
V(Directory_List, 8) \
|
||||
V(Directory_Open, 2) \
|
||||
V(File_OpenFile, 3) \
|
||||
V(File_Exists, 1) \
|
||||
|
||||
@@ -48,14 +48,17 @@ static intptr_t GetHandlerPort(Dart_Handle handle) {
|
||||
|
||||
void FUNCTION_NAME(Directory_List)(Dart_NativeArguments args) {
|
||||
Dart_EnterScope();
|
||||
intptr_t dir = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
|
||||
bool recursive = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2));
|
||||
Dart_Port dir_handler_port = GetHandlerPort(Dart_GetNativeArgument(args, 3));
|
||||
Dart_Port file_handler_port = GetHandlerPort(Dart_GetNativeArgument(args, 4));
|
||||
Dart_Port done_handler_port = GetHandlerPort(Dart_GetNativeArgument(args, 5));
|
||||
Dart_Handle path = Dart_GetNativeArgument(args, 1);
|
||||
intptr_t dir = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
|
||||
bool recursive = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
|
||||
Dart_Port dir_handler_port = GetHandlerPort(Dart_GetNativeArgument(args, 4));
|
||||
Dart_Port file_handler_port = GetHandlerPort(Dart_GetNativeArgument(args, 5));
|
||||
Dart_Port done_handler_port = GetHandlerPort(Dart_GetNativeArgument(args, 6));
|
||||
Dart_Port dir_error_handler_port =
|
||||
GetHandlerPort(Dart_GetNativeArgument(args, 6));
|
||||
Directory::List(dir,
|
||||
GetHandlerPort(Dart_GetNativeArgument(args, 7));
|
||||
ASSERT(Dart_IsString(path));
|
||||
Directory::List(DartUtils::GetStringValue(path),
|
||||
dir,
|
||||
recursive,
|
||||
dir_handler_port,
|
||||
file_handler_port,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// 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.
|
||||
|
||||
interface Directory factory DirectoryImpl {
|
||||
interface Directory factory _Directory {
|
||||
/**
|
||||
* Creates a directory object. The path is either a full path or
|
||||
* relative to the directory in which the Dart VM was
|
||||
|
||||
@@ -12,7 +12,8 @@ class Directory {
|
||||
public:
|
||||
static bool Open(const char* path, intptr_t* dir);
|
||||
static bool Close(intptr_t dir);
|
||||
static void List(intptr_t dir,
|
||||
static void List(const char* path,
|
||||
intptr_t dir,
|
||||
bool recursive,
|
||||
Dart_Port dir_handler,
|
||||
Dart_Port file_handler,
|
||||
|
||||
@@ -7,14 +7,13 @@ class DirectoryException {
|
||||
final String message;
|
||||
}
|
||||
|
||||
class _Directory implements Directory {
|
||||
|
||||
class DirectoryImpl implements Directory {
|
||||
|
||||
DirectoryImpl.open(String dir) {
|
||||
_Directory.open(String this._dir) {
|
||||
_id = 0;
|
||||
_closed = false;
|
||||
_listing = false;
|
||||
if (!_open(dir)) {
|
||||
if (!_open(_dir)) {
|
||||
_closed = true;
|
||||
throw new DirectoryException("Error: could not open directory");
|
||||
}
|
||||
@@ -41,6 +40,7 @@ class DirectoryImpl implements Directory {
|
||||
}
|
||||
|
||||
void list([bool recursive = false]) {
|
||||
// TODO(ager): Spawn an isolate to make the listing an async operation.
|
||||
if (_closed) {
|
||||
throw new DirectoryException("Error: directory closed");
|
||||
}
|
||||
@@ -48,7 +48,8 @@ class DirectoryImpl implements Directory {
|
||||
throw new DirectoryException("Error: listing already in progress");
|
||||
}
|
||||
_listing = true;
|
||||
_list(_id,
|
||||
_list(_dir,
|
||||
_id,
|
||||
recursive,
|
||||
_dirHandler,
|
||||
_fileHandler,
|
||||
@@ -112,7 +113,8 @@ class DirectoryImpl implements Directory {
|
||||
// Native code binding.
|
||||
bool _open(String dir) native "Directory_Open";
|
||||
bool _close(int id) native "Directory_Close";
|
||||
void _list(int id,
|
||||
void _list(String dir,
|
||||
int id,
|
||||
bool recursive,
|
||||
ReceivePort dirHandler,
|
||||
ReceivePort fileHandler,
|
||||
@@ -124,6 +126,7 @@ class DirectoryImpl implements Directory {
|
||||
ReceivePort _doneHandler;
|
||||
ReceivePort _dirErrorHandler;
|
||||
|
||||
String _dir;
|
||||
int _id;
|
||||
bool _closed;
|
||||
bool _listing;
|
||||
|
||||
+131
-26
@@ -2,11 +2,18 @@
|
||||
// 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 <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "bin/dartutils.h"
|
||||
#include "bin/directory.h"
|
||||
#include "bin/file.h"
|
||||
|
||||
|
||||
bool Directory::Open(const char* path, intptr_t* dir) {
|
||||
DIR* dir_pointer = opendir(path);
|
||||
@@ -17,56 +24,154 @@ bool Directory::Open(const char* path, intptr_t* dir) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Directory::Close(intptr_t dir) {
|
||||
DIR* dir_pointer = reinterpret_cast<DIR*>(dir);
|
||||
int result = closedir(dir_pointer);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
void Directory::List(intptr_t dir,
|
||||
|
||||
static void ComputeFullPath(const char* dir_name,
|
||||
char* path,
|
||||
int* path_length) {
|
||||
size_t written = 0;
|
||||
|
||||
if (!File::IsAbsolutePath(dir_name)) {
|
||||
ASSERT(getcwd(path, PATH_MAX) != NULL);
|
||||
*path_length = strlen(path);
|
||||
written = snprintf(path + *path_length,
|
||||
PATH_MAX - *path_length,
|
||||
"%s",
|
||||
File::PathSeparator());
|
||||
ASSERT(written == strlen(File::PathSeparator()));
|
||||
*path_length += written;
|
||||
}
|
||||
|
||||
// Use dirname and basename to canonicalize the provided directory
|
||||
// name.
|
||||
char* dir_name_copy = strdup(dir_name);
|
||||
char* dir = dirname(dir_name_copy);
|
||||
if (strcmp(dir, ".") != 0) {
|
||||
written = snprintf(path + *path_length,
|
||||
PATH_MAX - *path_length,
|
||||
"%s%s",
|
||||
dir,
|
||||
File::PathSeparator());
|
||||
ASSERT(written == (strlen(dir) + strlen(File::PathSeparator())));
|
||||
*path_length += written;
|
||||
}
|
||||
char* base = basename(dir_name_copy);
|
||||
if (strcmp(base, ".") != 0) {
|
||||
written = snprintf(path + *path_length,
|
||||
PATH_MAX - *path_length,
|
||||
"%s%s",
|
||||
base,
|
||||
File::PathSeparator());
|
||||
ASSERT(written == (strlen(base) + strlen(File::PathSeparator())));
|
||||
*path_length += written;
|
||||
}
|
||||
free(dir_name_copy);
|
||||
}
|
||||
|
||||
|
||||
static void HandleDir(char* dir_name,
|
||||
char* path,
|
||||
int path_length,
|
||||
Dart_Port dir_handler) {
|
||||
if (dir_handler != 0 &&
|
||||
strcmp(dir_name, ".") != 0 &&
|
||||
strcmp(dir_name, "..") != 0) {
|
||||
size_t written = snprintf(path + path_length,
|
||||
PATH_MAX - path_length,
|
||||
"%s",
|
||||
dir_name);
|
||||
ASSERT(written == strlen(dir_name));
|
||||
Dart_Handle name = Dart_NewString(path);
|
||||
Dart_Post(dir_handler, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void HandleFile(char* file_name,
|
||||
char* path,
|
||||
int path_length,
|
||||
Dart_Port file_handler) {
|
||||
if (file_handler != 0) {
|
||||
size_t written = snprintf(path + path_length,
|
||||
PATH_MAX - path_length,
|
||||
"%s",
|
||||
file_name);
|
||||
ASSERT(written == strlen(file_name));
|
||||
Dart_Handle name = Dart_NewString(path);
|
||||
Dart_Post(file_handler, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Directory::List(const char* dir_name,
|
||||
intptr_t dir_handle,
|
||||
bool recursive,
|
||||
Dart_Port dir_handler,
|
||||
Dart_Port file_handler,
|
||||
Dart_Port done_handler,
|
||||
Dart_Port dir_error_handler) {
|
||||
// Compute full path for the directory currently being listed.
|
||||
char path[PATH_MAX];
|
||||
int path_length = 0;
|
||||
ComputeFullPath(dir_name, path, &path_length);
|
||||
|
||||
// Iterated the directory and post the directories and files to the
|
||||
// handlers.
|
||||
//
|
||||
// TODO(ager): Handle recursion and errors caused by recursion.
|
||||
// TODO(ager): Make this async by using a thread to do this.
|
||||
DIR* dir_pointer = reinterpret_cast<DIR*>(dir);
|
||||
DIR* dir_pointer = reinterpret_cast<DIR*>(dir_handle);
|
||||
int success = 0;
|
||||
bool lstat_error = false;
|
||||
dirent entry;
|
||||
dirent* result;
|
||||
while ((success = readdir_r(dir_pointer, &entry, &result)) == 0 &&
|
||||
result != NULL) {
|
||||
switch (entry.d_type) {
|
||||
case DT_DIR:
|
||||
if (dir_handler != 0 &&
|
||||
strcmp(entry.d_name, ".") != 0 &&
|
||||
strcmp(entry.d_name, "..") != 0) {
|
||||
Dart_Handle name = Dart_NewString(entry.d_name);
|
||||
Dart_Post(dir_handler, name);
|
||||
}
|
||||
HandleDir(entry.d_name, path, path_length, dir_handler);
|
||||
break;
|
||||
case DT_REG:
|
||||
if (file_handler != 0) {
|
||||
Dart_Handle name = Dart_NewString(entry.d_name);
|
||||
Dart_Post(file_handler, name);
|
||||
HandleFile(entry.d_name, path, path_length, file_handler);
|
||||
break;
|
||||
case DT_UNKNOWN: {
|
||||
// On some file systems the entry type is not determined by
|
||||
// readdir_r. For those we use lstat to determine the entry
|
||||
// type.
|
||||
struct stat entry_info;
|
||||
size_t written = snprintf(path + path_length,
|
||||
PATH_MAX - path_length,
|
||||
"%s",
|
||||
entry.d_name);
|
||||
ASSERT(written == strlen(entry.d_name));
|
||||
int lstat_success = lstat(path, &entry_info);
|
||||
if (lstat_success != 0) {
|
||||
lstat_error = true;
|
||||
break;
|
||||
}
|
||||
if ((entry_info.st_mode & S_IFMT) == S_IFDIR) {
|
||||
HandleDir(entry.d_name, path, path_length, dir_handler);
|
||||
} else if ((entry_info.st_mode & S_IFMT) == S_IFREG) {
|
||||
HandleFile(entry.d_name, path, path_length, file_handler);
|
||||
}
|
||||
break;
|
||||
case DT_UNKNOWN:
|
||||
UNIMPLEMENTED();
|
||||
// TODO(ager): Handle this correctly. Use lstat or something?
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// TODO(ager): Handle symbolic links?
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (success != 0) {
|
||||
// TODO(ager): Error listing directory. There should probably be
|
||||
// a general error handler. Maybe collaps the dir_error_handler
|
||||
// to just be a general error handler.
|
||||
} else if (done_handler != 0) {
|
||||
Dart_Handle value = Dart_NewBoolean(true);
|
||||
Dart_Post(done_handler, value);
|
||||
if (done_handler != 0) {
|
||||
if (success != 0 || lstat_error) {
|
||||
Dart_Handle value = Dart_NewBoolean(false);
|
||||
Dart_Post(done_handler, value);
|
||||
} else {
|
||||
Dart_Handle value = Dart_NewBoolean(true);
|
||||
Dart_Post(done_handler, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+128
-26
@@ -2,11 +2,18 @@
|
||||
// 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 <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "bin/dartutils.h"
|
||||
#include "bin/directory.h"
|
||||
#include "bin/file.h"
|
||||
|
||||
|
||||
bool Directory::Open(const char* path, intptr_t* dir) {
|
||||
DIR* dir_pointer = opendir(path);
|
||||
@@ -17,56 +24,151 @@ bool Directory::Open(const char* path, intptr_t* dir) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Directory::Close(intptr_t dir) {
|
||||
DIR* dir_pointer = reinterpret_cast<DIR*>(dir);
|
||||
int result = closedir(dir_pointer);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
void Directory::List(intptr_t dir,
|
||||
|
||||
static void ComputeFullPath(const char* dir_name,
|
||||
char* path,
|
||||
int* path_length) {
|
||||
size_t written = 0;
|
||||
|
||||
if (!File::IsAbsolutePath(dir_name)) {
|
||||
ASSERT(getcwd(path, PATH_MAX) != NULL);
|
||||
*path_length = strlen(path);
|
||||
written = snprintf(path + *path_length,
|
||||
PATH_MAX - *path_length,
|
||||
"%s",
|
||||
File::PathSeparator());
|
||||
ASSERT(written == strlen(File::PathSeparator()));
|
||||
*path_length += written;
|
||||
}
|
||||
|
||||
// Use dirname and basename to canonicalize the provided directory
|
||||
// name.
|
||||
char* dir_name_copy = strdup(dir_name);
|
||||
char* dir = dirname(dir_name_copy);
|
||||
if (strcmp(dir, ".") != 0) {
|
||||
written = snprintf(path + *path_length,
|
||||
PATH_MAX - *path_length,
|
||||
"%s%s",
|
||||
dir,
|
||||
File::PathSeparator());
|
||||
ASSERT(written == (strlen(dir) + strlen(File::PathSeparator())));
|
||||
*path_length += written;
|
||||
}
|
||||
char* base = basename(dir_name_copy);
|
||||
if (strcmp(base, ".") != 0) {
|
||||
written = snprintf(path + *path_length,
|
||||
PATH_MAX - *path_length,
|
||||
"%s%s",
|
||||
base,
|
||||
File::PathSeparator());
|
||||
ASSERT(written == (strlen(base) + strlen(File::PathSeparator())));
|
||||
*path_length += written;
|
||||
}
|
||||
free(dir_name_copy);
|
||||
}
|
||||
|
||||
|
||||
static void HandleDir(char* dir_name,
|
||||
char* path,
|
||||
int path_length,
|
||||
Dart_Port dir_handler) {
|
||||
if (dir_handler != 0 &&
|
||||
strcmp(dir_name, ".") != 0 &&
|
||||
strcmp(dir_name, "..") != 0) {
|
||||
size_t written = snprintf(path + path_length,
|
||||
PATH_MAX - path_length,
|
||||
"%s",
|
||||
dir_name);
|
||||
ASSERT(written == strlen(dir_name));
|
||||
Dart_Handle name = Dart_NewString(path);
|
||||
Dart_Post(dir_handler, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void HandleFile(char* file_name,
|
||||
char* path,
|
||||
int path_length,
|
||||
Dart_Port file_handler) {
|
||||
if (file_handler != 0) {
|
||||
size_t written = snprintf(path + path_length,
|
||||
PATH_MAX - path_length,
|
||||
"%s",
|
||||
file_name);
|
||||
ASSERT(written == strlen(file_name));
|
||||
Dart_Handle name = Dart_NewString(path);
|
||||
Dart_Post(file_handler, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Directory::List(const char* dir_name,
|
||||
intptr_t dir_handle,
|
||||
bool recursive,
|
||||
Dart_Port dir_handler,
|
||||
Dart_Port file_handler,
|
||||
Dart_Port done_handler,
|
||||
Dart_Port dir_error_handler) {
|
||||
// Compute full path for the directory currently being listed.
|
||||
char path[PATH_MAX];
|
||||
int path_length = 0;
|
||||
ComputeFullPath(dir_name, path, &path_length);
|
||||
|
||||
// Iterated the directory and post the directories and files to the
|
||||
// handlers.
|
||||
//
|
||||
// TODO(ager): Handle recursion and errors caused by recursion.
|
||||
// TODO(ager): Make this async by using a thread to do this.
|
||||
DIR* dir_pointer = reinterpret_cast<DIR*>(dir);
|
||||
DIR* dir_pointer = reinterpret_cast<DIR*>(dir_handle);
|
||||
int success = 0;
|
||||
bool lstat_error = false;
|
||||
dirent entry;
|
||||
dirent* result;
|
||||
while ((success = readdir_r(dir_pointer, &entry, &result)) == 0 &&
|
||||
result != NULL) {
|
||||
switch (entry.d_type) {
|
||||
case DT_DIR:
|
||||
if (dir_handler != 0 &&
|
||||
strcmp(entry.d_name, ".") != 0 &&
|
||||
strcmp(entry.d_name, "..") != 0) {
|
||||
Dart_Handle name = Dart_NewString(entry.d_name);
|
||||
Dart_Post(dir_handler, name);
|
||||
}
|
||||
HandleDir(entry.d_name, path, path_length, dir_handler);
|
||||
break;
|
||||
case DT_REG:
|
||||
if (file_handler != 0) {
|
||||
Dart_Handle name = Dart_NewString(entry.d_name);
|
||||
Dart_Post(file_handler, name);
|
||||
HandleFile(entry.d_name, path, path_length, file_handler);
|
||||
break;
|
||||
case DT_UNKNOWN: {
|
||||
struct stat entry_info;
|
||||
size_t written = snprintf(path + path_length,
|
||||
PATH_MAX - path_length,
|
||||
"%s",
|
||||
entry.d_name);
|
||||
ASSERT(written == strlen(entry.d_name));
|
||||
int lstat_success = lstat(path, &entry_info);
|
||||
if (lstat_success != 0) {
|
||||
lstat_error = true;
|
||||
break;
|
||||
}
|
||||
if ((entry_info.st_mode & S_IFMT) == S_IFDIR) {
|
||||
HandleDir(entry.d_name, path, path_length, dir_handler);
|
||||
} else if ((entry_info.st_mode & S_IFMT) == S_IFREG) {
|
||||
HandleFile(entry.d_name, path, path_length, file_handler);
|
||||
}
|
||||
break;
|
||||
case DT_UNKNOWN:
|
||||
UNIMPLEMENTED();
|
||||
// TODO(ager): Handle this correctly. Use lstat or something?
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// TODO(ager): Handle symbolic links?
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (success != 0) {
|
||||
// TODO(ager): Error listing directory. There should probably be
|
||||
// a general error handler. Maybe collaps the dir_error_handler
|
||||
// to just be a general error handler.
|
||||
} else if (done_handler != 0) {
|
||||
Dart_Handle value = Dart_NewBoolean(true);
|
||||
Dart_Post(done_handler, value);
|
||||
if (done_handler != 0) {
|
||||
if (success != 0 || lstat_error) {
|
||||
Dart_Handle value = Dart_NewBoolean(false);
|
||||
Dart_Post(done_handler, value);
|
||||
} else {
|
||||
Dart_Handle value = Dart_NewBoolean(true);
|
||||
Dart_Post(done_handler, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user