📄 ondemand.c
字号:
/*
This file is part of GNUnet.
(C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 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., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
/**
* @file applications/fs/gap/ondemand.c
* @brief functions for handling on-demand encoding
* @author Christian Grothoff
*/
#include "platform.h"
#include "gnunet_util.h"
#include "gnunet_directories.h"
#include "gnunet_protocols.h"
#include "gnunet_datastore_service.h"
#include "gnunet_state_service.h"
#include "ecrs_core.h"
#include "shared.h"
#include "ondemand.h"
/**
* Format of an on-demand block.
*/
typedef struct
{
GNUNET_DatastoreValue header;
unsigned int type;
/**
* Size of the on-demand encoded part of the file
* that this Block represents.
*/
unsigned int blockSize;
/**
* At what offset in the plaintext file is
* this content stored?
*/
unsigned long long fileOffset;
/**
* What is the GNUNET_hash of the file that contains
* this block? Used to determine the name
* of the file in the on-demand datastore.
*/
GNUNET_HashCode fileId;
} OnDemandBlock;
/**
* Name of the directory where we store symlinks to indexed
* files.
*/
static char *index_directory;
static GNUNET_State_ServiceAPI *state;
static GNUNET_Datastore_ServiceAPI *datastore;
static GNUNET_CoreAPIForPlugins *coreAPI;
/**
* Get the name of the symbolic link corresponding
* to the given hash of an indexed file.
*/
static char *
get_indexed_filename (const GNUNET_HashCode * fileId)
{
GNUNET_EncName enc;
char *fn;
GNUNET_hash_to_enc (fileId, &enc);
fn = GNUNET_malloc (strlen (index_directory) + sizeof (GNUNET_EncName) + 1);
strcpy (fn, index_directory);
strcat (fn, DIR_SEPARATOR_STR);
strcat (fn, (char *) &enc);
return fn;
}
/**
* We use the state-DB to mark that certain indexed
* files have disappeared. If they are indexed again
* or explicitly unindexed, we should remove the
* respective markers.
*
* @param fileId hash of the file for which the marker
* should be removed
*/
static void
remove_unavailable_mark (const GNUNET_HashCode * fileId)
{
GNUNET_EncName enc;
char unavail_key[256];
GNUNET_hash_to_enc (fileId, &enc);
GNUNET_snprintf (unavail_key, 256, "FIRST_UNAVAILABLE-%s", (char *) &enc);
state->unlink (coreAPI->ectx, unavail_key);
}
/**
* We use the state-DB to mark that certain indexed
* files have disappeared. If they are marked as
* disappeared for a while, we remove all traces of
* those files from the database. This function is
* called to either initially mark a file as unavailable,
* or, if the condition persists, to trigger its
* removal from the database.
*/
static void
publish_unavailable_mark (const GNUNET_HashCode * fileId)
{
char unavail_key[256];
GNUNET_EncName enc;
unsigned long long *first_unavail;
unsigned long long now;
unsigned int len;
char *ofn;
char *fn;
int ret;
now = GNUNET_get_time ();
GNUNET_hash_to_enc (fileId, &enc);
GNUNET_snprintf (unavail_key, 256, "FIRST_UNVAILABLE-%s", (char *) &enc);
if (state->read (coreAPI->ectx, unavail_key, (void *) &first_unavail) !=
sizeof (GNUNET_CronTime))
{
now = GNUNET_htonll (now);
state->write (coreAPI->ectx,
unavail_key, sizeof (GNUNET_CronTime), (void *) &now);
return;
}
if (GNUNET_ntohll (*first_unavail) - now < 3 * GNUNET_CRON_DAYS)
return; /* do nothing for first 3 days */
fn = get_indexed_filename (fileId);
/* Delete it after 3 days */
len = 256;
ofn = GNUNET_malloc (len);
while (((ret = READLINK (fn, ofn, len)) == -1) &&
(errno == ENAMETOOLONG) && (len < 4 * 1024 * 1024))
if (len * 2 < len)
{
GNUNET_GE_BREAK (coreAPI->ectx, 0);
GNUNET_array_grow (ofn, len, 0);
GNUNET_free (fn);
return;
}
GNUNET_array_grow (ofn, len, len * 2);
if (ret != -1)
{
GNUNET_GE_LOG (coreAPI->ectx,
GNUNET_GE_WARNING | GNUNET_GE_BULK |
GNUNET_GE_USER,
_
("Because the file `%s' has been unavailable for 3 days"
" it got removed from your share. Please unindex files before"
" deleting them as the index now contains invalid references!\n"),
ofn);
}
GNUNET_free (ofn);
state->unlink (coreAPI->ectx, unavail_key);
UNLINK (fn);
GNUNET_free (fn);
}
/**
* Creates a symlink to the given file in the shared directory
*
* @param fn the file that was indexed
* @param fileId the file's GNUNET_hash code
* @return GNUNET_SYSERR on error, GNUNET_NO if symlinking failed,
* GNUNET_YES on success
*/
int
GNUNET_FS_ONDEMAND_index_prepare_with_symlink (struct GNUNET_GE_Context *ectx,
const GNUNET_HashCode * fileId,
const char *fn)
{
GNUNET_EncName enc;
char *serverFN;
GNUNET_HashCode linkId;
if ((GNUNET_SYSERR == GNUNET_hash_file (ectx,
fn,
&linkId)) ||
(0 != memcmp (&linkId, fileId, sizeof (GNUNET_HashCode))))
return GNUNET_SYSERR;
serverFN =
GNUNET_malloc (strlen (index_directory) + 2 + sizeof (GNUNET_EncName));
strcpy (serverFN, index_directory);
strcat (serverFN, DIR_SEPARATOR_STR);
GNUNET_hash_to_enc (fileId, &enc);
strcat (serverFN, (char *) &enc);
UNLINK (serverFN);
GNUNET_disk_directory_create_for_file (ectx, serverFN);
if (0 != SYMLINK (fn, serverFN))
{
GNUNET_GE_LOG_STRERROR_FILE (ectx,
GNUNET_GE_ERROR | GNUNET_GE_ADMIN |
GNUNET_GE_USER | GNUNET_GE_BULK, "symlink",
fn);
GNUNET_GE_LOG_STRERROR_FILE (ectx,
GNUNET_GE_ERROR | GNUNET_GE_ADMIN |
GNUNET_GE_USER | GNUNET_GE_BULK, "symlink",
serverFN);
GNUNET_free (serverFN);
return GNUNET_NO;
}
GNUNET_free (serverFN);
remove_unavailable_mark (fileId);
return GNUNET_YES;
}
/**
* Writes the given content to the file at the specified offset
* and stores an OnDemandBlock into the datastore.
*
* @return GNUNET_NO if already present, GNUNET_YES on success,
* GNUNET_SYSERR on other error (i.e. datastore full)
*/
int
GNUNET_FS_ONDEMAND_add_indexed_content (struct GNUNET_GE_Context *ectx,
GNUNET_Datastore_ServiceAPI *
datastore, unsigned int prio,
GNUNET_CronTime expiration,
unsigned long long fileOffset,
unsigned int anonymityLevel,
const GNUNET_HashCode * fileId,
unsigned int size,
const GNUNET_EC_DBlock * content)
{
int ret;
OnDemandBlock odb;
GNUNET_HashCode key;
struct stat sbuf;
char *fn;
int fd;
if (size <= sizeof (GNUNET_EC_DBlock))
{
GNUNET_GE_BREAK (coreAPI->ectx, 0);
return GNUNET_SYSERR;
}
fn = get_indexed_filename (fileId);
if ((0 != LSTAT (fn, &sbuf))
#ifdef S_ISLNK
|| (!S_ISLNK (sbuf.st_mode))
#endif
)
{
/* not sym-linked, write content to offset! */
fd = GNUNET_disk_file_open (ectx, fn, O_LARGEFILE | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 644 */
if (fd == -1)
{
GNUNET_free (fn);
return GNUNET_SYSERR;
}
LSEEK (fd, fileOffset, SEEK_SET);
ret = WRITE (fd, &content[1], size - sizeof (GNUNET_EC_DBlock));
if (ret == size - sizeof (GNUNET_EC_DBlock))
{
ret = GNUNET_OK;
}
else
{
GNUNET_GE_LOG_STRERROR_FILE (ectx,
GNUNET_GE_ERROR | GNUNET_GE_ADMIN |
GNUNET_GE_USER | GNUNET_GE_BULK,
"write", fn);
ret = GNUNET_SYSERR;
}
CLOSE (fd);
if (ret == GNUNET_SYSERR)
{
GNUNET_free (fn);
return GNUNET_SYSERR;
}
}
GNUNET_free (fn);
odb.header.size = htonl (sizeof (OnDemandBlock));
odb.header.type = htonl (GNUNET_ECRS_BLOCKTYPE_ONDEMAND);
odb.header.priority = htonl (prio);
odb.header.anonymity_level = htonl (anonymityLevel);
odb.header.expiration_time = GNUNET_htonll (expiration);
odb.type = htonl (GNUNET_ECRS_BLOCKTYPE_ONDEMAND);
odb.fileOffset = GNUNET_htonll (fileOffset);
odb.blockSize = htonl (size - sizeof (GNUNET_EC_DBlock));
odb.fileId = *fileId;
/* compute the primary key */
GNUNET_EC_file_block_get_query (content, size, &key);
#if EXTRA_CHECKS
{
GNUNET_DatastoreValue *dsvalue;
if (GNUNET_OK !=
GNUNET_EC_file_block_encode (content, size, &key, &dsvalue))
{
GNUNET_GE_BREAK (ectx, 0);
GNUNET_GE_BREAK (coreAPI->ectx, 0);
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -