Skip to content

Commit 72c5d0d

Browse files
author
Arthur Zakirov
committed
Add crazy function get_control_value().
It parses json-like lines of backup_content.control file.
1 parent 0077a78 commit 72c5d0d

File tree

1 file changed

+165
-57
lines changed

1 file changed

+165
-57
lines changed

dir.c

Lines changed: 165 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ print_file_list(FILE *out, const parray *files, const char *root)
670670
path = GetRelativePath(path, root);
671671

672672
fprintf(out, "{\"path\":\"%s\", \"size\":\"%lu\",\"mode\":\"%u\","
673-
"\"is_datafile\":\"%u\" \"crc\":\"%u\"",
673+
"\"is_datafile\":\"%u\", \"crc\":\"%u\"",
674674
path, (unsigned long) file->write_size, file->mode,
675675
file->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+
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+
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)
699833
FILE *fp;
700834
parray *files;
701835
char buf[MAXPGPATH * 2];
702-
int line_num = 0;
703836

704837
fp = fopen(file_txt, "rt");
705838
if (fp == NULL)
@@ -710,60 +843,33 @@ dir_read_file_list(const char *root, const char *file_txt)
710843

711844
while (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-
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;
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
768874
if (root)
769875
join_path_components(filepath, root, path);
@@ -772,15 +878,17 @@ dir_read_file_list(const char *root, const char *file_txt)
772878

773879
file = 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;
777883
file->is_datafile = is_datafile ? true : false;
778-
file->crc = crc;
884+
file->crc = (pg_crc32) crc;
779885
if (linked[0])
780886
file->linked = pgut_strdup(linked);
781-
file->segno = segno;
887+
file->segno = (int) segno;
888+
#ifdef PGPRO_EE
782889
file->generation = generation;
783-
file->is_partial_copy = is_partial_copy;
890+
file->is_partial_copy = (int) is_partial_copy;
891+
#endif
784892

785893
parray_append(files, file);
786894
}

0 commit comments

Comments
 (0)