/* Chrysalide - Outil d'analyse de fichiers binaires * io.c - entrées sorties fiables * * Copyright (C) 2014-2017 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Chrysalide. If not, see . */ #include "io.h" #include #include #include #include #include #include #include #include #include #include #include #include "../core/logs.h" #include "../core/params.h" /****************************************************************************** * * * Paramètres : fd = flux ouvert en lecture. * * buf = données à recevoir. * * count = quantité de ces données. * * * * Description : Lit des données depuis un flux local. * * * * Retour : true si toutes les données ont été lues, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool safe_read(int fd, void *buf, size_t count) { uint8_t *iter; /* Données en attente */ size_t remaining; /* Quantité restante */ ssize_t got; /* Données envoyées */ iter = (uint8_t *)buf; remaining = count; while (remaining > 0) { got = read(fd, iter, remaining); if (got == -1) { if (errno == EINTR) continue; else { perror("read"); break; } } if (got == 0) break; iter += got; remaining -= got; } return (remaining == 0); } /****************************************************************************** * * * Paramètres : fd = flux ouvert en lecture. * * buf = données à recevoir. * * max = quantité maximale de ces données. * * * * Description : Lit des données depuis un flux local. * * * * Retour : Nombre d'octets lus, au pire 0 en cas d'erreur. * * * * Remarques : - * * * ******************************************************************************/ ssize_t safe_read_partial(int fd, void *buf, size_t max) { ssize_t result; /* Quantité lue à remonter */ uint8_t *iter; /* Données en attente */ size_t remaining; /* Quantité restante */ ssize_t got; /* Données envoyées */ result = 0; iter = (uint8_t *)buf; remaining = max; while (remaining > 0) { got = read(fd, iter, remaining); if (got == -1) { if (errno == EINTR) continue; else { perror("read"); break; } } if (got == 0) break; result += got; iter += got; remaining -= got; } return result; } /****************************************************************************** * * * Paramètres : fd = flux ouvert en écriture. * * buf = données à émettre. * * count = quantité de ces données. * * * * Description : Ecrit des données dans un flux local. * * * * Retour : true si toutes les données ont été écrites, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool safe_write(int fd, const void *buf, size_t count) { uint8_t *iter; /* Données en attente */ size_t remaining; /* Quantité restante */ ssize_t sent; /* Données envoyées */ iter = (uint8_t *)buf; remaining = count; while (remaining > 0) { sent = write(fd, iter, remaining); if (sent == -1) { if (errno == EINTR) continue; else { perror("write"); break; } } if (sent == 0) break; iter += sent; remaining -= sent; } return (remaining == 0); } /****************************************************************************** * * * Paramètres : sockfd = flux ouvert en lecture. * * buf = données à recevoir. * * len = quantité de ces données. * * flags = options de réception. * * * * Description : Réceptionne des données depuis un flux réseau. * * * * Retour : true si toutes les données ont été reçues, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool safe_recv(int sockfd, const void *buf, size_t len, int flags) { uint8_t *iter; /* Données en attente */ size_t remaining; /* Quantité restante */ ssize_t got; /* Données envoyées */ iter = (uint8_t *)buf; remaining = len; while (remaining > 0) { got = recv(sockfd, iter, remaining, MSG_NOSIGNAL | flags); if (got == -1) { if (errno == EINTR) continue; else { perror("recv"); break; } } iter += got; remaining -= got; } return (remaining == 0); } /****************************************************************************** * * * Paramètres : sockfd = flux ouvert en écriture. * * buf = données à émettre. * * len = quantité de ces données. * * flags = options d'envoi. * * * * Description : Envoie des données au travers un flux réseau. * * * * Retour : true si toutes les données ont été émises, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool safe_send(int sockfd, const void *buf, size_t len, int flags) { uint8_t *iter; /* Données en attente */ size_t remaining; /* Quantité restante */ ssize_t sent; /* Données envoyées */ iter = (uint8_t *)buf; remaining = len; while (remaining > 0) { sent = send(sockfd, iter, remaining, MSG_NOSIGNAL | flags); if (sent == -1) { if (errno == EINTR) continue; else { perror("send"); break; } } iter += sent; remaining -= sent; } return (remaining == 0); } /****************************************************************************** * * * Paramètres : path = chemin d'accès à valider. * * * * Description : S'assure qu'un chemin donné existe dans le système. * * * * Retour : 0 si le chemin est actuellement présent, -1 sinon. * * * * Remarques : - * * * ******************************************************************************/ int ensure_path_exists(const char *path) { int result; /* Bilan de l'assurance */ char *copy; /* Chemin libérable */ char *tmp; /* Chemin altérable */ copy = strdup(path); tmp = dirname(copy); result = access(tmp, W_OK | X_OK); if (result != 0) { result = ensure_path_exists(tmp); if (result == 0) result = mkdir(tmp, 0700); } free(copy); return result; } /****************************************************************************** * * * Paramètres : base = préfixe du nom du fichier temporaire à créer. * * filename = chemin d'accès complet au nouveau fichier. [OUT] * * * * Description : Met en place un fichier temporaire. * * * * Retour : Flux ouvert en lecture et écriture, ou -1 en cas d'erreur. * * * * Remarques : - * * * ******************************************************************************/ int make_tmp_file(const char *base, char **filename) { int result; /* Flux ou code à retourner */ const char *tmpdir; /* Répertoire d'accueil */ bool status; /* Bilan d'un consultation */ status = g_generic_config_get_value(get_main_configuration(), MPK_TMPDIR, &tmpdir); if (!status) return -1; asprintf(filename, "%s" G_DIR_SEPARATOR_S "%s-%d.XXXXXX", tmpdir, base, getpid()); result = ensure_path_exists(*filename); if (result == 0) { result = mkstemp(*filename); if (result == -1) perror("mkstemp"); } if (result == -1) { free(*filename); *filename = NULL; } return result; } /****************************************************************************** * * * Paramètres : base = préfixe du nom du fichier temporaire à créer. * * addr = adresse UNIX constituée. [OUT] * * * * Description : Met en place un canal UNIX temporaire. * * * * Retour : Bilan de la définition. * * * * Remarques : - * * * ******************************************************************************/ bool build_tmp_socket(const char *base, struct sockaddr_un *addr) { bool result; /* Bilan à retourner */ const char *tmpdir; /* Répertoire d'accueil */ bool status; /* Bilan d'un consultation */ char *path; /* Chemin d'accès au canal */ int ret; /* Bilan intermédiaire */ size_t length; /* Taille du chemin complet */ status = g_generic_config_get_value(get_main_configuration(), MPK_TMPDIR, &tmpdir); if (!status) return false; result = false; asprintf(&path, "%s" G_DIR_SEPARATOR_S "%s-%d", tmpdir, base, getpid()); ret = ensure_path_exists(path); if (ret != 0) goto mts_exit; length = strlen(path) + 1; #ifndef UNIX_PATH_MAX # define UNIX_PATH_MAX 108 #endif if (length > UNIX_PATH_MAX) { log_variadic_message(LMT_ERROR, _("Impossible to use '%s' as UNIX socket path: string is too long ! (%zu vs %u)\n"), path, length, UNIX_PATH_MAX); goto mts_exit; } memset(addr, 0, sizeof(struct sockaddr_un)); addr->sun_family = AF_UNIX; strncpy(addr->sun_path, path, UNIX_PATH_MAX - 1); result = true; mts_exit: free(path); return result; }