Skip to content

Commit 6050b6a

Browse files
committed
Add and use symbolic constants for tar header offsets and file types.
Because symbolic constants in a header file are better than magic constants embedded in the code. Patch by me, reviewed by Tom Lane, Dagfinn Ilmari Mannsåker, and Tristan Partin. Discussion: http://postgr.es/m/CA+TgmoZNbLwhmCrNtkJAvi8FLkwFdMeVU3myV2HQQpA5bvbRZg@mail.gmail.com
1 parent deae165 commit 6050b6a

File tree

5 files changed

+80
-42
lines changed

5 files changed

+80
-42
lines changed

src/bin/pg_basebackup/bbstreamer_tar.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -286,22 +286,20 @@ bbstreamer_tar_header(bbstreamer_tar_parser *mystreamer)
286286

287287
/*
288288
* Parse key fields out of the header.
289-
*
290-
* FIXME: It's terrible that we use hard-coded values here instead of some
291-
* more principled approach. It's been like this for a long time, but we
292-
* ought to do better.
293289
*/
294-
strlcpy(member->pathname, &buffer[0], MAXPGPATH);
290+
strlcpy(member->pathname, &buffer[TAR_OFFSET_NAME], MAXPGPATH);
295291
if (member->pathname[0] == '\0')
296292
pg_fatal("tar member has empty name");
297-
member->size = read_tar_number(&buffer[124], 12);
298-
member->mode = read_tar_number(&buffer[100], 8);
299-
member->uid = read_tar_number(&buffer[108], 8);
300-
member->gid = read_tar_number(&buffer[116], 8);
301-
member->is_directory = (buffer[156] == '5');
302-
member->is_link = (buffer[156] == '2');
293+
member->size = read_tar_number(&buffer[TAR_OFFSET_SIZE], 12);
294+
member->mode = read_tar_number(&buffer[TAR_OFFSET_MODE], 8);
295+
member->uid = read_tar_number(&buffer[TAR_OFFSET_UID], 8);
296+
member->gid = read_tar_number(&buffer[TAR_OFFSET_GID], 8);
297+
member->is_directory =
298+
(buffer[TAR_OFFSET_TYPEFLAG] == TAR_FILETYPE_DIRECTORY);
299+
member->is_link =
300+
(buffer[TAR_OFFSET_TYPEFLAG] == TAR_FILETYPE_SYMLINK);
303301
if (member->is_link)
304-
strlcpy(member->linktarget, &buffer[157], 100);
302+
strlcpy(member->linktarget, &buffer[TAR_OFFSET_LINKNAME], 100);
305303

306304
/* Compute number of padding bytes. */
307305
mystreamer->pad_bytes_expected = tarPaddingBytesRequired(member->size);

src/bin/pg_basebackup/walmethods.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,17 +1131,18 @@ tar_close(Walfile *f, WalCloseMethod method)
11311131
* possibly also renaming the file. We overwrite the entire current header
11321132
* when done, including the checksum.
11331133
*/
1134-
print_tar_number(&(tf->header[124]), 12, filesize);
1134+
print_tar_number(&(tf->header[TAR_OFFSET_SIZE]), 12, filesize);
11351135

11361136
if (method == CLOSE_NORMAL)
11371137

11381138
/*
11391139
* We overwrite it with what it was before if we have no tempname,
11401140
* since we're going to write the buffer anyway.
11411141
*/
1142-
strlcpy(&(tf->header[0]), tf->base.pathname, 100);
1142+
strlcpy(&(tf->header[TAR_OFFSET_NAME]), tf->base.pathname, 100);
11431143

1144-
print_tar_number(&(tf->header[148]), 8, tarChecksum(((TarMethodFile *) f)->header));
1144+
print_tar_number(&(tf->header[TAR_OFFSET_CHECKSUM]), 8,
1145+
tarChecksum(((TarMethodFile *) f)->header));
11451146
if (lseek(tar_data->fd, tf->ofs_start, SEEK_SET) != ((TarMethodFile *) f)->ofs_start)
11461147
{
11471148
f->wwmethod->lasterrno = errno;

src/bin/pg_dump/pg_backup_tar.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -975,20 +975,20 @@ isValidTarHeader(char *header)
975975
int sum;
976976
int chk = tarChecksum(header);
977977

978-
sum = read_tar_number(&header[148], 8);
978+
sum = read_tar_number(&header[TAR_OFFSET_CHECKSUM], 8);
979979

980980
if (sum != chk)
981981
return false;
982982

983983
/* POSIX tar format */
984-
if (memcmp(&header[257], "ustar\0", 6) == 0 &&
985-
memcmp(&header[263], "00", 2) == 0)
984+
if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar\0", 6) == 0 &&
985+
memcmp(&header[TAR_OFFSET_VERSION], "00", 2) == 0)
986986
return true;
987987
/* GNU tar format */
988-
if (memcmp(&header[257], "ustar \0", 8) == 0)
988+
if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar \0", 8) == 0)
989989
return true;
990990
/* not-quite-POSIX format written by pre-9.3 pg_dump */
991-
if (memcmp(&header[257], "ustar00\0", 8) == 0)
991+
if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar00\0", 8) == 0)
992992
return true;
993993

