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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy