fix: address c-review for -R/--dirs/--mkpath row
B1: destination-root existence/creation mishandled two legitimate forms. file_directory_exists_secure/file_ensure_directory_secure now normalize a trailing-slash destination (so the last component is never an empty leaf) and treat a destination equal to the already-open authorized root as present (no spurious <root>/<basename> nested dir with --mkpath). Confinement and O_NOFOLLOW probing are unchanged. Regression integration tests: existing dest with trailing slash works with and without --mkpath; dest == authorized root works and creates no stray nested dir. W1: chunk serialize/deserialize round-trip unit test for a directory entry mixed with a regular file, with and without metadata; --dirs coverage under -s and -s -m. W2: --list-only and --dry-run now print file_wire_path() so all outputs show the -R transformed relative name, matching -i/--out-format. W3: RSYNC_COMPAT -d/--dirs note: dirs are created immediately under --delay-updates (only regular files are staged). W4: --dirs generator flushes chunks by element count too, so a long --files-from list of empty directories cannot exceed the per-chunk file cap. N1: STATUS_MKDIR added to status_to_string. N2: removed dead TestMkpath._transfer. N3: removed redundant --no-implied-dirs OPTION_TABLE row. N4: integration tests: --dirs --delete keeps the just-created empty dir (and deletes extras); a listed dir colliding with a regular file at the dest fails cleanly.
This commit is contained in:
@@ -89,7 +89,78 @@ static void test_chunk_operations() {
|
||||
unlink(path2);
|
||||
}
|
||||
|
||||
/* A chunk mixing a regular file and an explicit directory entry (--dirs, with
|
||||
* or without metadata) must round-trip through serialize/deserialize with the
|
||||
* is_dir flag and the entry type marker preserved. */
|
||||
static void test_chunk_dir_entry_roundtrip() {
|
||||
const char* file_path = "temp_chunk_dir_file.txt";
|
||||
const char* dir_path = "temp_chunk_dir_entry";
|
||||
const char* content = "regular file payload";
|
||||
|
||||
/* A failed earlier run can leave artifacts behind; start clean. */
|
||||
rmdir(dir_path);
|
||||
unlink(file_path);
|
||||
|
||||
file_write_to_disk(file_path, content, strlen(content), false, false);
|
||||
EXPECT_EQ_INT(mkdir(dir_path, 0755), 0);
|
||||
|
||||
for (int use_metadata = 0; use_metadata <= 1; use_metadata++) {
|
||||
struct stat st;
|
||||
EXPECT_EQ_INT(stat(file_path, &st), 0);
|
||||
|
||||
File* reg = file_create(file_path);
|
||||
EXPECT_NOT_NULL(reg);
|
||||
reg->data->size = (unsigned long long)st.st_size;
|
||||
EXPECT_TRUE(file_load_data(reg));
|
||||
|
||||
File* dir = file_create(dir_path);
|
||||
EXPECT_NOT_NULL(dir);
|
||||
dir->is_dir = true;
|
||||
|
||||
if (use_metadata) {
|
||||
reg->metadata = file_metadata_create(&st);
|
||||
EXPECT_NOT_NULL(reg->metadata);
|
||||
struct stat dst;
|
||||
EXPECT_EQ_INT(stat(dir_path, &dst), 0);
|
||||
dir->metadata = file_metadata_create(&dst);
|
||||
EXPECT_NOT_NULL(dir->metadata);
|
||||
}
|
||||
|
||||
File* files[2] = {reg, dir};
|
||||
Chunk* chunk = chunk_create(files, 2);
|
||||
EXPECT_NOT_NULL(chunk);
|
||||
|
||||
Data* serialized = chunk_serialize(chunk, use_metadata != 0);
|
||||
EXPECT_NOT_NULL(serialized);
|
||||
Chunk* deserialized = chunk_deserialize(serialized, use_metadata != 0);
|
||||
EXPECT_NOT_NULL(deserialized);
|
||||
EXPECT_EQ_INT(deserialized->element_count, 2);
|
||||
EXPECT_FALSE(deserialized->items[0]->is_dir);
|
||||
EXPECT_EQ_STR(deserialized->items[0]->path, file_path);
|
||||
EXPECT_EQ_INT((int)deserialized->items[0]->data->size, (int)strlen(content));
|
||||
EXPECT_EQ_INT(memcmp(deserialized->items[0]->data->data, content, strlen(content)), 0);
|
||||
EXPECT_TRUE(deserialized->items[1]->is_dir);
|
||||
EXPECT_EQ_STR(deserialized->items[1]->path, dir_path);
|
||||
EXPECT_EQ_INT((int)deserialized->items[1]->data->size, 0);
|
||||
if (use_metadata) {
|
||||
EXPECT_NOT_NULL(deserialized->items[0]->metadata);
|
||||
EXPECT_NOT_NULL(deserialized->items[1]->metadata);
|
||||
} else {
|
||||
EXPECT_NULL(deserialized->items[0]->metadata);
|
||||
EXPECT_NULL(deserialized->items[1]->metadata);
|
||||
}
|
||||
|
||||
data_destroy(serialized);
|
||||
chunk_destroy(deserialized);
|
||||
chunk_destroy(chunk); /* frees reg and dir */
|
||||
}
|
||||
|
||||
unlink(file_path);
|
||||
rmdir(dir_path);
|
||||
}
|
||||
|
||||
void test_chunk() {
|
||||
test_file_operations();
|
||||
test_chunk_operations();
|
||||
test_chunk_dir_entry_roundtrip();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user