... | ... |
@@ -319,7 +319,7 @@ int cfg_tcpsock(const struct optstruct *opts, struct sockaddr_in *tcpsock, in_ad |
319 | 319 |
int cli_is_abspath(const char *path) { |
320 | 320 |
#ifdef _WIN32 |
321 | 321 |
int len = strlen(path); |
322 |
- return (len > 2 && path[0] == '\\' && path[1] == '\\') || (len > 3 && path[1] == ':' && path[2] == '\\'); |
|
322 |
+ return (len > 2 && path[0] == '\\' && path[1] == '\\') || (len >= 2 && ((*path >= 'a' && *path <= 'z') || (*path >= 'A' && *path <= 'Z')) && path[1] == ':'); |
|
323 | 323 |
#else |
324 | 324 |
return *path == '/'; |
325 | 325 |
#endif |
... | ... |
@@ -21,6 +21,7 @@ |
21 | 21 |
#include <errno.h> |
22 | 22 |
#include "others.h" |
23 | 23 |
#include "dirent.h" |
24 |
+#include "w32_stat.h" |
|
24 | 25 |
#include "shared/misc.h" |
25 | 26 |
|
26 | 27 |
DIR *opendir(const char *name) { |
... | ... |
@@ -28,11 +29,11 @@ DIR *opendir(const char *name) { |
28 | 28 |
DWORD attrs; |
29 | 29 |
int len; |
30 | 30 |
struct stat sb; |
31 |
+ wchar_t *wpath; |
|
31 | 32 |
|
32 |
- if(stat(name, &sb) < 0) { |
|
33 |
- errno = ENOENT; /* FIXME: should be set by stat() */ |
|
33 |
+ if(stat(name, &sb) < 0) |
|
34 | 34 |
return NULL; |
35 |
- } |
|
35 |
+ |
|
36 | 36 |
if(!S_ISDIR(sb.st_mode)) { |
37 | 37 |
errno = ENOTDIR; |
38 | 38 |
return NULL; |
... | ... |
@@ -41,19 +42,26 @@ DIR *opendir(const char *name) { |
41 | 41 |
errno = ENOMEM; |
42 | 42 |
return NULL; |
43 | 43 |
} |
44 |
- len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, d->entry, sizeof(d->entry) / sizeof(d->entry[0])); |
|
45 |
- if(!len || len >= PATH_MAX - 4) { |
|
44 |
+ wpath = uncpath(name); |
|
45 |
+ if(!wpath) |
|
46 |
+ return NULL; |
|
47 |
+ wcsncpy(d->entry, wpath, sizeof(d->entry) / sizeof(d->entry[0])); |
|
48 |
+ free(wpath); |
|
49 |
+ d->entry[sizeof(d->entry) / sizeof(d->entry[0])] = L'\0'; |
|
50 |
+ len = wcslen(d->entry); |
|
51 |
+ |
|
52 |
+ if(len >= sizeof(d->entry) / sizeof(d->entry[0]) - 4) { |
|
46 | 53 |
free(d); |
47 |
- errno = (len || (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) ? ENAMETOOLONG : ENOENT; |
|
54 |
+ errno = ENAMETOOLONG; |
|
48 | 55 |
return NULL; |
49 | 56 |
} |
50 |
- while(len) { |
|
57 |
+ while(len--) { |
|
51 | 58 |
if(d->entry[len] == L'\\') |
52 | 59 |
d->entry[len] = L'\0'; |
53 | 60 |
else |
54 | 61 |
break; |
55 | 62 |
} |
56 |
- /* FIXME: this should be UNC'd */ |
|
63 |
+ |
|
57 | 64 |
wcsncat(d->entry, L"\\*.*", 4); |
58 | 65 |
d->dh = INVALID_HANDLE_VALUE; |
59 | 66 |
return d; |
... | ... |
@@ -100,7 +100,7 @@ void fix_paths(void) { |
100 | 100 |
if(!have_ddir) |
101 | 101 |
snprintf(_DATADIR, sizeof(_DATADIR), "%s\\database", dir); |
102 | 102 |
if(!have_cdir) { |
103 |
- strncpy(_CONFDIR, dir, sizeof(_DATADIR)); |
|
103 |
+ strncpy(_CONFDIR, dir, sizeof(_CONFDIR)); |
|
104 | 104 |
have_cdir = 1; |
105 | 105 |
} |
106 | 106 |
} |
... | ... |
@@ -18,36 +18,73 @@ |
18 | 18 |
* MA 02110-1301, USA. |
19 | 19 |
*/ |
20 | 20 |
|
21 |
+#include <errno.h> |
|
22 |
+ |
|
21 | 23 |
#include "others.h" |
24 |
+#include "shared/misc.h" |
|
22 | 25 |
|
23 |
-w32_stat(const char *path, struct stat *buf) { |
|
24 |
- int len = strlen(path) + 2; |
|
25 |
- wchar_t *wpath; |
|
26 |
- WIN32_FILE_ATTRIBUTE_DATA attrs; |
|
27 | 26 |
|
28 |
- if(len > PATH_MAX) { |
|
29 |
- errno = ENAMETOOLONG; |
|
30 |
- return -1; |
|
31 |
- } |
|
32 |
- if(!(wpath = cli_malloc(len * 2))) { |
|
33 |
- errno = ENOMEM; |
|
34 |
- return -1; |
|
27 |
+wchar_t *uncpath(const char *path) { |
|
28 |
+ DWORD len = 0; |
|
29 |
+ wchar_t *dest = cli_malloc((PATH_MAX + 1) * sizeof(wchar_t)); |
|
30 |
+ |
|
31 |
+ if(!dest) |
|
32 |
+ return NULL; |
|
33 |
+ |
|
34 |
+ if(strncmp(path, "\\\\", 2)) { |
|
35 |
+ /* NOT already UNC */ |
|
36 |
+ memcpy(dest, L"\\\\?\\", 8); |
|
37 |
+ |
|
38 |
+ if(!cli_is_abspath(path)) { |
|
39 |
+ /* Relative path */ |
|
40 |
+ len = GetCurrentDirectoryW(PATH_MAX - 5, &dest[4]); |
|
41 |
+ if(!len || len > PATH_MAX - 5) { |
|
42 |
+ free(dest); |
|
43 |
+ errno = (len || (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) ? ENAMETOOLONG : ENOENT; |
|
44 |
+ return NULL; |
|
45 |
+ } |
|
46 |
+ len += 4; |
|
47 |
+ dest[len] = L'\\'; |
|
48 |
+ len++; |
|
49 |
+ } else { |
|
50 |
+ /* C:\ and friends */ |
|
51 |
+ len = 4; |
|
52 |
+ } |
|
53 |
+ } else { |
|
54 |
+ /* UNC already */ |
|
55 |
+ len = 0; |
|
35 | 56 |
} |
36 |
- /* FIXME: make it UNC */ |
|
37 |
- if(!(len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, path, -1, wpath, len))) { |
|
38 |
- errno = ENOENT; |
|
39 |
- free(wpath); |
|
40 |
- return -1; |
|
57 |
+ if(!(len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, path, -1, &dest[len], PATH_MAX - len)) || len > PATH_MAX - len) { |
|
58 |
+ free(dest); |
|
59 |
+ errno = (len || (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) ? ENAMETOOLONG : ENOENT; |
|
60 |
+ return NULL; |
|
41 | 61 |
} |
42 |
- if((len == 3 || (len == 7 && !wcsncmp(wpath, L"\\\\?\\", 4))) && (wpath[len-2] == L':') && |
|
43 |
- ((wpath[len-3] >= L'A' && wpath[len-3] <= L'Z') || (wpath[len-3] >= L'a' && wpath[len-2] <= L'z')) ) { |
|
44 |
- /* stat drives as dirs */ |
|
45 |
- wpath[len-1] = L'\\'; |
|
46 |
- wpath[len] = L'\0'; |
|
62 |
+ |
|
63 |
+ len = wcslen(dest); |
|
64 |
+ if(len == 6 && !wcsncmp(dest, L"\\\\?\\", 4) && (dest[5] == L':') && ((dest[4] >= L'A' && dest[4] <= L'Z') || (dest[4] >= L'a' && dest[4] <= L'z'))) { |
|
65 |
+ dest[6] = L'\\'; |
|
66 |
+ dest[7] = L'\0'; |
|
47 | 67 |
} |
68 |
+ |
|
69 |
+ return dest; |
|
70 |
+} |
|
71 |
+ |
|
72 |
+ |
|
73 |
+w32_stat(const char *path, struct stat *buf) { |
|
74 |
+ int len; |
|
75 |
+ wchar_t *wpath = uncpath(path); |
|
76 |
+ WIN32_FILE_ATTRIBUTE_DATA attrs; |
|
77 |
+ |
|
78 |
+ if(!wpath) |
|
79 |
+ return -1; |
|
80 |
+ |
|
81 |
+ len = wcslen(wpath); |
|
82 |
+ if(len > 2 && wpath[len-1] == L'.' && wpath[len-2] == L'\\') |
|
83 |
+ wpath[len-2] = L'\0'; /* windoze can't stat '.' ... */ |
|
48 | 84 |
len = GetFileAttributesExW(wpath, GetFileExInfoStandard, &attrs); |
49 | 85 |
free(wpath); |
50 | 86 |
if(!len) { |
87 |
+ len = GetLastError(); |
|
51 | 88 |
errno = ENOENT; |
52 | 89 |
return -1; |
53 | 90 |
} |