uae-wii/src/od-wii/fsdb_wii.c

226 lines
5.9 KiB
C

/*
* UAE - The Un*x Amiga Emulator
*
* Library of functions to make emulated filesystem as independent as
* possible of the host filesystem's capabilities.
* This is the Win32 version.
*
* Copyright 1997 Mathias Ortmann
* Copyright 1999 Bernd Schmidt
*/
#ifdef FILESYS
#include "sysconfig.h"
#include "sysdeps.h"
#include "fsdb.h"
#include <fat.h>
#define TRACING_ENABLED 0
#if TRACING_ENABLED
#define TRACE(x) do { write_log x; } while(0)
#else
#define TRACE(x)
#endif
/* these are deadly (but I think allowed on the Amiga): */
#define NUM_EVILCHARS 7
static const char evilchars[NUM_EVILCHARS] = { '\\', '*', '?', '\"', '<', '>', '|' };
/* Return nonzero for any name we can't create on the native filesystem. */
int fsdb_name_invalid (const char *n)
{
int i;
char a = n[0];
char b = (a == '\0' ? a : n[1]);
char c = (b == '\0' ? b : n[2]);
char d = (c == '\0' ? c : n[3]);
int l = strlen (n), ll;
if (a >= 'a' && a <= 'z')
a -= 32;
if (b >= 'a' && b <= 'z')
b -= 32;
if (c >= 'a' && c <= 'z')
c -= 32;
/* reserved dos devices */
ll = 0;
if (a == 'A' && b == 'U' && c == 'X') ll = 3; /* AUX */
if (a == 'C' && b == 'O' && c == 'N') ll = 3; /* CON */
if (a == 'P' && b == 'R' && c == 'N') ll = 3; /* PRN */
if (a == 'N' && b == 'U' && c == 'L') ll = 3; /* NUL */
if (a == 'L' && b == 'P' && c == 'T' && (d >= '0' && d <= '9')) ll = 4; /* LPT# */
if (a == 'C' && b == 'O' && c == 'M' && (d >= '0' && d <= '9')) ll = 4; /* COM# */
/* AUX.anything, CON.anything etc.. are also illegal names */
if (ll && (l == ll || (l > ll && n[ll] == '.')))
return 1;
/* spaces and periods at the end are a no-no */
i = l - 1;
if (n[i] == '.' || n[i] == ' ')
return 1;
/* these characters are *never* allowed */
for (i = 0; i < NUM_EVILCHARS; i++) {
if (strchr (n, evilchars[i]) != 0)
return 1;
}
/* the reserved fsdb filename */
if (strcmp (n, FSDB_FILE) == 0)
return 1;
return 0; /* the filename passed all checks, now it should be ok */
}
static uae_u32 filesys_parse_mask (uae_u32 mask)
{
return mask ^ 0xf;
}
int fsdb_exists (char *nname)
{
struct stat statbuf;
return (stat (nname, &statbuf) != -1);
}
/* For an a_inode we have newly created based on a filename we found on the
* native fs, fill in information about this file/directory. */
int fsdb_fill_file_attrs (a_inode *base, a_inode *aino)
{
int mode;
if ((mode = FAT_getAttr (aino->nname)) <0) {
write_log ("FAT_getAttr('%s') failed! error=%d, aino=%p dir=%d\n", aino->nname,errno,aino,aino->dir);
return 0;
}
aino->dir = (mode & ATTR_DIRECTORY) ? 1 : 0;
aino->amigaos_mode = A_FIBF_EXECUTE | A_FIBF_READ;
if (ATTR_ARCHIVE & mode)
aino->amigaos_mode |= A_FIBF_ARCHIVE;
if (! (ATTR_READONLY & mode))
aino->amigaos_mode |= A_FIBF_WRITE | A_FIBF_DELETE;
aino->amigaos_mode = filesys_parse_mask (aino->amigaos_mode);
return 1;
}
int fsdb_set_file_attrs (a_inode *aino)
{
struct stat statbuf;
int mode=0, tmpmask;
tmpmask = filesys_parse_mask (aino->amigaos_mode);
if (stat (aino->nname, &statbuf) == -1)
return ERROR_OBJECT_NOT_AROUND;
/* Unix dirs behave differently than AmigaOS ones. */
/* windows dirs go where no dir has gone before... */
if (! aino->dir) {
if ((tmpmask & (A_FIBF_WRITE | A_FIBF_DELETE)) == 0)
mode |= ATTR_READONLY;
if (tmpmask & A_FIBF_ARCHIVE)
mode |= ATTR_ARCHIVE;
//else
//mode &= ~ATTR_ARCHIVE;
FAT_setAttr(aino->nname, mode);
}
aino->dirty = 1;
return 0;
}
/* Return nonzero if we can represent the amigaos_mode of AINO within the
* native FS. Return zero if that is not possible. */
int fsdb_mode_representable_p (const a_inode *aino)
{
int mask = aino->amigaos_mode;
int m1;
if (aino->dir)
return aino->amigaos_mode == 0;
/* P or S set, or E or R clear, means we can't handle it. */
if (mask & (A_FIBF_SCRIPT | A_FIBF_PURE | A_FIBF_EXECUTE | A_FIBF_READ))
return 0;
m1 = A_FIBF_DELETE | A_FIBF_WRITE;
/* If it's rwed, we are OK... */
if ((mask & m1) == 0) //Both delete and write protected
return 1;
/* We can also represent r-e-, by setting the host's readonly flag. */
if ((mask & m1) == m1) //Neither delete nor write protected
return 1;
return 0;
}
char *fsdb_create_unique_nname (a_inode *base, const char *suggestion)
{
char *c;
char tmp[256] = "__uae___";
int i;
strncat (tmp, suggestion, 240);
/* replace the evil ones... */
for (i=0; i < NUM_EVILCHARS; i++)
while ((c = strchr (tmp, evilchars[i])) != 0)
*c = '_';
while ((c = strchr (tmp, '.')) != 0)
*c = '_';
while ((c = strchr (tmp, ' ')) != 0)
*c = '_';
for (;;) {
char *p = build_nname (base->nname, tmp);
struct stat st;
if (stat(p, &st) < 0) {
write_log ("unique name: %s\n", p);
return p;
}
free (p);
/* tmpnam isn't reentrant and I don't really want to hack configure
* right now to see whether tmpnam_r is available... */
for (i = 0; i < 8; i++) {
tmp[i+8] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[rand () % 63];
}
}
}
int dos_errno (void)
{
int e = errno;
switch (e) {
case ENOMEM: return ERROR_NO_FREE_STORE;
case EEXIST: return ERROR_OBJECT_EXISTS;
case EACCES: return ERROR_WRITE_PROTECTED;
case ENOENT: return ERROR_OBJECT_NOT_AROUND;
case ENOTDIR: return ERROR_OBJECT_WRONG_TYPE;
case ENOSPC: return ERROR_DISK_IS_FULL;
case EBUSY: return ERROR_OBJECT_IN_USE;
case EISDIR: return ERROR_OBJECT_WRONG_TYPE;
#if defined(ETXTBSY)
case ETXTBSY: return ERROR_OBJECT_IN_USE;
#endif
#if defined(EROFS)
case EROFS: return ERROR_DISK_WRITE_PROTECTED;
#endif
#if defined(ENOTEMPTY)
#if ENOTEMPTY != EEXIST
case ENOTEMPTY: return ERROR_DIRECTORY_NOT_EMPTY;
#endif
#endif
default:
TRACE (("FSDB: Unimplemented error: %s\n", strerror (e)));
return ERROR_NOT_IMPLEMENTED;
}
}
#endif