mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 09:58:11 +00:00
find: Don't canonicalize path operands
The POSIX specification for `find` says that: "Each path operand shall be evaluated unaltered as it was provided, including all trailing <slash> characters". This also matches the behavior of `find` on FreeBSD and Linux.
This commit is contained in:
parent
881581820f
commit
6f1f0710f8
1 changed files with 49 additions and 29 deletions
|
@ -47,8 +47,10 @@ template<typename... Parameters>
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FileData {
|
struct FileData {
|
||||||
// Full path to the file; either absolute or relative to cwd.
|
// The current path specified on the command line
|
||||||
LexicalPath full_path;
|
StringView root_path;
|
||||||
|
// Path to the file relative to the current root path
|
||||||
|
LexicalPath relative_path;
|
||||||
// The parent directory of the file.
|
// The parent directory of the file.
|
||||||
int dirfd { -1 };
|
int dirfd { -1 };
|
||||||
// The file's basename, relative to the directory.
|
// The file's basename, relative to the directory.
|
||||||
|
@ -60,6 +62,22 @@ struct FileData {
|
||||||
// File type as returned from readdir(), or DT_UNKNOWN.
|
// File type as returned from readdir(), or DT_UNKNOWN.
|
||||||
unsigned char d_type { DT_UNKNOWN };
|
unsigned char d_type { DT_UNKNOWN };
|
||||||
|
|
||||||
|
DeprecatedString full_path() const
|
||||||
|
{
|
||||||
|
if (root_path.is_empty())
|
||||||
|
return relative_path.string();
|
||||||
|
|
||||||
|
if (relative_path.string() == ".")
|
||||||
|
return root_path;
|
||||||
|
|
||||||
|
// POSIX says that a single slash should be added between the root path and the relative portion if the root path doesn't end in one
|
||||||
|
// any additional trailing slashes should be left unaltered.
|
||||||
|
if (root_path.ends_with('/'))
|
||||||
|
return DeprecatedString::formatted("{}{}", root_path, relative_path.string());
|
||||||
|
|
||||||
|
return DeprecatedString::formatted("{}/{}", root_path, relative_path.string());
|
||||||
|
}
|
||||||
|
|
||||||
const struct stat* ensure_stat()
|
const struct stat* ensure_stat()
|
||||||
{
|
{
|
||||||
if (stat_is_valid)
|
if (stat_is_valid)
|
||||||
|
@ -68,7 +86,7 @@ struct FileData {
|
||||||
int flags = g_follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW;
|
int flags = g_follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW;
|
||||||
int rc = fstatat(dirfd, basename, &stat, flags);
|
int rc = fstatat(dirfd, basename, &stat, flags);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
perror(full_path.string().characters());
|
perror(full_path().characters());
|
||||||
g_there_was_an_error = true;
|
g_there_was_an_error = true;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -387,7 +405,7 @@ private:
|
||||||
return stat->st_size == 0;
|
return stat->st_size == 0;
|
||||||
|
|
||||||
if (S_ISDIR(stat->st_mode)) {
|
if (S_ISDIR(stat->st_mode)) {
|
||||||
auto dir_iterator = Core::DirIterator(file_data.full_path.string(), Core::DirIterator::SkipDots);
|
auto dir_iterator = Core::DirIterator(file_data.full_path(), Core::DirIterator::SkipDots);
|
||||||
return !dir_iterator.has_next();
|
return !dir_iterator.has_next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +424,7 @@ public:
|
||||||
private:
|
private:
|
||||||
virtual bool evaluate(FileData& file_data) const override
|
virtual bool evaluate(FileData& file_data) const override
|
||||||
{
|
{
|
||||||
return file_data.full_path.basename().matches(m_pattern, m_case_sensitivity);
|
return file_data.relative_path.basename().matches(m_pattern, m_case_sensitivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringView m_pattern;
|
StringView m_pattern;
|
||||||
|
@ -423,7 +441,7 @@ public:
|
||||||
private:
|
private:
|
||||||
virtual bool evaluate(FileData& file_data) const override
|
virtual bool evaluate(FileData& file_data) const override
|
||||||
{
|
{
|
||||||
auto haystack = file_data.full_path.string();
|
auto haystack = file_data.full_path();
|
||||||
auto match_result = m_regex.match(haystack);
|
auto match_result = m_regex.match(haystack);
|
||||||
return match_result.success;
|
return match_result.success;
|
||||||
}
|
}
|
||||||
|
@ -441,7 +459,7 @@ public:
|
||||||
private:
|
private:
|
||||||
virtual bool evaluate(FileData& file_data) const override
|
virtual bool evaluate(FileData& file_data) const override
|
||||||
{
|
{
|
||||||
auto maybe_error = Core::System::access(file_data.full_path.string(), m_mode);
|
auto maybe_error = Core::System::access(file_data.full_path(), m_mode);
|
||||||
return !maybe_error.is_error();
|
return !maybe_error.is_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,17 +564,17 @@ private:
|
||||||
{
|
{
|
||||||
auto printed = false;
|
auto printed = false;
|
||||||
if (g_print_hyperlinks) {
|
if (g_print_hyperlinks) {
|
||||||
auto full_path_or_error = FileSystem::real_path(file_data.full_path.string());
|
auto full_path_or_error = FileSystem::real_path(file_data.full_path());
|
||||||
if (!full_path_or_error.is_error()) {
|
if (!full_path_or_error.is_error()) {
|
||||||
auto fullpath = full_path_or_error.release_value();
|
auto fullpath = full_path_or_error.release_value();
|
||||||
auto url = URL::create_with_file_scheme(fullpath.to_deprecated_string());
|
auto url = URL::create_with_file_scheme(fullpath.to_deprecated_string());
|
||||||
out("\033]8;;{}\033\\{}{}\033]8;;\033\\", url.serialize(), file_data.full_path, m_terminator);
|
out("\033]8;;{}\033\\{}{}\033]8;;\033\\", url.serialize(), file_data.full_path(), m_terminator);
|
||||||
printed = true;
|
printed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!printed)
|
if (!printed)
|
||||||
out("{}{}", file_data.full_path, m_terminator);
|
out("{}{}", file_data.full_path(), m_terminator);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -581,18 +599,20 @@ private:
|
||||||
virtual bool evaluate(FileData& file_data) const override
|
virtual bool evaluate(FileData& file_data) const override
|
||||||
{
|
{
|
||||||
// Replace any occurrences of "{}" with the path.
|
// Replace any occurrences of "{}" with the path.
|
||||||
// Since we know that the array isn't modified before we
|
Vector<DeprecatedString> full_paths;
|
||||||
// fork the process, let's just const_cast away the constness.
|
Vector<char*> argv = m_argv;
|
||||||
auto argv = const_cast<Vector<char*>&>(m_argv);
|
|
||||||
for (auto& arg : argv) {
|
for (auto& arg : argv) {
|
||||||
if (StringView { arg, strlen(arg) } == "{}")
|
if (StringView { arg, strlen(arg) } == "{}") {
|
||||||
arg = const_cast<char*>(file_data.full_path.string().characters());
|
auto full_path = file_data.full_path();
|
||||||
|
full_paths.append(full_path);
|
||||||
|
arg = const_cast<char*>(full_path.characters());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_await_confirmation == AwaitConfirmation::Yes) {
|
if (m_await_confirmation == AwaitConfirmation::Yes) {
|
||||||
out(stderr, "\"");
|
out(stderr, "\"");
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto& arg : argv) {
|
for (auto const& arg : argv) {
|
||||||
if (!first)
|
if (!first)
|
||||||
out(stderr, " ");
|
out(stderr, " ");
|
||||||
|
|
||||||
|
@ -620,11 +640,8 @@ private:
|
||||||
perror("fork");
|
perror("fork");
|
||||||
g_there_was_an_error = true;
|
g_there_was_an_error = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
} else if (pid == 0) {
|
||||||
|
argv.append(nullptr);
|
||||||
argv.ensure_capacity(argv.size() + 1);
|
|
||||||
argv.append(nullptr);
|
|
||||||
if (pid == 0) {
|
|
||||||
execvp(m_argv[0], argv.data());
|
execvp(m_argv[0], argv.data());
|
||||||
perror("execvp");
|
perror("execvp");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -913,7 +930,7 @@ static void walk_tree(FileData& root_data, Command& command, u32 depth = 0)
|
||||||
// be a directory, but turns out it's not. This is fine though.
|
// be a directory, but turns out it's not. This is fine though.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
perror(root_data.full_path.string().characters());
|
perror(root_data.full_path().characters());
|
||||||
g_there_was_an_error = true;
|
g_there_was_an_error = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -930,7 +947,8 @@ static void walk_tree(FileData& root_data, Command& command, u32 depth = 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
FileData file_data {
|
FileData file_data {
|
||||||
root_data.full_path.append({ dirent->d_name, strlen(dirent->d_name) }),
|
root_data.root_path,
|
||||||
|
root_data.relative_path.append({ dirent->d_name, strlen(dirent->d_name) }),
|
||||||
dirfd,
|
dirfd,
|
||||||
dirent->d_name,
|
dirent->d_name,
|
||||||
(struct stat) {},
|
(struct stat) {},
|
||||||
|
@ -954,7 +972,7 @@ static void walk_tree(FileData& root_data, Command& command, u32 depth = 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errno != 0) {
|
if (errno != 0) {
|
||||||
perror(root_data.full_path.string().characters());
|
perror(root_data.full_path().characters());
|
||||||
g_there_was_an_error = true;
|
g_there_was_an_error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -967,7 +985,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
args.append(arguments.argv + 1, arguments.argc - 1);
|
args.append(arguments.argv + 1, arguments.argc - 1);
|
||||||
|
|
||||||
OwnPtr<Command> command;
|
OwnPtr<Command> command;
|
||||||
Vector<LexicalPath> paths;
|
Vector<StringView> paths;
|
||||||
|
|
||||||
while (!args.is_empty()) {
|
while (!args.is_empty()) {
|
||||||
char* raw_arg = args.take_first();
|
char* raw_arg = args.take_first();
|
||||||
|
@ -978,7 +996,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
args.prepend(raw_arg);
|
args.prepend(raw_arg);
|
||||||
command = parse_all_commands(args);
|
command = parse_all_commands(args);
|
||||||
} else {
|
} else {
|
||||||
paths.append(LexicalPath(arg));
|
paths.append(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -988,16 +1006,18 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
command = make<PrintCommand>();
|
command = make<PrintCommand>();
|
||||||
|
|
||||||
if (paths.is_empty())
|
if (paths.is_empty())
|
||||||
paths.append(LexicalPath("."));
|
paths.append("."sv);
|
||||||
|
|
||||||
for (auto& path : paths) {
|
for (auto& path : paths) {
|
||||||
DeprecatedString dirname = path.dirname();
|
LexicalPath lexical_path { path };
|
||||||
DeprecatedString basename = path.basename();
|
DeprecatedString dirname = lexical_path.dirname();
|
||||||
|
DeprecatedString basename = lexical_path.basename();
|
||||||
|
|
||||||
int dirfd = TRY(Core::System::open(dirname, O_RDONLY | O_DIRECTORY | O_CLOEXEC));
|
int dirfd = TRY(Core::System::open(dirname, O_RDONLY | O_DIRECTORY | O_CLOEXEC));
|
||||||
|
|
||||||
FileData file_data {
|
FileData file_data {
|
||||||
path,
|
path,
|
||||||
|
LexicalPath { "" },
|
||||||
dirfd,
|
dirfd,
|
||||||
basename.characters(),
|
basename.characters(),
|
||||||
(struct stat) {},
|
(struct stat) {},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue