|
160
|
1 /* Copyright libuv project contributors. All rights reserved.
|
|
|
2 *
|
|
|
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
4 * of this software and associated documentation files (the "Software"), to
|
|
|
5 * deal in the Software without restriction, including without limitation the
|
|
|
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
7 * sell copies of the Software, and to permit persons to whom the Software is
|
|
|
8 * furnished to do so, subject to the following conditions:
|
|
|
9 *
|
|
|
10 * The above copyright notice and this permission notice shall be included in
|
|
|
11 * all copies or substantial portions of the Software.
|
|
|
12 *
|
|
|
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
19 * IN THE SOFTWARE.
|
|
|
20 */
|
|
|
21
|
|
|
22 #ifdef _WIN32
|
|
|
23
|
|
|
24 #include "uv.h"
|
|
|
25 #include "task.h"
|
|
|
26
|
|
|
27 #if defined(__unix__) || defined(__POSIX__) || \
|
|
|
28 defined(__APPLE__) || defined(__sun) || \
|
|
|
29 defined(_AIX) || defined(__MVS__) || \
|
|
|
30 defined(__HAIKU__)
|
|
|
31 # include <unistd.h> /* unlink, rmdir */
|
|
|
32 #else
|
|
|
33 # include <direct.h>
|
|
|
34 # define rmdir _rmdir
|
|
|
35 # define unlink _unlink
|
|
|
36 #endif
|
|
|
37
|
|
|
38 static int flags;
|
|
|
39
|
|
|
40 static uv_fs_t close_req;
|
|
|
41 static uv_fs_t mkdir_req;
|
|
|
42 static uv_fs_t open_req;
|
|
|
43 static uv_fs_t read_req;
|
|
|
44 static uv_fs_t rmdir_req;
|
|
|
45 static uv_fs_t unlink_req;
|
|
|
46 static uv_fs_t write_req;
|
|
|
47
|
|
|
48 static char buf[32];
|
|
|
49 static uv_buf_t iov;
|
|
|
50
|
|
|
51 /* Opening the same file multiple times quickly can cause uv_fs_open to fail
|
|
|
52 * with EBUSY, so append an identifier to the file name for each operation */
|
|
|
53 static int sid = 0;
|
|
|
54
|
|
|
55 #define FILE_NAME_SIZE 128
|
|
|
56 static char absent_file[FILE_NAME_SIZE];
|
|
|
57 static char empty_file[FILE_NAME_SIZE];
|
|
|
58 static char dummy_file[FILE_NAME_SIZE];
|
|
|
59 static char empty_dir[] = "empty_dir";
|
|
|
60
|
|
|
61 static void setup(void) {
|
|
|
62 int r;
|
|
|
63
|
|
|
64 /* empty_dir */
|
|
|
65 r = uv_fs_rmdir(NULL, &rmdir_req, empty_dir, NULL);
|
|
|
66 ASSERT(r == 0 || r == UV_ENOENT);
|
|
|
67 ASSERT(rmdir_req.result == 0 || rmdir_req.result == UV_ENOENT);
|
|
|
68 uv_fs_req_cleanup(&rmdir_req);
|
|
|
69
|
|
|
70 r = uv_fs_mkdir(NULL, &mkdir_req, empty_dir, 0755, NULL);
|
|
|
71 ASSERT_OK(r);
|
|
|
72 ASSERT_OK(mkdir_req.result);
|
|
|
73 uv_fs_req_cleanup(&mkdir_req);
|
|
|
74 }
|
|
|
75
|
|
|
76 static void refresh(void) {
|
|
|
77 int r;
|
|
|
78
|
|
|
79 /* absent_file */
|
|
|
80 sprintf(absent_file, "test_file_%d", sid++);
|
|
|
81
|
|
|
82 r = uv_fs_unlink(NULL, &unlink_req, absent_file, NULL);
|
|
|
83 ASSERT(r == 0 || r == UV_ENOENT);
|
|
|
84 ASSERT(unlink_req.result == 0 || unlink_req.result == UV_ENOENT);
|
|
|
85 uv_fs_req_cleanup(&unlink_req);
|
|
|
86
|
|
|
87 /* empty_file */
|
|
|
88 sprintf(empty_file, "test_file_%d", sid++);
|
|
|
89
|
|
|
90 r = uv_fs_open(NULL, &open_req, empty_file,
|
|
|
91 UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY, S_IWUSR | S_IRUSR, NULL);
|
|
|
92 ASSERT_GE(r, 0);
|
|
|
93 ASSERT_GE(open_req.result, 0);
|
|
|
94 uv_fs_req_cleanup(&open_req);
|
|
|
95
|
|
|
96 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
|
|
97 ASSERT_OK(r);
|
|
|
98 ASSERT_OK(close_req.result);
|
|
|
99 uv_fs_req_cleanup(&close_req);
|
|
|
100
|
|
|
101 /* dummy_file */
|
|
|
102 sprintf(dummy_file, "test_file_%d", sid++);
|
|
|
103
|
|
|
104 r = uv_fs_open(NULL, &open_req, dummy_file,
|
|
|
105 UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY, S_IWUSR | S_IRUSR, NULL);
|
|
|
106 ASSERT_GE(r, 0);
|
|
|
107 ASSERT_GE(open_req.result, 0);
|
|
|
108 uv_fs_req_cleanup(&open_req);
|
|
|
109
|
|
|
110 iov = uv_buf_init("a", 1);
|
|
|
111 r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
|
|
|
112 ASSERT_EQ(1, r);
|
|
|
113 ASSERT_EQ(1, write_req.result);
|
|
|
114 uv_fs_req_cleanup(&write_req);
|
|
|
115
|
|
|
116 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
|
|
117 ASSERT_OK(r);
|
|
|
118 ASSERT_OK(close_req.result);
|
|
|
119 uv_fs_req_cleanup(&close_req);
|
|
|
120 }
|
|
|
121
|
|
|
122 static void cleanup(void) {
|
|
|
123 unlink(absent_file);
|
|
|
124 unlink(empty_file);
|
|
|
125 unlink(dummy_file);
|
|
|
126 }
|
|
|
127
|
|
|
128 static void openFail(char *file, int error) {
|
|
|
129 int r;
|
|
|
130
|
|
|
131 refresh();
|
|
|
132
|
|
|
133 r = uv_fs_open(NULL, &open_req, file, flags, S_IWUSR | S_IRUSR, NULL);
|
|
|
134 ASSERT_EQ(r, error);
|
|
|
135 ASSERT_EQ(open_req.result, error);
|
|
|
136 uv_fs_req_cleanup(&open_req);
|
|
|
137
|
|
|
138 /* Ensure the first call does not create the file */
|
|
|
139 r = uv_fs_open(NULL, &open_req, file, flags, S_IWUSR | S_IRUSR, NULL);
|
|
|
140 ASSERT_EQ(r, error);
|
|
|
141 ASSERT_EQ(open_req.result, error);
|
|
|
142 uv_fs_req_cleanup(&open_req);
|
|
|
143
|
|
|
144 cleanup();
|
|
|
145 }
|
|
|
146
|
|
|
147 static void refreshOpen(char *file) {
|
|
|
148 int r;
|
|
|
149
|
|
|
150 refresh();
|
|
|
151
|
|
|
152 r = uv_fs_open(NULL, &open_req, file, flags, S_IWUSR | S_IRUSR, NULL);
|
|
|
153 ASSERT_GE(r, 0);
|
|
|
154 ASSERT_GE(open_req.result, 0);
|
|
|
155 uv_fs_req_cleanup(&open_req);
|
|
|
156 }
|
|
|
157
|
|
|
158 static void writeExpect(char *file, char *expected, int size) {
|
|
|
159 int r;
|
|
|
160
|
|
|
161 refreshOpen(file);
|
|
|
162
|
|
|
163 iov = uv_buf_init("b", 1);
|
|
|
164 r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
|
|
|
165 ASSERT_EQ(1, r);
|
|
|
166 ASSERT_EQ(1, write_req.result);
|
|
|
167 uv_fs_req_cleanup(&write_req);
|
|
|
168
|
|
|
169 iov = uv_buf_init("c", 1);
|
|
|
170 r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
|
|
|
171 ASSERT_EQ(1, r);
|
|
|
172 ASSERT_EQ(1, write_req.result);
|
|
|
173 uv_fs_req_cleanup(&write_req);
|
|
|
174
|
|
|
175 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
|
|
176 ASSERT_OK(r);
|
|
|
177 ASSERT_OK(close_req.result);
|
|
|
178 uv_fs_req_cleanup(&close_req);
|
|
|
179
|
|
|
180 /* Check contents */
|
|
|
181 r = uv_fs_open(NULL, &open_req, file, UV_FS_O_RDONLY, S_IWUSR | S_IRUSR, NULL);
|
|
|
182 ASSERT_GE(r, 0);
|
|
|
183 ASSERT_GE(open_req.result, 0);
|
|
|
184 uv_fs_req_cleanup(&open_req);
|
|
|
185
|
|
|
186 iov = uv_buf_init(buf, sizeof(buf));
|
|
|
187 r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL);
|
|
|
188 ASSERT_EQ(r, size);
|
|
|
189 ASSERT_EQ(read_req.result, size);
|
|
|
190 ASSERT_OK(strncmp(buf, expected, size));
|
|
|
191 uv_fs_req_cleanup(&read_req);
|
|
|
192
|
|
|
193 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
|
|
194 ASSERT_OK(r);
|
|
|
195 ASSERT_OK(close_req.result);
|
|
|
196 uv_fs_req_cleanup(&close_req);
|
|
|
197
|
|
|
198 cleanup();
|
|
|
199 }
|
|
|
200
|
|
|
201 static void writeFail(char *file, int error) {
|
|
|
202 int r;
|
|
|
203
|
|
|
204 refreshOpen(file);
|
|
|
205
|
|
|
206 iov = uv_buf_init("z", 1);
|
|
|
207 r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
|
|
|
208 ASSERT_EQ(r, error);
|
|
|
209 ASSERT_EQ(write_req.result, error);
|
|
|
210 uv_fs_req_cleanup(&write_req);
|
|
|
211
|
|
|
212 iov = uv_buf_init("z", 1);
|
|
|
213 r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL);
|
|
|
214 ASSERT_EQ(r, error);
|
|
|
215 ASSERT_EQ(write_req.result, error);
|
|
|
216 uv_fs_req_cleanup(&write_req);
|
|
|
217
|
|
|
218 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
|
|
219 ASSERT_OK(r);
|
|
|
220 ASSERT_OK(close_req.result);
|
|
|
221 uv_fs_req_cleanup(&close_req);
|
|
|
222
|
|
|
223 cleanup();
|
|
|
224 }
|
|
|
225
|
|
|
226 static void readExpect(char *file, char *expected, int size) {
|
|
|
227 int r;
|
|
|
228
|
|
|
229 refreshOpen(file);
|
|
|
230
|
|
|
231 iov = uv_buf_init(buf, sizeof(buf));
|
|
|
232 r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL);
|
|
|
233 ASSERT_EQ(r, size);
|
|
|
234 ASSERT_EQ(read_req.result, size);
|
|
|
235 ASSERT_OK(strncmp(buf, expected, size));
|
|
|
236 uv_fs_req_cleanup(&read_req);
|
|
|
237
|
|
|
238 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
|
|
239 ASSERT_OK(r);
|
|
|
240 ASSERT_OK(close_req.result);
|
|
|
241 uv_fs_req_cleanup(&close_req);
|
|
|
242
|
|
|
243 cleanup();
|
|
|
244 }
|
|
|
245
|
|
|
246 static void readFail(char *file, int error) {
|
|
|
247 int r;
|
|
|
248
|
|
|
249 refreshOpen(file);
|
|
|
250
|
|
|
251 iov = uv_buf_init(buf, sizeof(buf));
|
|
|
252 r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL);
|
|
|
253 ASSERT_EQ(r, error);
|
|
|
254 ASSERT_EQ(read_req.result, error);
|
|
|
255 uv_fs_req_cleanup(&read_req);
|
|
|
256
|
|
|
257 iov = uv_buf_init(buf, sizeof(buf));
|
|
|
258 r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL);
|
|
|
259 ASSERT_EQ(r, error);
|
|
|
260 ASSERT_EQ(read_req.result, error);
|
|
|
261 uv_fs_req_cleanup(&read_req);
|
|
|
262
|
|
|
263 r = uv_fs_close(NULL, &close_req, open_req.result, NULL);
|
|
|
264 ASSERT_OK(r);
|
|
|
265 ASSERT_OK(close_req.result);
|
|
|
266 uv_fs_req_cleanup(&close_req);
|
|
|
267
|
|
|
268 cleanup();
|
|
|
269 }
|
|
|
270
|
|
|
271 static void fs_open_flags(int add_flags) {
|
|
|
272 /* Follow the order from
|
|
|
273 * https://github.com/nodejs/node/blob/1a96abe849/lib/internal/fs/utils.js#L329-L354
|
|
|
274 */
|
|
|
275
|
|
|
276 /* r */
|
|
|
277 flags = add_flags | UV_FS_O_RDONLY;
|
|
|
278 openFail(absent_file, UV_ENOENT);
|
|
|
279 writeFail(empty_file, UV_EBADF);
|
|
|
280 readExpect(empty_file, "", 0);
|
|
|
281 writeFail(dummy_file, UV_EBADF);
|
|
|
282 readExpect(dummy_file, "a", 1);
|
|
|
283 writeFail(empty_dir, UV_EBADF);
|
|
|
284 readFail(empty_dir, UV_EISDIR);
|
|
|
285
|
|
|
286 /* rs */
|
|
|
287 flags = add_flags | UV_FS_O_RDONLY | UV_FS_O_SYNC;
|
|
|
288 openFail(absent_file, UV_ENOENT);
|
|
|
289 writeFail(empty_file, UV_EBADF);
|
|
|
290 readExpect(empty_file, "", 0);
|
|
|
291 writeFail(dummy_file, UV_EBADF);
|
|
|
292 readExpect(dummy_file, "a", 1);
|
|
|
293 writeFail(empty_dir, UV_EBADF);
|
|
|
294 readFail(empty_dir, UV_EISDIR);
|
|
|
295
|
|
|
296 /* r+ */
|
|
|
297 flags = add_flags | UV_FS_O_RDWR;
|
|
|
298 openFail(absent_file, UV_ENOENT);
|
|
|
299 writeExpect(empty_file, "bc", 2);
|
|
|
300 readExpect(empty_file, "", 0);
|
|
|
301 writeExpect(dummy_file, "bc", 2);
|
|
|
302 readExpect(dummy_file, "a", 1);
|
|
|
303 writeFail(empty_dir, UV_EISDIR);
|
|
|
304 readFail(empty_dir, UV_EISDIR);
|
|
|
305
|
|
|
306 /* rs+ */
|
|
|
307 flags = add_flags | UV_FS_O_RDWR | UV_FS_O_SYNC;
|
|
|
308 openFail(absent_file, UV_ENOENT);
|
|
|
309 writeExpect(empty_file, "bc", 2);
|
|
|
310 readExpect(empty_file, "", 0);
|
|
|
311 writeExpect(dummy_file, "bc", 2);
|
|
|
312 readExpect(dummy_file, "a", 1);
|
|
|
313 writeFail(empty_dir, UV_EISDIR);
|
|
|
314 readFail(empty_dir, UV_EISDIR);
|
|
|
315
|
|
|
316 /* w */
|
|
|
317 flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY;
|
|
|
318 writeExpect(absent_file, "bc", 2);
|
|
|
319 readFail(absent_file, UV_EBADF);
|
|
|
320 writeExpect(empty_file, "bc", 2);
|
|
|
321 readFail(empty_file, UV_EBADF);
|
|
|
322 writeExpect(dummy_file, "bc", 2);
|
|
|
323 readFail(dummy_file, UV_EBADF);
|
|
|
324 openFail(empty_dir, UV_EISDIR);
|
|
|
325
|
|
|
326 /* wx */
|
|
|
327 flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY |
|
|
|
328 UV_FS_O_EXCL;
|
|
|
329 writeExpect(absent_file, "bc", 2);
|
|
|
330 readFail(absent_file, UV_EBADF);
|
|
|
331 openFail(empty_file, UV_EEXIST);
|
|
|
332 openFail(dummy_file, UV_EEXIST);
|
|
|
333 openFail(empty_dir, UV_EEXIST);
|
|
|
334
|
|
|
335 /* w+ */
|
|
|
336 flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_RDWR;
|
|
|
337 writeExpect(absent_file, "bc", 2);
|
|
|
338 readExpect(absent_file, "", 0);
|
|
|
339 writeExpect(empty_file, "bc", 2);
|
|
|
340 readExpect(empty_file, "", 0);
|
|
|
341 writeExpect(dummy_file, "bc", 2);
|
|
|
342 readExpect(dummy_file, "", 0);
|
|
|
343 openFail(empty_dir, UV_EISDIR);
|
|
|
344
|
|
|
345 /* wx+ */
|
|
|
346 flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_RDWR |
|
|
|
347 UV_FS_O_EXCL;
|
|
|
348 writeExpect(absent_file, "bc", 2);
|
|
|
349 readExpect(absent_file, "", 0);
|
|
|
350 openFail(empty_file, UV_EEXIST);
|
|
|
351 openFail(dummy_file, UV_EEXIST);
|
|
|
352 openFail(empty_dir, UV_EEXIST);
|
|
|
353
|
|
|
354 /* a */
|
|
|
355 flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY;
|
|
|
356 writeExpect(absent_file, "bc", 2);
|
|
|
357 readFail(absent_file, UV_EBADF);
|
|
|
358 writeExpect(empty_file, "bc", 2);
|
|
|
359 readFail(empty_file, UV_EBADF);
|
|
|
360 writeExpect(dummy_file, "abc", 3);
|
|
|
361 readFail(dummy_file, UV_EBADF);
|
|
|
362 writeFail(empty_dir, UV_EISDIR);
|
|
|
363 readFail(empty_dir, UV_EBADF);
|
|
|
364
|
|
|
365 /* ax */
|
|
|
366 flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY |
|
|
|
367 UV_FS_O_EXCL;
|
|
|
368 writeExpect(absent_file, "bc", 2);
|
|
|
369 readFail(absent_file, UV_EBADF);
|
|
|
370 openFail(empty_file, UV_EEXIST);
|
|
|
371 openFail(dummy_file, UV_EEXIST);
|
|
|
372 openFail(empty_dir, UV_EEXIST);
|
|
|
373
|
|
|
374 /* as */
|
|
|
375 flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY |
|
|
|
376 UV_FS_O_SYNC;
|
|
|
377 writeExpect(absent_file, "bc", 2);
|
|
|
378 readFail(absent_file, UV_EBADF);
|
|
|
379 writeExpect(empty_file, "bc", 2);
|
|
|
380 readFail(empty_file, UV_EBADF);
|
|
|
381 writeExpect(dummy_file, "abc", 3);
|
|
|
382 readFail(dummy_file, UV_EBADF);
|
|
|
383 writeFail(empty_dir, UV_EISDIR);
|
|
|
384 readFail(empty_dir, UV_EBADF);
|
|
|
385
|
|
|
386 /* a+ */
|
|
|
387 flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR;
|
|
|
388 writeExpect(absent_file, "bc", 2);
|
|
|
389 readExpect(absent_file, "", 0);
|
|
|
390 writeExpect(empty_file, "bc", 2);
|
|
|
391 readExpect(empty_file, "", 0);
|
|
|
392 writeExpect(dummy_file, "abc", 3);
|
|
|
393 readExpect(dummy_file, "a", 1);
|
|
|
394 writeFail(empty_dir, UV_EISDIR);
|
|
|
395 readFail(empty_dir, UV_EISDIR);
|
|
|
396
|
|
|
397 /* ax+ */
|
|
|
398 flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR |
|
|
|
399 UV_FS_O_EXCL;
|
|
|
400 writeExpect(absent_file, "bc", 2);
|
|
|
401 readExpect(absent_file, "", 0);
|
|
|
402 openFail(empty_file, UV_EEXIST);
|
|
|
403 openFail(dummy_file, UV_EEXIST);
|
|
|
404 openFail(empty_dir, UV_EEXIST);
|
|
|
405
|
|
|
406 /* as+ */
|
|
|
407 flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR |
|
|
|
408 UV_FS_O_SYNC;
|
|
|
409 writeExpect(absent_file, "bc", 2);
|
|
|
410 readExpect(absent_file, "", 0);
|
|
|
411 writeExpect(empty_file, "bc", 2);
|
|
|
412 readExpect(empty_file, "", 0);
|
|
|
413 writeExpect(dummy_file, "abc", 3);
|
|
|
414 readExpect(dummy_file, "a", 1);
|
|
|
415 writeFail(empty_dir, UV_EISDIR);
|
|
|
416 readFail(empty_dir, UV_EISDIR);
|
|
|
417 }
|
|
|
418 TEST_IMPL(fs_open_flags) {
|
|
|
419 setup();
|
|
|
420
|
|
|
421 fs_open_flags(0);
|
|
|
422 fs_open_flags(UV_FS_O_FILEMAP);
|
|
|
423
|
|
|
424 /* Cleanup. */
|
|
|
425 rmdir(empty_dir);
|
|
|
426
|
|
|
427 MAKE_VALGRIND_HAPPY(uv_default_loop());
|
|
|
428 return 0;
|
|
|
429 }
|
|
|
430
|
|
|
431 #else
|
|
|
432
|
|
|
433 typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
|
|
|
434
|
|
|
435 #endif /* ifndef _WIN32 */
|