-
Notifications
You must be signed in to change notification settings - Fork 333
win32: Fix enumerate root dir content on SFTP-server #148
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
Changes from all commits
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 |
---|---|---|
|
@@ -745,12 +745,21 @@ fileio_stat(const char *path, struct _stat64 *buf) | |
wchar_t* wpath = NULL; | ||
WIN32_FILE_ATTRIBUTE_DATA attributes = { 0 }; | ||
int ret = -1, len = 0; | ||
|
||
memset(buf, 0, sizeof(struct _stat64)); | ||
|
||
/* Detect root dir */ | ||
if (path && strcmp(path, "/") == 0) { | ||
buf->st_mode = _S_IFDIR | _S_IREAD | 0xFF; | ||
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. 0xff is not required here? 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 this can also be removed.. |
||
buf->st_dev = USHRT_MAX; // rootdir flag | ||
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. Use ATTR_ROOTDIR to be consistent.. 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. ATTR_ROOTDIR is 32 bit 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. what is the need for setting this here as we are not using this any where else? 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 can remove this line, if it so cuts your eyes. 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. We should remove the unnecessary code so its easy to maintain the long run.. |
||
return 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(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,8 +42,54 @@ struct DIR_ { | |
intptr_t hFile; | ||
struct _wfinddata_t c_file; | ||
int first; | ||
wchar_t * nextdisk; | ||
}; | ||
|
||
#define ATTR_ROOTDIR UINT_MAX | ||
|
||
/* Enumerate all devices which have drive name. | ||
Return a DIR stream on the root directory, or NULL if it could not be enumerated. */ | ||
DIR * | ||
openrootdir(const char *name) | ||
{ | ||
int hr = 0; | ||
DWORD dw; | ||
DIR * pdir; | ||
struct _wfinddata_t c_file = {0}; | ||
wchar_t * p; | ||
|
||
dw = GetLogicalDriveStringsW(_countof(c_file.name) - 2, c_file.name); | ||
if (!dw) { | ||
errno = ENODEV; | ||
return NULL; | ||
} | ||
c_file.attrib = ATTR_ROOTDIR; | ||
c_file.size = 0; | ||
p = c_file.name; | ||
while (*p) { | ||
size_t len = wcslen(p); | ||
if (len == 0) | ||
break; | ||
p += len + 1; | ||
c_file.size++; | ||
} | ||
if (c_file.size == 0) { | ||
errno = ENODEV; | ||
return NULL; | ||
} | ||
pdir = malloc(sizeof(DIR)); | ||
if (!pdir) { | ||
errno = ENOMEM; | ||
return NULL; | ||
} | ||
memset(pdir, 0, sizeof(DIR)); | ||
pdir->hFile = 0; | ||
memcpy(&pdir->c_file, &c_file, sizeof(c_file)); | ||
pdir->first = 1; | ||
|
||
return pdir; | ||
} | ||
|
||
/* Open a directory stream on NAME. | ||
Return a DIR stream on the directory, or NULL if it could not be opened. */ | ||
DIR * | ||
|
@@ -55,14 +101,31 @@ opendir(const char *name) | |
wchar_t searchstr[PATH_MAX]; | ||
wchar_t* wname = NULL; | ||
int needed; | ||
size_t len; | ||
|
||
/* Detect root dir */ | ||
if (name && strcmp(name, "/") == 0) | ||
return openrootdir(name); | ||
|
||
if ((wname = utf8_to_utf16(sanitized_path(name))) == NULL) { | ||
errno = ENOMEM; | ||
return NULL; | ||
} | ||
|
||
convertToBackslashW(wname); | ||
len = wcslen(wname); | ||
if (len && wname[len-1] == L'\\') { | ||
len--; | ||
wname[len] = 0; | ||
} | ||
if (len >= PATH_MAX) { | ||
free(wname); | ||
errno = ENAMETOOLONG; | ||
return NULL; | ||
} | ||
|
||
/* add *.* for Windows _findfirst() search pattern */ | ||
swprintf_s(searchstr, PATH_MAX, L"%s\\*.*", wname); | ||
swprintf_s(searchstr, _countof(searchstr) - 1, L"%s\\*.*", wname); | ||
free(wname); | ||
|
||
if ((hFile = _wfindfirst(searchstr, &c_file)) == -1L) | ||
|
@@ -92,13 +155,69 @@ closedir(DIR *dirp) | |
|
||
if (dirp && (dirp->hFile)) { | ||
_findclose(dirp->hFile); | ||
dirp->hFile = 0; | ||
free(dirp); | ||
} | ||
free(dirp); | ||
|
||
return 0; | ||
} | ||
|
||
/* Read a root directory entry from DIRP. | ||
Return a pointer to a `struct dirent' describing the entry, | ||
or NULL for EOF or error. The storage returned may be overwritten | ||
by a later readdir call on the same DIR stream. */ | ||
struct dirent * | ||
readrootdir(DIR * dirp) | ||
{ | ||
wchar_t * p; | ||
size_t len = 0; | ||
struct dirent *pdirentry; | ||
UINT dt; | ||
ULARGE_INTEGER totalNumberOfBytes; | ||
BOOL x; | ||
|
||
if (dirp->c_file.size <= 0) { | ||
errno = ENODATA; | ||
return NULL; | ||
} | ||
if (dirp->first) { | ||
dirp->first = 0; | ||
dirp->nextdisk = dirp->c_file.name; | ||
} | ||
|
||
p = dirp->nextdisk; | ||
|
||
for ( ; ; p += len + 1) { | ||
len = wcslen(p); | ||
if (len == 0) { | ||
dirp->nextdisk = p; | ||
errno = ENODATA; | ||
return NULL; /* end of multi-string */ | ||
} | ||
|
||
dt = GetDriveTypeW(p); | ||
if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR || dt == DRIVE_RAMDISK) | ||
continue; | ||
|
||
x = GetDiskFreeSpaceExW(p, NULL, &totalNumberOfBytes, NULL); | ||
if (!x || totalNumberOfBytes.QuadPart == 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. I think, we can remove "totalNumberOfBytes.QuadPart == 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. Var totalNumberOfBytes.QuadPart equ 0 when CD-drive have not CD-disk. |
||
continue; | ||
|
||
break; // process filtered disk | ||
} | ||
dirp->nextdisk = p + len + 1; | ||
|
||
if ((pdirentry = malloc(sizeof(struct dirent))) == NULL) { | ||
errno = ENOMEM; | ||
return NULL; | ||
} | ||
pdirentry->d_name[0] = (char)p[0]; | ||
pdirentry->d_name[1] = ':'; | ||
pdirentry->d_name[2] = 0; | ||
|
||
pdirentry->d_ino = 1; // a fictious one like UNIX to say it is nonzero | ||
return pdirentry; | ||
} | ||
|
||
/* Read a directory entry from DIRP. | ||
Return a pointer to a `struct dirent' describing the entry, | ||
or NULL for EOF or error. The storage returned may be overwritten | ||
|
@@ -113,6 +232,9 @@ readdir(void *avp) | |
DIR *dirp = (DIR *)avp; | ||
char *tmp = NULL; | ||
|
||
if (dirp->hFile == 0 && dirp->c_file.attrib == ATTR_ROOTDIR) | ||
return readrootdir(dirp); | ||
|
||
for (;;) { | ||
if (dirp->first) { | ||
memcpy(&c_file, &dirp->c_file, sizeof(c_file)); | ||
|
@@ -128,7 +250,7 @@ readdir(void *avp) | |
return NULL; | ||
} | ||
|
||
strncpy(pdirentry.d_name, tmp, strlen(tmp) + 1); | ||
strncpy(pdirentry.d_name, tmp, sizeof(pdirentry.d_name)); | ||
free(tmp); | ||
|
||
pdirentry.d_ino = 1; /* a fictious one like UNIX to say it is nonzero */ | ||
|
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.
from winscp (or) any other third party software.. if we receive "/" then it is treated as the root dir....
But I am not sure if all the thirdparty softwares follow the same notion.. not sure if some of them can use \ instead of "/", is it possible.. is there a standard notion?
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.
I tested this PR in WinSCP and Bitvise SFTP-clients.