mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 10:51:54 -04:00
More precise file modification time, now using nanoseconds.
This commit is contained in:
parent
97b0464d75
commit
71c7f4dffb
15 changed files with 130 additions and 40 deletions
5
HISTORY
5
HISTORY
|
|
@ -1,6 +1,11 @@
|
|||
SnapRAID HISTORY
|
||||
================
|
||||
|
||||
1.12 2012/7
|
||||
===========
|
||||
* Increased the file modification time precision. Now also nanoseconds are counted.
|
||||
Note that content files written with this version are not backward compatible.
|
||||
|
||||
1.11 2012/7
|
||||
===========
|
||||
* Fixed again directories inclusion. Exclusion rules for directories were
|
||||
|
|
|
|||
2
TODO
2
TODO
|
|
@ -3,7 +3,7 @@ SnapRAID TODO
|
|||
|
||||
This is the list of TODO items for SnapRAID.
|
||||
|
||||
- v1.11
|
||||
- v1.13
|
||||
|
||||
* In the repair() function the euristic to detect if we recovered after the sync, can be extended
|
||||
to all the subsequent blocks, because we always proceeed in block order during a sync.
|
||||
|
|
|
|||
3
check.c
3
check.c
|
|
@ -880,7 +880,8 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
|
|||
if (!collide_file /* if not in the database, there is no collision */
|
||||
|| strcmp(collide_file->sub, handle[j].file->sub) == 0 /* if the name is the same, it's the right collision */
|
||||
|| collide_file->size != handle[j].file->size /* if the size is different, the collision is identified */
|
||||
|| collide_file->mtime != handle[j].file->mtime /* if the mtime is different, the collision is identified */
|
||||
|| collide_file->mtime_sec != handle[j].file->mtime_sec /* if the mtime is different, the collision is identified */
|
||||
|| collide_file->mtime_nsec != handle[j].file->mtime_nsec
|
||||
) {
|
||||
/* set the original modification time */
|
||||
ret = handle_utime(&handle[j]);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ([2.65])
|
||||
AC_INIT([snapraid], [1.11], [], [], [http://snapraid.sourceforge.net])
|
||||
AC_INIT([snapraid], [1.12], [], [], [http://snapraid.sourceforge.net])
|
||||
AM_INIT_AUTOMAKE([foreign no-dependencies -Wall])
|
||||
AC_CONFIG_SRCDIR([snapraid.c])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
|
|
|
|||
5
elem.c
5
elem.c
|
|
@ -256,7 +256,7 @@ unsigned block_file_size(struct snapraid_block* block, unsigned block_size)
|
|||
return block_size;
|
||||
}
|
||||
|
||||
struct snapraid_file* file_alloc(unsigned block_size, const char* sub, uint64_t size, uint64_t mtime, uint64_t inode)
|
||||
struct snapraid_file* file_alloc(unsigned block_size, const char* sub, uint64_t size, uint64_t mtime_sec, int mtime_nsec, uint64_t inode)
|
||||
{
|
||||
struct snapraid_file* file;
|
||||
block_off_t i;
|
||||
|
|
@ -265,7 +265,8 @@ struct snapraid_file* file_alloc(unsigned block_size, const char* sub, uint64_t
|
|||
pathcpy(file->sub, sizeof(file->sub), sub);
|
||||
file->size = size;
|
||||
file->blockmax = (size + block_size - 1) / block_size;
|
||||
file->mtime = mtime;
|
||||
file->mtime_sec = mtime_sec;
|
||||
file->mtime_nsec = mtime_nsec;
|
||||
file->inode = inode;
|
||||
file->flag = 0;
|
||||
file->blockvec = malloc_nofail(file->blockmax * sizeof(struct snapraid_block));
|
||||
|
|
|
|||
5
elem.h
5
elem.h
|
|
@ -140,10 +140,11 @@ struct snapraid_block {
|
|||
* File.
|
||||
*/
|
||||
struct snapraid_file {
|
||||
int64_t mtime; /**< Modification time. */
|
||||
int64_t mtime_sec; /**< Modification time. */
|
||||
uint64_t inode; /**< Inode. */
|
||||
data_off_t size; /**< Size of the file. */
|
||||
struct snapraid_block* blockvec; /**< All the blocks of the file. */
|
||||
int mtime_nsec; /**< Modification time nanoseconds. Less than 1000000000. */
|
||||
block_off_t blockmax; /**< Number of blocks. */
|
||||
unsigned flag; /**< FILE_IS_* flags. */
|
||||
char sub[PATH_MAX]; /**< Sub path of the file. Without the disk dir. The disk is implicit. */
|
||||
|
|
@ -334,7 +335,7 @@ static inline void file_flag_clear(struct snapraid_file* file, unsigned mask)
|
|||
/**
|
||||
* Allocates a file.
|
||||
*/
|
||||
struct snapraid_file* file_alloc(unsigned block_size, const char* sub, uint64_t size, uint64_t mtime, uint64_t inode);
|
||||
struct snapraid_file* file_alloc(unsigned block_size, const char* sub, uint64_t size, uint64_t mtime_sec, int mtime_nsec, uint64_t inode);
|
||||
|
||||
/**
|
||||
* Deallocates a file.
|
||||
|
|
|
|||
14
handle.c
14
handle.c
|
|
@ -183,7 +183,7 @@ int handle_open(struct snapraid_handle* handle, struct snapraid_file* file)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* get the size of the exising data */
|
||||
/* get the size of the existing data */
|
||||
handle->valid_size = handle->st.st_size;
|
||||
|
||||
#if HAVE_POSIX_FADVISE
|
||||
|
|
@ -320,27 +320,27 @@ int handle_write(struct snapraid_handle* handle, struct snapraid_block* block, u
|
|||
}
|
||||
|
||||
/* Here doesn't make sense to call posix_fadvise(..., POSIX_FADV_DONTNEED) because */
|
||||
/* at this time the data is still in not yet written and it cannot be discharged. */
|
||||
/* at this time the data is still not yet written and it cannot be discharged. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_utime(struct snapraid_handle* handle)
|
||||
{
|
||||
struct timeval tv[2];
|
||||
struct timespec tv[2];
|
||||
int ret;
|
||||
|
||||
/* do nothing if not opened */
|
||||
if (handle->f == -1)
|
||||
return 0;
|
||||
|
||||
tv[0].tv_sec = handle->file->mtime;
|
||||
tv[0].tv_usec = 0;
|
||||
tv[0].tv_sec = handle->file->mtime_sec;
|
||||
tv[0].tv_nsec = handle->file->mtime_nsec;
|
||||
|
||||
tv[1].tv_sec = tv[0].tv_sec;
|
||||
tv[1].tv_usec = tv[0].tv_usec;
|
||||
tv[1].tv_nsec = tv[0].tv_nsec;
|
||||
|
||||
ret = futimes(handle->f, tv);
|
||||
ret = futimens(handle->f, tv);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Error timing file '%s'. %s.\n", handle->file->sub, strerror(errno));
|
||||
return -1;
|
||||
|
|
|
|||
64
mingw.c
64
mingw.c
|
|
@ -94,7 +94,6 @@ static wchar_t* convert(const char* src)
|
|||
{
|
||||
int ret;
|
||||
wchar_t* dst;
|
||||
int convert_slash;
|
||||
int count;
|
||||
|
||||
if (++conv_utf16 == CONV_ROLL)
|
||||
|
|
@ -159,6 +158,8 @@ static wchar_t* convert(const char* src)
|
|||
*/
|
||||
static void windows_info2stat(const BY_HANDLE_FILE_INFORMATION* info, struct windows_stat* st)
|
||||
{
|
||||
uint64_t mtime;
|
||||
|
||||
/* Convert special attributes */
|
||||
if ((info->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) != 0) {
|
||||
st->st_mode = S_IFBLK;
|
||||
|
|
@ -190,9 +191,9 @@ static void windows_info2stat(const BY_HANDLE_FILE_INFORMATION* info, struct win
|
|||
st->st_size <<= 32;
|
||||
st->st_size |= info->nFileSizeLow;
|
||||
|
||||
st->st_mtime = info->ftLastWriteTime.dwHighDateTime;
|
||||
st->st_mtime <<= 32;
|
||||
st->st_mtime |= info->ftLastWriteTime.dwLowDateTime;
|
||||
mtime = info->ftLastWriteTime.dwHighDateTime;
|
||||
mtime <<= 32;
|
||||
mtime |= info->ftLastWriteTime.dwLowDateTime;
|
||||
|
||||
/*
|
||||
* Convert to unix time
|
||||
|
|
@ -200,7 +201,9 @@ static void windows_info2stat(const BY_HANDLE_FILE_INFORMATION* info, struct win
|
|||
* How To Convert a UNIX time_t to a Win32 FILETIME or SYSTEMTIME
|
||||
* http://support.microsoft.com/kb/167296
|
||||
*/
|
||||
st->st_mtime = (st->st_mtime - 116444736000000000LL) / 10000000;
|
||||
mtime -= 116444736000000000LL;
|
||||
st->st_mtime = mtime / 10000000;
|
||||
st->st_mtim.tv_nsec = (mtime % 10000000) * 100;
|
||||
|
||||
st->st_ino = info->nFileIndexHigh;
|
||||
st->st_ino <<= 32;
|
||||
|
|
@ -216,6 +219,8 @@ static void windows_info2stat(const BY_HANDLE_FILE_INFORMATION* info, struct win
|
|||
*/
|
||||
static void windows_finddata2stat(const WIN32_FIND_DATAW* info, struct windows_stat* st)
|
||||
{
|
||||
uint64_t mtime;
|
||||
|
||||
/* Convert special attributes */
|
||||
if ((info->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) != 0) {
|
||||
st->st_mode = S_IFBLK;
|
||||
|
|
@ -247,9 +252,9 @@ static void windows_finddata2stat(const WIN32_FIND_DATAW* info, struct windows_s
|
|||
st->st_size <<= 32;
|
||||
st->st_size |= info->nFileSizeLow;
|
||||
|
||||
st->st_mtime = info->ftLastWriteTime.dwHighDateTime;
|
||||
st->st_mtime <<= 32;
|
||||
st->st_mtime |= info->ftLastWriteTime.dwLowDateTime;
|
||||
mtime = info->ftLastWriteTime.dwHighDateTime;
|
||||
mtime <<= 32;
|
||||
mtime |= info->ftLastWriteTime.dwLowDateTime;
|
||||
|
||||
/*
|
||||
* Convert to unix time
|
||||
|
|
@ -257,7 +262,9 @@ static void windows_finddata2stat(const WIN32_FIND_DATAW* info, struct windows_s
|
|||
* How To Convert a UNIX time_t to a Win32 FILETIME or SYSTEMTIME
|
||||
* http://support.microsoft.com/kb/167296
|
||||
*/
|
||||
st->st_mtime = (st->st_mtime - 116444736000000000LL) / 10000000;
|
||||
mtime -= 116444736000000000LL;
|
||||
st->st_mtime = mtime / 10000000;
|
||||
st->st_mtim.tv_nsec = (mtime % 10000000) * 100;
|
||||
|
||||
/* No inode information available */
|
||||
st->st_ino = 0;
|
||||
|
|
@ -502,6 +509,45 @@ int windows_futimes(int fd, struct timeval tv[2])
|
|||
return 0;
|
||||
}
|
||||
|
||||
int windows_futimens(int fd, struct windows_timespec tv[2])
|
||||
{
|
||||
HANDLE h;
|
||||
FILETIME ft;
|
||||
uint64_t mtime;
|
||||
|
||||
if (fd == -1) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
h = (HANDLE)_get_osfhandle(fd);
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert to windows time
|
||||
*
|
||||
* How To Convert a UNIX time_t to a Win32 FILETIME or SYSTEMTIME
|
||||
* http://support.microsoft.com/kb/167296
|
||||
*/
|
||||
mtime = tv[0].tv_sec;
|
||||
mtime *= 10000000;
|
||||
mtime += tv[0].tv_nsec / 100;
|
||||
mtime += 116444736000000000;
|
||||
|
||||
ft.dwHighDateTime = mtime >> 32;
|
||||
ft.dwLowDateTime = mtime;
|
||||
|
||||
if (!SetFileTime(h, 0, 0, &ft)) {
|
||||
windows_errno(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int windows_rename(const char* a, const char* b)
|
||||
{
|
||||
/*
|
||||
|
|
|
|||
18
mingw.h
18
mingw.h
|
|
@ -50,6 +50,7 @@
|
|||
#define readdir windows_readdir
|
||||
#define closedir windows_closedir
|
||||
#define futimes windows_futimes
|
||||
#define futimens windows_futimens
|
||||
#define O_NOFOLLOW 0
|
||||
#define stat_hidden windows_stat_hidden
|
||||
#define stat_desc windows_stat_desc
|
||||
|
|
@ -58,6 +59,10 @@
|
|||
#define readlink(a,b,c) -1
|
||||
#define symlink(a,b) -1
|
||||
|
||||
struct windows_mtim {
|
||||
int tv_nsec;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic stat information.
|
||||
*/
|
||||
|
|
@ -65,6 +70,7 @@ struct windows_stat {
|
|||
uint64_t st_ino;
|
||||
int64_t st_size;
|
||||
int64_t st_mtime;
|
||||
struct windows_mtim st_mtim;
|
||||
uint32_t st_mode;
|
||||
uint32_t st_nlink;
|
||||
uint32_t st_dev;
|
||||
|
|
@ -132,6 +138,18 @@ int windows_ftruncate(int fd, off64_t off);
|
|||
*/
|
||||
int windows_futimes(int fd, struct timeval tv[2]);
|
||||
|
||||
struct windows_timespec {
|
||||
int64_t tv_sec;
|
||||
int tv_nsec;
|
||||
};
|
||||
|
||||
#define timespec windows_timespec
|
||||
|
||||
/**
|
||||
* Like the C futimens().
|
||||
*/
|
||||
int windows_futimens(int fd, struct windows_timespec tv[2]);
|
||||
|
||||
/**
|
||||
* Like the C rename().
|
||||
*/
|
||||
|
|
|
|||
4
scan.c
4
scan.c
|
|
@ -172,7 +172,7 @@ static void scan_file(struct snapraid_scan* scan, struct snapraid_state* state,
|
|||
}
|
||||
|
||||
/* check if the file is not changed */
|
||||
if (file->size == st->st_size && file->mtime == st->st_mtime) {
|
||||
if (file->size == st->st_size && file->mtime_sec == st->st_mtime && file->mtime_nsec == st->st_mtim.tv_nsec) {
|
||||
/* mark as present */
|
||||
file_flag_set(file, FILE_IS_PRESENT);
|
||||
|
||||
|
|
@ -304,7 +304,7 @@ static void scan_file(struct snapraid_scan* scan, struct snapraid_state* state,
|
|||
}
|
||||
|
||||
/* insert it */
|
||||
file = file_alloc(state->block_size, sub, st->st_size, st->st_mtime, st->st_ino);
|
||||
file = file_alloc(state->block_size, sub, st->st_size, st->st_mtime, st->st_mtim.tv_nsec, st->st_ino);
|
||||
|
||||
/* mark it as present */
|
||||
file_flag_set(file, FILE_IS_PRESENT);
|
||||
|
|
|
|||
|
|
@ -866,7 +866,7 @@ Defines the position INDEX of the disk NAME in the parity computation.
|
|||
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 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"
|
||||
|
|
|
|||
|
|
@ -608,7 +608,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 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"
|
||||
|
|
|
|||
|
|
@ -673,8 +673,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 INODE PATH
|
||||
-----------------------------------
|
||||
10.5 file DISK SIZE TIME_SEC.TIME_NSEC INODE PATH
|
||||
-------------------------------------------------
|
||||
|
||||
Defines a file in the specified DISK.
|
||||
|
||||
|
|
|
|||
32
state.c
32
state.c
|
|
@ -841,7 +841,8 @@ void state_read(struct snapraid_state* state)
|
|||
/* file */
|
||||
char sub[PATH_MAX];
|
||||
uint64_t v_size;
|
||||
uint64_t v_mtime;
|
||||
uint64_t v_mtime_sec;
|
||||
uint32_t v_mtime_nsec;
|
||||
uint64_t v_inode;
|
||||
tommy_node* i;
|
||||
|
||||
|
|
@ -878,14 +879,24 @@ void state_read(struct snapraid_state* state)
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = sgetu64(f, &v_mtime);
|
||||
ret = sgetu64(f, &v_mtime_sec);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Invalid 'file' specification in '%s' at line %u\n", path, line);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
hash = oathash64(hash, v_mtime);
|
||||
hash = oathash64(hash, v_mtime_sec);
|
||||
|
||||
c = sgetc(f);
|
||||
if (c == '.') { /* the nanosecond field is present only from version 1.13 */
|
||||
ret = sgetu32(f, &v_mtime_nsec);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Invalid 'file' specification in '%s' at line %u\n", path, line);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
hash = oathash32(hash, v_mtime_nsec);
|
||||
|
||||
c = sgetc(f);
|
||||
}
|
||||
if (c != ' ') {
|
||||
fprintf(stderr, "Invalid 'file' specification in '%s' at line %u\n", path, line);
|
||||
exit(EXIT_FAILURE);
|
||||
|
|
@ -928,7 +939,7 @@ void state_read(struct snapraid_state* state)
|
|||
}
|
||||
|
||||
/* allocate the file */
|
||||
file = file_alloc(state->block_size, sub, v_size, v_mtime, v_inode);
|
||||
file = file_alloc(state->block_size, sub, v_size, v_mtime_sec, v_mtime_nsec, v_inode);
|
||||
|
||||
/* insert the file in the file containers */
|
||||
tommy_hashdyn_insert(&disk->inodeset, &file->nodeset, file, file_inode_hash(file->inode));
|
||||
|
|
@ -1287,11 +1298,13 @@ void state_write(struct snapraid_state* state)
|
|||
struct snapraid_file* file = j->data;
|
||||
block_off_t k;
|
||||
uint64_t size;
|
||||
uint64_t mtime;
|
||||
uint64_t mtime_sec;
|
||||
uint32_t mtime_nsec;
|
||||
uint64_t inode;
|
||||
|
||||
size = file->size;
|
||||
mtime = file->mtime;
|
||||
mtime_sec = file->mtime_sec;
|
||||
mtime_nsec = file->mtime_nsec;
|
||||
inode = file->inode;
|
||||
|
||||
sputsl("file ", f);
|
||||
|
|
@ -1302,8 +1315,11 @@ void state_write(struct snapraid_state* state)
|
|||
sputu64(size, f);
|
||||
hash = oathash64(hash, size);
|
||||
sputc(' ', f);
|
||||
sputu64(mtime, f);
|
||||
hash = oathash64(hash, mtime);
|
||||
sputu64(mtime_sec, f);
|
||||
hash = oathash64(hash, mtime_sec);
|
||||
sputc('.', f);
|
||||
sputu32(mtime_nsec, f);
|
||||
hash = oathash32(hash, mtime_nsec);
|
||||
sputc(' ', f);
|
||||
sputu64(inode, f);
|
||||
hash = oathash64(hash, inode);
|
||||
|
|
|
|||
8
sync.c
8
sync.c
|
|
@ -196,12 +196,14 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
|
|||
|
||||
/* check if the file is changed */
|
||||
if (handle[j].st.st_size != block_file_get(block)->size
|
||||
|| handle[j].st.st_mtime != block_file_get(block)->mtime
|
||||
|| handle[j].st.st_mtime != block_file_get(block)->mtime_sec
|
||||
|| handle[j].st.st_mtim.tv_nsec != block_file_get(block)->mtime_nsec
|
||||
|| handle[j].st.st_ino != block_file_get(block)->inode
|
||||
) {
|
||||
if (handle[j].st.st_size != block_file_get(block)->size)
|
||||
fprintf(stderr, "Unexpected size change at file '%s'.\n", handle[j].path);
|
||||
else if (handle[j].st.st_mtime != block_file_get(block)->mtime)
|
||||
else if (handle[j].st.st_mtime != block_file_get(block)->mtime_sec
|
||||
|| handle[j].st.st_mtim.tv_nsec != block_file_get(block)->mtime_nsec)
|
||||
fprintf(stderr, "Unexpected time change at file '%s'.\n", handle[j].path);
|
||||
else
|
||||
fprintf(stderr, "Unexpected inode change from %"PRIu64" to %"PRIu64" at file '%s'.\n", block_file_get(block)->inode, handle[j].st.st_ino, handle[j].path);
|
||||
|
|
@ -209,7 +211,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
|
|||
|
||||
++unrecoverable_error;
|
||||
|
||||
/* if the file is charnged, it means that it was modified during sync */
|
||||
/* if the file is changed, it means that it was modified during sync */
|
||||
/* this isn't a serious error, so we skip this block, and continue with others */
|
||||
skip_this_block = 1;
|
||||
continue;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue