#include "../CgeFile.h" #include struct CgeFile { HANDLE handle; int flags; int mode; int lastError; }; static int errorCodeFromError(void) { DWORD error; error = GetLastError(); switch (error) { case ERROR_NOT_ENOUGH_MEMORY: return CGE_FILE_EOOM; case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: return CGE_FILE_ENOENT; case ERROR_ACCESS_DENIED: return CGE_FILE_EACCES; case ERROR_FILE_EXISTS: case ERROR_ALREADY_EXISTS: return CGE_FILE_EEXIST; case ERROR_DIRECTORY: return CGE_FILE_EISDIR; case ERROR_WRITE_PROTECT: return CGE_FILE_EROFS; case ERROR_TOO_MANY_OPEN_FILES: return CGE_FILE_EMFILE; case ERROR_INVALID_NAME: case ERROR_FILENAME_EXCED_RANGE: return CGE_FILE_ENAMETOOLONG; case ERROR_DISK_FULL: case ERROR_HANDLE_DISK_FULL: return CGE_FILE_ENOSPC; default: return CGE_FILE_EUNKNOWN; } } static int fileInit(CgeFile *file, const char *path, int mode) { DWORD access = 0, how = 0; if (!path) return CGE_FILE_EINVAL; if (mode & CGE_FILE_READ) access |= GENERIC_READ; if (mode & CGE_FILE_WRITE) access |= GENERIC_WRITE; if (!access) return CGE_FILE_EINVAL; if (mode & CGE_FILE_TRUNCATE) { switch (mode & (CGE_FILE_CREATE | CGE_FILE_EXIST)) { case 0: how = CREATE_ALWAYS; break; case CGE_FILE_CREATE: how = CREATE_NEW; break; case CGE_FILE_EXIST: how = TRUNCATE_EXISTING; break; default: return CGE_FILE_EINVAL; } } else { switch (mode & (CGE_FILE_CREATE | CGE_FILE_EXIST)) { case 0: how = OPEN_ALWAYS; break; case CGE_FILE_CREATE: how = CREATE_NEW; break; case CGE_FILE_EXIST: how = OPEN_EXISTING; break; default: return CGE_FILE_EINVAL; } } file->flags = 0; file->mode = mode; file->handle = CreateFileA(path, access, FILE_SHARE_READ, NULL, how, FILE_ATTRIBUTE_NORMAL, NULL); if (file->handle == INVALID_HANDLE_VALUE) return errorCodeFromError(); if (mode & CGE_FILE_TRUNCATE) SetEndOfFile(file->handle); return CGE_FILE_EOK; } CgeFile *CgeFileNew(const char *path, int mode, int *result) { CgeFile *file; int code = 0; if ((file = malloc(sizeof(*file)))) { if ((code = fileInit(file, path, mode))) { free(file); file = NULL; } } if (result) *result = code; return file; } void CgeFileFree(CgeFile *file) { CloseHandle(file->handle); free(file); } int CgeFileRead(CgeFile *file, char *buffer, size_t size, size_t *actual) { DWORD readed; if (file->flags & CGE_FILE_ERROR) return 0; if (!ReadFile(file->handle, buffer, (DWORD)size, &readed, NULL)) goto error; if (!readed) file->flags |= CGE_FILE_EOF; else file->flags &= ~CGE_FILE_EOF; if (actual) *actual = readed; return 1; error: file->flags |= CGE_FILE_ERROR; file->lastError = errorCodeFromError(); return 0; } int CgeFileWrite(CgeFile *file, const char *buffer, size_t size, size_t *actual) { DWORD written; LARGE_INTEGER position; if (file->flags & CGE_FILE_ERROR) return 0; if (file->mode & CGE_FILE_APPEND) { position.QuadPart = 0; if (!SetFilePointerEx(file->handle, position, NULL, FILE_END)) goto error; } if (!WriteFile(file->handle, buffer, (DWORD)size, &written, NULL)) goto error; if (actual) *actual = written; return 1; error: file->flags |= CGE_FILE_ERROR; file->lastError = errorCodeFromError(); return 0; } int CgeFileTell(CgeFile *file, int64_t *offset) { LARGE_INTEGER dummy, position; if (file->flags & CGE_FILE_ERROR) return 0; dummy.QuadPart = 0; if (!SetFilePointerEx(file->handle, dummy, &position, FILE_CURRENT)) goto error; *offset = position.QuadPart; return 1; error: file->flags |= CGE_FILE_ERROR; file->lastError = errorCodeFromError(); return 0; } int CgeFileSeek(CgeFile *file, int64_t offset, int whence) { LARGE_INTEGER position; if (file->flags & CGE_FILE_ERROR) return 0; position.QuadPart = offset; if (!SetFilePointerEx(file->handle, position, NULL, whence)) goto error; file->flags &= ~CGE_FILE_EOF; return 1; error: file->flags |= CGE_FILE_ERROR; file->lastError = errorCodeFromError(); return 0; } int CgeFileFlush(CgeFile *file) { if (!FlushFileBuffers(file->handle)) goto error; return 1; error: file->flags |= CGE_FILE_ERROR; file->lastError = errorCodeFromError(); return 0; } int CgeFileSize(CgeFile *file, int64_t *size) { LARGE_INTEGER dummy; if (file->flags & CGE_FILE_ERROR) return 0; if (!GetFileSizeEx(file->handle, &dummy)) goto error; *size = dummy.QuadPart; return 1; error: file->flags |= CGE_FILE_ERROR; file->lastError = errorCodeFromError(); return 0; } int CgeFileFlags(CgeFile *file, int *flags) { *flags = file->flags; return 1; } int CgeFileClear(CgeFile *file) { file->flags &= ~CGE_FILE_ERROR; return 1; } int CgeFileErrorCode(CgeFile *file) { return file->lastError; }