PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
tar.c
Go to the documentation of this file.
1 #include "c.h"
2 #include "pgtar.h"
3 #include <sys/stat.h>
4 
5 /*
6  * Print a numeric field in a tar header. The field starts at *s and is of
7  * length len; val is the value to be written.
8  *
9  * Per POSIX, the way to write a number is in octal with leading zeroes and
10  * one trailing space (or NUL, but we use space) at the end of the specified
11  * field width.
12  *
13  * However, the given value may not fit in the available space in octal form.
14  * If that's true, we use the GNU extension of writing \200 followed by the
15  * number in base-256 form (ie, stored in binary MSB-first). (Note: here we
16  * support only non-negative numbers, so we don't worry about the GNU rules
17  * for handling negative numbers.)
18  */
19 void
20 print_tar_number(char *s, int len, uint64 val)
21 {
22  if (val < (((uint64) 1) << ((len - 1) * 3)))
23  {
24  /* Use octal with trailing space */
25  s[--len] = ' ';
26  while (len)
27  {
28  s[--len] = (val & 7) + '0';
29  val >>= 3;
30  }
31  }
32  else
33  {
34  /* Use base-256 with leading \200 */
35  s[0] = '\200';
36  while (len > 1)
37  {
38  s[--len] = (val & 255);
39  val >>= 8;
40  }
41  }
42 }
43 
44 
45 /*
46  * Read a numeric field in a tar header. The field starts at *s and is of
47  * length len.
48  *
49  * The POSIX-approved format for a number is octal, ending with a space or
50  * NUL. However, for values that don't fit, we recognize the GNU extension
51  * of \200 followed by the number in base-256 form (ie, stored in binary
52  * MSB-first). (Note: here we support only non-negative numbers, so we don't
53  * worry about the GNU rules for handling negative numbers.)
54  */
55 uint64
56 read_tar_number(const char *s, int len)
57 {
58  uint64 result = 0;
59 
60  if (*s == '\200')
61  {
62  /* base-256 */
63  while (--len)
64  {
65  result <<= 8;
66  result |= (unsigned char) (*++s);
67  }
68  }
69  else
70  {
71  /* octal */
72  while (len-- && *s >= '0' && *s <= '7')
73  {
74  result <<= 3;
75  result |= (*s - '0');
76  s++;
77  }
78  }
79  return result;
80 }
81 
82 
83 /*
84  * Calculate the tar checksum for a header. The header is assumed to always
85  * be 512 bytes, per the tar standard.
86  */
87 int
89 {
90  int i,
91  sum;
92 
93  /*
94  * Per POSIX, the checksum is the simple sum of all bytes in the header,
95  * treating the bytes as unsigned, and treating the checksum field (at
96  * offset 148) as though it contained 8 spaces.
97  */
98  sum = 8 * ' '; /* presumed value for checksum field */
99  for (i = 0; i < 512; i++)
100  if (i < 148 || i >= 156)
101  sum += 0xFF & header[i];
102  return sum;
103 }
104 
105 
106 /*
107  * Fill in the buffer pointed to by h with a tar format header. This buffer
108  * must always have space for 512 characters, which is a requirement of
109  * the tar format.
110  */
111 enum tarError
112 tarCreateHeader(char *h, const char *filename, const char *linktarget,
113  pgoff_t size, mode_t mode, uid_t uid, gid_t gid, time_t mtime)
114 {
115  if (strlen(filename) > 99)
116  return TAR_NAME_TOO_LONG;
117 
118  if (linktarget && strlen(linktarget) > 99)
119  return TAR_SYMLINK_TOO_LONG;
120 
121  memset(h, 0, 512); /* assume tar header size */
122 
123  /* Name 100 */
124  strlcpy(&h[0], filename, 100);
125  if (linktarget != NULL || S_ISDIR(mode))
126  {
127  /*
128  * We only support symbolic links to directories, and this is
129  * indicated in the tar format by adding a slash at the end of the
130  * name, the same as for regular directories.
131  */
132  int flen = strlen(filename);
133 
134  flen = Min(flen, 99);
135  h[flen] = '/';
136  h[flen + 1] = '\0';
137  }
138 
139  /* Mode 8 - this doesn't include the file type bits (S_IFMT) */
140  print_tar_number(&h[100], 8, (mode & 07777));
141 
142  /* User ID 8 */
143  print_tar_number(&h[108], 8, uid);
144 
145  /* Group 8 */
146  print_tar_number(&h[116], 8, gid);
147 
148  /* File size 12 */
149  if (linktarget != NULL || S_ISDIR(mode))
150  /* Symbolic link or directory has size zero */
151  print_tar_number(&h[124], 12, 0);
152  else
153  print_tar_number(&h[124], 12, size);
154 
155  /* Mod Time 12 */
156  print_tar_number(&h[136], 12, mtime);
157 
158  /* Checksum 8 cannot be calculated until we've filled all other fields */
159 
160  if (linktarget != NULL)
161  {
162  /* Type - Symbolic link */
163  h[156] = '2';
164  /* Link Name 100 */
165  strlcpy(&h[157], linktarget, 100);
166  }
167  else if (S_ISDIR(mode))
168  {
169  /* Type - directory */
170  h[156] = '5';
171  }
172  else
173  {
174  /* Type - regular file */
175  h[156] = '0';
176  }
177 
178  /* Magic 6 */
179  strcpy(&h[257], "ustar");
180 
181  /* Version 2 */
182  memcpy(&h[263], "00", 2);
183 
184  /* User 32 */
185  /* XXX: Do we need to care about setting correct username? */
186  strlcpy(&h[265], "postgres", 32);
187 
188  /* Group 32 */
189  /* XXX: Do we need to care about setting correct group name? */
190  strlcpy(&h[297], "postgres", 32);
191 
192  /* Major Dev 8 */
193  print_tar_number(&h[329], 8, 0);
194 
195  /* Minor Dev 8 */
196  print_tar_number(&h[337], 8, 0);
197 
198  /* Prefix 155 - not used, leave as nulls */
199 
200  /* Finally, compute and insert the checksum */
201  print_tar_number(&h[148], 8, tarChecksum(h));
202 
203  return TAR_OK;
204 }
int tarChecksum(char *header)
Definition: tar.c:88
uint64 read_tar_number(const char *s, int len)
Definition: tar.c:56
int gid_t
Definition: win32.h:251
int uid_t
Definition: win32.h:250
Definition: pgtar.h:17
#define Min(x, y)
Definition: c.h:806
return result
Definition: formatting.c:1633
tarError
Definition: pgtar.h:15
void print_tar_number(char *s, int len, uint64 val)
Definition: tar.c:20
enum tarError tarCreateHeader(char *h, const char *filename, const char *linktarget, pgoff_t size, mode_t mode, uid_t uid, gid_t gid, time_t mtime)
Definition: tar.c:112
#define pgoff_t
Definition: win32.h:231
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define NULL
Definition: c.h:229
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:207
static char * filename
Definition: pg_dumpall.c:89
int i
long val
Definition: informix.c:689