Explorar o código

tar: Implement support for extended headers :^)

Tim Schumacher %!s(int64=3) %!d(string=hai) anos
pai
achega
495a1be925
Modificáronse 1 ficheiros con 48 adicións e 9 borrados
  1. 48 9
      Userland/Utilities/tar.cpp

+ 48 - 9
Userland/Utilities/tar.cpp

@@ -77,13 +77,57 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
             warnln("the provided file is not a well-formatted ustar file");
             return 1;
         }
+
+        HashMap<String, String> global_overrides;
+        HashMap<String, String> local_overrides;
+
+        auto get_override = [&](StringView key) -> Optional<String> {
+            Optional<String> maybe_local = local_overrides.get(key);
+
+            if (maybe_local.has_value())
+                return maybe_local;
+
+            Optional<String> maybe_global = global_overrides.get(key);
+
+            if (maybe_global.has_value())
+                return maybe_global;
+
+            return {};
+        };
+
         for (; !tar_stream.finished(); tar_stream.advance()) {
             const Archive::TarFileHeader& header = tar_stream.header();
 
+            // Handle meta-entries earlier to avoid consuming the file content stream.
+            if (header.content_is_like_extended_header()) {
+                switch (header.type_flag()) {
+                case Archive::TarFileType::GlobalExtendedHeader: {
+                    TRY(tar_stream.for_each_extended_header([&](StringView key, StringView value) {
+                        if (value.length() == 0)
+                            global_overrides.remove(key);
+                        else
+                            global_overrides.set(key, value);
+                    }));
+                    break;
+                }
+                case Archive::TarFileType::ExtendedHeader: {
+                    TRY(tar_stream.for_each_extended_header([&](StringView key, StringView value) {
+                        local_overrides.set(key, value);
+                    }));
+                    break;
+                }
+                default:
+                    warnln("Unknown extended header type '{}' of {}", (char)header.type_flag(), header.filename());
+                    VERIFY_NOT_REACHED();
+                }
+
+                continue;
+            }
+
             LexicalPath path = LexicalPath(header.filename());
             if (!header.prefix().is_empty())
                 path = path.prepend(header.prefix());
-            String filename = path.string();
+            String filename = get_override("path"sv).value_or(path.string());
 
             if (list || verbose)
                 outln("{}", filename);
@@ -122,20 +166,15 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
                         return result_or_error.error();
                     break;
                 }
-                case Archive::TarFileType::GlobalExtendedHeader: {
-                    dbgln("ignoring global extended header: {}", header.filename());
-                    break;
-                }
-                case Archive::TarFileType::ExtendedHeader: {
-                    dbgln("ignoring extended header: {}", header.filename());
-                    break;
-                }
                 default:
                     // FIXME: Implement other file types
                     warnln("file type '{}' of {} is not yet supported", (char)header.type_flag(), header.filename());
                     VERIFY_NOT_REACHED();
                 }
             }
+
+            // Non-global headers should be cleared after every file.
+            local_overrides.clear();
         }
         file_stream.close();