Saves and restores also empty directories.

This commit is contained in:
Andrea Mazzoleni 2013-01-27 16:44:04 +01:00
parent bf0ab70a00
commit a0a213664b
12 changed files with 471 additions and 25 deletions

View file

@ -1,6 +1,10 @@
SnapRAID HISTORY
================
2.2 2013/2
==========
* Syncs and fixes also empty directories.
2.1 2013/1
==========
* Checks for wrong empty fields in the configuration file.

View file

@ -105,8 +105,13 @@ check-local:
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid5.conf -a check
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf check
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf -a check
echo --- Create some more files, sync raid5 and check
echo --- Create some more files and empty directories, sync raid5 and check
$(TESTENV) ./mktest$(EXEEXT) generate 2 3 $(CHECKCOUNT) $(CHECKSIZE)
mkdir test/disk1/empty1
mkdir test/disk2/empty2
mkdir test/disk3/empty3a
mkdir test/disk3/empty3a/emptyinner
mkdir test/disk3/empty3b
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -v -c $(srcdir)/test-raid5.conf diff
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -v -c $(srcdir)/test-raid5.conf dup
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -v -c $(srcdir)/test-raid5.conf sync

17
TODO
View file

@ -5,9 +5,10 @@ This is the list of TODO items for SnapRAID.
- v2.2
* Allow to specify more than one disk directories to cover the case of multi partitions.
* Keep track of empty directories and restore them.
* Implement an "undelete" command to recover missing files, without the
integrity check of the existing ones.
It should restore only missing files, without recovering modified ones
or check validity of data of existing ones.
* If a content file is missing, sync should rewrite it, even if no change was done at the content.
@ -18,17 +19,13 @@ This will also help when running with the parity filesystem unmounted.
* Filtered out files should be opened in read-only mode.
* Implement an "undelete" command to recover missing files, without the
integrity check of the existing ones.
It should restore only missing files, without recovering modified ones
or check validity of data of existing ones.
* Adds a log option, to save log files with the date in the name. This could
help to keep track of what happens during automated operations.
We must keep the log to stdout/err, and only save a copy to the log file.
* In fix an existing symlink with the same name of a file to be recovered may stop
the process making the create() operation to fail.
The same for directories, when recreating the directory tree.
* If a directory exists with the same name of a parity/content file be more explicative
on the error message. See: https://sourceforge.net/projects/snapraid/forums/forum/1677233/topic/4861034
@ -105,6 +102,10 @@ Rejected TODO
This is a list of rejected TODO items.
* Allow to specify more than one disk directories to cover the case of multi partitions.
- Different partitions have duplicate inode. The only way to support this is to
add also a kind of device_id, increasing the memory required.
* Recognizes that a file is moved from one disk to another, and if the parity
data doesn't overlap, do not recompute it.
- It's going to work only in RAID5 mode and only in special cases.

72
check.c
View file

@ -1118,6 +1118,78 @@ static int state_check_process(struct snapraid_state* state, int check, int fix,
}
}
/* check all dirs */
for(i=0;i<diskmax;++i) {
tommy_node* node;
struct snapraid_disk* disk;
if (!handle[i].disk)
continue;
/* for each dir in the disk */
disk = handle[i].disk;
node = disk->dirlist;
while (node) {
char path[PATH_MAX];
struct stat st;
struct snapraid_dir* dir;
int failed = 0;
dir = node->data;
node = node->next; /* next node */
/* if excluded continue to the next one */
if (dir_flag_has(dir, FILE_IS_EXCLUDED)) {
continue;
}
/* stat the dir */
pathprint(path, sizeof(path), "%s%s", disk->dir, dir->sub);
ret = stat(path, &st);
if (ret == -1) {
failed = 1;
fprintf(stderr, "Error stating dir '%s'. %s.\n", path, strerror(errno));
fprintf(stderr, "dir_error:%s:%s: Dir stat error\n", disk->name, dir->sub);
++error;
} else if (!S_ISDIR(st.st_mode)) {
failed = 1;
fprintf(stderr, "dir_error:%s:%s: Dir error for not directory\n", disk->name, dir->sub);
++error;
}
if (fix && failed) {
/* create the ancestor directories */
ret = handle_ancestor(path);
if (ret != 0) {
fprintf(stderr, "WARNING! Without a working data disk, it isn't possible to fix errors on it.\n");
printf("Stopping\n");
++unrecoverable_error;
goto bail;
}
/* create it */
ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
if (ret != 0) {
fprintf(stderr, "Error creating dir '%s'. %s.\n", path, strerror(errno));
if (errno == EACCES) {
fprintf(stderr, "WARNING! Please give write permission to the dir.\n");
} else {
/* we do not use DANGER because it could be ENOSPC which is not always correctly reported */
fprintf(stderr, "WARNING! Without a working data disk, it isn't possible to fix errors on it.\n");
}
printf("Stopping\n");
++unrecoverable_error;
goto bail;
}
fprintf(stderr, "dir_fixed:%s:%s: Fixed dir error\n", disk->name, dir->sub);
++recovered_error;
}
}
}
state_progress_end(state, countpos, countmax, countsize);
bail:

