You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

161 lines
3.1 KiB
C

// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/fs_windows.c
*
* System specific filesystem utilities over Windows.
*
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
* \author Lorenzo Cogotti
*/
#include "sys/fs.h"
#include "sys/err_local.h"
#include <errno.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#error "Sorry, not fully implemented yet!"
typedef union {
wchar_t wstr[_MAX_PATH + 1];
char str[(_MAX_PATH + 1) * sizeof(wchar_t)];
} Pathbuf;
static THREAD_LOCAL Pathbuf pathbuf;
static wchar_t *Sys_Utf8PathToW(const char *path)
{
int n = MultiByteToWideChar(CP_UTF8, 0, path, -1, pathbuf.wstr, ARRAY_SIZE(pathbuf.wstr));
if (n < 0) {
Sys_SetErrStat(GetLastError(), "MultiByteToWideChar() failed");
return NULL;
}
return pathbuf.wstr;
}
static char *Sys_WPathToUtf8(const wchar_t *path)
{
int n = WideCharToMultiByte(CP_UTF16, 0, path, -1, pathbuf.str, sizeof(pathbuf.str));
if (n < 0) {
Sys_GetErrStat(GetLastError(), "WideCharToMultiByte() failed");
return NULL;
}
return pathbuf.str;
}
Judgement Sys_SetEof(Fildes fd)
{
if (!SetEndOfFile(fd)) {
Sys_SetErrStat(GetLastError(), "SetEndOfFile() failed");
return NG;
}
return OK;
}
void Sys_Fclose(Fildes fd)
{
CloseHandle(fd);
}
typedef struct FileList FileList;
struct FileList {
FileList *next;
unsigned len;
char name[1]; // dynamically sized len+1
};
char **Sys_ListFiles(const char *dir, unsigned *nfiles, const char *pat)
{
if (!pat)
pat = "";
int flag;
if (strcmp(pat, "/") == 0) {
pat = "";
flag = _A_SUBDIR;
} else {
flag = 0;
}
char *search = (char *) alloca(strlen(dir) + 1 + 1 + strlen(pat) + 1);
if (sprintf(search, "%s\\*%s", dir, pat) < 0) {
Sys_SetErrStat(errno, "sprintf() failed");
return NULL;
}
wchar_t *wsearch = Sys_Utf8PathToW(search);
if (!wsearch)
return NULL; // error already set
FileList *entries = NULL;
unsigned count = 0;
size_t nchars = 0;
errno = 0;
struct _wfinddata_t finddata;
intptr_t findhn = _wfindfirst(wsearch, &finddata);
if (findhn != -1) {
// Scan directory
do {
if (finddata.attrib & flag) {
// remember this file
char *path = Sys_WPathToUtf8(finddata.name);
size_t n = strlen(path);
count++;
nchars += n + 1;
FileList *e = (FileList *) alloca(sizeof(*e) + n);
e->next = entries;
e->len = n;
memcpy(e->name, path, n + 1);
entries = e;
}
} while (_wfindnext(findhn, &finddata) == 0);
}
if (errno != 0) {
Sys_SetErrStat(errno, "_wfindfirst()/_wfindnext()");
goto fail;
}
char **files = (char **) malloc(sizeof(*files) * (count + 1) + nchars);
if (!files) {
Sys_OutOfMemory();
goto fail;
}
_findclose(findhn); // safe, can't fail anymore
char *namep = (char *) (files + count + 1);
for (unsigned i = 0; i < count; i++) {
files[i] = namep;
size_t n = entries->len + 1;
memcpy(namep, entries->name, n);
namep += n;
entries = entries->next;
}
files[count] = NULL;
if (nfiles)
*nfiles = count;
return files;
fail:
_findclose(findhn);
return NULL;
}