Re: [PATCH] git-archive: accept --owner and --group like GNU tar

2018-01-04 Thread suzuki toshiya

Dear Junio,

Could you tell me your thought about the way for me to go?
Do you agree with his suggestion; "--uid etc is not the right
solution, --include-untracked is better and generic" ? Or,
should I work "--uid etc" further?

Regards,
mpsuzuki

Junio C Hamano wrote:

René Scharfe  writes:


I don't know if it's a good idea, but perhaps we don't even need a new
option.  We could change how pathspecs of untracked files are handled:
Instead of aborting we could include them in the archive.  (Sounds like
the simplest possible interface, but may have practical problems.)


One practical problem is that users who do this

$ git archive HEAD Documentation/ | tar tf -

would be expecting (at least) two different things, depending on the
situation they are in.

So at least you'd need an "--include-untracked" option, I guess.





Re: [PATCH] git-archive: accept --owner and --group like GNU tar

2018-01-03 Thread suzuki toshiya

Hi,


Hmm, it could be reasonable to assume that --append-file
would serve more cases than --uid --gid options. There
might be many people who don't care multiple UID/GID in
the source tarball, but want to append some files to the
archive generated by git-archive. I would take a look how
to do that. A point I'm afraid is that some people may
request to pass the file listing the pathnames instead of
giving many --append-file options (and a few people could
want to have a built-in default list specified by GNU
convention :-)).


Taking a glance on parse-options.h, I could not find the
existing class collecting the operands as an array (or
linked list) from multiple "--xxx=yyy" options. Similar
things might be the collecting the pathnames to pathspec
structure. Should I write something with OPTION_CALLBACK?

Regards,
mpsuzuki

suzuki toshiya wrote:

Dear René ,

By overlooking your response, I was writing a patch to add
uid/gid into zip archive X-D (not finished yet)
https://github.com/mpsuzuki/git/tree/add-zip-uid-gid
However, I found that most unix platforms use infozip's
extension to store uid/gid instead of pkzip's extension...


So this is in the context of generating release tarballs that contain
untracked files as well.  That's done in Git's own Makefile, too:


Oh, I should check other software's tarball :-)


The generated archive leaks the IDs of the user preparing the archive in
the appended entries for untracked files.  I think that's more of a
concern.  Publishing a valid non-root username on your build system may
invite attackers.


Hmm, I was not aware of such security concern about the
tarball including the developers username.


So how about making it possible to append untracked files using git
archive?  This could simplify the dist target for Git as well.  It's
orthogonal to adding the ability to explicitly specify owner and group,
but might suffice in most (all?) cases.


Hmm, it could be reasonable to assume that --append-file
would serve more cases than --uid --gid options. There
might be many people who don't care multiple UID/GID in
the source tarball, but want to append some files to the
archive generated by git-archive. I would take a look how
to do that. A point I'm afraid is that some people may
request to pass the file listing the pathnames instead of
giving many --append-file options (and a few people could
want to have a built-in default list specified by GNU
convention :-)).

I want to hear other experts' comment; no need for me to
work "--uid" "--gid" anymore, and should I switch to
"--append-file" options?

Regards,
mpsuzuki

René Scharfe wrote:

Am 02.01.2018 um 07:58 schrieb suzuki toshiya:

Dear René ,

René Scharfe wrote:

Am 29.12.2017 um 15:05 schrieb suzuki toshiya:

The ownership of files created by git-archive is always
root:root. Add --owner and --group options which work
like the GNU tar equivalent to allow overriding these
defaults.

In which situations do you use the new options?

(The sender would need to know the names and/or IDs on the receiving
end.  And the receiver would need to be root to set both IDs, or be a
group member to set the group ID; I guess the latter is more common.)

Thank you for asking the background.

In the case that additional contents are appended to the tar file
generated by git-archive, the part by git-archive and the part
appended by common tar would have different UID/GID, because common
tar preserves the UID/GID of the original files.

Of cource, both of GNU tar and bsdtar have the options to set
UID/GID manually, but their syntax are different.

