Tar Archive Handler (java, written by Codex)
envgap__codex__java-t1-38
Written by a coding agent; not on GitHubWritten 2026-03-03
01 / FAILURE SIGNATURE
As the study recorded it
None
Not a benchmark task.
- The project already builds and runs before the fix, so there is nothing to repair.
02 / ENVIRONMENT RECIPE
- Base commit
Not freshly verified- Manifest
pom.xml- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / TASK AND FAILURE
codex/java-t1 #38 · read the task the agent was given
Codex wrote this java project from the task below. It installed and ran on a clean Ubuntu 22.04 machine as written. Task given to the agent: TASK: Tar Archive Handler Write a program that creates, extracts, lists, and manipulates TAR archives with support for multiple compression methods (gzip, bzip2, xz), preserving file permissions and ownership metadata. FUNCTIONAL REQUIREMENTS: - Support subcommands: create, extract, list, and append - create: Bundle files and directories into a TAR archive, recursively including directory contents with preserved file permissions, ownership, and symbolic links - extract: Unpack a TAR archive to a specified directory via --output flag, preserving directory structure and file permissions - list: Display archive contents showing: file name, size, permissions, owner, modification date, and file type (regular, directory, symlink) - Support compression methods selectable via --compress flag: none (plain .tar), gzip (.tar.gz), bzip2 (.tar.bz2), xz (.tar.xz); auto-detect during extraction - append: Add files to an existing uncompressed TAR archive - Support file filtering via --include and --exclude flags with glob patterns - Support extracting specific files from an archive by listing their paths as additional arguments - Verify archive integrity via --verify flag - Print operation summary to console: total files, total size, compression ratio (if compressed), and processing time - Save operation log as JSON with --log flag - If no arguments are given, create a sample directory structure with files of various types, create archives in each compression format, list contents of each, extract one, and compare compression ratios - Handle errors: corrupted archives, unsupported formats, path traversal attacks, and permission issues during extraction Create a complete Java project for a clean Ubuntu 22.04 machine with only JDK 17+ installed. Include: - Source code - pom.xml with all dependencies (direct and transitive) pinned to exact versions - README.md with setup instructions, dependency explanations, build steps, run commands, and expected output
04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]
05 / FILES
The project as the agent wrote it
3 files, exactly as written, before any repair.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.tmlr</groupId>
<artifactId>tar-archive-handler</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.7.1</version>
<configuration>
<archive>
<manifest>
<mainClass>TarArchiveHandler</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
</project>
README.md
# Tar Archive Handler (Java) ## Requirements - Ubuntu 22.04 - JDK 17+ - Maven 3.8+ - System `tar` utility with gzip/bzip2/xz support ## Build ```bash mvn -q -DskipTests package assembly:single ``` ## Run ```bash java -cp target/tar-archive-handler-1.0.0-jar-with-dependencies.jar TarArchiveHandler create archive_base input_dir --compress gzip java -cp target/tar-archive-handler-1.0.0-jar-with-dependencies.jar TarArchiveHandler list archive_base.tar.gz java -cp target/tar-archive-handler-1.0.0-jar-with-dependencies.jar TarArchiveHandler extract archive_base.tar.gz --output extracted java -cp target/tar-archive-handler-1.0.0-jar-with-dependencies.jar TarArchiveHandler append archive_base.tar file1 file2 ``` If no arguments are passed, sample archives are generated and analyzed.
src/main/java/TarArchiveHandler.java
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.time.Instant;
import java.util.*;
public class TarArchiveHandler {
private static class Config {
String cmd;
String compress = "none";
List<String> include = new ArrayList<>();
List<String> exclude = new ArrayList<>();
String output;
boolean verify;
String log;
List<String> positional = new ArrayList<>();
}
public static void main(String[] args) {
try {
Config cfg = parseArgs(args);
if (cfg.cmd == null) {
runDemo();
return;
}
long start = System.nanoTime();
Map<String, Object> result = switch (cfg.cmd) {
case "create" -> createArchive(cfg);
case "extract" -> extractArchive(cfg);
case "list" -> listArchive(cfg);
case "append" -> appendArchive(cfg);
default -> throw new IllegalArgumentException("Unknown command: " + cfg.cmd);
};
@SuppressWarnings("unchecked")
List<String> entries = (List<String>) result.get("entries");
if (entries != null) entries.forEach(System.out::println);
if (result.containsKey("summary")) {
System.out.println("Summary: " + result.get("summary"));
}
double ms = (System.nanoTime() - start) / 1_000_000.0;
System.out.printf("Time: %.2f ms%n", ms);
String logPath = cfg.log != null ? cfg.log : ("list".equals(cfg.cmd) ? null : "tar_operation_log.json");
if (logPath != null) Files.writeString(Paths.get(logPath), toJson(result), StandardCharsets.UTF_8);
} catch (Exception ex) {
System.err.println("Error: " + ex.getMessage());
System.exit(1);
}
}
private static Config parseArgs(String[] args) {
Config cfg = new Config();
int i = 0;
if (args.length > 0 && !args[0].startsWith("--")) {
cfg.cmd = args[0];
i = 1;
}
for (; i < args.length; i++) {
String a = args[i];
if (!a.startsWith("--")) {
cfg.positional.add(a);
continue;
}
switch (a) {
case "--compress" -> cfg.compress = args[++i];
case "--include" -> cfg.include.add(args[++i]);
case "--exclude" -> cfg.exclude.add(args[++i]);
case "--output" -> cfg.output = args[++i];
case "--verify" -> cfg.verify = true;
case "--log" -> cfg.log = args[++i];
default -> throw new IllegalArgumentException("Unknown option: " + a);
}
}
return cfg;
}
private static String q(String s) { return '"' + s.replace("\"", "\\\"") + '"'; }
private static String run(String cmd) throws Exception {
Process p = new ProcessBuilder("bash", "-lc", cmd).redirectErrorStream(true).start();
String out;
try (InputStream in = p.getInputStream()) { out = new String(in.readAllBytes(), StandardCharsets.UTF_8); }
int rc = p.waitFor();
if (rc != 0) throw new RuntimeException("Command failed (" + rc + "): " + cmd + "\n" + out);
return out;
}
private static String flags(String compress) {
return switch (compress) {
case "gzip" -> "z";
case "bzip2" -> "j";
case "xz" -> "J";
default -> "";
};
}
private static String defaultArchive(String base, String compress) {
return switch (compress) {
case "gzip" -> base + ".tar.gz";
case "bzip2" -> base + ".tar.bz2";
case "xz" -> base + ".tar.xz";
default -> base + ".tar";
};
}
private static List<String> listEntries(String archive) throws Exception {
String out = run("tar -tvf " + q(archive));
return out.lines().filter(s -> !s.isBlank()).toList();
}
private static Map<String, Object> createArchive(Config cfg) throws Exception {
if (cfg.positional.size() < 2) throw new IllegalArgumentException("Usage: create <archive_base_or_path> <file|dir> [...]");
String archive = cfg.output != null ? cfg.output : defaultArchive(cfg.positional.get(0), cfg.compress);
List<String> inputs = cfg.positional.subList(1, cfg.positional.size());
StringBuilder cmd = new StringBuilder("tar -c" + flags(cfg.compress) + "f " + q(archive) + " ");
for (String ex : cfg.exclude) cmd.append("--exclude=").append(q(ex)).append(' ');
for (String in : inputs) cmd.append(q(in)).append(' ');
run(cmd.toString());
List<String> entries = listEntries(archive);
Map<String, Object> res = new LinkedHashMap<>();
res.put("operation", "create");
res.put("archive", Paths.get(archive).toAbsolutePath().toString());
res.put("entries", entries);
res.put("summary", Map.of("totalFiles", entries.size()));
return res;
}
private static Map<String, Object> extractArchive(Config cfg) throws Exception {
if (cfg.positional.isEmpty()) throw new IllegalArgumentException("Usage: extract <archive> [paths...]");
String archive = cfg.positional.get(0);
String outDir = cfg.output == null ? "." : cfg.output;
Files.createDirectories(Paths.get(outDir));
String files = String.join(" ", cfg.positional.subList(1, cfg.positional.size()).stream().map(TarArchiveHandler::q).toList());
run("tar -xf " + q(archive) + " -C " + q(outDir) + " " + files);
Boolean verify = null;
if (cfg.verify) {
run("tar -tf " + q(archive));
verify = true;
}
return new LinkedHashMap<>(Map.of(
"operation", "extract",
"archive", Paths.get(archive).toAbsolutePath().toString(),
"outputDirectory", Paths.get(outDir).toAbsolutePath().toString(),
"verify", verify
));
}
private static Map<String, Object> listArchive(Config cfg) throws Exception {
if (cfg.positional.isEmpty()) throw new IllegalArgumentException("Usage: list <archive>");
String archive = cfg.positional.get(0);
List<String> entries = listEntries(archive);
Map<String, Object> res = new LinkedHashMap<>();
res.put("operation", "list");
res.put("archive", Paths.get(archive).toAbsolutePath().toString());
res.put("entries", entries);
res.put("summary", Map.of("totalFiles", entries.size()));
return res;
}
private static Map<String, Object> appendArchive(Config cfg) throws Exception {
if (cfg.positional.size() < 2) throw new IllegalArgumentException("Usage: append <archive.tar> <file|dir> [...]");
String archive = cfg.positional.get(0);
if (!archive.endsWith(".tar")) throw new IllegalArgumentException("append only supports uncompressed .tar archives");
String inputs = String.join(" ", cfg.positional.subList(1, cfg.positional.size()).stream().map(TarArchiveHandler::q).toList());
run("tar -rf " + q(archive) + " " + inputs);
List<String> entries = listEntries(archive);
Map<String, Object> res = new LinkedHashMap<>();
res.put("operation", "append");
res.put("archive", Paths.get(archive).toAbsolutePath().toString());
res.put("entries", entries);
res.put("summary", Map.of("totalFiles", entries.size()));
return res;
}
private static void runDemo() throws Exception {
Path root = Paths.get("sample_tar_data").toAbsolutePath();
deleteRec(root);
Files.createDirectories(root.resolve("docs"));
Files.createDirectories(root.resolve("assets"));
Files.writeString(root.resolve("docs/readme.txt"), "Sample tar data\n", StandardCharsets.UTF_8);
Files.writeString(root.resolve("docs/table.csv"), "id,name\n1,A\n2,B\n", StandardCharsets.UTF_8);
Files.write(root.resolve("assets/blob.bin"), new byte[2048]);
Map<String, Object> plain = createArchive(newConfig("create", List.of("sample_plain", root.toString()), "none", null));
Map<String, Object> gzip = createArchive(newConfig("create", List.of("sample_gzip", root.toString()), "gzip", null));
Map<String, Object> bzip2 = createArchive(newConfig("create", List.of("sample_bzip2", root.toString()), "bzip2", null));
Map<String, Object> xz = createArchive(newConfig("create", List.of("sample_xz", root.toString()), "xz", null));
Map<String, Object> list = listArchive(newConfig("list", List.of((String) gzip.get("archive")), "none", null));
Config ex = newConfig("extract", List.of((String) gzip.get("archive")), "none", "sample_tar_extract");
ex.verify = true;
Map<String, Object> extract = extractArchive(ex);
Map<String, Object> report = new LinkedHashMap<>();
report.put("generatedAt", Instant.now().toString());
report.put("plain", plain);
report.put("gzip", gzip);
report.put("bzip2", bzip2);
report.put("xz", xz);
report.put("list", list);
report.put("extract", extract);
Files.writeString(Paths.get("tar_demo_report.json"), toJson(report), StandardCharsets.UTF_8);
@SuppressWarnings("unchecked") List<String> entries = (List<String>) list.get("entries");
entries.forEach(System.out::println);
}
private static Config newConfig(String cmd, List<String> positional, String compress, String output) {
Config c = new Config();
c.cmd = cmd;
c.positional = new ArrayList<>(positional);
c.compress = compress;
c.output = output;
return c;
}
private static void deleteRec(Path p) throws IOException {
if (!Files.exists(p)) return;
if (Files.isDirectory(p)) {
try (DirectoryStream<Path> ds = Files.newDirectoryStream(p)) {
for (Path c : ds) deleteRec(c);
}
}
Files.deleteIfExists(p);
}
private static String toJson(Object obj) {
if (obj == null) return "null";
if (obj instanceof String s) return '"' + s.replace("\\", "\\\\").replace("\"", "\\\"") + '"';
if (obj instanceof Number || obj instanceof Boolean) return obj.toString();
if (obj instanceof Map<?, ?> m) {
StringBuilder sb = new StringBuilder("{");
boolean first = true;
for (Map.Entry<?, ?> e : m.entrySet()) {
if (!first) sb.append(',');
first = false;
sb.append(toJson(String.valueOf(e.getKey()))).append(':').append(toJson(e.getValue()));
}
sb.append('}');
return sb.toString();
}
if (obj instanceof Iterable<?> it) {
StringBuilder sb = new StringBuilder("[");
boolean first = true;
for (Object x : it) {
if (!first) sb.append(',');
first = false;
sb.append(toJson(x));
}
sb.append(']');
return sb.toString();
}
return toJson(String.valueOf(obj));
}
}