Skip to content
Snippets Groups Projects
tools.c 4.69 KiB
#include "tools.h"
#include "header.h"
#include "io.h"

#include "particle.h"

#include <stdio.h>

int tools_get_next_chunk(const struct header *h, void *map, size_t *offset,
                         int fd) {
  if (h->forward_offset)
    return _tools_get_next_chunk_forward(h, map, offset);
  else
    return _tools_get_next_chunk_backward(h, map, offset, fd);
}

int _tools_get_next_chunk_forward(const struct header *h, void *map,
                                  size_t *offset) {
  size_t diff_offset = 0;

  /* read offset */
  int test = io_read_mask(h, map, offset, NULL, &diff_offset);
  if (test != 0) return test;

  if (diff_offset == 0) return -1;

  /* set absolute offset */
  *offset += diff_offset - LOGGER_MASK_SIZE - LOGGER_OFFSET_SIZE;
  return 0;
}

int _tools_get_next_chunk_backward(const struct header *h, void *map,
                                   size_t *offset, int fd) {
#ifndef SWIFT_DEBUG_CHECKS
  error(ENOTSUP, "Should not be used, method too slow");
#endif
  size_t current_offset = *offset;
  size_t chunk_header = LOGGER_MASK_SIZE + LOGGER_OFFSET_SIZE;

  size_t file_size = 0;
  int test = io_get_file_size(fd, &file_size);

  if (test != 0) return test;

  while (current_offset < file_size) {
    size_t mask = 0;
    size_t prev_offset;
    int test = io_read_mask(h, map, &current_offset, &mask, &prev_offset);
    if (test != 0) return test;

    prev_offset = current_offset - prev_offset - chunk_header;
    if (*offset == prev_offset) {
      *offset = current_offset - chunk_header;
      return 0;
    }

    current_offset += header_get_mask_size(h, mask);
  }

  return -1;
}

int tools_reverse_offset(const struct header *h, void *map, size_t *offset) {
  size_t mask = 0;
  size_t prev_offset = 0;
  const size_t cur_offset = *offset;

  /* read mask + offset */
  int error_code = io_read_mask(h, map, offset, &mask, &prev_offset);
  if (error_code != 0) return error_code;

  /* write offset of zero (in case it is the last chunk) */
  const size_t zero = 0;
  *offset -= LOGGER_OFFSET_SIZE;
  error_code = io_write_data(map, LOGGER_OFFSET_SIZE, &zero, offset);
  if (error_code != 0) error(errno, "Unable to write data while reversing");

  /* set offset after current chunk */
  *offset += header_get_mask_size(h, mask);

  /* first chunks do not have a previous partner */
  if (prev_offset == cur_offset) return 0;

  if (prev_offset > cur_offset)
    error(EIO, "Unexpected offset, header %lu, current %lu", prev_offset,
          cur_offset);

  /* modify previous offset */
  size_t abs_prev_offset = cur_offset - prev_offset + LOGGER_MASK_SIZE;
  error_code = io_write_data(map, LOGGER_OFFSET_SIZE, &prev_offset, &abs_prev_offset);
  if (error_code != 0) error(errno, "Unable to write offset");

#ifdef SWIFT_DEBUG_CHECKS
  size_t prev_mask = 0;
  abs_prev_offset -= LOGGER_MASK_SIZE + LOGGER_OFFSET_SIZE;
  error_code = io_read_mask(h, map, &abs_prev_offset, &prev_mask, NULL);

  if (prev_mask != mask)
    error(EIO, "Unexpected mask: %lu (at %lu), got %lu (at %lu)", mask, *offset,
          prev_mask, prev_offset);

#endif  // SWIFT_DEBUG_CHECKS

  return 0;
}

int tools_check_offset(const struct header *h, void *map, size_t *offset) {
#ifndef SWIFT_DEBUG_CHECKS
  error(ENOTSUP, "Should not check in non debug mode");
#endif

  size_t tmp = *offset;

  size_t mask;
  size_t pointed_offset;

  /* read mask + offset */
  int error_code = io_read_mask(h, map, offset, &mask, &pointed_offset);
  if (error_code != 0) return error_code;

  /* get absolute offset */
  if (h->forward_offset)
    pointed_offset += tmp;
  else {
    if (tmp < pointed_offset)
      error(EIO, "Offset too large (%lu) at %lu with mask %lu", pointed_offset,
            tmp, mask);
    pointed_offset = tmp - pointed_offset;
  }

  /* set offset after current chunk */
  *offset += header_get_mask_size(h, mask);

  if (pointed_offset == tmp || pointed_offset == 0) return 0;

  /* read mask of the pointed chunk */
  size_t pointed_mask = 0;
  error_code = io_read_mask(h, map, &pointed_offset, &pointed_mask, NULL);

  /* check masks */
  if (pointed_mask != mask)
    error(EIO, "Error in the offset (mask %lu != %lu) at %lu and %lu", mask,
          pointed_mask,
          *offset - header_get_mask_size(h, mask) - LOGGER_MASK_SIZE - LOGGER_OFFSET_SIZE,
          pointed_offset - LOGGER_MASK_SIZE - LOGGER_OFFSET_SIZE);

  if (pointed_mask == 128) return 0;

  struct particle part;
  error_code = particle_read(&part, h, map, &tmp, 0, reader_const, NULL);

  size_t id = part.id;
  tmp = pointed_offset - LOGGER_MASK_SIZE - LOGGER_OFFSET_SIZE;
  error_code = particle_read(&part, h, map, &tmp, 0, reader_const, NULL);

  if (id != part.id)
    error(EIO, "Offset wrong, id incorrect (%lu != %lu) at %lu", id, part.id,
          tmp);

  return 0;
}