Files
sdk/runtime/bin/directory_linux.cc
T
ager@google.com 023fa46e48 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
2011-10-05 14:33:49 +00:00

178 lines
5.5 KiB
C++

// Copyright (c) 2011, 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 <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);
if (dir_pointer == NULL) {
return false;
}
*dir = reinterpret_cast<intptr_t>(dir_pointer);
return true;
}
bool Directory::Close(intptr_t dir) {
DIR* dir_pointer = reinterpret_cast<DIR*>(dir);
int result = closedir(dir_pointer);
return result == 0;
}
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.
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:
HandleDir(entry.d_name, path, path_length, dir_handler);
break;
case DT_REG:
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;
}
default:
break;
}
}
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);
}
}
}