- #286: --numeric-ids is a mapping modifier only; it no longer activates chown by itself (identity_active_enabled/owner/group predicates), and --fake-super stores the resolved mapping instead of real-chowning. - #286: apply owner/group to directories via the deferred directory metadata path; capture+transmit+apply directory xattrs/ACLs (-aX/-aA), including default ACLs, in STATUS_MKDIR/STATUS_DIR_TIMES. - #294: --usermap/--groupmap support inclusive ranges, '*', empty FROM (unnamed ids), and receiver-side TO name resolution; --chown mixing with a same-side map is rejected like rsync. - Protocol 2.22.0 -> 2.23.0 (map wire entry gains from_hi + to_name; dir frames gain a bounded xattr block).
This commit is contained in:
+39
-15
@@ -1345,13 +1345,19 @@ static void test_config_identity_wire_roundtrip() {
|
||||
send_cfg->usermap_count = 2;
|
||||
send_cfg->usermap = calloc(2, sizeof(IdentityMap));
|
||||
send_cfg->usermap[0].from = IDENTITY_MATCH_ANY;
|
||||
send_cfg->usermap[0].from_hi = IDENTITY_MATCH_ANY;
|
||||
send_cfg->usermap[0].to = 65534;
|
||||
send_cfg->usermap[0].to_name = NULL;
|
||||
send_cfg->usermap[1].from = 1000;
|
||||
send_cfg->usermap[1].from_hi = 1000;
|
||||
send_cfg->usermap[1].to = 1000;
|
||||
send_cfg->usermap[1].to_name = NULL;
|
||||
send_cfg->groupmap_count = 1;
|
||||
send_cfg->groupmap = calloc(1, sizeof(IdentityMap));
|
||||
send_cfg->groupmap[0].from = 0;
|
||||
send_cfg->groupmap[0].from_hi = 0;
|
||||
send_cfg->groupmap[0].to = IDENTITY_CURRENT;
|
||||
send_cfg->groupmap[0].to_name = str_dup("root");
|
||||
|
||||
int p[2];
|
||||
EXPECT_EQ_INT(socketpair(AF_UNIX, SOCK_STREAM, 0, p), 0);
|
||||
@@ -1367,9 +1373,12 @@ static void test_config_identity_wire_roundtrip() {
|
||||
ok = recv->numeric_ids && recv->chown_uid_set && recv->chown_uid == 1001 &&
|
||||
recv->chown_gid_set && recv->chown_gid == IDENTITY_CURRENT && recv->usermap_count == 2 &&
|
||||
recv->groupmap_count == 1 && recv->usermap[0].from == IDENTITY_MATCH_ANY &&
|
||||
recv->usermap[0].to == 65534 && recv->usermap[1].from == 1000 &&
|
||||
recv->usermap[1].to == 1000 && recv->groupmap[0].from == 0 &&
|
||||
recv->groupmap[0].to == IDENTITY_CURRENT;
|
||||
recv->usermap[0].from_hi == IDENTITY_MATCH_ANY && recv->usermap[0].to == 65534 &&
|
||||
recv->usermap[0].to_name == NULL && recv->usermap[1].from == 1000 &&
|
||||
recv->usermap[1].from_hi == 1000 && recv->usermap[1].to == 1000 &&
|
||||
recv->groupmap[0].from == 0 && recv->groupmap[0].from_hi == 0 &&
|
||||
recv->groupmap[0].to == IDENTITY_CURRENT && recv->groupmap[0].to_name != NULL &&
|
||||
strcmp(recv->groupmap[0].to_name, "root") == 0;
|
||||
}
|
||||
config_delete(recv);
|
||||
close(p[0]);
|
||||
@@ -1399,7 +1408,8 @@ static void test_config_receive_rejects_invalid_identity() {
|
||||
c->receive_root_directory = str_dup("/dst");
|
||||
c->usermap_count = 1;
|
||||
c->usermap = calloc(1, sizeof(IdentityMap));
|
||||
c->usermap[0].from = -2; /* below IDENTITY_MATCH_ANY */
|
||||
c->usermap[0].from = -3; /* below IDENTITY_MATCH_UNNAMED */
|
||||
c->usermap[0].from_hi = -3;
|
||||
c->usermap[0].to = 0;
|
||||
EXPECT_FALSE(roundtrip_config_ok(c));
|
||||
config_delete(c);
|
||||
@@ -2101,8 +2111,10 @@ static void test_identity_explicit_ownership_requested() {
|
||||
}
|
||||
|
||||
/* P7 Wave E hardening (A3): --super no longer implies raw numeric-id
|
||||
preservation, so it must never enable ownership application on its own; an
|
||||
explicit identity flag is required. */
|
||||
preservation, so it must never enable ownership application on its own.
|
||||
#286: --numeric-ids is a mapping MODIFIER only and is likewise inert on its
|
||||
own; a real ownership request (-o/-g or an explicit identity flag) is
|
||||
required to activate chown. */
|
||||
static void test_super_does_not_imply_numeric() {
|
||||
Config* c = config_create();
|
||||
EXPECT_NOT_NULL(c);
|
||||
@@ -2112,6 +2124,9 @@ static void test_super_does_not_imply_numeric() {
|
||||
EXPECT_FALSE(identity_active_enabled());
|
||||
c->numeric_ids = true;
|
||||
EXPECT_TRUE(identity_set_active(c));
|
||||
EXPECT_FALSE(identity_active_enabled()); /* mapping modifier only */
|
||||
c->preserve_owner = true;
|
||||
EXPECT_TRUE(identity_set_active(c));
|
||||
EXPECT_TRUE(identity_active_enabled());
|
||||
identity_clear_active();
|
||||
config_delete(c);
|
||||
@@ -2635,13 +2650,19 @@ static void golden_config_populate(Config* c) {
|
||||
c->usermap_count = 2;
|
||||
c->usermap = calloc(2, sizeof(IdentityMap));
|
||||
c->usermap[0].from = IDENTITY_MATCH_ANY;
|
||||
c->usermap[0].from_hi = IDENTITY_MATCH_ANY;
|
||||
c->usermap[0].to = 1000;
|
||||
c->usermap[0].to_name = NULL;
|
||||
c->usermap[1].from = 5;
|
||||
c->usermap[1].from_hi = 9;
|
||||
c->usermap[1].to = 6;
|
||||
c->usermap[1].to_name = NULL;
|
||||
c->groupmap_count = 1;
|
||||
c->groupmap = calloc(1, sizeof(IdentityMap));
|
||||
c->groupmap[0].from = 7;
|
||||
c->groupmap[0].from_hi = 7;
|
||||
c->groupmap[0].to = 8;
|
||||
c->groupmap[0].to_name = str_dup("root");
|
||||
c->preserve_atimes = true;
|
||||
c->preserve_crtimes = false;
|
||||
c->omit_dir_times = true;
|
||||
@@ -2665,14 +2686,14 @@ static void golden_config_populate(Config* c) {
|
||||
c->copy_as_gid = 222;
|
||||
}
|
||||
|
||||
/* The pinned golden frame (protocol 2.22.0). The values below are the only
|
||||
/* The pinned golden frame (protocol 2.23.0). The values below are the only
|
||||
* thing that ties the generated table to the historical wire format; update
|
||||
* them ONLY with a PROTOCOL_VERSION bump and a documented reason. The 2.22.0
|
||||
* preserve-attribute split appends four serialized bools
|
||||
* (preserve_perms/times/owner/group) to CONFIG_WIRE_METADATA_TIMES_FIELDS after
|
||||
* omit_link_times. */
|
||||
#define GOLDEN_WIRE_LEN 653
|
||||
#define GOLDEN_WIRE_HASH 95530566005420798ULL
|
||||
* them ONLY with a PROTOCOL_VERSION bump and a documented reason. The 2.23.0
|
||||
* ownership-parity wave extends each --usermap/--groupmap wire entry with
|
||||
* from_hi + a TO-name string (and the earlier preserve-attribute split appended
|
||||
* four serialized bools after omit_link_times). */
|
||||
#define GOLDEN_WIRE_LEN 693
|
||||
#define GOLDEN_WIRE_HASH 6341115972171444885ULL
|
||||
|
||||
static unsigned long long fnv1a_64(const unsigned char* buf, size_t len) {
|
||||
unsigned long long h = 1469598103934665603ULL;
|
||||
@@ -2754,7 +2775,7 @@ static unsigned long long capture_wire_hash(const Config* cfg, size_t* out_len)
|
||||
return h;
|
||||
}
|
||||
|
||||
/* Byte-for-byte wire compatibility guard (protocol 2.22.0). The expected hash
|
||||
/* Byte-for-byte wire compatibility guard (protocol 2.23.0). The expected hash
|
||||
* pins the pre-X-macro byte stream; the refactor MUST NOT change it. */
|
||||
static void test_config_wire_golden() {
|
||||
if (is_running_under_valgrind())
|
||||
@@ -2815,7 +2836,10 @@ static void test_config_wire_golden_receive() {
|
||||
ok = ok && recv->super_mode == SUPER_MODE_ON;
|
||||
ok = ok && recv->chown_uid == 1234 && recv->chown_gid == 5678;
|
||||
ok = ok && recv->usermap_count == 2 && recv->usermap[0].from == IDENTITY_MATCH_ANY &&
|
||||
recv->usermap[0].to == 1000 && recv->usermap[1].from == 5 && recv->usermap[1].to == 6;
|
||||
recv->usermap[0].from_hi == IDENTITY_MATCH_ANY && recv->usermap[0].to == 1000 &&
|
||||
recv->usermap[1].from == 5 && recv->usermap[1].from_hi == 9 && recv->usermap[1].to == 6;
|
||||
ok = ok && recv->groupmap_count == 1 && recv->groupmap[0].from == 7 &&
|
||||
recv->groupmap[0].to_name != NULL && strcmp(recv->groupmap[0].to_name, "root") == 0;
|
||||
ok = ok && recv->basis_count == 2 && recv->basis_dirs[0].type == BASIS_DEST_COMPARE &&
|
||||
recv->basis_dirs[1].type == BASIS_DEST_LINK;
|
||||
ok = ok && recv->module != NULL && strcmp(recv->module, "goldenmod") == 0;
|
||||
|
||||
Reference in New Issue
Block a user