⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ondemand.c

📁 GNUnet是一个安全的点对点网络框架
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
     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 + -