summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2023-03-15 20:08:53 +0100
committerVivien Kraus <vivien@planete-kraus.eu>2023-03-15 20:56:35 +0100
commit13feab587ff754ed0a9e3e93639ecd5c43f3ec40 (patch)
tree3ffa0bf4bbb14cdc8b93b2edb6d53edffee1d888
parent9bbdb37e12021eca17d84107449e367a999bd658 (diff)
Rework the cache entry file API.
A cache entry does not hold a reference to a file descriptor anymore. They are loaded in memory, and can be updated with a system of backups.
-rw-r--r--bootstrap.conf3
-rw-r--r--include/disfluid.h27
-rw-r--r--src/adwaita/disfluid-adwaita.h3
-rw-r--r--src/adwaita/disfluid-cache-entry.c52
-rw-r--r--src/adwaita/disfluid-window.c2
-rw-r--r--src/libdisfluid/disfluid-cache-entry.h688
-rw-r--r--src/libdisfluid/disfluid-tests.h514
-rw-r--r--src/libdisfluid/main.c42
-rw-r--r--tests/run-unit-tests.c1
9 files changed, 692 insertions, 640 deletions
diff --git a/bootstrap.conf b/bootstrap.conf
index 4b8a2e6..8de9c9d 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -23,10 +23,12 @@ assert
assert-h
attribute
close
+copy-file-range
do-release-commit-and-tag
errno
fclose
free-posix
+ftruncate
gettext-h
git-version-gen
gitlog-to-changelog
@@ -42,6 +44,7 @@ realloc-gnu
relocatable-lib-lgpl
remove
stdbool
+stdint
stdio
strdup
sys_stat
diff --git a/include/disfluid.h b/include/disfluid.h
index 8c52922..51f096a 100644
--- a/include/disfluid.h
+++ b/include/disfluid.h
@@ -136,14 +136,6 @@ extern "C"
LIBDISFLUID_API LIBDISFLUID_DEALLOC_AS_CACHE_ENTRY
extern struct disfluid_cache_entry
- *disfluid_cache_entry_from_file_name (const char *filename);
-
- LIBDISFLUID_API LIBDISFLUID_DEALLOC_AS_CACHE_ENTRY
- LIBDISFLUID_FD_ARG_READ_1 extern struct disfluid_cache_entry
- *disfluid_cache_entry_from_fd (int fd);
-
- LIBDISFLUID_API LIBDISFLUID_DEALLOC_AS_CACHE_ENTRY
- extern struct disfluid_cache_entry
*disfluid_cache_entry_dup (const struct disfluid_cache_entry *entry);
LIBDISFLUID_API extern void
@@ -164,9 +156,9 @@ extern "C"
disfluid_cache_entry_set_invalidated (struct disfluid_cache_entry *entry,
int invalidated);
- LIBDISFLUID_API extern void
- disfluid_cache_entry_set_file_name (struct disfluid_cache_entry *entry,
- const char *filename);
+ LIBDISFLUID_API extern int
+ disfluid_cache_entry_load (struct disfluid_cache_entry *entry,
+ const char *filename);
LIBDISFLUID_API extern void
disfluid_cache_entry_get_request_date (const struct disfluid_cache_entry
@@ -180,18 +172,9 @@ extern "C"
disfluid_cache_entry_invalidated (const struct disfluid_cache_entry
*entry);
- LIBDISFLUID_API LIBDISFLUID_DEALLOC_WITH_FREE extern char
- *disfluid_cache_entry_get_file_name (const struct disfluid_cache_entry
- *entry);
-
LIBDISFLUID_API extern int
- disfluid_cache_entry_save_other_file_name (const struct
- disfluid_cache_entry *entry,
- const char *filename);
-
- LIBDISFLUID_API LIBDISFLUID_FD_ARG_WRITE_2 extern int
- disfluid_cache_entry_save_other_fd (const struct disfluid_cache_entry
- *entry, int fd);
+ disfluid_cache_entry_save (const struct disfluid_cache_entry *entry,
+ const char *filename);
# ifdef __cplusplus
}
diff --git a/src/adwaita/disfluid-adwaita.h b/src/adwaita/disfluid-adwaita.h
index e589c75..9ed0304 100644
--- a/src/adwaita/disfluid-adwaita.h
+++ b/src/adwaita/disfluid-adwaita.h
@@ -53,6 +53,9 @@ GMenuItem *disfluid_adw_menu_item_about (void);
GMenu *disfluid_adw_main_menu (void);
+void disfluid_adw_cache_entry_set_file_name (DisfluidAdwCacheEntry *
+ cache_entry, const char *fname);
+
void disfluid_adw_cache_entry_set_cache_entry (DisfluidAdwCacheEntry *
cache_entry,
struct disfluid_cache_entry
diff --git a/src/adwaita/disfluid-cache-entry.c b/src/adwaita/disfluid-cache-entry.c
index 060fb96..d1da6b0 100644
--- a/src/adwaita/disfluid-cache-entry.c
+++ b/src/adwaita/disfluid-cache-entry.c
@@ -24,6 +24,7 @@
struct _DisfluidAdwCacheEntry
{
AdwPreferencesGroup parent_instance;
+ char *file_name;
struct disfluid_cache_entry *cache_entry;
GtkLabel *row_request_date;
GtkLabel *row_response_date;
@@ -43,7 +44,8 @@ G_DEFINE_TYPE (DisfluidAdwCacheEntry,
typedef enum
{
- PROP_CACHE_ENTRY = 1,
+ PROP_FILE_NAME = 1,
+ PROP_CACHE_ENTRY = 2,
/* ... */
N_PROPERTIES
@@ -60,6 +62,11 @@ disfluid_adw_cache_entry_set_property (GObject * object,
DisfluidAdwCacheEntry *self = DISFLUID_ADW_CACHE_ENTRY (object);
switch ((DisfluidAdwCacheEntryProperty) property_id)
{
+ case PROP_FILE_NAME:
+ disfluid_adw_cache_entry_set_file_name (self,
+ g_value_get_string (value));
+ break;
+
case PROP_CACHE_ENTRY:
assert (G_VALUE_TYPE (value) == DISFLUID_TYPE_CACHE_ENTRY);
disfluid_adw_cache_entry_set_cache_entry (self,
@@ -80,6 +87,9 @@ disfluid_adw_cache_entry_get_property (GObject * object,
DisfluidAdwCacheEntry *self = DISFLUID_ADW_CACHE_ENTRY (object);
switch ((DisfluidAdwCacheEntryProperty) property_id)
{
+ case PROP_FILE_NAME:
+ g_value_set_string (value, self->file_name);
+ break;
case PROP_CACHE_ENTRY:
if (self->cache_entry != NULL)
{
@@ -101,6 +111,7 @@ static void
disfluid_adw_cache_entry_finalize (GObject * obj)
{
DisfluidAdwCacheEntry *self = DISFLUID_ADW_CACHE_ENTRY (obj);
+ free (self->file_name);
disfluid_cache_entry_free (self->cache_entry);
G_OBJECT_CLASS (disfluid_adw_cache_entry_parent_class)->finalize (obj);
}
@@ -112,6 +123,9 @@ disfluid_adw_cache_entry_class_init (DisfluidAdwCacheEntryClass * klass)
object_class->set_property = disfluid_adw_cache_entry_set_property;
object_class->get_property = disfluid_adw_cache_entry_get_property;
object_class->finalize = disfluid_adw_cache_entry_finalize;
+ obj_properties[PROP_FILE_NAME] =
+ g_param_spec_string ("file-name", _("File name"), _("Name of the file \
+of this cache entry"), NULL, G_PARAM_READWRITE);
obj_properties[PROP_CACHE_ENTRY] =
g_param_spec_boxed ("cache-entry",
_("Cache entry"), _("Value of the cache entry \
@@ -124,6 +138,7 @@ static void
disfluid_adw_cache_entry_init (DisfluidAdwCacheEntry * self)
{
/* Perform default initialization of self. */
+ self->file_name = NULL;
self->cache_entry = NULL;
self->row_request_date = GTK_LABEL (gtk_label_new (_("Unset")));
self->row_response_date = GTK_LABEL (gtk_label_new (_("Unset")));
@@ -171,6 +186,28 @@ disfluid_adw_cache_entry_init (DisfluidAdwCacheEntry * self)
}
void
+disfluid_adw_cache_entry_set_file_name (DisfluidAdwCacheEntry * self,
+ const char *fname)
+{
+ free (self->file_name);
+ self->file_name = NULL;
+ if (fname)
+ {
+ self->file_name = g_strdup (fname);
+ }
+ if (self->file_name == NULL)
+ {
+ adw_preferences_group_set_title (ADW_PREFERENCES_GROUP (self),
+ _("Unknown cache entry"));
+ }
+ else
+ {
+ adw_preferences_group_set_title (ADW_PREFERENCES_GROUP (self),
+ self->file_name);
+ }
+}
+
+void
disfluid_adw_cache_entry_set_cache_entry (DisfluidAdwCacheEntry * self,
struct disfluid_cache_entry *value)
{
@@ -235,19 +272,6 @@ disfluid_adw_cache_entry_set_cache_entry (DisfluidAdwCacheEntry * self,
gtk_label_set_label (self->row_response_date, response_title);
gtk_label_set_label (self->row_invalidation_status,
invalidation_status_title);
- char *file_name =
- disfluid_cache_entry_get_file_name (self->cache_entry);
- if (file_name == NULL)
- {
- adw_preferences_group_set_title (ADW_PREFERENCES_GROUP (self),
- _("Unknown cache entry"));
- }
- else
- {
- adw_preferences_group_set_title (ADW_PREFERENCES_GROUP (self),
- file_name);
- }
- free (file_name);
g_free (request_title);
g_free (response_title);
g_free (invalidation_status_title);
diff --git a/src/adwaita/disfluid-window.c b/src/adwaita/disfluid-window.c
index bb8d592..8f9d87f 100644
--- a/src/adwaita/disfluid-window.c
+++ b/src/adwaita/disfluid-window.c
@@ -58,8 +58,6 @@ disfluid_adw_window_init (DisfluidAdwWindow * self)
{
abort ();
}
- disfluid_cache_entry_set_file_name (cache_entry,
- "/tmp/test.disfluid-cache-entry");
GtkWidget *unique_content =
g_object_new (DISFLUID_ADW_TYPE_CACHE_ENTRY, NULL);
disfluid_adw_cache_entry_set_cache_entry (DISFLUID_ADW_CACHE_ENTRY
diff --git a/src/libdisfluid/disfluid-cache-entry.h b/src/libdisfluid/disfluid-cache-entry.h
index 272c9e8..ae91390 100644
--- a/src/libdisfluid/disfluid-cache-entry.h
+++ b/src/libdisfluid/disfluid-cache-entry.h
@@ -7,20 +7,8 @@ MAYBE_UNUSED static void
cache_entry_free (struct disfluid_cache_entry *entry);
MAYBE_UNUSED static struct disfluid_cache_entry
- *cache_entry_from_file_name (const char *file_name);
-
-MAYBE_UNUSED static struct disfluid_cache_entry *cache_entry_from_fd (int fd);
-
-MAYBE_UNUSED static struct disfluid_cache_entry
*cache_entry_dup (const struct disfluid_cache_entry *entry);
-MAYBE_UNUSED static int
-cache_entry_save_other_file_name (const struct disfluid_cache_entry *entry,
- const char *file_name);
-
-MAYBE_UNUSED static int
-cache_entry_save_other_fd (const struct disfluid_cache_entry *entry, int fd);
-
MAYBE_UNUSED static void
cache_entry_set_request_date (struct disfluid_cache_entry *entry,
const struct timespec *date);
@@ -36,9 +24,8 @@ MAYBE_UNUSED static void
cache_entry_set_invalidated (struct disfluid_cache_entry *entry,
bool invalidated);
-MAYBE_UNUSED static void
-cache_entry_set_file_name (struct disfluid_cache_entry *entry,
- const char *file_name);
+MAYBE_UNUSED static int
+cache_entry_load (struct disfluid_cache_entry *entry, const char *filename);
MAYBE_UNUSED static void
cache_entry_get_request_date (const struct disfluid_cache_entry *entry,
@@ -51,9 +38,9 @@ cache_entry_get_response_date (const struct disfluid_cache_entry *entry,
MAYBE_UNUSED static bool
cache_entry_invalidated (const struct disfluid_cache_entry *entry);
-MAYBE_UNUSED static char *cache_entry_get_file_name (const struct
- disfluid_cache_entry
- *entry);
+MAYBE_UNUSED static int
+cache_entry_save (const struct disfluid_cache_entry *entry,
+ const char *filename);
# include <assert.h>
@@ -61,10 +48,6 @@ MAYBE_UNUSED static char *cache_entry_get_file_name (const struct
struct disfluid_cache_entry
{
- char *file_name; /* Might be NULL */
- int fd; /* Might be < 0, but must be >= 0 if there is a file_name. */
- off_t start;
- off_t header_stop;
struct timespec request_date;
struct timespec response_date;
bool invalidated;
@@ -80,10 +63,6 @@ cache_entry_alloc (void)
{
abort ();
}
- ret->file_name = NULL;
- ret->fd = -1;
- ret->start = 0;
- ret->header_stop = 0;
ret->request_date.tv_sec = 0;
ret->request_date.tv_nsec = 0;
ret->response_date.tv_sec = 0;
@@ -95,60 +74,15 @@ cache_entry_alloc (void)
static void
cache_entry_free (struct disfluid_cache_entry *entry)
{
- if (entry != NULL)
- {
- free (entry->file_name);
- if (entry->fd >= 0)
- {
- close (entry->fd);
- }
- }
free (entry);
}
static struct disfluid_cache_entry *
-cache_entry_from_file_name (const char *file_name)
-{
- int fd = open (file_name, O_RDONLY, S_IRUSR);
- if (fd < 0)
- {
- abort ();
- }
- struct disfluid_cache_entry *ret = cache_entry_from_fd (fd);
- if (ret == NULL)
- {
- abort ();
- }
- cache_entry_set_file_name (ret, file_name);
- return ret;
-}
-
-static struct disfluid_cache_entry *
cache_entry_dup (const struct disfluid_cache_entry *entry)
{
struct disfluid_cache_entry *ret = cache_entry_alloc ();
- if (ret != NULL && entry->fd >= 0)
- {
- ret->fd = dup (entry->fd);
- if (ret->fd < 0)
- {
- cache_entry_free (ret);
- ret = NULL;
- }
- }
- if (ret != NULL && entry->file_name != NULL)
- {
- ret->file_name = strdup (entry->file_name);
- if ((ret->file_name == NULL) != (entry->file_name == NULL))
- {
- cache_entry_free (ret);
- ret = NULL;
- }
- }
if (ret != NULL)
{
- ret->start = entry->start;
- ret->header_stop = entry->header_stop;
ret->request_date.tv_sec = entry->request_date.tv_sec;
ret->request_date.tv_nsec = entry->request_date.tv_nsec;
ret->response_date.tv_sec = entry->response_date.tv_sec;
@@ -158,391 +92,203 @@ cache_entry_dup (const struct disfluid_cache_entry *entry)
return ret;
}
-static inline void
-cache_entry_string_append (char **str, size_t *max, size_t *n,
- size_t suffix_length, const char *suffix)
+static void
+cache_entry_set_request_date (struct disfluid_cache_entry *entry,
+ const struct timespec *date)
{
- if (*n + suffix_length > *max)
- {
- *str = realloc (*str, 2 * *max);
- if (*str == NULL)
- {
- abort ();
- }
- *max *= 2;
- cache_entry_string_append (str, max, n, suffix_length, suffix);
- }
- else
- {
- memcpy (&((*str)[*n]), suffix, suffix_length);
- *n += suffix_length;
- }
+ entry->request_date.tv_sec = date->tv_sec;
+ entry->request_date.tv_nsec = date->tv_nsec;
}
-static inline ssize_t
-cache_entry_read_next_line_aux (int fd, size_t *restrict buffer_max,
- size_t *restrict buffer_length, char **buffer,
- size_t checked)
+static void
+cache_entry_set_response_date (struct disfluid_cache_entry *entry,
+ const struct timespec *date)
{
- while (checked + 1 < *buffer_length
- && ((*buffer)[checked] != '\r' || (*buffer)[checked + 1] != '\n'))
- {
- checked++;
- }
- if (checked + 1 < *buffer_length)
- {
- return checked + 2;
- }
- if (*buffer_length == *buffer_max)
- {
- *buffer = realloc (*buffer, 2 * *buffer_max);
- if (*buffer == NULL)
- {
- abort ();
- }
- *buffer_max *= 2;
- }
- assert (*buffer_max > *buffer_length);
- ssize_t n_added =
- read (fd, &((*buffer)[*buffer_length]), *buffer_max - *buffer_length);
- if (n_added < 0)
- {
- abort ();
- }
- else if (n_added == 0)
- {
- return *buffer_length;
- }
- else
- {
- assert (*buffer_length + n_added <= *buffer_max);
- *buffer_length += n_added;
- }
- return cache_entry_read_next_line_aux (fd, buffer_max, buffer_length,
- buffer, checked);
+ entry->response_date.tv_sec = date->tv_sec;
+ entry->response_date.tv_nsec = date->tv_nsec;
}
-static inline void
-cache_entry_read_next_line (int fd, size_t *restrict buffer_max,
- size_t *restrict buffer_length, char **buffer,
- char **line, size_t *line_length)
+static void
+cache_entry_invalidate (struct disfluid_cache_entry *entry)
{
- ssize_t length =
- cache_entry_read_next_line_aux (fd, buffer_max, buffer_length, buffer, 0);
- if (length < 0)
- {
- abort ();
- }
- *line = malloc (length + 1);
- if (*line == NULL)
- {
- abort ();
- }
- *line_length = length;
- memcpy (*line, *buffer, length);
- (*line)[length] = '\0';
- memmove (*buffer, &((*buffer)[length]), *buffer_length - length);
- *buffer_length -= length;
+ entry->invalidated = true;
}
-static inline void
-cache_entry_enumerate_header_lines (const struct disfluid_cache_entry *entry,
- void (*cb) (void *, const char *,
- const char *), void *context)
+static void
+cache_entry_set_invalidated (struct disfluid_cache_entry *entry,
+ bool invalidated)
{
- off_t start_offset = lseek (entry->fd, 0, SEEK_CUR);
- if (start_offset < 0)
- {
- abort ();
- }
- size_t buffer_max = 1;
- size_t buffer_length = 0;
- char *buffer = malloc (buffer_max);
- if (buffer == NULL)
- {
- abort ();
- }
- char *line;
- size_t line_length;
- while (true)
- {
- cache_entry_read_next_line (entry->fd, &buffer_max, &buffer_length,
- &buffer, &line, &line_length);
- if (line == NULL)
- {
- /* Memory error */
- abort ();
- }
- if (STREQ (line, "\r\n"))
- {
- /* End of parse */
- ssize_t undo = buffer_length;
- lseek (entry->fd, -undo, SEEK_CUR);
- free (buffer);
- free (line);
- return;
- }
- char *header_name = malloc (line_length + 1);
- if (header_name == NULL)
- {
- abort ();
- }
- size_t header_name_length = 0;
- for (header_name_length = 0;
- header_name_length < line_length
- && line[header_name_length] != ':'; header_name_length++)
- {
- if (line[header_name_length] >= 'A'
- && line[header_name_length] <= 'Z')
- {
- line[header_name_length] =
- (line[header_name_length] - 'A') + 'a';
- }
- header_name[header_name_length] = line[header_name_length];
- }
- header_name[header_name_length] = '\0';
- if (line[header_name_length] != ':')
- {
- /* HTTP bad header, restore position */
- lseek (entry->fd, start_offset, SEEK_SET);
- free (buffer);
- free (line);
- free (header_name);
- return;
- }
- header_name_length++;
- cb (context, header_name, &(line[header_name_length]));
- free (line);
- free (header_name);
- }
+ entry->invalidated = invalidated;
}
-static inline void
-cache_entry_parse_timespec (const char *data, struct timespec *ts)
-{
- /* A timespec is represented as SSS.NNN where SSS is the number of seconds, and NNN the number of nanoseconds. */
- while (*data == ' ' || *data == '\t' || *data == '\r' || *data == '\n')
- {
- data++;
- }
- struct timespec r = {.tv_sec = 0,.tv_nsec = 0 };
- size_t n_seconds_digits = 0;
- for (n_seconds_digits = 0;
- data[n_seconds_digits] >= '0' && data[n_seconds_digits] <= '9';
- n_seconds_digits++)
- {
- r.tv_sec *= 10;
- r.tv_sec += (data[n_seconds_digits] - '0');
- }
- data += n_seconds_digits;
- const bool has_dot = (data[0] == '.');
- if (has_dot)
- {
- data++;
- }
- int nano_digits[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- for (size_t i = 0; i < 9 && data[i] >= '0' && data[i] <= '9'; i++)
- {
- nano_digits[i] = (data[i] - '0');
- }
- for (size_t i = 0; i < 9; i++)
- {
- r.tv_nsec *= 10;
- r.tv_nsec += nano_digits[i];
- }
- ts->tv_sec = r.tv_sec;
- ts->tv_nsec = r.tv_nsec;
-}
+/* The cache entry file is composed as: */
-static inline void
-cache_entry_iterate_metadata (void *ctx, const char *header,
- const char *value)
+/* "disfluid c.entry" as the magic number on 16 bytes. */
+/* The request date on 12 bytes: 8 bytes, big endian, unsigned, for
+ the tv_sec field, and then 4 bytes, big endian, unsigned, for the
+ tv_nsec field (must be < 1e9). */
+/* The response date on 12 bytes. */
+/* On 1 byte: a value >= 128 if invalidated, < 128 if still valid. */
+
+static int
+cache_entry_really_read_n (int fd, size_t n, uint8_t * bytes,
+ bool *file_incomplete)
{
- struct disfluid_cache_entry *entry = ctx;
- if (STREQ (header, "request-date"))
- {
- cache_entry_parse_timespec (value, &(entry->request_date));
- }
- else if (STREQ (header, "response-date"))
- {
- cache_entry_parse_timespec (value, &(entry->response_date));
- }
- else if (STREQ (header, "invalidated"))
+ size_t n_read = 0;
+ *file_incomplete = false;
+ while (n_read < n)
{
- while (*value == ' ' || *value == '\t' || *value == '\r'
- || *value == '\n')
+ ssize_t n_this_time = read (fd, &(bytes[n_read]), n - n_read);
+ if (n_this_time < 0)
{
- value++;
+ return 1;
}
- if (STREQ (value, "true\r\n"))
+ else if (n_this_time == 0)
{
- entry->invalidated = true;
+ *file_incomplete = true;
+ return 1;
}
- else if (STREQ (value, "false\r\n"))
+ else
{
- entry->invalidated = false;
+ assert (n_this_time > 0);
+ n_read += n_this_time;
}
}
+ return 0;
}
-static inline void
-cache_entry_scan (struct disfluid_cache_entry *entry)
+static int
+cache_entry_read_magic (int fd, bool *magic_ok, bool *file_incomplete)
{
- entry->start = lseek (entry->fd, 0, SEEK_CUR);
- cache_entry_enumerate_header_lines (entry, cache_entry_iterate_metadata,
- entry);
- entry->header_stop = lseek (entry->fd, 0, SEEK_CUR);
- /* Reset the file descriptor position, in case it is shared */
- lseek (entry->fd, entry->start, SEEK_SET);
+ uint8_t magic[16];
+ *magic_ok = false;
+ *file_incomplete = false;
+ int err = cache_entry_really_read_n (fd, 16, magic, file_incomplete);
+ if (err)
+ {
+ return err;
+ }
+ if (memcmp (magic, "disfluid c.entry", 16) != 0)
+ {
+ *magic_ok = false;
+ return 1;
+ }
+ *magic_ok = true;
+ return 0;
}
-static struct disfluid_cache_entry *
-cache_entry_from_fd (int fd)
+static int
+cache_entry_read_timespec (int fd, struct timespec *timespec,
+ bool *file_incomplete)
{
- struct disfluid_cache_entry *ret = cache_entry_alloc ();
- if (ret == NULL)
+ uint8_t data[12];
+ *file_incomplete = false;
+ int err = cache_entry_really_read_n (fd, 12, data, file_incomplete);
+ if (err)
{
- abort ();
+ return err;
}
- ret->fd = dup (fd);
- if (ret->fd < 0)
+ timespec->tv_sec = 0;
+ timespec->tv_nsec = 0;
+ for (size_t i = 0; i < 8; i++)
{
- abort ();
+ timespec->tv_sec *= 256;
+ timespec->tv_sec += data[i];
}
- cache_entry_scan (ret);
- assert (ret->start >= 0);
- assert (ret->header_stop >= 0);
- if (ret->header_stop == ret->start)
+ for (size_t i = 8; i < 12; i++)
{
- /* Assume that reading failed. */
- cache_entry_free (ret);
- ret = NULL;
+ timespec->tv_nsec *= 256;
+ timespec->tv_nsec += data[i];
}
- return ret;
+ return 0;
}
static int
-cache_entry_save_other_file_name (const struct disfluid_cache_entry *entry,
- const char *file_name)
+cache_entry_load_aux (struct disfluid_cache_entry *entry,
+ const char *filename, bool *file_incomplete)
{
- int fd = open (file_name, O_WRONLY | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR | S_IRGRP);
+ *file_incomplete = false;
+ int fd = open (filename, O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd < 0)
{
- return errno;
+ return -1;
}
- return cache_entry_save_other_fd (entry, fd);
-}
-
-static int
-cache_entry_save_other_fd (const struct disfluid_cache_entry *entry, int fd)
-{
- char *set_request_date;
- char *set_response_date;
- char *set_invalidated;
- char *meta_header;
- int status;
- status =
- asprintf (&set_request_date, "Request-Date: %lld.%09ld\r\n",
- (long long) entry->request_date.tv_sec,
- (long) entry->request_date.tv_nsec);
- if (status < 0)
+ bool magic_ok = false;
+ struct timespec request_date, response_date;
+ bool invalidated;
+ int error = 0;
+ error = cache_entry_read_magic (fd, &magic_ok, file_incomplete);
+ if (error)
{
- abort ();
+ goto cleanup;
}
- status =
- asprintf (&set_response_date, "Response-Date: %lld.%09ld\r\n",
- (long long) entry->response_date.tv_sec,
- (long) entry->response_date.tv_nsec);
- if (status < 0)
+ if (!magic_ok)
{
- abort ();
+ error = -1;
+ goto cleanup;
}
- if (entry->invalidated)
+ error = cache_entry_read_timespec (fd, &request_date, file_incomplete);
+ if (error)
{
- status = asprintf (&set_invalidated, "Invalidated: true\r\n");
- if (status < 0)
- {
- abort ();
- }
+ goto cleanup;
}
- else
+ error = cache_entry_read_timespec (fd, &response_date, file_incomplete);
+ if (error)
{
- set_invalidated = strdup ("");
- if (set_invalidated == NULL)
- {
- abort ();
- }
+ goto cleanup;
}
- status =
- asprintf (&meta_header, "%s%s%s\r\n", set_request_date, set_response_date,
- set_invalidated);
- free (set_request_date);
- free (set_response_date);
- free (set_invalidated);
- if (status < 0)
+ uint8_t flags;
+ ssize_t n_flags_read = read (fd, &flags, 1);
+ if (n_flags_read == 0)
{
- abort ();
+ *file_incomplete = true;
}
- size_t n_written = 0;
- while (n_written < strlen (meta_header))
+ if (n_flags_read < 0)
{
- ssize_t n_written_this_time = write (fd, &(meta_header[n_written]),
- strlen (meta_header) - n_written);
- if (n_written_this_time <= 0)
- {
- free (meta_header);
- return 2;
- }
- n_written += n_written_this_time;
+ error = -1;
+ goto cleanup;
}
- free (meta_header);
- return 0;
+ invalidated = ((flags & 0x80) != 0);
+ cache_entry_set_request_date (entry, &request_date);
+ cache_entry_set_response_date (entry, &response_date);
+ cache_entry_set_invalidated (entry, invalidated);
+cleanup:
+ close (fd);
+ return error;
}
-static void
-cache_entry_set_request_date (struct disfluid_cache_entry *entry,
- const struct timespec *date)
-{
- entry->request_date.tv_sec = date->tv_sec;
- entry->request_date.tv_nsec = date->tv_nsec;
-}
-
-static void
-cache_entry_set_response_date (struct disfluid_cache_entry *entry,
- const struct timespec *date)
-{
- entry->response_date.tv_sec = date->tv_sec;
- entry->response_date.tv_nsec = date->tv_nsec;
-}
-
-static void
-cache_entry_invalidate (struct disfluid_cache_entry *entry)
-{
- cache_entry_set_invalidated (entry, true);
-}
-
-static void
-cache_entry_set_invalidated (struct disfluid_cache_entry *entry,
- bool invalidated)
+static char *
+cache_entry_backup_file_name (const char *filename)
{
- entry->invalidated = invalidated;
+ char *backup_file = malloc (strlen (filename) + strlen ("~") + 1);
+ if (backup_file == NULL)
+ {
+ return NULL;
+ }
+ strcpy (backup_file, filename);
+ strcat (backup_file, "~");
+ return backup_file;
}
-static void
-cache_entry_set_file_name (struct disfluid_cache_entry *entry,
- const char *file_name)
+static int
+cache_entry_load (struct disfluid_cache_entry *entry, const char *filename)
{
- free (entry->file_name);
- entry->file_name = NULL;
- if (file_name != NULL)
- {
- entry->file_name = strdup (file_name);
- if (entry->file_name == NULL)
+ /* Try to read from filename. If the file does not exist, do not
+ even try to read a backup. If the file exists but is incomplete,
+ read the backup file. */
+ bool file_incomplete = false;
+ int error = cache_entry_load_aux (entry, filename, &file_incomplete);
+ if (file_incomplete)
+ {
+ char *backup_file = cache_entry_backup_file_name (filename);
+ if (backup_file == NULL)
{
abort ();
}
+ error = cache_entry_load_aux (entry, backup_file, &file_incomplete);
+ free (backup_file);
}
+ return error;
}
static void
@@ -567,19 +313,161 @@ cache_entry_invalidated (const struct disfluid_cache_entry *entry)
return entry->invalidated;
}
-static char *
-cache_entry_get_file_name (const struct disfluid_cache_entry *entry)
+static int
+cache_entry_really_write_n (int fd, size_t n, const uint8_t * data)
{
- if (entry->file_name == NULL)
+ while (n != 0)
{
- return NULL;
+ ssize_t n_this_time = write (fd, data, n);
+ if (n_this_time < 0)
+ {
+ return -1;
+ }
+ else if (n_this_time == 0)
+ {
+ /* Impossible */
+ abort ();
+ }
+ else
+ {
+ assert (n_this_time > 0);
+ n -= n_this_time;
+ data = &(data[n_this_time]);
+ }
}
- char *ret = strdup (entry->file_name);
- if (ret == NULL)
+ return 0;
+}
+
+static int
+cache_entry_write_magic (int fd)
+{
+ static const uint8_t magic[16] = "disfluid c.entry";
+ return cache_entry_really_write_n (fd, 16, magic);
+}
+
+static int
+cache_entry_write_timespec (int fd, const struct timespec *ts)
+{
+ uint8_t data[12];
+ time_t tv_sec = ts->tv_sec;
+ long tv_nsec = ts->tv_nsec;
+ assert (tv_nsec >= 0);
+ for (size_t i = 8; i-- > 0;)
+ {
+ data[i] = tv_sec % 256;
+ tv_sec /= 256;
+ }
+ for (size_t i = 12; i-- > 8;)
+ {
+ data[i] = tv_nsec % 256;
+ tv_nsec /= 256;
+ }
+ return cache_entry_really_write_n (fd, 12, data);
+}
+
+static int
+cache_entry_save (const struct disfluid_cache_entry *entry,
+ const char *filename)
+{
+ /* To save a file: */
+ /* 1. Lock it. */
+ /* 2. Copy it to `filename~' with copy_file_range. */
+ /* 3. Overwrite `filename'. */
+ /* 4. Unlock it. */
+ int error = 0;
+ int actual_fd, backup_fd;
+ actual_fd = open (filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
+ char *backup_file = cache_entry_backup_file_name (filename);
+ if (backup_file == NULL)
{
abort ();
}
- return ret;
+ backup_fd =
+ open (backup_file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
+ free (backup_file);
+ if (actual_fd < 0 || backup_fd < 0)
+ {
+ error = -1;
+ goto cleanup;
+ }
+ struct flock lock = {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0
+ };
+ int lock_error = fcntl (actual_fd, F_SETLKW, &lock);
+ if (lock_error)
+ {
+ error = -2;
+ goto cleanup;
+ }
+ ssize_t n_copied = 0;
+ do
+ {
+ /* Copy by blocks of 2 MiB. I don’t care the size, I don’t have
+ to allocate it anyway. */
+ n_copied =
+ copy_file_range (actual_fd, NULL, backup_fd, NULL, 2 * 1024 * 1024,
+ 0);
+ if (n_copied < 0)
+ {
+ error = -3;
+ goto cleanup;
+ }
+ }
+ while (n_copied != 0);
+ off_t to_start = lseek (actual_fd, SEEK_SET, 0);
+ if (to_start != 0)
+ {
+ error = -4;
+ goto cleanup;
+ }
+ if (ftruncate (actual_fd, 0) != 0)
+ {
+ error = -5;
+ goto cleanup;
+ }
+ assert (error == 0);
+ error = cache_entry_write_magic (actual_fd);
+ if (error)
+ {
+ error = -6;
+ goto cleanup;
+ }
+ error = cache_entry_write_timespec (actual_fd, &(entry->request_date));
+ if (error)
+ {
+ error = -7;
+ goto cleanup;
+ }
+ error = cache_entry_write_timespec (actual_fd, &(entry->response_date));
+ if (error)
+ {
+ error = -8;
+ goto cleanup;
+ }
+ uint8_t flags = 0;
+ if (entry->invalidated)
+ {
+ flags = 0x80;
+ }
+ error = cache_entry_really_write_n (actual_fd, 1, &flags);
+ if (error)
+ {
+ error = -9;
+ goto cleanup;
+ }
+cleanup:
+ if (actual_fd >= 0)
+ {
+ close (actual_fd);
+ }
+ if (backup_fd >= 0)
+ {
+ close (backup_fd);
+ }
+ return error;
}
#endif /* DISFLUID_DISFLUID_CACHE_ENTRY_INCLUDED */
diff --git a/src/libdisfluid/disfluid-tests.h b/src/libdisfluid/disfluid-tests.h
index 0a40f20..0819bb0 100644
--- a/src/libdisfluid/disfluid-tests.h
+++ b/src/libdisfluid/disfluid-tests.h
@@ -11,8 +11,8 @@ static inline char *run_tests (size_t *n_tests, size_t *n_errors);
# include "disfluid-version.h"
# include "disfluid-cache-entry.h"
-static inline int
-test_open_file_with_content (const char *content)
+static inline char *
+test_tmp_file_name_with_content (size_t n, const uint8_t * content)
{
char name[] = "/tmp/disfluid-cache-entry-test-XXXXXX";
int fd = mkstemp (name);
@@ -20,27 +20,34 @@ test_open_file_with_content (const char *content)
{
abort ();
}
- size_t n_written = 0;
- while (n_written < strlen (content))
+ while (n > 0)
{
- ssize_t next =
- write (fd, &(content[n_written]), strlen (content) - n_written);
+ ssize_t next = write (fd, content, n);
if (next <= 0)
{
abort ();
}
- n_written += next;
+ else if (next == 0)
+ {
+ /* Impossible */
+ abort ();
+ }
+ else
+ {
+ assert (next > 0);
+ assert ((size_t) next <= n);
+ n -= next;
+ content = &(content[next]);
+ }
}
- remove (name);
- lseek (fd, 0, SEEK_SET);
- return fd;
-}
-
-static inline void
-fwrite_text (FILE * file, const char *text)
-{
- fwrite (text, 1, strlen (text), file);
- fflush (file);
+ close (fd);
+ char *ret = malloc (strlen (name) + 1);
+ if (ret == NULL)
+ {
+ abort ();
+ }
+ strcpy (ret, name);
+ return ret;
}
/* *INDENT-OFF* */
@@ -56,204 +63,312 @@ END_TEST
/* *INDENT-ON* */
/* *INDENT-OFF* */
-START_TEST (test_read_invalid_cache_entry_file)
+START_TEST (test_read_invalid_magic_number)
/* *INDENT-ON* */
{
- int fd_source = test_open_file_with_content ("Hello, world!");
- if (fd_source < 0)
+ uint8_t data[16 + 12 + 12 + 1] = { 0 };
+ memcpy (data, "invalid magic no", 16);
+ char *filename =
+ test_tmp_file_name_with_content (sizeof (data) / sizeof (data[0]), data);
+ if (filename == NULL)
+ {
+ abort ();
+ }
+ struct disfluid_cache_entry *entry = cache_entry_alloc ();
+ if (entry == NULL)
{
abort ();
}
- struct disfluid_cache_entry *entry =
- disfluid_cache_entry_from_fd (fd_source);
- ck_assert_ptr_null (entry);
- close (fd_source);
+ int error = cache_entry_load (entry, filename);
+ cache_entry_free (entry);
+ remove (filename);
+ free (filename);
+ ck_assert_int_ne (error, 0);
}
/* *INDENT-OFF* */
END_TEST
/* *INDENT-ON* */
/* *INDENT-OFF* */
-START_TEST (test_read_cache_entry_no_date)
+START_TEST (test_read_inexistent_file)
/* *INDENT-ON* */
{
- int fd_source = test_open_file_with_content ("Invalidated: true\r\n\r\n");
- if (fd_source < 0)
+ static const char *filename =
+ "/disfluid-this-file-should-not-exist-to-pass-tests";
+ struct disfluid_cache_entry *entry = cache_entry_alloc ();
+ if (entry == NULL)
{
abort ();
}
- struct disfluid_cache_entry *entry =
- disfluid_cache_entry_from_fd (fd_source);
- ck_assert_ptr_ne (entry, NULL);
- close (fd_source);
- struct timespec request_date = {.tv_sec = 42,.tv_nsec = 69 };
- struct timespec response_date = {.tv_sec = 42,.tv_nsec = 69 };
- disfluid_cache_entry_get_request_date (entry, &request_date);
- disfluid_cache_entry_get_request_date (entry, &response_date);
- ck_assert_int_eq (request_date.tv_sec, 0);
- ck_assert_int_eq (request_date.tv_nsec, 0);
- ck_assert_int_eq (response_date.tv_sec, 0);
- ck_assert_int_eq (response_date.tv_nsec, 0);
- ck_assert ((bool) disfluid_cache_entry_invalidated (entry));
- disfluid_cache_entry_free (entry);
+ int error = cache_entry_load (entry, filename);
+ cache_entry_free (entry);
+ ck_assert_int_ne (error, 0);
}
/* *INDENT-OFF* */
END_TEST
/* *INDENT-ON* */
/* *INDENT-OFF* */
-START_TEST (test_read_cache_entry_whole_seconds)
+START_TEST (test_read_inexistent_file_with_valid_backup)
/* *INDENT-ON* */
{
- int fd_source = test_open_file_with_content ("\
-Request-Date: 42\r\n\
-Response-Date: 69\r\n\
-Invalidated: true\r\n\
-\r\n");
- if (fd_source < 0)
+ uint8_t data[16 + 12 + 12 + 1] = { 0 };
+ memcpy (data, "disfluid c.entry", 16);
+ char *filename =
+ test_tmp_file_name_with_content (sizeof (data) / sizeof (data[0]), data);
+ if (filename == NULL)
+ {
+ abort ();
+ }
+ char *filename_backup = malloc (strlen (filename) + strlen ("~") + 1);
+ if (filename_backup == NULL)
+ {
+ abort ();
+ }
+ strcpy (filename_backup, filename);
+ strcat (filename_backup, "~");
+ rename (filename, filename_backup);
+ struct disfluid_cache_entry *entry = cache_entry_alloc ();
+ if (entry == NULL)
{
abort ();
}
- struct disfluid_cache_entry *entry =
- disfluid_cache_entry_from_fd (fd_source);
- close (fd_source);
- ck_assert_ptr_ne (entry, NULL);
- struct timespec request_date = {.tv_sec = 1,.tv_nsec = 3 };
- struct timespec response_date = {.tv_sec = 2,.tv_nsec = 4 };
- disfluid_cache_entry_get_request_date (entry, &request_date);
- disfluid_cache_entry_get_response_date (entry, &response_date);
- ck_assert_int_eq (request_date.tv_sec, 42);
- ck_assert_int_eq (request_date.tv_nsec, 0);
- ck_assert_int_eq (response_date.tv_sec, 69);
- ck_assert_int_eq (response_date.tv_nsec, 0);
- ck_assert ((bool) disfluid_cache_entry_invalidated (entry));
- disfluid_cache_entry_free (entry);
+ int error = cache_entry_load (entry, filename);
+ cache_entry_free (entry);
+ remove (filename_backup);
+ free (filename_backup);
+ free (filename);
+ ck_assert_int_ne (error, 0);
}
/* *INDENT-OFF* */
END_TEST
/* *INDENT-ON* */
+static inline void
+test_check_partial_situation (size_t n_partial)
+{
+ uint8_t data[16 + 12 + 12 + 1] = { 0 };
+ memcpy (data, "disfluid c.entry", 16);
+ /* The data is all zeros */
+ uint8_t backup_data[16 + 12 + 12 + 1] = { 0 };
+ memcpy (backup_data, "disfluid c.entry", 16);
+ backup_data[16 + 8 - 1] = 1;
+ backup_data[16 + 12 - 1] = 2;
+ backup_data[16 + 12 + 8 - 1] = 3;
+ backup_data[16 + 12 + 12 - 1] = 4;
+ backup_data[16 + 12 + 12 + 1 - 1] = 0x80;
+ /* The backup has a request date of 1s + 2ns, response of 3s + 4ns,
+ and is invalidated. */
+ assert (n_partial <= sizeof (data) / sizeof (data[0]));
+ char *filename = test_tmp_file_name_with_content (n_partial, data);
+ if (filename == NULL)
+ {
+ abort ();
+ }
+ char *filename_backup = malloc (strlen (filename) + strlen ("~") + 1);
+ if (filename_backup == NULL)
+ {
+ abort ();
+ }
+ strcpy (filename_backup, filename);
+ strcat (filename_backup, "~");
+ char *backup_content_filename =
+ test_tmp_file_name_with_content (sizeof (backup_data) /
+ sizeof (backup_data[0]), backup_data);
+ if (backup_content_filename == NULL)
+ {
+ abort ();
+ }
+ rename (backup_content_filename, filename_backup);
+ /* Now, filename is a partial file, and filename~ is a valid
+ backup. */
+ struct disfluid_cache_entry *entry = cache_entry_alloc ();
+ if (entry == NULL)
+ {
+ abort ();
+ }
+ int error = cache_entry_load (entry, filename);
+ ck_assert_int_eq (error, 0);
+ if (n_partial < sizeof (data) / sizeof (data[0]))
+ {
+ /* This should be the content of the backup file. */
+ struct timespec request, response;
+ cache_entry_get_request_date (entry, &request);
+ cache_entry_get_response_date (entry, &response);
+ bool invalidated = cache_entry_invalidated (entry);
+ ck_assert_int_eq (request.tv_sec, 1);
+ ck_assert_int_eq (request.tv_nsec, 2);
+ ck_assert_int_eq (response.tv_sec, 3);
+ ck_assert_int_eq (response.tv_nsec, 4);
+ ck_assert (invalidated);
+ }
+ else
+ {
+ /* This should be the content of the full file. */
+ struct timespec request, response;
+ cache_entry_get_request_date (entry, &request);
+ cache_entry_get_response_date (entry, &response);
+ bool invalidated = cache_entry_invalidated (entry);
+ ck_assert_int_eq (request.tv_sec, 0);
+ ck_assert_int_eq (request.tv_nsec, 0);
+ ck_assert_int_eq (response.tv_sec, 0);
+ ck_assert_int_eq (response.tv_nsec, 0);
+ ck_assert (!invalidated);
+ }
+ cache_entry_free (entry);
+ free (backup_content_filename);
+ free (filename_backup);
+ free (filename);
+}
+
/* *INDENT-OFF* */
-START_TEST (test_read_cache_entry_whole_seconds_dot)
+START_TEST (test_read_file_with_valid_backup)
/* *INDENT-ON* */
{
- int fd_source = test_open_file_with_content ("\
-Request-Date: 42.\r\n\
-Response-Date: 69.\r\n\
-Invalidated: true\r\n\
-\r\n");
- if (fd_source < 0)
+ uint8_t data[16 + 12 + 12 + 1] = { 0 };
+ memcpy (data, "disfluid c.entry", 16);
+ /* The data is all zeros */
+ uint8_t backup_data[16 + 12 + 12 + 1] = { 0 };
+ memcpy (backup_data, "disfluid c.entry", 16);
+ backup_data[16 + 8 - 1] = 1;
+ backup_data[16 + 12 - 1] = 2;
+ backup_data[16 + 12 + 8 - 1] = 3;
+ backup_data[16 + 12 + 12 - 1] = 4;
+ backup_data[16 + 12 + 12 + 1 - 1] = 0x80;
+ /* The backup has a request date of 1s + 2ns, response of 3s + 4ns,
+ and is invalidated. */
+ char *filename =
+ test_tmp_file_name_with_content (sizeof (data) / sizeof (data[0]), data);
+ if (filename == NULL)
+ {
+ abort ();
+ }
+ char *filename_backup = malloc (strlen (filename) + strlen ("~") + 1);
+ if (filename_backup == NULL)
+ {
+ abort ();
+ }
+ strcpy (filename_backup, filename);
+ strcat (filename_backup, "~");
+ rename (filename, filename_backup);
+ struct disfluid_cache_entry *entry = cache_entry_alloc ();
+ if (entry == NULL)
{
abort ();
}
- struct disfluid_cache_entry *entry =
- disfluid_cache_entry_from_fd (fd_source);
- close (fd_source);
- ck_assert_ptr_ne (entry, NULL);
- struct timespec request_date = {.tv_sec = 1,.tv_nsec = 3 };
- struct timespec response_date = {.tv_sec = 2,.tv_nsec = 4 };
- disfluid_cache_entry_get_request_date (entry, &request_date);
- disfluid_cache_entry_get_response_date (entry, &response_date);
- ck_assert_int_eq (request_date.tv_sec, 42);
- ck_assert_int_eq (request_date.tv_nsec, 0);
- ck_assert_int_eq (response_date.tv_sec, 69);
- ck_assert_int_eq (response_date.tv_nsec, 0);
- ck_assert ((bool) disfluid_cache_entry_invalidated (entry));
- disfluid_cache_entry_free (entry);
+ int error = cache_entry_load (entry, filename);
+ remove (filename_backup);
+ free (filename_backup);
+ free (filename);
+ cache_entry_free (entry);
+ ck_assert_int_ne (error, 0);
}
/* *INDENT-OFF* */
END_TEST
/* *INDENT-ON* */
/* *INDENT-OFF* */
-START_TEST (test_read_cache_entry_milliseconds)
+START_TEST (test_read_cache_file_partial_0)
/* *INDENT-ON* */
{
- int fd_source = test_open_file_with_content ("\
-Request-Date: 42.123\r\n\
-Response-Date: 69.456\r\n\
-Invalidated: true\r\n\
-\r\n");
- if (fd_source < 0)
- {
- abort ();
- }
- struct disfluid_cache_entry *entry =
- disfluid_cache_entry_from_fd (fd_source);
- close (fd_source);
- ck_assert_ptr_ne (entry, NULL);
- struct timespec request_date = {.tv_sec = 1,.tv_nsec = 3 };
- struct timespec response_date = {.tv_sec = 2,.tv_nsec = 4 };
- disfluid_cache_entry_get_request_date (entry, &request_date);
- disfluid_cache_entry_get_response_date (entry, &response_date);
- ck_assert_int_eq (request_date.tv_sec, 42);
- ck_assert_int_eq (request_date.tv_nsec, 123000000);
- ck_assert_int_eq (response_date.tv_sec, 69);
- ck_assert_int_eq (response_date.tv_nsec, 456000000);
- ck_assert ((bool) disfluid_cache_entry_invalidated (entry));
- disfluid_cache_entry_free (entry);
+ test_check_partial_situation (0);
}
/* *INDENT-OFF* */
END_TEST
/* *INDENT-ON* */
/* *INDENT-OFF* */
-START_TEST (test_read_cache_entry_precise)
+START_TEST (test_read_cache_file_partial_1)
/* *INDENT-ON* */
{
- int fd_source = test_open_file_with_content ("\
-Request-Date: 42.123456789\r\n\
-Response-Date: 69.456789123\r\n\
-Invalidated: true\r\n\
-\r\n");
- if (fd_source < 0)
- {
- abort ();
- }
- struct disfluid_cache_entry *entry =
- disfluid_cache_entry_from_fd (fd_source);
- close (fd_source);
- ck_assert_ptr_ne (entry, NULL);
- struct timespec request_date = {.tv_sec = 1,.tv_nsec = 3 };
- struct timespec response_date = {.tv_sec = 2,.tv_nsec = 4 };
- disfluid_cache_entry_get_request_date (entry, &request_date);
- disfluid_cache_entry_get_response_date (entry, &response_date);
- ck_assert_int_eq (request_date.tv_sec, 42);
- ck_assert_int_eq (request_date.tv_nsec, 123456789);
- ck_assert_int_eq (response_date.tv_sec, 69);
- ck_assert_int_eq (response_date.tv_nsec, 456789123);
- ck_assert ((bool) disfluid_cache_entry_invalidated (entry));
- disfluid_cache_entry_free (entry);
+ test_check_partial_situation (1);
}
/* *INDENT-OFF* */
END_TEST
/* *INDENT-ON* */
/* *INDENT-OFF* */
-START_TEST (test_read_cache_entry_ambiguous)
+START_TEST (test_read_cache_file_partial_16)
/* *INDENT-ON* */
{
- int fd_source = test_open_file_with_content ("\
-Request-Date: 42.123456789\r\n\
-Response-Date: 69.456789123\r\n");
- /* Notice how we don’t know if we’re at the end because of a missing
- \r\n. */
- if (fd_source < 0)
- {
- abort ();
- }
- /* Is it the end? */
- struct disfluid_cache_entry *entry =
- disfluid_cache_entry_from_fd (fd_source);
- ck_assert_ptr_eq (entry, NULL);
- close (fd_source);
+ test_check_partial_situation (16);
+}
+/* *INDENT-OFF* */
+END_TEST
+
+/* *INDENT-ON* */
+
+START_TEST (test_read_cache_file_partial_17)
+/* *INDENT-ON* */
+{
+ test_check_partial_situation (17);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-ON* */
+START_TEST (test_read_cache_file_partial_28)
+/* *INDENT-ON* */
+{
+ test_check_partial_situation (28);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-ON* */
+START_TEST (test_read_cache_file_partial_29)
+/* *INDENT-ON* */
+{
+ test_check_partial_situation (29);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-ON* */
+START_TEST (test_read_cache_file_partial_36)
+/* *INDENT-ON* */
+{
+ test_check_partial_situation (36);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-ON* */
+START_TEST (test_read_cache_file_partial_37)
+/* *INDENT-ON* */
+{
+ test_check_partial_situation (37);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-ON* */
+START_TEST (test_read_cache_file_partial_40)
+/* *INDENT-ON* */
+{
+ test_check_partial_situation (40);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-ON* */
+START_TEST (test_read_cache_file_partial_41)
+/* *INDENT-ON* */
+{
+ test_check_partial_situation (41);
}
/* *INDENT-OFF* */
END_TEST
@@ -264,30 +379,84 @@ START_TEST (test_write_cache_entry)
/* *INDENT-ON* */
{
- int fd_dest = test_open_file_with_content ("hehe");
- if (fd_dest < 0)
+ uint8_t old_data[16 + 12 + 12 + 1] = { 0 };
+ memcpy (old_data, "disfluid c.entry", 16);
+ old_data[16 + 8 - 1] = 1;
+ old_data[16 + 12 - 1] = 2;
+ old_data[16 + 12 + 8 - 1] = 3;
+ old_data[16 + 12 + 12 - 1] = 4;
+ old_data[16 + 12 + 12 + 1 - 1] = 0x80;
+ /* The old data has a request date of 1s + 2ns, response of 3s +
+ 4ns, and is invalidated. */
+ char *filename =
+ test_tmp_file_name_with_content (sizeof (old_data) / sizeof (old_data[0]),
+ old_data);
+ if (filename == NULL)
+ {
+ abort ();
+ }
+ char *filename_backup = malloc (strlen (filename) + strlen ("~") + 1);
+ if (filename_backup == NULL)
{
abort ();
}
- struct disfluid_cache_entry *entry = disfluid_cache_entry_alloc ();
+ strcpy (filename_backup, filename);
+ strcat (filename_backup, "~");
+ struct disfluid_cache_entry *entry = cache_entry_alloc ();
if (entry == NULL)
{
abort ();
}
- const struct timespec rq = {
- .tv_sec = 123,
- .tv_nsec = 456
- };
- const struct timespec rs = {
- .tv_sec = 789,
- .tv_nsec = 101112
- };
- disfluid_cache_entry_set_request_date (entry, &rq);
- disfluid_cache_entry_set_response_date (entry, &rs);
- int error = disfluid_cache_entry_save_other_fd (entry, fd_dest);
+ struct timespec request, response;
+ request.tv_sec = 10;
+ request.tv_nsec = 11;
+ response.tv_sec = 12;
+ response.tv_nsec = 13;
+ cache_entry_set_request_date (entry, &request);
+ cache_entry_set_response_date (entry, &response);
+ cache_entry_set_invalidated (entry, false);
+ int error = cache_entry_save (entry, filename);
ck_assert_int_eq (error, 0);
- disfluid_cache_entry_free (entry);
- close (fd_dest);
+ uint8_t check_backup_data[16 + 12 + 12 + 1];
+ uint8_t check_data[16 + 12 + 12 + 1];
+ assert (sizeof (check_data) == sizeof (old_data));
+ assert (sizeof (check_backup_data) == sizeof (old_data));
+ bool file_incomplete, backup_file_incomplete;
+ int fd = open (filename, O_RDONLY, 0);
+ int fd_backup = open (filename_backup, O_RDONLY, 0);
+ if (fd < 0 || fd_backup < 0)
+ {
+ abort ();
+ }
+ int check_error =
+ (cache_entry_really_read_n
+ (fd, sizeof (check_data) / sizeof (check_data[0]), check_data,
+ &file_incomplete) != 0);
+ int check_backup_error =
+ (cache_entry_really_read_n
+ (fd_backup, sizeof (check_backup_data) / sizeof (check_backup_data[0]),
+ check_backup_data, &backup_file_incomplete) != 0);
+ ck_assert_int_eq (check_error, 0);
+ ck_assert_int_eq (check_backup_error, 0);
+ ck_assert (!file_incomplete);
+ ck_assert (!backup_file_incomplete);
+ ck_assert_int_eq (memcmp (check_data, "disfluid c.entry", 16), 0);
+ ck_assert_int_eq (check_data[16 + 8 - 1], 10);
+ ck_assert_int_eq (check_data[16 + 12 - 1], 11);
+ ck_assert_int_eq (check_data[16 + 12 + 8 - 1], 12);
+ ck_assert_int_eq (check_data[16 + 12 + 12 - 1], 13);
+ ck_assert_int_eq (check_data[16 + 12 + 12 + 1 - 1], 0);
+ ck_assert_int_eq (memcmp
+ (check_backup_data, old_data,
+ sizeof (check_backup_data) /
+ sizeof (check_backup_data[0])), 0);
+ close (fd);
+ close (fd_backup);
+ remove (filename);
+ remove (filename_backup);
+ cache_entry_free (entry);
+ free (filename_backup);
+ free (filename);
}
/* *INDENT-OFF* */
END_TEST
@@ -327,13 +496,20 @@ run_tests (size_t *n_tests, size_t *n_errors)
tcase_add_test (general, test_check_version);
suite_add_tcase (suite, general);
TCase *cache_entry = tcase_create (_("disfluid cache entry files"));
- tcase_add_test (cache_entry, test_read_invalid_cache_entry_file);
- tcase_add_test (cache_entry, test_read_cache_entry_no_date);
- tcase_add_test (cache_entry, test_read_cache_entry_whole_seconds);
- tcase_add_test (cache_entry, test_read_cache_entry_whole_seconds_dot);
- tcase_add_test (cache_entry, test_read_cache_entry_milliseconds);
- tcase_add_test (cache_entry, test_read_cache_entry_precise);
- tcase_add_test (cache_entry, test_read_cache_entry_ambiguous);
+ tcase_add_test (cache_entry, test_read_invalid_magic_number);
+ tcase_add_test (cache_entry, test_read_inexistent_file);
+ tcase_add_test (cache_entry, test_read_inexistent_file_with_valid_backup);
+ tcase_add_test (cache_entry, test_read_file_with_valid_backup);
+ tcase_add_test (cache_entry, test_read_cache_file_partial_0);
+ tcase_add_test (cache_entry, test_read_cache_file_partial_1);
+ tcase_add_test (cache_entry, test_read_cache_file_partial_16);
+ tcase_add_test (cache_entry, test_read_cache_file_partial_17);
+ tcase_add_test (cache_entry, test_read_cache_file_partial_28);
+ tcase_add_test (cache_entry, test_read_cache_file_partial_29);
+ tcase_add_test (cache_entry, test_read_cache_file_partial_36);
+ tcase_add_test (cache_entry, test_read_cache_file_partial_37);
+ tcase_add_test (cache_entry, test_read_cache_file_partial_40);
+ tcase_add_test (cache_entry, test_read_cache_file_partial_41);
tcase_add_test (cache_entry, test_write_cache_entry);
suite_add_tcase (suite, cache_entry);
SRunner *runner = srunner_create (suite);
diff --git a/src/libdisfluid/main.c b/src/libdisfluid/main.c
index c254a4a..24efb51 100644
--- a/src/libdisfluid/main.c
+++ b/src/libdisfluid/main.c
@@ -8,6 +8,7 @@
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
@@ -127,37 +128,11 @@ disfluid_cache_entry_free (struct disfluid_cache_entry *entry)
}
struct disfluid_cache_entry *
-disfluid_cache_entry_from_file_name (const char *file_name)
-{
- return cache_entry_from_file_name (file_name);
-}
-
-struct disfluid_cache_entry *
-disfluid_cache_entry_from_fd (int fd)
-{
- return cache_entry_from_fd (fd);
-}
-
-struct disfluid_cache_entry *
disfluid_cache_entry_dup (const struct disfluid_cache_entry *entry)
{
return cache_entry_dup (entry);
}
-int
-disfluid_cache_entry_save_other_file_name (const struct disfluid_cache_entry
- *entry, const char *file_name)
-{
- return cache_entry_save_other_file_name (entry, file_name);
-}
-
-int
-disfluid_cache_entry_save_other_fd (const struct disfluid_cache_entry *entry,
- int fd)
-{
- return cache_entry_save_other_fd (entry, fd);
-}
-
void
disfluid_cache_entry_set_request_date (struct disfluid_cache_entry *entry,
const struct timespec *date)
@@ -185,11 +160,11 @@ disfluid_cache_entry_set_invalidated (struct disfluid_cache_entry *entry,
cache_entry_set_invalidated (entry, invalidated);
}
-void
-disfluid_cache_entry_set_file_name (struct disfluid_cache_entry *entry,
- const char *file_name)
+int
+disfluid_cache_entry_load (struct disfluid_cache_entry *entry,
+ const char *filename)
{
- return cache_entry_set_file_name (entry, file_name);
+ return cache_entry_load (entry, filename);
}
void
@@ -212,8 +187,9 @@ disfluid_cache_entry_invalidated (const struct disfluid_cache_entry *entry)
return cache_entry_invalidated (entry);
}
-char *
-disfluid_cache_entry_get_file_name (const struct disfluid_cache_entry *entry)
+int
+disfluid_cache_entry_save (const struct disfluid_cache_entry *entry,
+ const char *filename)
{
- return cache_entry_get_file_name (entry);
+ return cache_entry_save (entry, filename);
}
diff --git a/tests/run-unit-tests.c b/tests/run-unit-tests.c
index 5361b72..96fa35e 100644
--- a/tests/run-unit-tests.c
+++ b/tests/run-unit-tests.c
@@ -9,6 +9,7 @@
int
main (int argc, char *argv[])
{
+ (void) argc;
set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, relocate (LOCALEDIR));