struct ovsdb_error * ovsdb_log_read(struct ovsdb_log *file, struct json **jsonp) { uint8_t expected_sha1[SHA1_DIGEST_SIZE]; uint8_t actual_sha1[SHA1_DIGEST_SIZE]; struct ovsdb_error *error; off_t data_offset; unsigned long data_length; struct json *json; char header[128]; *jsonp = json = NULL; if (file->read_error) { return ovsdb_error_clone(file->read_error); } else if (file->mode == OVSDB_LOG_WRITE) { return OVSDB_BUG("reading file in write mode"); } if (!fgets(header, sizeof header, file->stream)) { if (feof(file->stream)) { error = NULL; } else { error = ovsdb_io_error(errno, "%s: read failed", file->name); } goto error; } if (!parse_header(header, &data_length, expected_sha1)) { error = ovsdb_syntax_error(NULL, NULL, "%s: parse error at offset " "%lld in header line \"%.*s\"", file->name, (long long int) file->offset, (int) strcspn(header, "\n"), header); goto error; } data_offset = file->offset + strlen(header); error = parse_body(file, data_offset, data_length, actual_sha1, &json); if (error) { goto error; } if (memcmp(expected_sha1, actual_sha1, SHA1_DIGEST_SIZE)) { error = ovsdb_syntax_error(NULL, NULL, "%s: %lu bytes starting at " "offset %lld have SHA-1 hash "SHA1_FMT" " "but should have hash "SHA1_FMT, file->name, data_length, (long long int) data_offset, SHA1_ARGS(actual_sha1), SHA1_ARGS(expected_sha1)); goto error; } if (json->type == JSON_STRING) { error = ovsdb_syntax_error(NULL, NULL, "%s: %lu bytes starting at " "offset %lld are not valid JSON (%s)", file->name, data_length, (long long int) data_offset, json->u.string); goto error; } file->prev_offset = file->offset; file->offset = data_offset + data_length; *jsonp = json; return NULL; error: file->read_error = ovsdb_error_clone(error); json_destroy(json); return error; }
struct ovsdb_error * ovsdb_parser_get_error(const struct ovsdb_parser *parser) { return parser->error ? ovsdb_error_clone(parser->error) : NULL; }
struct ovsdb_error * ovsdb_log_write(struct ovsdb_log *file, struct json *json) { uint8_t sha1[SHA1_DIGEST_SIZE]; struct ovsdb_error *error; char *json_string; char header[128]; size_t length; json_string = NULL; if (file->write_error) { return ovsdb_error_clone(file->write_error); } else if (file->mode == OVSDB_LOG_READ) { file->mode = OVSDB_LOG_WRITE; if (fseeko(file->stream, file->offset, SEEK_SET)) { error = ovsdb_io_error(errno, "%s: cannot seek to offset %lld", file->name, (long long int) file->offset); goto error; } if (ftruncate(fileno(file->stream), file->offset)) { error = ovsdb_io_error(errno, "%s: cannot truncate to length %lld", file->name, (long long int) file->offset); goto error; } } if (json->type != JSON_OBJECT && json->type != JSON_ARRAY) { error = OVSDB_BUG("bad JSON type"); goto error; } /* Compose content. Add a new-line (replacing the null terminator) to make * the file easier to read, even though it has no semantic value. */ json_string = json_to_string(json, 0); length = strlen(json_string) + 1; json_string[length - 1] = '\n'; /* Compose header. */ sha1_bytes(json_string, length, sha1); snprintf(header, sizeof header, "%s%zu "SHA1_FMT"\n", magic, length, SHA1_ARGS(sha1)); /* Write. */ if (fwrite(header, strlen(header), 1, file->stream) != 1 || fwrite(json_string, length, 1, file->stream) != 1 || fflush(file->stream)) { error = ovsdb_io_error(errno, "%s: write failed", file->name); /* Remove any partially written data, ignoring errors since there is * nothing further we can do. */ ignore(ftruncate(fileno(file->stream), file->offset)); goto error; } file->offset += strlen(header) + length; free(json_string); return NULL; error: file->write_error = ovsdb_error_clone(error); free(json_string); return error; }