Browse Source

Merge branch 'rs/tar-tree' into next

* rs/tar-tree:
  tar-tree: Use the prefix field of a tar header
  tar-tree: Remove obsolete code
  tar-tree: Use write_entry() to write the archive contents
  tar-tree: Introduce write_entry()
  tar-tree: Use SHA1 of root tree for the basedir
  git-apply: safety fixes
  Removed bogus "<snap>" identifier.
  Clarify and expand some hook documentation.
  commit-tree: check return value from write_sha1_file()
  send-email: Identify author at the top when sending e-mail
  Format tweaks for asciidoc.
maint
Junio C Hamano 19 years ago
parent
commit
48d6e97afe
  1. 14
      Documentation/git-grep.txt
  2. 6
      Documentation/git-whatchanged.txt
  3. 6
      Documentation/git.txt
  4. 51
      Documentation/hooks.txt
  5. 2
      Documentation/repository-layout.txt
  6. 4
      apply.c
  7. 9
      commit-tree.c
  8. 11
      git-send-email.perl
  9. 3
      t/t5000-tar-tree.sh
  10. 385
      tar-tree.c
  11. 25
      tar.h

14
Documentation/git-grep.txt

@ -24,13 +24,13 @@ OPTIONS @@ -24,13 +24,13 @@ OPTIONS

<option>...::
Either an option to pass to `grep` or `git-ls-files`.

The following are the specific `git-ls-files` options
that may be given: `-o`, `--cached`, `--deleted`, `--others`,
`--killed`, `--ignored`, `--modified`, `--exclude=*`,
`--exclude-from=*`, and `--exclude-per-directory=*`.

All other options will be passed to `grep`.
+
The following are the specific `git-ls-files` options
that may be given: `-o`, `--cached`, `--deleted`, `--others`,
`--killed`, `--ignored`, `--modified`, `--exclude=\*`,
`--exclude-from=\*`, and `--exclude-per-directory=\*`.
+
All other options will be passed to `grep`.

<pattern>::
The pattern to look for. The first non option is taken

6
Documentation/git-whatchanged.txt

@ -47,9 +47,9 @@ OPTIONS @@ -47,9 +47,9 @@ OPTIONS
By default, differences for merge commits are not shown.
With this flag, show differences to that commit from all
of its parents.

However, it is not very useful in general, although it
*is* useful on a file-by-file basis.
+
However, it is not very useful in general, although it
*is* useful on a file-by-file basis.

Examples
--------

6
Documentation/git.txt

@ -521,16 +521,14 @@ HEAD:: @@ -521,16 +521,14 @@ HEAD::
a valid head 'name'
(i.e. the contents of `$GIT_DIR/refs/heads/<head>`).

<snap>::
a valid snapshot 'name'
(i.e. the contents of `$GIT_DIR/refs/snap/<snap>`).


File/Directory Structure
------------------------

Please see link:repository-layout.html[repository layout] document.

Read link:hooks.html[hooks] for more details about each hook.

Higher level SCMs may provide and manage additional information in the
`$GIT_DIR`.


51
Documentation/hooks.txt

@ -97,16 +97,31 @@ send out a commit notification e-mail. @@ -97,16 +97,31 @@ send out a commit notification e-mail.
update
------

This hook is invoked by `git-receive-pack`, which is invoked
when a `git push` is done against the repository. It takes
three parameters, name of the ref being updated, old object name
stored in the ref, and the new objectname to be stored in the
ref. Exiting with non-zero status from this hook prevents
`git-receive-pack` from updating the ref.

This can be used to prevent 'forced' update on certain refs by
This hook is invoked by `git-receive-pack` on the remote repository,
which is happens when a `git push` is done on a local repository.
Just before updating the ref on the remote repository, the update hook
is invoked. It's exit status determins the success or failure of
the ref update.

The hook executes once for each ref to be updated, and takes
three parameters:
- the name of the ref being updated,
- the old object name stored in the ref,
- and the new objectname to be stored in the ref.

A zero exit from the update hook allows the ref to be updated.
Exiting with a non-zero status prevents `git-receive-pack`
from updating the ref.

This hook can be used to prevent 'forced' update on certain refs by
making sure that the object name is a commit object that is a
descendant of the commit object named by the old object name.
That is, to enforce a "fast forward only" policy.