In the recent source package of poppler (poppler.freedesktop.org),
there are 2 sets of UID/GIDs are found:
https://poppler.freedesktop.org/poppler-0.62.0.tar.xz

I've discussed with the maintainers of poppler, and there was a
suggestion to propose a feature to git.
https://lists.freedesktop.org/archives/poppler/2017-December/012739.html

So this is in the context of generating release tarballs that contain
untracked files as well.  That's done in Git's own Makefile, too:

  dist: git-archive$(X) configure
  ./git-archive --format=tar \
  --prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
  @mkdir -p $(GIT_TARNAME)
  @cp configure $(GIT_TARNAME)
  @echo $(GIT_VERSION) > $(GIT_TARNAME)/version
  @$(MAKE) -C git-gui TARDIR=../$(GIT_TARNAME)/git-gui dist-version
  $(TAR) rf $(GIT_TARNAME).tar \
  $(GIT_TARNAME)/configure \
  $(GIT_TARNAME)/version \
  $(GIT_TARNAME)/git-gui/version
  @$(RM) -r $(GIT_TARNAME)
  gzip -f -9 $(GIT_TARNAME).tar

Having files with different owners and groups is a non-issue when
extracting with --no-same-owner, which is the default for regular users.
I assume this covers most use cases in the wild.

The generated archive leaks the IDs of the user preparing the archive in
the appended ent

Re: [PATCH] git-archive: accept --owner and --group like GNU tar

2018-01-03 Thread suzuki toshiya

Dear René ,

By overlooking your response, I was writing a patch to add
uid/gid into zip archive X-D (not finished yet)
https://github.com/mpsuzuki/git/tree/add-zip-uid-gid
However, I found that most unix platforms use infozip's
extension to store uid/gid instead of pkzip's extension...


So this is in the context of generating release tarballs that contain
untracked files as well.  That's done in Git's own Makefile, too:


Oh, I should check other software's tarball :-)


The generated archive leaks the IDs of the user preparing the archive in
the appended entries for untracked files.  I think that's more of a
concern.  Publishing a valid non-root username on your build system may
invite attackers.


Hmm, I was not aware of such security concern about the
tarball including the developers username.


So how about making it possible to append untracked files using git
archive?  This could simplify the dist target for Git as well.  It's
orthogonal to adding the ability to explicitly specify owner and group,
but might suffice in most (all?) cases.


Hmm, it could be reasonable to assume that --append-file
would serve more cases than --uid --gid options. There
might be many people who don't care multiple UID/GID in
the source tarball, but want to append some files to the
archive generated by git-archive. I would take a look how
to do that. A point I'm afraid is that some people may
request to pass the file listing the pathnames instead of
giving many --append-file options (and a few people could
want to have a built-in default list specified by GNU
convention :-)).

I want to hear other experts' comment; no need for me to
work "--uid" "--gid" anymore, and should I switch to
"--append-file" options?

Regards,
mpsuzuki

René Scharfe wrote:

Am 02.01.2018 um 07:58 schrieb suzuki toshiya:

Dear René ,

René Scharfe wrote:

Am 29.12.2017 um 15:05 schrieb suzuki toshiya:

The ownership of files created by git-archive is always
root:root. Add --owner and --group options which work
like the GNU tar equivalent to allow overriding these
defaults.

In which situations do you use the new options?

(The sender would need to know the names and/or IDs on the receiving
end.  And the receiver would need to be root to set both IDs, or be a
group member to set the group ID; I guess the latter is more common.)

Thank you for asking the background.

In the case that additional contents are appended to the tar file
generated by git-archive, the part by git-archive and the part
appended by common tar would have different UID/GID, because common
tar preserves the UID/GID of the original files.

Of cource, both of GNU tar and bsdtar have the options to set
UID/GID manually, but their syntax are different.

In the recent source package of poppler (poppler.freedesktop.org),
there are 2 sets of UID/GIDs are found:
https://poppler.freedesktop.org/poppler-0.62.0.tar.xz

I've discussed with the maintainers of poppler, and there was a
suggestion to propose a feature to git.
https://lists.freedesktop.org/archives/poppler/2017-December/012739.html