27
elem.c
View file

@ -373,6 +373,29 @@ int link_name_compare(const void* void_arg, const void* void_data)
return strcmp(arg, link->sub);
}
struct snapraid_dir* dir_alloc(const char* sub)
{
struct snapraid_dir* dir;
dir = malloc_nofail(sizeof(struct snapraid_dir));
pathcpy(dir->sub, sizeof(dir->sub), sub);
dir->flag = 0;
return dir;
}
void dir_free(struct snapraid_dir* dir)
{
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);
}
struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev)
{
struct snapraid_disk* disk;
@ -391,6 +414,8 @@ struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev
tommy_hashdyn_init(&disk->pathset);
tommy_list_init(&disk->linklist);
tommy_hashdyn_init(&disk->linkset);
tommy_list_init(&disk->dirlist);
tommy_hashdyn_init(&disk->dirset);
tommy_array_init(&disk->blockarr);
return disk;
@ -403,6 +428,8 @@ void disk_free(struct snapraid_disk* disk)
tommy_hashdyn_done(&disk->pathset);
tommy_list_foreach(&disk->linklist, (tommy_foreach_func*)link_free);
tommy_hashdyn_done(&disk->linkset);
tommy_list_foreach(&disk->dirlist, (tommy_foreach_func*)dir_free);
tommy_hashdyn_done(&disk->dirset);
tommy_array_done(&disk->blockarr);
free(disk);
}

53
elem.h
View file

@ -175,6 +175,19 @@ struct snapraid_link {
tommy_hashdyn_node nodeset;
};
/**
* Dir.
*/
struct snapraid_dir {
unsigned flag; /**< FILE_IS_* flags. */
char sub[PATH_MAX]; /**< Sub path of the file. Without the disk dir. The disk is implicit. */
/* nodes for data structures */
tommy_node nodelist;
tommy_hashdyn_node nodeset;
};
/**
* Disk.
*/
@ -188,6 +201,8 @@ struct snapraid_disk {
tommy_hashdyn pathset; /**< Hashtable by path of all the files. */
tommy_list linklist; /**< List of all the links. */
tommy_hashdyn linkset; /**< Hashtable by name of all the links. */
tommy_list dirlist; /**< List of all the dirs. */
tommy_hashdyn dirset; /**< Hashtable by name of all the dirs. */
tommy_array blockarr; /**< Block array of the disk. */
/* nodes for data structures */
@ -423,6 +438,44 @@ static inline tommy_uint32_t link_name_hash(const char* name)
return tommy_hash_u32(0, name, strlen(name));
}
static inline int dir_flag_has(struct snapraid_dir* dir, unsigned mask)
{
return (dir->flag & mask) == mask;
}
static inline void dir_flag_set(struct snapraid_dir* dir, unsigned mask)
{
dir->flag |= mask;
}
static inline void dir_flag_clear(struct snapraid_dir* dir, unsigned mask)
{
dir->flag &= ~mask;
}
/**
* Allocates a dir.
*/
struct snapraid_dir* dir_alloc(const char* name);
/**
* Deallocates a dir.
*/
void dir_free(struct snapraid_dir* dir);
/**
* Compare a dir with a name.
*/
int dir_name_compare(const void* void_arg, const void* void_data);
/**
* Computes the hash of a dir name.
*/
static inline tommy_uint32_t dir_name_hash(const char* name)
{
return tommy_hash_u32(0, name, strlen(name));
}
/**
* Allocates a disk.
*/

144
scan.c
View file

