diff --git a/HISTORY b/HISTORY index 1ee38c84..4646f987 100644 --- a/HISTORY +++ b/HISTORY @@ -16,6 +16,13 @@ SnapRAID HISTORY only for blocks that really are changed. * Reduced memory usage avoiding to allocate unnecessary memory. +4.2 2013/9 (BETA) +================= + * Fixed the wrong warning about physical offsets not supported caused + by files not having a real offset because too small. + For example, in NTFS it's possible to store such files in the MFT. + It's just a cosmetic change, and not a functional one. + 4.1 2013/9 ========== * If the underline filesystem doesn't support the FIEMAP command, diff --git a/mingw.c b/mingw.c index 7057ee11..71f3d51b 100644 --- a/mingw.c +++ b/mingw.c @@ -1130,7 +1130,12 @@ int filephy(const char* file, struct stat* st, uint64_t* physical) } else if (error == ERROR_HANDLE_EOF) { /* if the file is small, it can be stored in the Master File Table (MFT) */ /* and then it doesn't have a physical address */ - rpb->ExtentCount = 0; + /* In such case we report a specific fake address, to report this special condition */ + /* that it's different from the 0 offset reported by the underline file system */ + *physical = FILEPHY_WITHOUT_OFFSET; + + CloseHandle(h); + return 0; } else { windows_errno(error); CloseHandle(h); @@ -1141,9 +1146,9 @@ int filephy(const char* file, struct stat* st, uint64_t* physical) CloseHandle(h); if (rpb->ExtentCount < 1) - *physical = 0; + *physical = FILEPHY_UNREPORTED_OFFSET; else - *physical = rpb->Extents[0].Lcn.QuadPart; + *physical = rpb->Extents[0].Lcn.QuadPart + FILEPHY_REAL_OFFSET; return 0; } diff --git a/portable.h b/portable.h index 4922d2f0..ccaa34fa 100644 --- a/portable.h +++ b/portable.h @@ -187,6 +187,22 @@ static inline int hardlink(const char* a, const char* b) */ int devuuid(uint64_t device, char* uuid, size_t size); +/** + * Special value returned when the file doesn't have a real offset. + * For example, because it's stored in the NTFS MFT. + */ +#define FILEPHY_WITHOUT_OFFSET 0 + +/** + * Special value returned when the filesystem doesn't report any offset for unknown reason. + */ +#define FILEPHY_UNREPORTED_OFFSET 1 + +/** + * Value indicating real offsets. All offsets greater or equal at this one are real. + */ +#define FILEPHY_REAL_OFFSET 2 + /** * Get the physcal address of the specified file. * This is expected to be just a hint and not necessarely correct or unique. diff --git a/scan.c b/scan.c index 5b1ebb54..184ffbd3 100644 --- a/scan.c +++ b/scan.c @@ -991,7 +991,7 @@ void state_scan(struct snapraid_state* state, int output) /* if the file is not empty, count duplicate physical offsets */ if (state->opt.force_order == SORT_PHYSICAL && file->size != 0) { - if (phy_count > 0 && file->physical == phy_last) + if (phy_count > 0 && file->physical == phy_last && phy_last != FILEPHY_WITHOUT_OFFSET) ++phy_dup; phy_last = file->physical; ++phy_count; diff --git a/unix.c b/unix.c index a775b9da..f6c646a1 100644 --- a/unix.c +++ b/unix.c @@ -149,7 +149,7 @@ int filephy(const char* path, struct stat* st, uint64_t* physical) fm.fiemap.fm_extent_count = 1; /* we are interested only at the first block */ if (ioctl(f, FS_IOC_FIEMAP, &fm) != -1) { - *physical = fm.fiemap.fm_extents[0].fe_physical; + *physical = fm.fiemap.fm_extents[0].fe_physical + FILEPHY_REAL_OFFSET; if (close(f) == -1) return -1; return 0; @@ -157,7 +157,7 @@ int filephy(const char* path, struct stat* st, uint64_t* physical) /* if empty, FIBMAP doesn't work */ if (st->st_size == 0) { - *physical = 0; + *physical = FILEPHY_WITHOUT_OFFSET; if (close(f) == -1) return -1; return 0; @@ -168,7 +168,7 @@ int filephy(const char* path, struct stat* st, uint64_t* physical) /* in exfat it always returns 0, that it's anyway better than the fake inodes */ blknum = 0; /* first block */ if (ioctl(f, FIBMAP, &blknum) != -1) { - *physical = blknum; + *physical = blknum + FILEPHY_REAL_OFFSET; if (close(f) == -1) return -1; return 0; @@ -177,13 +177,13 @@ int filephy(const char* path, struct stat* st, uint64_t* physical) /* otherwise don't use anything, and keep the existing order */ /* at now this should happen only for vfat */ /* and it's surely better than using fake inodes */ - *physical = 0; + *physical = FILEPHY_UNREPORTED_OFFSET; if (close(f) == -1) return -1; #else /* In a generic Unix use a dummy value for all the files */ /* We don't want to risk to use the inode without knowing if it really improves performance */ - *physical = 0; + *physical = FILEPHY_UNREPORTED_OFFSET; (void)path; /* not used here */ (void)st;