blob: 67cc9a1f9c45ad23a01bfde4b66b090060ecd1e2 [file] [log] [blame] [raw]
#include <windows.h>
#include <time.h>
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <shared.h>
struct stat_file_info_t {
DWORD dwFileAttributes;
FILETIME ftLastWriteTime;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
DWORD nFileSizeLow;
};
#define COPY_MEMBER(DEST, SRC, MEMBER) \
do { \
(DEST)->MEMBER = (SRC)->MEMBER; \
} while (0)
#define TO_STAT_FILE_INFO(DEST, SRC) \
do { \
COPY_MEMBER (DEST, SRC, dwFileAttributes); \
COPY_MEMBER (DEST, SRC, ftLastWriteTime); \
COPY_MEMBER (DEST, SRC, ftCreationTime); \
COPY_MEMBER (DEST, SRC, ftLastAccessTime); \
COPY_MEMBER (DEST, SRC, nFileSizeLow); \
} while (0)
static int __stat_by_file_info (struct stat_file_info_t *fi, struct stat *st, int exec) {
int permission = _S_IREAD;
memset (st, 0, sizeof (*st));
st->st_size = fi->nFileSizeLow;
st->st_mode = _S_IFREG;
if((fi->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
st->st_mode = _S_IFDIR | _S_IEXEC;
} else if(exec) permission |= _S_IEXEC;
if((fi->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) {
permission |= _S_IWRITE;
}
st->st_mode |= permission | (permission >> 3) | (permission >> 6);
st->st_nlink = 1; /* always 1? */
st->st_rdev = 1; /* Where to get drive info? */
st->st_ino = 0; /* always 0 on Windows */
st->st_mtime = __filetime_to_time_t(fi->ftLastWriteTime);
st->st_ctime = __filetime_to_time_t(fi->ftCreationTime);
st->st_atime = __filetime_to_time_t(fi->ftLastAccessTime);
/* Looks like the code below is never triggered.
Windows CE always only keeps the LastWriteTime, and
copies it to the CreationTime and LastAccessTime fields. */
if(st->st_ctime == 0) st->st_ctime = st->st_mtime;
if(st->st_atime == 0) {
/* On XP, at least, the st_atime is always set to the same as
the st_mtime, except the hour/min/sec == 00:00:00. */
SYSTEMTIME s;
FILETIME f = fi->ftLastWriteTime;
FileTimeToSystemTime(&f, &s);
s.wHour = 0; s.wMinute = 0;
s.wSecond = 0; s.wMilliseconds = 0;
SystemTimeToFileTime (&s, &f);
st->st_atime = __filetime_to_time_t(f);
/* st->st_atime = st->st_mtime; */
}
return 0;
}
int _fstat(int fd, struct _stat *st) {
BY_HANDLE_FILE_INFORMATION_NEW fi;
struct stat_file_info_t sfi;
if(!GetFileInformationByHandle((HANDLE)fd, (BY_HANDLE_FILE_INFORMATION *)&fi)) return -1;
TO_STAT_FILE_INFO(&sfi, &fi);
return __stat_by_file_info(&sfi, (struct stat *)st, 1);
}
int fstat(int fd, struct stat *st) {
return _fstat(fd, (struct _stat *)st);
}
int _stat(const char *path, struct _stat *st) {
WIN32_FIND_DATAW fd;
HANDLE h;
int ret;
struct stat_file_info_t sfi;
wchar_t wpath[MAX_PATH + 1];
size_t len, wlen;
int dir = 0;
len = strlen(path);
if(len > MAX_PATH) {
errno = ENAMETOOLONG;
return -1;
}
wlen = mbstowcs(wpath, path, len + 1);
if(path[len - 1] == '/') {
dir = 1;
if(len > 1 && wlen > 0) wpath[wlen - 1] = 0;
}
if((h = FindFirstFileW(wpath, &fd)) == INVALID_HANDLE_VALUE) {
DWORD dwError = GetLastError();
if(dwError == ERROR_NO_MORE_FILES) {
/* Convert error to something more sensible. */
SetLastError(ERROR_FILE_NOT_FOUND);
}
return -1;
}
TO_STAT_FILE_INFO(&sfi, &fd);
//fprintf(stderr, "celibc debug: path = \"%s\", wpath = L\"%ls\", dir = %d, sfi.dwFileAttributes = %lu\n", path, wpath, dir, sfi.dwFileAttributes);
if(dir && !(sfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
errno = ENOTDIR;
return -1;
}
ret = __stat_by_file_info(&sfi, (struct stat *)st, 1);
FindClose(h);
return ret;
}
int stat(const char *path, struct stat *st) {
return _stat(path, (struct _stat *)st);
}