Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/programs/cmd/tests/directory.c
4389 views
1
/*
2
* Copyright 2023 Akihiro Sagawa
3
*
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2.1 of the License, or (at your option) any later version.
8
*
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
13
*
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17
*/
18
19
#include <windows.h>
20
#include "wine/test.h"
21
22
#define MAX_BUFFER 65536
23
24
static char stdout_buffer[MAX_BUFFER], stderr_buffer[MAX_BUFFER];
25
static DWORD stdout_size, stderr_size;
26
static char work_dir[MAX_PATH];
27
28
typedef BOOL (*find_line_callback)(const char* line, void *data);
29
30
static void read_all_from_handle(HANDLE handle, char *buffer, DWORD *size)
31
{
32
char bytes[4096];
33
DWORD bytes_read;
34
35
memset(buffer, 0, MAX_BUFFER);
36
*size = 0;
37
for (;;)
38
{
39
BOOL success = ReadFile(handle, bytes, sizeof(bytes), &bytes_read, NULL);
40
if (!success || !bytes_read)
41
break;
42
if (*size + bytes_read > MAX_BUFFER)
43
{
44
ok(FALSE, "Insufficient buffer.\n");
45
break;
46
}
47
memcpy(buffer + *size, bytes, bytes_read);
48
*size += bytes_read;
49
}
50
}
51
52
#define run_dir(a, b) _run_dir(__FILE__, __LINE__, a, b)
53
static void _run_dir(const char *file, int line, const char *commandline, int exitcode_expected)
54
{
55
HANDLE child_stdout_write, child_stderr_write, parent_stdout_read, parent_stderr_read;
56
SECURITY_ATTRIBUTES security_attributes = {0};
57
PROCESS_INFORMATION process_info = {0};
58
STARTUPINFOA startup_info = {0};
59
DWORD exitcode;
60
char cmd[256];
61
62
security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
63
security_attributes.bInheritHandle = TRUE;
64
65
CreatePipe(&parent_stdout_read, &child_stdout_write, &security_attributes, 0);
66
CreatePipe(&parent_stderr_read, &child_stderr_write, &security_attributes, 0);
67
SetHandleInformation(parent_stdout_read, HANDLE_FLAG_INHERIT, 0);
68
SetHandleInformation(parent_stderr_read, HANDLE_FLAG_INHERIT, 0);
69
70
startup_info.cb = sizeof(STARTUPINFOA);
71
startup_info.hStdOutput = child_stdout_write;
72
startup_info.hStdError = child_stderr_write;
73
startup_info.dwFlags |= STARTF_USESTDHANDLES;
74
75
sprintf(cmd, "cmd.exe /d /c dir %s", commandline);
76
CreateProcessA(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info);
77
CloseHandle(child_stdout_write);
78
CloseHandle(child_stderr_write);
79
80
read_all_from_handle(parent_stdout_read, stdout_buffer, &stdout_size);
81
read_all_from_handle(parent_stderr_read, stderr_buffer, &stderr_size);
82
CloseHandle(parent_stdout_read);
83
CloseHandle(parent_stderr_read);
84
85
WaitForSingleObject(process_info.hProcess, INFINITE);
86
GetExitCodeProcess(process_info.hProcess, &exitcode);
87
CloseHandle(process_info.hProcess);
88
CloseHandle(process_info.hThread);
89
ok_(file, line)(exitcode == exitcode_expected, "expected exitcode %d, got %ld\n",
90
exitcode_expected, exitcode);
91
}
92
93
static BOOL find_line(const char* buf, find_line_callback callback, void *data)
94
{
95
BOOL found = FALSE;
96
const char* p = buf;
97
char *line = NULL;
98
size_t size = 0;
99
100
while (*p)
101
{
102
size_t len;
103
const char* eol = strpbrk(p, "\r\n");
104
len = eol ? (eol - p) : strlen(p);
105
if (len + 1 > size)
106
{
107
char *ptr = realloc(line, len + 1);
108
if (!ptr) break;
109
line = ptr;
110
size = len + 1;
111
}
112
memcpy(line, p, len);
113
line[len] = '\0';
114
found = callback(line, data);
115
if (found) break;
116
if (*eol == '\r' && *(eol+1) == '\n') eol++;
117
p = eol + 1;
118
}
119
free(line);
120
return found;
121
}
122
123
static void test_basic(void)
124
{
125
/* no options */
126
run_dir("", 0);
127
ok(stdout_size > 0, "unexpected stdout buffer size %ld.\n", stdout_size);
128
ok(stderr_size == 0, "unexpected stderr buffer size %ld.\n", stderr_size);
129
130
/* if file doesn't exist, cmd.exe prints an error message to stderr. */
131
run_dir("nonexistent", 1);
132
ok(stdout_size > 0, "unexpected stdout buffer size %ld.\n", stdout_size);
133
ok(stderr_size > 0, "unexpected stderr buffer size %ld.\n", stderr_size);
134
135
/* unknown option produces an error message to stderr. */
136
run_dir("/*", 1);
137
ok(stdout_size == 0, "unexpected stdout buffer size %ld.\n", stdout_size);
138
ok(stderr_size > 0, "unexpected stderr buffer size %ld.\n", stderr_size);
139
140
/* errorlevel for usage is 0. But, cmd.exe's exit code is 1. */
141
run_dir("/?", 1);
142
ok(stdout_size > 0, "unexpected stdout buffer size %ld.\n", stdout_size);
143
ok(stderr_size == 0, "unexpected stderr buffer size %ld.\n", stderr_size);
144
}
145
146
struct timestamp_param {
147
SYSTEMTIME st;
148
const char* filename;
149
};
150
151
static BOOL match_timestamp(const char* line, void *data)
152
{
153
const struct timestamp_param *param = (const struct timestamp_param *)data;
154
char pattern[MAX_BUFFER], *ptr;
155
156
if ((ptr = strstr(line, " 0 ")) && strstr(ptr, param->filename)) {
157
char format[60];
158
159
while (*ptr == ' ') *ptr-- = '\0';
160
161
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, format, sizeof(format));
162
if ((ptr = strstr(format, "d")) && strncmp(ptr, "ddd", 3) &&
163
(!strncmp(ptr, "dd", 2) || !strncmp(ptr, "d", 1)))
164
{
165
sprintf(pattern, "%02hd", param->st.wDay);
166
ok(!!strstr(line, pattern), "expected day %s, got %s\n", pattern, wine_dbgstr_a(line));
167
}
168
else
169
skip("date format %s doesn't represent day of the month as digits\n", wine_dbgstr_a(format));
170
171
if ((ptr = strstr(format, "M")) && strncmp(ptr, "MMM", 3) &&
172
(!strncmp(ptr, "MM", 2) || !strncmp(ptr, "M", 1)))
173
{
174
sprintf(pattern, "%02hd", param->st.wMonth);
175
ok(!!strstr(line, pattern), "expected month %s, got %s\n", pattern, wine_dbgstr_a(line));
176
}
177
else
178
skip("date format %s doesn't represent month as digits\n", wine_dbgstr_a(format));
179
180
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, format, sizeof(format));
181
if (strstr(format, "h") || strstr(format, "H"))
182
{
183
sprintf(pattern, "%02hd", param->st.wHour);
184
ok(!!strstr(line, pattern), "expected hour %s, got %s\n", pattern, wine_dbgstr_a(line));
185
}
186
else
187
skip("time format %s doesn't represent hour as digits\n", wine_dbgstr_a(format));
188
189
if (strstr(format, "m"))
190
{
191
sprintf(pattern, "%02hd", param->st.wMinute);
192
ok(!!strstr(line, pattern), "expected minute %s, got %s\n", pattern, wine_dbgstr_a(line));
193
}
194
else
195
skip("time format %s doesn't represent minute as digits\n", wine_dbgstr_a(format));
196
197
return TRUE;
198
}
199
return FALSE;
200
}
201
202
static void test_timestamp(void)
203
{
204
static const char* filename = "test.dir";
205
FILETIME local, ft;
206
SYSTEMTIME st = {
207
/* Use single digits for leading zeros except the year */
208
.wYear = 2009, .wMonth = 1, .wDay = 3, .wHour = 5, .wMinute = 7,
209
};
210
struct timestamp_param param = {
211
.filename = filename,
212
};
213
HANDLE file;
214
BOOL ret;
215
216
file = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
217
ok(file != INVALID_HANDLE_VALUE, "Can't create file, err %lu\n", GetLastError());
218
219
SystemTimeToFileTime(&st, &local);
220
LocalFileTimeToFileTime(&local, &ft);
221
SetFileTime(file, NULL, NULL, &ft);
222
FileTimeToLocalFileTime(&ft, &local);
223
FileTimeToSystemTime(&local, &param.st);
224
225
CloseHandle(file);
226
227
run_dir(filename, 0);
228
stdout_buffer[stdout_size] = '\0';
229
ret = find_line(stdout_buffer, match_timestamp, &param);
230
ok(ret, "file name is not found in the output\n");
231
232
ret = DeleteFileA(filename);
233
ok(ret, "Can't delete file, err %lu\n", GetLastError());
234
}
235
236
START_TEST(directory)
237
{
238
WCHAR curdir[MAX_PATH];
239
BOOL ret;
240
241
GetCurrentDirectoryW(ARRAY_SIZE(curdir), curdir);
242
GetTempPathA(ARRAY_SIZE(work_dir), work_dir);
243
lstrcatA(work_dir, "winetest.dir");
244
ret = CreateDirectoryA(work_dir, NULL);
245
ok(ret, "Failed to create %s\n", work_dir);
246
ret = SetCurrentDirectoryA(work_dir);
247
ok(ret, "Failed to set the working directory\n");
248
249
test_basic();
250
test_timestamp();
251
252
ret = SetCurrentDirectoryW(curdir);
253
ok(ret, "Failed to restore the current directory\n");
254
ret = RemoveDirectoryA(work_dir);
255
ok(ret, "Failed to remove the working directory\n");
256
}
257
258