It could also be used to log the old..new status. However, it
does not know the entire set of branches, so it would end up
firing one e-mail per ref when used naively, though.

Another use suggested on the mailing list is to use this hook to
implement access control which is finer grained than the one
based on filesystem group.
@ -115,20 +130,30 @@ The standard output of this hook is sent to /dev/null; if you @@ -115,20 +130,30 @@ The standard output of this hook is sent to /dev/null; if you
want to report something to the git-send-pack on the other end,
you can redirect your output to your stderr.


post-update
-----------

This hook is invoked by `git-receive-pack`, which is invoked
when a `git push` is done against the repository. It takes
variable number of parameters; each of which is the name of ref
that was actually updated.
This hook is invoked by `git-receive-pack` on the remote repository,
which is happens when a `git push` is done on a local repository.
It executes on the remote repository once after all the refs have
been updated.

It takes a variable number of parameters, each of which is the
name of ref that was actually updated.

This hook is meant primarily for notification, and cannot affect
the outcome of `git-receive-pack`.

The post-update hook can tell what are the heads that were pushed,
but it does not know what their original and updated values are,
so it is a poor place to do log old..new.

The default post-update hook, when enabled, runs
`git-update-server-info` to keep the information used by dumb
transport up-to-date.
transports (eg, http) up-to-date. If you are publishing
a git repository that is accessible via http, you should
probably enable this hook.

The standard output of this hook is sent to /dev/null; if you
want to report something to the git-send-pack on the other end,

2
Documentation/repository-layout.txt

@ -89,6 +89,8 @@ hooks:: @@ -89,6 +89,8 @@ hooks::
commands. A handful of sample hooks are installed when
`git init-db` is run, but all of them are disabled by
default. To enable, they need to be made executable.
Read link:hooks.html[hooks] for more details about
each hook.

index::
The current index file for the repository. It is

4
apply.c

