wposix: seriously speed up mounting by removing hand-brake (i.e. checking file system name in every stat() ) call. thanks to philip for reporting the problem!
This was SVN commit r2097.
This commit is contained in:
parent
0eb78450c0
commit
dfb576c563
@ -163,6 +163,60 @@ int ioctl(int fd, int op, int* data)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// determine file system type on the current drive -
|
||||||
|
// needed to work around incorrect FAT time translation.
|
||||||
|
//
|
||||||
|
|
||||||
|
static enum Filesystem
|
||||||
|
{
|
||||||
|
FS_INVALID, // detect_filesystem() not yet called
|
||||||
|
FS_FAT, // FAT12, FAT16, or FAT32
|
||||||
|
FS_NTFS, // (most common)
|
||||||
|
FS_UNKNOWN // newer FS we don't know about
|
||||||
|
}
|
||||||
|
filesystem;
|
||||||
|
|
||||||
|
|
||||||
|
// rationale: the previous method of checking every path was way too slow
|
||||||
|
// (taking ~800ms total during init). instead, we only determine the FS once.
|
||||||
|
// this is quite a bit easier than intercepting chdir() calls and/or
|
||||||
|
// caching FS type per drive letter, but not foolproof.
|
||||||
|
//
|
||||||
|
// if some data files are on a different volume that is set up as FAT,
|
||||||
|
// the workaround below won't be triggered (=> timestamps may be off by
|
||||||
|
// 1 hour when DST is in effect). oh well, that is not a supported.
|
||||||
|
//
|
||||||
|
// the common case (everything is on a single NTFS volume) is more important
|
||||||
|
// and must run without penalty.
|
||||||
|
|
||||||
|
|
||||||
|
// called from the first filetime_to_time_t() call, not win.cpp init;
|
||||||
|
// this means we can rely on the current directory having been set to
|
||||||
|
// the app's directory (and therefore its appendant volume - see above).
|
||||||
|
static void detect_filesystem()
|
||||||
|
{
|
||||||
|
char root_path[MAX_PATH] = "c:\\"; // default in case GCD fails
|
||||||
|
DWORD gcd_ret = GetCurrentDirectory(sizeof(root_path), root_path);
|
||||||
|
assert2(gcd_ret != 0);
|
||||||
|
// if this fails, no problem - we have the default from above.
|
||||||
|
root_path[3] = '\0'; // cut off after "c:\"
|
||||||
|
|
||||||
|
char fs_name[32];
|
||||||
|
BOOL ret = GetVolumeInformation(root_path, 0,0,0,0,0, fs_name, sizeof(fs_name));
|
||||||
|
assert2(ret != 0);
|
||||||
|
// if this fails, no problem - we really only care if fs is FAT,
|
||||||
|
// and will assume that's not the case (since fs_name != "FAT").
|
||||||
|
|
||||||
|
filesystem = FS_UNKNOWN;
|
||||||
|
|
||||||
|
if(!strncmp(fs_name, "FAT", 3)) // e.g. FAT32
|
||||||
|
filesystem = FS_FAT;
|
||||||
|
else if(!strcmp(fs_name, "NTFS"))
|
||||||
|
filesystem = FS_NTFS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// from wtime
|
// from wtime
|
||||||
extern time_t local_filetime_to_time_t(FILETIME* ft);
|
extern time_t local_filetime_to_time_t(FILETIME* ft);
|
||||||
extern time_t utc_filetime_to_time_t(FILETIME* ft);
|
extern time_t utc_filetime_to_time_t(FILETIME* ft);
|
||||||
@ -170,32 +224,18 @@ extern time_t utc_filetime_to_time_t(FILETIME* ft);
|
|||||||
// convert Windows FILETIME to POSIX time_t (seconds-since-1970 UTC);
|
// convert Windows FILETIME to POSIX time_t (seconds-since-1970 UTC);
|
||||||
// used by stat and readdir_stat_np for st_mtime.
|
// used by stat and readdir_stat_np for st_mtime.
|
||||||
//
|
//
|
||||||
// path is used to determine the file system that recorded the time
|
// works around a documented Windows bug in converting FAT file times
|
||||||
// (workaround for a documented Windows bug in converting FAT file times)
|
// (correct results are desired since VFS mount logic considers
|
||||||
//
|
// files 'equal' if their mtime and size are the same).
|
||||||
// note: complicated because we need to ensure the time returned is correct:
|
static time_t filetime_to_time_t(FILETIME* ft)
|
||||||
// VFS mount logic considers files 'equal' if mtime and size are the same.
|
|
||||||
static time_t filetime_to_time_t(FILETIME* ft, const char* path)
|
|
||||||
{
|
{
|
||||||
// determine file system on volume containing path:
|
ONCE(detect_filesystem());
|
||||||
// .. assume relative path
|
|
||||||
const char* root = 0;
|
|
||||||
char drive_str[] = "?:\\";
|
|
||||||
// .. it's an absolute path
|
|
||||||
if(isalpha(path[0]) && path[1] == ':' && path[2] == '\\')
|
|
||||||
{
|
|
||||||
drive_str[0] = path[0]; // drive letter
|
|
||||||
root = drive_str;
|
|
||||||
}
|
|
||||||
char fs_name[16] = { 0 };
|
|
||||||
GetVolumeInformation(root, 0,0,0,0,0, fs_name, sizeof(fs_name));
|
|
||||||
// if this fails, fs_name != "FAT" => special-case is skipped.
|
|
||||||
|
|
||||||
// the FAT file system stores local file times, while
|
// the FAT file system stores local file times, while
|
||||||
// NTFS records UTC. Windows does convert automatically,
|
// NTFS records UTC. Windows does convert automatically,
|
||||||
// but uses the current DST settings. (boo!)
|
// but uses the current DST settings. (boo!)
|
||||||
// we go back to local time, and convert properly.
|
// we go back to local time, and convert properly.
|
||||||
if(!strncmp(fs_name, "FAT", 3)) // e.g. FAT32
|
if(filesystem == FS_FAT)
|
||||||
{
|
{
|
||||||
FILETIME local_ft;
|
FILETIME local_ft;
|
||||||
FileTimeToLocalFileTime(ft, &local_ft);
|
FileTimeToLocalFileTime(ft, &local_ft);
|
||||||
@ -215,7 +255,7 @@ int stat(const char* fn, struct stat* s)
|
|||||||
if(!GetFileAttributesEx(fn, GetFileExInfoStandard, &fad))
|
if(!GetFileAttributesEx(fn, GetFileExInfoStandard, &fad))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
s->st_mtime = fad.ftLastAccessTime
|
s->st_mtime = filetime_to_time_t(fad.ftLastAccessTime)
|
||||||
|
|
||||||
// dir
|
// dir
|
||||||
if(fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
if(fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
@ -369,7 +409,7 @@ int readdir_stat_np(DIR* d_, struct stat* s)
|
|||||||
memset(s, 0, sizeof(struct stat));
|
memset(s, 0, sizeof(struct stat));
|
||||||
s->st_size = (off_t)((((u64)d->fd.nFileSizeHigh) << 32) | d->fd.nFileSizeLow);
|
s->st_size = (off_t)((((u64)d->fd.nFileSizeHigh) << 32) | d->fd.nFileSizeLow);
|
||||||
s->st_mode = (d->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
|
s->st_mode = (d->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
|
||||||
s->st_mtime = filetime_to_time_t(&d->fd.ftLastWriteTime, d->path);
|
s->st_mtime = filetime_to_time_t(&d->fd.ftLastWriteTime);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user