/* * Copyright (C) Tristan Franssen, . * * This software is licensed under the Apache License, Version 2.0 (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License in the file LICENSE or at * http://www.apache.org/licenses/LICENSE-2.0 */ #include "cosms-core/file.h" #include #include #include #if defined(__GNUC__) #define _FILE_OFFSET_BITS_ 64 #include #include #include #include #endif CosmsCoreFileError cosms_core_file_open(struct cosms_core_file *file, const char *path, int mode) { file->mode = mode; #if defined(__GNUC__) int flags = 0; if (mode & (COSMS_CORE_FILE_MODE_READ | COSMS_CORE_FILE_MODE_WRITE)) { flags |= O_RDWR; } else if (mode & COSMS_CORE_FILE_MODE_READ) { flags |= O_RDONLY; } else if (mode & COSMS_CORE_FILE_MODE_WRITE) { flags |= O_WRONLY; } if (mode & COSMS_CORE_FILE_MODE_APPEND) { flags |= O_APPEND; } else { flags |= O_TRUNC; if (mode & COSMS_CORE_FILE_MODE_CREATE) { flags |= O_CREAT; } } struct stat file_stat; if (stat(path, &file_stat) != 0) { return COSMS_CORE_FILE_COULD_NOT_READ_SIZE; } if (file_stat.st_size > COSMS_CORE_FILE_LARGE) { flags |= O_LARGEFILE; } file->native_file = open(path, flags); if (file->native_file == -1) { switch(errno) { case ENOENT: return COSMS_CORE_FILE_NOT_FOUND; case EACCES: return COSMS_CORE_FILE_NO_ACCESS; case EMFILE: case ENFILE: return COSMS_CORE_FILE_LIMIT_REACHED; default: return COSMS_CORE_FILE_UNKOWN_ERROR; } } #elif defined(_WIN32) DWORD access_flags = 0; DWORD create_flag = OPEN_EXISTING; if (mode & COSMS_CORE_FILE_MODE_READ) { access_flags |= GENERIC_READ; } if (mode & COSMS_CORE_FILE_MODE_WRITE) { access_flags |= GENERIC_WRITE; } if (mode & COSMS_CORE_FILE_MODE_APPEND) { create_flag = OPEN_ALWAYS; } else if (mode & COSMS_CORE_FILE_MODE_CREATE) { create_flag = CREATE_ALWAYS; } file->native_file = CreateFile(path, access_flags, 0, NULL, create_flag, FILE_ATTRIBUTE_NORMAL, NULL); if (file->native_file == INVALID_HANDLE_VALUE) { switch(GetLastError()) { case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: return COSMS_CORE_FILE_NOT_FOUND; case ERROR_ACCESS_DENIED: case ERROR_SHARING_VIOLATION: case ERROR_LOCK_VIOLATION: return COSMS_CORE_FILE_NO_ACCESS; case ERROR_TOO_MANY_OPEN_FILES: return COSMS_CORE_FILE_LIMIT_REACHED; default: return COSMS_CORE_FILE_UNKOWN_ERROR; } } #endif return COSMS_CORE_FILE_OK; } CosmsCoreFileError cosms_core_file_close(struct cosms_core_file *file) { #if defined(__GNUC__) int error = close(file->native_file); if (error == -1) { if (errno == EBADF) { return COSMS_CORE_FILE_INVALID_FILE; } return COSMS_CORE_FILE_UNKOWN_ERROR; } #elif defined(_WIN32) BOOL error = CloseHandle(file->native_file); if (error == 0) { if (GetLastError() == ERROR_INVALID_HANDLE) { return COSMS_CORE_FILE_INVALID_FILE; } return COSMS_CORE_FILE_UNKOWN_ERROR; } #endif return COSMS_CORE_FILE_OK; } CosmsCoreFileError cosms_core_file_get_size(struct cosms_core_file *file, unsigned long long *size) { #if defined(__GNUC__) struct stat file_stat; if (fstat(file->native_file, &file_stat) != 0) { if (errno == EBADF) { return COSMS_CORE_FILE_INVALID_FILE; } return COSMS_CORE_FILE_COULD_NOT_READ_SIZE; } (*size) = file_stat.st_size; #elif defined(_WIN32) DWORD high_size; DWORD low_size = GetFileSize(file->native_file, &high_size); if (low_size == INVALID_FILE_SIZE) { if (GetLastError() == ERROR_INVALID_HANDLE) { return COSMS_CORE_FILE_INVALID_FILE; } return COSMS_CORE_FILE_COULD_NOT_READ_SIZE; } (*size) = ((unsigned long long)high_size << 32) | low_size; #endif return COSMS_CORE_FILE_OK; } CosmsCoreFileError cosms_core_file_read(struct cosms_core_file *file, char *buffer, unsigned int bytes_to_read, unsigned int *bytes_read) { if ((file->mode & COSMS_CORE_FILE_MODE_READ) == 0) { return COSMS_CORE_FILE_INVALID_OPERATION; } #if defined(__GNUC__) int read_bytes = read(file->native_file, buffer, bytes_to_read); if (read_bytes == -1) { return COSMS_CORE_FILE_FAILED_TO_READ; } if (bytes_read != NULL) { (*bytes_read) = read_bytes; } #elif defined(_WIN32) if (ReadFile(file->native_file, buffer, bytes_to_read, (LPDWORD)bytes_read, NULL) == 0) { return COSMS_CORE_FILE_FAILED_TO_READ; } #endif buffer[bytes_to_read] = '\0'; return COSMS_CORE_FILE_OK; } CosmsCoreFileError cosms_core_file_read_all(struct cosms_core_file *file, char **buffer, unsigned long long *bytes_read) { if ((file->mode & COSMS_CORE_FILE_MODE_READ) == 0) { return COSMS_CORE_FILE_INVALID_OPERATION; } #if defined(__GNUC__) struct stat file_stat; if (fstat(file->native_file, &file_stat) != 0) { return COSMS_CORE_FILE_COULD_NOT_READ_SIZE; } if (bytes_read != NULL) { (*bytes_read) = file_stat.st_size; } (*buffer) = (char*)malloc((file_stat.st_size + 1) * sizeof(char)); if ((*buffer) == NULL) { return COSMS_CORE_FILE_FAILED_TO_ALLOCATE; } unsigned long long remaining_bytes = file_stat.st_size; while (remaining_bytes != 0) { unsigned int current_bytes_to_read; if (remaining_bytes > UINT_MAX) { current_bytes_to_read = UINT_MAX; } else { current_bytes_to_read = (unsigned int)remaining_bytes; } int read_bytes = read(file, (*buffer) + (file_stat.st_size - remaining_bytes), current_bytes_to_read); if (read_bytes == -1) { free(*buffer); return COSMS_CORE_FILE_FAILED_TO_READ; } remaining_bytes -= read_bytes; } (*buffer)[file_stat.st_size] = '\0'; #elif defined(_WIN32) DWORD high_size; DWORD low_size = GetFileSize(file->native_file, &high_size); if (low_size == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { return COSMS_CORE_FILE_COULD_NOT_READ_SIZE; } unsigned long long file_size = ((unsigned long long)high_size << 32) | low_size; if (bytes_read != NULL) { (*bytes_read) = file_size; } (*buffer) = (char*)malloc((file_size + 1) * sizeof(char)); if ((*buffer) == NULL) { return COSMS_CORE_FILE_FAILED_TO_ALLOCATE; } unsigned long long remaining_bytes = file_size; while (remaining_bytes != 0) { DWORD current_bytes_to_read, read_bytes; if (remaining_bytes > UINT_MAX) { current_bytes_to_read = UINT_MAX; } else { current_bytes_to_read = (DWORD)remaining_bytes; } if (ReadFile(file->native_file, (*buffer) + (file_size - remaining_bytes), current_bytes_to_read, &read_bytes, NULL) == 0) { free(*buffer); return COSMS_CORE_FILE_FAILED_TO_READ; } remaining_bytes -= read_bytes; } (*buffer)[file_size] = '\0'; #endif return COSMS_CORE_FILE_OK; } CosmsCoreFileError cosms_core_file_write(struct cosms_core_file *file, char *buffer, unsigned int bytes_to_write, unsigned int *bytes_written) { if ((file->mode & COSMS_CORE_FILE_MODE_WRITE) == 0) { return COSMS_CORE_FILE_INVALID_OPERATION; } #if defined(__GNUC__) int written_bytes = write(file->native_file, buffer, bytes_to_write); if (written_bytes == -1) { return COSMS_CORE_FILE_FAILED_TO_WRITE; } if (bytes_written != NULL) { (*bytes_written) = written_bytes; } #elif defined(_WIN32) if (file->mode & COSMS_CORE_FILE_MODE_APPEND) { SetFilePointer(file->native_file, 0, NULL, FILE_END); } if (WriteFile(file->native_file, buffer, bytes_to_write, (LPDWORD)bytes_written, NULL) == 0) { return COSMS_CORE_FILE_FAILED_TO_WRITE; } #endif return COSMS_CORE_FILE_OK; } CosmsCoreFileError cosms_core_file_write_all(struct cosms_core_file *file, char *buffer, unsigned long long bytes_to_write) { if ((file->mode & COSMS_CORE_FILE_MODE_WRITE) == 0) { return COSMS_CORE_FILE_INVALID_OPERATION; } #if defined(__GNUC__) unsigned long long remaining_bytes = bytes_to_write; while (remaining_bytes != 0) { unsigned int current_bytes_to_write; if (remaining_bytes > UINT_MAX) { current_bytes_to_write = UINT_MAX; } else { current_bytes_to_write = (unsigned int)remaining_bytes; } int written_bytes = write(file->native_file, content + (bytes_to_write - remaining_bytes), current_bytes_to_write); if (written_bytes == -1) { return COSMS_CORE_FILE_FAILED_TO_WRITE; } remaining_bytes -= written_bytes; } #elif defined(_WIN32) if (file->mode & COSMS_CORE_FILE_MODE_APPEND) { LARGE_INTEGER zero; zero.QuadPart = 0; SetFilePointerEx(file->native_file, zero, NULL, FILE_END); } unsigned long long remaining_bytes = bytes_to_write; while (remaining_bytes != 0) { DWORD current_bytes_to_write, written_bytes; if (remaining_bytes > UINT_MAX) { current_bytes_to_write = UINT_MAX; } else { current_bytes_to_write = (DWORD)remaining_bytes; } if (WriteFile(file->native_file, buffer + (bytes_to_write - remaining_bytes), current_bytes_to_write, &written_bytes, NULL) == 0) { return COSMS_CORE_FILE_FAILED_TO_WRITE; } remaining_bytes -= written_bytes; } #endif return COSMS_CORE_FILE_OK; } CosmsCoreFileError cosms_core_file_delete(const char *path) { #if defined(__GNUC__) if (unlink(path) == -1) { switch (errno) { case ENOENT: return COSMS_CORE_FILE_NOT_FOUND; case EACCES: return COSMS_CORE_FILE_NO_ACCESS; case EBUSY: return COSMS_CORE_FILE_STILL_OPEN; default: return COSMS_CORE_FILE_UNKOWN_ERROR; } } #elif defined(_WIN32) if (!DeleteFile(path)) { switch(GetLastError()) { case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: return COSMS_CORE_FILE_NOT_FOUND; case ERROR_ACCESS_DENIED: return COSMS_CORE_FILE_NO_ACCESS; case ERROR_LOCK_VIOLATION: case ERROR_SHARING_VIOLATION: return COSMS_CORE_FILE_STILL_OPEN; default: return COSMS_CORE_FILE_UNKOWN_ERROR; } } #endif return COSMS_CORE_FILE_OK; } const char *cosms_core_file_error_string(CosmsCoreFileError error) { switch(error) { case COSMS_CORE_FILE_OK: return "cosms-file everything ok"; case COSMS_CORE_FILE_NOT_FOUND: return "cosms-file path not found"; case COSMS_CORE_FILE_NO_ACCESS: return "cosms-file no access"; case COSMS_CORE_FILE_LIMIT_REACHED: return "cosms-file to many open files"; case COSMS_CORE_FILE_COULD_NOT_READ_SIZE: return "cosms-file failed to read size"; case COSMS_CORE_FILE_UNKOWN_ERROR: return "cosms-file unkown error occured"; case COSMS_CORE_FILE_FAILED_TO_ALLOCATE: return "cosms-file failed to allocate memory"; case COSMS_CORE_FILE_FAILED_TO_READ: return "cosms-file failed to read content of file"; case COSMS_CORE_FILE_FAILED_TO_WRITE: return "cosms-file failed to write content to file"; case COSMS_CORE_FILE_STILL_OPEN: return "cosms-file still open"; case COSMS_CORE_FILE_INVALID_FILE: return "cosms-file invalid native file given"; case COSMS_CORE_FILE_INVALID_OPERATION: return "cosms-file invalid operation for current file"; default: return NULL; } }