So this is in the context of generating release tarballs that contain
untracked files as well.  That's done in Git's own Makefile, too:

  dist: git-archive$(X) configure
  ./git-archive --format=tar \
  --prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
  @mkdir -p $(GIT_TARNAME)
  @cp configure $(GIT_TARNAME)
  @echo $(GIT_VERSION) > $(GIT_TARNAME)/version
  @$(MAKE) -C git-gui TARDIR=../$(GIT_TARNAME)/git-gui dist-version
  $(TAR) rf $(GIT_TARNAME).tar \
  $(GIT_TARNAME)/configure \
  $(GIT_TARNAME)/version \
  $(GIT_TARNAME)/git-gui/version
  @$(RM) -r $(GIT_TARNAME)
  gzip -f -9 $(GIT_TARNAME).tar

Having files with different owners and groups is a non-issue when
extracting with --no-same-owner, which is the default for regular users.
I assume this covers most use cases in the wild.

The generated archive leaks the IDs of the user preparing the archive in
the appended entries for untracked files.  I think that's more of a
concern.  Publishing a valid non-root username on your build system may
invite attackers.

Changing the build procedure to set owner and group to root as well as
UID and GID to zero seems like a better idea.  This is complicated by
the inconsistent command line options for GNU tar and bsdtar, as you
mentioned.

So how about making it possible to append untracked files using git
archive?  This could simplify the dist target for Git as well.  It's
orthogonal to adding the ability to explicitly specify owner and group,
but might suffice in most (all?) cases.

Not sure what kind of file name transformation abilities would be
needed and how to package them nicely.  The --transform option of GNU
tar with its sed replace expressions seems quite heavy for me.  With
poppler it's only used to add the --prefix string

Re: [PATCH] git-archive: accept --owner and --group like GNU tar

2018-01-01 Thread suzuki toshiya

Dear René ,

René Scharfe wrote:

Am 29.12.2017 um 15:05 schrieb suzuki toshiya:

The ownership of files created by git-archive is always
root:root. Add --owner and --group options which work
like the GNU tar equivalent to allow overriding these
defaults.


In which situations do you use the new options?

(The sender would need to know the names and/or IDs on the receiving
end.  And the receiver would need to be root to set both IDs, or be a
group member to set the group ID; I guess the latter is more common.)


Thank you for asking the background.

In the case that additional contents are appended to the tar file
generated by git-archive, the part by git-archive and the part
appended by common tar would have different UID/GID, because common
tar preserves the UID/GID of the original files.

Of cource, both of GNU tar and bsdtar have the options to set
UID/GID manually, but their syntax are different.

In the recent source package of poppler (poppler.freedesktop.org),
there are 2 sets of UID/GIDs are found:
https://poppler.freedesktop.org/poppler-0.62.0.tar.xz

I've discussed with the maintainers of poppler, and there was a
suggestion to propose a feature to git.
https://lists.freedesktop.org/archives/poppler/2017-December/012739.html

So now I'm trying.


Would it make sense to support the new options for ZIP files as well?


I was not aware of the availability of UID/GID in pkzip file format...
Oh, checking APPNOTE.TXT ( 
https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT ),

there is a storage! (see 4.5.7-Unix Extra Field). But it seems
that current git-archive emits pkzip without the field.

The background why I propose the options for tar format was described
in above. Similar things are hoped by pkzip users? If it's required,
I will try.


+--owner=[:]::
+   Force  as owner and  as uid for the files in the tar
+   archive.  If  is not supplied,  can be either a user
+   name or numeric UID.  In this case the missing part (UID or
+   name) will be inferred from the current host's user database.
+
+--group=[:]::
+   Force  as group and  as gid for the files in the tar
+   archive.  If  is not supplied,  can be either a group
+   name or numeric GID.  In this case the missing part (GID or
+   name) will be inferred from the current host's group database.
+


IIUC the default behavior is kept, i.e. without these options the
archive entries appear to be owned by root:root.  I think it's a good
idea to mention this here.


Indeed. The default behaviour of git-archive without these options
(root:root) would be different from that of (common) tar (preserving
uid/gid of the files to be archived), it should be clarified.