@ -693,7 +693,7 @@ static int parse_range(const char *line, int len, int offset, const char *expect @@ -693,7 +693,7 @@ static int parse_range(const char *line, int len, int offset, const char *expect
line += digits;
len -= digits;

*p2 = *p1;
*p2 = 1;
if (*line == ',') {
digits = parse_num(line+1, p2);
if (!digits)
@ -901,6 +901,8 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s @@ -901,6 +901,8 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
break;
}
}
if (oldlines || newlines)
return -1;
/* If a fragment ends with an incomplete line, we failed to include
* it in the above loop because we hit oldlines == newlines == 0
* before seeing it.

9
commit-tree.c

@ -125,7 +125,10 @@ int main(int argc, char **argv) @@ -125,7 +125,10 @@ int main(int argc, char **argv)
while (fgets(comment, sizeof(comment), stdin) != NULL)
add_buffer(&buffer, &size, "%s", comment);

write_sha1_file(buffer, size, "commit", commit_sha1);
printf("%s\n", sha1_to_hex(commit_sha1));
return 0;
if (!write_sha1_file(buffer, size, "commit", commit_sha1)) {
printf("%s\n", sha1_to_hex(commit_sha1));
return 0;
}
else
return 1;
}

11
git-send-email.perl

@ -307,6 +307,7 @@ $subject = $initial_subject; @@ -307,6 +307,7 @@ $subject = $initial_subject;
foreach my $t (@files) {
open(F,"<",$t) or die "can't open file $t";

my $author_not_sender = undef;
@cc = @initial_cc;
my $found_mbox = 0;
my $header_done = 0;
@ -321,7 +322,12 @@ foreach my $t (@files) { @@ -321,7 +322,12 @@ foreach my $t (@files) {
$subject = $1;

} elsif (/^(Cc|From):\s+(.*)$/) {
next if ($2 eq $from && $suppress_from);
if ($2 eq $from) {
next if ($suppress_from);
}
else {
$author_not_sender = $2;
}
printf("(mbox) Adding cc: %s from line '%s'\n",
$2, $_) unless $quiet;
push @cc, $2;
@ -360,6 +366,9 @@ foreach my $t (@files) { @@ -360,6 +366,9 @@ foreach my $t (@files) {
}
}
close F;
if (defined $author_not_sender) {
$message = "From: $author_not_sender\n\n$message";
}

$cc = join(", ", unique_email_list(@cc));


3
t/t5000-tar-tree.sh

@ -34,6 +34,9 @@ test_expect_success \ @@ -34,6 +34,9 @@ test_expect_success \
mkdir a/bin &&
cp /bin/sh a/bin &&
ln -s a a/l1 &&
(p=long_path_to_a_file && cd a &&
for depth in 1 2 3 4 5; do mkdir $p && cd $p; done &&
echo text >file_with_long_path) &&
(cd a && find .) | sort >a.lst'

test_expect_success \

385
tar-tree.c

@ -1,37 +1,23 @@ @@ -1,37 +1,23 @@
/*
* Copyright (c) 2005 Rene Scharfe
* Copyright (c) 2005, 2006 Rene Scharfe
*/
#include <time.h>
#include "cache.h"
#include "diff.h"
#include "commit.h"
#include "strbuf.h"
#include "tar.h"

#define RECORDSIZE (512)
#define BLOCKSIZE (RECORDSIZE * 20)

#define TYPEFLAG_AUTO '\0'
#define TYPEFLAG_REG '0'
#define TYPEFLAG_LNK '2'
#define TYPEFLAG_DIR '5'
#define TYPEFLAG_GLOBAL_HEADER 'g'
#define TYPEFLAG_EXT_HEADER 'x'

#define EXT_HEADER_PATH 1
#define EXT_HEADER_LINKPATH 2

static const char tar_tree_usage[] = "git-tar-tree <key> [basedir]";

static char block[BLOCKSIZE];
static unsigned long offset;

static const char *basedir;
static time_t archive_time;

struct path_prefix {
struct path_prefix *prev;
const char *name;
};

/* tries hard to write, either succeeds or dies in the attempt */
static void reliable_write(void *buf, unsigned long size)
{
@ -119,230 +105,170 @@ static void write_blocked(void *buf, unsigned long size) @@ -119,230 +105,170 @@ static void write_blocked(void *buf, unsigned long size)
write_if_needed();
}

static void append_string(char **p, const char *s)
{
unsigned int len = strlen(s);
memcpy(*p, s, len);
*p += len;
}

static void append_char(char **p, char c)
{
**p = c;
*p += 1;
}

static void append_path_prefix(char **buffer, struct path_prefix *prefix)
static void strbuf_append_string(struct strbuf *sb, const char *s)
{
if (!prefix)
return;
append_path_prefix(buffer, prefix->prev);
append_string(buffer, prefix->name);
append_char(buffer, '/');
}

static unsigned int path_prefix_len(struct path_prefix *prefix)
{
if (!prefix)
return 0;
return path_prefix_len(prefix->prev) + strlen(prefix->name) + 1;
}

static void append_path(char **p, int is_dir, const char *basepath,
struct path_prefix *prefix, const char *path)
{
if (basepath) {
append_string(p, basepath);
append_char(p, '/');
int slen = strlen(s);
int total = sb->len + slen;
if (total > sb->alloc) {
sb->buf = xrealloc(sb->buf, total);
sb->alloc = total;
}
append_path_prefix(p, prefix);
append_string(p, path);
if (is_dir)
append_char(p, '/');
memcpy(sb->buf + sb->len, s, slen);
sb->len = total;
}

static unsigned int path_len(int is_dir, const char *basepath,
struct path_prefix *prefix, const char *path)
{
unsigned int len = 0;
if (basepath)
len += strlen(basepath) + 1;
len += path_prefix_len(prefix) + strlen(path);
if (is_dir)
len++;
return len;
}

static void append_extended_header_prefix(char **p, unsigned int size,
const char *keyword)
/*
* pax extended header records have the format "%u %s=%s\n". %u contains
* the size of the whole string (including the %u), the first %s is the
* keyword, the second one is the value. This function constructs such a
* string and appends it to a struct strbuf.
*/
static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,
const char *value, unsigned int valuelen)
{
int len = sprintf(*p, "%u %s=", size, keyword);
*p += len;
}
char *p;
int len, total, tmp;

static unsigned int extended_header_len(const char *keyword,
unsigned int valuelen)
{
/* "%u %s=%s\n" */
unsigned int len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;
if (len > 9)
len++;
if (len > 99)
len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;
for (tmp = len; tmp > 9; tmp /= 10)
len++;
return len;
}

static void append_extended_header(char **p, const char *keyword,
const char *value, unsigned int len)
{
unsigned int size = extended_header_len(keyword, len);
append_extended_header_prefix(p, size, keyword);
memcpy(*p, value, len);
*p += len;
append_char(p, '\n');
}
total = sb->len + len;
if (total > sb->alloc) {
sb->buf = xrealloc(sb->buf, total);
sb->alloc = total;
}

static void write_header(const unsigned char *, char, const char *, struct path_prefix *,
const char *, unsigned int, void *, unsigned long);
p = sb->buf;
p += sprintf(p, "%u %s=", len, keyword);
memcpy(p, value, valuelen);
p += valuelen;
*p = '\n';
sb->len = total;
}

