diff --git a/src/metaentry.c b/src/metaentry.c index da28723..8987813 100644 --- a/src/metaentry.c +++ b/src/metaentry.c @@ -193,7 +193,7 @@ mentries_print(const struct metahash *mhash) /* Creates a metaentry for the file/dir/etc at path */ struct metaentry * -mentry_create(const char *path) +mentry_create(const char *path, msettings *st) { #if !defined(NO_XATTR) || !(NO_XATTR+0) ssize_t lsize, vsize; @@ -214,15 +214,17 @@ mentry_create(const char *path) } pbuf = xgetpwuid(sbuf.st_uid); - if (!pbuf) { - msg(MSG_ERROR, "getpwuid failed for %s: uid %i not found\n", + if (!pbuf && !st->owner) { + msg(MSG_ERROR, "getpwuid failed for %s: uid %i not found, " + "you can use `--owner' (`-O') to manually specify it.\n", path, (int)sbuf.st_uid); return NULL; } gbuf = xgetgrgid(sbuf.st_gid); - if (!gbuf) { - msg(MSG_ERROR, "getgrgid failed for %s: gid %i not found\n", + if (!gbuf && !st->group) { + msg(MSG_ERROR, "getgrgid failed for %s: gid %i not found, " + "you can use `--group' (`-G') to manually specify it.\n", path, (int)sbuf.st_gid); return NULL; } @@ -230,8 +232,8 @@ mentry_create(const char *path) mentry = mentry_alloc(); mentry->path = xstrdup(path); mentry->pathlen = strlen(mentry->path); - mentry->owner = xstrdup(pbuf->pw_name); - mentry->group = xstrdup(gbuf->gr_name); + mentry->owner = pbuf ? xstrdup(pbuf->pw_name) : st->owner; + mentry->group = gbuf ? xstrdup(gbuf->gr_name) : st->group; mentry->mode = sbuf.st_mode & 0177777; mentry->mtime = sbuf.st_mtim.tv_sec; mentry->mtimensec = sbuf.st_mtim.tv_nsec; @@ -359,7 +361,7 @@ mentries_recurse(const char *path, struct metahash *mhash, msettings *st) return; } - mentry = mentry_create(path); + mentry = mentry_create(path, st); if (!mentry) return; diff --git a/src/metaentry.h b/src/metaentry.h index d5f209d..0fbcfe7 100644 --- a/src/metaentry.h +++ b/src/metaentry.h @@ -54,7 +54,7 @@ struct metahash { }; /* Create a metaentry for the file/dir/etc at path */ -struct metaentry *mentry_create(const char *path); +struct metaentry *mentry_create(const char *path, msettings *st); /* Recurses opath and adds metadata entries to the metaentry list */ void mentries_recurse_path(const char *opath, struct metahash **mhash, diff --git a/src/metastore.c b/src/metastore.c index d85f0bc..0a2fefa 100644 --- a/src/metastore.c +++ b/src/metastore.c @@ -43,6 +43,8 @@ /* metastore settings */ static struct metasettings settings = { .metafile = METAFILE, + .owner = NULL, + .group = NULL, .do_mtime = false, .do_emptydirs = false, .do_removeemptydirs = false, @@ -285,7 +287,7 @@ compare_fix(struct metaentry *real, struct metaentry *stored, int cmp) * recreating them. */ static void -fixup_emptydirs(void) +fixup_emptydirs(msettings *st) { struct metaentry *entry; struct metaentry *cur; @@ -363,7 +365,7 @@ fixup_emptydirs(void) } msg(MSG_QUIET, "ok\n"); - new = mentry_create(cur->path); + new = mentry_create(cur->path, st); if (!new) { msg(MSG_QUIET, "Failed to get metadata for %s\n", cur->path); continue; @@ -462,6 +464,8 @@ usage(const char *arg0, const char *message) " -E, --remove-empty-dirs Remove extra empty directories\n" " -g, --git Do not omit .git directories\n" " -f, --file=FILE Set metadata file (" METAFILE " by default)\n" +" -O, --owner Owner to use when internal check fails.\n" +" -G, --group Group to use when internal check fails.\n" ); exit(message ? EXIT_FAILURE : EXIT_SUCCESS); @@ -482,6 +486,8 @@ static struct option long_options[] = { { "remove-empty-dirs", no_argument, NULL, 'E' }, { "git", no_argument, NULL, 'g' }, { "file", required_argument, NULL, 'f' }, + { "owner", required_argument, NULL, 'O' }, + { "group", required_argument, NULL, 'G' }, { NULL, 0, NULL, 0 } }; @@ -498,7 +504,7 @@ main(int argc, char **argv) i = 0; while (1) { int option_index = 0; - c = getopt_long(argc, argv, "csadVhvqmeEgf:", + c = getopt_long(argc, argv, "csadVhvqmeEgf:O:G:", long_options, &option_index); if (c == -1) break; @@ -517,11 +523,14 @@ main(int argc, char **argv) break; case 'g': /* git */ settings.do_git = true; break; case 'f': /* file */ settings.metafile = optarg; break; + case 'O': /* owner */ settings.owner = optarg; break; + case 'G': /* group */ settings.group = optarg; break; default: usage(argv[0], "unknown option"); } } + /* Make sure only one action is specified */ if (i != 1) usage(argv[0], "incorrect option(s)"); @@ -573,7 +582,7 @@ main(int argc, char **argv) case ACTION_APPLY: mentries_compare(real, stored, compare_fix, &settings); if (settings.do_emptydirs) - fixup_emptydirs(); + fixup_emptydirs(&settings); if (settings.do_removeemptydirs) fixup_newemptydirs(); break; diff --git a/src/settings.h b/src/settings.h index b6baa50..8b5ca3f 100644 --- a/src/settings.h +++ b/src/settings.h @@ -23,6 +23,8 @@ /* Data structure to hold metastore settings */ struct metasettings { char *metafile; /* path to the file containing the metadata */ + char *owner; /* user-provided owner. */ + char *group; /* user-provided group. */ bool do_mtime; /* should mtimes be corrected? */ bool do_emptydirs; /* should empty dirs be recreated? */ bool do_removeemptydirs; /* should new empty dirs be removed? */