@@ -670,7 +670,7 @@ print_file_list(FILE *out, const parray *files, const char *root)
670
670
path = GetRelativePath (path ,root );
671
671
672
672
fprintf (out ,"{\"path\":\"%s\", \"size\":\"%lu\",\"mode\":\"%u\","
673
- "\"is_datafile\":\"%u\" \"crc\":\"%u\"" ,
673
+ "\"is_datafile\":\"%u\", \"crc\":\"%u\"" ,
674
674
path , (unsigned long )file -> write_size ,file -> mode ,
675
675
file -> is_datafile ?1 :0 ,file -> crc );
676
676
@@ -689,6 +689,140 @@ print_file_list(FILE *out, const parray *files, const char *root)
689
689
}
690
690
}
691
691
692
+ /* Parsing states for get_control_value() */
693
+ #define CONTROL_WAIT_NAME 1
694
+ #define CONTROL_INNAME 2
695
+ #define CONTROL_WAIT_COLON 3
696
+ #define CONTROL_WAIT_VALUE 4
697
+ #define CONTROL_INVALUE 5
698
+ #define CONTROL_WAIT_NEXT_NAME 6
699
+
700
+ /*
701
+ * Get value from json-like line "str" of backup_content.control file.
702
+ *
703
+ * The line has the following format:
704
+ * {"name1":"value1", "name2":"value2"}
705
+ *
706
+ * The value will be returned to "value_str" as string if it is not NULL. If it
707
+ * is NULL the value will be returned to "value_ulong" as unsigned long.
708
+ */
709
+ static void
710
+ get_control_value (const char * str ,const char * name ,
711
+ char * value_str ,uint64 * value_uint64 ,bool is_mandatory )
712
+ {
713
+ int state = CONTROL_WAIT_NAME ;
714
+ char * name_ptr = (char * )name ;
715
+ char * buf = (char * )str ;
716
+ char buf_uint64 [32 ],/* Buffer for "value_uint64" */
717
+ * buf_uint64_ptr ;
718
+
719
+ /* Set default values */
720
+ if (value_str )
721
+ * value_str = '\0' ;
722
+ else if (value_uint64 )
723
+ * value_uint64 = 0 ;
724
+
725
+ while (* buf )
726
+ {
727
+ switch (state )
728
+ {
729
+ case CONTROL_WAIT_NAME :
730
+ if (* buf == '"' )
731
+ state = CONTROL_INNAME ;
732
+ else if (IsAlpha (* buf ))
733
+ gotobad_format ;
734
+ break ;
735
+ case CONTROL_INNAME :
736
+ /* Found target field. Parse value. */
737
+ if (* buf == '"' )
738
+ state = CONTROL_WAIT_COLON ;
739
+ /* Check next field */
740
+ else if (* buf != * name_ptr )
741
+ {
742
+ name_ptr = (char * )name ;
743
+ state = CONTROL_WAIT_NEXT_NAME ;
744
+ }
745
+ else
746
+ name_ptr ++ ;
747
+ break ;
748
+ case CONTROL_WAIT_COLON :
749
+ if (* buf == ':' )
750
+ state = CONTROL_WAIT_VALUE ;
751
+ else if (!IsSpace (* buf ))
752
+ gotobad_format ;
753
+ break ;
754
+ case CONTROL_WAIT_VALUE :
755
+ if (* buf == '"' )
756
+ {
757
+ state = CONTROL_INVALUE ;
758
+ buf_uint64_ptr = buf_uint64 ;
759
+ }
760
+ else if (IsAlpha (* buf ))
761
+ gotobad_format ;
762
+ break ;
763
+ case CONTROL_INVALUE :
764
+ /* Value was parsed, exit */
765
+ if (* buf == '"' )
766
+ {
767
+ if (value_str )
768
+ {
769
+ * value_str = '\0' ;
770
+ }
771
+ else if (value_uint64 )
772
+ {
773
+ /* Length of buf_uint64 should not be greater than 31 */
774
+ if (buf_uint64_ptr - buf_uint64 >=32 )
775
+ elog (ERROR ,"field \"%s\" is out of range in the line %s of the file %s" ,
776
+ name ,str ,DATABASE_FILE_LIST );
777
+
778
+ * buf_uint64_ptr = '\0' ;
779
+ if (!parse_uint64 (buf_uint64 ,value_uint64 ))
780
+ gotobad_format ;
781
+ }
782
+
783
+ return ;
784
+ }
785
+ else
786
+ {
787
+ if (value_str )
788
+ {
789
+ * value_str = * buf ;
790
+ value_str ++ ;
791
+ }
792
+ else
793
+ {
794
+ * buf_uint64_ptr = * buf ;
795
+ buf_uint64_ptr ++ ;
796
+ }
797
+ }
798
+ break ;
799
+ case CONTROL_WAIT_NEXT_NAME :
800
+ if (* buf == ',' )
801
+ state = CONTROL_WAIT_NAME ;
802
+ break ;
803
+ default :
804
+ /* Should not happen */
805
+ break ;
806
+ }
807
+
808
+ buf ++ ;
809
+ }
810
+
811
+ /* There is no close quotes */
812
+ if (state == CONTROL_INNAME || state == CONTROL_INVALUE )
813
+ gotobad_format ;
814
+
815
+ /* Did not find target field */
816
+ if (is_mandatory )
817
+ elog (ERROR ,"field \"%s\" is not found in the line %s of the file %s" ,
818
+ name ,str ,DATABASE_FILE_LIST );
819
+ return ;
820
+
821
+ bad_format :
822
+ elog (ERROR ,"%s file has invalid format in line %s" ,
823
+ DATABASE_FILE_LIST ,str );
824
+ }
825
+
692
826
/*
693
827
* Construct parray of pgFile from the backup content list.
694
828
* If root is not NULL, path will be absolute path.
@@ -699,7 +833,6 @@ dir_read_file_list(const char *root, const char *file_txt)
699
833
FILE * fp ;
700
834
parray * files ;
701
835
char buf [MAXPGPATH * 2 ];
702
- int line_num = 0 ;
703
836
704
837
fp = fopen (file_txt ,"rt" );
705
838
if (fp == NULL )
@@ -710,60 +843,33 @@ dir_read_file_list(const char *root, const char *file_txt)
710
843
711
844
while (fgets (buf ,lengthof (buf ),fp ))
712
845
{
713
- char path [MAXPGPATH ];
714
- char filepath [MAXPGPATH ];
715
- char linked [MAXPGPATH ];
716
- uint64 generation = -1 ;
717
- int is_partial_copy = 0 ;
718
- unsigned long write_size ;
719
- pg_crc32 crc ;
720
- unsignedint mode ;/* bit length of mode_t depends on platforms */
721
- pgFile * file ;
722
- char * ptr ;
723
- unsignedint is_datafile ;
724
- int segno = 0 ;
725
-
726
- /* XXX Maybe use better parser function? */
727
- #define GET_VALUE (name ,value ,format ,is_mandatory )\
728
- do {\
729
- if (ptr == NULL && is_mandatory)\
730
- elog(ERROR, "parameter \"%s\" is not found in \"%s\" in %d line",\
731
- name, file_txt, line_num);\
732
- if (ptr)\
733
- sscanf(ptr, format, &value);\
734
- } while (0)
735
-
736
- line_num ++ ;
737
-
738
- ptr = strstr (buf ,"\"path\"" );
739
- GET_VALUE ("path" ,path ,"\"path\":\"%s\"" , true);
740
-
741
- ptr = strstr (buf ,"\"size\"" );
742
- GET_VALUE ("size" ,write_size ,"\"size\":\"%lu\"" , true);
743
-
744
- ptr = strstr (buf ,"\"mode\"" );
745
- GET_VALUE ("mode" ,mode ,"\"mode\":\"%u\"" , true);
746
-
747
- ptr = strstr (buf ,"\"is_datafile\"" );
748
- GET_VALUE ("is_datafile" ,is_datafile ,"\"is_datafile\":\"%u\"" , true);
749
-
750
- ptr = strstr (buf ,"\"crc\"" );
751
- GET_VALUE ("crc" ,crc ,"\"crc\":\"%u\"" , true);
846
+ char path [MAXPGPATH ];
847
+ char filepath [MAXPGPATH ];
848
+ char linked [MAXPGPATH ];
849
+ uint64 write_size ,
850
+ mode ,/* bit length of mode_t depends on platforms */
851
+ is_datafile ,
852
+ crc ,
853
+ segno ;
854
+ #ifdef PGPRO_EE
855
+ uint64 generation ,
856
+ is_partial_copy ;
857
+ #endif
858
+ pgFile * file ;
752
859
753
- /* optional fields */
754
- linked [0 ]= '\0' ;
755
- ptr = strstr (buf ,"\"linked\"" );
756
- GET_VALUE ("linked" ,linked ,"\"linked\":\"%s\"" , false);
860
+ get_control_value (buf ,"path" ,path ,NULL , true);
861
+ get_control_value (buf ,"size" ,NULL ,& write_size , true);
862
+ get_control_value (buf ,"mode" ,NULL ,& mode , true);
863
+ get_control_value (buf ,"is_datafile" ,NULL ,& is_datafile , true);
864
+ get_control_value (buf ,"crc" ,NULL ,& crc , true);
757
865
758
- ptr = strstr (buf ,"\"segno\"" );
759
- GET_VALUE ("segno" ,segno ,"\"segno\":\"%d\"" , false);
866
+ /* optional fields */
867
+ get_control_value (buf ,"linked" ,linked ,NULL , false);
868
+ get_control_value (buf ,"segno" ,NULL ,& segno , false);
760
869
761
870
#ifdef PGPRO_EE
762
- ptr = strstr (buf ,"\"CFS_generation\"" );
763
- GET_VALUE ("CFS_generation" ,generation ,"\"CFS_generation\":\"%lu\"" , true);
764
-
765
- sscanf (buf ,"\"CFS_generation\":\"%lu\"" ,& generation );
766
- GET_VALUE ("is_partial_copy" ,is_partial_copy ,"\"is_partial_copy\":\"%d\"" , true);
871
+ get_control_value (buf ,"CFS_generation" ,NULL ,& generation , true);
872
+ get_control_value (buf ,"is_partial_copy" ,NULL ,& is_partial_copy , true);
767
873
#endif
768
874
if (root )
769
875
join_path_components (filepath ,root ,path );
@@ -772,15 +878,17 @@ dir_read_file_list(const char *root, const char *file_txt)
772
878
773
879
file = pgFileInit (filepath );
774
880
775
- file -> write_size = write_size ;
776
- file -> mode = mode ;
881
+ file -> write_size = ( size_t ) write_size ;
882
+ file -> mode = ( mode_t ) mode ;
777
883
file -> is_datafile = is_datafile ? true : false;
778
- file -> crc = crc ;
884
+ file -> crc = ( pg_crc32 ) crc ;
779
885
if (linked [0 ])
780
886
file -> linked = pgut_strdup (linked );
781
- file -> segno = segno ;
887
+ file -> segno = (int )segno ;
888
+ #ifdef PGPRO_EE
782
889
file -> generation = generation ;
783
- file -> is_partial_copy = is_partial_copy ;
890
+ file -> is_partial_copy = (int )is_partial_copy ;
891
+ #endif
784
892
785
893
parray_append (files ,file );
786
894
}