/* stores a pax extended header directly in the block buffer */
static void write_extended_header(const char *headerfilename, int is_dir,
unsigned int flags, const char *basepath,
struct path_prefix *prefix,
const char *path, unsigned int namelen,
void *content, unsigned int contentsize)
static unsigned int ustar_header_chksum(const struct ustar_header *header)
{
char *buffer, *p;
unsigned int pathlen, size, linkpathlen = 0;

size = pathlen = extended_header_len("path", namelen);
if (flags & EXT_HEADER_LINKPATH) {
linkpathlen = extended_header_len("linkpath", contentsize);
size += linkpathlen;
}
write_header(NULL, TYPEFLAG_EXT_HEADER, NULL, NULL, headerfilename,
0100600, NULL, size);

buffer = p = malloc(size);
if (!buffer)
die("git-tar-tree: %s", strerror(errno));
append_extended_header_prefix(&p, pathlen, "path");
append_path(&p, is_dir, basepath, prefix, path);
append_char(&p, '\n');
if (flags & EXT_HEADER_LINKPATH)
append_extended_header(&p, "linkpath", content, contentsize);
write_blocked(buffer, size);
free(buffer);
char *p = (char *)header;
unsigned int chksum = 0;
while (p < header->chksum)
chksum += *p++;
chksum += sizeof(header->chksum) * ' ';
p += sizeof(header->chksum);
while (p < (char *)header + sizeof(struct ustar_header))
chksum += *p++;
return chksum;
}

static void write_global_extended_header(const unsigned char *sha1)
static int get_path_prefix(const struct strbuf *path, int maxlen)
{
char *p;
unsigned int size;

size = extended_header_len("comment", 40);
write_header(NULL, TYPEFLAG_GLOBAL_HEADER, NULL, NULL,
"pax_global_header", 0100600, NULL, size);

p = get_record();
append_extended_header(&p, "comment", sha1_to_hex(sha1), 40);
write_if_needed();
int i = path->len;
if (i > maxlen)
i = maxlen;
while (i > 0 && path->buf[i] != '/')
i--;
return i;
}

