X-Git-Url: http://git.tuebingen.mpg.de/?p=adu.git;a=blobdiff_plain;f=fd.c;h=902e8f1898d29c7ace5a481c4f731ce7134f4433;hp=cfef4d9a663268d24c130ecf11fee71fac0864a9;hb=4884395952589ec5310ad6220928d4bd25ab10cb;hpb=a4cf08e8062d1d73c343a628563acf4d9f454742 diff --git a/fd.c b/fd.c index cfef4d9..902e8f1 100644 --- a/fd.c +++ b/fd.c @@ -1,208 +1,73 @@ /* - * Copyright (C) 2006-2008 Andre Noll + * Copyright (C) 2006-2008 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ -/** \file fd.c Helper functions for file descriptor handling. */ +/** \file fd.c \brief Helper functions for file descriptor handling. */ #include #include #include -#include -#include +#include #include "adu.h" #include "error.h" +#include "string.h" +#include "fd.h" /** - * Write a buffer to a file descriptor, re-write on short writes. + * Wrapper for the write system call. * - * \param fd The file descriptor. - * \param buf The buffer to be sent. - * \param len The length of \a buf. + * \param fd The file descriptor to write to. + * \param buf The buffer to write. + * \param size The length of \a buf in bytes. * - * \return Standard. In any case, the number of bytes that have been written is - * stored in \a len. - */ -int write_all(int fd, const char *buf, size_t *len) -{ - size_t total = *len; - - assert(total); - *len = 0; - while (*len < total) { - int ret = write(fd, buf + *len, total - *len); - if (ret == -1) - return -ERRNO_TO_ERROR(errno); - *len += ret; - } - return 1; -} - -/** - * Check whether a file exists. - * - * \param fn The file name. - * - * \return Non-zero iff file exists. - */ -int file_exists(const char *fn) -{ - struct stat statbuf; - - return !stat(fn, &statbuf); -} - -/** - * Paraslash's wrapper for select(2). - * - * It calls select(2) (with no exceptfds) and starts over if select() was - * interrupted by a signal. - * - * \param n The highest-numbered descriptor in any of the two sets, plus 1. - * \param readfds fds that should be checked for readability. - * \param writefds fds that should be checked for writablility. - * \param timeout_tv upper bound on the amount of time elapsed before select() - * returns. - * - * \return The return value of the underlying select() call on success, the - * negative system error code on errors. - * - * All arguments are passed verbatim to select(2). - * \sa select(2) select_tut(2). - */ -int para_select(int n, fd_set *readfds, fd_set *writefds, - struct timeval *timeout_tv) -{ - int ret, err; - do { - ret = select(n, readfds, writefds, NULL, timeout_tv); - err = errno; - } while (ret < 0 && err == EINTR); - if (ret < 0) - return -ERRNO_TO_ERROR(errno); - return ret; -} - -/** - * Set a file descriptor to blocking mode. - * - * \param fd The file descriptor. + * This function writes out the given buffer and retries if an interrupt + * occurred during the write. The file descriptor is assumed to be in blocking + * mode (i.e., EAGAIN is treated as an error). * * \return Standard. - */ -__must_check int mark_fd_blocking(int fd) -{ - int flags = fcntl(fd, F_GETFL); - if (flags < 0) - return -ERRNO_TO_ERROR(errno); - flags = fcntl(fd, F_SETFL, ((long)flags) & ~O_NONBLOCK); - if (flags < 0) - return -ERRNO_TO_ERROR(errno); - return 1; -} - -/** - * Set a file descriptor to non-blocking mode. * - * \param fd The file descriptor. - * - * \return Standard. + * \sa write(2). */ -__must_check int mark_fd_nonblocking(int fd) -{ - int flags = fcntl(fd, F_GETFL); - if (flags < 0) - return -ERRNO_TO_ERROR(errno); - flags = fcntl(fd, F_SETFL, ((long)flags) | O_NONBLOCK); - if (flags < 0) - return -ERRNO_TO_ERROR(errno); - return 1; -} - -/** - * Set a file descriptor in a fd_set. - * - * \param fd The file descriptor to be set. - * \param fds The file descriptor set. - * \param max_fileno Highest-numbered file descriptor. - * - * This wrapper for FD_SET() passes its first two arguments to \p FD_SET. Upon - * return, \a max_fileno contains the maximum of the old_value and \a fd. - * - * \sa para_select. -*/ -void para_fd_set(int fd, fd_set *fds, int *max_fileno) +static ssize_t __write(int fd, const void *buf, size_t size) { + ssize_t ret; - if (fd < 0 || fd >= FD_SETSIZE) { - EMERG_LOG("fatal: tried to add invalid fd %d\n", fd); - exit(EXIT_FAILURE); + for (;;) { + ret = write(fd, buf, size); + if (ret < 0 && errno == EINTR) + continue; + return ret >= 0? ret : -ERRNO_TO_ERROR(errno); } -#if 0 - { - int flags = fcntl(fd, F_GETFL); - if (!(flags & O_NONBLOCK)) { - EMERG_LOG("fd %d is a blocking file descriptor\n", fd); - exit(EXIT_FAILURE); - } - } -#endif - FD_SET(fd, fds); - *max_fileno = MAX(*max_fileno, fd); } /** - * Paraslash's wrapper for fgets(3). - * - * \param line Pointer to the buffer to store the line. - * \param size The size of the buffer given by \a line. - * \param f The stream to read from. + * Write the whole buffer to a file descriptor. * - * \return Unlike the standard fgets() function, an integer value - * is returned. On success, this function returns 1. On errors, -E_FGETS - * is returned. A zero return value indicates an end of file condition. - */ -__must_check int para_fgets(char *line, int size, FILE *f) -{ -again: - if (fgets(line, size, f)) - return 1; - if (feof(f)) - return 0; - if (!ferror(f)) - return -E_FGETS; - if (errno != EINTR) { - ERROR_LOG("%s\n", strerror(errno)); - return -E_FGETS; - } - clearerr(f); - goto again; -} - -/** - * Paraslash's wrapper for mmap. + * \param fd The file descriptor to write to. + * \param buf The buffer to write. + * \param size The length of \a buf in bytes. * - * \param length Number of bytes to mmap. - * \param prot Either PROT_NONE or the bitwise OR of one or more of - * PROT_EXEC PROT_READ PROT_WRITE. - * \param flags Exactly one of MAP_SHARED and MAP_PRIVATE. - * \param fd The file to mmap from. - * \param offset Mmap start. + * This function writes the given buffer and continues on short writes and + * when interrupted by a signal. * - * \return This function either returns a valid pointer to the mapped area - * or calls exit() on errors. + * \return Standard. */ -void *para_mmap(size_t length, int prot, int flags, int fd, off_t offset) +static ssize_t write_all(int fd, const void *buf, size_t size) { - void *ret = mmap(NULL, length, prot, flags, fd, offset); - if (ret != MAP_FAILED) - return ret; - EMERG_LOG("mmap failed: %s\n", strerror(errno)); - EMERG_LOG("length: %zu, flags: %d, fd: %d, offset: %zu\n", - length, flags, fd, (size_t)offset); - exit(EXIT_FAILURE); +// DEBUG_LOG("writing %zu bytes\n", size); + const char *b = buf; + while (size) { + ssize_t ret = __write(fd, b, size); +// DEBUG_LOG("ret: %zd\n", ret); + if (ret < 0) + return ret; + b += ret; + size -= ret; + } + return 1; } /** @@ -219,7 +84,7 @@ void *para_mmap(size_t length, int prot, int flags, int fd, off_t offset) * * \sa open(2). */ -int para_open(const char *path, int flags, mode_t mode) +static int __open(const char *path, int flags, mode_t mode) { int ret = open(path, flags, mode); @@ -228,6 +93,32 @@ int para_open(const char *path, int flags, mode_t mode) return -ERRNO_TO_ERROR(errno); } +/** + * Open a file, write the given buffer and close the file. + * + * \param filename Full path to the file to open. + * \param buf The buffer to write to the file. + * \param size The size of \a buf. + * + * \return Standard. + */ +int adu_write_file(const char *filename, const void *buf, size_t size) +{ + int ret, fd; + + ret = __open(filename, O_WRONLY | O_CREAT | O_EXCL, 0644); + if (ret < 0) + return ret; + fd = ret; + ret = write_all(fd, buf, size); + if (ret < 0) + goto out; + ret = 1; +out: + close(fd); + return ret; +} + /** * Wrapper for chdir(2). * @@ -235,7 +126,7 @@ int para_open(const char *path, int flags, mode_t mode) * * \return Standard. */ -int para_chdir(const char *path) +static int __chdir(const char *path) { int ret = chdir(path); @@ -268,17 +159,17 @@ int para_chdir(const char *path) * \sa getcwd(3). * */ -int para_opendir(const char *dirname, DIR **dir, int *cwd) +int adu_opendir(const char *dirname, DIR **dir, int *cwd) { int ret; if (cwd) { - ret = para_open(".", O_RDONLY, 0); + ret = __open(".", O_RDONLY, 0); if (ret < 0) return ret; *cwd = ret; } - ret = para_chdir(dirname); + ret = __chdir(dirname); if (ret < 0) goto close_cwd; *dir = opendir("."); @@ -301,7 +192,7 @@ close_cwd: * * \return Standard. */ -int para_fchdir(int fd) +int adu_fchdir(int fd) { if (fchdir(fd) < 0) return -ERRNO_TO_ERROR(errno); @@ -309,51 +200,25 @@ int para_fchdir(int fd) } /** - * A wrapper for mkdir(2). - * - * \param path Name of the directory to create. - * \param mode The permissions to use. - * - * \return Standard. - */ -int para_mkdir(const char *path, mode_t mode) -{ - if (!mkdir(path, mode)) - return 1; - return -ERRNO_TO_ERROR(errno); -} - -/** - * Open a file and map it into memory. + * Open a file read-only and map it into memory. * * \param path Name of the regular file to map. - * \param open_mode Either \p O_RDONLY or \p O_RDWR. * \param map On success, the mapping is returned here. - * \param size size of the mapping. - * \param fd_ptr The file descriptor of the mapping. + * \param size Result parameter: size of the mapping in bytes. * - * If \a fd_ptr is \p NULL, the file descriptor resulting from the underlying - * open call is closed after mmap(). Otherwise the file is kept open and the - * file descriptor is returned in \a fd_ptr. + * The file will be mapped privately with memory protection PROT_READ. The file + * descriptor resulting from the underlying open call is closed after mmap(). * * \return Standard. * - * \sa para_open(), mmap(2). + * \sa mmap(2). */ -int mmap_full_file(const char *path, int open_mode, void **map, - size_t *size, int *fd_ptr) +int mmap_file_ro(const char *path, void **map, size_t *size) { - int fd, ret, mmap_prot, mmap_flags; + int fd, ret; struct stat file_status; - if (open_mode == O_RDONLY) { - mmap_prot = PROT_READ; - mmap_flags = MAP_PRIVATE; - } else { - mmap_prot = PROT_READ | PROT_WRITE; - mmap_flags = MAP_SHARED; - } - ret = para_open(path, open_mode, 0); + ret = __open(path, O_RDONLY, 0); if (ret < 0) return ret; fd = ret; @@ -366,7 +231,7 @@ int mmap_full_file(const char *path, int open_mode, void **map, DEBUG_LOG("%s: size %zu\n", path, *size); if (!*size) goto out; - *map = mmap(NULL, *size, mmap_prot, mmap_flags, fd, 0); + *map = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0); if (*map == MAP_FAILED) { *map = NULL; ret = -E_MMAP; @@ -374,10 +239,7 @@ int mmap_full_file(const char *path, int open_mode, void **map, } ret = 1; out: - if (ret < 0 || !fd_ptr) - close(fd); - else - *fd_ptr = fd; + close(fd); return ret; } @@ -391,7 +253,7 @@ out: * * \sa munmap(2), mmap_full_file(). */ -int para_munmap(void *start, size_t length) +int adu_munmap(void *start, size_t length) { int err; if (munmap(start, length) >= 0) @@ -402,27 +264,53 @@ int para_munmap(void *start, size_t length) return -ERRNO_TO_ERROR(err); } +__must_check __malloc static char *adu_dirname(const char *name) +{ + char *p, *ret; + + if (!name || !*name) + return NULL; + ret = adu_strdup(name); + p = strrchr(ret, '/'); + if (!p) + *ret = '\0'; + else + *p = '\0'; + return ret; +} + /** - * Check a file descriptor for writability. + * Recursive mkdir + * + * \param p Full path that should be created. * - * \param fd The file descriptor. + * \param mode Use this mode when creating directories. * - * \return positive if fd is ready for writing, zero if it isn't, negative if - * an error occurred. + * \return 0 if successful, -E_MKDIR on errors. */ - -int write_ok(int fd) +int mkpath(const char *p, mode_t mode) { - struct timeval tv = {0, 0}; - fd_set wfds; - int ret; -again: - FD_ZERO(&wfds); - FD_SET(fd, &wfds); - tv.tv_sec = 0; - tv.tv_usec = 0; - ret = select(fd + 1, NULL, &wfds, NULL, &tv); - if (ret < 0 && errno == EINTR) - goto again; + char *parent, *path; + int ret = -E_MKDIR; + + DEBUG_LOG("%s\n", p); + if (strcmp(p, ".") == 0 || strcmp(p, "/") == 0 || strcmp(p, "") == 0) { + DEBUG_LOG("reached beginning of path\n"); + return 0; + } + path = adu_strdup(p); + parent = adu_dirname(p); + if (!parent) + goto out; + ret = mkpath(parent, mode); + if (ret < 0) + goto out; + INFO_LOG("making dir %s\n", path); + ret = 0; + if ((mkdir(path, mode) == -1) && (errno != EEXIST)) + ret = -E_MKDIR; +out: + free(parent); + free(path); return ret; }