📄 deserialize.c
字号:
/*
This file is part of GNUnet.
(C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 Christian Grothoff (and other contributing authors)
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2, or (at your
option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNUnet; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/**
* @file applications/fs/fsui/deserializer.c
* @brief FSUI functions for reading state from disk
* @author Christian Grothoff
* @see serializer.c
*/
#include "platform.h"
#include "gnunet_fsui_lib.h"
#include "gnunet_directories.h"
#include "fsui.h"
typedef struct
{
int fd;
unsigned int have;
unsigned int size;
unsigned int pos;
char *buffer;
} ReadBuffer;
static int
read_buffered (ReadBuffer * rb, void *d, unsigned int size)
{
char *dst = d;
unsigned int min;
unsigned int pos;
int ret;
if (rb->fd == -1)
return -1;
pos = 0;
do
{
/* first, use buffer */
min = rb->have - rb->pos;
if (min > 0)
{
if (min > size - pos)
min = size - pos;
memcpy (&dst[pos], &rb->buffer[rb->pos], min);
rb->pos += min;
pos += min;
}
if (pos == size)
return pos; /* done! */
GNUNET_GE_ASSERT (NULL, rb->have == rb->pos);
/* fill buffer */
ret = READ (rb->fd, rb->buffer, rb->size);
if (ret == -1)
{
CLOSE (rb->fd);
rb->fd = -1;
return -1;
}
if (ret == 0)
return 0;
rb->pos = 0;
rb->have = ret;
}
while (pos < size); /* should always be true */
return pos;
}
static int
read_int (ReadBuffer * rb, int *val)
{
int big;
if (sizeof (int) != read_buffered (rb, &big, sizeof (int)))
return GNUNET_SYSERR;
*val = ntohl (big);
return GNUNET_OK;
}
static unsigned int
read_uint (ReadBuffer * rb, unsigned int *val)
{
unsigned int big;
if (sizeof (unsigned int) !=
read_buffered (rb, &big, sizeof (unsigned int)))
return GNUNET_SYSERR;
*val = ntohl (big);
return GNUNET_OK;
}
#define READINT(a) if (GNUNET_OK != read_int(rb, (int*) &a)) return GNUNET_SYSERR;
static int
read_long (ReadBuffer * rb, long long *val)
{
long long big;
if (sizeof (long long) != read_buffered (rb, &big, sizeof (long long)))
return GNUNET_SYSERR;
*val = GNUNET_ntohll (big);
return GNUNET_OK;
}
#define READLONG(a) if (GNUNET_OK != read_long(rb, (long long*) &a)) return GNUNET_SYSERR;
static struct GNUNET_ECRS_URI *
read_uri (struct GNUNET_GE_Context *ectx, ReadBuffer * rb)
{
char *buf;
struct GNUNET_ECRS_URI *ret;
unsigned int size;
if (GNUNET_OK != read_uint (rb, &size))
return NULL;
buf = GNUNET_malloc (size + 1);
buf[size] = '\0';
if (size != read_buffered (rb, buf, size))
{
GNUNET_free (buf);
return NULL;
}
ret = GNUNET_ECRS_string_to_uri (ectx, buf);
GNUNET_GE_BREAK (ectx, ret != NULL);
GNUNET_free (buf);
return ret;
}
#define READURI(u) if (NULL == (u = read_uri(ectx, rb))) return GNUNET_SYSERR;
static char *
read_string (ReadBuffer * rb, unsigned int maxLen)
{
char *buf;
unsigned int big;
if (GNUNET_OK != read_uint (rb, &big))
return NULL;
if (big > maxLen)
return NULL;
buf = GNUNET_malloc (big + 1);
buf[big] = '\0';
if (big != read_buffered (rb, buf, big))
{
GNUNET_free (buf);
return NULL;
}
return buf;
}
#define READSTRING(c, max) if (NULL == (c = read_string(rb, max))) return GNUNET_SYSERR;
static void
fixState (GNUNET_FSUI_State * state)
{
switch (*state)
{ /* try to correct errors */
case GNUNET_FSUI_ACTIVE:
*state = GNUNET_FSUI_PENDING;
break;
case GNUNET_FSUI_PENDING:
case GNUNET_FSUI_COMPLETED_JOINED:
case GNUNET_FSUI_ABORTED_JOINED:
case GNUNET_FSUI_ERROR_JOINED:
break;
case GNUNET_FSUI_ERROR:
*state = GNUNET_FSUI_ERROR_JOINED;
break;
case GNUNET_FSUI_ABORTED:
*state = GNUNET_FSUI_ABORTED_JOINED;
break;
case GNUNET_FSUI_COMPLETED:
*state = GNUNET_FSUI_COMPLETED_JOINED;
break;
default:
*state = GNUNET_FSUI_ERROR_JOINED;
break;
}
}
/**
* Read file info from file.
*
* @return GNUNET_OK on success, GNUNET_SYSERR on error
*/
static struct GNUNET_MetaData *
read_meta (struct GNUNET_GE_Context *ectx, ReadBuffer * rb)
{
unsigned int size;
char *buf;
struct GNUNET_MetaData *meta;
if (read_uint (rb, &size) != GNUNET_OK)
{
GNUNET_GE_BREAK (ectx, 0);
return NULL;
}
if (size > 1024 * 1024)
{
GNUNET_GE_BREAK (ectx, 0);
return NULL;
}
buf = GNUNET_malloc (size);
if (size != read_buffered (rb, buf, size))
{
GNUNET_free (buf);
GNUNET_GE_BREAK (ectx, 0);
return NULL;
}
meta = GNUNET_meta_data_deserialize (ectx, buf, size);
if (meta == NULL)
{
GNUNET_free (buf);
GNUNET_GE_BREAK (ectx, 0);
return NULL;
}
GNUNET_free (buf);
return meta;
}
/**
* Read file info from file.
*
* @return GNUNET_OK on success, GNUNET_SYSERR on error
*/
static int
readFileInfo (struct GNUNET_GE_Context *ectx, ReadBuffer * rb,
GNUNET_ECRS_FileInfo * fi)
{
fi->meta = read_meta (ectx, rb);
if (fi->meta == NULL)
{
GNUNET_GE_BREAK (ectx, 0);
return GNUNET_SYSERR;
}
fi->uri = NULL;
fi->uri = read_uri (ectx, rb);
if (fi->uri == NULL)
{
GNUNET_meta_data_destroy (fi->meta);
fi->meta = NULL;
GNUNET_GE_BREAK (ectx, 0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
/**
* (Recursively) read a download list from the given fd. The returned
* pointer is expected to be integrated into the tree either as a next
* or child pointer such that the given parent becomes the parent of the
* returned node.
*
* @return NULL on error AND on read of empty
* list (these two cannot be distinguished)
*/
static GNUNET_FSUI_DownloadList *
readDownloadList (struct GNUNET_GE_Context *ectx,
ReadBuffer * rb, GNUNET_FSUI_Context * ctx,
GNUNET_FSUI_DownloadList * parent)
{
GNUNET_FSUI_DownloadList *ret;
GNUNET_FSUI_SearchList *pos;
unsigned int big;
int i;
int ok;
int soff;
GNUNET_GE_ASSERT (ectx, ctx != NULL);
if ((GNUNET_OK != read_uint (rb, &big)) || (big == 0))
return NULL;
ret = GNUNET_malloc (sizeof (GNUNET_FSUI_DownloadList));
memset (ret, 0, sizeof (GNUNET_FSUI_DownloadList));
ret->ctx = ctx;
if ((GNUNET_OK != read_int (rb, &soff)) ||
(GNUNET_OK != read_int (rb, (int *) &ret->state)) ||
(GNUNET_OK != read_int (rb, &ret->is_recursive)) ||
(GNUNET_OK != read_int (rb, &ret->is_directory)) ||
(GNUNET_OK != read_uint (rb, &ret->anonymityLevel)) ||
(GNUNET_OK != read_uint (rb, &ret->completedDownloadsCount)) ||
(GNUNET_OK != read_long (rb, (long long *) &ret->total)) ||
(GNUNET_OK != read_long (rb, (long long *) &ret->completed)) ||
(GNUNET_OK != read_long (rb, (long long *) &ret->runTime)) ||
(GNUNET_OK != read_uint (rb, &big)) || (big > 1024 * 1024))
{
GNUNET_GE_BREAK (NULL, 0);
GNUNET_free (ret);
return NULL;
}
ret->lastProgressTime = GNUNET_get_time();
ret->progressBits = 1;
fixState (&ret->state);
ret->filename = GNUNET_malloc (big + 1);
ret->filename[big] = '\0';
if (big != read_buffered (rb, ret->filename, big))
{
GNUNET_GE_BREAK (ectx, 0);
GNUNET_free (ret->filename);
GNUNET_free (ret);
return NULL;
}
if (GNUNET_OK != readFileInfo (ectx, rb, &ret->fi))
{
GNUNET_GE_BREAK (NULL, 0);
GNUNET_free (ret->filename);
GNUNET_free (ret);
return NULL;
}
if (ret->completedDownloadsCount > 0)
ret->completedDownloads
=
GNUNET_malloc (sizeof (struct GNUNET_ECRS_URI *) *
ret->completedDownloadsCount);
ok = GNUNET_YES;
for (i = 0; i < ret->completedDownloadsCount; i++)
{
ret->completedDownloads[i] = read_uri (ectx, rb);
if (ret->completedDownloads[i] == NULL)
{
GNUNET_GE_BREAK (NULL, 0);
ok = GNUNET_NO;
}
}
if (GNUNET_NO == ok)
{
GNUNET_free (ret->filename);
GNUNET_ECRS_uri_destroy (ret->fi.uri);
GNUNET_meta_data_destroy (ret->fi.meta);
for (i = 0; i < ret->completedDownloadsCount; i++)
{
if (ret->completedDownloads[i] != NULL)
GNUNET_ECRS_uri_destroy (ret->completedDownloads[i]);
}
GNUNET_free (ret->completedDownloads);
GNUNET_free (ret);
GNUNET_GE_BREAK (NULL, 0);
return NULL;
}
ret->parent = parent;
if (soff == 0)
{
ret->search = NULL;
}
else
{
pos = ctx->activeSearches;
while (--soff > 0)
{
if (pos == NULL)
{
GNUNET_GE_BREAK (NULL, 0);
break;
}
pos = pos->next;
}
ret->search = pos;
if (pos != NULL)
{
GNUNET_array_grow (pos->my_downloads,
pos->my_downloads_size,
pos->my_downloads_size + 1);
pos->my_downloads[pos->my_downloads_size - 1] = ret;
}
}
ret->next = readDownloadList (ectx, rb, ctx, parent);
ret->child = readDownloadList (ectx, rb, ctx, ret);
#if DEBUG_PERSISTENCE
GNUNET_GE_LOG (ectx,
GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
"FSUI persistence: restoring download `%s': (%llu, %llu)\n",
ret->filename, ret->completed, ret->total);
#endif
return ret;
}
static int
checkMagic (ReadBuffer * rb)
{
char magic[8];
if (8 != read_buffered (rb, magic, 8))
{
GNUNET_GE_BREAK (NULL, 0);
return GNUNET_SYSERR;
}
if (0 != memcmp (magic, "FSUI03\n\0", 8))
{
GNUNET_GE_BREAK (NULL, 0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
static int
readCollection (ReadBuffer * rb, struct GNUNET_FSUI_Context *ctx)
{
int big;
/* deserialize collection data */
READINT (big);
if (big == 0)
{
ctx->collectionData = NULL;
return GNUNET_OK;
}
if ((big > 16 * 1024 * 1024) || (big < sizeof (unsigned int)))
{
GNUNET_GE_BREAK (NULL, 0);
return GNUNET_SYSERR;
}
ctx->collectionDataSize = big;
ctx->collectionData = GNUNET_malloc (big);
if (big != read_buffered (rb, ctx->collectionData, big))
{
GNUNET_free (ctx->collectionData);
ctx->collectionData = NULL;
ctx->collectionDataSize = 0;
GNUNET_GE_BREAK (NULL, 0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
/**
* Read in information about the individual ECRS searches
* that we are performing.
*/
struct SearchRecordList *
read_search_record_list (struct GNUNET_GE_Context *ectx, ReadBuffer * rb)
{
unsigned int is_required;
GNUNET_HashCode key;
struct GNUNET_ECRS_URI *uri;
struct SearchRecordList *ret;
struct SearchRecordList *head;
struct SearchRecordList *tail;
ret = NULL;
head = NULL;
tail = NULL;
while (1)
{
if (GNUNET_OK != read_uint (rb, &is_required))
break;
if (is_required == -1)
break; /* end of list marker */
if (sizeof (GNUNET_HashCode)
!= read_buffered (rb, &key, sizeof (GNUNET_HashCode)))
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -