Linux tar 协议格式解析

Tar仅仅是归档文件, 用于多个文件合并. 并不进行压缩;

  • 介绍Tar结构体
  • 以及如何归档

Tar归档文件组成

归档单个文件

tar -cf off.tar offpage.c

Tar = 512Byte + file.st_size + padding;

1566980179215

归档多个文件

Tar = 512Byte + file.st_size + padding * N [0-N];

归档文件夹

tar -cf dir.tar dir/

归档文件夹: 512Byte(文件夹信息) + 文件归档 * N;

1566980062837

Tar头部结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct tar_header
{
   char name[100];
   char mode[8];
   char uid[8];
   char gid[8];
   char size[12];
   char mtime[12]; //148byte
   char chksum[8];
   char typeflag; //156byte
   char linkname[100];
   char magic[6];
   char version[2];
   char uname[32];
   char gname[32];
   char devmajor[8];
   char devminor[8];
   char prefix[155];
   char padding[12];
};

man tar.h可以查看更多信息;

tarCreateHeader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
int
tarCheckSum(char *header)
{
int i,
sum;

sum = 8 * ' ';
for (i = 0 ; i < TAR_HEADER_LENGTH ; i++ )
if (i < 148 || i >= 156)
sum += 0xFF & header[i];
return sum;
}


enum tarError
tarCreateHeader(char *header, const char *filename, const char *linktarget, struct stat *filebuf)
{
struct passwd *userinfo = NULL;
struct group *groupinfo = NULL;

if (strlen(filename) > 99)
return TAR_NAME_TOO_LONG;

if (linktarget && strlen(linktarget) > 99)
return TAR_SYMLINK_TOO_LONG;

memset(header, 0, TAR_HEADER_LENGTH);

strncpy(&header[0], filename, 100); //filename[100]

if (linktarget != NULL || S_ISDIR(filebuf->st_mode))
{
int flen = strlen(filename);
flen = flen > 99 ? 99 : flen;
header[flen] = '/';
header[flen + 1] = '\0';
}

write_tar_number(&header[100], 8, ( filebuf->st_mode & 07777));

write_tar_number(&header[108], 8, filebuf->st_uid);

write_tar_number(&header[116], 8, filebuf->st_gid);

if (linktarget != NULL || S_ISDIR(filebuf->st_mode))
write_tar_number(&header[124], 12, 0);
else
write_tar_number(&header[124], 12, filebuf->st_size); //size = file size;

write_tar_number(&header[136], 12, filebuf->st_mtime); //modify time;

// 156byte is typeflag;
if (linktarget != NULL)
{
header[156] = '2';
strncpy(&header[157], linktarget, 100);
}
else if (S_ISDIR(filebuf->st_mode))
header[156] = '5';
//else if (S_ISBLK(filebuf->st_mode))
// header[156] = '4';
//else if (S_ISCHR(filebuf->st_mode))
// header[156] = '3';
//else if(S_ISFIFO(filebuf->st_mode))
// header[156] = '6';
else
header[156] = '0';

strcpy(&header[257], "ustar"); //magic

memcpy(&header[263], "00", 2); //version;

userinfo = getpwuid(filebuf->st_uid);
groupinfo = getgrgid(filebuf->st_gid);

strncpy(&header[265], userinfo->pw_name, 32); //u name;
strncpy(&header[297], groupinfo->gr_name, 32); //g name;

write_tar_number(&header[329], 8, 0); //major;

write_tar_number(&header[337], 8, 0); //minor;

write_tar_number(&header[148], 8, tarCheckSum(header)); //checksum;;

return TAR_OK;

填充文件数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
void writeTarData(FILE *tarfile, char *buf, int r, char *current_file)
{
if (fwrite(buf, r, 1, tarfile) != 1)
{
fprintf(stderr, ("%s: could not write to file \"%s\": %s\n"),
"cs51-tar", current_file, strerror(errno));
exit(1);
}
}

#define WRITE_TAR_DATA(buf, sz) writeTarData(tarfile, buf, sz, filename)


main::
for (int i = 0; i < file num; i++)
{
fp = fopen(file[i], "r");//

printf("append %s\n", file[i]);

memset(zerobuf, 0, sizeof(zerobuf));

stat(file[i], &filebuf);

header = (char *)malloc(sizeof(char) * TAR_HEADER_LENGTH);
memset(header, 0, TAR_HEADER_LENGTH);

//context file ;
context = (char *)malloc(sizeof(char) * filebuf.st_size);
fread(context, 1, filebuf.st_size, fp);

tarCreateHeader(header, file[i], NULL, &filebuf);

padding = ((filebuf.st_size + 511) & ~511) - filebuf.st_size;

WRITE_TAR_DATA(header, TAR_HEADER_LENGTH);
WRITE_TAR_DATA(context /*file data*/, filebuf.st_size);

if (padding)
WRITE_TAR_DATA(zerobuf, padding);
}
WRITE_TAR_DATA(zerobuf, sizeof(zerobuf));
欣赏此文? 求鼓励,求支持!