2011-03-04 20:59:21 +01:00
|
|
|
/*
|
|
|
|
|
* 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 "elem.h"
|
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
|
/* snapraid */
|
|
|
|
|
|
2011-09-20 22:35:15 +02:00
|
|
|
struct snapraid_content* content_alloc(const char* path, uint64_t dev)
|
2011-04-25 13:43:51 +02:00
|
|
|
{
|
|
|
|
|
struct snapraid_content* content;
|
|
|
|
|
|
|
|
|
|
content = malloc_nofail(sizeof(struct snapraid_content));
|
2011-11-14 19:21:52 +01:00
|
|
|
pathimport(content->content, sizeof(content->content), path);
|
2011-09-20 22:35:15 +02:00
|
|
|
content->device = dev;
|
2011-04-25 13:43:51 +02:00
|
|
|
|
|
|
|
|
return content;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void content_free(struct snapraid_content* content)
|
|
|
|
|
{
|
|
|
|
|
free(content);
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-10 23:32:09 +02:00
|
|
|
struct snapraid_filter* filter_alloc_file(int direction, const char* pattern)
|
2011-03-16 23:52:10 +01:00
|
|
|
{
|
|
|
|
|
struct snapraid_filter* filter;
|
|
|
|
|
char* i;
|
|
|
|
|
char* first;
|
|
|
|
|
char* last;
|
|
|
|
|
|
|
|
|
|
filter = malloc_nofail(sizeof(struct snapraid_filter));
|
2011-05-03 23:28:03 +02:00
|
|
|
pathimport(filter->pattern, sizeof(filter->pattern), pattern);
|
2011-04-26 18:51:42 +02:00
|
|
|
filter->direction = direction;
|
2011-03-16 23:52:10 +01:00
|
|
|
|
|
|
|
|
/* find first and last slash */
|
|
|
|
|
first = 0;
|
|
|
|
|
last = 0;
|
|
|
|
|
for(i=filter->pattern;*i;++i) {
|
|
|
|
|
if (*i == '/') {
|
|
|
|
|
if (!first)
|
|
|
|
|
first = i;
|
|
|
|
|
last = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-10 23:32:09 +02:00
|
|
|
/* it's a file filter */
|
|
|
|
|
filter->is_disk = 0;
|
|
|
|
|
|
2011-03-16 23:52:10 +01:00
|
|
|
if (first == 0) {
|
|
|
|
|
/* no slash */
|
|
|
|
|
filter->is_path = 0;
|
|
|
|
|
filter->is_dir = 0;
|
|
|
|
|
} else if (first == last && last[1] == 0) {
|
|
|
|
|
/* one slash at the end */
|
|
|
|
|
filter->is_path = 0;
|
|
|
|
|
filter->is_dir = 1;
|
|
|
|
|
last[0] = 0;
|
|
|
|
|
} else {
|
|
|
|
|
/* at least a slash not at the end */
|
|
|
|
|
filter->is_path = 1;
|
|
|
|
|
if (last[1] == 0) {
|
|
|
|
|
filter->is_dir = 1;
|
|
|
|
|
last[0] = 0;
|
|
|
|
|
} else {
|
|
|
|
|
filter->is_dir = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* a slash must be the first char, as we reject PATH/DIR/FILE */
|
|
|
|
|
if (filter->pattern[0] != '/') {
|
2014-03-20 22:10:19 +01:00
|
|
|
/* LCOV_EXCL_START */
|
2011-03-16 23:52:10 +01:00
|
|
|
free(filter);
|
|
|
|
|
return 0;
|
2014-03-20 22:10:19 +01:00
|
|
|
/* LCOV_EXCL_STOP */
|
2011-03-16 23:52:10 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return filter;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-10 23:32:09 +02:00
|
|
|
struct snapraid_filter* filter_alloc_disk(int direction, const char* pattern)
|
|
|
|
|
{
|
|
|
|
|
struct snapraid_filter* filter;
|
|
|
|
|
|
|
|
|
|
filter = malloc_nofail(sizeof(struct snapraid_filter));
|
|
|
|
|
pathimport(filter->pattern, sizeof(filter->pattern), pattern);
|
|
|
|
|
filter->direction = direction;
|
|
|
|
|
|
|
|
|
|
/* it's a disk filter */
|
|
|
|
|
filter->is_disk = 1;
|
|
|
|
|
filter->is_path = 0;
|
|
|
|
|
filter->is_dir = 0;
|
|
|
|
|
|
|
|
|
|
/* no slash allowed in disk names */
|
|
|
|
|
if (strchr(filter->pattern, '/') != 0) {
|
2014-03-20 22:10:19 +01:00
|
|
|
/* LCOV_EXCL_START */
|
2012-10-10 23:32:09 +02:00
|
|
|
free(filter);
|
|
|
|
|
return 0;
|
2014-03-20 22:10:19 +01:00
|
|
|
/* LCOV_EXCL_STOP */
|
2012-10-10 23:32:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return filter;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-16 23:52:10 +01:00
|
|
|
void filter_free(struct snapraid_filter* filter)
|
|
|
|
|
{
|
|
|
|
|
free(filter);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-26 18:51:42 +02:00
|
|
|
static int filter_apply(struct snapraid_filter* filter, const char* path, const char* name, int is_dir)
|
2011-03-16 23:52:10 +01:00
|
|
|
{
|
|
|
|
|
/* matches dirs with dirs and files with files */
|
|
|
|
|
if (filter->is_dir && !is_dir)
|
2011-04-26 18:51:42 +02:00
|
|
|
return 0;
|
2011-03-16 23:52:10 +01:00
|
|
|
if (!filter->is_dir && is_dir)
|
2011-04-26 18:51:42 +02:00
|
|
|
return 0;
|
2011-03-16 23:52:10 +01:00
|
|
|
|
|
|
|
|
if (filter->is_path) {
|
|
|
|
|
/* skip initial slash, as always missing from the path */
|
2013-05-14 21:34:51 +02:00
|
|
|
if (fnmatch(filter->pattern + 1, path, FNM_PATHNAME | FNM_CASEINSENSITIVE_FOR_WIN) == 0)
|
2011-04-26 18:51:42 +02:00
|
|
|
return filter->direction;
|
2011-03-16 23:52:10 +01:00
|
|
|
} else {
|
2013-05-14 21:34:51 +02:00
|
|
|
if (fnmatch(filter->pattern, name, FNM_CASEINSENSITIVE_FOR_WIN) == 0)
|
2011-04-26 18:51:42 +02:00
|
|
|
return filter->direction;
|
2011-03-16 23:52:10 +01:00
|
|
|
}
|
|
|
|
|
|
2011-04-26 18:51:42 +02:00
|
|
|
return 0;
|
2011-03-16 23:52:10 +01:00
|
|
|
}
|
|
|
|
|
|
2011-04-26 18:51:42 +02:00
|
|
|
static int filter_recurse(struct snapraid_filter* filter, const char* const_path, int is_dir)
|
2011-03-30 00:14:43 +02:00
|
|
|
{
|
2011-03-30 17:02:02 +02:00
|
|
|
char path[PATH_MAX];
|
|
|
|
|
char* name;
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
2011-04-26 18:51:42 +02:00
|
|
|
pathcpy(path, sizeof(path), const_path);
|
2011-03-30 17:02:02 +02:00
|
|
|
|
2011-04-26 18:51:42 +02:00
|
|
|
/* filter for all the directories */
|
2011-03-30 17:02:02 +02:00
|
|
|
name = path;
|
|
|
|
|
for(i=0;path[i] != 0;++i) {
|
|
|
|
|
if (path[i] == '/') {
|
|
|
|
|
/* set a terminator */
|
|
|
|
|
path[i] = 0;
|
|
|
|
|
|
|
|
|
|
/* filter the directory */
|
2011-04-26 18:51:42 +02:00
|
|
|
if (filter_apply(filter, path, name, 1) != 0)
|
|
|
|
|
return filter->direction;
|
2011-03-30 17:02:02 +02:00
|
|
|
|
|
|
|
|
/* restore the slash */
|
|
|
|
|
path[i] = '/';
|
|
|
|
|
|
|
|
|
|
/* next name */
|
|
|
|
|
name = path + i + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* filter the final file */
|
2011-04-26 18:51:42 +02:00
|
|
|
if (filter_apply(filter, path, name, is_dir) != 0)
|
|
|
|
|
return filter->direction;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-10 23:32:09 +02:00
|
|
|
static int filter_element(tommy_list* filterlist, const char* disk, const char* sub, int is_dir)
|
2011-04-26 18:51:42 +02:00
|
|
|
{
|
|
|
|
|
tommy_node* i;
|
|
|
|
|
|
|
|
|
|
int direction = 1; /* by default include all */
|
|
|
|
|
|
|
|
|
|
/* for each filter */
|
|
|
|
|
for(i=tommy_list_head(filterlist);i!=0;i=i->next) {
|
|
|
|
|
int ret;
|
|
|
|
|
struct snapraid_filter* filter = i->data;
|
|
|
|
|
|
2012-10-10 23:32:09 +02:00
|
|
|
if (filter->is_disk) {
|
2013-05-14 21:34:51 +02:00
|
|
|
if (fnmatch(filter->pattern, disk, FNM_CASEINSENSITIVE_FOR_WIN) == 0)
|
2012-10-10 23:32:09 +02:00
|
|
|
ret = filter->direction;
|
|
|
|
|
else
|
|
|
|
|
ret = 0;
|
|
|
|
|
} else {
|
|
|
|
|
ret = filter_recurse(filter, sub, is_dir);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-26 18:51:42 +02:00
|
|
|
if (ret > 0) {
|
|
|
|
|
/* include the file */
|
2012-07-03 21:51:50 +02:00
|
|
|
return 0;
|
2011-04-26 18:51:42 +02:00
|
|
|
} else if (ret < 0) {
|
|
|
|
|
/* exclude the file */
|
2012-07-03 21:51:50 +02:00
|
|
|
return -1;
|
2011-04-26 18:51:42 +02:00
|
|
|
} else {
|
|
|
|
|
/* default is opposite of the last filter */
|
|
|
|
|
direction = -filter->direction;
|
|
|
|
|
/* continue with the next one */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-29 20:35:43 +02:00
|
|
|
/* directories are always included by default, otherwise we cannot apply rules */
|
|
|
|
|
/* to the contained files */
|
|
|
|
|
if (is_dir)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* files are excluded/included depending of the last rule processed */
|
2011-04-26 18:51:42 +02:00
|
|
|
if (direction < 0)
|
|
|
|
|
return -1;
|
2011-03-30 17:02:02 +02:00
|
|
|
|
2011-04-26 18:51:42 +02:00
|
|
|
return 0;
|
2011-03-30 00:14:43 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-10 23:32:09 +02:00
|
|
|
int filter_path(tommy_list* filterlist, const char* disk, const char* sub)
|
2011-09-18 22:43:41 +02:00
|
|
|
{
|
2012-10-10 23:32:09 +02:00
|
|
|
return filter_element(filterlist, disk, sub, 0);
|
2011-09-18 22:43:41 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-10 23:32:09 +02:00
|
|
|
int filter_dir(tommy_list* filterlist, const char* disk, const char* sub)
|
2011-09-18 22:43:41 +02:00
|
|
|
{
|
2012-10-10 23:32:09 +02:00
|
|
|
return filter_element(filterlist, disk, sub, 1);
|
2011-09-18 22:43:41 +02:00
|
|
|
}
|
|
|
|
|
|
2013-03-01 18:29:04 +01:00
|
|
|
int filter_existence(int filter_missing, const char* dir, const char* sub)
|
2013-02-24 11:33:09 +01:00
|
|
|
{
|
2013-03-01 18:29:04 +01:00
|
|
|
char path[PATH_MAX];
|
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
|
|
if (!filter_missing)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* we directly check if in the disk the file is present or not */
|
|
|
|
|
pathprint(path, sizeof(path), "%s%s", dir, sub);
|
|
|
|
|
|
|
|
|
|
if (lstat(path, &st) != 0) {
|
|
|
|
|
/* if the file doesn't exist, we don't filter it out */
|
|
|
|
|
if (errno == ENOENT)
|
|
|
|
|
return 0;
|
2014-02-03 22:40:51 +01:00
|
|
|
/* LCOV_EXCL_START */
|
2013-03-01 18:29:04 +01:00
|
|
|
fprintf(stderr, "Error in stat file '%s'. %s.\n", path, strerror(errno));
|
|
|
|
|
exit(EXIT_FAILURE);
|
2014-02-03 22:40:51 +01:00
|
|
|
/* LCOV_EXCL_STOP */
|
2013-03-01 18:29:04 +01:00
|
|
|
}
|
|
|
|
|
|
2013-08-18 19:24:55 +02:00
|
|
|
/* the file is present, so we filter it out */
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-28 09:40:08 +02:00
|
|
|
int filter_correctness(int filter_error, tommy_arrayblkof* infoarr, struct snapraid_file* file)
|
2013-08-18 19:24:55 +02:00
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
if (!filter_error)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* check each block of the file */
|
|
|
|
|
for(i=0;i<file->blockmax;++i) {
|
|
|
|
|
struct snapraid_block* block;
|
|
|
|
|
snapraid_info info;
|
|
|
|
|
|
|
|
|
|
block = &file->blockvec[i];
|
|
|
|
|
|
|
|
|
|
info = info_get(infoarr, block->parity_pos);
|
|
|
|
|
|
|
|
|
|
/* if the file has a bad block, don't exclude it */
|
|
|
|
|
if (info_get_bad(info))
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* the file is correct, so we filter it out */
|
2013-03-01 18:29:04 +01:00
|
|
|
return 1;
|
2013-02-24 11:33:09 +01:00
|
|
|
}
|
|
|
|
|
|
2011-09-18 22:43:41 +02:00
|
|
|
int filter_content(tommy_list* contentlist, const char* path)
|
|
|
|
|
{
|
|
|
|
|
tommy_node* i;
|
|
|
|
|
|
|
|
|
|
for(i=tommy_list_head(contentlist);i!=0;i=i->next) {
|
|
|
|
|
struct snapraid_content* content = i->data;
|
2012-04-14 14:03:49 +02:00
|
|
|
char tmp[PATH_MAX];
|
2011-09-18 22:43:41 +02:00
|
|
|
|
2013-06-01 22:49:15 +02:00
|
|
|
if (pathcmp(content->content, path) == 0)
|
2011-09-18 22:43:41 +02:00
|
|
|
return -1;
|
2012-04-14 14:03:49 +02:00
|
|
|
|
|
|
|
|
/* exclude also the ".tmp" copy used to save it */
|
|
|
|
|
pathprint(tmp, sizeof(tmp), "%s.tmp", content->content);
|
2013-06-01 22:49:15 +02:00
|
|
|
if (pathcmp(tmp, path) == 0)
|
2012-04-14 14:03:49 +02:00
|
|
|
return -1;
|
2014-06-13 18:23:24 +02:00
|
|
|
|
|
|
|
|
/* exclude also the ".lock" file */
|
|
|
|
|
pathprint(tmp, sizeof(tmp), "%s.lock", content->content);
|
|
|
|
|
if (pathcmp(tmp, path) == 0)
|
|
|
|
|
return -1;
|
2011-09-18 22:43:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-12 10:09:59 +01:00
|
|
|
block_off_t block_file_pos(struct snapraid_block* block)
|
2011-03-04 20:59:21 +01:00
|
|
|
{
|
2011-04-28 23:09:19 +02:00
|
|
|
struct snapraid_file* file = block_file_get(block);
|
2011-03-04 20:59:21 +01:00
|
|
|
|
|
|
|
|
if (block < file->blockvec || block >= file->blockvec + file->blockmax) {
|
2014-02-03 22:40:51 +01:00
|
|
|
/* LCOV_EXCL_START */
|
2011-03-04 20:59:21 +01:00
|
|
|
fprintf(stderr, "Internal inconsistency in block %u ownership\n", block->parity_pos);
|
|
|
|
|
exit(EXIT_FAILURE);
|
2014-02-03 22:40:51 +01:00
|
|
|
/* LCOV_EXCL_STOP */
|
2011-03-04 20:59:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return block - file->blockvec;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-31 23:33:43 +02:00
|
|
|
int block_is_last(struct snapraid_block* block)
|
|
|
|
|
{
|
|
|
|
|
struct snapraid_file* file = block_file_get(block);
|
|
|
|
|
|
|
|
|
|
return block == file->blockvec + file->blockmax - 1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-04 20:59:21 +01:00
|
|
|
unsigned block_file_size(struct snapraid_block* block, unsigned block_size)
|
|
|
|
|
{
|
2011-03-12 10:09:59 +01:00
|
|
|
block_off_t pos = block_file_pos(block);
|
2011-03-04 20:59:21 +01:00
|
|
|
|
|
|
|
|
/* if it's the last block */
|
2011-04-28 23:09:19 +02:00
|
|
|
if (pos + 1 == block_file_get(block)->blockmax) {
|
2011-03-04 20:59:21 +01:00
|
|
|
unsigned remainder;
|
2011-04-28 23:09:19 +02:00
|
|
|
if (block_file_get(block)->size == 0)
|
2011-03-04 20:59:21 +01:00
|
|
|
return 0;
|
2011-04-28 23:09:19 +02:00
|
|
|
remainder = block_file_get(block)->size % block_size;
|
2011-03-04 20:59:21 +01:00
|
|
|
if (remainder == 0)
|
|
|
|
|
remainder = block_size;
|
|
|
|
|
return remainder;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return block_size;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-24 19:02:53 +01:00
|
|
|
struct snapraid_deleted* deleted_alloc(void)
|
|
|
|
|
{
|
|
|
|
|
struct snapraid_deleted* deleted;
|
|
|
|
|
|
|
|
|
|
deleted = malloc_nofail(sizeof(struct snapraid_deleted));
|
|
|
|
|
|
|
|
|
|
/* set the state as deleted */
|
|
|
|
|
deleted->block.file_mixed = BLOCK_STATE_DELETED;
|
|
|
|
|
|
|
|
|
|
return deleted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct snapraid_deleted* deleted_dup(struct snapraid_block* block)
|
|
|
|
|
{
|
|
|
|
|
struct snapraid_deleted* deleted;
|
|
|
|
|
|
|
|
|
|
deleted = deleted_alloc();
|
|
|
|
|
|
|
|
|
|
/* copy data from deleted block */
|
|
|
|
|
deleted->block.parity_pos = block->parity_pos;
|
|
|
|
|
memcpy(deleted->block.hash, block->hash, HASH_SIZE);
|
|
|
|
|
|
|
|
|
|
return deleted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deleted_free(struct snapraid_deleted* deleted)
|
|
|
|
|
{
|
|
|
|
|
free(deleted);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-25 22:41:10 +02:00
|
|
|
struct snapraid_file* file_alloc(unsigned block_size, const char* sub, uint64_t size, uint64_t mtime_sec, int mtime_nsec, uint64_t inode, uint64_t physical)
|
2011-03-04 20:59:21 +01:00
|
|
|
{
|
|
|
|
|
struct snapraid_file* file;
|
2011-03-12 10:09:59 +01:00
|
|
|
block_off_t i;
|
2011-03-04 20:59:21 +01:00
|
|
|
|
|
|
|
|
file = malloc_nofail(sizeof(struct snapraid_file));
|
2013-02-26 21:26:45 +01:00
|
|
|
file->sub = strdup_nofail(sub);
|
2011-03-04 20:59:21 +01:00
|
|
|
file->size = size;
|
|
|
|
|
file->blockmax = (size + block_size - 1) / block_size;
|
2012-07-10 23:24:31 +02:00
|
|
|
file->mtime_sec = mtime_sec;
|
|
|
|
|
file->mtime_nsec = mtime_nsec;
|
2011-03-20 22:36:49 +01:00
|
|
|
file->inode = inode;
|
2013-06-25 22:41:10 +02:00
|
|
|
file->physical = physical;
|
2011-04-28 23:09:19 +02:00
|
|
|
file->flag = 0;
|
2011-03-04 20:59:21 +01:00
|
|
|
file->blockvec = malloc_nofail(file->blockmax * sizeof(struct snapraid_block));
|
|
|
|
|
|
|
|
|
|
/* set the back pointer */
|
|
|
|
|
for(i=0;i<file->blockmax;++i) {
|
|
|
|
|
file->blockvec[i].parity_pos = POS_INVALID;
|
2011-04-28 23:09:19 +02:00
|
|
|
file->blockvec[i].file_mixed = 0;
|
2014-02-01 23:32:53 +01:00
|
|
|
|
|
|
|
|
/* set the file */
|
2011-04-28 23:09:19 +02:00
|
|
|
block_file_set(&file->blockvec[i], file);
|
2014-02-01 23:32:53 +01:00
|
|
|
|
|
|
|
|
/* set an invalid hash */
|
|
|
|
|
block_state_set(&file->blockvec[i], BLOCK_STATE_CHG);
|
2014-02-12 20:02:35 +01:00
|
|
|
hash_invalid_set(file->blockvec[i].hash);
|
2011-03-04 20:59:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return file;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void file_free(struct snapraid_file* file)
|
|
|
|
|
{
|
2013-02-26 21:26:45 +01:00
|
|
|
free(file->sub);
|
2011-03-04 20:59:21 +01:00
|
|
|
free(file->blockvec);
|
|
|
|
|
free(file);
|
|
|
|
|
}
|
2011-03-30 00:14:43 +02:00
|
|
|
|
2013-02-26 21:26:45 +01:00
|
|
|
void file_rename(struct snapraid_file* file, const char* sub)
|
|
|
|
|
{
|
|
|
|
|
free(file->sub);
|
|
|
|
|
file->sub = strdup_nofail(sub);
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-12 20:02:35 +01:00
|
|
|
void file_copy(struct snapraid_file* src_file, struct snapraid_file* dst_file)
|
|
|
|
|
{
|
|
|
|
|
block_off_t i;
|
|
|
|
|
|
|
|
|
|
if (src_file->size != dst_file->size) {
|
|
|
|
|
/* LCOV_EXCL_START */
|
|
|
|
|
fprintf(stderr, "Internal inconsistency in copy file with different size\n");
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
/* LCOV_EXCL_STOP */
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-15 23:45:51 +02:00
|
|
|
if (src_file->mtime_sec != dst_file->mtime_sec) {
|
|
|
|
|
/* LCOV_EXCL_START */
|
|
|
|
|
fprintf(stderr, "Internal inconsistency in copy file with different mtime_sec\n");
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
/* LCOV_EXCL_STOP */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (src_file->mtime_nsec != dst_file->mtime_nsec) {
|
|
|
|
|
/* LCOV_EXCL_START */
|
|
|
|
|
fprintf(stderr, "Internal inconsistency in copy file with different mtime_nsec\n");
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
/* LCOV_EXCL_STOP */
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-12 20:02:35 +01:00
|
|
|
for(i=0;i<dst_file->blockmax;++i) {
|
|
|
|
|
/* set a block with hash computed but without parity */
|
|
|
|
|
block_state_set(&dst_file->blockvec[i], BLOCK_STATE_REP);
|
|
|
|
|
|
|
|
|
|
/* copy the hash */
|
|
|
|
|
memcpy(dst_file->blockvec[i].hash, src_file->blockvec[i].hash, HASH_SIZE);
|
|
|
|
|
}
|
2014-05-15 23:45:51 +02:00
|
|
|
|
|
|
|
|
file_flag_set(dst_file, FILE_IS_COPY);
|
2014-02-12 20:02:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* file_name(const struct snapraid_file* file)
|
2011-03-30 00:14:43 +02:00
|
|
|
{
|
|
|
|
|
const char* r = strrchr(file->sub, '/');
|
|
|
|
|
if (!r)
|
|
|
|
|
r = file->sub;
|
|
|
|
|
else
|
|
|
|
|
++r;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
2011-03-04 20:59:21 +01:00
|
|
|
|
2013-06-25 22:41:10 +02:00
|
|
|
int file_inode_compare_to_arg(const void* void_arg, const void* void_data)
|
2011-03-04 20:59:21 +01:00
|
|
|
{
|
2011-03-20 22:36:49 +01:00
|
|
|
const uint64_t* arg = void_arg;
|
2011-03-04 20:59:21 +01:00
|
|
|
const struct snapraid_file* file = void_data;
|
2011-03-20 22:36:49 +01:00
|
|
|
if (*arg < file->inode)
|
|
|
|
|
return -1;
|
|
|
|
|
if (*arg > file->inode)
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
2011-03-04 20:59:21 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-25 22:41:10 +02:00
|
|
|
int file_inode_compare(const void* void_a, const void* void_b)
|
|
|
|
|
{
|
|
|
|
|
const struct snapraid_file* file_a = void_a;
|
|
|
|
|
const struct snapraid_file* file_b = void_b;
|
|
|
|
|
if (file_a->inode < file_b->inode)
|
|
|
|
|
return -1;
|
|
|
|
|
if (file_a->inode > file_b->inode)
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-12 20:02:35 +01:00
|
|
|
int file_path_compare(const void* void_a, const void* void_b)
|
2013-06-25 22:41:10 +02:00
|
|
|
{
|
|
|
|
|
const struct snapraid_file* file_a = void_a;
|
|
|
|
|
const struct snapraid_file* file_b = void_b;
|
|
|
|
|
return strcmp(file_a->sub, file_b->sub);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int file_physical_compare(const void* void_a, const void* void_b)
|
|
|
|
|
{
|
|
|
|
|
const struct snapraid_file* file_a = void_a;
|
|
|
|
|
const struct snapraid_file* file_b = void_b;
|
|
|
|
|
if (file_a->physical < file_b->physical)
|
|
|
|
|
return -1;
|
|
|
|
|
if (file_a->physical > file_b->physical)
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-12 20:02:35 +01:00
|
|
|
int file_path_compare_to_arg(const void* void_arg, const void* void_data)
|
2011-10-09 23:41:08 +02:00
|
|
|
{
|
|
|
|
|
const char* arg = void_arg;
|
|
|
|
|
const struct snapraid_file* file = void_data;
|
|
|
|
|
return strcmp(arg, file->sub);
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-12 20:02:35 +01:00
|
|
|
int file_name_compare(const void* void_a, const void* void_b)
|
|
|
|
|
{
|
|
|
|
|
const struct snapraid_file* file_a = void_a;
|
|
|
|
|
const struct snapraid_file* file_b = void_b;
|
|
|
|
|
const char* name_a = file_name(file_a);
|
|
|
|
|
const char* name_b = file_name(file_b);
|
|
|
|
|
|
|
|
|
|
return strcmp(name_a, name_b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int file_stamp_compare(const void* void_a, const void* void_b)
|
|
|
|
|
{
|
|
|
|
|
const struct snapraid_file* file_a = void_a;
|
|
|
|
|
const struct snapraid_file* file_b = void_b;
|
|
|
|
|
|
|
|
|
|
if (file_a->size < file_b->size)
|
|
|
|
|
return -1;
|
|
|
|
|
if (file_a->size > file_b->size)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (file_a->mtime_sec < file_b->mtime_sec)
|
|
|
|
|
return -1;
|
|
|
|
|
if (file_a->mtime_sec > file_b->mtime_sec)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (file_a->mtime_nsec < file_b->mtime_nsec)
|
|
|
|
|
return -1;
|
|
|
|
|
if (file_a->mtime_nsec > file_b->mtime_nsec)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int file_namestamp_compare(const void* void_a, const void* void_b)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = file_name_compare(void_a, void_b);
|
|
|
|
|
if (ret != 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
return file_stamp_compare(void_a, void_b);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-15 23:45:51 +02:00
|
|
|
int file_pathstamp_compare(const void* void_a, const void* void_b)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = file_path_compare(void_a, void_b);
|
|
|
|
|
if (ret != 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
return file_stamp_compare(void_a, void_b);
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-28 21:56:02 +01:00
|
|
|
struct snapraid_link* link_alloc(const char* sub, const char* linkto, unsigned link_flag)
|
2011-08-26 14:18:38 +02:00
|
|
|
{
|
|
|
|
|
struct snapraid_link* link;
|
|
|
|
|
|
|
|
|
|
link = malloc_nofail(sizeof(struct snapraid_link));
|
2013-05-30 23:50:26 +02:00
|
|
|
link->sub = strdup_nofail(sub);
|
|
|
|
|
link->linkto = strdup_nofail(linkto);
|
2013-02-28 21:56:02 +01:00
|
|
|
link->flag = link_flag;
|
2011-08-26 14:18:38 +02:00
|
|
|
|
|
|
|
|
return link;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void link_free(struct snapraid_link* link)
|
|
|
|
|
{
|
2013-05-30 23:50:26 +02:00
|
|
|
free(link->sub);
|
|
|
|
|
free(link->linkto);
|
2011-08-26 14:18:38 +02:00
|
|
|
free(link);
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-19 13:24:35 +02:00
|
|
|
int link_name_compare_to_arg(const void* void_arg, const void* void_data)
|
2011-08-26 14:18:38 +02:00
|
|
|
{
|
|
|
|
|
const char* arg = void_arg;
|
|
|
|
|
const struct snapraid_link* link = void_data;
|
|
|
|
|
return strcmp(arg, link->sub);
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-19 13:24:35 +02:00
|
|
|
int link_alpha_compare(const void* void_a, const void* void_b)
|
|
|
|
|
{
|
|
|
|
|
const struct snapraid_link* link_a = void_a;
|
|
|
|
|
const struct snapraid_link* link_b = void_b;
|
|
|
|
|
return strcmp(link_a->sub, link_b->sub);
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-27 16:44:04 +01:00
|
|
|
struct snapraid_dir* dir_alloc(const char* sub)
|
|
|
|
|
{
|
|
|
|
|
struct snapraid_dir* dir;
|
|
|
|
|
|
|
|
|
|
dir = malloc_nofail(sizeof(struct snapraid_dir));
|
2013-05-30 23:50:26 +02:00
|
|
|
dir->sub = strdup_nofail(sub);
|
2013-01-27 16:44:04 +01:00
|
|
|
dir->flag = 0;
|
|
|
|
|
|
|
|
|
|
return dir;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dir_free(struct snapraid_dir* dir)
|
|
|
|
|
{
|
2013-05-30 23:50:26 +02:00
|
|
|
free(dir->sub);
|
2013-01-27 16:44:04 +01:00
|
|
|
free(dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int dir_name_compare(const void* void_arg, const void* void_data)
|
|
|
|
|
{
|
|
|
|
|
const char* arg = void_arg;
|
|
|
|
|
const struct snapraid_dir* dir = void_data;
|
|
|
|
|
return strcmp(arg, dir->sub);
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-20 22:35:15 +02:00
|
|
|
struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev)
|
2011-03-04 20:59:21 +01:00
|
|
|
{
|
|
|
|
|
struct snapraid_disk* disk;
|
|
|
|
|
|
|
|
|
|
disk = malloc_nofail(sizeof(struct snapraid_disk));
|
2011-03-16 23:52:10 +01:00
|
|
|
pathcpy(disk->name, sizeof(disk->name), name);
|
2011-05-02 20:32:54 +02:00
|
|
|
pathimport(disk->dir, sizeof(disk->dir), dir);
|
2011-03-12 10:23:42 +01:00
|
|
|
|
|
|
|
|
/* ensure that the dir terminate with "/" if it isn't empty */
|
2011-03-16 23:52:10 +01:00
|
|
|
pathslash(disk->dir, sizeof(disk->dir));
|
2011-03-12 10:23:42 +01:00
|
|
|
|
2011-09-20 22:35:15 +02:00
|
|
|
disk->device = dev;
|
2014-06-25 22:32:36 +02:00
|
|
|
disk->tick = 0;
|
2011-03-04 20:59:21 +01:00
|
|
|
disk->first_free_block = 0;
|
2013-12-14 17:54:04 +01:00
|
|
|
disk->has_volatile_inodes = 0;
|
|
|
|
|
disk->has_unreliable_physical = 0;
|
|
|
|
|
disk->has_different_uuid = 0;
|
2014-04-03 23:02:43 +02:00
|
|
|
disk->has_unsupported_uuid = 0;
|
2014-01-04 17:42:45 +01:00
|
|
|
disk->had_empty_uuid = 0;
|
2013-08-23 22:35:14 +02:00
|
|
|
disk->mapping = -1;
|
2011-03-04 20:59:21 +01:00
|
|
|
tommy_list_init(&disk->filelist);
|
2013-02-24 19:02:53 +01:00
|
|
|
tommy_list_init(&disk->deletedlist);
|
2011-03-20 22:36:49 +01:00
|
|
|
tommy_hashdyn_init(&disk->inodeset);
|
2011-10-09 23:41:08 +02:00
|
|
|
tommy_hashdyn_init(&disk->pathset);
|
2014-02-12 20:02:35 +01:00
|
|
|
tommy_hashdyn_init(&disk->stampset);
|
2011-08-26 14:18:38 +02:00
|
|
|
tommy_list_init(&disk->linklist);
|
|
|
|
|
tommy_hashdyn_init(&disk->linkset);
|
2013-01-27 16:44:04 +01:00
|
|
|
tommy_list_init(&disk->dirlist);
|
|
|
|
|
tommy_hashdyn_init(&disk->dirset);
|
2013-09-28 09:40:08 +02:00
|
|
|
tommy_arrayblk_init(&disk->blockarr);
|
2011-03-04 20:59:21 +01:00
|
|
|
|
|
|
|
|
return disk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void disk_free(struct snapraid_disk* disk)
|
|
|
|
|
{
|
2011-12-08 20:37:27 +01:00
|
|
|
tommy_list_foreach(&disk->filelist, (tommy_foreach_func*)file_free);
|
2013-02-24 19:02:53 +01:00
|
|
|
tommy_list_foreach(&disk->deletedlist, (tommy_foreach_func*)deleted_free);
|
2011-03-20 22:36:49 +01:00
|
|
|
tommy_hashdyn_done(&disk->inodeset);
|
2011-10-09 23:41:08 +02:00
|
|
|
tommy_hashdyn_done(&disk->pathset);
|
2014-02-12 20:02:35 +01:00
|
|
|
tommy_hashdyn_done(&disk->stampset);
|
2011-12-08 20:37:27 +01:00
|
|
|
tommy_list_foreach(&disk->linklist, (tommy_foreach_func*)link_free);
|
2011-08-26 14:18:38 +02:00
|
|
|
tommy_hashdyn_done(&disk->linkset);
|
2013-01-27 16:44:04 +01:00
|
|
|
tommy_list_foreach(&disk->dirlist, (tommy_foreach_func*)dir_free);
|
|
|
|
|
tommy_hashdyn_done(&disk->dirset);
|
2013-09-28 09:40:08 +02:00
|
|
|
tommy_arrayblk_done(&disk->blockarr);
|
2011-03-04 20:59:21 +01:00
|
|
|
free(disk);
|
|
|
|
|
}
|
2011-03-06 22:52:50 +01:00
|
|
|
|
2013-08-23 22:35:14 +02:00
|
|
|
int disk_is_empty(struct snapraid_disk* disk, block_off_t blockmax)
|
|
|
|
|
{
|
|
|
|
|
block_off_t i;
|
|
|
|
|
|
|
|
|
|
/* if there is an element, it's not empty */
|
|
|
|
|
/* even if links and dirs have no block allocation */
|
|
|
|
|
if (!tommy_list_empty(&disk->filelist))
|
|
|
|
|
return 0;
|
|
|
|
|
if (!tommy_list_empty(&disk->linklist))
|
|
|
|
|
return 0;
|
|
|
|
|
if (!tommy_list_empty(&disk->dirlist))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* limit the search to the size of the disk */
|
2013-09-28 09:40:08 +02:00
|
|
|
if (blockmax > tommy_arrayblk_size(&disk->blockarr))
|
|
|
|
|
blockmax = tommy_arrayblk_size(&disk->blockarr);
|
2013-08-23 22:35:14 +02:00
|
|
|
|
|
|
|
|
/* checks all the blocks to search for deleted ones */
|
|
|
|
|
/* this search is slow, but it's done only if no file is present */
|
|
|
|
|
for(i=0;i<blockmax;++i) {
|
2013-09-28 09:40:08 +02:00
|
|
|
struct snapraid_block* block = tommy_arrayblk_get(&disk->blockarr, i);
|
2013-08-23 22:35:14 +02:00
|
|
|
unsigned block_state = block_state_get(block);
|
|
|
|
|
|
|
|
|
|
switch (block_state) {
|
|
|
|
|
case BLOCK_STATE_EMPTY :
|
|
|
|
|
/* empty block are expected for an empty disk */
|
|
|
|
|
break;
|
|
|
|
|
case BLOCK_STATE_DELETED :
|
|
|
|
|
/* if there is a deleted block, the disk is not empty */
|
|
|
|
|
return 0;
|
|
|
|
|
default:
|
2014-02-03 22:40:51 +01:00
|
|
|
/* LCOV_EXCL_START */
|
2013-09-22 23:54:49 +02:00
|
|
|
fprintf(stderr, "Internal inconsistency for used block in disk '%s' without files\n", disk->name);
|
2013-08-23 22:35:14 +02:00
|
|
|
exit(EXIT_FAILURE);
|
2014-02-03 22:40:51 +01:00
|
|
|
/* LCOV_EXCL_STOP */
|
2013-08-23 22:35:14 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* finally, it's empty */
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-03 22:39:46 +01:00
|
|
|
struct snapraid_map* map_alloc(const char* name, unsigned position, const char* uuid)
|
2011-10-01 19:18:32 +02:00
|
|
|
{
|
|
|
|
|
struct snapraid_map* map;
|
|
|
|
|
|
|
|
|
|
map = malloc_nofail(sizeof(struct snapraid_map));
|
|
|
|
|
pathcpy(map->name, sizeof(map->name), name);
|
2013-03-03 22:39:46 +01:00
|
|
|
pathcpy(map->uuid, sizeof(map->uuid), uuid);
|
2011-10-01 19:18:32 +02:00
|
|
|
map->position = position;
|
|
|
|
|
|
|
|
|
|
return map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void map_free(struct snapraid_map* map)
|
|
|
|
|
{
|
|
|
|
|
free(map);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-29 17:53:40 +02:00
|
|
|
int info_time_compare(const void* void_a, const void* void_b)
|
|
|
|
|
{
|
|
|
|
|
const snapraid_info* info_a = void_a;
|
|
|
|
|
const snapraid_info* info_b = void_b;
|
|
|
|
|
time_t time_a = info_get_time(*info_a);
|
|
|
|
|
time_t time_b = info_get_time(*info_b);
|
|
|
|
|
if (time_a < time_b)
|
|
|
|
|
return -1;
|
|
|
|
|
if (time_a > time_b)
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|