Age Owner Branch data TLA Line data Source code
1 : : #include "c.h"
2 : :
3 : : #include <sys/stat.h>
4 : :
5 : : #include "pgtar.h"
6 : :
7 : : /*
8 : : * Print a numeric field in a tar header. The field starts at *s and is of
9 : : * length len; val is the value to be written.
10 : : *
11 : : * Per POSIX, the way to write a number is in octal with leading zeroes and
12 : : * one trailing space (or NUL, but we use space) at the end of the specified
13 : : * field width.
14 : : *
15 : : * However, the given value may not fit in the available space in octal form.
16 : : * If that's true, we use the GNU extension of writing \200 followed by the
17 : : * number in base-256 form (ie, stored in binary MSB-first). (Note: here we
18 : : * support only non-negative numbers, so we don't worry about the GNU rules
19 : : * for handling negative numbers.)
20 : : */
21 : : void
3818 tgl@sss.pgh.pa.us 22 :CBC 1571984 : print_tar_number(char *s, int len, uint64 val)
23 : : {
24 [ + - ]: 1571984 : if (val < (((uint64) 1) << ((len - 1) * 3)))
25 : : {
26 : : /* Use octal with trailing space */
27 : 1571984 : s[--len] = ' ';
28 [ + + ]: 14147888 : while (len)
29 : : {
30 : 12575904 : s[--len] = (val & 7) + '0';
31 : 12575904 : val >>= 3;
32 : : }
33 : : }
34 : : else
35 : : {
36 : : /* Use base-256 with leading \200 */
3818 tgl@sss.pgh.pa.us 37 :UBC 0 : s[0] = '\200';
38 [ # # ]: 0 : while (len > 1)
39 : : {
40 : 0 : s[--len] = (val & 255);
41 : 0 : val >>= 8;
42 : : }
43 : : }
3818 tgl@sss.pgh.pa.us 44 :CBC 1571984 : }
45 : :
46 : :
47 : : /*
48 : : * Read a numeric field in a tar header. The field starts at *s and is of
49 : : * length len.
50 : : *
51 : : * The POSIX-approved format for a number is octal, ending with a space or
52 : : * NUL. However, for values that don't fit, we recognize the GNU extension
53 : : * of \200 followed by the number in base-256 form (ie, stored in binary
54 : : * MSB-first). (Note: here we support only non-negative numbers, so we don't
55 : : * worry about the GNU rules for handling negative numbers.)
56 : : */
57 : : uint64
58 : 1019553 : read_tar_number(const char *s, int len)
59 : : {
60 : 1019553 : uint64 result = 0;
61 : :
62 [ - + ]: 1019553 : if (*s == '\200')
63 : : {
64 : : /* base-256 */
3818 tgl@sss.pgh.pa.us 65 [ # # ]:UBC 0 : while (--len)
66 : : {
67 : 0 : result <<= 8;
68 : 0 : result |= (unsigned char) (*++s);
69 : : }
70 : : }
71 : : else
72 : : {
73 : : /* octal */
3818 tgl@sss.pgh.pa.us 74 [ + - + + :CBC 8964695 : while (len-- && *s >= '0' && *s <= '7')
+ - ]
75 : : {
76 : 7945142 : result <<= 3;
77 : 7945142 : result |= (*s - '0');
78 : 7945142 : s++;
79 : : }
80 : : }
81 : 1019553 : return result;
82 : : }
83 : :
84 : :
85 : : /*
86 : : * Calculate the tar checksum for a header. The header is assumed to always
87 : : * be 512 bytes, per the tar standard.
88 : : */
89 : : int
33 90 : 400471 : tarChecksum(const char *header)
91 : : {
92 : : int i,
93 : : sum;
94 : :
95 : : /*
96 : : * Per POSIX, the checksum is the simple sum of all bytes in the header,
97 : : * treating the bytes as unsigned, and treating the checksum field (at
98 : : * offset TAR_OFFSET_CHECKSUM) as though it contained 8 spaces.
99 : : */
4872 magnus@hagander.net 100 : 400471 : sum = 8 * ' '; /* presumed value for checksum field */
33 tgl@sss.pgh.pa.us 101 [ + + ]: 205441623 : for (i = 0; i < TAR_BLOCK_SIZE; i++)
102 [ + + + + ]: 205041152 : if (i < TAR_OFFSET_CHECKSUM || i >= TAR_OFFSET_CHECKSUM + 8)
4872 magnus@hagander.net 103 : 201837384 : sum += 0xFF & header[i];
104 : 400471 : return sum;
105 : : }
106 : :
107 : : /*
108 : : * Check validity of a tar header (assumed to be 512 bytes long).
109 : : * We verify the checksum and the magic number / version.
110 : : */
111 : : bool
33 tgl@sss.pgh.pa.us 112 : 203889 : isValidTarHeader(const char *header)
113 : : {
114 : : int sum;
115 : 203889 : int chk = tarChecksum(header);
116 : :
117 : 203889 : sum = read_tar_number(&header[TAR_OFFSET_CHECKSUM], 8);
118 : :
119 [ - + ]: 203889 : if (sum != chk)
33 tgl@sss.pgh.pa.us 120 :UBC 0 : return false;
121 : :
122 : : /* POSIX tar format */
33 tgl@sss.pgh.pa.us 123 [ + - ]:CBC 203889 : if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar\0", 6) == 0 &&
124 [ + - ]: 203889 : memcmp(&header[TAR_OFFSET_VERSION], "00", 2) == 0)
125 : 203889 : return true;
126 : : /* GNU tar format */
33 tgl@sss.pgh.pa.us 127 [ # # ]:UBC 0 : if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar \0", 8) == 0)
128 : 0 : return true;
129 : : /* not-quite-POSIX format written by pre-9.3 pg_dump */
130 [ # # ]: 0 : if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar00\0", 8) == 0)
131 : 0 : return true;
132 : :
133 : 0 : return false;
134 : : }
135 : :
136 : :
137 : : /*
138 : : * Fill in the buffer pointed to by h with a tar format header. This buffer
139 : : * must always have space for 512 characters, which is a requirement of
140 : : * the tar format.
141 : : */
142 : : enum tarError
4872 magnus@hagander.net 143 :CBC 196495 : tarCreateHeader(char *h, const char *filename, const char *linktarget,
144 : : pgoff_t size, mode_t mode, uid_t uid, gid_t gid, time_t mtime)
145 : : {
4088 peter_e@gmx.net 146 [ + + ]: 196495 : if (strlen(filename) > 99)
147 : 1 : return TAR_NAME_TOO_LONG;
148 : :
149 [ + + - + ]: 196494 : if (linktarget && strlen(linktarget) > 99)
4088 peter_e@gmx.net 150 :UBC 0 : return TAR_SYMLINK_TOO_LONG;
151 : :
1008 rhaas@postgresql.org 152 :CBC 196494 : memset(h, 0, TAR_BLOCK_SIZE);
153 : :
154 : : /* Name 100 */
155 : 196494 : strlcpy(&h[TAR_OFFSET_NAME], filename, 100);
4872 magnus@hagander.net 156 [ + + + + ]: 196494 : if (linktarget != NULL || S_ISDIR(mode))
157 : : {
158 : : /*
159 : : * We only support symbolic links to directories, and this is
160 : : * indicated in the tar format by adding a slash at the end of the
161 : : * name, the same as for regular directories.
162 : : */
163 : 4838 : int flen = strlen(filename);
164 : :
165 : 4838 : flen = Min(flen, 99);
166 : 4838 : h[flen] = '/';
167 : 4838 : h[flen + 1] = '\0';
168 : : }
169 : :
170 : : /* Mode 8 - this doesn't include the file type bits (S_IFMT) */
1008 rhaas@postgresql.org 171 : 196494 : print_tar_number(&h[TAR_OFFSET_MODE], 8, (mode & 07777));
172 : :
173 : : /* User ID 8 */
174 : 196494 : print_tar_number(&h[TAR_OFFSET_UID], 8, uid);
175 : :
176 : : /* Group 8 */
177 : 196494 : print_tar_number(&h[TAR_OFFSET_GID], 8, gid);
178 : :
179 : : /* File size 12 */
4872 magnus@hagander.net 180 [ + + + + ]: 196494 : if (linktarget != NULL || S_ISDIR(mode))
181 : : /* Symbolic link or directory has size zero */
1008 rhaas@postgresql.org 182 : 4838 : print_tar_number(&h[TAR_OFFSET_SIZE], 12, 0);
183 : : else
184 : 191656 : print_tar_number(&h[TAR_OFFSET_SIZE], 12, size);
185 : :
186 : : /* Mod Time 12 */
187 : 196494 : print_tar_number(&h[TAR_OFFSET_MTIME], 12, mtime);
188 : :
189 : : /* Checksum 8 cannot be calculated until we've filled all other fields */
190 : :
4872 magnus@hagander.net 191 [ + + ]: 196494 : if (linktarget != NULL)
192 : : {
193 : : /* Type - Symbolic link */
1008 rhaas@postgresql.org 194 : 16 : h[TAR_OFFSET_TYPEFLAG] = TAR_FILETYPE_SYMLINK;
195 : : /* Link Name 100 */
196 : 16 : strlcpy(&h[TAR_OFFSET_LINKNAME], linktarget, 100);
197 : : }
4872 magnus@hagander.net 198 [ + + ]: 196478 : else if (S_ISDIR(mode))
199 : : {
200 : : /* Type - directory */
1008 rhaas@postgresql.org 201 : 4822 : h[TAR_OFFSET_TYPEFLAG] = TAR_FILETYPE_DIRECTORY;
202 : : }
203 : : else
204 : : {
205 : : /* Type - regular file */
206 : 191656 : h[TAR_OFFSET_TYPEFLAG] = TAR_FILETYPE_PLAIN;
207 : : }
208 : :
209 : : /* Magic 6 */
210 : 196494 : strcpy(&h[TAR_OFFSET_MAGIC], "ustar");
211 : :
212 : : /* Version 2 */
213 : 196494 : memcpy(&h[TAR_OFFSET_VERSION], "00", 2);
214 : :
215 : : /* User 32 */
216 : : /* XXX: Do we need to care about setting correct username? */
217 : 196494 : strlcpy(&h[TAR_OFFSET_UNAME], "postgres", 32);
218 : :
219 : : /* Group 32 */
220 : : /* XXX: Do we need to care about setting correct group name? */
221 : 196494 : strlcpy(&h[TAR_OFFSET_GNAME], "postgres", 32);
222 : :
223 : : /* Major Dev 8 */
224 : 196494 : print_tar_number(&h[TAR_OFFSET_DEVMAJOR], 8, 0);
225 : :
226 : : /* Minor Dev 8 */
227 : 196494 : print_tar_number(&h[TAR_OFFSET_DEVMINOR], 8, 0);
228 : :
229 : : /* Prefix 155 - not used, leave as nulls */
230 : :
231 : : /* Finally, compute and insert the checksum */
232 : 196494 : print_tar_number(&h[TAR_OFFSET_CHECKSUM], 8, tarChecksum(h));
233 : :
4088 peter_e@gmx.net 234 : 196494 : return TAR_OK;
235 : : }
|