fix(parity): accept rsync client aliases, --iconv=. / - and lone -h
- --ignore-non-existing (alias of --existing) - --protect-args (pre-3.2.6 --secluded-args no-op) - --msgs2stderr / --no-msgs2stderr (deprecated --stderr=all/client) - --iconv=. (locale codeset via nl_langinfo), --iconv=- and --no-iconv (disable) - lone -h prints help and exits 0; -h elsewhere stays human-readable
This commit is contained in:
@@ -20,7 +20,9 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <langinfo.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <locale.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -792,6 +794,9 @@ static const OptionEntry OPTION_TABLE[] = {
|
|||||||
{"--human-readable", "-h", OPT_FLAG, offsetof(Config, human_readable)},
|
{"--human-readable", "-h", OPT_FLAG, offsetof(Config, human_readable)},
|
||||||
{"--partial", NULL, OPT_FLAG, offsetof(Config, partial)},
|
{"--partial", NULL, OPT_FLAG, offsetof(Config, partial)},
|
||||||
{"--secluded-args", "-s", OPT_NOOP, 0},
|
{"--secluded-args", "-s", OPT_NOOP, 0},
|
||||||
|
/* rsync's pre-3.2.6 name for --secluded-args (--protect-args) is accepted
|
||||||
|
* as the same secure-argv no-op. */
|
||||||
|
{"--protect-args", NULL, OPT_NOOP, 0},
|
||||||
/* rsync -r/--recursive: FastSync is always recursive, so this is a
|
/* rsync -r/--recursive: FastSync is always recursive, so this is a
|
||||||
* faithful no-op (accepted silently, never consumes an argument). */
|
* faithful no-op (accepted silently, never consumes an argument). */
|
||||||
{"--recursive", "-r", OPT_NOOP, 0},
|
{"--recursive", "-r", OPT_NOOP, 0},
|
||||||
@@ -820,6 +825,8 @@ static const OptionEntry OPTION_TABLE[] = {
|
|||||||
{"--out-format", NULL, OPT_STRING, offsetof(Config, out_format)},
|
{"--out-format", NULL, OPT_STRING, offsetof(Config, out_format)},
|
||||||
{"--log-file-format", NULL, OPT_STRING, offsetof(Config, log_file_format)},
|
{"--log-file-format", NULL, OPT_STRING, offsetof(Config, log_file_format)},
|
||||||
{"--existing", NULL, OPT_FLAG, offsetof(Config, existing)},
|
{"--existing", NULL, OPT_FLAG, offsetof(Config, existing)},
|
||||||
|
/* rsync's man-page alias for --existing (--ignore-non-existing). */
|
||||||
|
{"--ignore-non-existing", NULL, OPT_FLAG, offsetof(Config, existing)},
|
||||||
{"--ignore-existing", NULL, OPT_FLAG, offsetof(Config, ignore_existing)},
|
{"--ignore-existing", NULL, OPT_FLAG, offsetof(Config, ignore_existing)},
|
||||||
{"--delay-updates", NULL, OPT_FLAG, offsetof(Config, delay_updates)},
|
{"--delay-updates", NULL, OPT_FLAG, offsetof(Config, delay_updates)},
|
||||||
{"--chmod", NULL, OPT_STRING, offsetof(Config, chmod_spec)},
|
{"--chmod", NULL, OPT_STRING, offsetof(Config, chmod_spec)},
|
||||||
@@ -1034,6 +1041,26 @@ static int apply_negation(Config* config, const char* arg) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* rsync's --iconv accepted extra spellings beyond explicit charset pairs:
|
||||||
|
* "." selects the locale's default charset for both directions, and "-" (or
|
||||||
|
* --no-iconv) disables conversion entirely. Normalize both here so the rest
|
||||||
|
* of the pipeline only ever sees a real charset spec or NULL. */
|
||||||
|
static int set_iconv_option(char** field, const char* value) {
|
||||||
|
if (value && strcmp(value, "-") == 0) {
|
||||||
|
free(*field);
|
||||||
|
*field = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (value && strcmp(value, ".") == 0) {
|
||||||
|
setlocale(LC_ALL, "");
|
||||||
|
const char* codeset = nl_langinfo(CODESET);
|
||||||
|
if (!codeset || codeset[0] == '\0')
|
||||||
|
codeset = "UTF-8";
|
||||||
|
return set_string_option(field, codeset, "--iconv");
|
||||||
|
}
|
||||||
|
return set_string_option(field, value, "--iconv");
|
||||||
|
}
|
||||||
|
|
||||||
static int apply_table_option(Config* config, const OptionEntry* entry, const char* value) {
|
static int apply_table_option(Config* config, const OptionEntry* entry, const char* value) {
|
||||||
if (entry->kind == OPT_NOOP)
|
if (entry->kind == OPT_NOOP)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1047,6 +1074,8 @@ static int apply_table_option(Config* config, const OptionEntry* entry, const ch
|
|||||||
case OPT_STRING:
|
case OPT_STRING:
|
||||||
if (entry->offset == offsetof(Config, chmod_spec))
|
if (entry->offset == offsetof(Config, chmod_spec))
|
||||||
return append_chmod_spec((char**)field, value);
|
return append_chmod_spec((char**)field, value);
|
||||||
|
if (entry->offset == offsetof(Config, iconv_spec))
|
||||||
|
return set_iconv_option((char**)field, value);
|
||||||
return set_string_option((char**)field, value, entry->name);
|
return set_string_option((char**)field, value, entry->name);
|
||||||
case OPT_POS_INT:
|
case OPT_POS_INT:
|
||||||
return set_positive_int_option((int*)field, value, entry->name);
|
return set_positive_int_option((int*)field, value, entry->name);
|
||||||
@@ -1125,6 +1154,19 @@ static bool cli_handle_pre_negation(CliParseCtx* ctx) {
|
|||||||
config->no_implied_dirs = true;
|
config->no_implied_dirs = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
/* "--no-iconv" is a real rsync option name that turns charset conversion off
|
||||||
|
* (the negation of the argument-taking --iconv), so it is handled before the
|
||||||
|
* generic --no-* negation branch. */
|
||||||
|
if (strcmp(arg, "--no-iconv") == 0) {
|
||||||
|
free(config->iconv_spec);
|
||||||
|
config->iconv_spec = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/* "--no-msgs2stderr" is the deprecated spelling of --stderr=client (rsync
|
||||||
|
* 3.4.1). FastSync has no separate client message channel, so the closest
|
||||||
|
* supported mode is the errors-only default. */
|
||||||
|
if (strcmp(arg, "--no-msgs2stderr") == 0)
|
||||||
|
return set_stderr_mode("errors") == 0;
|
||||||
/* "--no-motd" is a real rsync option name (client-side daemon MOTD display
|
/* "--no-motd" is a real rsync option name (client-side daemon MOTD display
|
||||||
* suppression), not a negation of a "--motd" flag, so it is handled before
|
* suppression), not a negation of a "--motd" flag, so it is handled before
|
||||||
* the generic --no-* negation branch. */
|
* the generic --no-* negation branch. */
|
||||||
@@ -1795,6 +1837,12 @@ static bool cli_handle_io_options(CliParseCtx* ctx) {
|
|||||||
ctx->exit_code = -1;
|
ctx->exit_code = -1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
/* rsync's deprecated spelling of --stderr=all. */
|
||||||
|
if (opt_is(arg, "--msgs2stderr", NULL)) {
|
||||||
|
if (set_stderr_mode("all") != 0)
|
||||||
|
ctx->exit_code = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2505,6 +2553,13 @@ int parse_args(Config* config, int argc, char* argv[], int* positional_args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int result = -1;
|
int result = -1;
|
||||||
|
/* rsync treats a lone -h as a help request (it only means human-readable
|
||||||
|
* when combined with a source/destination or other options). */
|
||||||
|
if (exp_argc == 2 && strcmp(exp_argv[1], "-h") == 0) {
|
||||||
|
print_usage();
|
||||||
|
result = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
int output_ret = cli_apply_output_controls(config, exp_argc, exp_argv);
|
int output_ret = cli_apply_output_controls(config, exp_argc, exp_argv);
|
||||||
if (output_ret != 0) {
|
if (output_ret != 0) {
|
||||||
result = output_ret;
|
result = output_ret;
|
||||||
|
|||||||
Reference in New Issue
Block a user