예제 #1
0
파일: service.c 프로젝트: tg-x/gnunet
/**
 * Write PID file.
 *
 * @param sctx service context
 * @param pid PID to write (should be equal to 'getpid()'
 * @return  #GNUNET_OK on success (including no work to be done)
 */
static int
write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
{
  FILE *pidfd;
  char *pif;
  char *user;
  char *rdir;
  int len;

  if (NULL == (pif = get_pid_file_name (sctx)))
    return GNUNET_OK;           /* no file desired */
  user = get_user_name (sctx);
  rdir = GNUNET_strdup (pif);
  len = strlen (rdir);
  while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
    len--;
  rdir[len] = '\0';
  if (0 != ACCESS (rdir, F_OK))
  {
    /* we get to create a directory -- and claim it
     * as ours! */
    (void) GNUNET_DISK_directory_create (rdir);
    if ((NULL != user) && (0 < strlen (user)))
      GNUNET_DISK_file_change_owner (rdir, user);
  }
  if (0 != ACCESS (rdir, W_OK | X_OK))
  {
    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
    GNUNET_free (rdir);
    GNUNET_free_non_null (user);
    GNUNET_free (pif);
    return GNUNET_SYSERR;
  }
  GNUNET_free (rdir);
  pidfd = FOPEN (pif, "w");
  if (NULL == pidfd)
  {
    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
    GNUNET_free (pif);
    GNUNET_free_non_null (user);
    return GNUNET_SYSERR;
  }
  if (0 > FPRINTF (pidfd, "%u", pid))
    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
  GNUNET_break (0 == FCLOSE (pidfd));
  if ((NULL != user) && (0 < strlen (user)))
    GNUNET_DISK_file_change_owner (pif, user);
  GNUNET_free_non_null (user);
  GNUNET_free (pif);
  return GNUNET_OK;
}
예제 #2
0
/**
 * File hashing task.
 *
 * @param cls closure
 * @param tc context
 */
static void
file_hash_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
    struct GNUNET_CRYPTO_FileHashContext *fhc = cls;
    struct GNUNET_HashCode *res;
    size_t delta;

    fhc->task = GNUNET_SCHEDULER_NO_TASK;
    GNUNET_assert (fhc->offset <= fhc->fsize);
    delta = fhc->bsize;
    if (fhc->fsize - fhc->offset < delta)
        delta = fhc->fsize - fhc->offset;
    if (delta != GNUNET_DISK_file_read (fhc->fh, fhc->buffer, delta))
    {
        LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", fhc->filename);
        file_hash_finish (fhc, NULL);
        return;
    }
    gcry_md_write (fhc->md, fhc->buffer, delta);
    fhc->offset += delta;
    if (fhc->offset == fhc->fsize)
    {
        res = (struct GNUNET_HashCode *) gcry_md_read (fhc->md, GCRY_MD_SHA512);
        file_hash_finish (fhc, res);
        return;
    }
    fhc->task = GNUNET_SCHEDULER_add_with_priority (fhc->priority,
                &file_hash_task, fhc);
}
예제 #3
0
/**
 * Return unique variant of the namespace name.
 * Use it after GNUNET_PSEUDONYM_get_info() to make sure
 * that name is unique.
 *
 * @param cfg configuration
 * @param nsid cryptographic ID of the namespace
 * @param name name to uniquify
 * @param suffix if not NULL, filled with the suffix value
 * @return NULL on failure (should never happen), name on success.
 *         Free the name with GNUNET_free().
 */
char *
GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg,
    const struct GNUNET_HashCode * nsid, const char *name, unsigned int *suffix)
{
  struct GNUNET_HashCode nh;
  uint64_t len;
  char *fn;
  struct GNUNET_DISK_FileHandle *fh;
  unsigned int i;
  unsigned int idx;
  char *ret;
  struct stat sbuf;

  GNUNET_CRYPTO_hash (name, strlen (name), &nh);
  fn = get_data_filename (cfg, PS_NAMES_DIR, &nh);
  GNUNET_assert (fn != NULL);

  len = 0;
  if (0 == STAT (fn, &sbuf))
    GNUNET_break (GNUNET_OK == GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES));
  fh = GNUNET_DISK_file_open (fn,
                              GNUNET_DISK_OPEN_CREATE |
                              GNUNET_DISK_OPEN_READWRITE,
                              GNUNET_DISK_PERM_USER_READ |
                              GNUNET_DISK_PERM_USER_WRITE);
  i = 0;
  idx = -1;
  while ((len >= sizeof (struct GNUNET_HashCode)) &&
         (sizeof (struct GNUNET_HashCode) ==
          GNUNET_DISK_file_read (fh, &nh, sizeof (struct GNUNET_HashCode))))
  {
    if (0 == memcmp (&nh, nsid, sizeof (struct GNUNET_HashCode)))
    {
      idx = i;
      break;
    }
    i++;
    len -= sizeof (struct GNUNET_HashCode);
  }
  if (idx == -1)
  {
    idx = i;
    if (sizeof (struct GNUNET_HashCode) !=
        GNUNET_DISK_file_write (fh, nsid, sizeof (struct GNUNET_HashCode)))
      LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "write", fn);
  }
  GNUNET_DISK_file_close (fh);
  ret = GNUNET_malloc (strlen (name) + 32);
  GNUNET_snprintf (ret, strlen (name) + 32, "%s-%u", name, idx);
  if (suffix != NULL)
    *suffix = idx;
  GNUNET_free (fn);
  return ret;
}
예제 #4
0
파일: service.c 프로젝트: tg-x/gnunet
/**
 * Delete the PID file that was created by our parent.
 *
 * @param sctx service context
 */
