summaryrefslogtreecommitdiff
path: root/src/libdisfluid/disfluid-cache-entry.h
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 /src/libdisfluid/disfluid-cache-entry.h
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.
Diffstat (limited to 'src/libdisfluid/disfluid-cache-entry.h')
-rw-r--r--src/libdisfluid/disfluid-cache-entry.h688
1 files changed, 288 insertions, 400 deletions
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 */