994994
return false;
@@ -1151,7 +1151,7 @@ _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
11511151

11521152
/* Calc checksum */
11531153
chk = tarChecksum(h);
1154-
sum = read_tar_number(&h[148], 8);
1154+
sum = read_tar_number(&h[TAR_OFFSET_CHECKSUM], 8);
11551155

11561156
/*
11571157
* If the checksum failed, see if it is a null block. If so, silently
@@ -1175,9 +1175,9 @@ _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
11751175
}
11761176

11771177
/* Name field is 100 bytes, might not be null-terminated */
1178-
strlcpy(tag, &h[0], 100 + 1);
1178+
strlcpy(tag, &h[TAR_OFFSET_NAME], 100 + 1);
11791179

1180-
len = read_tar_number(&h[124], 12);
1180+
len = read_tar_number(&h[TAR_OFFSET_SIZE], 12);
11811181

11821182
pg_log_debug("TOC Entry %s at %llu (length %llu, checksum %d)",
11831183
tag, (unsigned long long) hPos, (unsigned long long) len, sum);

src/include/pgtar.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,45 @@ enum tarError
2323
TAR_SYMLINK_TOO_LONG
2424
};
2525

26+
/*
27+
* Offsets of fields within a 512-byte tar header.
28+
*
29+
* "tar number" values should be generated using print_tar_number() and can be
30+
* read using read_tar_number(). Fields that contain strings are generally
31+
* both filled and read using strlcpy().
32+
*
33+
* The value for the checksum field can be computed using tarChecksum().
34+
*
35+
* Some fields are not used by PostgreSQL; see tarCreateHeader().
36+
*/
37+
enum tarHeaderOffset
38+
{
39+
TAR_OFFSET_NAME = 0, /* 100 byte string */
40+
TAR_OFFSET_MODE = 100, /* 8 byte tar number, excludes S_IFMT */
41+
TAR_OFFSET_UID = 108, /* 8 byte tar number */
42+
TAR_OFFSET_GID = 116, /* 8 byte tar number */
43+
TAR_OFFSET_SIZE = 124, /* 8 byte tar number */
44+
TAR_OFFSET_MTIME = 136, /* 12 byte tar number */
45+
TAR_OFFSET_CHECKSUM = 148, /* 8 byte tar number */
46+
TAR_OFFSET_TYPEFLAG = 156, /* 1 byte file type, see TAR_FILETYPE_* */
47+
TAR_OFFSET_LINKNAME = 157, /* 100 byte string */
48+
TAR_OFFSET_MAGIC = 257, /* "ustar" with terminating zero byte */
49+
TAR_OFFSET_VERSION = 263, /* "00" */
50+
TAR_OFFSET_UNAME = 265, /* 32 byte string */
51+
TAR_OFFSET_GNAME = 297, /* 32 byte string */
52+
TAR_OFFSET_DEVMAJOR = 329, /* 8 byte tar number */
53+
TAR_OFFSET_DEVMINOR = 337, /* 8 byte tar number */
54+
TAR_OFFSET_PREFIX = 345 /* 155 byte string */
55+
/* last 12 bytes of the 512-byte block are unassigned */
56+
};
57+
58+
enum tarFileType
59+
{
60+
TAR_FILETYPE_PLAIN = '0',
61+
TAR_FILETYPE_SYMLINK = '2',
62+
TAR_FILETYPE_DIRECTORY = '5'
63+
};
64+
2665
extern enum tarError tarCreateHeader(char *h, const char *filename,
2766
const char *linktarget, pgoff_t size,
2867
mode_t mode, uid_t uid, gid_t gid,

src/port/tar.c

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,10 @@ tarCreateHeader(char *h, const char *filename, const char *linktarget,
120120
if (linktarget && strlen(linktarget) > 99)
121121
return TAR_SYMLINK_TOO_LONG;
122122

123-
memset(h, 0, 512); /* assume tar header size */
123+
memset(h, 0, TAR_BLOCK_SIZE);
124124

125125
/* Name 100 */
126-
strlcpy(&h[0], filename, 100);
126+
strlcpy(&h[TAR_OFFSET_NAME], filename, 100);
127127
if (linktarget != NULL || S_ISDIR(mode))
128128
{
129129
/*
@@ -139,68 +139,68 @@ tarCreateHeader(char *h, const char *filename, const char *linktarget,
139139
}
140140

141141
/* Mode 8 - this doesn't include the file type bits (S_IFMT) */
142-
print_tar_number(&h[100], 8, (mode & 07777));
142+
print_tar_number(&h[TAR_OFFSET_MODE], 8, (mode & 07777));
143143

144144
/* User ID 8 */
145-
print_tar_number(&h[108], 8, uid);
145+
print_tar_number(&h[TAR_OFFSET_UID], 8, uid);
146146

147147
/* Group 8 */
148-
print_tar_number(&h[116], 8, gid);
148+
print_tar_number(&h[TAR_OFFSET_GID], 8, gid);
149149

150150
/* File size 12 */
151151
if (linktarget != NULL || S_ISDIR(mode))
152152
/* Symbolic link or directory has size zero */
153-
print_tar_number(&h[124], 12, 0);
153+
print_tar_number(&h[TAR_OFFSET_SIZE], 12, 0);
154154
else
155-
print_tar_number(&h[124], 12, size);
155+
print_tar_number(&h[TAR_OFFSET_SIZE], 12, size);
156156

157157
/* Mod Time 12 */
158-
print_tar_number(&h[136], 12, mtime);
158+
print_tar_number(&h[TAR_OFFSET_MTIME], 12, mtime);
159159

160160
/* Checksum 8 cannot be calculated until we've filled all other fields */
161161

162162
if (linktarget != NULL)
163163
{
164164
/* Type - Symbolic link */
165-
h[156] = '2';
165+
h[TAR_OFFSET_TYPEFLAG] = TAR_FILETYPE_SYMLINK;
166166
/* Link Name 100 */
167-
strlcpy(&h[157], linktarget, 100);
167+
strlcpy(&h[TAR_OFFSET_LINKNAME], linktarget, 100);
168168
}
169169
else if (S_ISDIR(mode))
170170
{
171171
/* Type - directory */
172-
h[156] = '5';
172+
h[TAR_OFFSET_TYPEFLAG] = TAR_FILETYPE_DIRECTORY;
173173
}
174174
else
175175
{
176176
/* Type - regular file */
177-
h[156] = '0';
177+
h[TAR_OFFSET_TYPEFLAG] = TAR_FILETYPE_PLAIN;
178178
}
179179

180180
/* Magic 6 */
181-
strcpy(&h[257], "ustar");
181+
strcpy(&h[TAR_OFFSET_MAGIC], "ustar");
182182

183183
/* Version 2 */
184-
memcpy(&h[263], "00", 2);
184+
memcpy(&h[TAR_OFFSET_VERSION], "00", 2);
185185

186186
/* User 32 */
187187
/* XXX: Do we need to care about setting correct username? */
188-
strlcpy(&h[265], "postgres", 32);
188+
strlcpy(&h[TAR_OFFSET_UNAME], "postgres", 32);
189189

190190
/* Group 32 */
191191
/* XXX: Do we need to care about setting correct group name? */
192-
strlcpy(&h[297], "postgres", 32);
192+
strlcpy(&h[TAR_OFFSET_GNAME], "postgres", 32);
193193

194194
/* Major Dev 8 */
195-
print_tar_number(&h[329], 8, 0);
195+
print_tar_number(&h[TAR_OFFSET_DEVMAJOR], 8, 0);
196196

197197
/* Minor Dev 8 */
198-
print_tar_number(&h[337], 8, 0);
198+
print_tar_number(&h[TAR_OFFSET_DEVMINOR], 8, 0);
199199

200200
/* Prefix 155 - not used, leave as nulls */
201201

202202
/* Finally, compute and insert the checksum */
203-
print_tar_number(&h[148], 8, tarChecksum(h));
203+
print_tar_number(&h[TAR_OFFSET_CHECKSUM], 8, tarChecksum(h));
204204

205205
return TAR_OK;
206206
}

0 commit comments

Comments
 (0)