/* stores a ustar header directly in the block buffer */
static void write_header(const unsigned char *sha1, char typeflag, const char *basepath,
struct path_prefix *prefix, const char *path,
unsigned int mode, void *buffer, unsigned long size)
static void write_entry(const unsigned char *sha1, struct strbuf *path,
unsigned int mode, void *buffer, unsigned long size)
{
unsigned int namelen;
char *header = NULL;
unsigned int checksum = 0;
int i;
unsigned int ext_header = 0;

if (typeflag == TYPEFLAG_AUTO) {
if (S_ISDIR(mode))
typeflag = TYPEFLAG_DIR;
else if (S_ISLNK(mode))
typeflag = TYPEFLAG_LNK;
else
typeflag = TYPEFLAG_REG;
}

namelen = path_len(S_ISDIR(mode), basepath, prefix, path);
if (namelen > 100)
ext_header |= EXT_HEADER_PATH;
if (typeflag == TYPEFLAG_LNK && size > 100)
ext_header |= EXT_HEADER_LINKPATH;

/* the extended header must be written before the normal one */
if (ext_header) {
char headerfilename[51];
sprintf(headerfilename, "%s.paxheader", sha1_to_hex(sha1));
write_extended_header(headerfilename, S_ISDIR(mode),
ext_header, basepath, prefix, path,
namelen, buffer, size);
}

header = get_record();

if (ext_header) {
sprintf(header, "%s.data", sha1_to_hex(sha1));
struct ustar_header header;
struct strbuf ext_header;

memset(&header, 0, sizeof(header));
ext_header.buf = NULL;
ext_header.len = ext_header.alloc = 0;

if (!sha1) {
*header.typeflag = TYPEFLAG_GLOBAL_HEADER;
mode = 0100666;
strcpy(header.name, "pax_global_header");
} else if (!path) {
*header.typeflag = TYPEFLAG_EXT_HEADER;
mode = 0100666;
sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
} else {
char *p = header;
append_path(&p, S_ISDIR(mode), basepath, prefix, path);
if (S_ISDIR(mode)) {
*header.typeflag = TYPEFLAG_DIR;
mode |= 0777;
} else if (S_ISLNK(mode)) {
*header.typeflag = TYPEFLAG_LNK;
mode |= 0777;
} else if (S_ISREG(mode)) {
*header.typeflag = TYPEFLAG_REG;
mode |= (mode & 0100) ? 0777 : 0666;
} else {
error("unsupported file mode: 0%o (SHA1: %s)",
mode, sha1_to_hex(sha1));
return;
}
if (path->len > sizeof(header.name)) {
int plen = get_path_prefix(path, sizeof(header.prefix));
int rest = path->len - plen - 1;
if (plen > 0 && rest <= sizeof(header.name)) {
memcpy(header.prefix, path->buf, plen);
memcpy(header.name, path->buf + plen + 1, rest);
} else {
sprintf(header.name, "%s.data",
sha1_to_hex(sha1));
strbuf_append_ext_header(&ext_header, "path",
path->buf, path->len);
}
} else
memcpy(header.name, path->buf, path->len);
}

if (typeflag == TYPEFLAG_LNK) {
if (ext_header & EXT_HEADER_LINKPATH) {
sprintf(&header[157], "see %s.paxheader",
if (S_ISLNK(mode) && buffer) {
if (size > sizeof(header.linkname)) {
sprintf(header.linkname, "see %s.paxheader",
sha1_to_hex(sha1));
} else {
if (buffer)
strncpy(&header[157], buffer, size);
}
strbuf_append_ext_header(&ext_header, "linkpath",
buffer, size);
} else
memcpy(header.linkname, buffer, size);
}

if (S_ISDIR(mode))
mode |= 0777;
else if (S_ISREG(mode))
mode |= (mode & 0100) ? 0777 : 0666;
else if (S_ISLNK(mode))
mode |= 0777;
sprintf(&header[100], "%07o", mode & 07777);
sprintf(header.mode, "%07o", mode & 07777);
sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0);
sprintf(header.mtime, "%011lo", archive_time);

/* XXX: should we provide more meaningful info here? */
sprintf(&header[108], "%07o", 0); /* uid */
sprintf(&header[116], "%07o", 0); /* gid */
strncpy(&header[265], "git", 31); /* uname */
strncpy(&header[297], "git", 31); /* gname */

if (S_ISDIR(mode) || S_ISLNK(mode))
size = 0;
sprintf(&header[124], "%011lo", size);
sprintf(&header[136], "%011lo", archive_time);
sprintf(header.uid, "%07o", 0);
sprintf(header.gid, "%07o", 0);
strncpy(header.uname, "git", 31);
strncpy(header.gname, "git", 31);
sprintf(header.devmajor, "%07o", 0);
sprintf(header.devminor, "%07o", 0);

header[156] = typeflag;
memcpy(header.magic, "ustar", 6);
memcpy(header.version, "00", 2);

memcpy(&header[257], "ustar", 6);
memcpy(&header[263], "00", 2);
sprintf(header.chksum, "%07o", ustar_header_chksum(&header));

sprintf(&header[329], "%07o", 0); /* devmajor */
sprintf(&header[337], "%07o", 0); /* devminor */

memset(&header[148], ' ', 8);
for (i = 0; i < RECORDSIZE; i++)
checksum += header[i];
sprintf(&header[148], "%07o", checksum & 0x1fffff);
if (ext_header.len > 0) {
write_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);
free(ext_header.buf);
}
write_blocked(&header, sizeof(header));
if (S_ISREG(mode) && buffer && size > 0)
write_blocked(buffer, size);
}

write_if_needed();
static void write_global_extended_header(const unsigned char *sha1)
{
struct strbuf ext_header;
ext_header.buf = NULL;
ext_header.len = ext_header.alloc = 0;
strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
write_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);
free(ext_header.buf);
}

