mirror of
https://github.com/AltraMayor/f3.git
synced 2025-08-03 18:46:00 -04:00

Calling "./f3write a" returns the following error: f3write: Can't change root directory to a at adjust_dev_path(): No such file or directory This patch avoids this bug.
275 lines
5.3 KiB
C
275 lines
5.3 KiB
C
#define _GNU_SOURCE
|
|
|
|
#if __APPLE__ && __MACH__
|
|
|
|
#define _DARWIN_C_SOURCE
|
|
|
|
#include <fcntl.h> /* For fcntl(). */
|
|
|
|
#endif /* Apple Macintosh */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <assert.h>
|
|
#include <sys/types.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <err.h>
|
|
#include <unistd.h>
|
|
|
|
#include "version.h"
|
|
#include "utils.h"
|
|
|
|
void adjust_dev_path(const char **dev_path)
|
|
{
|
|
if (chdir(*dev_path)) {
|
|
err(errno, "Can't change working directory to %s at %s()", *dev_path, __func__);
|
|
}
|
|
*dev_path = ".";
|
|
|
|
if (!chroot(*dev_path)) {
|
|
assert(!chdir("/"));
|
|
} else if (errno != EPERM) {
|
|
err(errno, "Can't change root directory to %s at %s()", *dev_path, __func__);
|
|
}
|
|
}
|
|
|
|
const char *adjust_unit(double *ptr_bytes)
|
|
{
|
|
const char *units[] = { "Byte", "KB", "MB", "GB", "TB", "PB", "EB" };
|
|
int i = 0;
|
|
double final = *ptr_bytes;
|
|
|
|
while (i < 7 && final >= 1024) {
|
|
final /= 1024;
|
|
i++;
|
|
}
|
|
*ptr_bytes = final;
|
|
return units[i];
|
|
}
|
|
|
|
int is_my_file(const char *filename)
|
|
{
|
|
const char *p = filename;
|
|
|
|
if (!p || !isdigit(*p))
|
|
return 0;
|
|
|
|
/* Skip digits. */
|
|
do {
|
|
p++;
|
|
} while (isdigit(*p));
|
|
|
|
return (p[0] == '.') && (p[1] == 'h') && (p[2] == '2') &&
|
|
(p[3] == 'w') && (p[4] == '\0');
|
|
}
|
|
|
|
char *full_fn_from_number(const char **filename, const char *path, long num)
|
|
{
|
|
char *str;
|
|
assert(asprintf(&str, "%s/%li.h2w", path, num + 1) > 0);
|
|
*filename = str + strlen(path) + 1;
|
|
return str;
|
|
}
|
|
|
|
static long number_from_filename(const char *filename)
|
|
{
|
|
const char *p;
|
|
long num;
|
|
|
|
assert(is_my_file(filename));
|
|
|
|
p = filename;
|
|
num = 0;
|
|
do {
|
|
num = num * 10 + (*p - '0');
|
|
p++;
|
|
} while (isdigit(*p));
|
|
|
|
return num - 1;
|
|
}
|
|
|
|
static inline bool include_this_file(const char *filename,
|
|
long start_at, long end_at, long *number)
|
|
{
|
|
if (!is_my_file(filename))
|
|
return false;
|
|
|
|
*number = number_from_filename(filename);
|
|
|
|
return start_at <= *number && *number <= end_at;
|
|
}
|
|
|
|
static long count_files(const char *path, long start_at, long end_at)
|
|
{
|
|
DIR *dir = opendir(path);
|
|
struct dirent *entry;
|
|
long dummy, total = 0;
|
|
|
|
if (!dir)
|
|
err(errno, "Can't open path %s at %s()", path, __func__);
|
|
|
|
entry = readdir(dir);
|
|
while (entry) {
|
|
if (include_this_file(entry->d_name, start_at, end_at, &dummy))
|
|
total++;
|
|
entry = readdir(dir);
|
|
}
|
|
closedir(dir);
|
|
|
|
return total;
|
|
}
|
|
|
|
/* Don't call this function directly, use ls_my_files() instead. */
|
|
static long *__ls_my_files(const char *path, long start_at, long end_at,
|
|
long *pcount)
|
|
{
|
|
long total_files = count_files(path, start_at, end_at);
|
|
DIR *dir;
|
|
struct dirent *entry;
|
|
long *ret, index;
|
|
|
|
assert(total_files >= 0);
|
|
ret = malloc(sizeof(*ret) * (total_files + 1));
|
|
assert(ret);
|
|
|
|
dir = opendir(path);
|
|
if (!dir)
|
|
err(errno, "Can't open path %s at %s()", path, __func__);
|
|
|
|
entry = readdir(dir);
|
|
index = 0;
|
|
while (entry) {
|
|
long number;
|
|
if (include_this_file(entry->d_name, start_at, end_at,
|
|
&number)) {
|
|
if (index >= total_files) {
|
|
/* The folder @path received more files
|
|
* before we finished scanning it.
|
|
*/
|
|
closedir(dir);
|
|
free(ret);
|
|
return NULL;
|
|
}
|
|
ret[index++] = number;
|
|
}
|
|
|
|
entry = readdir(dir);
|
|
}
|
|
closedir(dir);
|
|
|
|
ret[index] = -1;
|
|
*pcount = index;
|
|
return ret;
|
|
}
|
|
|
|
/* To be used with qsort(3). */
|
|
static int cmpintp(const void *p1, const void *p2)
|
|
{
|
|
return *(const long *)p1 - *(const long *)p2;
|
|
}
|
|
|
|
const long *ls_my_files(const char *path, long start_at, long end_at)
|
|
{
|
|
long *ret, my_count;
|
|
|
|
do {
|
|
ret = __ls_my_files(path, start_at, end_at, &my_count);
|
|
} while (!ret);
|
|
|
|
qsort(ret, my_count, sizeof(*ret), cmpintp);
|
|
return ret;
|
|
}
|
|
|
|
long arg_to_long(const struct argp_state *state, const char *arg)
|
|
{
|
|
char *end;
|
|
long l = strtol(arg, &end, 0);
|
|
if (!arg)
|
|
argp_error(state, "An integer must be provided");
|
|
if (!*arg || *end)
|
|
argp_error(state, "`%s' is not an integer", arg);
|
|
return l;
|
|
}
|
|
|
|
void print_header(FILE *f, const char *name)
|
|
{
|
|
fprintf(f,
|
|
"F3 %s " F3_STR_VERSION "\n"
|
|
"Copyright (C) 2010 Digirati Internet LTDA.\n"
|
|
"This is free software; see the source for copying conditions.\n"
|
|
"\n", name);
|
|
}
|
|
|
|
#if __APPLE__ && __MACH__
|
|
|
|
/* This function is a _rough_ approximation of fdatasync(2). */
|
|
int fdatasync(int fd)
|
|
{
|
|
return fcntl(fd, F_FULLFSYNC);
|
|
}
|
|
|
|
/* This function is a _rough_ approximation of posix_fadvise(2). */
|
|
int posix_fadvise(int fd, off_t offset, off_t len, int advice)
|
|
{
|
|
UNUSED(offset);
|
|
UNUSED(len);
|
|
switch (advice) {
|
|
case POSIX_FADV_SEQUENTIAL:
|
|
return fcntl(fd, F_RDAHEAD, 1);
|
|
case POSIX_FADV_DONTNEED:
|
|
return fcntl(fd, F_NOCACHE, 1);
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
#endif /* Apple Macintosh */
|
|
|
|
#if (__APPLE__ && __MACH__) || defined(__OpenBSD__)
|
|
|
|
void msleep(double wait_ms)
|
|
{
|
|
assert(!usleep(wait_ms * 1000));
|
|
}
|
|
|
|
#else /* Apple Macintosh / OpenBSD */
|
|
|
|
#include <time.h> /* For clock_gettime() and clock_nanosleep(). */
|
|
|
|
void msleep(double wait_ms)
|
|
{
|
|
struct timespec req;
|
|
int ret;
|
|
|
|
assert(!clock_gettime(CLOCK_MONOTONIC, &req));
|
|
|
|
/* Add @wait_ms to @req. */
|
|
if (wait_ms > 1000) {
|
|
time_t sec = wait_ms / 1000;
|
|
wait_ms -= sec * 1000;
|
|
assert(wait_ms > 0);
|
|
req.tv_sec += sec;
|
|
}
|
|
req.tv_nsec += wait_ms * 1000000;
|
|
|
|
/* Round @req up. */
|
|
if (req.tv_nsec >= 1000000000) {
|
|
ldiv_t result = ldiv(req.tv_nsec, 1000000000);
|
|
req.tv_sec += result.quot;
|
|
req.tv_nsec = result.rem;
|
|
}
|
|
|
|
do {
|
|
ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
|
|
&req, NULL);
|
|
} while (ret == EINTR);
|
|
|
|
assert(ret == 0);
|
|
}
|
|
|
|
#endif /* Apple Macintosh / OpenBSD */
|