Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478/* * Unit test suite for file functions * * Copyright 2024 Eric Pouech for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
#include <errno.h>#include <direct.h>#include <stdarg.h>#include <locale.h>#include <process.h>#include <share.h>#include <sys/stat.h>
#include <windef.h>#include <winbase.h>#include <winnls.h>#include "wine/test.h"#include <corecrt_io.h>
#define STDIN_FILENO 0#define STDOUT_FILENO 1#define STDERR_FILENO 2
static void test_std_stream_buffering(void){ int dup_fd, ret, pos; FILE *file; char ch;
dup_fd = _dup(STDOUT_FILENO); ok(dup_fd != -1, "_dup failed\n");
file = freopen("std_stream_test.tmp", "w", stdout); ok(file != NULL, "freopen failed\n");
ret = fprintf(stdout, "test"); pos = _telli64(STDOUT_FILENO);
fflush(stdout); _dup2(dup_fd, STDOUT_FILENO); close(dup_fd); setvbuf(stdout, NULL, _IONBF, 0);
ok(ret == 4, "fprintf(stdout) returned %d\n", ret); ok(!pos, "expected stdout to be buffered\n");
dup_fd = _dup(STDERR_FILENO); ok(dup_fd != -1, "_dup failed\n");
file = freopen("std_stream_test.tmp", "w", stderr); ok(file != NULL, "freopen failed\n");
ret = fprintf(stderr, "test"); ok(ret == 4, "fprintf(stderr) returned %d\n", ret); pos = _telli64(STDERR_FILENO); if (broken(!GetProcAddress(GetModuleHandleA("ucrtbase"), "__CxxFrameHandler4") && !pos)) trace("stderr is buffered\n"); else ok(pos == 4, "expected stderr to be unbuffered (%d)\n", pos);
fflush(stderr); _dup2(dup_fd, STDERR_FILENO); close(dup_fd);
dup_fd = _dup(STDIN_FILENO); ok(dup_fd != -1, "_dup failed\n");
file = freopen("std_stream_test.tmp", "r", stdin); ok(file != NULL, "freopen failed\n");
ch = 0; ret = fscanf(stdin, "%c", &ch); ok(ret == 1, "fscanf returned %d\n", ret); ok(ch == 't', "ch = 0x%x\n", (unsigned char)ch); pos = _telli64(STDIN_FILENO); ok(pos == 4, "pos = %d\n", pos);
fflush(stdin); _dup2(dup_fd, STDIN_FILENO); close(dup_fd);
ok(DeleteFileA("std_stream_test.tmp"), "DeleteFile failed\n");}
int CDECL _get_stream_buffer_pointers(FILE*,char***,char***,int**);static void test_iobuf_layout(void){ union { FILE *f; struct { char* _ptr; char* _base; int _cnt; int _flag; int _file; int _charbuf; int _bufsiz; char* _tmpfname; CRITICAL_SECTION _crit; } *iobuf; } fp; char *tempf, *ptr, **file_ptr, **file_base; int cnt, r, *file_cnt;
tempf = _tempnam(".","wne"); fp.f = fopen(tempf, "wb"); ok(fp.f != NULL, "fopen failed with error: %d\n", errno);
ok(!(fp.iobuf->_flag & 0x440), "fp.iobuf->_flag = %x\n", fp.iobuf->_flag); r = fprintf(fp.f, "%s", "init"); ok(r == 4, "fprintf returned %d\n", r); ok(fp.iobuf->_flag & 0x40, "fp.iobuf->_flag = %x\n", fp.iobuf->_flag); ok(fp.iobuf->_cnt + 4 == fp.iobuf->_bufsiz, "_cnt = %d, _bufsiz = %d\n", fp.iobuf->_cnt, fp.iobuf->_bufsiz);
ptr = fp.iobuf->_ptr; cnt = fp.iobuf->_cnt; r = fprintf(fp.f, "%s", "hello"); ok(r == 5, "fprintf returned %d\n", r); ok(ptr + 5 == fp.iobuf->_ptr, "fp.iobuf->_ptr = %p, expected %p\n", fp.iobuf->_ptr, ptr + 5); ok(cnt - 5 == fp.iobuf->_cnt, "fp.iobuf->_cnt = %d, expected %d\n", fp.iobuf->_cnt, cnt - 5); ok(fp.iobuf->_ptr + fp.iobuf->_cnt == fp.iobuf->_base + fp.iobuf->_bufsiz, "_ptr = %p, _cnt = %d, _base = %p, _bufsiz = %d\n", fp.iobuf->_ptr, fp.iobuf->_cnt, fp.iobuf->_base, fp.iobuf->_bufsiz);
_get_stream_buffer_pointers(fp.f, &file_base, &file_ptr, &file_cnt); ok(file_base == &fp.iobuf->_base, "_base = %p, expected %p\n", file_base, &fp.iobuf->_base); ok(file_ptr == &fp.iobuf->_ptr, "_ptr = %p, expected %p\n", file_ptr, &fp.iobuf->_ptr); ok(file_cnt == &fp.iobuf->_cnt, "_cnt = %p, expected %p\n", file_cnt, &fp.iobuf->_cnt);
r = setvbuf(fp.f, NULL, _IONBF, 0); ok(!r, "setvbuf returned %d\n", r); ok(fp.iobuf->_flag & 0x400, "fp.iobuf->_flag = %x\n", fp.iobuf->_flag);
ok(TryEnterCriticalSection(&fp.iobuf->_crit), "TryEnterCriticalSection section returned FALSE\n"); LeaveCriticalSection(&fp.iobuf->_crit);
fclose(fp.f); unlink(tempf);}
static void test_std_stream_open(void){ FILE *f; int fd;
fd = _dup(STDIN_FILENO); ok(fd != -1, "_dup failed\n");
ok(!fclose(stdin), "fclose failed\n"); f = fopen("nul", "r"); ok(f != stdin, "f = %p, stdin = %p\n", f, stdin); ok(_fileno(f) == STDIN_FILENO, "_fileno(f) = %d\n", _fileno(f)); ok(!fclose(f), "fclose failed\n");
f = freopen("nul", "r", stdin); ok(f == stdin, "f = %p, expected %p\n", f, stdin); ok(_fileno(f) == STDIN_FILENO, "_fileno(f) = %d\n", _fileno(f));
_dup2(fd, STDIN_FILENO); close(fd);}
static void test_fopen(void){ int i; FILE *f; wchar_t wpath[MAX_PATH]; static const struct { const char *loc; const char *path; } tests[] = { { "German.utf8", "t\xc3\xa4\xc3\x8f\xc3\xb6\xc3\x9f.txt" }, { "Polish.utf8", "t\xc4\x99\xc5\x9b\xc4\x87.txt" }, { "Turkish.utf8", "t\xc3\x87\xc4\x9e\xc4\xb1\xc4\xb0\xc5\x9e.txt" }, { "Arabic.utf8", "t\xd8\xaa\xda\x86.txt" }, { "Japanese.utf8", "t\xe3\x82\xaf\xe3\x83\xa4.txt" }, { "Chinese.utf8", "t\xe4\xb8\x82\xe9\xbd\xab.txt" }, { "Japanese", "t\xb8\xd5.txt" },
};
for(i=0; i<ARRAY_SIZE(tests); i++) { if(!setlocale(LC_ALL, tests[i].loc)) { win_skip("skipping locale %s\n", tests[i].loc); continue; }
if(!MultiByteToWideChar(___lc_codepage_func() == CP_UTF8 ? CP_UTF8 : CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, tests[i].path, -1, wpath, MAX_PATH)) continue;
f = _fsopen(tests[i].path, "w", SH_DENYNO); ok(!!f, "failed to create %s with locale %s\n", debugstr_a(tests[i].path), tests[i].loc); fclose(f);
f = _wfsopen(wpath, L"r", SH_DENYNO); ok(!!f, "failed to open %s with locale %s\n", debugstr_a(tests[i].path), tests[i].loc); if(f) fclose(f);
ok(!unlink(tests[i].path), "failed to unlink %s with locale %s\n", tests[i].path, tests[i].loc); } setlocale(LC_ALL, "C");}
static void test_utf8(const char *argv0){ const char file[] = "file\xc4\x99\xc5\x9b\xc4\x87.a"; const char dir[] = "dir\xc4\x99\xc5\x9b\xc4\x87"; const WCHAR fileW[] = L"file\x0119\x015b\x0107.a"; const WCHAR dirW[] = L"dir\x0119\x015b\x0107";
char file2[32], buf[256], *p, *q, *env[2]; struct _finddata64i32_t fdata64i32; struct _finddata32_t fdata32; struct _finddata64_t fdata64; intptr_t hfind, hproc; WCHAR bufW[256], *pW; struct _stat64 stat; FILE *f; int ret;
if (!setlocale(LC_ALL, ".utf8")) { win_skip("utf-8 tests\n"); return; }
ret = _mkdir(dir); if (ret == -1 && errno == ENOENT) { skip("can't create test environment\n"); return; } ok(!ret, "_mkdir returned %d, error %d\n", ret, errno);
ret = _chdir(dir); ok(!ret, "_chdir returned %d, error %d\n", ret, errno);
p = _getcwd(buf, sizeof(buf)); ok(p == buf, "_getcwd returned %p, errno %d\n", p, errno); p = strrchr(p, '\\'); ok(!!p, "strrchr returned NULL, buf = %s\n", debugstr_a(buf)); ok(!strcmp(p + 1, dir), "unexpected working directory: %s\n", debugstr_a(buf));
p = _getdcwd(_getdrive(), buf, sizeof(buf)); ok(p == buf, "_getdcwd returned %p, errno %d\n", p, errno); p = strrchr(p, '\\'); ok(!!p, "strrchr returned NULL, buf = %s\n", debugstr_a(buf)); ok(!strcmp(p + 1, dir), "unexpected working directory: %s\n", debugstr_a(buf));
p = _fullpath(buf, NULL, sizeof(buf)); ok(p == buf, "_fulpath returned %p, errno %d\n", p, errno); p = strrchr(p, '\\'); ok(!!p, "strrchr returned NULL, buf = %s\n", debugstr_a(buf)); ok(!strcmp(p + 1, dir), "unexpected working directory: %s\n", debugstr_a(buf));
f = fopen(file, "w"); ok(!!f, "fopen returned %d, error %d\n", ret, errno); fclose(f);
ret = access(file, 0); ok(!ret, "access returned %d, error %d\n", ret, errno);
ret = _stat64(file, &stat); ok(!ret, "_stat64 returned %d, error %d\n", ret, errno);
ret = _chmod(file, _S_IREAD | _S_IWRITE); ok(!ret, "_chmod returned %d, error %d\n", ret, errno);
strcpy(file2, file); strcat(file2, "XXXXXX"); p = _mktemp(file2); ok(p == file2, "_mktemp returned %p, file2 %p, errno %d\n", p, file2, errno); ok(!memcmp(file2, file, sizeof(file) - 1), "file2 = %s\n", debugstr_a(file2)); ok(p[ARRAY_SIZE(file) - 1] == 'a', "p = %s\n", debugstr_a(p)); f = fopen(p, "w"); ok(!!f, "fopen returned %d, error %d\n", ret, errno); fclose(f);
strcpy(buf, file); strcat(buf, "XXXXXX"); p = _mktemp(buf); ok(p == buf, "_mktemp returned %p, buf %p, errno %d\n", p, buf, errno); ok(!memcmp(buf, file, sizeof(file) - 1), "buf = %s\n", debugstr_a(buf)); ok(p[ARRAY_SIZE(file) - 1] == 'b', "p = %s\n", debugstr_a(p));
strcpy(buf, file); strcat(buf, "XXXXXX"); ret = _mktemp_s(buf, sizeof(buf)); ok(!memcmp(buf, file, sizeof(file) - 1), "buf = %s\n", debugstr_a(buf)); ok(buf[ARRAY_SIZE(file) - 1] == 'b', "buf = %s\n", debugstr_a(buf));
strcpy(buf, file); strcat(buf, "*"); fdata32.name[0] = 'x'; hfind = _findfirst32(buf, &fdata32); ok(hfind != -1, "_findfirst32 returned %Id, errno %d\n", hfind, errno); ok(!memcmp(file, fdata32.name, sizeof(file) - 1), "fdata32.name = %s\n", debugstr_a(fdata32.name));
fdata32.name[0] = 'x'; ret = _findnext32(hfind, &fdata32); ok(!ret, "_findnext32 returned %d, errno %d\n", ret, errno); ok(!memcmp(file, fdata32.name, sizeof(file) - 1), "fdata32.name = %s\n", debugstr_a(fdata32.name)); ret = _findclose(hfind); ok(!ret, "_findclose returned %d, errno %d\n", ret, errno);
strcpy(buf, file); strcat(buf, "*"); fdata64.name[0] = 'x'; hfind = _findfirst64(buf, &fdata64); ok(hfind != -1, "_findfirst64 returned %Id, errno %d\n", hfind, errno); ok(!memcmp(file, fdata64.name, sizeof(file) - 1), "fdata64.name = %s\n", debugstr_a(fdata64.name));
fdata64.name[0] = 'x'; ret = _findnext64(hfind, &fdata64); ok(!ret, "_findnext64 returned %d, errno %d\n", ret, errno); ok(!memcmp(file, fdata64.name, sizeof(file) - 1), "fdata64.name = %s\n", debugstr_a(fdata64.name)); ret = _findclose(hfind); ok(!ret, "_findclose returned %d, errno %d\n", ret, errno);
strcpy(buf, file); strcat(buf, "*"); fdata64i32.name[0] = 'x'; hfind = _findfirst64i32(buf, &fdata64i32); ok(hfind != -1, "_findfirst64i32 returned %Id, errno %d\n", hfind, errno); ok(!memcmp(file, fdata64i32.name, sizeof(file) - 1), "fdata64i32.name = %s\n", debugstr_a(fdata64i32.name));
fdata64i32.name[0] = 'x'; ret = _findnext64i32(hfind, &fdata64i32); ok(!ret, "_findnext64i32 returned %d, errno %d\n", ret, errno); ok(!memcmp(file, fdata64i32.name, sizeof(file) - 1), "fdata64i32.name = %s\n", debugstr_a(fdata64i32.name)); ret = _findclose(hfind); ok(!ret, "_findclose returned %d, errno %d\n", ret, errno);
ret = remove(file2); ok(!ret, "remove returned %d, errno %d\n", ret, errno);
buf[0] = 'x'; _searchenv(file, "env", buf); p = strrchr(buf, '\\'); ok(!!p, "buf = %s\n", debugstr_a(buf)); ok(!strcmp(p + 1, file), "buf = %s\n", debugstr_a(buf));
ret = _wunlink(fileW); ok(!ret, "_wunlink returned %d, errno %d\n", ret, errno);
ret = _chdir(".."); ok(!ret, "_chdir returned %d, error %d\n", ret, errno);
ret = _wrmdir(dirW); ok(!ret, "_wrmdir returned %d, errno %d\n", ret, errno);
p = _tempnam(NULL, file); ok(!!p, "_tempnam returned NULL, error %d\n", errno); q = strrchr(p, '\\'); ok(!!q, "_tempnam returned %s\n", debugstr_a(p)); todo_wine ok(!memcmp(q + 1, file, ARRAY_SIZE(file) - 1), "incorrect file prefix: %s\n", debugstr_a(p)); free(p);
/* native implementation mixes CP_UTF8 and CP_ACP */ if (GetACP() != CP_UTF8) { /* make sure wide environment is initialized (works around bug in native) */ ret = _putenv("__wine_env_test=test"); ok(!ret, "_putenv returned %d, errno %d\n", ret, errno); _wgetenv(L"__wine_env_test");
strcpy(buf, file); strcat(buf, "=test"); ret = _putenv(buf); ok(!ret, "_putenv returned %d, errno %d\n", ret, errno); /* bug in native _wgetenv/_putenv implementation */ pW = _wgetenv(fileW); ok(!pW, "environment variable name was converted\n"); bufW[0] = 0; ret = GetEnvironmentVariableW(fileW, bufW, ARRAY_SIZE(bufW)); todo_wine ok(ret, "GetEnvironmentVariableW returned error %lu\n", GetLastError()); todo_wine ok(!wcscmp(bufW, L"test"), "bufW = %s\n", debugstr_w(bufW)); strcpy(buf, file); strcat(buf, "="); ret = _putenv(buf); ok(!ret, "_putenv returned %d, errno %d\n", ret, errno);
strcpy(buf, "__wine_env_test="); strcat(buf, file); ret = _putenv(buf); ok(!ret, "_putenv returned %d, errno %d\n", ret, errno); /* bug in native _wgetenv/_putenv implementation */ pW = _wgetenv(L"__wine_env_test"); ok(wcscmp(pW, fileW), "pW = %s\n", debugstr_w(pW)); ret = GetEnvironmentVariableW(L"__wine_env_test", bufW, ARRAY_SIZE(bufW)); ok(ret, "GetEnvironmentVariableW returned error %lu\n", GetLastError()); todo_wine ok(!wcscmp(bufW, fileW), "bufW = %s\n", debugstr_w(bufW));
wcscpy(bufW, L"__wine_env_test="); wcscat(bufW, fileW); ret = _wputenv(bufW); ok(!ret, "_wputenv returned %d, errno %d\n", ret, errno); p = getenv("__wine_env_test"); ok(strcmp(p, file), "environment variable was converted\n"); strcpy(buf, "__wine_env_test="); ret = _putenv(buf); ok(!ret, "_putenv returned %d, errno %d\n", ret, errno); }
strcpy(buf, "__wine_env_test="); strcat(buf, file); env[0] = buf; env[1] = NULL; hproc = _spawnle(_P_NOWAIT, argv0, argv0, "file", "utf8", file, NULL, env); ok(hproc != -1, "_spawnl returned %Id, errno %d\n", hproc, errno); wait_child_process((HANDLE)hproc); CloseHandle((HANDLE)hproc);
setlocale(LC_ALL, "C");}
static void test_utf8_argument(void){ static const WCHAR nameW[] = L"file\x0119\x015b\x0107.a"; const WCHAR *cmdline = GetCommandLineW(), *p; WCHAR buf[256]; DWORD ret;
p = wcsrchr(cmdline, ' '); ok(!!p, "cmdline = %s\n", debugstr_w(cmdline)); ok(!wcscmp(p + 1, nameW), "cmdline = %s\n", debugstr_w(cmdline));
ret = GetEnvironmentVariableW(L"__wine_env_test", buf, ARRAY_SIZE(buf)); ok(ret, "GetEnvironmentVariableW returned error %lu\n", GetLastError()); if (GetACP() == CP_UTF8) ok(!wcscmp(buf, nameW), "__wine_env_test = %s\n", debugstr_w(buf)); else ok(wcscmp(buf, nameW), "environment was converted\n");}
START_TEST(file){ int arg_c; char** arg_v;
arg_c = winetest_get_mainargs(&arg_v); if(arg_c == 4 && !strcmp(arg_v[2], "utf8")) { test_utf8_argument(); return; }
test_std_stream_buffering(); test_iobuf_layout(); test_std_stream_open(); test_fopen(); test_utf8(arg_v[0]);}