@ -33,6 +33,7 @@ struct snapraid_scan {
tommy_list file_insert_list; /**< Files to insert. */
tommy_list link_insert_list; /**< Links to insert. */
tommy_list dir_insert_list; /**< Dirs to insert. */
/* nodes for data structures */
tommy_node node;
@ -434,10 +435,95 @@ static void scan_link(struct snapraid_scan* scan, struct snapraid_state* state,
}
/**
* Processes a directory.
* Removes the specified dir from the data set.
*/
static void scan_dir(struct snapraid_scan* scan, struct snapraid_state* state, int output, struct snapraid_disk* disk, const char* dir, const char* sub)
static void scan_emptydir_remove(struct snapraid_state* state, struct snapraid_disk* disk, struct snapraid_dir* dir)
{
/* state changed */
state->need_write = 1;
/* remove the file from the dir containers */
tommy_hashdyn_remove_existing(&disk->dirset, &dir->nodeset);
tommy_list_remove_existing(&disk->dirlist, &dir->nodelist);
/* deallocate */
dir_free(dir);
}
/**
* Inserts the specified dir in the data set.
*/
static void scan_emptydir_insert(struct snapraid_state* state, struct snapraid_disk* disk, struct snapraid_dir* dir)
{
/* state changed */
state->need_write = 1;
/* insert the dir in the dir containers */
tommy_hashdyn_insert(&disk->dirset, &dir->nodeset, dir, dir_name_hash(dir->sub));
tommy_list_insert_tail(&disk->dirlist, &dir->nodelist, dir);
}
/**
* Processes a dir.
*/
static void scan_emptydir(struct snapraid_scan* scan, struct snapraid_state* state, int output, struct snapraid_disk* disk, const char* sub)
{
struct snapraid_dir* dir;
/* check if the dir already exists */
dir = tommy_hashdyn_search(&disk->dirset, dir_name_compare, sub, dir_name_hash(sub));
if (dir) {
/* check if multiple files have the same name */
if (dir_flag_has(dir, FILE_IS_PRESENT)) {
fprintf(stderr, "Internal inconsistency for symdir '%s%s'\n", disk->dir, sub);
exit(EXIT_FAILURE);
}
/* mark as present */
dir_flag_set(dir, FILE_IS_PRESENT);
/* it's equal */
++scan->count_equal;
if (state->gui) {
fprintf(stderr, "scan:equal:%s:%s\n", disk->name, dir->sub);
fflush(stderr);
}
/* nothing more to do */
return;
} else {
/* create the new dir */
++scan->count_insert;
if (state->gui) {
fprintf(stderr, "scan:add:%s:%s\n", disk->name, sub);
fflush(stderr);
}
if (output) {
printf("Add '%s%s'\n", disk->dir, sub);
}
/* and continue to insert it */
}
/* insert it */
dir = dir_alloc(sub);
/* mark it as present */
dir_flag_set(dir, FILE_IS_PRESENT);
/* insert it in the delayed insert list */
tommy_list_insert_tail(&scan->dir_insert_list, &dir->nodelist, dir);
}
/**
* Processes a directory.
* Return != 0 if at least one file or link is processed.
*/
static int scan_dir(struct snapraid_scan* scan, struct snapraid_state* state, int output, struct snapraid_disk* disk, const char* dir, const char* sub)
{
int processed = 0;
DIR* d;
d = opendir(dir);
@ -525,6 +611,7 @@ static void scan_dir(struct snapraid_scan* scan, struct snapraid_state* state, i
#endif
scan_file(scan, state, output, disk, sub_next, &st);
processed = 1;
} else {
if (state->verbose) {
printf("Excluding file '%s'\n", path_next);
@ -549,6 +636,7 @@ static void scan_dir(struct snapraid_scan* scan, struct snapraid_state* state, i
subnew[ret] = 0;
scan_link(scan, state, output, disk, sub_next, subnew);
processed = 1;
} else {
if (state->verbose) {
printf("Excluding link '%s'\n", path_next);
@ -556,9 +644,18 @@ static void scan_dir(struct snapraid_scan* scan, struct snapraid_state* state, i
}
} else if (S_ISDIR(st.st_mode)) {
if (filter_dir(&state->filterlist, disk->name, sub_next) == 0) {
char sub_dir[PATH_MAX];
/* recurse */
pathslash(path_next, sizeof(path_next));
pathslash(sub_next, sizeof(sub_next));
scan_dir(scan, state, output, disk, path_next, sub_next);
pathcpy(sub_dir, sizeof(sub_dir), sub_next);
pathslash(sub_dir, sizeof(sub_dir));
if (scan_dir(scan, state, output, disk, path_next, sub_dir) == 0) {
/* scan the directory as empty dir */
scan_emptydir(scan, state, output, disk, sub_next);
}
/* or we processed something internally, or we have added the empty dir */
processed = 1;
} else {
if (state->verbose) {
printf("Excluding directory '%s'\n", path_next);
@ -579,6 +676,8 @@ static void scan_dir(struct snapraid_scan* scan, struct snapraid_state* state, i
fprintf(stderr, "Error closing directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
}
return processed;
}
void state_scan(struct snapraid_state* state, int output)
@ -602,6 +701,7 @@ void state_scan(struct snapraid_state* state, int output)
scan->count_insert = 0;
tommy_list_init(&scan->file_insert_list);
tommy_list_init(&scan->link_insert_list);
tommy_list_init(&scan->dir_insert_list);
tommy_list_insert_tail(&scanlist, &scan->node, scan);
@ -657,6 +757,30 @@ void state_scan(struct snapraid_state* state, int output)
}
}
/* check for removed dirs */
node = disk->dirlist;
while (node) {
struct snapraid_dir* dir = node->data;
/* next node */
node = node->next;
/* remove if not present */
if (!dir_flag_has(dir, FILE_IS_PRESENT)) {
++scan->count_remove;
if (state->gui) {
fprintf(stderr, "scan:remove:%s:%s\n", disk->name, dir->sub);
fflush(stderr);
}
if (output) {
printf("Remove '%s%s'\n", disk->dir, dir->sub);
}
scan_emptydir_remove(state, disk, dir);
}
}
/* insert all the new files, we insert them only after the deletion */
/* to reuse the just freed space */
node = scan->file_insert_list;
@ -681,6 +805,18 @@ void state_scan(struct snapraid_state* state, int output)
/* insert it */
scan_link_insert(state, disk, link);
}
/* insert all the new dirs */
node = scan->dir_insert_list;
while (node) {
struct snapraid_dir* dir = node->data;
/* next node */
node = node->next;
/* insert it */
scan_emptydir_insert(state, disk, dir);
}
}
/* checks for disks where all the previously existing files where removed */

View file

@ -114,7 +114,7 @@ With a Backup you are able to recover from a complete
failure of the whole disk array.
.IP \(bu
Only file data, time and symlinks are saved. Permissions,
extended attributes and hard\(hylinks are not saved.
ownership, extended attributes and hard\(hylinks are not saved.
.PD
.SH GETTING STARTED
To use SnapRAID you need to first select one disk of your disk array
@ -904,14 +904,15 @@ This file is read and written by the \(a"sync\(a" command, and only read by
Defines the size of the block in bytes. It must match the size
defined in the configuration file.
.SS checksum CHECKSUM
Defines the checksum kind used. It can be \(a"md5\(a" or \(a"murmur3\(a".
Defines the checksum kind used. It can be only \(a"murmur3\(a".
From SnapRAID 2.0 the old \(a"md5\(a" checksum is not supported anymore.
.SS map NAME INDEX
Defines the position INDEX of the disk NAME in the parity computation.
.SS sign SIGN
Signature checksum of the content file to ensure that it doesn\(cqt get
corrupted. If you want to modify the content file manually, you have
to remove this line to avoid this check.
.SS file DISK SIZE TIME_SEC.TIME_NSEC INODE PATH
.SS file DISK SIZE TIME_SEC[.TIME_NSEC] INODE PATH
Defines a file in the specified DISK.
.PP
The INODE number is used to identify the file in the \(a"sync\(a"
@ -922,6 +923,10 @@ The SIZE and TIME information are used to identify if the file
changed from the last \(a"sync\(a" command, and if there is the need
to recompute the parity.
.PP
The [.TIME_NSEC] information is optional, and only present if
it\(cqs possible to read a such precise time information.
It\(cqs present only from SnapRAID 2.0.
.PP
The PATH information is used in the \(a"check\(a" and \(a"fix\(a" commands
to identify the file.
.SS blk BLOCK HASH
@ -962,6 +967,15 @@ for which the parity is computed using the previous value.
.PP
This field is used only when you interrupt manually the \(a"sync\(a"
command.
.SS symlink DISK PATH
Defines a symbolic link in the specified DISK.
.SS to PATH
Defines where the previous symlink links to.
.SS dir DISK PATH
Defines an empty directory in the specified DISK.
.PP
Directory that contains saved files, are not included, as they
are implicitely defined in the file specifications.
.SH PARITY
SnapRAID stores the redundancy information of your array in the parity
and q\(hyparity files.

View file

@ -71,7 +71,7 @@ Limitations
With a Backup you are able to recover from a complete
failure of the whole disk array.
* Only file data, time and symlinks are saved. Permissions,
extended attributes and hard-links are not saved.
ownership, extended attributes and hard-links are not saved.
Getting Started
To use SnapRAID you need to first select one disk of your disk array
@ -637,7 +637,8 @@ Content
defined in the configuration file.
checksum CHECKSUM
Defines the checksum kind used. It can be "md5" or "murmur3".
Defines the checksum kind used. It can be only "murmur3".
From SnapRAID 2.0 the old "md5" checksum is not supported anymore.
map NAME INDEX
Defines the position INDEX of the disk NAME in the parity computation.
@ -647,7 +648,7 @@ Content
corrupted. If you want to modify the content file manually, you have
to remove this line to avoid this check.
file DISK SIZE TIME_SEC.TIME_NSEC INODE PATH
file DISK SIZE TIME_SEC[.TIME_NSEC] INODE PATH
Defines a file in the specified DISK.
The INODE number is used to identify the file in the "sync"
@ -658,6 +659,10 @@ Content
changed from the last "sync" command, and if there is the need
to recompute the parity.
The [.TIME_NSEC] information is optional, and only present if
it's possible to read a such precise time information.
It's present only from SnapRAID 2.0.
The PATH information is used in the "check" and "fix" commands
to identify the file.
@ -705,6 +710,18 @@ Content
This field is used only when you interrupt manually the "sync"
command.
symlink DISK PATH
Defines a symbolic link in the specified DISK.
to PATH
Defines where the previous symlink links to.
dir DISK PATH
Defines an empty directory in the specified DISK.
Directory that contains saved files, are not included, as they
are implicitely defined in the file specifications.
Parity
SnapRAID stores the redundancy information of your array in the parity
and q-parity files.

View file

@ -81,7 +81,7 @@ Other limitations are:
With a Backup you are able to recover from a complete
failure of the whole disk array.
* Only file data, time and symlinks are saved. Permissions,
extended attributes and hard-links are not saved.
ownership, extended attributes and hard-links are not saved.
4 GETTING STARTED
@ -698,7 +698,8 @@ defined in the configuration file.
10.2 checksum CHECKSUM
----------------------
Defines the checksum kind used. It can be "md5" or "murmur3".
Defines the checksum kind used. It can be only "murmur3".
From SnapRAID 2.0 the old "md5" checksum is not supported anymore.
10.3 map NAME INDEX
-------------------
@ -712,8 +713,8 @@ Signature checksum of the content file to ensure that it doesn't get
corrupted. If you want to modify the content file manually, you have
to remove this line to avoid this check.
10.5 file DISK SIZE TIME_SEC.TIME_NSEC INODE PATH
-------------------------------------------------
10.5 file DISK SIZE TIME_SEC[.TIME_NSEC] INODE PATH
---------------------------------------------------
Defines a file in the specified DISK.
@ -725,6 +726,10 @@ The SIZE and TIME information are used to identify if the file
changed from the last "sync" command, and if there is the need
to recompute the parity.
The [.TIME_NSEC] information is optional, and only present if
it's possible to read a such precise time information.
It's present only from SnapRAID 2.0.
The PATH information is used in the "check" and "fix" commands
to identify the file.
@ -784,6 +789,24 @@ for which the parity is computed using the previous value.
This field is used only when you interrupt manually the "sync"
command.
10.12 symlink DISK PATH
-----------------------
Defines a symbolic link in the specified DISK.
10.13 to PATH
-------------
Defines where the previous symlink links to.
10.14 dir DISK PATH
-------------------
Defines an empty directory in the specified DISK.
Directory that contains saved files, are not included, as they
are implicitely defined in the file specifications.
11 PARITY
=========

94
state.c
View file

@ -691,12 +691,14 @@ void state_read(struct snapraid_state* state)
unsigned count_file;
unsigned count_block;
unsigned count_link;
unsigned count_dir;
tommy_node* node;
oathash_t hash;
count_file = 0;
count_block = 0;
count_link = 0;
count_dir = 0;
hash = 0;
/* iterate over all the available content files and load the first one present */
@ -1125,6 +1127,59 @@ void state_read(struct snapraid_state* state)
/* stat */
++count_link;
} else if (strcmp(tag, "dir") == 0) {
/* symlink */
char sub[PATH_MAX];
tommy_node* i;
struct snapraid_dir* dir;
hash = oathash8(hash, 'r');
ret = sgettok(f, buffer, sizeof(buffer));
if (ret < 0) {
fprintf(stderr, "Invalid 'dir' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
hash = oathashs(hash, buffer);
c = sgetc(f);
if (c != ' ') {
fprintf(stderr, "Invalid 'dir' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
ret = sgetline(f, sub, sizeof(sub));
if (ret < 0) {
fprintf(stderr, "Invalid 'dir' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
if (!*sub) {
fprintf(stderr, "Invalid 'dir' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
hash = oathashs(hash, sub);
/* find the disk */
for(i=state->disklist;i!=0;i=i->next) {
disk = i->data;
if (strcmp(disk->name, buffer) == 0)
break;
}
if (!i) {
fprintf(stderr, "Disk named '%s' not found in '%s' at line %u\n", buffer, path, line);
exit(EXIT_FAILURE);
}
/* allocate the dir */
dir = dir_alloc(sub);
/* insert the dir in the dir containers */
tommy_hashdyn_insert(&disk->dirset, &dir->nodeset, dir, dir_name_hash(dir->sub));
tommy_list_insert_tail(&disk->dirlist, &dir->nodelist, dir);
/* stat */
++count_dir;
} else if (strcmp(tag, "checksum") == 0) {
hash = oathash8(hash, 'c');
@ -1258,6 +1313,7 @@ void state_read(struct snapraid_state* state)
printf("\tfile %u\n", count_file);
printf("\tblock %u\n", count_block);
printf("\tsymlink %u\n", count_link);
printf("\temptydir %u\n", count_dir);
}
}
@ -1267,6 +1323,7 @@ void state_write(struct snapraid_state* state)
unsigned count_file;
unsigned count_block;
unsigned count_link;
unsigned count_dir;
unsigned count_content;
tommy_node* i;
unsigned k;
@ -1275,6 +1332,7 @@ void state_write(struct snapraid_state* state)
count_file = 0;
count_block = 0;
count_link = 0;
count_dir = 0;
hash = 0;
/* count the content files */
@ -1466,6 +1524,26 @@ void state_write(struct snapraid_state* state)
++count_link;
}
/* for each dir */
for(j=disk->dirlist;j!=0;j=j->next) {
struct snapraid_dir* dir = j->data;
sputsl("dir ", f);
hash = oathash8(hash, 'r');
sputs(disk->name, f);
hash = oathashs(hash, disk->name);
sputc(' ', f);
sputs(dir->sub, f);
hash = oathashs(hash, dir->sub);
sputeol(f);
if (serror(f)) {
fprintf(stderr, "Error writing the content file '%s'. %s.\n", serrorfile(f), strerror(errno));
exit(EXIT_FAILURE);
}
++count_dir;
}
{
block_off_t k;
block_off_t blockmax;
@ -1552,6 +1630,7 @@ void state_write(struct snapraid_state* state)
printf("\tfile %u\n", count_file);
printf("\tblock %u\n", count_block);
printf("\tsymlink %u\n", count_link);
printf("\temptydir %u\n", count_dir);
}
state->need_write = 0; /* no write needed anymore */
@ -1619,6 +1698,21 @@ void state_filter(struct snapraid_state* state, tommy_list* filterlist_file, tom
printf("Processing symlink '%s'\n", link->sub);
}
}
/* for each dir */
for(j=tommy_list_head(&disk->dirlist);j!=0;j=j->next) {
struct snapraid_dir* dir = j->data;
if (filter_dir(filterlist_disk, disk->name, dir->sub) != 0
|| filter_dir(filterlist_file, disk->name, dir->sub) != 0
) {
dir_flag_set(dir, FILE_IS_EXCLUDED);
}
if (state->verbose && !dir_flag_has(dir, FILE_IS_EXCLUDED)) {
printf("Processing dir '%s'\n", dir->sub);
}
}
}
}

View file

@ -108,8 +108,8 @@ void state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t
void state_dup(struct snapraid_state* state);
/**
* Filter files.
* Apply and additional filter to list of file currently loaded.
* Filter files, symlinks and dirs.
* Apply an additional filter to the list currently loaded.
*/
void state_filter(struct snapraid_state* state, tommy_list* filterlist_file, tommy_list* filterlist_disk);