This commit is contained in:
251
posix/File.c
Normal file
251
posix/File.c
Normal file
@@ -0,0 +1,251 @@
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include "../CgeFile.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const int64_t off_t_max =
|
||||
(sizeof(off_t) == 8) ? INT64_MAX :
|
||||
(sizeof(off_t) == 4) ? INT32_MAX : 0;
|
||||
|
||||
static const int64_t off_t_min =
|
||||
(sizeof(off_t) == 8) ? INT64_MIN :
|
||||
(sizeof(off_t) == 4) ? INT32_MIN : 0;
|
||||
|
||||
struct CgeFile {
|
||||
int flags;
|
||||
int handle;
|
||||
int lastError;
|
||||
};
|
||||
|
||||
static int errnoToFileCode(int err) {
|
||||
switch (err) {
|
||||
case 0:
|
||||
return CGE_FILE_EOK;
|
||||
|
||||
case ENOMEM:
|
||||
return CGE_FILE_EOOM;
|
||||
|
||||
case ENOSPC:
|
||||
return CGE_FILE_ENOSPC;
|
||||
|
||||
case EINVAL:
|
||||
return CGE_FILE_EINVAL;
|
||||
|
||||
case ENOENT:
|
||||
return CGE_FILE_ENOENT;
|
||||
|
||||
case EACCES:
|
||||
case EPERM:
|
||||
return CGE_FILE_EACCES;
|
||||
|
||||
case EROFS:
|
||||
return CGE_FILE_EROFS;
|
||||
|
||||
case EEXIST:
|
||||
return CGE_FILE_EEXIST;
|
||||
|
||||
case EISDIR:
|
||||
return CGE_FILE_EISDIR;
|
||||
|
||||
case EMFILE:
|
||||
case ENFILE:
|
||||
return CGE_FILE_EMFILE;
|
||||
|
||||
case ENAMETOOLONG:
|
||||
return CGE_FILE_ENAMETOOLONG;
|
||||
|
||||
default:
|
||||
return CGE_FILE_EUNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static int fileOpenFlags(int mode) {
|
||||
int flags = 0;
|
||||
|
||||
if ((mode & CGE_FILE_READWRITE) == CGE_FILE_READWRITE)
|
||||
flags |= O_RDWR;
|
||||
else if (mode & CGE_FILE_WRITE)
|
||||
flags |= O_WRONLY;
|
||||
else if (mode & CGE_FILE_READ)
|
||||
flags |= O_RDONLY;
|
||||
else
|
||||
return -1;
|
||||
|
||||
if (!(mode & CGE_FILE_EXIST))
|
||||
{
|
||||
flags |= O_CREAT;
|
||||
if (mode & CGE_FILE_CREATE)
|
||||
flags |= O_EXCL;
|
||||
}
|
||||
|
||||
if (mode & CGE_FILE_APPEND)
|
||||
flags |= O_APPEND;
|
||||
|
||||
if (mode & CGE_FILE_TRUNCATE)
|
||||
flags |= O_TRUNC;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int fileInit(CgeFile *file, const char *path, int mode) {
|
||||
static const mode_t openMode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
int flags;
|
||||
|
||||
if (!path)
|
||||
return CGE_FILE_EINVAL;
|
||||
|
||||
flags = fileOpenFlags(mode);
|
||||
if (flags == -1)
|
||||
return CGE_FILE_EINVAL;
|
||||
|
||||
file->flags = 0;
|
||||
file->handle = open(path, flags, openMode);
|
||||
if (file->handle == -1)
|
||||
return errnoToFileCode(errno);
|
||||
|
||||
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) {
|
||||
close(file->handle);
|
||||
free(file);
|
||||
}
|
||||
|
||||
int CgeFileRead(CgeFile *file, char *buffer, size_t size, size_t *actual) {
|
||||
ssize_t readed;
|
||||
|
||||
if (file->flags & CGE_FILE_ERROR)
|
||||
return 0;
|
||||
|
||||
readed = read(file->handle, buffer, size);
|
||||
if (readed < 0)
|
||||
goto error;
|
||||
|
||||
if (readed > 0) 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 = errnoToFileCode(errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CgeFileWrite(CgeFile *file, const char *buffer, size_t size,
|
||||
size_t *actual) {
|
||||
ssize_t written;
|
||||
|
||||
if (file->flags & CGE_FILE_ERROR)
|
||||
return 0;
|
||||
|
||||
written = write(file->handle, buffer, size);
|
||||
if (written < 0)
|
||||
goto error;
|
||||
|
||||
if (actual) *actual = written;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
file->flags |= CGE_FILE_ERROR;
|
||||
file->lastError = errnoToFileCode(errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CgeFileTell(CgeFile *file, int64_t *offset) {
|
||||
if (file->flags & CGE_FILE_ERROR)
|
||||
return 0;
|
||||
|
||||
if ((*offset = lseek(file->handle, 0, SEEK_CUR)) == -1)
|
||||
goto error;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
file->flags |= CGE_FILE_ERROR;
|
||||
file->lastError = errnoToFileCode(errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CgeFileSeek(CgeFile *file, int64_t offset, int whence) {
|
||||
if (file->flags & CGE_FILE_ERROR)
|
||||
return 0;
|
||||
|
||||
if (offset < off_t_min || offset > off_t_max) {
|
||||
file->flags |= CGE_FILE_ERROR;
|
||||
file->lastError = CGE_FILE_EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lseek(file->handle, offset, whence) == -1)
|
||||
goto error;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
file->flags |= CGE_FILE_ERROR;
|
||||
file->lastError = errnoToFileCode(errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CgeFileFlush(CgeFile *file) {
|
||||
if (fsync(file->handle))
|
||||
goto error;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
file->flags |= CGE_FILE_ERROR;
|
||||
file->lastError = errnoToFileCode(errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CgeFileSize(CgeFile *file, int64_t *size) {
|
||||
struct stat sb;
|
||||
|
||||
if (fstat(file->handle, &sb))
|
||||
goto error;
|
||||
|
||||
*size = sb.st_size;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
file->flags |= CGE_FILE_ERROR;
|
||||
file->lastError = errnoToFileCode(errno);
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user