mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-31 06:15:24 +00:00
protbuf: Add protobuf (PB) image entries read/write helpers v4
To not bloat util.h or image.h the protobuf.h introduced to handle all PB needs. We represent our PB objects as pairs of records | 4 bytes for object packed size +--- | X bytes -- object itself v3: - Use plain read/write calls - Use local buffers for small objects v4: - Add pb_pksize helper to calculate object size with header Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
committed by
Pavel Emelyanov
parent
e564ac6f04
commit
c75b4b70fc
1
Makefile
1
Makefile
@@ -59,6 +59,7 @@ OBJS += eventpoll.o
|
||||
OBJS += mount.o
|
||||
OBJS += inotify.o
|
||||
OBJS += pstree.o
|
||||
OBJS += protobuf.o
|
||||
|
||||
DEPS := $(patsubst %.o,%.d,$(OBJS))
|
||||
|
||||
|
55
include/protobuf.h
Normal file
55
include/protobuf.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef PROTOBUF_H__
|
||||
#define PROTOBUF_H__
|
||||
|
||||
#include "types.h"
|
||||
#include "compiler.h"
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
* ATTENTION
|
||||
*
|
||||
* This typdefs represent "generic" prototypes for
|
||||
* pack/unpack/getsize functions generated by PB
|
||||
* engine, thus (!!!) if PB engine change arguments
|
||||
* order or their number we may meet serious problems.
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Find a way to verify PB generated functions statemens
|
||||
* to match this typedefs.
|
||||
*/
|
||||
|
||||
typedef size_t (pb_getpksize_t)(void *obj);
|
||||
typedef size_t (pb_pack_t)(void *obj, void *where);
|
||||
typedef void *(pb_unpack_t)(void *allocator, size_t size, void *from);
|
||||
|
||||
extern int pb_read_object_with_header(int fd, void **pobj,
|
||||
pb_unpack_t *unpack,
|
||||
bool eof);
|
||||
|
||||
#define pb_read(__fd, __obj_pptr, __proto_message_name) \
|
||||
pb_read_object_with_header(__fd, (void **)__obj_pptr, \
|
||||
(void *)&__proto_message_name ##__unpack, \
|
||||
false)
|
||||
|
||||
#define pb_read_eof(__fd, __obj_pptr, __proto_message_name) \
|
||||
pb_read_object_with_header(__fd, (void **)__obj_pptr, \
|
||||
(void *)&__proto_message_name ##__unpack, \
|
||||
true)
|
||||
|
||||
extern int pb_write_object_with_header(int fd, void *obj,
|
||||
pb_getpksize_t *getpksize,
|
||||
pb_pack_t *pack);
|
||||
|
||||
#define pb_write(__fd, __obj, __proto_message_name) \
|
||||
pb_write_object_with_header(__fd, __obj, \
|
||||
(void *)&__proto_message_name ##__get_packed_size, \
|
||||
(void *)&__proto_message_name ##__pack)
|
||||
|
||||
#define pb_pksize(__obj, __proto_message_name) \
|
||||
(__proto_message_name ##__get_packed_size(__obj) + sizeof(u32))
|
||||
|
||||
#define pb_repeated_size(__obj, __member) \
|
||||
(sizeof(*(__obj)->__member) * (__obj)->n_ ##__member)
|
||||
|
||||
#endif /* PROTOBUF_H__ */
|
132
protobuf.c
Normal file
132
protobuf.c
Normal file
@@ -0,0 +1,132 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "compiler.h"
|
||||
#include "types.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "protobuf.h"
|
||||
|
||||
/*
|
||||
* To speed up reading of packed objects
|
||||
* by providing space on stack, this should
|
||||
* be more than enough for most objects.
|
||||
*/
|
||||
#define PB_PKOBJ_LOCAL_SIZE 1024
|
||||
|
||||
/*
|
||||
* Reads PB record (header + packed object) from file @fd and unpack
|
||||
* it with @unpack procedure to the pointer @pobj
|
||||
*
|
||||
* 1 on success
|
||||
* -1 on error (or EOF met and @eof set to false)
|
||||
* 0 on EOF and @eof set to true
|
||||
*
|
||||
* Don't forget to free memory granted to unpacked object in calling code if needed
|
||||
*/
|
||||
int pb_read_object_with_header(int fd, void **pobj, pb_unpack_t *unpack, bool eof)
|
||||
{
|
||||
u8 local[PB_PKOBJ_LOCAL_SIZE];
|
||||
void *buf = (void *)&local;
|
||||
u32 size;
|
||||
int ret;
|
||||
|
||||
*pobj = NULL;
|
||||
|
||||
ret = read(fd, &size, sizeof(size));
|
||||
if (ret == 0) {
|
||||
if (eof) {
|
||||
return 0;
|
||||
} else {
|
||||
pr_err("Unexpected EOF\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (ret < sizeof(size)) {
|
||||
pr_perror("Read %d bytes while %d expected",
|
||||
ret, (int)sizeof(size));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (size > sizeof(local)) {
|
||||
ret = -1;
|
||||
buf = xmalloc(size);
|
||||
if (!buf)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = read(fd, buf, size);
|
||||
if (ret < 0) {
|
||||
pr_perror("Can't read %d bytes from file", size);
|
||||
goto err;
|
||||
} else if (ret != size) {
|
||||
pr_perror("Read %d bytes while %d expected", ret, size);
|
||||
goto err;
|
||||
}
|
||||
|
||||
*pobj = unpack(NULL, size, buf);
|
||||
if (!*pobj) {
|
||||
ret = -1;
|
||||
pr_err("Failed unpacking object %p\n", pobj);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
err:
|
||||
if (buf != (void *)&local)
|
||||
xfree(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes PB record (header + packed object pointed by @obj)
|
||||
* to file @fd, using @getpksize to get packed size and @pack
|
||||
* to implement packing
|
||||
*
|
||||
* 0 on success
|
||||
* -1 on error
|
||||
*/
|
||||
int pb_write_object_with_header(int fd, void *obj, pb_getpksize_t *getpksize, pb_pack_t *pack)
|
||||
{
|
||||
u8 local[PB_PKOBJ_LOCAL_SIZE];
|
||||
void *buf = (void *)&local;
|
||||
u32 size, packed;
|
||||
int ret = -1;
|
||||
|
||||
size = getpksize(obj);
|
||||
if (size > (u32)sizeof(local)) {
|
||||
buf = xmalloc(size);
|
||||
if (!buf)
|
||||
goto err;
|
||||
}
|
||||
|
||||
packed = pack(obj, buf);
|
||||
if (packed != size) {
|
||||
pr_err("Failed packing PB object %p\n", obj);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = write(fd, &size, sizeof(size));
|
||||
if (ret != sizeof(size)) {
|
||||
ret = -1;
|
||||
pr_perror("Can't write %d bytes", (int)sizeof(size));
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = write(fd, buf, size);
|
||||
if (ret != size) {
|
||||
ret = -1;
|
||||
pr_perror("Can't write %d bytes", size);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
err:
|
||||
if (buf != (void *)&local)
|
||||
xfree(buf);
|
||||
return ret;
|
||||
}
|
Reference in New Issue
Block a user