@@ -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
+ goto bad_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
+ goto bad_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
+ goto bad_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
+ goto bad_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
+ goto bad_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
- unsigned int mode ; /* bit length of mode_t depends on platforms */
721
- pgFile * file ;
722
- char * ptr ;
723
- unsigned int 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
}
0 commit comments