Skip to content

Commit

Permalink
Create a fake stat record for drive letters.
Browse files Browse the repository at this point in the history
While refactoring the code we seem to have lost the special case for a
drive letter only which needs special handling e.g. a fake stat
structure as most API calls on it will fail with a resource busy error.
  • Loading branch information
Marco van Wieringen committed May 13, 2014
1 parent ea9a242 commit b2f6e02
Showing 1 changed file with 112 additions and 99 deletions.
211 changes: 112 additions & 99 deletions src/win32/compat/compat.c
Expand Up @@ -1159,8 +1159,8 @@ int fstat(intptr_t fd, struct stat *sb)
Dmsg1(dbglvl, "st_nlink=%d\n", sb->st_nlink);
}

sb->st_mode |= S_IFREG;
sb->st_mode = 0777;
sb->st_mode |= S_IFREG;

/*
* See if we need to encode in the old Bacula compatible way.
Expand Down Expand Up @@ -1310,142 +1310,155 @@ int stat(const char *filename, struct stat *sb)
errno = 0;
memset(sb, 0, sizeof(*sb));

if (p_GetFileAttributesExW) {
/*
* Dynamically allocate enough space for UCS2 filename
*/
POOLMEM *pwszBuf = get_pool_memory(PM_FNAME);
make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
/*
* The windows API doesn't allow you the normal operations on just a drive letter
* e.g. you always get a resource busy message then so we fake the information for
* just a drive letter.
*/
if (is_drive_letter_only(filename)) {
time_t now = time(NULL);

BOOL b = p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, &data);
free_pool_memory(pwszBuf);
sb->st_mode = 0777;
sb->st_mode |= S_IFDIR;
sb->st_rdev = 0;
sb->st_nlink = 1;
sb->st_size = 1;
sb->st_blksize = 4096;
sb->st_ctime = now;
sb->st_mtime = now;
sb->st_atime = now;
sb->st_blocks = (uint32_t)(sb->st_size + 4095) / 4096;
} else {
if (p_GetFileAttributesExW) {
/*
* Dynamically allocate enough space for UCS2 filename
*/
POOLMEM *pwszBuf = get_pool_memory(PM_FNAME);
make_win32_path_UTF8_2_wchar(&pwszBuf, filename);

if (!b) {
goto bail_out;
}
BOOL b = p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, &data);
free_pool_memory(pwszBuf);

} else if (p_GetFileAttributesExA) {
win32_fname = get_pool_memory(PM_FNAME);
unix_name_to_win32(&win32_fname, filename);
if (!b) {
goto bail_out;
}
} else if (p_GetFileAttributesExA) {
win32_fname = get_pool_memory(PM_FNAME);
unix_name_to_win32(&win32_fname, filename);

if (!p_GetFileAttributesExA(win32_fname, GetFileExInfoStandard, &data)) {
if (!p_GetFileAttributesExA(win32_fname, GetFileExInfoStandard, &data)) {
goto bail_out;
}
} else {
goto bail_out;
}
} else {
goto bail_out;
}

