-
Notifications
You must be signed in to change notification settings - Fork 327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix for Issue648 #136
fix for Issue648 #136
Changes from all commits
1ff7404
02e46e9
05fcfe9
cf7935f
63148b7
37eb024
a436b72
898ce04
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ | |
#include <io.h> | ||
#include <errno.h> | ||
#include <stddef.h> | ||
#include <direct.h> | ||
|
||
#include "w32fd.h" | ||
#include "inc\utf.h" | ||
|
@@ -638,22 +639,53 @@ int | |
fileio_stat(const char *path, struct _stat64 *buf) | ||
{ | ||
wchar_t* wpath = NULL; | ||
int r = -1; | ||
|
||
if ((wpath = utf8_to_utf16(path)) == NULL) | ||
fatal("failed to covert input arguments"); | ||
|
||
r = _wstat64(wpath, buf); | ||
|
||
/* | ||
* If we doesn't have sufficient permissions then _wstat64() is returning "file not found" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest to remove all this code and have _wstat64() but before making that attempt call GetFileAttributesExW() since we are just worried about the wrong error message.. we shouldn't be re-writing _wstat64() implementation again? If GetFileAttributesExW() success then call _wstat64 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, with GetFileAttributesExW, we don't need to have that permission. GetFileAttributesExW success does not mean you can call _wstat64. |
||
* TODO - Replace the above call with GetFileAttributesEx | ||
*/ | ||
WIN32_FILE_ATTRIBUTE_DATA attributes = { 0 }; | ||
int ret = -1, len = 0; | ||
if ((wpath = utf8_to_utf16(path)) == NULL) { | ||
errno = errno_from_Win32LastError(); | ||
debug3("utf8_to_utf16 failed for file:%s error:%d", path, GetLastError()); | ||
return -1; | ||
} | ||
memset(buf, 0, sizeof(struct _stat64)); | ||
|
||
if (GetFileAttributesExW(wpath, GetFileExInfoStandard, &attributes) == FALSE) { | ||
errno = errno_from_Win32LastError(); | ||
debug3("GetFileAttributesExW with last error %d", GetLastError()); | ||
goto cleanup; | ||
} | ||
|
||
len = wcslen(wpath); | ||
|
||
buf->st_ino = 0; /* Has no meaning in the FAT, HPFS, or NTFS file systems*/ | ||
buf->st_gid = 0; /* UNIX - specific; has no meaning on windows */ | ||
buf->st_uid = 0; /* UNIX - specific; has no meaning on windows */ | ||
buf->st_nlink = 1; /* number of hard links. Always 1 on non - NTFS file systems.*/ | ||
buf->st_mode |= file_attr_to_st_mode(wpath, attributes.dwFileAttributes); | ||
buf->st_size = attributes.nFileSizeLow | (((off_t)attributes.nFileSizeHigh) << 32); | ||
if (len > 1 && __ascii_iswalpha(*wpath) && (*(wpath + 1) == ':')) | ||
buf->st_dev = buf->st_rdev = towupper(*wpath) - L'A'; /* drive num */ | ||
else | ||
buf->st_dev = buf->st_rdev = _getdrive() - 1; | ||
file_time_to_unix_time(&(attributes.ftLastAccessTime), &(buf->st_atime)); | ||
file_time_to_unix_time(&(attributes.ftLastWriteTime), &(buf->st_mtime)); | ||
file_time_to_unix_time(&(attributes.ftCreationTime), &(buf->st_ctime)); | ||
|
||
if (attributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { | ||
WIN32_FIND_DATAW findbuf = { 0 }; | ||
HANDLE handle = FindFirstFileW(wpath, &findbuf); | ||
if (handle != INVALID_HANDLE_VALUE) { | ||
if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && | ||
(findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { | ||
buf->st_mode |= S_IFLNK; | ||
} | ||
FindClose(handle); | ||
} | ||
} | ||
ret = 0; | ||
cleanup: | ||
if (wpath) | ||
free(wpath); | ||
return r; | ||
free(wpath); | ||
return ret; | ||
} | ||
|
||
long | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,6 +59,10 @@ static char* s_programdir = NULL; | |
#define IO_REPARSE_TAG_SIS (0x80000007L) /* winnt ntifs */ | ||
#define REPARSE_MOUNTPOINT_HEADER_SIZE 8 | ||
|
||
/* Difference in us between UNIX Epoch and Win32 Epoch */ | ||
#define EPOCH_DELTA_US 116444736000000000ULL | ||
#define RATE_DIFF 10000000ULL /* 1000 nsecs */ | ||
|
||
typedef struct _REPARSE_DATA_BUFFER { | ||
ULONG ReparseTag; | ||
USHORT ReparseDataLength; | ||
|
@@ -174,9 +178,6 @@ nanosleep(const struct timespec *req, struct timespec *rem) | |
} | ||
} | ||
|
||
/* Difference in us between UNIX Epoch and Win32 Epoch */ | ||
#define EPOCH_DELTA_US 11644473600000000ULL | ||
|
||
/* This routine is contributed by * Author: NoMachine <[email protected]> | ||
* Copyright (c) 2009, 2010 NoMachine | ||
* All rights reserved | ||
|
@@ -191,17 +192,14 @@ gettimeofday(struct timeval *tv, void *tz) | |
unsigned long long us; | ||
|
||
/* Fetch time since Jan 1, 1601 in 100ns increments */ | ||
GetSystemTimeAsFileTime(&timehelper.ft); | ||
|
||
/* Convert to microseconds from 100 ns units */ | ||
us = timehelper.ns / 10; | ||
GetSystemTimeAsFileTime(&timehelper.ft); | ||
|
||
/* Remove the epoch difference */ | ||
us -= EPOCH_DELTA_US; | ||
us = timehelper.ns - EPOCH_DELTA_US; | ||
|
||
/* Stuff result into the timeval */ | ||
tv->tv_sec = (long)(us / 1000000ULL); | ||
tv->tv_usec = (long)(us % 1000000ULL); | ||
tv->tv_sec = (long)(us / RATE_DIFF); | ||
tv->tv_usec = (long)(us % RATE_DIFF); | ||
|
||
return 0; | ||
} | ||
|
@@ -550,16 +548,83 @@ w32_chown(const char *pathname, unsigned int owner, unsigned int group) | |
return -1; | ||
} | ||
|
||
static void | ||
/* Convert a UNIX time into a Windows file time */ | ||
void | ||
unix_time_to_file_time(ULONG t, LPFILETIME pft) | ||
{ | ||
ULONGLONG ull; | ||
ull = UInt32x32To64(t, 10000000) + 116444736000000000; | ||
ull = UInt32x32To64(t, RATE_DIFF) + EPOCH_DELTA_US; | ||
|
||
pft->dwLowDateTime = (DWORD)ull; | ||
pft->dwHighDateTime = (DWORD)(ull >> 32); | ||
} | ||
|
||
/* Convert a Windows file time into a UNIX time_t */ | ||
void | ||
file_time_to_unix_time(const LPFILETIME pft, time_t * winTime) | ||
{ | ||
*winTime = ((long long)pft->dwHighDateTime << 32) + pft->dwLowDateTime; | ||
*winTime -= EPOCH_DELTA_US; | ||
*winTime /= RATE_DIFF; /* Nano to seconds resolution */ | ||
} | ||
|
||
static BOOL | ||
is_root_or_empty(wchar_t * path) | ||
{ | ||
wchar_t * path_start; | ||
BOOL has_drive_letter_and_colon; | ||
int len; | ||
if (!path) | ||
return FALSE; | ||
len = wcslen(path); | ||
if((len > 1) && __ascii_iswalpha(path[0]) && path[1] == L':') | ||
path_start = path + 2; | ||
else | ||
path_start = path; | ||
/*path like c:\, /, \ are root directory*/ | ||
if ((*path_start == L'\0') || ((*path_start == L'\\' || *path_start == L'/' ) && path_start[1] == L'\0')) | ||
return TRUE; | ||
return FALSE; | ||
} | ||
|
||
static BOOL | ||
has_executable_extension(wchar_t * path) | ||
{ | ||
wchar_t * last_dot; | ||
if (!path) | ||
return FALSE; | ||
|
||
last_dot = wcsrchr(path, L'.'); | ||
if (!last_dot) | ||
return FALSE; | ||
if (_wcsnicmp(last_dot, L".exe", 4) != 0 && _wcsnicmp(last_dot, L".cmd", 4) != 0 && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might need to retrieve the executable extension from %PATHEXT% environment variable.. If you fail to find / retrieve the environment variable then you can fall back on to the standard ones There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I compared the results for other extension, the current implementation mirror the functionality of _wstat64 except it doesn't require permission to access the file. I will keep it for now until three is a need to consider other file extension. |
||
_wcsnicmp(last_dot, L".bat", 4) != 0 && _wcsnicmp(last_dot, L".com", 4) != 0) | ||
return FALSE; | ||
return TRUE; | ||
} | ||
|
||
int | ||
file_attr_to_st_mode(wchar_t * path, DWORD attributes) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can use stat, st_mode for doing all this? https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The change is to replace the usage of stat because stat require some (read) permission. When the user doesn't have the permission, stat return file_not_found. that is the reason we don't want to use stat. |
||
{ | ||
int mode = S_IREAD; | ||
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 || is_root_or_empty(path)) | ||
mode |= S_IFDIR | _S_IEXEC; | ||
else { | ||
mode |= S_IFREG; | ||
/* See if file appears to be an executable by checking its extension */ | ||
if (has_executable_extension(path)) | ||
mode |= _S_IEXEC; | ||
|
||
} | ||
if (!(attributes & FILE_ATTRIBUTE_READONLY)) | ||
mode |= S_IWRITE; | ||
|
||
// propagate owner read/write/execute bits to group/other fields. | ||
mode |= (mode & 0700) >> 3; | ||
mode |= (mode & 0700) >> 6; | ||
return mode; | ||
} | ||
|
||
static int | ||
settimes(wchar_t * path, FILETIME *cretime, FILETIME *acttime, FILETIME *modtime) | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be independent of stopping the ssh-agent.. can you have this check down?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this check is needed. if the folder does not exists, there is no need to do any of the below steps. The purpose of stopping ssh-agent is to run uninstall script. If the folder does not exists, there is no need to stop ssh-agent either.