blob: 02542d15e350ce369236a2eedbca70200c3f3def [file] [log] [blame]
Björn Stenberg32125d42002-05-13 15:23:30 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Daniel Stenberg
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Björn Stenberg32125d42002-05-13 15:23:30 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
Daniel Stenberg7b3abdc2002-04-30 13:14:59 +000021
Daniel Stenberged6c7e42002-06-14 11:00:13 +000022#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
Daniel Stenberg22b77012005-02-22 12:19:12 +000025#include <stdarg.h>
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +000026#include <sys/stat.h>
Peter D'Hoyef0ed5942007-04-06 23:54:21 +000027#include <time.h>
Thomas Jaroscha87e3952011-06-10 16:29:55 +000028#include <errno.h>
Thomas Martitz240923a2010-08-02 20:34:47 +000029#include "config.h"
30
Thomas Martitze22aa752010-09-08 20:39:55 +000031#define HAVE_STATVFS (!defined(WIN32))
Thomas Martitz87c8be42010-12-23 19:02:18 +000032#define HAVE_LSTAT (!defined(WIN32))
Thomas Martitz240923a2010-08-02 20:34:47 +000033
34#if HAVE_STATVFS
Jens Arnold181e0e02010-03-20 12:45:54 +000035#include <sys/statvfs.h>
Björn Stenbergf6ed9702003-07-04 08:30:01 +000036#endif
Hardeep Sidhufb26bfb2004-06-14 07:00:50 +000037
Daniel Stenberg22b77012005-02-22 12:19:12 +000038#ifdef WIN32
39#include <windows.h>
40#endif
41
Hardeep Sidhufb26bfb2004-06-14 07:00:50 +000042#ifndef _MSC_VER
Daniel Stenberge3a12d32002-05-07 12:25:30 +000043#include <dirent.h>
Björn Stenberg2ba4fed2003-01-28 23:14:41 +000044#include <unistd.h>
Hardeep Sidhufb26bfb2004-06-14 07:00:50 +000045#else
46#include "dir-win32.h"
47#endif
Daniel Stenberg7b3abdc2002-04-30 13:14:59 +000048
Daniel Stenberged6c7e42002-06-14 11:00:13 +000049#include <fcntl.h>
Thomas Martitz6d85de32011-02-18 22:46:01 +000050#ifdef HAVE_SDL_THREADS
Thomas Martitz240923a2010-08-02 20:34:47 +000051#include "thread-sdl.h"
Thomas Martitz6d85de32011-02-18 22:46:01 +000052#else
53#define sim_thread_unlock() NULL
54#define sim_thread_lock(a)
55#endif
Michael Sevakisf64ebb12007-09-08 12:20:53 +000056#include "thread.h"
57#include "kernel.h"
Daniel Stenberged6c7e42002-06-14 11:00:13 +000058#include "debug.h"
Jens Arnold51280802007-09-13 20:53:32 +000059#include "ata.h" /* for IF_MV2 et al. */
Thomas Martitz9c0b2472010-08-01 16:15:27 +000060#include "rbpaths.h"
Thomas Martitz194174a2010-08-27 00:29:50 +000061#include "load_code.h"
Michael Sevakisa4d19b72007-12-03 14:01:12 +000062
Thomas Martitz9c0b2472010-08-01 16:15:27 +000063/* keep this in sync with file.h! */
64#undef MAX_PATH /* this avoids problems when building simulator */
65#define MAX_PATH 260
66#define MAX_OPEN_FILES 11
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +000067
Jens Arnold67eb1542007-02-01 23:08:15 +000068/* Windows (and potentially other OSes) distinguish binary and text files.
69 * Define a dummy for the others. */
70#ifndef O_BINARY
71#define O_BINARY 0
72#endif
73
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000074/* Unicode compatibility for win32 */
75#if defined __MINGW32__
76/* Rockbox unicode functions */
77extern const unsigned char* utf8decode(const unsigned char *utf8,
78 unsigned short *ucs);
79extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
80
Jens Arnold49be3fa2007-04-20 17:35:05 +000081/* Static buffers for the conversion results. This isn't thread safe,
82 * but it's sufficient for rockbox. */
83static unsigned char convbuf1[3*MAX_PATH];
84static unsigned char convbuf2[3*MAX_PATH];
85
86static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000087{
Jens Arnold49be3fa2007-04-20 17:35:05 +000088 wchar_t *ucs = buffer;
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000089
90 while (*utf8)
91 utf8 = utf8decode(utf8, ucs++);
Steve Bavinf87eb602007-11-08 12:11:34 +000092
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000093 *ucs = 0;
Jens Arnold49be3fa2007-04-20 17:35:05 +000094 return buffer;
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000095}
Jens Arnold49be3fa2007-04-20 17:35:05 +000096static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000097{
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000098 unsigned char *utf8 = buffer;
Jens Arnold49be3fa2007-04-20 17:35:05 +000099
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000100 while (*ucs)
101 utf8 = utf8encode(*ucs++, utf8);
Steve Bavinf87eb602007-11-08 12:11:34 +0000102
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000103 *utf8 = 0;
104 return buffer;
105}
106
Jens Arnold49be3fa2007-04-20 17:35:05 +0000107#define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
108#define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000109#define DIR_T _WDIR
110#define DIRENT_T struct _wdirent
111#define STAT_T struct _stat
112extern int _wmkdir(const wchar_t*);
113extern int _wrmdir(const wchar_t*);
114#define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
115#define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
116#define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
117#define READDIR(a) (_wreaddir)(a)
118#define CLOSEDIR(a) (_wclosedir)(a)
119#define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
Thomas Martitz0a1d7c22010-05-06 17:35:13 +0000120/* empty variable parameter list doesn't work for variadic macros,
121 * so pretend the second parameter is variable too */
122#define OPEN(a,...) (_wopen)(UTF8_TO_OS(a), __VA_ARGS__)
Jonas Häggqvistb24631c2007-10-09 17:51:02 +0000123#define CLOSE(a) (close)(a)
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000124#define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
Jens Arnold49be3fa2007-04-20 17:35:05 +0000125#define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000126
127#else /* !__MINGW32__ */
128
129#define UTF8_TO_OS(a) (a)
130#define OS_TO_UTF8(a) (a)
131#define DIR_T DIR
132#define DIRENT_T struct dirent
133#define STAT_T struct stat
134#define MKDIR(a,b) (mkdir)(a,b)
135#define RMDIR(a) (rmdir)(a)
136#define OPENDIR(a) (opendir)(a)
137#define READDIR(a) (readdir)(a)
138#define CLOSEDIR(a) (closedir)(a)
139#define STAT(a,b) (stat)(a,b)
Thomas Martitz0a1d7c22010-05-06 17:35:13 +0000140/* empty variable parameter list doesn't work for variadic macros,
141 * so pretend the second parameter is variable too */
142#define OPEN(a, ...) (open)(a, __VA_ARGS__)
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000143#define CLOSE(x) (close)(x)
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000144#define REMOVE(a) (remove)(a)
145#define RENAME(a,b) (rename)(a,b)
146
147#endif /* !__MINGW32__ */
148
149
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +0000150#ifdef HAVE_DIRCACHE
Thomas Martitzaf7aaae2011-06-20 20:12:42 +0000151int dircache_get_entry_id(const char *filename);
Michael Hohmuthd49d2e12011-04-15 21:45:36 +0000152void dircache_add_file(const char *name, long startcluster);
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +0000153void dircache_remove(const char *name);
Steve Bavinb61f0c62009-02-27 21:25:17 +0000154void dircache_rename(const char *oldname, const char *newname);
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +0000155#endif
Daniel Stenberged6c7e42002-06-14 11:00:13 +0000156
Steve Bavin9e05cc52007-11-08 10:15:44 +0000157
Björn Stenberg819378b2008-11-24 20:32:57 +0000158#define SIMULATOR_DEFAULT_ROOT "simdisk"
Steve Bavin9e05cc52007-11-08 10:15:44 +0000159extern const char *sim_root_dir;
Daniel Stenberge3a12d32002-05-07 12:25:30 +0000160
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000161static int num_openfiles = 0;
162
Thomas Martitz6eaab4d2010-09-01 21:29:34 +0000163/* from dir.h */
164struct dirinfo {
Daniel Stenberg22b77012005-02-22 12:19:12 +0000165 int attribute;
Jens Arnoldd6cb7162007-04-07 00:14:16 +0000166 long size;
Thomas Martitz6eaab4d2010-09-01 21:29:34 +0000167 unsigned short wrtdate;
168 unsigned short wrttime;
169};
170
171struct sim_dirent {
172 unsigned char d_name[MAX_PATH];
173 struct dirinfo info;
Jens Arnoldd6cb7162007-04-07 00:14:16 +0000174 long startcluster;
Daniel Stenberg22b77012005-02-22 12:19:12 +0000175};
176
177struct dirstruct {
178 void *dir; /* actually a DIR* dir */
Steve Bavinf87eb602007-11-08 12:11:34 +0000179 char *name;
Daniel Stenberg22b77012005-02-22 12:19:12 +0000180} SIM_DIR;
181
Daniel Stenberge3a12d32002-05-07 12:25:30 +0000182struct mydir {
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000183 DIR_T *dir;
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000184 char *name;
Daniel Stenberge3a12d32002-05-07 12:25:30 +0000185};
186
187typedef struct mydir MYDIR;
Daniel Stenberg7b3abdc2002-04-30 13:14:59 +0000188
Daniel Stenberg36c9a952004-06-14 22:22:49 +0000189static unsigned int rockbox2sim(int opt)
190{
Thomas Martitz2c2e2612010-08-27 12:38:25 +0000191#if 0
192/* this shouldn't be needed since we use the host's versions */
Linus Nielsen Feltzingfc72c532006-02-03 15:19:58 +0000193 int newopt = O_BINARY;
Jens Arnold67eb1542007-02-01 23:08:15 +0000194
Daniel Stenberg36c9a952004-06-14 22:22:49 +0000195 if(opt & 1)
196 newopt |= O_WRONLY;
197 if(opt & 2)
198 newopt |= O_RDWR;
199 if(opt & 4)
200 newopt |= O_CREAT;
201 if(opt & 8)
202 newopt |= O_APPEND;
203 if(opt & 0x10)
204 newopt |= O_TRUNC;
205
206 return newopt;
Thomas Martitz2c2e2612010-08-27 12:38:25 +0000207#else
208 return opt|O_BINARY;
Linus Nielsen Feltzingb6f67a82004-07-08 05:50:20 +0000209#endif
Thomas Martitz2c2e2612010-08-27 12:38:25 +0000210}
Daniel Stenberg36c9a952004-06-14 22:22:49 +0000211
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000212/** Simulator I/O engine routines **/
Michael Sevakis6a058832007-12-03 15:33:12 +0000213#define IO_YIELD_THRESHOLD 512
214
Thomas Martitz240923a2010-08-02 20:34:47 +0000215enum io_dir
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000216{
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000217 IO_READ,
218 IO_WRITE,
219};
220
221struct sim_io
222{
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000223 struct mutex sim_mutex; /* Rockbox mutex */
Michael Sevakis6a058832007-12-03 15:33:12 +0000224 int cmd; /* The command to perform */
225 int ready; /* I/O ready flag - 1= ready */
226 int fd; /* The file to read/write */
227 void *buf; /* The buffer to read/write */
228 size_t count; /* Number of bytes to read/write */
229 size_t accum; /* Acculated bytes transferred */
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000230};
231
232static struct sim_io io;
233
Michael Sevakisc4a76312007-09-10 03:49:12 +0000234int ata_init(void)
235{
236 /* Initialize the rockbox kernel objects on a rockbox thread */
237 mutex_init(&io.sim_mutex);
Michael Sevakis6a058832007-12-03 15:33:12 +0000238 io.accum = 0;
Michael Sevakisc4a76312007-09-10 03:49:12 +0000239 return 1;
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000240}
241
Björn Stenbergff498512009-01-10 21:38:56 +0000242int ata_spinup_time(void)
243{
244 return HZ;
245}
246
Thomas Martitz240923a2010-08-02 20:34:47 +0000247static ssize_t io_trigger_and_wait(enum io_dir cmd)
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000248{
Michael Sevakis6a058832007-12-03 15:33:12 +0000249 void *mythread = NULL;
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000250 ssize_t result;
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000251
Michael Sevakis6a058832007-12-03 15:33:12 +0000252 if (io.count > IO_YIELD_THRESHOLD ||
253 (io.accum += io.count) >= IO_YIELD_THRESHOLD)
254 {
255 /* Allow other rockbox threads to run */
256 io.accum = 0;
Thomas Martitz3d0cee82010-05-15 21:02:47 +0000257 mythread = sim_thread_unlock();
Michael Sevakis6a058832007-12-03 15:33:12 +0000258 }
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000259
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000260 switch (cmd)
261 {
262 case IO_READ:
263 result = read(io.fd, io.buf, io.count);
264 break;
265 case IO_WRITE:
266 result = write(io.fd, io.buf, io.count);
267 break;
Thomas Martitz240923a2010-08-02 20:34:47 +0000268 /* shut up gcc */
269 default:
270 result = -1;
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000271 }
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000272
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000273 /* Regain our status as current */
Michael Sevakis6a058832007-12-03 15:33:12 +0000274 if (mythread != NULL)
275 {
Thomas Martitz3d0cee82010-05-15 21:02:47 +0000276 sim_thread_lock(mythread);
Michael Sevakis6a058832007-12-03 15:33:12 +0000277 }
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000278
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000279 return result;
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000280}
281
Thomas Martitz9c0b2472010-08-01 16:15:27 +0000282#if !defined(__PCTOOL__) && !defined(APPLICATION)
Steve Bavin6eea66f2009-02-27 21:15:52 +0000283static const char *get_sim_pathname(const char *name)
Steve Bavin9e05cc52007-11-08 10:15:44 +0000284{
Steve Bavin6eea66f2009-02-27 21:15:52 +0000285 static char buffer[MAX_PATH]; /* sufficiently big */
286
287 if(name[0] == '/')
288 {
Steve Bavinb61f0c62009-02-27 21:25:17 +0000289 snprintf(buffer, sizeof(buffer), "%s%s",
Steve Bavin6eea66f2009-02-27 21:15:52 +0000290 sim_root_dir != NULL ? sim_root_dir : SIMULATOR_DEFAULT_ROOT, name);
291 return buffer;
292 }
Steve Bavinb61f0c62009-02-27 21:25:17 +0000293 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
Steve Bavin6eea66f2009-02-27 21:15:52 +0000294 return name;
Steve Bavin9e05cc52007-11-08 10:15:44 +0000295}
Steve Bavin6eea66f2009-02-27 21:15:52 +0000296#else
297#define get_sim_pathname(name) name
Björn Stenbergee46a3d2008-12-15 23:42:19 +0000298#endif
Steve Bavin9e05cc52007-11-08 10:15:44 +0000299
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000300MYDIR *sim_opendir(const char *name)
Daniel Stenberg7b3abdc2002-04-30 13:14:59 +0000301{
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000302 DIR_T *dir;
Steve Bavin6eea66f2009-02-27 21:15:52 +0000303 dir = (DIR_T *) OPENDIR(get_sim_pathname(name));
Björn Stenbergee46a3d2008-12-15 23:42:19 +0000304
Steve Bavin6eea66f2009-02-27 21:15:52 +0000305 if (dir)
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000306 {
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000307 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
308 my->dir = dir;
Björn Stenbergee46a3d2008-12-15 23:42:19 +0000309 my->name = (char *)malloc(strlen(name)+1);
310 strcpy(my->name, name);
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +0000311
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000312 return my;
313 }
314 /* failed open, return NULL */
315 return (MYDIR *)0;
Daniel Stenberg7b3abdc2002-04-30 13:14:59 +0000316}
Daniel Stenberg91f165e2002-05-05 10:28:23 +0000317
Andree Buschmann992f8972010-12-25 22:17:02 +0000318#if defined(WIN32)
319static inline struct tm* localtime_r (const time_t *clock, struct tm *result) {
320 if (!clock || !result) return NULL;
321 memcpy(result,localtime(clock),sizeof(*result));
322 return result;
323}
324#endif
325
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000326struct sim_dirent *sim_readdir(MYDIR *dir)
Daniel Stenberg159d4482002-05-07 11:35:03 +0000327{
Steve Bavinf87eb602007-11-08 12:11:34 +0000328 char buffer[MAX_PATH]; /* sufficiently big */
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000329 static struct sim_dirent secret;
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000330 STAT_T s;
Thomas Martitz87c8be42010-12-23 19:02:18 +0000331 struct tm tm;
Thomas Jaroscha87e3952011-06-10 16:29:55 +0000332 DIRENT_T *x11;
333
Andree Buschmann03b08eb2011-09-03 10:25:40 +0000334#ifdef EOVERFLOW
Thomas Jaroscha87e3952011-06-10 16:29:55 +0000335read_next:
Andree Buschmann03b08eb2011-09-03 10:25:40 +0000336#endif
Thomas Jaroscha87e3952011-06-10 16:29:55 +0000337 x11 = READDIR(dir->dir);
Daniel Stenberg159d4482002-05-07 11:35:03 +0000338
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000339 if(!x11)
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000340 return (struct sim_dirent *)0;
Daniel Stenberg159d4482002-05-07 11:35:03 +0000341
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000342 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +0000343
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000344 /* build file name */
Steve Bavinb61f0c62009-02-27 21:25:17 +0000345 snprintf(buffer, sizeof(buffer), "%s/%s",
Steve Bavin6eea66f2009-02-27 21:15:52 +0000346 get_sim_pathname(dir->name), secret.d_name);
Thomas Jaroscha87e3952011-06-10 16:29:55 +0000347
Thomas Martitz87c8be42010-12-23 19:02:18 +0000348 if (STAT(buffer, &s)) /* get info */
Thomas Jaroscha87e3952011-06-10 16:29:55 +0000349 {
Thomas Jarosch4e8bed22011-06-12 12:12:18 +0000350#ifdef EOVERFLOW
Thomas Jaroscha87e3952011-06-10 16:29:55 +0000351 /* File size larger than 2 GB? */
352 if (errno == EOVERFLOW)
353 {
354 DEBUGF("stat() overflow for %s. Skipping\n", buffer);
355 goto read_next;
356 }
Thomas Jarosch4e8bed22011-06-12 12:12:18 +0000357#endif
Thomas Jaroscha87e3952011-06-10 16:29:55 +0000358
Thomas Martitz87c8be42010-12-23 19:02:18 +0000359 return NULL;
Thomas Jaroscha87e3952011-06-10 16:29:55 +0000360 }
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +0000361
Daniel Stenberg22b77012005-02-22 12:19:12 +0000362#define ATTR_DIRECTORY 0x10
Steve Bavinf87eb602007-11-08 12:11:34 +0000363
Thomas Martitz87c8be42010-12-23 19:02:18 +0000364 secret.info.attribute = 0;
Daniel Stenberg159d4482002-05-07 11:35:03 +0000365
Thomas Martitz87c8be42010-12-23 19:02:18 +0000366 if (S_ISDIR(s.st_mode))
367 secret.info.attribute = ATTR_DIRECTORY;
368
369 secret.info.size = s.st_size;
370
371 if (localtime_r(&(s.st_mtime), &tm) == NULL)
372 return NULL;
373 secret.info.wrtdate = ((tm.tm_year - 80) << 9) |
374 ((tm.tm_mon + 1) << 5) |
375 tm.tm_mday;
376 secret.info.wrttime = (tm.tm_hour << 11) |
377 (tm.tm_min << 5) |
378 (tm.tm_sec >> 1);
379
Andree Buschmann992f8972010-12-25 22:17:02 +0000380#if HAVE_LSTAT
Thomas Martitz87c8be42010-12-23 19:02:18 +0000381#define ATTR_LINK 0x80
382 if (!lstat(buffer, &s) && S_ISLNK(s.st_mode))
383 {
384 secret.info.attribute |= ATTR_LINK;
385 }
386#endif
387
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000388 return &secret;
Daniel Stenberg159d4482002-05-07 11:35:03 +0000389}
390
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000391void sim_closedir(MYDIR *dir)
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +0000392{
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000393 free(dir->name);
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000394 CLOSEDIR(dir->dir);
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +0000395
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000396 free(dir);
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +0000397}
398
Thomas Martitz0a1d7c22010-05-06 17:35:13 +0000399int sim_open(const char *name, int o, ...)
Daniel Stenberg91f165e2002-05-05 10:28:23 +0000400{
Daniel Stenberg36c9a952004-06-14 22:22:49 +0000401 int opts = rockbox2sim(o);
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000402 int ret;
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000403 if (num_openfiles >= MAX_OPEN_FILES)
404 return -2;
Daniel Stenberg91f165e2002-05-05 10:28:23 +0000405
Thomas Martitze919b5d2010-05-07 16:56:40 +0000406 if (opts & O_CREAT)
Thomas Martitz0a1d7c22010-05-06 17:35:13 +0000407 {
408 va_list ap;
409 va_start(ap, o);
Thomas Martitze919b5d2010-05-07 16:56:40 +0000410 mode_t mode = va_arg(ap, unsigned int);
411 ret = OPEN(get_sim_pathname(name), opts, mode);
Michael Hohmuthd49d2e12011-04-15 21:45:36 +0000412#ifdef HAVE_DIRCACHE
Thomas Martitzaf7aaae2011-06-20 20:12:42 +0000413 if (ret >= 0 && (dircache_get_entry_id(name) < 0))
Michael Hohmuthd49d2e12011-04-15 21:45:36 +0000414 dircache_add_file(name, 0);
415#endif
Thomas Martitz0a1d7c22010-05-06 17:35:13 +0000416 va_end(ap);
417 }
418 else
419 ret = OPEN(get_sim_pathname(name), opts);
420
Björn Stenbergee46a3d2008-12-15 23:42:19 +0000421 if (ret >= 0)
422 num_openfiles++;
423 return ret;
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000424}
425
426int sim_close(int fd)
427{
428 int ret;
429 ret = CLOSE(fd);
Steve Bavinb61f0c62009-02-27 21:25:17 +0000430 if (ret == 0)
431 num_openfiles--;
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000432 return ret;
Daniel Stenberg91f165e2002-05-05 10:28:23 +0000433}
Björn Stenberg6fb512a2002-11-12 11:32:26 +0000434
Thomas Martitzc61e89c2010-05-06 17:35:04 +0000435int sim_creat(const char *name, mode_t mode)
Björn Stenbergc78e1b02003-01-09 00:55:00 +0000436{
Michael Hohmuthd49d2e12011-04-15 21:45:36 +0000437 int ret = OPEN(get_sim_pathname(name),
438 O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, mode);
439#ifdef HAVE_DIRCACHE
Thomas Martitzaf7aaae2011-06-20 20:12:42 +0000440 if (ret >= 0 && (dircache_get_entry_id(name) < 0))
Michael Hohmuthd49d2e12011-04-15 21:45:36 +0000441 dircache_add_file(name, 0);
442#endif
443 return ret;
Steve Bavinf87eb602007-11-08 12:11:34 +0000444}
Björn Stenbergc78e1b02003-01-09 00:55:00 +0000445
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000446ssize_t sim_read(int fd, void *buf, size_t count)
447{
448 ssize_t result;
449
450 mutex_lock(&io.sim_mutex);
451
452 /* Setup parameters */
453 io.fd = fd;
454 io.buf = buf;
455 io.count = count;
456
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000457 result = io_trigger_and_wait(IO_READ);
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000458
459 mutex_unlock(&io.sim_mutex);
460
461 return result;
462}
463
464ssize_t sim_write(int fd, const void *buf, size_t count)
465{
466 ssize_t result;
467
468 mutex_lock(&io.sim_mutex);
469
470 io.fd = fd;
471 io.buf = (void*)buf;
472 io.count = count;
473
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000474 result = io_trigger_and_wait(IO_WRITE);
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000475
476 mutex_unlock(&io.sim_mutex);
477
478 return result;
479}
480
Jens Arnold6b0fdae2007-02-03 10:28:55 +0000481int sim_mkdir(const char *name)
Linus Nielsen Feltzingef7293f2004-01-21 14:58:40 +0000482{
Steve Bavinb61f0c62009-02-27 21:25:17 +0000483 return MKDIR(get_sim_pathname(name), 0777);
Linus Nielsen Feltzingef7293f2004-01-21 14:58:40 +0000484}
485
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000486int sim_rmdir(const char *name)
Linus Nielsen Feltzing8fa821d2004-04-16 09:24:38 +0000487{
Steve Bavinb61f0c62009-02-27 21:25:17 +0000488 return RMDIR(get_sim_pathname(name));
Linus Nielsen Feltzing8fa821d2004-04-16 09:24:38 +0000489}
490
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000491int sim_remove(const char *name)
Björn Stenbergc78e1b02003-01-09 00:55:00 +0000492{
Michael Hohmuthd49d2e12011-04-15 21:45:36 +0000493 int ret = REMOVE(get_sim_pathname(name));
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +0000494#ifdef HAVE_DIRCACHE
Michael Hohmuthd49d2e12011-04-15 21:45:36 +0000495 if (ret >= 0)
496 dircache_remove(name);
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +0000497#endif
Michael Hohmuthd49d2e12011-04-15 21:45:36 +0000498 return ret;
Björn Stenbergc78e1b02003-01-09 00:55:00 +0000499}
500
Steve Bavinb61f0c62009-02-27 21:25:17 +0000501int sim_rename(const char *oldname, const char *newname)
Björn Stenberg7d80ba02003-01-15 11:38:03 +0000502{
Amaury Poulye9b3c902010-02-01 22:45:27 +0000503 char sim_old[MAX_PATH];
504 char sim_new[MAX_PATH];
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +0000505#ifdef HAVE_DIRCACHE
Steve Bavinb61f0c62009-02-27 21:25:17 +0000506 dircache_rename(oldname, newname);
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +0000507#endif
Amaury Poulye9b3c902010-02-01 22:45:27 +0000508 // This is needed as get_sim_pathname() has a static buffer
509 strncpy(sim_old, get_sim_pathname(oldname), MAX_PATH);
510 strncpy(sim_new, get_sim_pathname(newname), MAX_PATH);
511 return RENAME(sim_old, sim_new);
Björn Stenberg7d80ba02003-01-15 11:38:03 +0000512}
513
Jens Arnold399c0812005-02-28 18:32:57 +0000514/* rockbox off_t may be different from system off_t */
515long sim_lseek(int fildes, long offset, int whence)
Linus Nielsen Feltzinge98bad52003-03-18 00:39:57 +0000516{
Jens Arnold399c0812005-02-28 18:32:57 +0000517 return lseek(fildes, offset, whence);
518}
519
520long sim_filesize(int fd)
521{
Jens Arnoldbb9dfa02005-03-09 19:26:59 +0000522#ifdef WIN32
523 return _filelength(fd);
524#else
525 struct stat buf;
Steve Bavinf87eb602007-11-08 12:11:34 +0000526
Jens Arnoldbb9dfa02005-03-09 19:26:59 +0000527 if (!fstat(fd, &buf))
528 return buf.st_size;
529 else
530 return -1;
531#endif
Linus Nielsen Feltzinge98bad52003-03-18 00:39:57 +0000532}
533
Jens Arnold51280802007-09-13 20:53:32 +0000534void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
Björn Stenberg6fb512a2002-11-12 11:32:26 +0000535{
Jens Arnold51280802007-09-13 20:53:32 +0000536#ifdef HAVE_MULTIVOLUME
537 if (volume != 0) {
Steve Bavinac313ab2008-04-07 17:27:56 +0000538 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
Steve Bavinf87eb602007-11-08 12:11:34 +0000539
Jens Arnold51280802007-09-13 20:53:32 +0000540 if (size) *size = 0;
541 if (free) *free = 0;
542 return;
543 }
544#endif
545
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000546#ifdef WIN32
Jens Arnold78724262005-02-22 21:55:48 +0000547 long secperclus, bytespersec, free_clusters, num_clusters;
548
549 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
550 &num_clusters)) {
551 if (size)
552 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
553 if (free)
554 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
Michael Chicoine19c74942011-10-04 00:42:00 +0000555 } else
Thomas Martitz240923a2010-08-02 20:34:47 +0000556#elif HAVE_STATVFS
Jens Arnold181e0e02010-03-20 12:45:54 +0000557 struct statvfs vfs;
Björn Stenberg6fb512a2002-11-12 11:32:26 +0000558
Jens Arnold181e0e02010-03-20 12:45:54 +0000559 if (!statvfs(".", &vfs)) {
560 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
561 (int)vfs.f_frsize, (long)vfs.f_blocks, (long)vfs.f_bfree);
Björn Stenberg6fb512a2002-11-12 11:32:26 +0000562 if (size)
Jens Arnold181e0e02010-03-20 12:45:54 +0000563 *size = vfs.f_blocks / 2 * (vfs.f_frsize / 512);
Björn Stenberg6fb512a2002-11-12 11:32:26 +0000564 if (free)
Jens Arnold181e0e02010-03-20 12:45:54 +0000565 *free = vfs.f_bfree / 2 * (vfs.f_frsize / 512);
Michael Chicoine19c74942011-10-04 00:42:00 +0000566 } else
Jens Arnold78724262005-02-22 21:55:48 +0000567#endif
Michael Chicoine19c74942011-10-04 00:42:00 +0000568 {
Björn Stenberg6fb512a2002-11-12 11:32:26 +0000569 if (size)
570 *size = 0;
571 if (free)
572 *free = 0;
573 }
574}
Daniel Stenberg22b77012005-02-22 12:19:12 +0000575
576int sim_fsync(int fd)
577{
578#ifdef WIN32
579 return _commit(fd);
580#else
581 return fsync(fd);
582#endif
583}
584
Thomas Martitz89dcb1c2010-09-08 20:42:34 +0000585#ifndef __PCTOOL__
Thomas Martitz194174a2010-08-27 00:29:50 +0000586
Thomas Martitz0d4585b2010-09-09 16:17:21 +0000587void *lc_open(const char *filename, unsigned char *buf, size_t buf_size)
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000588{
Thomas Martitz194174a2010-08-27 00:29:50 +0000589 const char *sim_path = get_sim_pathname(filename);
Thomas Martitz2c2e2612010-08-27 12:38:25 +0000590 void *handle = _lc_open(UTF8_TO_OS(sim_path), buf, buf_size);
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000591
Thomas Martitz194174a2010-08-27 00:29:50 +0000592 if (handle == NULL)
Steve Bavin8c9d5f32006-09-28 08:46:28 +0000593 {
Thomas Martitz194174a2010-08-27 00:29:50 +0000594 DEBUGF("failed to load %s\n", filename);
595 DEBUGF("lc_open(%s): %s\n", filename, lc_last_error());
Steve Bavin8c9d5f32006-09-28 08:46:28 +0000596 }
Thomas Martitz194174a2010-08-27 00:29:50 +0000597 return handle;
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000598}
599
Thomas Martitz194174a2010-08-27 00:29:50 +0000600void *lc_get_header(void *handle)
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000601{
Thomas Martitz194174a2010-08-27 00:29:50 +0000602 return _lc_get_header(handle);
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000603}
604
Thomas Martitz194174a2010-08-27 00:29:50 +0000605void lc_close(void *handle)
Daniel Stenberg22b77012005-02-22 12:19:12 +0000606{
Thomas Martitz194174a2010-08-27 00:29:50 +0000607 _lc_close(handle);
Thomas Martitz97d2a6e2010-08-27 00:16:26 +0000608}
609
Thomas Martitz194174a2010-08-27 00:29:50 +0000610#endif /* __PCTOOL__ */
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000611#ifdef WIN32
612static unsigned old_cp;
Daniel Stenberg22b77012005-02-22 12:19:12 +0000613
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000614void debug_exit(void)
615{
616 /* Reset console output codepage */
617 SetConsoleOutputCP(old_cp);
618}
619
620void debug_init(void)
621{
622 old_cp = GetConsoleOutputCP();
623 /* Set console output codepage to UTF8. Only works
624 * correctly when the console uses a truetype font. */
625 SetConsoleOutputCP(65001);
626 atexit(debug_exit);
627}
628#else
Daniel Stenberg22b77012005-02-22 12:19:12 +0000629void debug_init(void)
630{
631 /* nothing to be done */
632}
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000633#endif
Daniel Stenberg22b77012005-02-22 12:19:12 +0000634
635void debugf(const char *fmt, ...)
636{
637 va_list ap;
638 va_start( ap, fmt );
639 vfprintf( stderr, fmt, ap );
640 va_end( ap );
641}
642
643void ldebugf(const char* file, int line, const char *fmt, ...)
644{
645 va_list ap;
646 va_start( ap, fmt );
647 fprintf( stderr, "%s:%d ", file, line );
648 vfprintf( stderr, fmt, ap );
649 va_end( ap );
650}
651
Jens Arnold576d0292005-03-05 21:48:58 +0000652/* rockbox off_t may be different from system off_t */
653int sim_ftruncate(int fd, long length)
Daniel Stenberg22b77012005-02-22 12:19:12 +0000654{
655#ifdef WIN32
656 return _chsize(fd, length);
657#else
658 return ftruncate(fd, length);
659#endif
660}