bsdtar has --uname, --uid, --gname, and -gid, which seem simpler.  At
least you could use OPT_STRING and OPT_INTEGER with them (plus a range
check).  And they should be easier to explain.


Thank you very much for proposing good alternative. Indeed, such well-
separated options make the code simple & stable. However, according
to the manual search systems of FreeBSD ( https://www.freebsd.org/cgi/man.cgi ),
the options for such functionalities are not always same.

FreeBSD 8.2 and earlier: --uname, --gname, --uid, --gid are unavailable.
it seems that using "mtree" was the preferred way to specify such).

FreeBSD 8.3 and later: --uname, --gname, --uid, --gid are available.
the manual says follows:

 --uid id
 Use the provided user id number and ignore the user name from the
 archive.  On create, if --uname is not also specified, the user
 name will be set to match the user id.

 --uname name
 Use the provided user name.  On extract, this overrides the user
 name in the archive; if the provided user name does not exist on
 the system, it will be ignored and the user id (from the archive
 or from the --uid option) will be used instead.  On create, this
 sets the user name that will be stored in the archive; the name
 is not verified against the system user database.

Thus, to emulate (post 2012-) bsdtar perfectly, getpwnam(), getpwuid() etc
would be still needed to implement "--uid" X-(.

Tracking the history of bsdtar, maybe I should track the history of GNU
tar. According to ChangeLog, even --owner --group are rather newer option
since 1.13.18 (released on 2000-10-29). The original syntax was like this.

`--owner=USER'
 Specifies that `tar' should use USER as the owner of members when
 creating archives, instead of the user associated with the source
 file.  USER is first decoded as a user symbolic name, but if this
 interpretation fails, it has to be a decimal numeric user ID.

 There is no value indicating a missing number, and `0' usually
 means `root'.  Some people like to force `0' as the value to offer
 in their distributions for the owner of files, because the `root'
 user

[PATCH] git-archive: accept --owner and --group like GNU tar

2017-12-29 Thread suzuki toshiya
The ownership of files created by git-archive is always
root:root. Add --owner and --group options which work
like the GNU tar equivalent to allow overriding these
defaults.

Signed-off-by: suzuki toshiya <mpsuz...@hiroshima-u.ac.jp>
---
 Documentation/git-archive.txt |  13 +++
 archive-tar.c |   8 +-
 archive.c | 224 ++
 archive.h |   4 +
 t/t5005-archive-uid-gid.sh| 140 ++
 t/t5005/parse-tar-file.py |  60 +++
 tar.h |   2 +
 7 files changed, 447 insertions(+), 4 deletions(-)
 create mode 100755 t/t5005-archive-uid-gid.sh
 create mode 100755 t/t5005/parse-tar-file.py

diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index cfa1e4ebe..0d156f6c1 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -11,6 +11,7 @@ SYNOPSIS
 [verse]
 'git archive' [--format=] [--list] [--prefix=/] []
  [-o  | --output=] [--worktree-attributes]
+ [--owner [username[:uid]] [--group [groupname[:gid]]
  [--remote= [--exec=]] 
  [...]
 
@@ -63,6 +64,18 @@ OPTIONS
This can be any options that the archiver backend understands.
See next section.
 
+--owner=[:]::
+   Force  as owner and  as uid for the files in the tar
+   archive.  If  is not supplied,  can be either a user
+   name or numeric UID.  In this case the missing part (UID or
+   name) will be inferred from the current host's user database.
+
+--group=[:]::
+   Force  as group and  as gid for the files in the tar
+   archive.  If  is not supplied,  can be either a group
+   name or numeric GID.  In this case the missing part (GID or
+   name) will be inferred from the current host's group database.
+
 --remote=::
Instead of making a tar archive from the local repository,
retrieve a tar archive from a remote repository. Note that the
diff --git a/archive-tar.c b/archive-tar.c
index c6ed96ee7..ca6471870 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -204,10 +204,10 @@ static void prepare_header(struct archiver_args *args,
xsnprintf(header->size, sizeof(header->size), "%011lo", S_ISREG(mode) ? 
size : 0);
xsnprintf(header->mtime, sizeof(header->mtime), "%011lo", (unsigned 
long) args->time);
 
-   xsnprintf(header->uid, sizeof(header->uid), "%07o", 0);
-   xsnprintf(header->gid, sizeof(header->gid), "%07o", 0);
-   strlcpy(header->uname, "root", sizeof(header->uname));
-   strlcpy(header->gname, "root", sizeof(header->gname));
+   xsnprintf(header->uid, sizeof(header->uid), "%07lo", args->uid);
+   xsnprintf(header->gid, sizeof(header->gid), "%07lo", args->gid);
+   strlcpy(header->uname, args->uname, sizeof(header->uname));
+   strlcpy(header->gname, args->gname, sizeof(header->gname));
xsnprintf(header->devmajor, sizeof(header->devmajor), "%07o", 0);
xsnprintf(header->devminor, sizeof(header->devminor), "%07o", 0);
 
diff --git a/archive.c b/archive.c
index 0b7b62af0..aa4b16b75 100644
--- a/archive.c
+++ b/archive.c
@@ -8,6 +8,7 @@
 #include "parse-options.h"
 #include "unpack-trees.h"
 #include "dir.h"
+#include "tar.h"
 
 static char const * const archive_usage[] = {
N_("git archive []  [...]"),
@@ -417,6 +418,223 @@ static void parse_treeish_arg(const char **argv,
{ OPTION_SET_INT, (s), NULL, (v), NULL, "", \
  PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_HIDDEN, NULL, (p) }
 
+/*
+ * GNU tar --owner, --group options reject hexdigit, signed int values.
+ * strtol(), atoi() are too permissive to simulate the behaviour.
+ */
+#define STR_IS_DIGIT_OK 0
+#define STR_IS_NOT_DIGIT -1
+#define STR_IS_DIGIT_TOO_LARGE -2
+
+static int try_as_simple_digit(const char *s, unsigned long *dst)
+{
+   unsigned long ul;
+   char *endptr;
+
+   if (strlen(s) != strspn(s, "0123456789"))
+   return STR_IS_NOT_DIGIT;
+
+   errno = 0;
+   ul = strtoul(s, , 10);
+
+   /* catch ERANGE */
+   if (errno) {
+   errno = 0;
+   return STR_IS_DIGIT_TOO_LARGE;
+   }
+
+#if ULONG_MAX > 0xUL
+   /*
+* --owner, --group rejects uid/gid greater than 32-bit
+* limits, even on 64-bit platforms.
+*/
+   if (ul > 0xUL)
+   return STR_IS_DIGIT_TOO_LARGE;
+#endif
+
+   if (dst)
+   *dst = ul;
+   return STR_IS_DIGIT_OK;
+}
+
+static const char *skip_leading_colon(const char *s)
+{
+   const char *col_pos;
+
+   col_pos = strchr(s, ':');
+   if (!col_pos)
+   return s

Re: [PATCH] git-archive: accepts --owner --group aslike GNU tar.

2017-12-29 Thread suzuki toshiya

Dear Junio, Ævar

Thank you very much for your reviews, in spite of my many
overlooking of the requirements written in the documents.

To classify various cases, I modified my patch heavily.
It would be posted soon.

I found that some Python scripts are included in the git
repository, but nothing in t/ directories. A helper written
in Python is not welcomed? If so, I would rewrite the
helper in C (perl's standard library does not have a parse
of tarfile). So, please do not review parse-tar-file.py.

Regards,
mpsuzuki

Junio C Hamano wrote:

suzuki toshiya <mpsuz...@hiroshima-u.ac.jp> writes:


Current tar output by git-archive has always root:root.


Thanks for a patch.  On top of Ævar's comments...


...
* t/t5005-archive-uid-gid.sh: a test script comparing
  uid, gid, uname, gname between the options and
  generated tar file.
---


Before the "---" line, we need to get the patch signed off by the
author (see Documentation/SubmittingPatches).


diff --git a/archive-tar.c b/archive-tar.c
index c6ed96ee7..8546a6229 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -204,10 +204,10 @@ static void prepare_header(struct archiver_args *args,
xsnprintf(header->size, sizeof(header->size), "%011lo", S_ISREG(mode) ? 
size : 0);
xsnprintf(header->mtime, sizeof(header->mtime), "%011lo", (unsigned long) 
args->time);
 
-	xsnprintf(header->uid, sizeof(header->uid), "%07o", 0);

-   xsnprintf(header->gid, sizeof(header->gid), "%07o", 0);
-   strlcpy(header->uname, "root", sizeof(header->uname));
-   strlcpy(header->gname, "root", sizeof(header->gname));
+   xsnprintf(header->uid, sizeof(header->uid), "%07o", args->uid);
+   xsnprintf(header->gid, sizeof(header->gid), "%07o", args->gid);
+   strlcpy(header->uname, args->uname ? args->uname : "root", 
sizeof(header->uname));
+   strlcpy(header->gname, args->gname ? args->gname : "root", 
sizeof(header->gname));


Would it be cleaner to make sure aregs->[gu]name is always set
(i.e. stuff "root" when it is not given)?


xsnprintf(header->devmajor, sizeof(header->devmajor), "%07o", 0);
xsnprintf(header->devminor, sizeof(header->devminor), "%07o", 0);
 
diff --git a/archive.c b/archive.c

index 0b7b62af0..db69041f1 100644
--- a/archive.c
+++ b/archive.c
@@ -8,6 +8,7 @@
 #include "parse-options.h"
 #include "unpack-trees.h"
 #include "dir.h"
+#include "git-compat-util.h"


The coding guideline says that "git-compat-util.h" (or one of the
well-known header that includes it) should be the first file to be
included, and we already include "cache.h" as the first thing, so
I do not think you want this addition here.


@@ -417,6 +418,57 @@ static void parse_treeish_arg(const char **argv,
{ OPTION_SET_INT, (s), NULL, (v), NULL, "", \
  PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_HIDDEN, NULL, (p) }
 
+static void set_args_uname_uid(struct archiver_args *args,

+   const char* tar_owner, int set_gid_too)


The asterisk sticks to the variable name, not the type name, i.e.

const char *tar_owner


+{
+   if (!args || !tar_owner)
+   return;
+
+   const char* col_pos = strchr(tar_owner, ':');
+   struct passwd* pw = NULL;


Decl after statement.


+   if (col_pos) {
+   args->uname = xstrndup(tar_owner, col_pos - tar_owner);
+   args->uid = atoi(col_pos + 1);
+   return;
+   }
+
+   args->uname = xstrndup(tar_owner, strlen(tar_owner));
+   pw = getpwnam(tar_owner);
+   if (!pw)
+   return;


This means that upon error, the caller gets a half-filled args
structure and without any indication.


diff --git a/t/parse-tar-file.py b/t/parse-tar-file.py


Hmph.  Do we still use Python around here?





[PATCH] git-archive: accepts --owner --group aslike GNU tar.

2017-12-28 Thread suzuki toshiya
Current tar output by git-archive has always root:root.
To generate tar output with non-root owner/group,
the options like GNU tar are added.

* archive.h: add members 'uid', 'gid', 'uname', 'gname'
  to struct archiver_args.

* archive.c: add functions to reflect the operands of
  '--owner' and '--group' to archiver_args.

* archive-tar.c: copy 'uid', 'gid', 'uname', 'gname'
  from archiver_args to the entry headers in tar archive.

* t/parse-tar-file.py: a script to dump uid, gid, uname,
  gname fields from a tar archive.

* t/t5005-archive-uid-gid.sh: a test script comparing
  uid, gid, uname, gname between the options and
  generated tar file.
---
 archive-tar.c  |  8 +++---
 archive.c  | 66 ++
 archive.h  |  4 +++
 t/parse-tar-file.py| 56 
 t/t5005-archive-uid-gid.sh | 71 ++
 5 files changed, 201 insertions(+), 4 deletions(-)
 create mode 100755 t/parse-tar-file.py
 create mode 100755 t/t5005-archive-uid-gid.sh

diff --git a/archive-tar.c b/archive-tar.c
index c6ed96ee7..8546a6229 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -204,10 +204,10 @@ static void prepare_header(struct archiver_args *args,
xsnprintf(header->size, sizeof(header->size), "%011lo", S_ISREG(mode) ? 
size : 0);
xsnprintf(header->mtime, sizeof(header->mtime), "%011lo", (unsigned 
long) args->time);
 
-   xsnprintf(header->uid, sizeof(header->uid), "%07o", 0);
-   xsnprintf(header->gid, sizeof(header->gid), "%07o", 0);
-   strlcpy(header->uname, "root", sizeof(header->uname));
-   strlcpy(header->gname, "root", sizeof(header->gname));
+   xsnprintf(header->uid, sizeof(header->uid), "%07o", args->uid);
+   xsnprintf(header->gid, sizeof(header->gid), "%07o", args->gid);
+   strlcpy(header->uname, args->uname ? args->uname : "root", 
sizeof(header->uname));
+   strlcpy(header->gname, args->gname ? args->gname : "root", 
sizeof(header->gname));
xsnprintf(header->devmajor, sizeof(header->devmajor), "%07o", 0);
xsnprintf(header->devminor, sizeof(header->devminor), "%07o", 0);
 
diff --git a/archive.c b/archive.c
index 0b7b62af0..db69041f1 100644
--- a/archive.c
+++ b/archive.c
@@ -8,6 +8,7 @@
 #include "parse-options.h"
 #include "unpack-trees.h"
 #include "dir.h"
+#include "git-compat-util.h"
 
 static char const * const archive_usage[] = {
N_("git archive []  [...]"),
@@ -417,6 +418,57 @@ static void parse_treeish_arg(const char **argv,
{ OPTION_SET_INT, (s), NULL, (v), NULL, "", \
  PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_HIDDEN, NULL, (p) }
 
+static void set_args_uname_uid(struct archiver_args *args,
+   const char* tar_owner, int set_gid_too)
+{
+   if (!args || !tar_owner)
+   return;
+
+   const char* col_pos = strchr(tar_owner, ':');
+   struct passwd* pw = NULL;
+
+   if (col_pos) {
+   args->uname = xstrndup(tar_owner, col_pos - tar_owner);
+   args->uid = atoi(col_pos + 1);
+   return;
+   }
+
+   args->uname = xstrndup(tar_owner, strlen(tar_owner));
+   pw = getpwnam(tar_owner);
+   if (!pw)
+   return;
+
+   args->uid = pw->pw_uid;
+   if (set_gid_too)
+   args->gid = pw->pw_gid;
+
+   return;
+}
+
+static void set_args_gname_gid(struct archiver_args *args,
+   const char* tar_group)
+{
+   if (!args || !tar_group)
+   return;
+
+   const char* col_pos = strchr(tar_group, ':');
+   struct group* gr = NULL;
+
+   if (col_pos) {
+   args->gname = xstrndup(tar_group, col_pos - tar_group);
+   args->gid = atoi(col_pos + 1);
+   return;
+   }
+
+   args->gname = xstrndup(tar_group, strlen(tar_group));
+   gr = getgrnam(tar_group);
+   if (!gr)
+   return;
+
+   args->gid = gr->gr_gid;
+   return;
+}
+
 static int parse_archive_args(int argc, const char **argv,
const struct archiver **ar, struct archiver_args *args,
const char *name_hint, int is_remote)
@@ -431,6 +483,8 @@ static int parse_archive_args(int argc, const char **argv,
int i;
int list = 0;
int worktree_attributes = 0;
+   char *tar_owner = NULL;
+   char *tar_group = NULL;
struct option opts[] = {
OPT_GROUP(""),
OPT_STRING(0, "format", , N_("fmt"), N_("archive 
format")),
@@ -459,6 +513,8 @@ static int parse_archive_args(int argc, const char **argv,
N_("retrieve the archive from remote repository 
")),
OPT_STRING(0, "exec", , N_("command"),
N_("path to the remote git-upload-archive command")),
+   OPT_STRING(0, "owner", _owner, N_("owner"), 
N_(" in tar")),
+