2002-05-13 15:23:30 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright (C) 2002 Daniel Stenberg
|
|
|
|
*
|
2008-06-28 18:10:04 +00:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2002-05-13 15:23:30 +00:00
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
2002-04-30 13:14:59 +00:00
|
|
|
|
2002-06-14 11:00:13 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2005-02-22 12:19:12 +00:00
|
|
|
#include <stdarg.h>
|
2002-05-07 12:06:32 +00:00
|
|
|
#include <sys/stat.h>
|
2007-04-06 23:54:21 +00:00
|
|
|
#include <time.h>
|
2011-06-10 16:29:55 +00:00
|
|
|
#include <errno.h>
|
2010-08-02 20:34:47 +00:00
|
|
|
#include "config.h"
|
2014-02-22 22:17:16 +00:00
|
|
|
#include "system.h"
|
2012-07-18 10:54:34 +00:00
|
|
|
#include "ata_idle_notify.h"
|
2014-02-22 22:17:16 +00:00
|
|
|
#include "mv.h"
|
2010-08-02 20:34:47 +00:00
|
|
|
|
2010-09-08 20:39:55 +00:00
|
|
|
#define HAVE_STATVFS (!defined(WIN32))
|
2010-12-23 19:02:18 +00:00
|
|
|
#define HAVE_LSTAT (!defined(WIN32))
|
2010-08-02 20:34:47 +00:00
|
|
|
|
|
|
|
#if HAVE_STATVFS
|
2010-03-20 12:45:54 +00:00
|
|
|
#include <sys/statvfs.h>
|
2003-07-04 08:30:01 +00:00
|
|
|
#endif
|
2004-06-14 07:00:50 +00:00
|
|
|
|
2005-02-22 12:19:12 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
|
2004-06-14 07:00:50 +00:00
|
|
|
#ifndef _MSC_VER
|
2002-05-07 12:25:30 +00:00
|
|
|
#include <dirent.h>
|
2003-01-28 23:14:41 +00:00
|
|
|
#include <unistd.h>
|
2004-06-14 07:00:50 +00:00
|
|
|
#else
|
|
|
|
#include "dir-win32.h"
|
|
|
|
#endif
|
2002-04-30 13:14:59 +00:00
|
|
|
|
2002-06-14 11:00:13 +00:00
|
|
|
#include <fcntl.h>
|
2011-02-18 22:46:01 +00:00
|
|
|
#ifdef HAVE_SDL_THREADS
|
2010-08-02 20:34:47 +00:00
|
|
|
#include "thread-sdl.h"
|
2011-02-18 22:46:01 +00:00
|
|
|
#else
|
|
|
|
#define sim_thread_unlock() NULL
|
|
|
|
#define sim_thread_lock(a)
|
|
|
|
#endif
|
2007-09-08 12:20:53 +00:00
|
|
|
#include "thread.h"
|
|
|
|
#include "kernel.h"
|
2002-06-14 11:00:13 +00:00
|
|
|
#include "debug.h"
|
2013-08-17 16:18:22 +00:00
|
|
|
#include "ata.h" /* for IF_MV et al. */
|
2010-08-01 16:15:27 +00:00
|
|
|
#include "rbpaths.h"
|
2010-08-27 00:29:50 +00:00
|
|
|
#include "load_code.h"
|
2007-12-03 14:01:12 +00:00
|
|
|
|
2010-08-01 16:15:27 +00:00
|
|
|
/* keep this in sync with file.h! */
|
|
|
|
#undef MAX_PATH /* this avoids problems when building simulator */
|
|
|
|
#define MAX_PATH 260
|
|
|
|
#define MAX_OPEN_FILES 11
|
2006-08-26 14:19:18 +00:00
|
|
|
|
2007-02-01 23:08:15 +00:00
|
|
|
/* Windows (and potentially other OSes) distinguish binary and text files.
|
|
|
|
* Define a dummy for the others. */
|
|
|
|
#ifndef O_BINARY
|
|
|
|
#define O_BINARY 0
|
|
|
|
#endif
|
|
|
|
|
2007-04-19 20:17:24 +00:00
|
|
|
/* Unicode compatibility for win32 */
|
|
|
|
#if defined __MINGW32__
|
|
|
|
/* Rockbox unicode functions */
|
|
|
|
extern const unsigned char* utf8decode(const unsigned char *utf8,
|
|
|
|
unsigned short *ucs);
|
|
|
|
extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
|
|
|
|
|
2007-04-20 17:35:05 +00:00
|
|
|
/* Static buffers for the conversion results. This isn't thread safe,
|
|
|
|
* but it's sufficient for rockbox. */
|
|
|
|
static unsigned char convbuf1[3*MAX_PATH];
|
|
|
|
static unsigned char convbuf2[3*MAX_PATH];
|
|
|
|
|
|
|
|
static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
|
2007-04-19 20:17:24 +00:00
|
|
|
{
|
2007-04-20 17:35:05 +00:00
|
|
|
wchar_t *ucs = buffer;
|
2007-04-19 20:17:24 +00:00
|
|
|
|
|
|
|
while (*utf8)
|
|
|
|
utf8 = utf8decode(utf8, ucs++);
|
2007-11-08 12:11:34 +00:00
|
|
|
|
2007-04-19 20:17:24 +00:00
|
|
|
*ucs = 0;
|
2007-04-20 17:35:05 +00:00
|
|
|
return buffer;
|
2007-04-19 20:17:24 +00:00
|
|
|
}
|
2007-04-20 17:35:05 +00:00
|
|
|
static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
|
2007-04-19 20:17:24 +00:00
|
|
|
{
|
|
|
|
unsigned char *utf8 = buffer;
|
2007-04-20 17:35:05 +00:00
|
|
|
|
2007-04-19 20:17:24 +00:00
|
|
|
while (*ucs)
|
|
|
|
utf8 = utf8encode(*ucs++, utf8);
|
2007-11-08 12:11:34 +00:00
|
|
|
|
2007-04-19 20:17:24 +00:00
|
|
|
*utf8 = 0;
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2007-04-20 17:35:05 +00:00
|
|
|
#define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
|
|
|
|
#define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
|
2007-04-19 20:17:24 +00:00
|
|
|
#define DIR_T _WDIR
|
|
|
|
#define DIRENT_T struct _wdirent
|
|
|
|
#define STAT_T struct _stat
|
|
|
|
extern int _wmkdir(const wchar_t*);
|
|
|
|
extern int _wrmdir(const wchar_t*);
|
|
|
|
#define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
|
|
|
|
#define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
|
|
|
|
#define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
|
|
|
|
#define READDIR(a) (_wreaddir)(a)
|
|
|
|
#define CLOSEDIR(a) (_wclosedir)(a)
|
|
|
|
#define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
|
2010-05-06 17:35:13 +00:00
|
|
|
/* empty variable parameter list doesn't work for variadic macros,
|
|
|
|
* so pretend the second parameter is variable too */
|
|
|
|
#define OPEN(a,...) (_wopen)(UTF8_TO_OS(a), __VA_ARGS__)
|
2007-10-09 17:51:02 +00:00
|
|
|
#define CLOSE(a) (close)(a)
|
2007-04-19 20:17:24 +00:00
|
|
|
#define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
|
2007-04-20 17:35:05 +00:00
|
|
|
#define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
|
2014-02-22 22:17:16 +00:00
|
|
|
/* readlink isn't used in the sim yet (FIXME) */
|
|
|
|
#define READLINK(a,b,c) ({ fprintf(stderr, "no readlink on windows yet"); abort(); })
|
2007-04-19 20:17:24 +00:00
|
|
|
#else /* !__MINGW32__ */
|
|
|
|
|
|
|
|
#define UTF8_TO_OS(a) (a)
|
|
|
|
#define OS_TO_UTF8(a) (a)
|
|
|
|
#define DIR_T DIR
|
|
|
|
#define DIRENT_T struct dirent
|
|
|
|
#define STAT_T struct stat
|
|
|
|
#define MKDIR(a,b) (mkdir)(a,b)
|
|
|
|
#define RMDIR(a) (rmdir)(a)
|
|
|
|
#define OPENDIR(a) (opendir)(a)
|
|
|
|
#define READDIR(a) (readdir)(a)
|
|
|
|
#define CLOSEDIR(a) (closedir)(a)
|
|
|
|
#define STAT(a,b) (stat)(a,b)
|
2010-05-06 17:35:13 +00:00
|
|
|
/* empty variable parameter list doesn't work for variadic macros,
|
|
|
|
* so pretend the second parameter is variable too */
|
|
|
|
#define OPEN(a, ...) (open)(a, __VA_ARGS__)
|
2007-10-09 15:15:00 +00:00
|
|
|
#define CLOSE(x) (close)(x)
|
2007-04-19 20:17:24 +00:00
|
|
|
#define REMOVE(a) (remove)(a)
|
|
|
|
#define RENAME(a,b) (rename)(a,b)
|
2014-02-22 22:17:16 +00:00
|
|
|
#define READLINK(a,b,c) (readlink)(a,b,c)
|
2007-04-19 20:17:24 +00:00
|
|
|
|
|
|
|
#endif /* !__MINGW32__ */
|
|
|
|
|
|
|
|
|
2006-08-26 14:19:18 +00:00
|
|
|
#ifdef HAVE_DIRCACHE
|
2011-06-20 20:12:42 +00:00
|
|
|
int dircache_get_entry_id(const char *filename);
|
2011-04-15 21:45:36 +00:00
|
|
|
void dircache_add_file(const char *name, long startcluster);
|
2006-08-26 14:19:18 +00:00
|
|
|
void dircache_remove(const char *name);
|
2009-02-27 21:25:17 +00:00
|
|
|
void dircache_rename(const char *oldname, const char *newname);
|
2006-08-26 14:19:18 +00:00
|
|
|
#endif
|
2002-06-14 11:00:13 +00:00
|
|
|
|
2014-02-11 14:27:23 +00:00
|
|
|
#ifndef APPLICATION
|
2007-11-08 10:15:44 +00:00
|
|
|
|
2008-11-24 20:32:57 +00:00
|
|
|
#define SIMULATOR_DEFAULT_ROOT "simdisk"
|
2007-11-08 10:15:44 +00:00
|
|
|
extern const char *sim_root_dir;
|
2002-05-07 12:25:30 +00:00
|
|
|
|
2007-10-09 15:15:00 +00:00
|
|
|
static int num_openfiles = 0;
|
|
|
|
|
2010-09-01 21:29:34 +00:00
|
|
|
/* from dir.h */
|
|
|
|
struct dirinfo {
|
2005-02-22 12:19:12 +00:00
|
|
|
int attribute;
|
2007-04-07 00:14:16 +00:00
|
|
|
long size;
|
2010-09-01 21:29:34 +00:00
|
|
|
unsigned short wrtdate;
|
|
|
|
unsigned short wrttime;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sim_dirent {
|
|
|
|
unsigned char d_name[MAX_PATH];
|
|
|
|
struct dirinfo info;
|
2007-04-07 00:14:16 +00:00
|
|
|
long startcluster;
|
2005-02-22 12:19:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct dirstruct {
|
|
|
|
void *dir; /* actually a DIR* dir */
|
2007-11-08 12:11:34 +00:00
|
|
|
char *name;
|
2005-02-22 12:19:12 +00:00
|
|
|
} SIM_DIR;
|
|
|
|
|
2002-05-07 12:25:30 +00:00
|
|
|
struct mydir {
|
2007-04-19 20:17:24 +00:00
|
|
|
DIR_T *dir;
|
2014-02-22 22:17:16 +00:00
|
|
|
IF_MV(int volumes_returned);
|
2003-03-05 22:59:36 +00:00
|
|
|
char *name;
|
2002-05-07 12:25:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct mydir MYDIR;
|
2002-04-30 13:14:59 +00:00
|
|
|
|
2004-06-14 22:22:49 +00:00
|
|
|
static unsigned int rockbox2sim(int opt)
|
|
|
|
{
|
2010-08-27 12:38:25 +00:00
|
|
|
#if 0
|
|
|
|
/* this shouldn't be needed since we use the host's versions */
|
2006-02-03 15:19:58 +00:00
|
|
|
int newopt = O_BINARY;
|
2007-02-01 23:08:15 +00:00
|
|
|
|
2004-06-14 22:22:49 +00:00
|
|
|
if(opt & 1)
|
|
|
|
newopt |= O_WRONLY;
|
|
|
|
if(opt & 2)
|
|
|
|
newopt |= O_RDWR;
|
|
|
|
if(opt & 4)
|
|
|
|
newopt |= O_CREAT;
|
|
|
|
if(opt & 8)
|
|
|
|
newopt |= O_APPEND;
|
|
|
|
if(opt & 0x10)
|
|
|
|
newopt |= O_TRUNC;
|
|
|
|
|
|
|
|
return newopt;
|
2010-08-27 12:38:25 +00:00
|
|
|
#else
|
|
|
|
return opt|O_BINARY;
|
2004-07-08 05:50:20 +00:00
|
|
|
#endif
|
2010-08-27 12:38:25 +00:00
|
|
|
}
|
2004-06-14 22:22:49 +00:00
|
|
|
|
2014-02-11 14:27:23 +00:00
|
|
|
#endif /* APPLICATION */
|
|
|
|
|
2007-09-08 12:20:53 +00:00
|
|
|
/** Simulator I/O engine routines **/
|
2007-12-03 15:33:12 +00:00
|
|
|
#define IO_YIELD_THRESHOLD 512
|
|
|
|
|
2010-08-02 20:34:47 +00:00
|
|
|
enum io_dir
|
2007-09-08 12:20:53 +00:00
|
|
|
{
|
|
|
|
IO_READ,
|
|
|
|
IO_WRITE,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sim_io
|
|
|
|
{
|
|
|
|
struct mutex sim_mutex; /* Rockbox mutex */
|
2007-12-03 15:33:12 +00:00
|
|
|
int cmd; /* The command to perform */
|
|
|
|
int ready; /* I/O ready flag - 1= ready */
|
|
|
|
int fd; /* The file to read/write */
|
|
|
|
void *buf; /* The buffer to read/write */
|
|
|
|
size_t count; /* Number of bytes to read/write */
|
|
|
|
size_t accum; /* Acculated bytes transferred */
|
2007-09-08 12:20:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct sim_io io;
|
|
|
|
|
2007-09-10 03:49:12 +00:00
|
|
|
int ata_init(void)
|
|
|
|
{
|
|
|
|
/* Initialize the rockbox kernel objects on a rockbox thread */
|
|
|
|
mutex_init(&io.sim_mutex);
|
2007-12-03 15:33:12 +00:00
|
|
|
io.accum = 0;
|
2007-09-10 03:49:12 +00:00
|
|
|
return 1;
|
2007-09-08 12:20:53 +00:00
|
|
|
}
|
|
|
|
|
2009-01-10 21:38:56 +00:00
|
|
|
int ata_spinup_time(void)
|
|
|
|
{
|
|
|
|
return HZ;
|
|
|
|
}
|
|
|
|
|
2010-08-02 20:34:47 +00:00
|
|
|
static ssize_t io_trigger_and_wait(enum io_dir cmd)
|
2007-09-08 12:20:53 +00:00
|
|
|
{
|
2007-12-03 15:33:12 +00:00
|
|
|
void *mythread = NULL;
|
2007-12-03 14:01:12 +00:00
|
|
|
ssize_t result;
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2007-12-03 15:33:12 +00:00
|
|
|
if (io.count > IO_YIELD_THRESHOLD ||
|
|
|
|
(io.accum += io.count) >= IO_YIELD_THRESHOLD)
|
|
|
|
{
|
|
|
|
/* Allow other rockbox threads to run */
|
|
|
|
io.accum = 0;
|
2010-05-15 21:02:47 +00:00
|
|
|
mythread = sim_thread_unlock();
|
2007-12-03 15:33:12 +00:00
|
|
|
}
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2007-12-03 14:01:12 +00:00
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case IO_READ:
|
|
|
|
result = read(io.fd, io.buf, io.count);
|
|
|
|
break;
|
|
|
|
case IO_WRITE:
|
|
|
|
result = write(io.fd, io.buf, io.count);
|
|
|
|
break;
|
2010-08-02 20:34:47 +00:00
|
|
|
/* shut up gcc */
|
|
|
|
default:
|
|
|
|
result = -1;
|
2007-12-03 14:01:12 +00:00
|
|
|
}
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2012-07-18 08:34:18 +00:00
|
|
|
call_storage_idle_notifys(false);
|
|
|
|
|
2007-12-03 14:01:12 +00:00
|
|
|
/* Regain our status as current */
|
2007-12-03 15:33:12 +00:00
|
|
|
if (mythread != NULL)
|
|
|
|
{
|
2010-05-15 21:02:47 +00:00
|
|
|
sim_thread_lock(mythread);
|
2007-12-03 15:33:12 +00:00
|
|
|
}
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2007-12-03 14:01:12 +00:00
|
|
|
return result;
|
2007-09-08 12:20:53 +00:00
|
|
|
}
|
|
|
|
|
2014-02-11 14:27:23 +00:00
|
|
|
|
|
|
|
ssize_t sim_read(int fd, void *buf, size_t count)
|
|
|
|
{
|
|
|
|
ssize_t result;
|
|
|
|
|
|
|
|
mutex_lock(&io.sim_mutex);
|
|
|
|
|
|
|
|
/* Setup parameters */
|
|
|
|
io.fd = fd;
|
|
|
|
io.buf = buf;
|
|
|
|
io.count = count;
|
|
|
|
|
|
|
|
result = io_trigger_and_wait(IO_READ);
|
|
|
|
|
|
|
|
mutex_unlock(&io.sim_mutex);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ssize_t sim_write(int fd, const void *buf, size_t count)
|
|
|
|
{
|
|
|
|
ssize_t result;
|
|
|
|
|
|
|
|
mutex_lock(&io.sim_mutex);
|
|
|
|
|
|
|
|
io.fd = fd;
|
|
|
|
io.buf = (void*)buf;
|
|
|
|
io.count = count;
|
|
|
|
|
|
|
|
result = io_trigger_and_wait(IO_WRITE);
|
|
|
|
|
|
|
|
mutex_unlock(&io.sim_mutex);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-07-31 08:33:27 +00:00
|
|
|
#if !defined(APPLICATION)
|
2014-02-22 22:17:16 +00:00
|
|
|
|
|
|
|
static const char *handle_special_links(const char* link)
|
|
|
|
{
|
2014-02-23 21:33:35 +00:00
|
|
|
#ifdef HAVE_MULTIDRIVE
|
2014-02-22 22:17:16 +00:00
|
|
|
static char buffer[MAX_PATH]; /* sufficiently big */
|
|
|
|
char vol_string[VOL_ENUM_POS + 8];
|
|
|
|
int len = sprintf(vol_string, VOL_NAMES, 1);
|
|
|
|
|
|
|
|
/* link might be passed with or without HOME_DIR expanded. To handle
|
|
|
|
* both perform substring matching (VOL_NAMES is unique enough) */
|
|
|
|
const char *begin = strstr(link, vol_string);
|
|
|
|
if (begin)
|
|
|
|
{
|
|
|
|
/* begin now points to the start of vol_string within link,
|
|
|
|
* we want to copy the remainder of the paths, prefixed by
|
|
|
|
* the actual mount point (the remainder might be "") */
|
|
|
|
snprintf(buffer, sizeof(buffer), "%s/../simext/%s",
|
|
|
|
sim_root_dir ?: SIMULATOR_DEFAULT_ROOT, begin + len);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
else
|
2014-02-23 21:33:35 +00:00
|
|
|
#endif
|
2014-02-22 22:17:16 +00:00
|
|
|
return link;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-27 21:15:52 +00:00
|
|
|
static const char *get_sim_pathname(const char *name)
|
2007-11-08 10:15:44 +00:00
|
|
|
{
|
2009-02-27 21:15:52 +00:00
|
|
|
static char buffer[MAX_PATH]; /* sufficiently big */
|
|
|
|
|
|
|
|
if(name[0] == '/')
|
|
|
|
{
|
2009-02-27 21:25:17 +00:00
|
|
|
snprintf(buffer, sizeof(buffer), "%s%s",
|
2014-02-22 22:17:16 +00:00
|
|
|
sim_root_dir ?: SIMULATOR_DEFAULT_ROOT, name);
|
|
|
|
return handle_special_links(buffer);
|
2009-02-27 21:15:52 +00:00
|
|
|
}
|
2009-02-27 21:25:17 +00:00
|
|
|
fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
|
2009-02-27 21:15:52 +00:00
|
|
|
return name;
|
2007-11-08 10:15:44 +00:00
|
|
|
}
|
|
|
|
|
2014-02-22 22:17:16 +00:00
|
|
|
|
2004-06-10 13:29:52 +00:00
|
|
|
MYDIR *sim_opendir(const char *name)
|
2002-04-30 13:14:59 +00:00
|
|
|
{
|
2007-04-19 20:17:24 +00:00
|
|
|
DIR_T *dir;
|
2009-02-27 21:15:52 +00:00
|
|
|
dir = (DIR_T *) OPENDIR(get_sim_pathname(name));
|
2008-12-15 23:42:19 +00:00
|
|
|
|
2009-02-27 21:15:52 +00:00
|
|
|
if (dir)
|
2006-11-10 08:03:33 +00:00
|
|
|
{
|
2003-03-05 22:59:36 +00:00
|
|
|
MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
|
|
|
|
my->dir = dir;
|
2008-12-15 23:42:19 +00:00
|
|
|
my->name = (char *)malloc(strlen(name)+1);
|
|
|
|
strcpy(my->name, name);
|
2014-02-22 22:17:16 +00:00
|
|
|
IF_MV(my->volumes_returned = 0);
|
2003-03-05 22:59:36 +00:00
|
|
|
|
|
|
|
return my;
|
|
|
|
}
|
|
|
|
/* failed open, return NULL */
|
|
|
|
return (MYDIR *)0;
|
2002-04-30 13:14:59 +00:00
|
|
|
}
|
2002-05-05 10:28:23 +00:00
|
|
|
|
2010-12-25 22:17:02 +00:00
|
|
|
#if defined(WIN32)
|
|
|
|
static inline struct tm* localtime_r (const time_t *clock, struct tm *result) {
|
|
|
|
if (!clock || !result) return NULL;
|
|
|
|
memcpy(result,localtime(clock),sizeof(*result));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-06-10 13:29:52 +00:00
|
|
|
struct sim_dirent *sim_readdir(MYDIR *dir)
|
2002-05-07 11:35:03 +00:00
|
|
|
{
|
2007-11-08 12:11:34 +00:00
|
|
|
char buffer[MAX_PATH]; /* sufficiently big */
|
2004-06-10 13:29:52 +00:00
|
|
|
static struct sim_dirent secret;
|
2007-04-19 20:17:24 +00:00
|
|
|
STAT_T s;
|
2010-12-23 19:02:18 +00:00
|
|
|
struct tm tm;
|
2011-06-10 16:29:55 +00:00
|
|
|
DIRENT_T *x11;
|
|
|
|
|
2011-09-03 10:25:40 +00:00
|
|
|
#ifdef EOVERFLOW
|
2011-06-10 16:29:55 +00:00
|
|
|
read_next:
|
2011-09-03 10:25:40 +00:00
|
|
|
#endif
|
2002-05-07 11:35:03 +00:00
|
|
|
|
2014-02-22 22:17:16 +00:00
|
|
|
#define ATTR_LINK 0x80 /* see dir.h */
|
|
|
|
|
|
|
|
secret.info.attribute = 0;
|
|
|
|
#ifdef HAVE_MULTIVOLUME
|
|
|
|
if (dir->name[0] == '/' && dir->name[1] == '\0'
|
|
|
|
&& dir->volumes_returned++ < (NUM_VOLUMES-1)
|
|
|
|
&& volume_present(dir->volumes_returned))
|
|
|
|
{
|
|
|
|
sprintf((char *)secret.d_name, VOL_NAMES, dir->volumes_returned);
|
|
|
|
secret.info.attribute = ATTR_LINK;
|
|
|
|
/* build file name for stat() which is the actual mount point */
|
|
|
|
snprintf(buffer, sizeof(buffer), "%s/../simext",
|
|
|
|
sim_root_dir ?: SIMULATOR_DEFAULT_ROOT);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
x11 = READDIR(dir->dir);
|
2002-05-07 11:35:03 +00:00
|
|
|
|
2014-02-22 22:17:16 +00:00
|
|
|
if(!x11)
|
|
|
|
return (struct sim_dirent *)0;
|
2002-05-07 12:06:32 +00:00
|
|
|
|
2014-02-22 22:17:16 +00:00
|
|
|
strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
|
|
|
|
/* build file name for stat() */
|
|
|
|
snprintf(buffer, sizeof(buffer), "%s/%s",
|
|
|
|
get_sim_pathname(dir->name), secret.d_name);
|
|
|
|
}
|
2011-06-10 16:29:55 +00:00
|
|
|
|
2010-12-23 19:02:18 +00:00
|
|
|
if (STAT(buffer, &s)) /* get info */
|
2011-06-10 16:29:55 +00:00
|
|
|
{
|
2011-06-12 12:12:18 +00:00
|
|
|
#ifdef EOVERFLOW
|
2011-06-10 16:29:55 +00:00
|
|
|
/* File size larger than 2 GB? */
|
|
|
|
if (errno == EOVERFLOW)
|
|
|
|
{
|
|
|
|
DEBUGF("stat() overflow for %s. Skipping\n", buffer);
|
|
|
|
goto read_next;
|
|
|
|
}
|
2011-06-12 12:12:18 +00:00
|
|
|
#endif
|
2011-06-10 16:29:55 +00:00
|
|
|
|
2010-12-23 19:02:18 +00:00
|
|
|
return NULL;
|
2011-06-10 16:29:55 +00:00
|
|
|
}
|
2002-05-07 12:06:32 +00:00
|
|
|
|
2005-02-22 12:19:12 +00:00
|
|
|
#define ATTR_DIRECTORY 0x10
|
2007-11-08 12:11:34 +00:00
|
|
|
|
2010-12-23 19:02:18 +00:00
|
|
|
if (S_ISDIR(s.st_mode))
|
|
|
|
secret.info.attribute = ATTR_DIRECTORY;
|
|
|
|
|
2010-09-01 21:29:34 +00:00
|
|
|
secret.info.size = s.st_size;
|
2010-12-23 19:02:18 +00:00
|
|
|
|
|
|
|
if (localtime_r(&(s.st_mtime), &tm) == NULL)
|
|
|
|
return NULL;
|
|
|
|
secret.info.wrtdate = ((tm.tm_year - 80) << 9) |
|
|
|
|
((tm.tm_mon + 1) << 5) |
|
|
|
|
tm.tm_mday;
|
|
|
|
secret.info.wrttime = (tm.tm_hour << 11) |
|
|
|
|
(tm.tm_min << 5) |
|
|
|
|
(tm.tm_sec >> 1);
|
|
|
|
|
2010-12-25 22:17:02 +00:00
|
|
|
#if HAVE_LSTAT
|
2010-12-23 19:02:18 +00:00
|
|
|
if (!lstat(buffer, &s) && S_ISLNK(s.st_mode))
|
|
|
|
{
|
|
|
|
secret.info.attribute |= ATTR_LINK;
|
|
|
|
}
|
|
|
|
#endif
|
2002-05-07 11:35:03 +00:00
|
|
|
|
2003-03-05 22:59:36 +00:00
|
|
|
return &secret;
|
2002-05-07 11:35:03 +00:00
|
|
|
}
|
|
|
|
|
2004-06-10 13:29:52 +00:00
|
|
|
void sim_closedir(MYDIR *dir)
|
2002-05-07 12:06:32 +00:00
|
|
|
{
|
2003-03-05 22:59:36 +00:00
|
|
|
free(dir->name);
|
2007-04-19 20:17:24 +00:00
|
|
|
CLOSEDIR(dir->dir);
|
2002-05-07 12:06:32 +00:00
|
|
|
|
2003-03-05 22:59:36 +00:00
|
|
|
free(dir);
|
2002-05-07 12:06:32 +00:00
|
|
|
}
|
|
|
|
|
2010-05-06 17:35:13 +00:00
|
|
|
int sim_open(const char *name, int o, ...)
|
2002-05-05 10:28:23 +00:00
|
|
|
{
|
2004-06-14 22:22:49 +00:00
|
|
|
int opts = rockbox2sim(o);
|
2007-10-09 15:15:00 +00:00
|
|
|
int ret;
|
|
|
|
if (num_openfiles >= MAX_OPEN_FILES)
|
|
|
|
return -2;
|
2002-05-05 10:28:23 +00:00
|
|
|
|
2010-05-07 16:56:40 +00:00
|
|
|
if (opts & O_CREAT)
|
2010-05-06 17:35:13 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, o);
|
2010-05-07 16:56:40 +00:00
|
|
|
mode_t mode = va_arg(ap, unsigned int);
|
|
|
|
ret = OPEN(get_sim_pathname(name), opts, mode);
|
2011-04-15 21:45:36 +00:00
|
|
|
#ifdef HAVE_DIRCACHE
|
2011-06-20 20:12:42 +00:00
|
|
|
if (ret >= 0 && (dircache_get_entry_id(name) < 0))
|
2011-04-15 21:45:36 +00:00
|
|
|
dircache_add_file(name, 0);
|
|
|
|
#endif
|
2010-05-06 17:35:13 +00:00
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = OPEN(get_sim_pathname(name), opts);
|
|
|
|
|
2008-12-15 23:42:19 +00:00
|
|
|
if (ret >= 0)
|
|
|
|
num_openfiles++;
|
|
|
|
return ret;
|
2007-10-09 15:15:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int sim_close(int fd)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
ret = CLOSE(fd);
|
2009-02-27 21:25:17 +00:00
|
|
|
if (ret == 0)
|
|
|
|
num_openfiles--;
|
2007-10-09 15:15:00 +00:00
|
|
|
return ret;
|
2002-05-05 10:28:23 +00:00
|
|
|
}
|
2002-11-12 11:32:26 +00:00
|
|
|
|
2010-05-06 17:35:04 +00:00
|
|
|
int sim_creat(const char *name, mode_t mode)
|
2003-01-09 00:55:00 +00:00
|
|
|
{
|
2011-04-15 21:45:36 +00:00
|
|
|
int ret = OPEN(get_sim_pathname(name),
|
|
|
|
O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, mode);
|
|
|
|
#ifdef HAVE_DIRCACHE
|
2011-06-20 20:12:42 +00:00
|
|
|
if (ret >= 0 && (dircache_get_entry_id(name) < 0))
|
2011-04-15 21:45:36 +00:00
|
|
|
dircache_add_file(name, 0);
|
|
|
|
#endif
|
|
|
|
return ret;
|
2007-11-08 12:11:34 +00:00
|
|
|
}
|
2003-01-09 00:55:00 +00:00
|
|
|
|
2007-02-03 10:28:55 +00:00
|
|
|
int sim_mkdir(const char *name)
|
2004-01-21 14:58:40 +00:00
|
|
|
{
|
2009-02-27 21:25:17 +00:00
|
|
|
return MKDIR(get_sim_pathname(name), 0777);
|
2004-01-21 14:58:40 +00:00
|
|
|
}
|
|
|
|
|
2004-06-10 13:29:52 +00:00
|
|
|
int sim_rmdir(const char *name)
|
2004-04-16 09:24:38 +00:00
|
|
|
{
|
2009-02-27 21:25:17 +00:00
|
|
|
return RMDIR(get_sim_pathname(name));
|
2004-04-16 09:24:38 +00:00
|
|
|
}
|
|
|
|
|
2004-06-10 13:29:52 +00:00
|
|
|
int sim_remove(const char *name)
|
2003-01-09 00:55:00 +00:00
|
|
|
{
|
2011-04-15 21:45:36 +00:00
|
|
|
int ret = REMOVE(get_sim_pathname(name));
|
2006-08-26 14:19:18 +00:00
|
|
|
#ifdef HAVE_DIRCACHE
|
2011-04-15 21:45:36 +00:00
|
|
|
if (ret >= 0)
|
|
|
|
dircache_remove(name);
|
2006-08-26 14:19:18 +00:00
|
|
|
#endif
|
2011-04-15 21:45:36 +00:00
|
|
|
return ret;
|
2003-01-09 00:55:00 +00:00
|
|
|
}
|
|
|
|
|
2009-02-27 21:25:17 +00:00
|
|
|
int sim_rename(const char *oldname, const char *newname)
|
2003-01-15 11:38:03 +00:00
|
|
|
{
|
2010-02-01 22:45:27 +00:00
|
|
|
char sim_old[MAX_PATH];
|
|
|
|
char sim_new[MAX_PATH];
|
2006-08-26 14:19:18 +00:00
|
|
|
#ifdef HAVE_DIRCACHE
|
2009-02-27 21:25:17 +00:00
|
|
|
dircache_rename(oldname, newname);
|
2006-11-10 08:03:33 +00:00
|
|
|
#endif
|
2010-02-01 22:45:27 +00:00
|
|
|
// This is needed as get_sim_pathname() has a static buffer
|
|
|
|
strncpy(sim_old, get_sim_pathname(oldname), MAX_PATH);
|
|
|
|
strncpy(sim_new, get_sim_pathname(newname), MAX_PATH);
|
|
|
|
return RENAME(sim_old, sim_new);
|
2003-01-15 11:38:03 +00:00
|
|
|
}
|
|
|
|
|
2005-02-28 18:32:57 +00:00
|
|
|
/* rockbox off_t may be different from system off_t */
|
|
|
|
long sim_lseek(int fildes, long offset, int whence)
|
|
|
|
{
|
|
|
|
return lseek(fildes, offset, whence);
|
|
|
|
}
|
|
|
|
|
2014-02-11 14:27:23 +00:00
|
|
|
#else
|
|
|
|
#define get_sim_pathname(x) x
|
|
|
|
#endif
|
|
|
|
|
2012-03-03 17:54:47 +00:00
|
|
|
long filesize(int fd)
|
2003-03-18 00:39:57 +00:00
|
|
|
{
|
2005-03-09 19:26:59 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
return _filelength(fd);
|
|
|
|
#else
|
|
|
|
struct stat buf;
|
2007-11-08 12:11:34 +00:00
|
|
|
|
2005-03-09 19:26:59 +00:00
|
|
|
if (!fstat(fd, &buf))
|
|
|
|
return buf.st_size;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
#endif
|
2003-03-18 00:39:57 +00:00
|
|
|
}
|
|
|
|
|
2013-08-17 16:18:22 +00:00
|
|
|
void fat_size(IF_MV(int volume,) unsigned long* size, unsigned long* free)
|
2002-11-12 11:32:26 +00:00
|
|
|
{
|
2007-09-13 20:53:32 +00:00
|
|
|
#ifdef HAVE_MULTIVOLUME
|
|
|
|
if (volume != 0) {
|
2008-04-07 17:27:56 +00:00
|
|
|
/* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
|
2007-11-08 12:11:34 +00:00
|
|
|
|
2007-09-13 20:53:32 +00:00
|
|
|
if (size) *size = 0;
|
|
|
|
if (free) *free = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-06-10 13:29:52 +00:00
|
|
|
#ifdef WIN32
|
2005-02-22 21:55:48 +00:00
|
|
|
long secperclus, bytespersec, free_clusters, num_clusters;
|
|
|
|
|
|
|
|
if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
|
|
|
|
&num_clusters)) {
|
|
|
|
if (size)
|
|
|
|
*size = num_clusters * secperclus / 2 * (bytespersec / 512);
|
|
|
|
if (free)
|
|
|
|
*free = free_clusters * secperclus / 2 * (bytespersec / 512);
|
2011-10-04 00:42:00 +00:00
|
|
|
} else
|
2010-08-02 20:34:47 +00:00
|
|
|
#elif HAVE_STATVFS
|
2010-03-20 12:45:54 +00:00
|
|
|
struct statvfs vfs;
|
2002-11-12 11:32:26 +00:00
|
|
|
|
2010-03-20 12:45:54 +00:00
|
|
|
if (!statvfs(".", &vfs)) {
|
|
|
|
DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
|
|
|
|
(int)vfs.f_frsize, (long)vfs.f_blocks, (long)vfs.f_bfree);
|
2002-11-12 11:32:26 +00:00
|
|
|
if (size)
|
2010-03-20 12:45:54 +00:00
|
|
|
*size = vfs.f_blocks / 2 * (vfs.f_frsize / 512);
|
2002-11-12 11:32:26 +00:00
|
|
|
if (free)
|
2010-03-20 12:45:54 +00:00
|
|
|
*free = vfs.f_bfree / 2 * (vfs.f_frsize / 512);
|
2011-10-04 00:42:00 +00:00
|
|
|
} else
|
2005-02-22 21:55:48 +00:00
|
|
|
#endif
|
2011-10-04 00:42:00 +00:00
|
|
|
{
|
2002-11-12 11:32:26 +00:00
|
|
|
if (size)
|
|
|
|
*size = 0;
|
|
|
|
if (free)
|
|
|
|
*free = 0;
|
|
|
|
}
|
|
|
|
}
|
2005-02-22 12:19:12 +00:00
|
|
|
|
|
|
|
int sim_fsync(int fd)
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
return _commit(fd);
|
|
|
|
#else
|
|
|
|
return fsync(fd);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-09-08 20:42:34 +00:00
|
|
|
#ifndef __PCTOOL__
|
2010-08-27 00:29:50 +00:00
|
|
|
|
2012-05-26 20:46:56 +00:00
|
|
|
#include <SDL_loadso.h>
|
2010-09-09 16:17:21 +00:00
|
|
|
void *lc_open(const char *filename, unsigned char *buf, size_t buf_size)
|
2010-08-27 00:29:50 +00:00
|
|
|
{
|
2012-05-26 20:46:56 +00:00
|
|
|
(void)buf;
|
|
|
|
(void)buf_size;
|
|
|
|
void *handle = SDL_LoadObject(get_sim_pathname(filename));
|
2010-08-27 00:29:50 +00:00
|
|
|
if (handle == NULL)
|
2010-08-27 00:16:26 +00:00
|
|
|
{
|
2010-08-27 00:29:50 +00:00
|
|
|
DEBUGF("failed to load %s\n", filename);
|
2012-05-26 20:46:56 +00:00
|
|
|
DEBUGF("lc_open(%s): %s\n", filename, SDL_GetError());
|
2005-07-10 16:33:03 +00:00
|
|
|
}
|
2010-08-27 00:29:50 +00:00
|
|
|
return handle;
|
2010-08-27 00:16:26 +00:00
|
|
|
}
|
|
|
|
|
2010-08-27 00:29:50 +00:00
|
|
|
void *lc_get_header(void *handle)
|
2010-08-27 00:16:26 +00:00
|
|
|
{
|
2012-05-26 20:46:56 +00:00
|
|
|
char *ret = SDL_LoadFunction(handle, "__header");
|
|
|
|
if (ret == NULL)
|
|
|
|
ret = SDL_LoadFunction(handle, "___header");
|
|
|
|
|
|
|
|
return ret;
|
2005-02-22 12:19:12 +00:00
|
|
|
}
|
|
|
|
|
2010-08-27 00:29:50 +00:00
|
|
|
void lc_close(void *handle)
|
2005-02-22 12:19:12 +00:00
|
|
|
{
|
2012-05-26 20:46:56 +00:00
|
|
|
SDL_UnloadObject(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *lc_open_from_mem(void *addr, size_t blob_size)
|
|
|
|
{
|
|
|
|
#ifndef SIMULATOR
|
|
|
|
(void)addr;
|
|
|
|
(void)blob_size;
|
|
|
|
/* we don't support loading code from memory on application builds,
|
|
|
|
* it doesn't make sense (since it means writing the blob to disk again and
|
|
|
|
* then falling back to load from disk) and requires the ability to write
|
|
|
|
* to an executable directory */
|
|
|
|
return NULL;
|
|
|
|
#else
|
|
|
|
/* support it in the sim for the sake of simulating */
|
|
|
|
int fd, i;
|
|
|
|
char temp_filename[MAX_PATH];
|
|
|
|
|
|
|
|
/* We have to create the dynamic link library file from ram so we
|
|
|
|
can simulate the codec loading. With voice and crossfade,
|
|
|
|
multiple codecs may be loaded at the same time, so we need
|
|
|
|
to find an unused filename */
|
|
|
|
for (i = 0; i < 10; i++)
|
|
|
|
{
|
|
|
|
snprintf(temp_filename, sizeof(temp_filename),
|
|
|
|
ROCKBOX_DIR "/libtemp_binary_%d.dll", i);
|
|
|
|
fd = open(temp_filename, O_WRONLY|O_CREAT|O_TRUNC, 0700);
|
|
|
|
if (fd >= 0)
|
|
|
|
break; /* Created a file ok */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fd < 0)
|
|
|
|
{
|
|
|
|
DEBUGF("open failed\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (write(fd, addr, blob_size) < (ssize_t)blob_size)
|
|
|
|
{
|
|
|
|
DEBUGF("Write failed\n");
|
|
|
|
close(fd);
|
|
|
|
remove(temp_filename);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
return lc_open(temp_filename, NULL, 0);
|
|
|
|
#endif
|
2005-02-22 12:19:12 +00:00
|
|
|
}
|
|
|
|
|
2010-08-27 00:29:50 +00:00
|
|
|
#endif /* __PCTOOL__ */
|
2005-02-22 12:19:12 +00:00
|
|
|
|
2005-03-05 21:48:58 +00:00
|
|
|
/* rockbox off_t may be different from system off_t */
|
|
|
|
int sim_ftruncate(int fd, long length)
|
2005-02-22 12:19:12 +00:00
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
return _chsize(fd, length);
|
|
|
|
#else
|
|
|
|
return ftruncate(fd, length);
|
|
|
|
#endif
|
|
|
|
}
|