static void traverse_tree(struct tree_desc *tree,
struct path_prefix *prefix)
static void traverse_tree(struct tree_desc *tree, struct strbuf *path)
{
struct path_prefix this_prefix;
this_prefix.prev = prefix;
int pathlen = path->len;

while (tree->size) {
const char *name;
@ -358,16 +284,19 @@ static void traverse_tree(struct tree_desc *tree, @@ -358,16 +284,19 @@ static void traverse_tree(struct tree_desc *tree,
eltbuf = read_sha1_file(sha1, elttype, &eltsize);
if (!eltbuf)
die("cannot read %s", sha1_to_hex(sha1));
write_header(sha1, TYPEFLAG_AUTO, basedir,
prefix, name, mode, eltbuf, eltsize);

path->len = pathlen;
strbuf_append_string(path, name);
if (S_ISDIR(mode))
strbuf_append_string(path, "/");

write_entry(sha1, path, mode, eltbuf, eltsize);

if (S_ISDIR(mode)) {
struct tree_desc subtree;
subtree.buf = eltbuf;
subtree.size = eltsize;
this_prefix.name = name;
traverse_tree(&subtree, &this_prefix);
} else if (!S_ISLNK(mode)) {
write_blocked(eltbuf, eltsize);
traverse_tree(&subtree, path);
}
free(eltbuf);
}
@ -375,16 +304,22 @@ static void traverse_tree(struct tree_desc *tree, @@ -375,16 +304,22 @@ static void traverse_tree(struct tree_desc *tree,

int main(int argc, char **argv)
{
unsigned char sha1[20];
unsigned char sha1[20], tree_sha1[20];
struct commit *commit;
struct tree_desc tree;
struct strbuf current_path;

current_path.buf = xmalloc(PATH_MAX);
current_path.alloc = PATH_MAX;
current_path.len = current_path.eof = 0;

setup_git_directory();
git_config(git_default_config);

switch (argc) {
case 3:
basedir = argv[2];
strbuf_append_string(&current_path, argv[2]);
strbuf_append_string(&current_path, "/");
/* FALLTHROUGH */
case 2:
if (get_sha1(argv[1], sha1) < 0)
@ -398,17 +333,19 @@ int main(int argc, char **argv) @@ -398,17 +333,19 @@ int main(int argc, char **argv)
if (commit) {
write_global_extended_header(commit->object.sha1);
archive_time = commit->date;
}
tree.buf = read_object_with_reference(sha1, "tree", &tree.size, NULL);
} else
archive_time = time(NULL);

tree.buf = read_object_with_reference(sha1, "tree", &tree.size,
tree_sha1);
if (!tree.buf)
die("not a reference to a tag, commit or tree object: %s",
sha1_to_hex(sha1));
if (!archive_time)
archive_time = time(NULL);
if (basedir)
write_header((unsigned char *)"0", TYPEFLAG_DIR, NULL, NULL,
basedir, 040777, NULL, 0);
traverse_tree(&tree, NULL);

if (current_path.len > 0)
write_entry(tree_sha1, &current_path, 040777, NULL, 0);
traverse_tree(&tree, &current_path);
write_trailer();
free(current_path.buf);
return 0;
}

25
tar.h

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
#define TYPEFLAG_AUTO '\0'
#define TYPEFLAG_REG '0'
#define TYPEFLAG_LNK '2'
#define TYPEFLAG_DIR '5'
#define TYPEFLAG_GLOBAL_HEADER 'g'
#define TYPEFLAG_EXT_HEADER 'x'

struct ustar_header {
char name[100]; /* 0 */
char mode[8]; /* 100 */
char uid[8]; /* 108 */
char gid[8]; /* 116 */
char size[12]; /* 124 */
char mtime[12]; /* 136 */
char chksum[8]; /* 148 */
char typeflag[1]; /* 156 */
char linkname[100]; /* 157 */
char magic[6]; /* 257 */
char version[2]; /* 263 */
char uname[32]; /* 265 */
char gname[32]; /* 297 */
char devmajor[8]; /* 329 */
char devminor[8]; /* 337 */
char prefix[155]; /* 345 */
};
Loading…
Cancel
Save