@@ -670,7 +670,7 @@ print_file_list(FILE *out, const parray *files, const char *root)
670670path = GetRelativePath (path ,root );
671671
672672fprintf (out ,"{\"path\":\"%s\", \"size\":\"%lu\",\"mode\":\"%u\","
673- "\"is_datafile\":\"%u\" \"crc\":\"%u\"" ,
673+ "\"is_datafile\":\"%u\", \"crc\":\"%u\"" ,
674674path , (unsigned long )file -> write_size ,file -> mode ,
675675file -> is_datafile ?1 :0 ,file -> crc );
676676
@@ -689,6 +689,140 @@ print_file_list(FILE *out, const parray *files, const char *root)
689689}
690690}
691691
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+
692826/*
693827 * Construct parray of pgFile from the backup content list.
694828 * 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)
699833FILE * fp ;
700834parray * files ;
701835char buf [MAXPGPATH * 2 ];
702- int line_num = 0 ;
703836
704837fp = fopen (file_txt ,"rt" );
705838if (fp == NULL )
@@ -710,60 +843,33 @@ dir_read_file_list(const char *root, const char *file_txt)
710843
711844while (fgets (buf ,lengthof (buf ),fp ))
712845{
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 ;
752859
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);
757865
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);
760869
761870#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);
767873#endif
768874if (root )
769875join_path_components (filepath ,root ,path );
@@ -772,15 +878,17 @@ dir_read_file_list(const char *root, const char *file_txt)
772878
773879file = pgFileInit (filepath );
774880
775- file -> write_size = write_size ;
776- file -> mode = mode ;
881+ file -> write_size = ( size_t ) write_size ;
882+ file -> mode = ( mode_t ) mode ;
777883file -> is_datafile = is_datafile ? true : false;
778- file -> crc = crc ;
884+ file -> crc = ( pg_crc32 ) crc ;
779885if (linked [0 ])
780886file -> linked = pgut_strdup (linked );
781- file -> segno = segno ;
887+ file -> segno = (int )segno ;
888+ #ifdef PGPRO_EE
782889file -> generation = generation ;
783- file -> is_partial_copy = is_partial_copy ;
890+ file -> is_partial_copy = (int )is_partial_copy ;
891+ #endif
784892
785893parray_append (files ,file );
786894}