Header And Logo

PostgreSQL
| The world's most advanced open source database.

tar.c

Go to the documentation of this file.
00001 #include "c.h"
00002 #include "pgtar.h"
00003 #include <sys/stat.h>
00004 
00005 /*
00006  * Utility routine to print possibly larger than 32 bit integers in a
00007  * portable fashion.  Filled with zeros.
00008  */
00009 static void
00010 print_val(char *s, uint64 val, unsigned int base, size_t len)
00011 {
00012     int         i;
00013 
00014     for (i = len; i > 0; i--)
00015     {
00016         int         digit = val % base;
00017 
00018         s[i - 1] = '0' + digit;
00019         val = val / base;
00020     }
00021 }
00022 
00023 
00024 /*
00025  * Calculate the tar checksum for a header. The header is assumed to always
00026  * be 512 bytes, per the tar standard.
00027  */
00028 int
00029 tarChecksum(char *header)
00030 {
00031     int         i,
00032                 sum;
00033 
00034     /*
00035      * Per POSIX, the checksum is the simple sum of all bytes in the header,
00036      * treating the bytes as unsigned, and treating the checksum field (at
00037      * offset 148) as though it contained 8 spaces.
00038      */
00039     sum = 8 * ' ';              /* presumed value for checksum field */
00040     for (i = 0; i < 512; i++)
00041         if (i < 148 || i >= 156)
00042             sum += 0xFF & header[i];
00043     return sum;
00044 }
00045 
00046 
00047 /*
00048  * Fill in the buffer pointed to by h with a tar format header. This buffer
00049  * must always have space for 512 characters, which is a requirement by
00050  * the tar format.
00051  */
00052 void
00053 tarCreateHeader(char *h, const char *filename, const char *linktarget,
00054                 size_t size, mode_t mode, uid_t uid, gid_t gid, time_t mtime)
00055 {
00056     /*
00057      * Note: most of the fields in a tar header are not supposed to be
00058      * null-terminated.  We use sprintf, which will write a null after the
00059      * required bytes; that null goes into the first byte of the next field.
00060      * This is okay as long as we fill the fields in order.
00061      */
00062     memset(h, 0, 512);          /* assume tar header size */
00063 
00064     /* Name 100 */
00065     sprintf(&h[0], "%.99s", filename);
00066     if (linktarget != NULL || S_ISDIR(mode))
00067     {
00068         /*
00069          * We only support symbolic links to directories, and this is
00070          * indicated in the tar format by adding a slash at the end of the
00071          * name, the same as for regular directories.
00072          */
00073         int         flen = strlen(filename);
00074 
00075         flen = Min(flen, 99);
00076         h[flen] = '/';
00077         h[flen + 1] = '\0';
00078     }
00079 
00080     /* Mode 8 */
00081     sprintf(&h[100], "%07o ", (int) mode);
00082 
00083     /* User ID 8 */
00084     sprintf(&h[108], "%07o ", uid);
00085 
00086     /* Group 8 */
00087     sprintf(&h[116], "%07o ", gid);
00088 
00089     /* File size 12 - 11 digits, 1 space; use print_val for 64 bit support */
00090     if (linktarget != NULL || S_ISDIR(mode))
00091         /* Symbolic link or directory has size zero */
00092         print_val(&h[124], 0, 8, 11);
00093     else
00094         print_val(&h[124], size, 8, 11);
00095     sprintf(&h[135], " ");
00096 
00097     /* Mod Time 12 */
00098     sprintf(&h[136], "%011o ", (int) mtime);
00099 
00100     /* Checksum 8 cannot be calculated until we've filled all other fields */
00101 
00102     if (linktarget != NULL)
00103     {
00104         /* Type - Symbolic link */
00105         sprintf(&h[156], "2");
00106         /* Link Name 100 */
00107         sprintf(&h[157], "%.99s", linktarget);
00108     }
00109     else if (S_ISDIR(mode))
00110         /* Type - directory */
00111         sprintf(&h[156], "5");
00112     else
00113         /* Type - regular file */
00114         sprintf(&h[156], "0");
00115 
00116     /* Magic 6 */
00117     sprintf(&h[257], "ustar");
00118 
00119     /* Version 2 */
00120     sprintf(&h[263], "00");
00121 
00122     /* User 32 */
00123     /* XXX: Do we need to care about setting correct username? */
00124     sprintf(&h[265], "%.31s", "postgres");
00125 
00126     /* Group 32 */
00127     /* XXX: Do we need to care about setting correct group name? */
00128     sprintf(&h[297], "%.31s", "postgres");
00129 
00130     /* Major Dev 8 */
00131     sprintf(&h[329], "%07o ", 0);
00132 
00133     /* Minor Dev 8 */
00134     sprintf(&h[337], "%07o ", 0);
00135 
00136     /* Prefix 155 - not used, leave as nulls */
00137 
00138     /*
00139      * We mustn't overwrite the next field while inserting the checksum.
00140      * Fortunately, the checksum can't exceed 6 octal digits, so we just write
00141      * 6 digits, a space, and a null, which is legal per POSIX.
00142      */
00143     sprintf(&h[148], "%06o ", tarChecksum(h));
00144 }