From ffe7f6fa57523cc174bf7253f396f0310f1b967d Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Fri, 2 Jan 2015 18:52:04 +0100 Subject: [PATCH] Adds new files support.c/h for low level support functions. --- Makefile.am | 5 +- cmdline/check.c | 1 + cmdline/dup.c | 1 + cmdline/elem.c | 1 + cmdline/handle.c | 2 +- cmdline/import.c | 1 + cmdline/nano.c | 2 +- cmdline/parity.c | 1 + cmdline/pool.c | 2 +- cmdline/scan.c | 2 +- cmdline/scrub.c | 2 +- cmdline/search.c | 1 + cmdline/snapraid.c | 2 +- cmdline/spin.c | 1 + cmdline/state.c | 2 +- cmdline/status.c | 2 +- cmdline/support.c | 397 ++++++++++++++++++++++++++++++++++++++ cmdline/support.h | 125 ++++++++++++ cmdline/sync.c | 2 +- cmdline/unix.c | 2 +- cmdline/util.c | 468 +++++---------------------------------------- cmdline/util.h | 103 ---------- tommyds/tommy.c | 2 +- 23 files changed, 591 insertions(+), 536 deletions(-) create mode 100644 cmdline/support.c create mode 100644 cmdline/support.h diff --git a/Makefile.am b/Makefile.am index 44d39bba..5fb213bc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,6 +16,7 @@ snapraid_SOURCES = \ tommyds/tommy.c \ cmdline/snapraid.c \ cmdline/util.c \ + cmdline/support.c \ cmdline/elem.c \ cmdline/state.c \ cmdline/scan.c \ @@ -66,6 +67,7 @@ noinst_HEADERS = \ cmdline/portable.h \ cmdline/snapraid.h \ cmdline/util.h \ + cmdline/support.h \ cmdline/elem.h \ cmdline/state.h \ cmdline/parity.h \ @@ -82,7 +84,8 @@ noinst_HEADERS = \ mktest_SOURCES = \ cmdline/mktest.c \ - cmdline/mingw.c + cmdline/mingw.c \ + cmdline/support.c EXTRA_DIST = \ autogen.sh \ diff --git a/cmdline/check.c b/cmdline/check.c index be32a7e7..7f1978b9 100644 --- a/cmdline/check.c +++ b/cmdline/check.c @@ -17,6 +17,7 @@ #include "portable.h" +#include "support.h" #include "util.h" #include "elem.h" #include "import.h" diff --git a/cmdline/dup.c b/cmdline/dup.c index 806e0961..dc4d2e10 100644 --- a/cmdline/dup.c +++ b/cmdline/dup.c @@ -17,6 +17,7 @@ #include "portable.h" +#include "support.h" #include "util.h" #include "elem.h" #include "state.h" diff --git a/cmdline/elem.c b/cmdline/elem.c index 4b0edeeb..e3cab4fd 100644 --- a/cmdline/elem.c +++ b/cmdline/elem.c @@ -18,6 +18,7 @@ #include "portable.h" #include "elem.h" +#include "support.h" #include "util.h" /****************************************************************************/ diff --git a/cmdline/handle.c b/cmdline/handle.c index 3ebea4e6..11958248 100644 --- a/cmdline/handle.c +++ b/cmdline/handle.c @@ -18,7 +18,7 @@ #include "portable.h" #include "elem.h" -#include "util.h" +#include "support.h" #include "handle.h" /****************************************************************************/ diff --git a/cmdline/import.c b/cmdline/import.c index b18f160d..fe85404c 100644 --- a/cmdline/import.c +++ b/cmdline/import.c @@ -17,6 +17,7 @@ #include "portable.h" +#include "support.h" #include "import.h" /****************************************************************************/ diff --git a/cmdline/nano.c b/cmdline/nano.c index 1fdedae9..80e795ff 100644 --- a/cmdline/nano.c +++ b/cmdline/nano.c @@ -17,7 +17,7 @@ #include "portable.h" -#include "util.h" +#include "support.h" #include "elem.h" #include "state.h" #include "handle.h" diff --git a/cmdline/parity.c b/cmdline/parity.c index 53d64228..880541df 100644 --- a/cmdline/parity.c +++ b/cmdline/parity.c @@ -17,6 +17,7 @@ #include "portable.h" +#include "support.h" #include "elem.h" #include "state.h" #include "parity.h" diff --git a/cmdline/pool.c b/cmdline/pool.c index 0bc7da36..48de6c4e 100644 --- a/cmdline/pool.c +++ b/cmdline/pool.c @@ -17,7 +17,7 @@ #include "portable.h" -#include "util.h" +#include "support.h" #include "elem.h" #include "state.h" diff --git a/cmdline/scan.c b/cmdline/scan.c index cf92252e..53bb3712 100644 --- a/cmdline/scan.c +++ b/cmdline/scan.c @@ -17,7 +17,7 @@ #include "portable.h" -#include "util.h" +#include "support.h" #include "elem.h" #include "state.h" diff --git a/cmdline/scrub.c b/cmdline/scrub.c index cec1c7a9..3961dcd9 100644 --- a/cmdline/scrub.c +++ b/cmdline/scrub.c @@ -17,7 +17,7 @@ #include "portable.h" -#include "util.h" +#include "support.h" #include "elem.h" #include "state.h" #include "parity.h" diff --git a/cmdline/search.c b/cmdline/search.c index 87e6e524..5ebf7ffc 100644 --- a/cmdline/search.c +++ b/cmdline/search.c @@ -17,6 +17,7 @@ #include "portable.h" +#include "support.h" #include "search.h" /****************************************************************************/ diff --git a/cmdline/snapraid.c b/cmdline/snapraid.c index 675b7d81..14ce7138 100644 --- a/cmdline/snapraid.c +++ b/cmdline/snapraid.c @@ -18,7 +18,7 @@ #include "portable.h" #include "snapraid.h" -#include "util.h" +#include "support.h" #include "elem.h" #include "import.h" #include "search.h" diff --git a/cmdline/spin.c b/cmdline/spin.c index d7bf135b..8b6eee21 100644 --- a/cmdline/spin.c +++ b/cmdline/spin.c @@ -17,6 +17,7 @@ #include "portable.h" +#include "support.h" #include "state.h" void state_spin(struct snapraid_state* state, int operation) diff --git a/cmdline/state.c b/cmdline/state.c index eac77fdc..6d18fc25 100644 --- a/cmdline/state.c +++ b/cmdline/state.c @@ -21,7 +21,7 @@ #include "import.h" #include "search.h" #include "state.h" -#include "util.h" +#include "support.h" #include "parity.h" #include "raid/raid.h" #include "raid/cpu.h" diff --git a/cmdline/status.c b/cmdline/status.c index 40639c59..9f375cd8 100644 --- a/cmdline/status.c +++ b/cmdline/status.c @@ -17,7 +17,7 @@ #include "portable.h" -#include "util.h" +#include "support.h" #include "elem.h" #include "state.h" #include "parity.h" diff --git a/cmdline/support.c b/cmdline/support.c new file mode 100644 index 00000000..63b81672 --- /dev/null +++ b/cmdline/support.c @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2011 Andrea Mazzoleni + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include "portable.h" + +#include "support.h" + +/****************************************************************************/ +/* path */ + +void pathcpy(char* dst, size_t size, const char* src) +{ + size_t len = strlen(src); + + if (len + 1 > size) { + /* LCOV_EXCL_START */ + fprintf(stderr, "Path too long\n"); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + + memcpy(dst, src, len + 1); +} + +void pathcat(char* dst, size_t size, const char* src) +{ + size_t dst_len = strlen(dst); + size_t src_len = strlen(src); + + if (dst_len + src_len + 1 > size) { + /* LCOV_EXCL_START */ + fprintf(stderr, "Path too long\n"); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + + memcpy(dst + dst_len, src, src_len + 1); +} + +void pathcatc(char* dst, size_t size, char c) +{ + size_t dst_len = strlen(dst); + + if (dst_len + 2 > size) { + /* LCOV_EXCL_START */ + fprintf(stderr, "Path too long\n"); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + + dst[dst_len] = c; + dst[dst_len + 1] = 0; +} + +void pathimport(char* dst, size_t size, const char* src) +{ + pathcpy(dst, size, src); + +#ifdef _WIN32 + /* convert all Windows '\' to C '/' */ + while (*dst) { + if (*dst == '\\') + *dst = '/'; + ++dst; + } +#endif +} + +void pathexport(char* dst, size_t size, const char* src) +{ + pathcpy(dst, size, src); + +#ifdef _WIN32 + /* convert all C '/' to Windows '\' */ + while (*dst) { + if (*dst == '/') + *dst = '\\'; + ++dst; + } +#endif +} + +void pathprint(char* dst, size_t size, const char* format, ...) +{ + size_t len; + va_list ap; + + va_start(ap, format); + len = vsnprintf(dst, size, format, ap); + va_end(ap); + + if (len >= size) { + /* LCOV_EXCL_START */ + fprintf(stderr, "Path too long\n"); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } +} + +void pathslash(char* dst, size_t size) +{ + size_t len = strlen(dst); + + if (len > 0 && dst[len - 1] != '/') { + if (len + 2 >= size) { + /* LCOV_EXCL_START */ + fprintf(stderr, "Path too long\n"); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + + dst[len] = '/'; + dst[len + 1] = 0; + } +} + +void pathcut(char* dst) +{ + char* slash = strrchr(dst, '/'); + if (slash) + slash[1] = 0; + else + dst[0] = 0; +} + +int pathcmp(const char* a, const char* b) +{ +#ifdef _WIN32 + char ai[PATH_MAX]; + char bi[PATH_MAX]; + + /* import to convert \ to / */ + pathimport(ai, sizeof(ai), a); + pathimport(bi, sizeof(bi), b); + + /* case insensitive compare in Windows */ + return stricmp(ai, bi); +#else + return strcmp(a, b); +#endif +} + +/****************************************************************************/ +/* filesystem */ + +int mkancestor(const char* file) +{ + char dir[PATH_MAX]; + struct stat st; + char* c; + + pathcpy(dir, sizeof(dir), file); + + c = strrchr(dir, '/'); + if (!c) { + /* no ancestor */ + return 0; + } + + /* clear the file */ + *c = 0; + + /* if it's the root dir */ + if (*dir == 0) { + /* nothing more to do */ + return 0; + } + +#ifdef _WIN32 + /* if it's a drive specificaion like "C:" */ + if (isalpha(dir[0]) && dir[1] == ':' && dir[2] == 0) { + /* nothing more to do */ + return 0; + } +#endif + + /* + * Check if the dir already exists using lstat(). + * + * Note that in Windows when dealing with read-only media + * you cannot try to create the directory, and expecting + * the EEXIST error because the call will fail with ERROR_WRITE_PROTECTED. + * + * Also in Windows it's better to use lstat() than stat() because it + * doen't need to open the dir with CreateFile(). + */ + if (lstat(dir, &st) == 0) { + /* it already exists */ + return 0; + } + + /* recursively create them all */ + if (mkancestor(dir) != 0) { + /* LCOV_EXCL_START */ + return -1; + /* LCOV_EXCL_STOP */ + } + + /* create it */ + if (mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { + /* LCOV_EXCL_START */ + fprintf(stderr, "Error creating directory '%s'. %s.\n", dir, strerror(errno)); + return -1; + /* LCOV_EXCL_STOP */ + } + + return 0; +} + +int fmtime(int f, int64_t mtime_sec, int mtime_nsec) +{ +#if HAVE_FUTIMENS + struct timespec tv[2]; +#else + struct timeval tv[2]; +#endif + int ret; + +#if HAVE_FUTIMENS /* futimens() is preferred because it gives nanosecond precision */ + tv[0].tv_sec = mtime_sec; + if (mtime_nsec != STAT_NSEC_INVALID) + tv[0].tv_nsec = mtime_nsec; + else + tv[0].tv_nsec = 0; + tv[1].tv_sec = tv[0].tv_sec; + tv[1].tv_nsec = tv[0].tv_nsec; + + ret = futimens(f, tv); +#elif HAVE_FUTIMES /* fallback to futimes() if nanosecond precision is not available */ + tv[0].tv_sec = mtime_sec; + if (mtime_nsec != STAT_NSEC_INVALID) + tv[0].tv_usec = mtime_nsec / 1000; + else + tv[0].tv_usec = 0; + tv[1].tv_sec = tv[0].tv_sec; + tv[1].tv_usec = tv[0].tv_usec; + + ret = futimes(f, tv); +#elif HAVE_FUTIMESAT /* fallback to futimesat() for Solaris, it only has futimesat() */ + tv[0].tv_sec = mtime_sec; + if (mtime_nsec != STAT_NSEC_INVALID) + tv[0].tv_usec = mtime_nsec / 1000; + else + tv[0].tv_usec = 0; + tv[1].tv_sec = tv[0].tv_sec; + tv[1].tv_usec = tv[0].tv_usec; + + ret = futimesat(f, 0, tv); +#else +#error No function available to set file timestamps with sub-second precision +#endif + + return ret; +} + +/****************************************************************************/ +/* memory */ + +static size_t mcounter; + +size_t malloc_counter(void) +{ + return mcounter; +} + +static ssize_t malloc_print(int f, const char* str) +{ + ssize_t len = 0; + while (str[len]) + ++len; + return write(f, str, len); +} + +static ssize_t malloc_printn(int f, size_t value) +{ + char buf[32]; + int i; + + if (!value) + return write(f, "0", 1); + + i = sizeof(buf); + while (value) { + buf[--i] = (value % 10) + '0'; + value /= 10; + } + + return write(f, buf + i, sizeof(buf) - i); +} + +void malloc_fail(size_t size) +{ + /* don't use printf to avoid any possible extra allocation */ + /* LCOV_EXCL_START */ + int f = 2; /* stderr */ + + malloc_print(f, "Failed for Low Memory!\n"); + malloc_print(f, "Allocating "); + malloc_printn(f, size); + malloc_print(f, " bytes.\n"); + malloc_print(f, "Already allocated "); + malloc_printn(f, malloc_counter()); + malloc_print(f, " bytes.\n"); + if (sizeof(void*) == 4) { + malloc_print(f, "You are currently using a 32 bits executable.\n"); + malloc_print(f, "If you have more than 4GB of memory, please upgrade to a 64 bits one.\n"); + } + /* LCOV_EXCL_STOP */ +} + +void* malloc_nofail(size_t size) +{ + void* ptr = malloc(size); + + if (!ptr) { + /* LCOV_EXCL_START */ + malloc_fail(size); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + +#ifndef CHECKER /* Don't preinitialize when running for valgrind */ + /* Here we preinitialize the memory to ensure that the OS is really allocating it */ + /* and not only reserving the addressable space. */ + /* Otherwise we are risking that the OOM (Out Of Memory) killer in Linux will kill the process. */ + /* Filling the memory doesn't ensure to disable OOM, but it increase a lot the chances to */ + /* get a real error from malloc() instead than a process killed. */ + /* Note that calloc() doesn't have the same effect. */ + memset(ptr, 0xA5, size); +#endif + + mcounter += size; + + return ptr; +} + +void* calloc_nofail(size_t count, size_t size) +{ + void* ptr; + + size *= count; + + /* see the note in malloc_nofail() of why we don't use calloc() */ + ptr = malloc(size); + + if (!ptr) { + /* LCOV_EXCL_START */ + malloc_fail(size); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + + memset(ptr, 0, size); + + mcounter += size; + + return ptr; +} + +char* strdup_nofail(const char* str) +{ + size_t size; + char* ptr; + + size = strlen(str) + 1; + + ptr = malloc(size); + + if (!ptr) { + /* LCOV_EXCL_START */ + malloc_fail(size); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + + memcpy(ptr, str, size); + + mcounter += size; + + return ptr; +} + + diff --git a/cmdline/support.h b/cmdline/support.h new file mode 100644 index 00000000..99f82cce --- /dev/null +++ b/cmdline/support.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011 Andrea Mazzoleni + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef __SUPPORT_H +#define __SUPPORT_H + +/****************************************************************************/ +/* path */ + +/** + * Copies a path limiting the size. + * Aborts if too long. + */ +void pathcpy(char* dst, size_t size, const char* src); + +/** + * Concatenates a path limiting the size. + * Aborts if too long. + */ +void pathcat(char* dst, size_t size, const char* src); + +/** + * Concatenates a path limiting the size. + * Aborts if too long. + */ +void pathcatc(char* dst, size_t size, char c); + +/** + * Imports a path limiting the size. + * In Windows all the backslash are converted to the C standard of forward slash. + * Aborts if too long. + */ +void pathimport(char* dst, size_t size, const char* src); + +/** + * Exports a path limiting the size. + * In Windows all the C slashes are converted to the Windows backslash. + * Aborts if too long. + */ +void pathexport(char* dst, size_t size, const char* src); + +/** + * Prints a path. + * Aborts if too long. + */ +void pathprint(char* dst, size_t size, const char* format, ...); + +/** + * Ensures the presence of a terminating slash, if it isn't empty. + * Aborts if too long. + */ +void pathslash(char* dst, size_t size); + +/** + * Cuts everything after the latest slash. + */ +void pathcut(char* dst); + +/** + * Compare two paths. + * In Windows it's case insentive and assumes \ equal at /. + */ +int pathcmp(const char* a, const char* b); + +/****************************************************************************/ +/* filesystem */ + +/** + * Creates all the ancestor directories if missing. + * The file name, after the last /, is ignored. + */ +int mkancestor(const char* file); + +/** + * Changes the modification time of an open file. + */ +int fmtime(int f, int64_t mtime_sec, int mtime_nsec); + +/****************************************************************************/ +/* memory */ + +/** + * Return the size of the allocated memory. + */ +size_t malloc_counter(void); + +/** + * Safe malloc. + * If no memory is available, it aborts. + */ +void* malloc_nofail(size_t size); + +/** + * Safe cmalloc. + * If no memory is available, it aborts. + */ +void* calloc_nofail(size_t count, size_t size); + +/** + * Safe strdup. + * If no memory is available, it aborts. + */ +char* strdup_nofail(const char* str); + +/** + * Helper for printing an error about a failed allocation. + */ +void malloc_fail(size_t size); + +#endif + diff --git a/cmdline/sync.c b/cmdline/sync.c index 835180d1..e7a75687 100644 --- a/cmdline/sync.c +++ b/cmdline/sync.c @@ -17,7 +17,7 @@ #include "portable.h" -#include "util.h" +#include "support.h" #include "elem.h" #include "state.h" #include "parity.h" diff --git a/cmdline/unix.c b/cmdline/unix.c index 304ddaa4..fc96796b 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -19,7 +19,7 @@ #ifndef __MINGW32__ /* Only for Unix */ -#include "util.h" +#include "support.h" /** * Standard exit codes. diff --git a/cmdline/util.c b/cmdline/util.c index ef6ef0a5..1d737c84 100644 --- a/cmdline/util.c +++ b/cmdline/util.c @@ -17,6 +17,7 @@ #include "portable.h" +#include "support.h" #include "util.h" #include "raid/cpu.h" #include "raid/memory.h" @@ -886,6 +887,52 @@ int ssync(STREAM* s) } #endif +/****************************************************************************/ +/* memory */ + +void* malloc_nofail_align(size_t size, void** freeptr) +{ + void* ptr; + + ptr = raid_malloc_align(size, freeptr); + + if (!ptr) { + /* LCOV_EXCL_START */ + malloc_fail(size); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + + return ptr; +} + +void** malloc_nofail_vector_align(int nd, int n, size_t size, void** freeptr) +{ + void* ptr; + + ptr = raid_malloc_vector(nd, n, size, freeptr); + + if (!ptr) { + /* LCOV_EXCL_START */ + malloc_fail(n * size); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + + return ptr; +} + +void mtest_vector(int n, size_t size, void** vv) +{ + if (raid_mtest_vector(n, size, vv) != 0) { + /* LCOV_EXCL_START */ + fprintf(stderr, "DANGER! Your RAM memory is broken! DO NOT PROCEED UNTIL FIXED!\n"); + fprintf(stderr, "Try running a memory test like http://www.memtest86.com/\n"); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } +} + /****************************************************************************/ /* crc */ @@ -1234,378 +1281,6 @@ void crc32c_init(void) #endif } -/****************************************************************************/ -/* path */ - -void pathcpy(char* dst, size_t size, const char* src) -{ - size_t len = strlen(src); - - if (len + 1 > size) { - /* LCOV_EXCL_START */ - fprintf(stderr, "Path too long\n"); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - - memcpy(dst, src, len + 1); -} - -void pathcat(char* dst, size_t size, const char* src) -{ - size_t dst_len = strlen(dst); - size_t src_len = strlen(src); - - if (dst_len + src_len + 1 > size) { - /* LCOV_EXCL_START */ - fprintf(stderr, "Path too long\n"); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - - memcpy(dst + dst_len, src, src_len + 1); -} - -void pathcatc(char* dst, size_t size, char c) -{ - size_t dst_len = strlen(dst); - - if (dst_len + 2 > size) { - /* LCOV_EXCL_START */ - fprintf(stderr, "Path too long\n"); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - - dst[dst_len] = c; - dst[dst_len + 1] = 0; -} - -void pathimport(char* dst, size_t size, const char* src) -{ - pathcpy(dst, size, src); - -#ifdef _WIN32 - /* convert all Windows '\' to C '/' */ - while (*dst) { - if (*dst == '\\') - *dst = '/'; - ++dst; - } -#endif -} - -void pathexport(char* dst, size_t size, const char* src) -{ - pathcpy(dst, size, src); - -#ifdef _WIN32 - /* convert all C '/' to Windows '\' */ - while (*dst) { - if (*dst == '/') - *dst = '\\'; - ++dst; - } -#endif -} - -void pathprint(char* dst, size_t size, const char* format, ...) -{ - size_t len; - va_list ap; - - va_start(ap, format); - len = vsnprintf(dst, size, format, ap); - va_end(ap); - - if (len >= size) { - /* LCOV_EXCL_START */ - fprintf(stderr, "Path too long\n"); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } -} - -void pathslash(char* dst, size_t size) -{ - size_t len = strlen(dst); - - if (len > 0 && dst[len - 1] != '/') { - if (len + 2 >= size) { - /* LCOV_EXCL_START */ - fprintf(stderr, "Path too long\n"); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - - dst[len] = '/'; - dst[len + 1] = 0; - } -} - -void pathcut(char* dst) -{ - char* slash = strrchr(dst, '/'); - if (slash) - slash[1] = 0; - else - dst[0] = 0; -} - -int pathcmp(const char* a, const char* b) -{ -#ifdef _WIN32 - char ai[PATH_MAX]; - char bi[PATH_MAX]; - - /* import to convert \ to / */ - pathimport(ai, sizeof(ai), a); - pathimport(bi, sizeof(bi), b); - - /* case insensitive compare in Windows */ - return stricmp(ai, bi); -#else - return strcmp(a, b); -#endif -} - -/****************************************************************************/ -/* filesystem */ - -int mkancestor(const char* file) -{ - char dir[PATH_MAX]; - struct stat st; - char* c; - - pathcpy(dir, sizeof(dir), file); - - c = strrchr(dir, '/'); - if (!c) { - /* no ancestor */ - return 0; - } - - /* clear the file */ - *c = 0; - - /* if it's the root dir */ - if (*dir == 0) { - /* nothing more to do */ - return 0; - } - -#ifdef _WIN32 - /* if it's a drive specificaion like "C:" */ - if (isalpha(dir[0]) && dir[1] == ':' && dir[2] == 0) { - /* nothing more to do */ - return 0; - } -#endif - - /* - * Check if the dir already exists using lstat(). - * - * Note that in Windows when dealing with read-only media - * you cannot try to create the directory, and expecting - * the EEXIST error because the call will fail with ERROR_WRITE_PROTECTED. - * - * Also in Windows it's better to use lstat() than stat() because it - * doen't need to open the dir with CreateFile(). - */ - if (lstat(dir, &st) == 0) { - /* it already exists */ - return 0; - } - - /* recursively create them all */ - if (mkancestor(dir) != 0) { - /* LCOV_EXCL_START */ - return -1; - /* LCOV_EXCL_STOP */ - } - - /* create it */ - if (mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { - /* LCOV_EXCL_START */ - fprintf(stderr, "Error creating directory '%s'. %s.\n", dir, strerror(errno)); - return -1; - /* LCOV_EXCL_STOP */ - } - - return 0; -} - -/****************************************************************************/ -/* mem */ - -static size_t mcounter; - -size_t malloc_counter(void) -{ - return mcounter; -} - -static ssize_t malloc_print(int f, const char* str) -{ - ssize_t len = 0; - while (str[len]) - ++len; - return write(f, str, len); -} - -static ssize_t malloc_printn(int f, size_t value) -{ - char buf[32]; - int i; - - if (!value) - return write(f, "0", 1); - - i = sizeof(buf); - while (value) { - buf[--i] = (value % 10) + '0'; - value /= 10; - } - - return write(f, buf + i, sizeof(buf) - i); -} - -static void malloc_fail(size_t size) -{ - /* don't use printf to avoid any possible extra allocation */ - /* LCOV_EXCL_START */ - int f = 2; /* stderr */ - - malloc_print(f, "Failed for Low Memory!\n"); - malloc_print(f, "Allocating "); - malloc_printn(f, size); - malloc_print(f, " bytes.\n"); - malloc_print(f, "Already allocated "); - malloc_printn(f, malloc_counter()); - malloc_print(f, " bytes.\n"); - if (sizeof(void*) == 4) { - malloc_print(f, "You are currently using a 32 bits executable.\n"); - malloc_print(f, "If you have more than 4GB of memory, please upgrade to a 64 bits one.\n"); - } - /* LCOV_EXCL_STOP */ -} - -void* malloc_nofail(size_t size) -{ - void* ptr = malloc(size); - - if (!ptr) { - /* LCOV_EXCL_START */ - malloc_fail(size); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - -#ifndef CHECKER /* Don't preinitialize when running for valgrind */ - /* Here we preinitialize the memory to ensure that the OS is really allocating it */ - /* and not only reserving the addressable space. */ - /* Otherwise we are risking that the OOM (Out Of Memory) killer in Linux will kill the process. */ - /* Filling the memory doesn't ensure to disable OOM, but it increase a lot the chances to */ - /* get a real error from malloc() instead than a process killed. */ - /* Note that calloc() doesn't have the same effect. */ - memset(ptr, 0xA5, size); -#endif - - mcounter += size; - - return ptr; -} - -void* calloc_nofail(size_t count, size_t size) -{ - void* ptr; - - size *= count; - - /* see the note in malloc_nofail() of why we don't use calloc() */ - ptr = malloc(size); - - if (!ptr) { - /* LCOV_EXCL_START */ - malloc_fail(size); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - - memset(ptr, 0, size); - - mcounter += size; - - return ptr; -} - -char* strdup_nofail(const char* str) -{ - size_t size; - char* ptr; - - size = strlen(str) + 1; - - ptr = malloc(size); - - if (!ptr) { - /* LCOV_EXCL_START */ - malloc_fail(size); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - - memcpy(ptr, str, size); - - mcounter += size; - - return ptr; -} - -void* malloc_nofail_align(size_t size, void** freeptr) -{ - void* ptr; - - ptr = raid_malloc_align(size, freeptr); - - if (!ptr) { - /* LCOV_EXCL_START */ - malloc_fail(size); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - - return ptr; -} - -void** malloc_nofail_vector_align(int nd, int n, size_t size, void** freeptr) -{ - void* ptr; - - ptr = raid_malloc_vector(nd, n, size, freeptr); - - if (!ptr) { - /* LCOV_EXCL_START */ - malloc_fail(n * size); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - - return ptr; -} - -void mtest_vector(int n, size_t size, void** vv) -{ - if (raid_mtest_vector(n, size, vv) != 0) { - /* LCOV_EXCL_START */ - fprintf(stderr, "DANGER! Your RAM memory is broken! DO NOT PROCEED UNTIL FIXED!\n"); - fprintf(stderr, "Try running a memory test like http://www.memtest86.com/\n"); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } -} - /****************************************************************************/ /* byte operations */ @@ -1737,52 +1412,3 @@ int lock_unlock(int f) } #endif -/****************************************************************************/ -/* file */ - -int fmtime(int f, int64_t mtime_sec, int mtime_nsec) -{ -#if HAVE_FUTIMENS - struct timespec tv[2]; -#else - struct timeval tv[2]; -#endif - int ret; - -#if HAVE_FUTIMENS /* futimens() is preferred because it gives nanosecond precision */ - tv[0].tv_sec = mtime_sec; - if (mtime_nsec != STAT_NSEC_INVALID) - tv[0].tv_nsec = mtime_nsec; - else - tv[0].tv_nsec = 0; - tv[1].tv_sec = tv[0].tv_sec; - tv[1].tv_nsec = tv[0].tv_nsec; - - ret = futimens(f, tv); -#elif HAVE_FUTIMES /* fallback to futimes() if nanosecond precision is not available */ - tv[0].tv_sec = mtime_sec; - if (mtime_nsec != STAT_NSEC_INVALID) - tv[0].tv_usec = mtime_nsec / 1000; - else - tv[0].tv_usec = 0; - tv[1].tv_sec = tv[0].tv_sec; - tv[1].tv_usec = tv[0].tv_usec; - - ret = futimes(f, tv); -#elif HAVE_FUTIMESAT /* fallback to futimesat() for Solaris, it only has futimesat() */ - tv[0].tv_sec = mtime_sec; - if (mtime_nsec != STAT_NSEC_INVALID) - tv[0].tv_usec = mtime_nsec / 1000; - else - tv[0].tv_usec = 0; - tv[1].tv_sec = tv[0].tv_sec; - tv[1].tv_usec = tv[0].tv_usec; - - ret = futimesat(f, 0, tv); -#else -#error No function available to set file timestamps with sub-second precision -#endif - - return ret; -} - diff --git a/cmdline/util.h b/cmdline/util.h index 8f99990c..6867a027 100644 --- a/cmdline/util.h +++ b/cmdline/util.h @@ -388,93 +388,9 @@ int sputble32(uint32_t value, STREAM* s); */ int sputbs(const char* str, STREAM* s); -/****************************************************************************/ -/* path */ - -/** - * Copies a path limiting the size. - * Aborts if too long. - */ -void pathcpy(char* dst, size_t size, const char* src); - -/** - * Concatenates a path limiting the size. - * Aborts if too long. - */ -void pathcat(char* dst, size_t size, const char* src); - -/** - * Concatenates a path limiting the size. - * Aborts if too long. - */ -void pathcatc(char* dst, size_t size, char c); - -/** - * Imports a path limiting the size. - * In Windows all the backslash are converted to the C standard of forward slash. - * Aborts if too long. - */ -void pathimport(char* dst, size_t size, const char* src); - -/** - * Exports a path limiting the size. - * In Windows all the C slashes are converted to the Windows backslash. - * Aborts if too long. - */ -void pathexport(char* dst, size_t size, const char* src); - -/** - * Prints a path. - * Aborts if too long. - */ -void pathprint(char* dst, size_t size, const char* format, ...); - -/** - * Ensures the presence of a terminating slash, if it isn't empty. - * Aborts if too long. - */ -void pathslash(char* dst, size_t size); - -/** - * Cuts everything after the latest slash. - */ -void pathcut(char* dst); - -/** - * Compare two paths. - * In Windows it's case insentive and assumes \ equal at /. - */ -int pathcmp(const char* a, const char* b); - -/****************************************************************************/ -/* filesystem */ - -/** - * Creates all the ancestor directories if missing. - * The file name, after the last /, is ignored. - */ -int mkancestor(const char* file); - /****************************************************************************/ /* memory */ -/** - * Return the size of the allocated memory. - */ -size_t malloc_counter(void); - -/** - * Safe malloc. - * If no memory is available, it aborts. - */ -void* malloc_nofail(size_t size); - -/** - * Safe cmalloc. - * If no memory is available, it aborts. - */ -void* calloc_nofail(size_t count, size_t size); - /** * Safe aligned malloc. * If no memory is available, it aborts. @@ -487,23 +403,12 @@ void* malloc_nofail_align(size_t size, void** freeptr); */ void** malloc_nofail_vector_align(int nd, int n, size_t size, void** freeptr); -/** - * Fills the memory vector with random data. - */ -void mrand_vector(unsigned seed, int n, size_t size, void** vv); - /** * Tests the memory vector for RAM problems. * If a problem is found, it crashes. */ void mtest_vector(int n, size_t size, void** vv); -/** - * Safe strdup. - * If no memory is available, it aborts. - */ -char* strdup_nofail(const char* str); - /****************************************************************************/ /* hash */ @@ -561,13 +466,5 @@ int lock_lock(const char* file); */ int lock_unlock(int f); -/****************************************************************************/ -/* file */ - -/** - * Changes the modification time of an open file. - */ -int fmtime(int f, int64_t mtime_sec, int mtime_nsec); - #endif diff --git a/tommyds/tommy.c b/tommyds/tommy.c index b69d9de1..68316587 100644 --- a/tommyds/tommy.c +++ b/tommyds/tommy.c @@ -31,7 +31,7 @@ #define tommy_free free #include "cmdline/portable.h" -#include "cmdline/util.h" /* for malloc_nofail() */ +#include "cmdline/support.h" /* for malloc/calloc_nofail() */ #include "tommyhash.c" #include "tommyarray.c"