@@ -572,7 +572,7 @@ sendFileWithContent(const char *filename, const char *content)
572
572
573
573
/*
574
574
* Include all files from the given directory in the output tar stream. If
575
- * 'sizeonly' is true, we just calculate a total length and return ig , without
575
+ * 'sizeonly' is true, we just calculate a total length and return it , without
576
576
* actually sending anything.
577
577
*/
578
578
static int64
@@ -767,11 +767,16 @@ _tarChecksum(char *header)
767
767
int i ,
768
768
sum ;
769
769
770
- sum = 0 ;
770
+ /*
771
+ * Per POSIX, the checksum is the simple sum of all bytes in the header,
772
+ * treating the bytes as unsigned, and treating the checksum field (at
773
+ * offset 148) as though it contained 8 spaces.
774
+ */
775
+ sum = 8 * ' ' ; /* presumed value for checksum field */
771
776
for (i = 0 ; i < 512 ; i ++ )
772
777
if (i < 148 || i >= 156 )
773
778
sum += 0xFF & header [i ];
774
- return sum + 256 ; /* Assume 8 blanks in checksum field */
779
+ return sum ;
775
780
}
776
781
777
782
/* Given the member, write the TAR header & send the file */
@@ -850,9 +855,13 @@ _tarWriteHeader(const char *filename, const char *linktarget,
850
855
struct stat * statbuf )
851
856
{
852
857
char h [512 ];
853
- int lastSum = 0 ;
854
- int sum ;
855
858
859
+ /*
860
+ * Note: most of the fields in a tar header are not supposed to be
861
+ * null-terminated. We use sprintf, which will write a null after the
862
+ * required bytes; that null goes into the first byte of the next field.
863
+ * This is okay as long as we fill the fields in order.
864
+ */
856
865
memset (h , 0 , sizeof (h ));
857
866
858
867
/* Name 100 */
@@ -864,8 +873,11 @@ _tarWriteHeader(const char *filename, const char *linktarget,
864
873
* indicated in the tar format by adding a slash at the end of the
865
874
* name, the same as for regular directories.
866
875
*/
867
- h [strlen (filename )] = '/' ;
868
- h [strlen (filename ) + 1 ] = '\0' ;
876
+ int flen = strlen (filename );
877
+
878
+ flen = Min (flen , 99 );
879
+ h [flen ] = '/' ;
880
+ h [flen + 1 ] = '\0' ;
869
881
}
870
882
871
883
/* Mode 8 */
@@ -875,9 +887,9 @@ _tarWriteHeader(const char *filename, const char *linktarget,
875
887
sprintf (& h [108 ], "%07o " , statbuf -> st_uid );
876
888
877
889
/* Group 8 */
878
- sprintf (& h [117 ], "%07o " , statbuf -> st_gid );
890
+ sprintf (& h [116 ], "%07o " , statbuf -> st_gid );
879
891
880
- /* File size 12 - 11 digits, 1 space, no NUL */
892
+ /* File size 12 - 11 digits, 1 space; use print_val for 64 bit support */
881
893
if (linktarget != NULL || S_ISDIR (statbuf -> st_mode ))
882
894
/* Symbolic link or directory has size zero */
883
895
print_val (& h [124 ], 0 , 8 , 11 );
@@ -888,13 +900,13 @@ _tarWriteHeader(const char *filename, const char *linktarget,
888
900
/* Mod Time 12 */
889
901
sprintf (& h [136 ], "%011o " , (int ) statbuf -> st_mtime );
890
902
891
- /* Checksum 8 */
892
- sprintf (& h [148 ], "%06o " , lastSum );
903
+ /* Checksum 8 cannot be calculated until we've filled all other fields */
893
904
894
905
if (linktarget != NULL )
895
906
{
896
907
/* Type - Symbolic link */
897
908
sprintf (& h [156 ], "2" );
909
+ /* Link Name 100 */
898
910
sprintf (& h [157 ], "%.99s" , linktarget );
899
911
}
900
912
else if (S_ISDIR (statbuf -> st_mode ))
@@ -904,10 +916,11 @@ _tarWriteHeader(const char *filename, const char *linktarget,
904
916
/* Type - regular file */
905
917
sprintf (& h [156 ], "0" );
906
918
907
- /* Link tag 100 (NULL) */
919
+ /* Magic 6 */
920
+ sprintf (& h [257 ], "ustar" );
908
921
909
- /* Magic 6 + Version 2 */
910
- sprintf (& h [257 ], "ustar00 " );
922
+ /* Version 2 */
923
+ sprintf (& h [263 ], "00 " );
911
924
912
925
/* User 32 */
913
926
/* XXX: Do we need to care about setting correct username? */
@@ -917,17 +930,21 @@ _tarWriteHeader(const char *filename, const char *linktarget,
917
930
/* XXX: Do we need to care about setting correct group name? */
918
931
sprintf (& h [297 ], "%.31s" , "postgres" );
919
932
920
- /* Maj Dev 8 */
921
- sprintf (& h [329 ], "%6o " , 0 );
933
+ /* Major Dev 8 */
934
+ sprintf (& h [329 ], "%07o " , 0 );
922
935
923
- /* Min Dev 8 */
924
- sprintf (& h [337 ], "%6o " , 0 );
936
+ /* Minor Dev 8 */
937
+ sprintf (& h [337 ], "%07o " , 0 );
925
938
926
- while ((sum = _tarChecksum (h )) != lastSum )
927
- {
928
- sprintf (& h [148 ], "%06o " , sum );
929
- lastSum = sum ;
930
- }
939
+ /* Prefix 155 - not used, leave as nulls */
940
+
941
+ /*
942
+ * We mustn't overwrite the next field while inserting the checksum.
943
+ * Fortunately, the checksum can't exceed 6 octal digits, so we just write
944
+ * 6 digits, a space, and a null, which is legal per POSIX.
945
+ */
946
+ sprintf (& h [148 ], "%06o " , _tarChecksum (h ));
931
947
948
+ /* Now send the completed header. */
932
949
pq_putmessage ('d' , h , 512 );
933
950
}
0 commit comments