# HG changeset patch # User František Kučera # Date 1547663497 -3600 # Node ID b4f29fb16159b48da96a222f728cb69f81e49f6c # Parent eb1ecb37c6b7f62ed22f575efbe1797adaf57f37 process also links to non-existent files and non-readable links diff -r eb1ecb37c6b7 -r b4f29fb16159 src/AttributeFinder.h --- a/src/AttributeFinder.h Wed Jan 16 18:19:50 2019 +0100 +++ b/src/AttributeFinder.h Wed Jan 16 19:31:37 2019 +0100 @@ -37,41 +37,14 @@ protected: fs::path currentFile; string currentFileRaw; -public: - - /** - * Single requested fields might generate multiple attributes in the relation. - * But usually it is 1:1. - * @param field requested field from the user (usually from CLI arguments) - * @return attribute metadata to be used in the RelationalWriter.startRelation() - */ - virtual vector toMetadata(const RequestedField& field) = 0; - - /** - * Writing of the record for current file is starting. - * Following writeField() calls are related to this file. - * @param file path to the file - * @param fileRaw raw file name as it was on the input - */ - virtual void startFile(const fs::path& file, const string& fileRaw) { - currentFile = file; - currentFileRaw = fileRaw; - } - - /** - * Writing of the record for current file is finished. All resources linked to this file should be released. - */ - virtual void endFile() { - currentFile.clear(); - currentFileRaw.clear(); - } + bool currentFileExists; /** * Writes field attribute(s). The attribute count must match with count of AttributeMetadata returned in toMetadata(). * @param writer * @param field */ - virtual void writeField(RelationalWriter* writer, const RequestedField& field) = 0; + virtual void writeFieldOfExistingFile(RelationalWriter* writer, const RequestedField& field) = 0; /** * Writes empty attribute(s) in case of non-existent file or an error. @@ -98,6 +71,41 @@ } } +public: + + /** + * Single requested fields might generate multiple attributes in the relation. + * But usually it is 1:1. + * @param field requested field from the user (usually from CLI arguments) + * @return attribute metadata to be used in the RelationalWriter.startRelation() + */ + virtual vector toMetadata(const RequestedField& field) = 0; + + /** + * Writing of the record for current file is starting. + * Following writeField() calls are related to this file. + * @param file path to the file + * @param fileRaw raw file name as it was on the input + */ + virtual void startFile(const fs::path& file, const string& fileRaw, bool exists) { + currentFile = file; + currentFileRaw = fileRaw; + currentFileExists = exists; + } + + virtual void writeField(RelationalWriter* writer, const RequestedField& field) { + if (currentFileExists) writeFieldOfExistingFile(writer, field); + else writeEmptyField(writer, field); + } + + /** + * Writing of the record for current file is finished. All resources linked to this file should be released. + */ + virtual void endFile() { + currentFile.clear(); + currentFileRaw.clear(); + } + virtual ~AttributeFinder() { } }; diff -r eb1ecb37c6b7 -r b4f29fb16159 src/FileAttributeFinder.h --- a/src/FileAttributeFinder.h Wed Jan 16 18:19:50 2019 +0100 +++ b/src/FileAttributeFinder.h Wed Jan 16 19:31:37 2019 +0100 @@ -41,9 +41,9 @@ string_t currentOwner; string_t currentGroup; - string_t getType(const fs::path& file, bool x) { + string_t getType(const fs::path& file, bool workWithSymlinkItself) { // TODO: Use whole words? (letters are compatible with find -type) - if (fs::is_symlink(file) && x) return L"l"; // symlinks are both symlinks and files/directories/etc. + if (fs::is_symlink(file) && workWithSymlinkItself) return L"l"; // symlinks are both symlinks and files/directories/etc. else if (fs::is_regular_file(file)) return L"f"; else if (fs::is_directory(file)) return L"d"; else if (fs::is_fifo(file)) return L"p"; @@ -69,6 +69,50 @@ owner = convertor.from_bytes(pw->pw_name); group = convertor.from_bytes(gr->gr_name); } + +protected: + + virtual void writeFieldOfExistingFile(RelationalWriter* writer, const RequestedField& field) override { + if (field.group == RequestedField::GROUP_FILE) { + for (string_t alias : field.getAliases()) { + if (field.name == FIELD_NAME) { + writer->writeAttribute(currentFile.filename().wstring()); + } else if (field.name == FIELD_PATH_ORIGINAL) { + writer->writeAttribute(convertor.from_bytes(currentFileRaw)); + } else if (field.name == FIELD_PATH_ABSOLUTE) { + writer->writeAttribute(fs::absolute(currentFile).wstring()); + } else if (field.name == FIELD_PATH_CANONICAL) { + writer->writeAttribute(fs::canonical(currentFile).wstring()); + } else if (field.name == FIELD_TYPE) { + writer->writeAttribute(getType(currentFile, true)); + } else if (field.name == FIELD_SYMLINK_TARGET_TYPE) { + writer->writeAttribute(getType(currentFile, false)); + } else if (field.name == FIELD_SYMLINK_TARGET) { + string_t symlinkTarget; // TODO: null value (when supported) + if (fs::is_symlink(currentFile)) { + try { + symlinkTarget = fs::read_symlink(currentFile).wstring(); + } catch (...) { + // missing permissions, not readable → leave empty + } + } + writer->writeAttribute(symlinkTarget); + } else if (field.name == FIELD_SIZE) { + integer_t size = fs::is_regular_file(currentFile) ? fs::file_size(currentFile) : 0; + writer->writeAttribute(&size, typeid (size)); + } else if (field.name == FIELD_OWNER) { + if (currentOwner.empty()) fetchOwner(currentFile, currentOwner, currentGroup); + writer->writeAttribute(currentOwner); + } else if (field.name == FIELD_GROUP) { + if (currentOwner.empty()) fetchOwner(currentFile, currentOwner, currentGroup); + writer->writeAttribute(currentGroup); + } else { + throw RelpipeWriterException(L"Unsupported field name in FileAttributeFinder: " + field.name); + } + } + } + } + public: static const string_t FIELD_PATH_ORIGINAL; @@ -95,46 +139,21 @@ } } + void writeField(RelationalWriter* writer, const RequestedField& field) override { + if (currentFileExists + || field.name == FIELD_PATH_ORIGINAL + || (fs::is_symlink(currentFile) && (field.name == FIELD_SYMLINK_TARGET || field.name == FIELD_TYPE))) + writeFieldOfExistingFile(writer, field); + else + writeEmptyField(writer, field); + } + void endFile() override { AttributeFinder::endFile(); currentOwner.clear(); currentGroup.clear(); }; - virtual void writeField(RelationalWriter* writer, const RequestedField& field) override { - if (field.group == RequestedField::GROUP_FILE) { - for (string_t alias : field.getAliases()) { - if (field.name == FIELD_NAME) { - writer->writeAttribute(currentFile.filename().wstring()); - } else if (field.name == FIELD_PATH_ORIGINAL) { - writer->writeAttribute(convertor.from_bytes(currentFileRaw)); - } else if (field.name == FIELD_PATH_ABSOLUTE) { - writer->writeAttribute(fs::absolute(currentFile).wstring()); - } else if (field.name == FIELD_PATH_CANONICAL) { - writer->writeAttribute(fs::canonical(currentFile).wstring()); - } else if (field.name == FIELD_TYPE) { - writer->writeAttribute(getType(currentFile, true)); - } else if (field.name == FIELD_SYMLINK_TARGET_TYPE) { - writer->writeAttribute(getType(currentFile, false)); - } else if (field.name == FIELD_SYMLINK_TARGET) { - writer->writeAttribute(fs::is_symlink(currentFile) ? fs::read_symlink(currentFile).wstring() : L""); // TODO: null value (when supported) - } else if (field.name == FIELD_SIZE) { - integer_t size = fs::is_regular_file(currentFile) ? fs::file_size(currentFile) : 0; - writer->writeAttribute(&size, typeid (size)); - } else if (field.name == FIELD_OWNER) { - if (currentOwner.empty()) fetchOwner(currentFile, currentOwner, currentGroup); - writer->writeAttribute(currentOwner); - } else if (field.name == FIELD_GROUP) { - if (currentOwner.empty()) fetchOwner(currentFile, currentOwner, currentGroup); - writer->writeAttribute(currentGroup); - } else { - // TODO: should not happend; check supported attributes in toMetadata()? - writer->writeAttribute(L""); - } - } - } - } - virtual ~FileAttributeFinder() override { } }; diff -r eb1ecb37c6b7 -r b4f29fb16159 src/FilesystemCommand.h --- a/src/FilesystemCommand.h Wed Jan 16 18:19:50 2019 +0100 +++ b/src/FilesystemCommand.h Wed Jan 16 19:31:37 2019 +0100 @@ -95,17 +95,11 @@ // we probably do not have permissions to given directory → pretend that the file does not exist } - for (auto& finder : attributeFinders) finder.second->startFile(file, originalName.str()); + for (auto& finder : attributeFinders) finder.second->startFile(file, originalName.str(), exists); for (RequestedField field : configuration.fields) { AttributeFinder* finder = attributeFinders[field.group]; // should not be nullptr, because already checked while writing the relation metadata - - // TODO: links to non-existent files are currently treated as non-existent files → we still can return the type and symlink_target values - if (exists || (field.group == RequestedField::GROUP_FILE && field.name == FileAttributeFinder::FIELD_PATH_ORIGINAL)) { - finder->writeField(writer.get(), field); - } else { - finder->writeEmptyField(writer.get(), field); - } + finder->writeField(writer.get(), field); } for (auto& finder : attributeFinders) finder.second->endFile(); diff -r eb1ecb37c6b7 -r b4f29fb16159 src/XattrAttributeFinder.h --- a/src/XattrAttributeFinder.h Wed Jan 16 18:19:50 2019 +0100 +++ b/src/XattrAttributeFinder.h Wed Jan 16 19:31:37 2019 +0100 @@ -51,6 +51,14 @@ return L""; } } +protected: + + virtual void writeFieldOfExistingFile(RelationalWriter* writer, const RequestedField& field) override { + for (string_t alias : field.getAliases()) { + if (field.group == RequestedField::GROUP_XATTR) writer->writeAttribute(getXattr(currentFile, field.name)); + } + } + public: virtual vector toMetadata(const RequestedField& field) override { @@ -63,12 +71,6 @@ } } - virtual void writeField(RelationalWriter* writer, const RequestedField& field) override { - for (string_t alias : field.getAliases()) { - if (field.group == RequestedField::GROUP_XATTR) writer->writeAttribute(getXattr(currentFile, field.name)); - } - } - virtual ~XattrAttributeFinder() override { } };