/*
* See if this is a directory or a reparse point and not a single drive letter.
* If so we call get_windows_file_info() which retrieves the lowlevel information we need.
* As get_windows_file_info() fills the complete stat structs we only need to perform the
* other part of the code when we don't call the get_windows_file_info() function.
*/
if (((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
(data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) &&
!is_drive_letter_only(filename)) {
rval = get_windows_file_info(filename, sb, (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
} else {
sb->st_mode = 0777;

/*
* See if we need to encode in the old Bacula compatible way.
*/
if (win32_bacula_compatible) {
encode_windows_flags_compatible(data.dwFileAttributes, sb);
}

/*
* We store the full windows file attributes into st_rdev.
* See if this is a directory or a reparse point and not a single drive letter.
* If so we call get_windows_file_info() which retrieves the lowlevel information we need.
* As get_windows_file_info() fills the complete stat structs we only need to perform the
* other part of the code when we don't call the get_windows_file_info() function.
*/
sb->st_rdev = data.dwFileAttributes;

if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
sb->st_mode |= S_IFDIR;
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
(data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
rval = get_windows_file_info(filename, sb, (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
} else {
sb->st_mode = 0777;
sb->st_mode |= S_IFREG;
}

sb->st_nlink = 1;
sb->st_size = data.nFileSizeHigh;
sb->st_size <<= 32;
sb->st_size |= data.nFileSizeLow;
sb->st_blksize = 4096;
sb->st_blocks = (uint32_t)(sb->st_size + 4095) / 4096;

#if (_WIN32_WINNT >= 0x0600)
/*
* See if GetFileInformationByHandleEx API is available.
*/
if (p_GetFileInformationByHandleEx) {
HANDLE h = INVALID_HANDLE_VALUE;
FILE_BASIC_INFO binfo;
/*
* See if we need to encode in the old Bacula compatible way.
*/
if (win32_bacula_compatible) {
encode_windows_flags_compatible(data.dwFileAttributes, sb);
}

/*
* The GetFileInformationByHandleEx need a file handle so we have to
* open the file or directory read-only.
* We store the full windows file attributes into st_rdev.
*/
if (p_CreateFileW) {
POOLMEM *pwszBuf;
sb->st_rdev = data.dwFileAttributes;

pwszBuf = get_pool_memory(PM_FNAME);
make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
sb->st_nlink = 1;
sb->st_size = data.nFileSizeHigh;
sb->st_size <<= 32;
sb->st_size |= data.nFileSizeLow;
sb->st_blksize = 4096;
sb->st_blocks = (uint32_t)(sb->st_size + 4095) / 4096;

h = p_CreateFileW((LPCWSTR)pwszBuf,
#if (_WIN32_WINNT >= 0x0600)
/*
* See if GetFileInformationByHandleEx API is available.
*/
if (p_GetFileInformationByHandleEx) {
HANDLE h = INVALID_HANDLE_VALUE;
FILE_BASIC_INFO binfo;

/*
* The GetFileInformationByHandleEx need a file handle so we have to
* open the file or directory read-only.
*/
if (p_CreateFileW) {
POOLMEM *pwszBuf;

pwszBuf = get_pool_memory(PM_FNAME);
make_win32_path_UTF8_2_wchar(&pwszBuf, filename);

h = p_CreateFileW((LPCWSTR)pwszBuf,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
free_pool_memory(pwszBuf);
} else {
h = CreateFileA(win32_fname,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
free_pool_memory(pwszBuf);
} else {
h = CreateFileA(win32_fname,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
}
}

if (h != INVALID_HANDLE_VALUE) {
if (!p_GetFileInformationByHandleEx(h, FileBasicInfo,
&binfo, sizeof(binfo)) < 0) {
const char *err = errorString();
if (h != INVALID_HANDLE_VALUE) {
if (!p_GetFileInformationByHandleEx(h, FileBasicInfo,
&binfo, sizeof(binfo)) < 0) {
const char *err = errorString();

Dmsg1(2099, "GetFileInformationByHandleEx: %s\n", err);
LocalFree((void *)err);
errno = b_errno_win32;
CloseHandle(h);
Dmsg1(2099, "GetFileInformationByHandleEx: %s\n", err);
LocalFree((void *)err);
errno = b_errno_win32;
CloseHandle(h);

return -1;
}
return -1;
}

sb->st_atime = cvt_ftime_to_utime(binfo.LastAccessTime);
sb->st_mtime = cvt_ftime_to_utime(binfo.LastWriteTime);
sb->st_ctime = cvt_ftime_to_utime(binfo.ChangeTime);
sb->st_atime = cvt_ftime_to_utime(binfo.LastAccessTime);
sb->st_mtime = cvt_ftime_to_utime(binfo.LastWriteTime);
sb->st_ctime = cvt_ftime_to_utime(binfo.ChangeTime);

CloseHandle(h);
CloseHandle(h);
} else {
/*
* Fall back to the GetFileAttributesEx data.
*/
sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
}
} else {
#endif
/*
* Fall back to the GetFileAttributesEx data.
*/
sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
#if (_WIN32_WINNT >= 0x0600)
}
} else {
#endif
/*
* Fall back to the GetFileAttributesEx data.
*/
sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
#if (_WIN32_WINNT >= 0x0600)
}
#endif
}
rval = 0;

Expand Down

0 comments on commit b2f6e02

Please sign in to comment.