static void
pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
{
  char *pif = get_pid_file_name (sctx);

  if (NULL == pif)
    return;                     /* no PID file */
  if (0 != UNLINK (pif))
    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
  GNUNET_free (pif);
}
예제 #5
0
/**
 * Create a new private key by reading it from a file.  If the
 * files does not exist, create a new key and write it to the
 * file.  Caller must free return value.  Note that this function
 * can not guarantee that another process might not be trying
 * the same operation on the same file at the same time.
 * If the contents of the file
 * are invalid the old file is deleted and a fresh key is
 * created.
 *
 * @param filename name of file to use to store the key
 * @return new private key, NULL on error (for example,
 *   permission denied)
 */
struct GNUNET_CRYPTO_EddsaPrivateKey *
GNUNET_CRYPTO_eddsa_key_create_from_file (const char *filename)
{
  struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
  struct GNUNET_DISK_FileHandle *fd;
  unsigned int cnt;
  int ec;
  uint64_t fs;

  if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
    return NULL;
  while (GNUNET_YES != GNUNET_DISK_file_test (filename))
  {
    fd = GNUNET_DISK_file_open (filename,
                                GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
                                | GNUNET_DISK_OPEN_FAILIFEXISTS,
                                GNUNET_DISK_PERM_USER_READ |
                                GNUNET_DISK_PERM_USER_WRITE);
    if (NULL == fd)
    {
      if (EEXIST == errno)
      {
        if (GNUNET_YES != GNUNET_DISK_file_test (filename))
        {
          /* must exist but not be accessible, fail for good! */
          if (0 != ACCESS (filename, R_OK))
            LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
          else
            GNUNET_break (0);   /* what is going on!? */
          return NULL;
        }
        continue;
      }
      LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
      return NULL;
    }
    cnt = 0;
    while (GNUNET_YES !=
           GNUNET_DISK_file_lock (fd, 0,
                                  sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
                                  GNUNET_YES))
    {
      short_wait ();
      if (0 == ++cnt % 10)
      {
        ec = errno;
        LOG (GNUNET_ERROR_TYPE_ERROR,
             _("Could not acquire lock on file `%s': %s...\n"), filename,
             STRERROR (ec));
      }
    }
    LOG (GNUNET_ERROR_TYPE_INFO,
         _("Creating a new private key.  This may take a while.\n"));
    priv = GNUNET_CRYPTO_eddsa_key_create ();
    GNUNET_assert (NULL != priv);
    GNUNET_assert (sizeof (*priv) ==
                   GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
    GNUNET_DISK_file_sync (fd);
    if (GNUNET_YES !=
        GNUNET_DISK_file_unlock (fd, 0,
                                 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
      LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
    GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
    return priv;
  }
  /* key file exists already, read it! */
  fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
                              GNUNET_DISK_PERM_NONE);
  if (NULL == fd)
  {
    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
    return NULL;
  }
  cnt = 0;
  while (1)
  {
    if (GNUNET_YES !=
        GNUNET_DISK_file_lock (fd, 0,
                               sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
                               GNUNET_NO))
    {
      if (0 == ++cnt % 60)
      {
        ec = errno;
        LOG (GNUNET_ERROR_TYPE_ERROR,
             _("Could not acquire lock on file `%s': %s...\n"), filename,
             STRERROR (ec));
        LOG (GNUNET_ERROR_TYPE_ERROR,
             _
             ("This may be ok if someone is currently generating a private key.\n"));
      }
      short_wait ();
      continue;
    }
    if (GNUNET_YES != GNUNET_DISK_file_test (filename))
    {
      /* eh, what!? File we opened is now gone!? */
      LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
      if (GNUNET_YES !=
          GNUNET_DISK_file_unlock (fd, 0,
                                   sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
        LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
      GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));

      return NULL;
    }
    if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
      fs = 0;
    if (fs < sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey))
    {
      /* maybe we got the read lock before the key generating
       * process had a chance to get the write lock; give it up! */
      if (GNUNET_YES !=
          GNUNET_DISK_file_unlock (fd, 0,
                                   sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
        LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
      if (0 == ++cnt % 10)
      {
        LOG (GNUNET_ERROR_TYPE_ERROR,
             _("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
             filename, (unsigned int) fs,
             (unsigned int) sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
        LOG (GNUNET_ERROR_TYPE_ERROR,
             _("This may be ok if someone is currently generating a key.\n"));
      }
      short_wait ();                /* wait a bit longer! */
      continue;
    }
    break;
  }
  fs = sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey);
  priv = GNUNET_malloc (fs);
  GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
  if (GNUNET_YES !=
      GNUNET_DISK_file_unlock (fd, 0,
                               sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
  GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
  return priv;
}
/**
 * Load a bloom-filter from a file.
 *
 * @param filename the name of the file (or the prefix)
 * @param size the size of the bloom-filter (number of
 *        bytes of storage space to use); will be rounded up
 *        to next power of 2
 * @param k the number of GNUNET_CRYPTO_hash-functions to apply per
 *        element (number of bits set per element in the set)
 * @return the bloomfilter
 */
struct GNUNET_CONTAINER_BloomFilter *
GNUNET_CONTAINER_bloomfilter_load (const char *filename, size_t size,
                                   unsigned int k)
{
  struct GNUNET_CONTAINER_BloomFilter *bf;
  char *rbuff;
  OFF_T pos;
  int i;
  size_t ui;
  OFF_T fsize;
  int must_read;

  GNUNET_assert (NULL != filename);
  if ((k == 0) || (size == 0))
    return NULL;
  if (size < BUFFSIZE)
    size = BUFFSIZE;
  ui = 1;
  while ( (ui < size) &&
	  (ui * 2 > ui) )
    ui *= 2;
  size = ui;                    /* make sure it's a power of 2 */

  bf = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_BloomFilter));
  /* Try to open a bloomfilter file */
  if (GNUNET_YES == GNUNET_DISK_file_test (filename))
    bf->fh =
      GNUNET_DISK_file_open (filename,
                             GNUNET_DISK_OPEN_READWRITE,
                             GNUNET_DISK_PERM_USER_READ |
                             GNUNET_DISK_PERM_USER_WRITE);
  if (NULL != bf->fh)
  {
    /* file existed, try to read it! */
    must_read = GNUNET_YES;
    if (GNUNET_OK !=
	GNUNET_DISK_file_handle_size (bf->fh, &fsize))
    {
      GNUNET_DISK_file_close (bf->fh);
      GNUNET_free (bf);
      return NULL;
    }
    if (fsize == 0)
    {
      /* found existing empty file, just overwrite */
      if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL))
      {
	GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
			     "write");
	GNUNET_DISK_file_close (bf->fh);
	GNUNET_free (bf);
	return NULL;
      }
    }
    else if (fsize != size * 4LL)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
		  _("Size of file on disk is incorrect for this Bloom filter (want %llu, have %llu)\n"),
		  (unsigned long long) (size * 4LL),
		  (unsigned long long) fsize);
      GNUNET_DISK_file_close (bf->fh);
      GNUNET_free (bf);
      return NULL;
    }
  }
  else
  {
    /* file did not exist, don't read, just create */
    must_read = GNUNET_NO;
    bf->fh =
      GNUNET_DISK_file_open (filename,
                             GNUNET_DISK_OPEN_CREATE |
                             GNUNET_DISK_OPEN_READWRITE,
                             GNUNET_DISK_PERM_USER_READ |
                             GNUNET_DISK_PERM_USER_WRITE);
    if (NULL == bf->fh)
      {
	GNUNET_free (bf);
	return NULL;
      }
    if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL))
    {
      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
			   "write");
      GNUNET_DISK_file_close (bf->fh);
      GNUNET_free (bf);
      return NULL;
    }
  }
  bf->filename = GNUNET_strdup (filename);
  /* Alloc block */
  bf->bitArray = GNUNET_malloc_large (size);
  if (bf->bitArray == NULL)
  {
    if (bf->fh != NULL)
      GNUNET_DISK_file_close (bf->fh);
    GNUNET_free (bf->filename);
    GNUNET_free (bf);
    return NULL;
  }
  bf->bitArraySize = size;
  bf->addressesPerElement = k;
  if (GNUNET_YES != must_read)      
    return bf; /* already done! */  
  /* Read from the file what bits we can */
  rbuff = GNUNET_malloc (BUFFSIZE);
  pos = 0;
  while (pos < size * 8LL)
  {
    int res;

    res = GNUNET_DISK_file_read (bf->fh, rbuff, BUFFSIZE);
    if (res == -1)
    {
      LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", bf->filename);
      GNUNET_free (rbuff);
      GNUNET_free (bf->filename);
      GNUNET_DISK_file_close (bf->fh);
      GNUNET_free (bf);
      return NULL;
    }
    if (res == 0)
      break;                    /* is ok! we just did not use that many bits yet */
    for (i = 0; i < res; i++)
    {
      if ((rbuff[i] & 0x0F) != 0)
        setBit (bf->bitArray, pos + i * 2);
      if ((rbuff[i] & 0xF0) != 0)
        setBit (bf->bitArray, pos + i * 2 + 1);
    }
    if (res < BUFFSIZE)
      break;
    pos += BUFFSIZE * 2;        /* 2 bits per byte in the buffer */
  }
  GNUNET_free (rbuff);
  return bf;
}