fix(p7-times): dir-time entries only record (never create dirs); bound/chunk dir-time frames; harden list add; docs+tests
Review fixes for Phase 7 Wave D. #1 (HIGH): STATUS_DIR_TIMES entries no longer create directories. A new receiver-only File.dir_time_only flag marks dir-time entries; file_save_to_disk_full short-circuits them as FILE_SAVE_SKIPPED before any device/dir branch, so the sink still accumulates metadata into the deferred DirTimeList but creates nothing. Empty source dirs stay untransferred (-a), -m/--prune-empty-dirs semantics are preserved, and a pre-existing regular file/symlink at an empty-dir mirror path no longer aborts the transfer. dir_time_list_apply fstatat()s the leaf (AT_SYMLINK_NOFOLLOW) and skips absent/non-directory paths QUIETLY; only a real existing directory is stamped. Also initialize File.dir_time_only in file_create() (uninitialised garbage otherwise). #2 (MED): send_dir_times() chunks entries into repeated STATUS_DIR_TIMES frames of at most MAX_MANIFEST_ENTRIES, matching the receiver's per-frame bound; the tautological > INT_MAX check is gone. #3 (LOW): dir_time_list_add() assigns each grown array right after its realloc (no dangling) and advances capacity only after both succeed. #4 (LOW): RSYNC_COMPAT.md -- STATUS_MKDIR carries metadata, dir times are transmitted via STATUS_DIR_TIMES and applied at the end, empty dirs are still never created; -m rationale, -O row and Wave D notes updated. Summary counts untouched. #5 (LOW): integration tests for the three #1 scenarios (empty-dir non-creation under -a and -a -m, collision non-abort), scanner test now covers empty-dir capture, and test_file_restore_symlink_metadata asserts the positive apply path when supported. PROTOCOL_VERSION stays 2.17.0; config-frame layout unchanged.
This commit is contained in:
+10
-1
@@ -1265,13 +1265,17 @@ static void test_files_from_relative_send_path() {
|
||||
|
||||
/* P7 Wave D: the recursive scan captures every traversed source directory as an
|
||||
* is_dir File (metadata, no payload) in the shared dir_entries list, including
|
||||
* the transfer root, so the sender can transmit directory times at the end. */
|
||||
* the transfer root and an EMPTY directory. The empty dir is captured even
|
||||
* though the receiver deliberately never creates it, so its time can still be
|
||||
* applied when the destination already holds that directory. */
|
||||
static void test_scanner_captures_directory_times() {
|
||||
const char* root = "test_scan_dirtime";
|
||||
const char* sub = "test_scan_dirtime/sub";
|
||||
const char* empty = "test_scan_dirtime/empty";
|
||||
const char* file1 = "test_scan_dirtime/sub/a.txt";
|
||||
EXPECT_EQ_INT(mkdir(root, 0755), 0);
|
||||
EXPECT_EQ_INT(mkdir(sub, 0755), 0);
|
||||
EXPECT_EQ_INT(mkdir(empty, 0755), 0);
|
||||
create_test_file(file1, "x");
|
||||
|
||||
ArrayList* dirs = array_list_create(file_destroy);
|
||||
@@ -1289,6 +1293,7 @@ static void test_scanner_captures_directory_times() {
|
||||
|
||||
int found_root = 0;
|
||||
int found_sub = 0;
|
||||
int found_empty = 0;
|
||||
for (int i = 0; i < dirs->size; i++) {
|
||||
const File* file = (const File*)dirs->items[i];
|
||||
EXPECT_TRUE(file->is_dir);
|
||||
@@ -1297,13 +1302,17 @@ static void test_scanner_captures_directory_times() {
|
||||
found_root = 1;
|
||||
if (strcmp(file->path, sub) == 0)
|
||||
found_sub = 1;
|
||||
if (strcmp(file->path, empty) == 0)
|
||||
found_empty = 1;
|
||||
}
|
||||
EXPECT_TRUE(found_root);
|
||||
EXPECT_TRUE(found_sub);
|
||||
EXPECT_TRUE(found_empty);
|
||||
|
||||
directory_scanner_destroy(scanner);
|
||||
array_list_delete(dirs);
|
||||
unlink(file1);
|
||||
rmdir(empty);
|
||||
rmdir(sub);
|
||||
rmdir(root);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user