Merge pull request #244 from vibe-d/osx_listdirectory_fix

Add `DirectoryListMode.shallowDirectories` and fix macOS `fstatat` declaration
This commit is contained in:
Leonid Kramer 2021-01-12 20:01:21 +01:00 committed by GitHub
commit 58f6b06e2d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 26 deletions

View file

@ -515,11 +515,13 @@ enum FileMode {
enum DirectoryListMode { enum DirectoryListMode {
/// Only iterate the directory itself /// Only iterate the directory itself
shallow, shallow = 0,
/// Only iterate over directories directly within the given directory
shallowDirectories = 1<<1,
/// Iterate recursively (depth-first, pre-order) /// Iterate recursively (depth-first, pre-order)
recursive, recursive = 1<<0,
/// Iterate only directories recursively (depth-first, pre-order) /// Iterate only directories recursively (depth-first, pre-order)
recursiveDirectories, recursiveDirectories = recursive | shallowDirectories,
} }
@ -948,7 +950,8 @@ private void performListDirectory(ListDirectoryRequest req)
@trusted nothrow { @trusted nothrow {
scope (exit) req.channel.close(); scope (exit) req.channel.close();
auto dirs_only = req.spanMode == DirectoryListMode.recursiveDirectories; auto dirs_only = !!(req.spanMode & DirectoryListMode.shallowDirectories);
auto rec = !!(req.spanMode & DirectoryListMode.recursive);
bool scanRec(NativePath path) bool scanRec(NativePath path)
{ {
@ -1001,7 +1004,7 @@ private void performListDirectory(ListDirectoryRequest req)
try req.channel.put(ListDirectoryData(fi, null)); try req.channel.put(ListDirectoryData(fi, null));
catch (Exception e) return false; // channel got closed catch (Exception e) return false; // channel got closed
if (req.spanMode != DirectoryListMode.shallow && fi.isDirectory) { if (rec && fi.isDirectory) {
if (fi.isSymlink && !req.followSymlinks) if (fi.isSymlink && !req.followSymlinks)
continue; continue;
try { try {
@ -1030,29 +1033,28 @@ private void performListDirectory(ListDirectoryRequest req)
continue; continue;
FileInfo fi; FileInfo fi;
auto zi = de.d_name[].countUntil(0); auto zi = de.d_name[].representation.countUntil(0);
if (zi < 0) zi = de.d_name.length; if (zi < 0) zi = de.d_name.length;
if (de.d_name[0 .. zi].among(".", "..")) if (de.d_name[0 .. zi].among(".", ".."))
continue; continue;
fi.name = de.d_name[0 .. zi].idup; fi.name = de.d_name[0 .. zi].idup;
fi.directory = path; fi.directory = path;
fi.hidden = de.d_name[0] == '.';
stat_t st; stat_t st;
if (fstatat(dfd, fi.name.toStringz, &st, AT_SYMLINK_NOFOLLOW) != 0) if (fstatat(dfd, fi.name.toStringz, &st, AT_SYMLINK_NOFOLLOW) == 0) {
continue; fi.isSymlink = S_ISLNK(st.st_mode);
fi.isSymlink = S_ISLNK(st.st_mode); // apart from the symlink flag, get the rest of the information from the link target
if (fi.isSymlink) fstatat(dfd, fi.name.toStringz, &st, 0);
// apart from the symlink flag, get the rest of the information from the link target fi.size = st.st_size;
if (fi.isSymlink) fstatat(dfd, fi.name.toStringz, &st, 0); fi.timeModified = timebase + st.st_mtime.seconds + (st.st_mtimensec / 100).hnsecs;
fi.timeCreated = timebase + st.st_ctime.seconds + (st.st_ctimensec / 100).hnsecs;
fi.size = st.st_size; fi.isDirectory = S_ISDIR(st.st_mode);
fi.timeModified = timebase + st.st_mtime.seconds + (st.st_mtimensec / 100).hnsecs; fi.isFile = S_ISREG(st.st_mode);
fi.timeCreated = timebase + st.st_ctime.seconds + (st.st_ctimensec / 100).hnsecs; }
fi.isDirectory = S_ISDIR(st.st_mode);
fi.isFile = S_ISREG(st.st_mode);
fi.hidden = de.d_name[0] == '.';
// skip non-directories if requested // skip non-directories if requested
if (dirs_only && !fi.isDirectory) if (dirs_only && !fi.isDirectory)
@ -1061,7 +1063,7 @@ private void performListDirectory(ListDirectoryRequest req)
try req.channel.put(ListDirectoryData(fi, null)); try req.channel.put(ListDirectoryData(fi, null));
catch (Exception e) return false; // channel got closed catch (Exception e) return false; // channel got closed
if (req.spanMode != DirectoryListMode.shallow && fi.isDirectory) { if (rec && fi.isDirectory) {
if (fi.isSymlink && !req.followSymlinks) if (fi.isSymlink && !req.followSymlinks)
continue; continue;
try { try {
@ -1089,8 +1091,12 @@ version (Posix) {
extern(C) @safe nothrow @nogc { extern(C) @safe nothrow @nogc {
static if (!is(typeof(dirfd))) static if (!is(typeof(dirfd)))
int dirfd(DIR*); int dirfd(DIR*);
static if (!is(typeof(fstatat))) static if (!is(typeof(fstatat))) {
int fstatat(int dirfd, const(char)* pathname, stat_t *statbuf, int flags); version (OSX) {
pragma(mangle, "fstatat$INODE64")
int fstatat(int dirfd, const(char)* pathname, stat_t *statbuf, int flags);
} else int fstatat(int dirfd, const(char)* pathname, stat_t *statbuf, int flags);
}
} }
version (darwin) { version (darwin) {

View file

@ -440,7 +440,7 @@ final package class TaskFiber : Fiber {
debug if (ms_taskEventCallback) ms_taskEventCallback(TaskEvent.end, handle); debug if (ms_taskEventCallback) ms_taskEventCallback(TaskEvent.end, handle);
debug if (() @trusted { return (cast(shared)this); } ().getTaskStatus().interrupt) debug if (() @trusted { return (cast(shared)this); } ().getTaskStatus().interrupt)
logDebug("Task exited while an interrupt was in flight."); logDebugV("Task exited while an interrupt was in flight.");
} catch (Exception e) { } catch (Exception e) {
debug if (ms_taskEventCallback) ms_taskEventCallback(TaskEvent.fail, handle); debug if (ms_taskEventCallback) ms_taskEventCallback(TaskEvent.fail, handle);
e.logException!(LogLevel.critical)("Task terminated with uncaught exception"); e.logException!(LogLevel.critical)("Task terminated with uncaught exception");

View file

@ -11,7 +11,7 @@ enum ubyte[] bytes(BYTES...) = [BYTES];
void main() void main()
{ {
auto f = openFile("test.dat", FileMode.createTrunc); auto f = openFile("têst.dat", FileMode.createTrunc);
assert(f.size == 0); assert(f.size == 0);
assert(f.tell == 0); assert(f.tell == 0);
f.write(bytes!(1, 2, 3, 4, 5)); f.write(bytes!(1, 2, 3, 4, 5));
@ -33,8 +33,8 @@ void main()
assert(dst[] == bytes!(3, 4, 5, 6, 7)); assert(dst[] == bytes!(3, 4, 5, 6, 7));
f.close(); f.close();
auto fi = getFileInfo("test.dat"); auto fi = getFileInfo("têst.dat");
assert(fi.name == "test.dat"); assert(fi.name == "têst.dat");
assert(fi.isFile); assert(fi.isFile);
assert(!fi.isDirectory); assert(!fi.isDirectory);
assert(!fi.isSymlink); assert(!fi.isSymlink);
@ -43,5 +43,18 @@ void main()
assertThrown(getFileInfo("*impossible:file?")); assertThrown(getFileInfo("*impossible:file?"));
removeFile("test.dat"); bool found = false;
listDirectory(".", (fi) {
if (fi.name != "têst.dat") return true;
assert(fi.isFile);
assert(!fi.isDirectory);
assert(!fi.isSymlink);
assert(!fi.hidden);
assert(fi.size == 10);
found = true;
return true;
});
assert(found, "listDirectory did not find test file.");
removeFile("têst.dat");
} }