CC: Tweaked

CC: Tweaked

42M Downloads

Port `fs.find` to Lua/CraftOS

SquidDev opened this issue ยท 1 comments

commented

Currently fs.find is implemented in Java, inside the main filesystem implementation.

private void findIn(String dir, List<String> matches, Pattern wildPattern) throws FileSystemException {
var list = list(dir);
for (var entry : list) {
var entryPath = dir.isEmpty() ? entry : dir + "/" + entry;
if (wildPattern.matcher(entryPath).matches()) {
matches.add(entryPath);
}
if (isDir(entryPath)) {
findIn(entryPath, matches, wildPattern);
}
}
}
public synchronized String[] find(String wildPath) throws FileSystemException {
// Match all the files on the system
wildPath = sanitizePath(wildPath, true);
// If we don't have a wildcard at all just check the file exists
var starIndex = wildPath.indexOf('*');
if (starIndex == -1) {
return exists(wildPath) ? new String[]{ wildPath } : new String[0];
}
// Find the all non-wildcarded directories. For instance foo/bar/baz* -> foo/bar
var prevDir = wildPath.substring(0, starIndex).lastIndexOf('/');
var startDir = prevDir == -1 ? "" : wildPath.substring(0, prevDir);
// If this isn't a directory then just abort
if (!isDir(startDir)) return new String[0];
// Scan as normal, starting from this directory
var wildPattern = Pattern.compile("^\\Q" + wildPath.replaceAll("\\*", "\\\\E[^\\\\/]*\\\\Q") + "\\E$");
List<String> matches = new ArrayList<>();
findIn(startDir, matches, wildPattern);
// Return matches
var array = new String[matches.size()];
matches.toArray(array);
return array;
}

This isn't really a problem most of the time. However, if someone wants to replace the fs API (for instance, adding file permissions or custom mounts), then fs.find no longer has the correct behaviour, and so must be reimplemented.

Given the current implementation only uses the "public" FS functions (list, isDir), it should be fairly easy to port this to Lua. It feels like it would also be a good time to make some improvements to the implementation:

  • Add support for single-character wildcards (?).
  • Be more efficient in how we visit files. fs.find("*") still walks the entire file tree, while it should only need to be an fs.list.

There's probably more improvements we could make here ([abc], [a-c], **), but those can probably wait for later.

We'll want to flesh out the tests for fs.find before starting this - I've definitely some uncertainties about how paths are sanitised.

commented

I've already made this for just this reason. Feel free to integrate it in the ROM if you have the time.