diff options
Diffstat (limited to 'trust/save.c')
-rw-r--r-- | trust/save.c | 593 |
1 files changed, 0 insertions, 593 deletions
diff --git a/trust/save.c b/trust/save.c deleted file mode 100644 index 66c9050..0000000 --- a/trust/save.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - * Copyright (c) 2013, Red Hat Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * * The names of contributors to this software may not be - * used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * Author: Stef Walter <stefw@redhat.com> - */ - -#include "config.h" - -#include "buffer.h" -#include "debug.h" -#include "dict.h" -#include "message.h" -#include "save.h" - -#include <sys/stat.h> - -#include <assert.h> -#include <dirent.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -struct _p11_save_file { - char *bare; - char *extension; - char *temp; - int fd; - int flags; -}; - -struct _p11_save_dir { - p11_dict *cache; - char *path; - int flags; -}; - -static char * make_unique_name (const char *bare, - const char *extension, - int (*check) (void *, char *), - void *data); - -bool -p11_save_write_and_finish (p11_save_file *file, - const void *data, - ssize_t length) -{ - bool ret; - - if (!file) - return false; - - ret = p11_save_write (file, data, length); - if (!p11_save_finish_file (file, NULL, ret)) - ret = false; - - return ret; -} - -p11_save_file * -p11_save_open_file (const char *path, - const char *extension, - int flags) -{ - p11_save_file *file; - char *temp; - int fd; - - return_val_if_fail (path != NULL, NULL); - - if (extension == NULL) - extension = ""; - - if (asprintf (&temp, "%s%s.XXXXXX", path, extension) < 0) - return_val_if_reached (NULL); - - fd = mkstemp (temp); - if (fd < 0) { - p11_message_err (errno, "couldn't create file: %s%s", path, extension); - free (temp); - return NULL; - } - - file = calloc (1, sizeof (p11_save_file)); - return_val_if_fail (file != NULL, NULL); - file->temp = temp; - file->bare = strdup (path); - return_val_if_fail (file->bare != NULL, NULL); - file->extension = strdup (extension); - return_val_if_fail (file->extension != NULL, NULL); - file->flags = flags; - file->fd = fd; - - return file; -} - -bool -p11_save_write (p11_save_file *file, - const void *data, - ssize_t length) -{ - const unsigned char *buf = data; - ssize_t written = 0; - ssize_t res; - - if (!file) - return false; - - /* Automatically calculate length */ - if (length < 0) { - if (!data) - return true; - length = strlen (data); - } - - while (written < length) { - res = write (file->fd, buf + written, length - written); - if (res <= 0) { - if (errno == EAGAIN || errno == EINTR) - continue; - p11_message_err (errno, "couldn't write to file: %s", file->temp); - return false; - } else { - written += res; - } - } - - return true; -} - -static void -filo_free (p11_save_file *file) -{ - free (file->temp); - free (file->bare); - free (file->extension); - free (file); -} - -#ifdef OS_UNIX - -static int -on_unique_try_link (void *data, - char *path) -{ - p11_save_file *file = data; - - if (link (file->temp, path) < 0) { - if (errno == EEXIST) - return 0; /* Continue trying other names */ - p11_message_err (errno, "couldn't complete writing of file: %s", path); - return -1; - } - - return 1; /* All done */ -} - -#else /* OS_WIN32 */ - -static int -on_unique_try_rename (void *data, - char *path) -{ - p11_save_file *file = data; - - if (rename (file->temp, path) < 0) { - if (errno == EEXIST) - return 0; /* Continue trying other names */ - p11_message ("couldn't complete writing of file: %s", path); - return -1; - } - - return 1; /* All done */ -} - -#endif /* OS_WIN32 */ - -bool -p11_save_finish_file (p11_save_file *file, - char **path_out, - bool commit) -{ - bool ret = true; - char *path; - - if (!file) - return false; - - if (!commit) { - close (file->fd); - unlink (file->temp); - filo_free (file); - return true; - } - - if (asprintf (&path, "%s%s", file->bare, file->extension) < 0) - return_val_if_reached (false); - - if (close (file->fd) < 0) { - p11_message_err (errno, "couldn't write file: %s", file->temp); - ret = false; - -#ifdef OS_UNIX - /* Set the mode of the file, readable by everyone, but not writable */ - } else if (chmod (file->temp, S_IRUSR | S_IRGRP | S_IROTH) < 0) { - p11_message_err (errno, "couldn't set file permissions: %s", file->temp); - ret = false; - - /* Atomically rename the tempfile over the filename */ - } else if (file->flags & P11_SAVE_OVERWRITE) { - if (rename (file->temp, path) < 0) { - p11_message_err (errno, "couldn't complete writing file: %s", path); - ret = false; - } else { - unlink (file->temp); - } - - /* Create a unique name if requested unique file name */ - } else if (file->flags & P11_SAVE_UNIQUE) { - free (path); - path = make_unique_name (file->bare, file->extension, - on_unique_try_link, file); - if (!path) - ret = false; - unlink (file->temp); - - /* When not overwriting, link will fail if filename exists. */ - } else { - if (link (file->temp, path) < 0) { - p11_message_err (errno, "couldn't complete writing of file: %s", path); - ret = false; - } - unlink (file->temp); - -#else /* OS_WIN32 */ - - /* Windows does not do atomic renames, so delete original file first */ - } else { - /* Create a unique name if requested unique file name */ - if (file->flags & P11_SAVE_UNIQUE) { - free (path); - path = make_unique_name (file->bare, file->extension, - on_unique_try_rename, file); - if (!path) - ret = false; - - } else if ((file->flags & P11_SAVE_OVERWRITE) && - unlink (path) < 0 && errno != ENOENT) { - p11_message_err (errno, "couldn't remove original file: %s", path); - ret = false; - } - - if (ret == true && - rename (file->temp, path) < 0) { - p11_message_err (errno, "couldn't complete writing file: %s", path); - ret = false; - } - - unlink (file->temp); - -#endif /* OS_WIN32 */ - } - - if (ret && path_out) { - *path_out = path; - path = NULL; - } - - free (path); - filo_free (file); - return ret; -} - -p11_save_dir * -p11_save_open_directory (const char *path, - int flags) -{ -#ifdef OS_UNIX - struct stat sb; -#endif - p11_save_dir *dir; - - return_val_if_fail (path != NULL, NULL); - -#ifdef OS_UNIX - /* We update the permissions when we finish writing */ - if (mkdir (path, S_IRWXU) < 0) { -#else /* OS_WIN32 */ - if (mkdir (path) < 0) { -#endif - /* Some random error, report it */ - if (errno != EEXIST) { - p11_message_err (errno, "couldn't create directory: %s", path); - - /* The directory exists and we're not overwriting */ - } else if (!(flags & P11_SAVE_OVERWRITE)) { - p11_message ("directory already exists: %s", path); - return NULL; - } -#ifdef OS_UNIX - /* - * If the directory exists on unix, we may have restricted - * the directory permissions to read-only. We have to change - * them back to writable in order for things to work. - */ - if (stat (path, &sb) >= 0) { - if ((sb.st_mode & S_IRWXU) != S_IRWXU && - chmod (path, S_IRWXU | sb.st_mode) < 0) { - p11_message_err (errno, "couldn't make directory writable: %s", path); - return NULL; - } - } -#endif /* OS_UNIX */ - } - - dir = calloc (1, sizeof (p11_save_dir)); - return_val_if_fail (dir != NULL, NULL); - - dir->path = strdup (path); - return_val_if_fail (dir->path != NULL, NULL); - - dir->cache = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL); - return_val_if_fail (dir->cache != NULL, NULL); - - dir->flags = flags; - return dir; -} - -static char * -make_unique_name (const char *bare, - const char *extension, - int (*check) (void *, char *), - void *data) -{ - char unique[16]; - p11_buffer buf; - int ret; - int i; - - assert (bare != NULL); - assert (check != NULL); - - p11_buffer_init_null (&buf, 0); - - for (i = 0; true; i++) { - - p11_buffer_reset (&buf, 64); - - switch (i) { - - /* - * For the first iteration, just build the filename as - * provided by the caller. - */ - case 0: - p11_buffer_add (&buf, bare, -1); - break; - - /* - * On later iterations we try to add a numeric .N suffix - * before the extension, so the resulting file might look - * like filename.1.ext. - * - * As a special case if the extension is already '.0' then - * just just keep incerementing that. - */ - case 1: - if (extension && strcmp (extension, ".0") == 0) - extension = NULL; - /* fall through */ - - default: - p11_buffer_add (&buf, bare, -1); - snprintf (unique, sizeof (unique), ".%d", i); - p11_buffer_add (&buf, unique, -1); - break; - } - - if (extension) - p11_buffer_add (&buf, extension, -1); - - return_val_if_fail (p11_buffer_ok (&buf), NULL); - - ret = check (data, buf.data); - if (ret < 0) - return NULL; - else if (ret > 0) - return p11_buffer_steal (&buf, NULL); - } - - assert_not_reached (); -} - -static int -on_unique_check_dir (void *data, - char *name) -{ - p11_save_dir *dir = data; - - if (!p11_dict_get (dir->cache, name)) - return 1; - - return 0; /* Keep looking */ -} - -p11_save_file * -p11_save_open_file_in (p11_save_dir *dir, - const char *basename, - const char *extension) -{ - p11_save_file *file = NULL; - char *name; - char *path; - - return_val_if_fail (dir != NULL, NULL); - return_val_if_fail (basename != NULL, NULL); - - name = make_unique_name (basename, extension, on_unique_check_dir, dir); - return_val_if_fail (name != NULL, NULL); - - if (asprintf (&path, "%s/%s", dir->path, name) < 0) - return_val_if_reached (NULL); - - file = p11_save_open_file (path, NULL, dir->flags); - - if (file) { - if (!p11_dict_set (dir->cache, name, name)) - return_val_if_reached (NULL); - name = NULL; - } - - free (name); - free (path); - - return file; -} - -#ifdef OS_UNIX - -bool -p11_save_symlink_in (p11_save_dir *dir, - const char *linkname, - const char *extension, - const char *destination) -{ - char *name; - char *path; - bool ret; - - return_val_if_fail (dir != NULL, false); - return_val_if_fail (linkname != NULL, false); - return_val_if_fail (destination != NULL, false); - - name = make_unique_name (linkname, extension, on_unique_check_dir, dir); - return_val_if_fail (name != NULL, false); - - if (asprintf (&path, "%s/%s", dir->path, name) < 0) - return_val_if_reached (false); - - unlink (path); - - if (symlink (destination, path) < 0) { - p11_message_err (errno, "couldn't create symlink: %s", path); - ret = false; - } else { - if (!p11_dict_set (dir->cache, name, name)) - return_val_if_reached (false); - name = NULL; - ret = true; - } - - free (path); - free (name); - - return ret; -} - -#endif /* OS_UNIX */ - -static bool -cleanup_directory (const char *directory, - p11_dict *cache) -{ - struct dirent *dp; - struct stat st; - p11_dict *remove; - p11_dictiter iter; - char *path; - DIR *dir; - bool ret; - - /* First we load all the modules */ - dir = opendir (directory); - if (!dir) { - p11_message_err (errno, "couldn't list directory: %s", directory); - return false; - } - - remove = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL); - - while ((dp = readdir (dir)) != NULL) { - if (p11_dict_get (cache, dp->d_name)) - continue; - - if (asprintf (&path, "%s/%s", directory, dp->d_name) < 0) - return_val_if_reached (false); - - - if (stat (path, &st) >= 0 && !S_ISDIR (st.st_mode)) { - if (!p11_dict_set (remove, path, path)) - return_val_if_reached (false); - } else { - free (path); - } - } - - closedir (dir); - - ret = true; - - /* Remove all the files still in the cache */ - p11_dict_iterate (remove, &iter); - while (p11_dict_next (&iter, (void **)&path, NULL)) { - if (unlink (path) < 0 && errno != ENOENT) { - p11_message_err (errno, "couldn't remove file: %s", path); - ret = false; - break; - } - } - - p11_dict_free (remove); - - return ret; -} - -bool -p11_save_finish_directory (p11_save_dir *dir, - bool commit) -{ - bool ret = true; - - if (!dir) - return false; - - if (commit) { - if (dir->flags & P11_SAVE_OVERWRITE) - ret = cleanup_directory (dir->path, dir->cache); - -#ifdef OS_UNIX - /* Try to set the mode of the directory to readable */ - if (ret && chmod (dir->path, S_IRUSR | S_IXUSR | S_IRGRP | - S_IXGRP | S_IROTH | S_IXOTH) < 0) { - p11_message_err (errno, "couldn't set directory permissions: %s", dir->path); - ret = false; - } -#endif /* OS_UNIX */ - } - - p11_dict_free (dir->cache); - free (dir->path); - free (dir); - - return ret; -} |