*/
/*
- * Copyright (C) 2015-2021 Eric Biggers
+ * Copyright 2015-2023 Eric Biggers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
#ifdef WITH_NTFS_3G
# include <sys/wait.h>
#endif
# include <windows.h>
# include <winternl.h>
# include <ntstatus.h>
+#else
+# include <linux/magic.h>
+# include <sys/vfs.h>
#endif
#include "wimlib.h"
static bool wimfile_in_use[MAX_NUM_WIMS];
static int in_use_wimfile_indices[MAX_NUM_WIMS];
static int num_wimfiles_in_use = 0;
+#ifndef _WIN32
+static u32 filesystem_type;
+#endif
static void
assertion_failed(int line, const char *format, ...)
change_to_temporary_directory(void)
{
#ifdef _WIN32
- ASSERT(SetCurrentDirectory(L"E:\\"),
- "failed to change directory to E:\\");
-#else
- const char *tmpdir = getenv("TMPDIR");
- if (!tmpdir)
- tmpdir = P_tmpdir;
+ const wchar_t *tmpdir = _wgetenv(T("TMPDIR"));
+
+ ASSERT(tmpdir != NULL, "TMPDIR must be set");
+ _wmkdir(tmpdir);
+ ASSERT(!_wchdir(tmpdir),
+ "failed to change to temporary directory '%ls'", tmpdir);
+#else /* _WIN32 */
+ const char *tmpdir = getenv("TMPDIR") ?: P_tmpdir;
+ struct statfs fs;
+
+ mkdir(tmpdir, 0700);
ASSERT(!chdir(tmpdir),
- "failed to change to temporary directory \"%s\": %m", tmpdir);
-#endif
+ "failed to change to temporary directory '%s': %m", tmpdir);
+ ASSERT(!statfs(".", &fs), "statfs of '%s' failed: %m", tmpdir);
+ filesystem_type = fs.f_type;
+#endif /* !_WIN32 */
}
static void __attribute__((unused))
#endif /* !_WIN32 */
-static uint32_t
+static u64 random_state;
+
+static u32
rand32(void)
{
- static uint64_t state;
-
- /* A simple linear congruential generator */
- state = (state * 25214903917 + 11) & (((uint64_t)1 << 48) - 1);
- return state >> 16;
+ /* A simple linear congruential generator */
+ random_state = (random_state * 25214903917 + 11) % (1ULL << 48);
+ return random_state >> 16;
}
-static inline bool
+static bool
randbool(void)
{
- return rand32() & 1;
+ return rand32() % 2;
+}
+
+static u64
+rand64(void)
+{
+ return ((u64)rand32() << 32) | rand32();
}
static tchar wimfile[32];
return write_flags;
}
-static uint32_t
+static u32
get_random_chunk_size(int min_order, int max_order)
{
return 1 << (min_order + (rand32() % (max_order - min_order + 1)));
const tchar *wimfile;
enum wimlib_compression_type ctype = WIMLIB_COMPRESSION_TYPE_NONE;
- uint32_t chunk_size = 0;
- uint32_t solid_chunk_size = 0;
+ u32 chunk_size = 0;
+ u32 solid_chunk_size = 0;
int write_flags;
WIMStruct *wim;
extract_flags |= WIMLIB_EXTRACT_FLAG_UNIX_DATA;
add_flags |= WIMLIB_ADD_FLAG_UNIX_DATA;
cmp_flags |= WIMLIB_CMP_FLAG_UNIX_MODE;
+ if (filesystem_type == EXT4_SUPER_MAGIC)
+ cmp_flags |= WIMLIB_CMP_FLAG_EXT4;
#endif /* !_WIN32 */
}
add_flags |= WIMLIB_ADD_FLAG_NORPFIX;
#ifdef _WIN32
-/* Enumerate and unregister all backing WIMs from the specified volume */
+/*
+ * Enumerate and unregister all backing WIMs from the volume containing the
+ * current directory.
+ */
static void
-unregister_all_backing_wims(const tchar drive_letter)
+unregister_all_backing_wims(void)
{
+ wchar_t full_path[MAX_PATH];
+ DWORD path_len;
wchar_t volume[7];
HANDLE h;
void *overlay_list;
WIM_PROVIDER_REMOVE_OVERLAY_INPUT wim;
} in;
- wsprintf(volume, L"\\\\.\\%lc:", drive_letter);
+ path_len = GetFullPathName(L".", ARRAY_LEN(full_path), full_path, NULL);
+ ASSERT(path_len > 0,
+ "Failed to get full path of current directory; error=%u",
+ (unsigned)GetLastError());
+ wsprintf(volume, L"\\\\.\\%lc:", full_path[0]);
h = CreateFile(volume, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_VALID_FLAGS, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
ASSERT(DeviceIoControl(h, FSCTL_REMOVE_OVERLAY, &in, sizeof(in),
NULL, 0, &bytes_returned, NULL),
"FSCTL_REMOVE_OVERLAY failed; error=%u",
- (unsigned )GetLastError());
+ (unsigned)GetLastError());
if (entry->NextEntryOffset == 0)
break;
entry = (const WIM_PROVIDER_OVERLAY_ENTRY *)
- ((const uint8_t *)entry + entry->NextEntryOffset);
+ ((const u8 *)entry + entry->NextEntryOffset);
}
free(overlay_list);
CloseHandle(h);
index = select_random_wimfile_index();
- unregister_all_backing_wims(L'E');
+ unregister_all_backing_wims();
copy_file(get_wimfile(index), L"wimboot.wim");
CHECK_RET(wimlib_open_wim(L"wimboot.wim", 0, &wim));
WIMStruct *wim;
WIMStruct *swm;
WIMStruct *joined_wim;
- uint64_t part_size;
+ u64 part_size;
int write_flags;
const tchar *globs[] = { T("tmp*.swm") };
int image_count;
int
main(int argc, tchar **argv)
{
- unsigned long long num_iterations;
-
- if (argc < 2) {
- num_iterations = ULLONG_MAX;
- printf("Starting test runner\n");
- } else {
- num_iterations = tstrtoull(argv[1], NULL, 10);
- printf("Starting test runner with %llu iterations\n",
- num_iterations);
- }
+ unsigned long time_limit = 0;
+ time_t start_time;
+ u64 i;
+
+ /* If you want to make the tests deterministic, delete this line. */
+ random_state = ((u64)time(NULL) << 16) ^ getpid();
+
+ if (argc >= 2)
+ time_limit = tstrtoul(argv[1], NULL, 10);
+
+ if (time_limit == 0)
+ printf("Starting wlfuzz with no time limit\n");
+ else
+ printf("Starting wlfuzz with time limit of %lu seconds\n",
+ time_limit);
- CHECK_RET(wimlib_global_init(0));
+ CHECK_RET(wimlib_global_init(WIMLIB_INIT_FLAG_STRICT_APPLY_PRIVILEGES |
+ WIMLIB_INIT_FLAG_STRICT_CAPTURE_PRIVILEGES));
wimlib_set_print_errors(true);
+ wimlib_seed_random(rand64());
change_to_temporary_directory();
- for (int i = 0; i < MAX_NUM_WIMS; i++)
+ for (i = 0; i < MAX_NUM_WIMS; i++)
ASSERT(!tunlink(get_wimfile(i)) || errno == ENOENT, "unlink: %m");
- for (unsigned long long i = 0; i < num_iterations; i++) {
- printf("--> iteration %llu\n", i);
+ i = 0;
+ start_time = time(NULL);
+ while (time_limit == 0 || time(NULL) < start_time + time_limit) {
+ printf("--> iteration %"PRIu64"\n", ++i);
(*operation_table[rand32() % ARRAY_LEN(operation_table)])();
}