mame/src/osd/sdl/sdlfile.c

503 lines
12 KiB
C

//============================================================
//
// fileio.c - SDL file access functions
//
// Copyright (c) 1996-2010, Nicola Salmoria and the MAME Team.
// Visit http://mamedev.org for licensing and usage restrictions.
//
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
#endif
#ifdef SDLMAME_LINUX
#define __USE_LARGEFILE64
#endif
#ifndef SDLMAME_BSD
#ifdef _XOPEN_SOURCE
#undef _XOPEN_SOURCE
#endif
#define _XOPEN_SOURCE 500
#endif
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
// MAME headers
#include "sdlfile.h"
//============================================================
// GLOBAL IDENTIFIERS
//============================================================
extern const char *sdlfile_socket_identifier;
extern const char *sdlfile_ptty_identifier;
//============================================================
// CONSTANTS
//============================================================
#if defined(SDLMAME_WIN32) || defined(SDLMAME_OS2)
#define PATHSEPCH '\\'
#define INVPATHSEPCH '/'
#else
#define PATHSEPCH '/'
#define INVPATHSEPCH '\\'
#endif
#define NO_ERROR (0)
//============================================================
// Prototypes
//============================================================
static UINT32 create_path_recursive(char *path);
//============================================================
// error_to_file_error
// (does filling this out on non-Windows make any sense?)
//============================================================
file_error error_to_file_error(UINT32 error)
{
switch (error)
{
case ENOENT:
case ENOTDIR:
return FILERR_NOT_FOUND;
case EACCES:
case EROFS:
#ifndef SDLMAME_WIN32
case ETXTBSY:
#endif
case EEXIST:
case EPERM:
case EISDIR:
case EINVAL:
return FILERR_ACCESS_DENIED;
case ENFILE:
case EMFILE:
return FILERR_TOO_MANY_FILES;
default:
return FILERR_FAILURE;
}
}
//============================================================
// osd_open
//============================================================
file_error osd_open(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize)
{
UINT32 access;
const char *src;
char *dst;
#if defined(SDLMAME_DARWIN) || defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_OS2) || defined(SDLMAME_HAIKU)
struct stat st;
#else
struct stat64 st;
#endif
char *tmpstr, *envstr;
int i, j;
file_error filerr = FILERR_NONE;
tmpstr = NULL;
// allocate a file object, plus space for the converted filename
*file = (osd_file *) osd_malloc_array(sizeof(**file) + sizeof(char) * strlen(path));
if (*file == NULL)
{
filerr = FILERR_OUT_OF_MEMORY;
goto error;
}
if (sdl_check_socket_path(path))
{
(*file)->type = SDLFILE_SOCKET;
filerr = sdl_open_socket(path, openflags, file, filesize);
goto error;
}
if (strlen(sdlfile_ptty_identifier) > 0 && strncmp(path, sdlfile_ptty_identifier, strlen(sdlfile_ptty_identifier)) == 0)
{
(*file)->type = SDLFILE_PTTY;
filerr = sdl_open_ptty(path, openflags, file, filesize);
goto error;
}
(*file)->type = SDLFILE_FILE;
// convert the path into something compatible
dst = (*file)->filename;
for (src = path; *src != 0; src++)
*dst++ = (*src == INVPATHSEPCH) ? PATHSEPCH : *src;
*dst++ = 0;
// select the file open modes
if (openflags & OPEN_FLAG_WRITE)
{
access = (openflags & OPEN_FLAG_READ) ? O_RDWR : O_WRONLY;
access |= (openflags & OPEN_FLAG_CREATE) ? (O_CREAT | O_TRUNC) : 0;
}
else if (openflags & OPEN_FLAG_READ)
{
access = O_RDONLY;
}
else
{
filerr = FILERR_INVALID_ACCESS;
goto error;
}
tmpstr = (char *) osd_malloc_array(strlen((*file)->filename)+1);
strcpy(tmpstr, (*file)->filename);
// does path start with an environment variable?
if (tmpstr[0] == '$')
{
char *envval;
envstr = (char *) osd_malloc_array(strlen(tmpstr)+1);
strcpy(envstr, tmpstr);
i = 0;
while (envstr[i] != PATHSEPCH && envstr[i] != 0 && envstr[i] != '.')
{
i++;
}
envstr[i] = '\0';
envval = osd_getenv(&envstr[1]);
if (envval != NULL)
{
j = strlen(envval) + strlen(tmpstr) + 1;
osd_free(tmpstr);
tmpstr = (char *) osd_malloc_array(j);
// start with the value of $HOME
strcpy(tmpstr, envval);
// replace the null with a path separator again
envstr[i] = PATHSEPCH;
// append it
strcat(tmpstr, &envstr[i]);
}
else
fprintf(stderr, "Warning: osd_open environment variable %s not found.\n", envstr);
osd_free(envstr);
}
#if defined(SDLMAME_WIN32) || defined(SDLMAME_OS2)
access |= O_BINARY;
#endif
// attempt to open the file
#if defined(SDLMAME_DARWIN) || defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_OS2) || defined(SDLMAME_HAIKU)
(*file)->handle = open(tmpstr, access, 0666);
#else
(*file)->handle = open64(tmpstr, access, 0666);
#endif
if ((*file)->handle == -1)
{
// create the path if necessary
if ((openflags & OPEN_FLAG_CREATE) && (openflags & OPEN_FLAG_CREATE_PATHS))
{
char *pathsep = strrchr(tmpstr, PATHSEPCH);
if (pathsep != NULL)
{
int error;
// create the path up to the file
*pathsep = 0;
error = create_path_recursive(tmpstr);
*pathsep = PATHSEPCH;
// attempt to reopen the file
if (error == NO_ERROR)
{
#if defined(SDLMAME_DARWIN) || defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_OS2) || defined(SDLMAME_HAIKU)
(*file)->handle = open(tmpstr, access, 0666);
#else
(*file)->handle = open64(tmpstr, access, 0666);
#endif
}
}
}
// if we still failed, clean up and osd_free
if ((*file)->handle == -1)
{
osd_free(*file);
*file = NULL;
osd_free(tmpstr);
return error_to_file_error(errno);
}
}
// get the file size
#if defined(SDLMAME_DARWIN) || defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_BSD) || defined(SDLMAME_OS2) || defined(SDLMAME_HAIKU)
fstat((*file)->handle, &st);
#else
fstat64((*file)->handle, &st);
#endif
*filesize = (UINT64)st.st_size;
error:
// cleanup
if (filerr != FILERR_NONE && *file != NULL)
{
osd_free(*file);
*file = NULL;
}
if (tmpstr)
osd_free(tmpstr);
return filerr;
}
//============================================================
// osd_read
//============================================================
file_error osd_read(osd_file *file, void *buffer, UINT64 offset, UINT32 count, UINT32 *actual)
{
ssize_t result;
switch (file->type)
{
case SDLFILE_FILE:
#if defined(SDLMAME_DARWIN) || defined(SDLMAME_BSD) || defined(SDLMAME_EMSCRIPTEN)
result = pread(file->handle, buffer, count, offset);
if (result < 0)
#elif defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_OS2)
lseek(file->handle, (UINT32)offset&0xffffffff, SEEK_SET);
result = read(file->handle, buffer, count);
if (result < 0)
#elif defined(SDLMAME_UNIX)
result = pread64(file->handle, buffer, count, offset);
if (result < 0)
#else
#error Unknown SDL SUBARCH!
#endif
return error_to_file_error(errno);
if (actual != NULL)
*actual = result;
return FILERR_NONE;
break;
case SDLFILE_SOCKET:
return sdl_read_socket(file, buffer, offset, count, actual);
break;
case SDLFILE_PTTY:
return sdl_read_ptty(file, buffer, offset, count, actual);
break;
default:
return FILERR_FAILURE;
}
}
//============================================================
// osd_write
//============================================================
file_error osd_write(osd_file *file, const void *buffer, UINT64 offset, UINT32 count, UINT32 *actual)
{
UINT32 result;
switch (file->type)
{
case SDLFILE_FILE:
#if defined(SDLMAME_DARWIN) || defined(SDLMAME_BSD) || defined(SDLMAME_EMSCRIPTEN)
result = pwrite(file->handle, buffer, count, offset);
if (!result)
#elif defined(SDLMAME_WIN32) || defined(SDLMAME_NO64BITIO) || defined(SDLMAME_OS2)
lseek(file->handle, (UINT32)offset&0xffffffff, SEEK_SET);
result = write(file->handle, buffer, count);
if (!result)
#elif defined(SDLMAME_UNIX)
result = pwrite64(file->handle, buffer, count, offset);
if (!result)
#else
#error Unknown SDL SUBARCH!
#endif
return error_to_file_error(errno);
if (actual != NULL)
*actual = result;
return FILERR_NONE;
break;
case SDLFILE_SOCKET:
return sdl_write_socket(file, buffer, offset, count, actual);
break;
case SDLFILE_PTTY:
return sdl_write_ptty(file, buffer, offset, count, actual);
break;
default:
return FILERR_FAILURE;
}
}
//============================================================
// osd_truncate
//============================================================
file_error osd_truncate(osd_file *file, UINT64 offset)
{
UINT32 result;
switch (file->type)
{
case SDLFILE_FILE:
result = ftruncate(file->handle, offset);
if (!result)
return error_to_file_error(errno);
return FILERR_NONE;
break;
default:
return FILERR_FAILURE;
}
}
//============================================================
// osd_close
//============================================================
file_error osd_close(osd_file *file)
{
// close the file handle and free the file structure
switch (file->type)
{
case SDLFILE_FILE:
close(file->handle);
osd_free(file);
return FILERR_NONE;
break;
case SDLFILE_SOCKET:
return sdl_close_socket(file);
break;
case SDLFILE_PTTY:
return sdl_close_ptty(file);
break;
default:
return FILERR_FAILURE;
}
}
//============================================================
// osd_rmfile
//============================================================
file_error osd_rmfile(const char *filename)
{
if (unlink(filename) == -1)
{
return error_to_file_error(errno);
}
return FILERR_NONE;
}
//============================================================
// create_path_recursive
//============================================================
static UINT32 create_path_recursive(char *path)
{
char *sep = strrchr(path, PATHSEPCH);
UINT32 filerr;
struct stat st;
// if there's still a separator, and it's not the root, nuke it and recurse
if (sep != NULL && sep > path && sep[0] != ':' && sep[-1] != PATHSEPCH)
{
*sep = 0;
filerr = create_path_recursive(path);
*sep = PATHSEPCH;
if (filerr != NO_ERROR)
return filerr;
}
// if the path already exists, we're done
if (!stat(path, &st))
return NO_ERROR;
// create the path
#ifdef SDLMAME_WIN32
if (mkdir(path) != 0)
#else
if (mkdir(path, 0777) != 0)
#endif
return error_to_file_error(errno);
return NO_ERROR;
}
//============================================================
// osd_get_physical_drive_geometry
//============================================================
int osd_get_physical_drive_geometry(const char *filename, UINT32 *cylinders, UINT32 *heads, UINT32 *sectors, UINT32 *bps)
{
return FALSE; // no, no way, huh-uh, forget it
}
//============================================================
// osd_is_path_separator
//============================================================
static int osd_is_path_separator(char c)
{
return (c == '/') || (c == '\\');
}
//============================================================
// osd_is_absolute_path
//============================================================
int osd_is_absolute_path(const char *path)
{
int result;
if (osd_is_path_separator(path[0]))
result = TRUE;
#if !defined(SDLMAME_WIN32) && !defined(SDLMAME_OS2)
else if (path[0] == '.')
result = TRUE;
#else
#ifndef UNDER_CE
else if (*path && path[1] == ':')
result = TRUE;
#endif
#endif
else
result = FALSE;
return result;
}