fix: free basis path on copy-dest hits; keep --delete staging skip top-level-only
- copy-dest basis hits leaked the heap-allocated basis path: BASIS_DEST_COPY did not transfer it (only LINK does) and returned before the basis cleanup. basis_match_free is now called on every materialization return path (success and send-failure) after content/link ownership is transferred. - the --delete walker regression: the delay-updates staging name must be protected only as a DIRECT child of the receive root, while basis dirs may be skipped at any depth. delete_extras_limited now takes DeleteSkipEntry entries carrying a top_level_only flag instead of a flat prefix list, so a nested destination directory named .fastsync-stage is ordinary content again (its extras are deleted) and a basis tree is still never removed.
This commit is contained in:
+14
-7
@@ -10,14 +10,21 @@ char* output_escape(const char* string, bool eight_bit_output);
|
||||
char* path_cat(const char* path1, const char* path2);
|
||||
bool glob_match(const char* pattern, const char* str);
|
||||
bool delete_extras(const char* dest_root, ArrayList* manifest);
|
||||
/* Remove files/dirs under dest_root that are not listed in manifest. The
|
||||
delete walker never descends into (and so never removes) an entry whose
|
||||
relative path equals one of the skip_prefixes or lies below one: used to
|
||||
protect the --delay-updates staging directory (files still to be published)
|
||||
and the --compare-dest/--copy-dest/--link-dest basis trees (snapshots the
|
||||
transfer links from, never destination content). */
|
||||
/* One protected entry for the delete walker. When top_level_only is true the
|
||||
prefix is skipped only as a DIRECT child of dest_root (the --delay-updates
|
||||
staging directory, which must not hide genuine extras inside a nested
|
||||
destination directory that happens to share the staging name); otherwise the
|
||||
prefix is skipped at any depth (the --compare-dest/--copy-dest/--link-dest
|
||||
basis trees, which the transfer links from and are never destination
|
||||
content). */
|
||||
typedef struct {
|
||||
const char* prefix;
|
||||
bool top_level_only;
|
||||
} DeleteSkipEntry;
|
||||
/* Remove files/dirs under dest_root that are not listed in manifest without
|
||||
ever descending into a protected prefix (see DeleteSkipEntry). */
|
||||
bool delete_extras_limited(const char* dest_root, ArrayList* manifest, size_t max_delete,
|
||||
const char* const* skip_prefixes, int skip_prefix_count);
|
||||
const DeleteSkipEntry* skips, int skip_count);
|
||||
bool utils_set_authorized_root(int fd, const char* canonical_path);
|
||||
/* The fd-only compatibility form is fail-closed for path-based operations;
|
||||
* callers should use utils_set_authorized_root with the canonical identity. */
|
||||
|
||||
Reference in New Issue
Block a user