mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-25 18:40:19 -04:00
Adds new files support.c/h for low level support functions.
This commit is contained in:
parent
297d648675
commit
ffe7f6fa57
23 changed files with 591 additions and 536 deletions
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "portable.h"
|
||||
|
||||
#include "support.h"
|
||||
#include "util.h"
|
||||
#include "elem.h"
|
||||
#include "import.h"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "portable.h"
|
||||
|
||||
#include "support.h"
|
||||
#include "util.h"
|
||||
#include "elem.h"
|
||||
#include "state.h"
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "portable.h"
|
||||
|
||||
#include "elem.h"
|
||||
#include "support.h"
|
||||
#include "util.h"
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
#include "portable.h"
|
||||
|
||||
#include "elem.h"
|
||||
#include "util.h"
|
||||
#include "support.h"
|
||||
#include "handle.h"
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "portable.h"
|
||||
|
||||
#include "support.h"
|
||||
#include "import.h"
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "portable.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "support.h"
|
||||
#include "elem.h"
|
||||
#include "state.h"
|
||||
#include "handle.h"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "portable.h"
|
||||
|
||||
#include "support.h"
|
||||
#include "elem.h"
|
||||
#include "state.h"
|
||||
#include "parity.h"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "portable.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "support.h"
|
||||
#include "elem.h"
|
||||
#include "state.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "portable.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "support.h"
|
||||
#include "elem.h"
|
||||
#include "state.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "portable.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "support.h"
|
||||
#include "elem.h"
|
||||
#include "state.h"
|
||||
#include "parity.h"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "portable.h"
|
||||
|
||||
#include "support.h"
|
||||
#include "search.h"
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "portable.h"
|
||||
|
||||
#include "support.h"
|
||||
#include "state.h"
|
||||
|
||||
void state_spin(struct snapraid_state* state, int operation)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "portable.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "support.h"
|
||||
#include "elem.h"
|
||||
#include "state.h"
|
||||
#include "parity.h"
|
||||
|
|
|
|||
397
cmdline/support.c
Normal file
397
cmdline/support.c
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
125
cmdline/support.h
Normal file
125
cmdline/support.h
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "portable.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "support.h"
|
||||
#include "elem.h"
|
||||
#include "state.h"
|
||||
#include "parity.h"
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#ifndef __MINGW32__ /* Only for Unix */
|
||||
|
||||
#include "util.h"
|
||||
#include "support.h"
|
||||
|
||||
/**
|
||||
* Standard exit codes.
|
||||
|
|
|
|||
468
cmdline/util.c
468
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
103
cmdline/util.h
103
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue