symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/syborg_hostfs.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * Syborg Host Filesystem pseudo-device
       
     3  * Implements a set of syscalls that may look remarkably similar
       
     4  * to those used by SymbianOS.
       
     5  *
       
     6  * Copyright (c) 2009 CodeSourcery
       
     7  *
       
     8  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
     9  * of this software and associated documentation files (the "Software"), to deal
       
    10  * in the Software without restriction, including without limitation the rights
       
    11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    12  * copies of the Software, and to permit persons to whom the Software is
       
    13  * furnished to do so, subject to the following conditions:
       
    14  *
       
    15  * The above copyright notice and this permission notice shall be included in
       
    16  * all copies or substantial portions of the Software.
       
    17  *
       
    18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
       
    21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    24  * THE SOFTWARE.
       
    25  */
       
    26 
       
    27 #include "hw.h"
       
    28 #include "syborg.h"
       
    29 #include "devtree.h"
       
    30 
       
    31 //#define DEBUG_SYBORG_HOSTFS
       
    32 
       
    33 #ifdef DEBUG_SYBORG_HOSTFS
       
    34 #define DPRINTF(fmt, args...) \
       
    35 do { printf("syborg_hostfs: " fmt , ##args); } while (0)
       
    36 #define BADF(fmt, args...) \
       
    37 do { fprintf(stderr, "syborg_hostfs: error: " fmt , ##args); exit(1);} while (0)
       
    38 #else
       
    39 #define DPRINTF(fmt, args...) do {} while(0)
       
    40 #define BADF(fmt, args...) \
       
    41 do { fprintf(stderr, "syborg_hostfs: error: " fmt , ##args);} while (0)
       
    42 #endif
       
    43 
       
    44 #define HOSTFS_PATH_MAX 65536
       
    45 #ifdef _WIN32
       
    46 #include <mbstring.h>
       
    47 #include <wchar.h>
       
    48 #include <io.h>
       
    49 typedef wchar_t host_char;
       
    50 typedef struct _stat host_stat;
       
    51 typedef struct {
       
    52     int handle;
       
    53     struct  _wfinddata_t info;
       
    54 } hostfs_dir;
       
    55 #else
       
    56 #include <iconv.h>
       
    57 #include <langinfo.h>
       
    58 #include <locale.h>
       
    59 #include <dirent.h>
       
    60 #include <fnmatch.h>
       
    61 typedef char host_char;
       
    62 typedef struct stat host_stat;
       
    63 typedef struct {
       
    64     DIR *dir;
       
    65     char pattern[HOSTFS_PATH_MAX];
       
    66     char path[HOSTFS_PATH_MAX];
       
    67 } hostfs_dir;
       
    68 #endif
       
    69 #define HOST_CHAR(var) host_char var[HOSTFS_PATH_MAX]
       
    70 
       
    71 enum {
       
    72     HOSTFS_ID           = 0,
       
    73     HOSTFS_COMMAND      = 1,
       
    74     HOSTFS_RESULT       = 2,
       
    75     HOSTFS_ARG0         = 3,
       
    76     HOSTFS_ARG1         = 4,
       
    77     HOSTFS_ARG2         = 5,
       
    78     HOSTFS_ARG3         = 6
       
    79 };
       
    80 
       
    81 typedef struct hostfs_handle_cache {
       
    82     int handle;
       
    83     int is_fd;
       
    84     struct {
       
    85         int fd;
       
    86         hostfs_dir *d;
       
    87     } val;
       
    88     struct hostfs_handle_cache *next;
       
    89 } hostfs_handle_cache;
       
    90 
       
    91 typedef struct {
       
    92     QEMUDevice *qdev;
       
    93     uint32_t result;
       
    94     uint32_t arg[4];
       
    95     uint32_t command;
       
    96     char drive_letter;
       
    97     host_char *host_prefix;
       
    98     int host_prefix_len;
       
    99     int last_handle;
       
   100     hostfs_handle_cache *handle_cache;
       
   101     hostfs_handle_cache *free_handle;
       
   102 #ifndef _WIN32
       
   103     iconv_t iconv_guest_to_host;
       
   104     iconv_t iconv_host_to_guest;
       
   105 #endif
       
   106 } syborg_hostfs_state;
       
   107 
       
   108 #define HOSTFS_ATTR_READONLY    0x01
       
   109 #define HOSTFS_ATTR_HIDDEN      0x02
       
   110 #define HOSTFS_ATTR_DIRECTORY   0x10
       
   111 
       
   112 #define HOST_FS_SUCCESS          0          // KErrNone
       
   113 #define HOST_FS_NOT_FOUND       -1          // KErrNotFound=(-1
       
   114 #define HOST_FS_GENERAL_ERROR   -2          // KErrGeneral=(-2);
       
   115 
       
   116 #define HOST_FS_NO_MEMORY       -4          // KErrNoMemory=(-4)
       
   117 #define HOST_FS_UNSUPPORTED     -5          // KErrNotSupported=(-5) 
       
   118 #define HOST_FS_BAD_ARG         -6          // KErrArgument=(-6)    
       
   119 #define HOST_FS_BAD_HANDLE      -8          // KErrBadHandle=(-8)
       
   120 #define HOST_FS_EXISTS          -11         // KErrAlreadyExists=(-11)
       
   121 #define HOST_FS_PATH_NOT_FOUND  -12         // KErrPathNotFound=(-12)
       
   122 #define HOST_FS_IN_USE          -14         // KErrInUse=(-14)
       
   123 #define HOST_FS_UNKNOWN         -19         // KErrUnknown=(-19)
       
   124 #define HOST_FS_CORRUPT         -20         // KErrCorrupt=(-20)
       
   125 #define HOST_FS_ACCESS_DENIED   -21         // KErrAccessDenied=(-21)
       
   126 #define HOST_FS_LOCKED          -22         // KErrLocked=(-22)
       
   127 #define HOST_FS_WRITE           -23         // KErrWrite=(-23)
       
   128 #define HOST_FS_EOF             -25         // KErrEof=(-25)
       
   129 #define HOST_FS_DISKFULL        -26         // KErrDiskFull=(-26)
       
   130 #define HOST_FS_BAD_NAME        -28         // KErrBadName=(-28)
       
   131 #define HOST_FS_ABORT           -39         // KErrAbort=(-39)
       
   132 #define HOST_FS_TOO_BIG         -40         // KErrTooBig=(-40)
       
   133 #define HOST_FS_DIR_FULL        -43         // KErrDirFull=(-43)
       
   134 #define HOST_FS_PERMISSION_DENIED -46       // KErrPermissionDenied=(-46)
       
   135 
       
   136 static int decode_error(int e)
       
   137 {
       
   138     int r = HOST_FS_GENERAL_ERROR;
       
   139     switch (e) {
       
   140     case EPERM :                            /* Operation not permitted */
       
   141         r = HOST_FS_PERMISSION_DENIED;
       
   142         break;
       
   143 #ifdef ENOFILE
       
   144     case ENOFILE :                          /* No such file or directory */
       
   145 #endif
       
   146 #ifdef ENOENT
       
   147 #if !defined(ENOFILE) || (ENOFILE != ENOENT)
       
   148         case ENOENT:
       
   149 #endif
       
   150 #endif
       
   151         r = HOST_FS_PATH_NOT_FOUND;
       
   152         break;
       
   153     case ESRCH :                            /* No such process */
       
   154         r = HOST_FS_NOT_FOUND;
       
   155         break;
       
   156     case EINTR :                            /* Interrupted function call */
       
   157     case EIO :                              /* Input/output error */
       
   158     case ENXIO :                            /* No such device or address */
       
   159         break;
       
   160     case E2BIG :                            /* Arg list too long */
       
   161         r = HOST_FS_TOO_BIG;
       
   162         break;
       
   163     case ENOEXEC :                          /* Exec format error */
       
   164         break;
       
   165     case EBADF :                            /* Bad file descriptor */
       
   166         r = HOST_FS_BAD_ARG;
       
   167         break;
       
   168     case ECHILD :                           /* No child processes */
       
   169         break;
       
   170     case EAGAIN :                           /* Resource temporarily unavailable */
       
   171         r = HOST_FS_GENERAL_ERROR;
       
   172         break;
       
   173     case ENOMEM :                           /* Not enough space */
       
   174         r = HOST_FS_NO_MEMORY;
       
   175         break;
       
   176     case EACCES :                           /* Permission denied */
       
   177         r = HOST_FS_ACCESS_DENIED;
       
   178         break;
       
   179     case EFAULT :                           /* Bad address */
       
   180         break;
       
   181     case 15 :                               /* 15 - Unknown Error */
       
   182         r = HOST_FS_UNKNOWN;
       
   183         break;
       
   184     case EBUSY :                            /* strerror reports "Resource device" */
       
   185         r = HOST_FS_IN_USE;
       
   186         break;
       
   187     case EEXIST :                           /* File exists */
       
   188         r = HOST_FS_EXISTS;
       
   189         break;
       
   190     case EXDEV :                            /* Improper link (cross-device link?) */
       
   191         break;
       
   192     case ENODEV :                           /* No such device */
       
   193         r = HOST_FS_BAD_NAME;
       
   194         break;
       
   195     case ENOTDIR :                          /* Not a directory */
       
   196     case EISDIR :                           /* Is a directory */
       
   197     case EINVAL :                           /* Invalid argument */
       
   198         r = HOST_FS_BAD_ARG;
       
   199         break;
       
   200     case ENFILE :                           /* Too many open files in system */
       
   201     case EMFILE :                           /* Too many open files */
       
   202     case ENOTTY :                           /* Inappropriate I/O control operation */
       
   203         break;
       
   204     case 26 :                               /* 26 - Unknown Error */
       
   205         r = HOST_FS_UNKNOWN;
       
   206         break;
       
   207     case EFBIG :                            /* File too large */
       
   208         r = HOST_FS_TOO_BIG;
       
   209         break;
       
   210     case ENOSPC :                           /* No space left on device */
       
   211         r = HOST_FS_DISKFULL;
       
   212         break;
       
   213     case ESPIPE :                           /* Invalid seek (seek on a pipe?) */
       
   214     case EROFS :                            /* Read-only file system */
       
   215     case EMLINK :                           /* Too many links */
       
   216     case EPIPE :                            /* Broken pipe */
       
   217     case EDOM :                             /* Domain error (math functions) */
       
   218     case ERANGE :                           /* Result too large (possibly too small) */
       
   219         break;
       
   220     case EDEADLK :                          /* Resource deadlock avoided (non-Cyg) */
       
   221         break;
       
   222     case ENAMETOOLONG :                     /* Filename too long (91 in Cyg?) */
       
   223         r = HOST_FS_BAD_NAME;
       
   224         break;
       
   225     case ENOLCK :                           /* No locks available (46 in Cyg?) */
       
   226     case ENOSYS :                           /* Function not implemented (88 in Cyg?) */
       
   227         r = HOST_FS_UNSUPPORTED;
       
   228         break;
       
   229     case ENOTEMPTY :                        /* Directory not empty (90 in Cyg?) */
       
   230     case EILSEQ :                           /* Illegal byte sequence */
       
   231         break;
       
   232     }
       
   233     return r;
       
   234 }
       
   235 
       
   236 typedef enum hostfs_op {
       
   237     EDummy = 0,
       
   238 
       
   239     /*  Codes for CMountCB operations */
       
   240     EMkDir,
       
   241     ERmDir,
       
   242     EDelete,
       
   243     ERename,
       
   244     EReplace,
       
   245     EReadUid,
       
   246     EEntry,
       
   247     ESetEntry,
       
   248     EFileOpen,
       
   249     EDirOpen,
       
   250     
       
   251     /*  Code for CFileCB operations */
       
   252     EFileClose, 
       
   253     EFileRead,
       
   254     EFileWrite,
       
   255     EFileSetSize,
       
   256     EFileFlush,
       
   257 
       
   258     /*  Code for CDirCB operations */
       
   259     EDirClose, 
       
   260     EDirRead,
       
   261 } syborg_hostfs_op_t;
       
   262 
       
   263 static hostfs_handle_cache *get_new_handle(syborg_hostfs_state *s)
       
   264 {
       
   265     hostfs_handle_cache *c;
       
   266 
       
   267     if (s->free_handle) {
       
   268         c = s->free_handle;
       
   269         s->free_handle = c->next;
       
   270     } else {
       
   271         c = qemu_malloc(sizeof(*c));
       
   272         c->handle = ++s->last_handle;
       
   273     }
       
   274     c->next = s->handle_cache;
       
   275     s->handle_cache = c;
       
   276 
       
   277     return c;
       
   278 }
       
   279 
       
   280 static int add_file_cache_entry(syborg_hostfs_state *s, int fd)
       
   281 {
       
   282     hostfs_handle_cache *c = get_new_handle(s);
       
   283     c->is_fd = 1;
       
   284     c->val.fd = fd;
       
   285     return c->handle;
       
   286 }
       
   287 
       
   288 static int add_dir_cache_entry(syborg_hostfs_state *s, hostfs_dir *d)
       
   289 {
       
   290     hostfs_handle_cache *c = get_new_handle(s);
       
   291     c->is_fd = 0;
       
   292     c->val.d = d;
       
   293     return c->handle;
       
   294 }
       
   295 
       
   296 static hostfs_handle_cache *get_handle_cache_entry(syborg_hostfs_state *s,
       
   297                                                    int handle)
       
   298 {
       
   299     hostfs_handle_cache *c;
       
   300 
       
   301     for (c = s->handle_cache; c; c = c->next) {
       
   302         if (c->handle == handle)
       
   303             return c;
       
   304     }
       
   305     return NULL;
       
   306 }
       
   307 
       
   308 static int get_file_cache_entry(syborg_hostfs_state *s, int handle, int *fd)
       
   309 {
       
   310     hostfs_handle_cache *c = get_handle_cache_entry(s, handle);
       
   311     if (!c || !c->is_fd)
       
   312         return HOST_FS_BAD_HANDLE;
       
   313     *fd = c->val.fd;
       
   314     return HOST_FS_SUCCESS;
       
   315 }
       
   316 
       
   317 static int get_dir_cache_entry(syborg_hostfs_state *s, int handle, hostfs_dir **d)
       
   318 {
       
   319     hostfs_handle_cache *c = get_handle_cache_entry(s, handle);
       
   320     if (!c || c->is_fd)
       
   321         return HOST_FS_BAD_HANDLE;
       
   322     *d = c->val.d;
       
   323     return HOST_FS_SUCCESS;
       
   324 }
       
   325 
       
   326 static void remove_handle_cache_entry(syborg_hostfs_state *s, int handle)
       
   327 {
       
   328     hostfs_handle_cache *c;
       
   329     hostfs_handle_cache **p;
       
   330     p = &s->handle_cache;
       
   331     c = *p;
       
   332     while (c && c->handle != handle) {
       
   333         p = &c->next;
       
   334         c = c->next;
       
   335     }
       
   336     if (!c)
       
   337         return;
       
   338     *p = c->next;
       
   339     c->next = s->free_handle;
       
   340     s->free_handle = c;
       
   341 }
       
   342 
       
   343 static void remove_file_cache_entry(syborg_hostfs_state *s, int handle)
       
   344 {
       
   345     remove_handle_cache_entry(s, handle);
       
   346 }
       
   347 
       
   348 static void remove_dir_cache_entry(syborg_hostfs_state *s, int handle)
       
   349 {
       
   350     remove_handle_cache_entry(s, handle);
       
   351 }
       
   352 
       
   353 static int hostfs_get_filename(syborg_hostfs_state *s, host_char *buf,
       
   354                                uint32_t addr, uint32_t len)
       
   355 {
       
   356     uint8_t prefix[6];
       
   357 
       
   358     if (len < 3)
       
   359         return HOST_FS_BAD_NAME;
       
   360     cpu_physical_memory_read(addr, prefix, 6);
       
   361     if (prefix[1] != 0 || prefix[3] != 0 || prefix[5] != 0
       
   362         || qemu_toupper(prefix[0]) != s->drive_letter
       
   363         || prefix[2] != ':' || prefix[4] != '\\')
       
   364         return HOST_FS_BAD_NAME;
       
   365     len -= 3;
       
   366     addr += 6;
       
   367 #ifdef _WIN32
       
   368     if (len + s->host_prefix_len >= HOSTFS_PATH_MAX)
       
   369         return HOST_FS_BAD_NAME;
       
   370     memcpy(buf, s->host_prefix, s->host_prefix_len * 2);
       
   371     buf += s->host_prefix_len;
       
   372     cpu_physical_memory_read(addr, (void *)buf, len * 2);
       
   373     buf[len] = 0;
       
   374 #else
       
   375     uint8_t guest_path[HOSTFS_PATH_MAX];
       
   376     char *inp;
       
   377     char *outp;
       
   378     size_t inbytes;
       
   379     size_t outbytes;
       
   380     int err;
       
   381     if (len >= HOSTFS_PATH_MAX)
       
   382         return HOST_FS_BAD_NAME;
       
   383     memcpy(buf, s->host_prefix, s->host_prefix_len);
       
   384     cpu_physical_memory_read(addr, guest_path, len * 2);
       
   385     if (len > 0) {
       
   386         inp = (char *)guest_path;
       
   387         outp = buf + s->host_prefix_len;
       
   388         inbytes = len * 2;
       
   389         outbytes = HOSTFS_PATH_MAX - (s->host_prefix_len + 1);
       
   390         if (s->host_prefix_len > 0 && buf[s->host_prefix_len - 1] != '/') {
       
   391             *(outp++) = '/';
       
   392             outbytes--;
       
   393         }
       
   394         *outp = '/';
       
   395         err = iconv(s->iconv_guest_to_host, &inp, &inbytes, &outp, &outbytes);
       
   396         if (err < 0)
       
   397             return decode_error(errno);
       
   398         *outp = 0;
       
   399         for (outp = buf; *outp; outp++) {
       
   400             if (*outp == '\\')
       
   401                 *outp = '/';
       
   402         }
       
   403     }
       
   404 #endif
       
   405     return HOST_FS_SUCCESS;
       
   406 }
       
   407 
       
   408 typedef int (*syborg_hostfs_op_fn)(syborg_hostfs_state *);
       
   409 
       
   410 static int hostfs_unsupported(syborg_hostfs_state *s)
       
   411 {
       
   412     return HOST_FS_UNSUPPORTED;
       
   413 }
       
   414 
       
   415 static int hostfs_mkdir(syborg_hostfs_state *s)
       
   416 {
       
   417     HOST_CHAR(name);
       
   418     int err;
       
   419 
       
   420     err = hostfs_get_filename(s, name, s->arg[0], s->arg[1]);
       
   421     if (err)
       
   422         return err;
       
   423 #ifdef _WIN32
       
   424     err = _wmkdir(name);
       
   425 #else
       
   426     err = mkdir(name, 0777);
       
   427 #endif
       
   428     if (err < 0)
       
   429         return decode_error(errno);
       
   430 
       
   431     return HOST_FS_SUCCESS;
       
   432 }
       
   433 
       
   434 static int hostfs_rmdir(syborg_hostfs_state *s)
       
   435 {
       
   436     HOST_CHAR(name);
       
   437     int err;
       
   438 
       
   439     err = hostfs_get_filename(s, name, s->arg[0], s->arg[1]);
       
   440     if (err)
       
   441         return err;
       
   442 #ifdef _WIN32
       
   443     err = _wrmdir(name);
       
   444 #else
       
   445     err = rmdir(name);
       
   446 #endif
       
   447     if (err < 0)
       
   448         return decode_error(errno);
       
   449 
       
   450     return HOST_FS_SUCCESS;
       
   451 }
       
   452 
       
   453 static int hostfs_delete(syborg_hostfs_state *s)
       
   454 {
       
   455     HOST_CHAR(name);
       
   456     int err;
       
   457 
       
   458     err = hostfs_get_filename(s, name, s->arg[0], s->arg[1]);
       
   459     if (err)
       
   460         return err;
       
   461 #ifdef _WIN32
       
   462     err = _wunlink(name);
       
   463 #else
       
   464     err = unlink(name);
       
   465 #endif
       
   466     if (err < 0)
       
   467         return decode_error(errno);
       
   468 
       
   469     return HOST_FS_SUCCESS;
       
   470 }
       
   471 
       
   472 static int hostfs_rename(syborg_hostfs_state *s)
       
   473 {
       
   474     HOST_CHAR(old_name);
       
   475     HOST_CHAR(new_name);
       
   476     int err;
       
   477 
       
   478     err = hostfs_get_filename(s, old_name, s->arg[0], s->arg[1]);
       
   479     if (err)
       
   480         return err;
       
   481     err = hostfs_get_filename(s, new_name, s->arg[2], s->arg[3]);
       
   482     if (err)
       
   483         return err;
       
   484 #ifdef _WIN32
       
   485     err = _wrename(old_name, new_name);
       
   486 #else
       
   487     err = rename(old_name, new_name);
       
   488 #endif
       
   489     if (err < 0)
       
   490         return decode_error(errno);
       
   491 
       
   492     return HOST_FS_SUCCESS;
       
   493 }
       
   494 
       
   495 static int hostfs_replace(syborg_hostfs_state *s)
       
   496 {
       
   497     HOST_CHAR(old_name);
       
   498     HOST_CHAR(new_name);
       
   499     int err;
       
   500 
       
   501     err = hostfs_get_filename(s, old_name, s->arg[0], s->arg[1]);
       
   502     if (err)
       
   503         return err;
       
   504     err = hostfs_get_filename(s, new_name, s->arg[2], s->arg[3]);
       
   505     if (err)
       
   506         return err;
       
   507 #ifdef _WIN32
       
   508     if (!_waccess(new_name, F_OK)) {
       
   509         if (_wunlink(new_name)) {
       
   510             return decode_error(errno);
       
   511         }
       
   512     }
       
   513     err = _wrename(old_name, new_name);
       
   514 #else
       
   515     if (!access(new_name, F_OK)) {
       
   516         if (unlink(new_name)) {
       
   517             return decode_error(errno);
       
   518         }
       
   519     }
       
   520     err = rename(old_name, new_name);
       
   521 #endif
       
   522     if (err < 0)
       
   523         return decode_error(errno);
       
   524 
       
   525     return HOST_FS_SUCCESS;
       
   526 }
       
   527 
       
   528 static uint32 hostfs_map_file_att(uint32 val)
       
   529 {
       
   530     uint32 r = 0;
       
   531     if (!(val & S_IRWXU))           /* hidden */
       
   532         r |= HOSTFS_ATTR_HIDDEN;
       
   533     else if (!(val & S_IWRITE))     /* readonly */
       
   534         r |= HOSTFS_ATTR_READONLY;
       
   535     if (S_ISDIR(val))               /* directory */
       
   536         r |= HOSTFS_ATTR_DIRECTORY;
       
   537     
       
   538     return r;
       
   539 }
       
   540 
       
   541 static int hostfs_entry(syborg_hostfs_state *s)
       
   542 {
       
   543     HOST_CHAR(name);
       
   544     host_stat stat_buf;
       
   545     int err;
       
   546 
       
   547     err = hostfs_get_filename(s, name, s->arg[0], s->arg[1]);
       
   548     if (err)
       
   549         return err;
       
   550 #ifdef _WIN32
       
   551     err = _wstat(name, &stat_buf);
       
   552 #else
       
   553     err = lstat(name, &stat_buf);
       
   554 #endif
       
   555     if (err < 0)
       
   556         return decode_error(errno);
       
   557 
       
   558     s->arg[0] = hostfs_map_file_att(stat_buf.st_mode); /*  attributes */
       
   559     s->arg[1] = stat_buf.st_mtime;              /*  modified time */
       
   560     s->arg[2] = stat_buf.st_size;               /*  file size */
       
   561 
       
   562     return HOST_FS_SUCCESS;
       
   563 }
       
   564 
       
   565 static int hostfs_set_entry(syborg_hostfs_state *s)
       
   566 {
       
   567     return HOST_FS_UNSUPPORTED;
       
   568 }
       
   569 
       
   570 #define _EFileWrite     0x200
       
   571 #define EFileOpen       0
       
   572 #define EFileCreate     1
       
   573 #define EFileReplace    2
       
   574 
       
   575 static int hostfs_file_open(syborg_hostfs_state *s)
       
   576 {
       
   577     HOST_CHAR(name);
       
   578     int fd, handle, flags = 0, access = O_RDWR, create = 0, mode = 0;
       
   579     host_stat stat_buf;
       
   580     int err;
       
   581 
       
   582     err = hostfs_get_filename(s, name, s->arg[0], s->arg[1]);
       
   583     if (err)
       
   584         return err;
       
   585     
       
   586     if (!(s->arg[2] & _EFileWrite))
       
   587         access = O_RDONLY;
       
   588     else
       
   589         access = O_RDWR;
       
   590     
       
   591     switch (s->arg[3]) {
       
   592     case EFileOpen:
       
   593         break;
       
   594     case EFileCreate:
       
   595         create = (O_CREAT|O_EXCL);
       
   596         mode = S_IRUSR | S_IWUSR;
       
   597         break;
       
   598     case EFileReplace:
       
   599         create = O_CREAT | O_TRUNC;
       
   600         mode = S_IRUSR | S_IWUSR;
       
   601         break;
       
   602     }
       
   603     flags = access|create|O_BINARY;
       
   604 #ifdef _WIN32
       
   605     fd = _wopen(name, flags, mode);
       
   606 #else
       
   607     DPRINTF("Opening %s %x 0%o\n", name, flags, mode);
       
   608     fd = open(name, flags, mode);
       
   609 #endif
       
   610     if (fd == -1) {
       
   611         err = errno;
       
   612         return decode_error(err);
       
   613     }
       
   614 
       
   615 #ifdef _WIN32
       
   616     if (_fstat(fd, &stat_buf)) {
       
   617 #else
       
   618     if (fstat(fd, &stat_buf)) {
       
   619 #endif
       
   620         err = errno;
       
   621         close(fd);
       
   622         return decode_error(err);       
       
   623     }
       
   624 
       
   625     handle = add_file_cache_entry(s, fd);
       
   626     if (handle < 0)
       
   627         return handle;
       
   628     
       
   629     s->arg[0] = handle;                         /* handle */
       
   630     /* make entry's stat info available in registers */
       
   631     s->arg[1] = hostfs_map_file_att(stat_buf.st_mode); /* attributes */
       
   632     s->arg[2] = stat_buf.st_mtime;              /* modified time */
       
   633     s->arg[3] = stat_buf.st_size;               /* file size */
       
   634     
       
   635     return HOST_FS_SUCCESS;
       
   636 }
       
   637 
       
   638 static int hostfs_dir_open(syborg_hostfs_state *s)
       
   639 {
       
   640     host_char name[HOSTFS_PATH_MAX + 2];
       
   641     hostfs_dir *d;
       
   642     int err;
       
   643     int len;
       
   644 
       
   645     err = hostfs_get_filename(s, name, s->arg[0], s->arg[1]);
       
   646     if (err)
       
   647         return err;
       
   648     d = qemu_mallocz(sizeof(*d));
       
   649     if (!d)
       
   650         return HOST_FS_NO_MEMORY;
       
   651 #ifdef _WIN32
       
   652     len = wcslen(name);
       
   653     if (name[len - 1] == '\\') {
       
   654         name[len++] = '*';
       
   655         name[len] = 0;
       
   656     }
       
   657     d->handle = _wfindfirst(name, &d->info);
       
   658     if (d->handle == -1) {
       
   659         err = decode_error(errno);
       
   660         qemu_free(d);
       
   661         return err;
       
   662     }
       
   663     s->arg[0] = add_dir_cache_entry(s, d);
       
   664 #else
       
   665     DPRINTF("Opening %s\n", name);
       
   666     len = strlen(name) - 1;
       
   667     while (len > 0 && name[len] != '/')
       
   668       len--;
       
   669     name[len++] = 0;
       
   670     strcpy(d->path, name);
       
   671     strcpy(d->pattern, name + len);
       
   672     d->dir = opendir(name);
       
   673     if (d->pattern[0] == '*' && d->pattern[1] == 0)
       
   674         d->pattern[0] = 0;
       
   675     if (!d->dir) {
       
   676         return decode_error(errno);
       
   677     }
       
   678     s->arg[0] = add_dir_cache_entry(s, d);
       
   679     DPRINTF("Handle %d\n", s->arg[0]);
       
   680 #endif
       
   681     return HOST_FS_SUCCESS;
       
   682 }
       
   683 
       
   684 static int hostfs_file_close(syborg_hostfs_state *s)
       
   685 {
       
   686     int handle = s->arg[0];
       
   687     int fd;
       
   688     int err;
       
   689 
       
   690     err = get_file_cache_entry(s, handle, &fd);
       
   691     if (err)
       
   692         return err;
       
   693     err = close(fd);
       
   694     if (err)
       
   695         return decode_error(err);
       
   696     remove_file_cache_entry(s, handle);
       
   697 
       
   698     return HOST_FS_SUCCESS;
       
   699 }
       
   700 
       
   701 static int hostfs_dir_close(syborg_hostfs_state *s)
       
   702 {
       
   703     int handle = s->arg[0];
       
   704     hostfs_dir *d;
       
   705     int err;
       
   706 
       
   707     err = get_dir_cache_entry(s, handle, &d);
       
   708     if (err)
       
   709         return err;
       
   710 #ifdef _WIN32
       
   711     _findclose(d->handle);
       
   712 #else
       
   713     closedir(d->dir);
       
   714 #endif
       
   715     qemu_free(d);
       
   716     remove_dir_cache_entry(s, handle);
       
   717 
       
   718     return HOST_FS_SUCCESS;
       
   719 }
       
   720 
       
   721 static int hostfs_dir_read(syborg_hostfs_state *s)
       
   722 {
       
   723     int handle = s->arg[0];
       
   724     hostfs_dir *d;
       
   725     int err;
       
   726 
       
   727     err = get_dir_cache_entry(s, handle, &d);
       
   728     if (err)
       
   729         return err;
       
   730 #ifdef _WIN32
       
   731     {
       
   732     int name_len;
       
   733     if (d->handle == -1) {
       
   734         return HOST_FS_EOF;
       
   735     }
       
   736     name_len = wcslen(d->info.name);
       
   737     if (name_len >= s->arg[2])
       
   738         return HOST_FS_TOO_BIG;
       
   739     cpu_physical_memory_write(s->arg[1], (void *)d->info.name,
       
   740                               (name_len + 1) * 2);
       
   741     s->arg[3] = name_len;
       
   742 
       
   743     s->arg[0] = 0;
       
   744     if (d->info.attrib & _A_RDONLY)
       
   745         s->arg[0] |= HOSTFS_ATTR_READONLY;
       
   746     if (d->info.attrib & _A_HIDDEN)
       
   747         s->arg[0] |= HOSTFS_ATTR_HIDDEN;
       
   748     if (d->info.attrib & _A_SUBDIR)
       
   749         s->arg[0] |= HOSTFS_ATTR_DIRECTORY;
       
   750     s->arg[1] = d->info.time_write;
       
   751     s->arg[2] = d->info.size;
       
   752 
       
   753     err = _wfindnext(d->handle, &d->info);
       
   754     if (err)
       
   755         d->handle = -1;
       
   756     }
       
   757 #else
       
   758     {
       
   759     struct dirent *de;
       
   760     uint16_t unicode_name[HOSTFS_PATH_MAX];
       
   761     char full_name[HOSTFS_PATH_MAX];
       
   762     char *inp;
       
   763     char *outp;
       
   764     size_t outbytes;
       
   765     size_t inbytes;
       
   766     struct stat stat_buf;
       
   767 
       
   768     de = NULL;
       
   769     while (!de) {
       
   770         de = readdir(d->dir);
       
   771         if (!de) {
       
   772             err = errno;
       
   773             if (err == EAGAIN)
       
   774                 return HOST_FS_EOF;
       
   775             return decode_error(errno);
       
   776         }
       
   777         if (d->pattern[0] && fnmatch(d->pattern, de->d_name, 0))
       
   778             de = NULL;
       
   779     }
       
   780     inp = de->d_name;
       
   781     DPRINTF("dirent %s\n", de->d_name);
       
   782     outp = (char *)unicode_name;
       
   783     inbytes = strlen(inp) + 1;
       
   784     outbytes = HOSTFS_PATH_MAX;
       
   785     err = iconv(s->iconv_host_to_guest, &inp, &inbytes, &outp, &outbytes);
       
   786     if (err == -1)
       
   787         return decode_error(errno);
       
   788     outbytes = HOSTFS_PATH_MAX - outbytes;
       
   789     if (outbytes > s->arg[2] * 2)
       
   790         return HOST_FS_TOO_BIG;
       
   791     cpu_physical_memory_write(s->arg[1], (void *)unicode_name, outbytes);
       
   792     s->arg[3] = (outbytes >> 1) - 1;
       
   793 
       
   794     snprintf(full_name, HOSTFS_PATH_MAX, "%s/%s", d->path, de->d_name);
       
   795     err = lstat(full_name, &stat_buf);
       
   796     if (err < 0)
       
   797         return decode_error(errno);
       
   798 
       
   799     s->arg[0] = hostfs_map_file_att(stat_buf.st_mode); /*  attributes */
       
   800     s->arg[1] = stat_buf.st_mtime;              /*  modified time */
       
   801     s->arg[2] = stat_buf.st_size;               /*  file size */
       
   802     }
       
   803 #endif
       
   804     return HOST_FS_SUCCESS;
       
   805 }
       
   806 
       
   807 static int hostfs_file_read(syborg_hostfs_state *s)
       
   808 {
       
   809     uint8_t buf[0x1000];
       
   810     int handle = s->arg[0];
       
   811     int pos = s->arg[1];
       
   812     uint32_t addr = s->arg[2];
       
   813     int len = s->arg[3];
       
   814     int fd;
       
   815     int bit;
       
   816     int err;
       
   817 
       
   818     err = get_file_cache_entry(s, handle, &fd);
       
   819     if (err)
       
   820         return err;
       
   821 
       
   822     err = lseek(fd, pos, SEEK_SET);
       
   823     if (err == -1)
       
   824       return decode_error(errno);
       
   825 
       
   826     while (len) {
       
   827         if (len > 0x1000)
       
   828             bit = 0x1000;
       
   829         else
       
   830             bit = len;
       
   831         bit = uninterrupted_read(fd, buf, bit);
       
   832         if (bit == -1) {
       
   833             s->arg[0] = -1;
       
   834             return decode_error(errno);
       
   835         }
       
   836         if (bit == 0)
       
   837             break;
       
   838         cpu_physical_memory_write(addr, buf, bit);
       
   839         addr += bit;
       
   840         len -= bit;
       
   841     }
       
   842     s->arg[0] = s->arg[3] - len;
       
   843 
       
   844     return HOST_FS_SUCCESS;
       
   845 }
       
   846 
       
   847 static int hostfs_file_write(syborg_hostfs_state *s)
       
   848 {
       
   849     uint8_t buf[0x1000];
       
   850     int handle = s->arg[0];
       
   851     int pos = s->arg[1];
       
   852     uint32_t addr = s->arg[2];
       
   853     int len = s->arg[3];
       
   854     int fd;
       
   855     int bit;
       
   856     int err;
       
   857 
       
   858     err = get_file_cache_entry(s, handle, &fd);
       
   859     if (err)
       
   860         return err;
       
   861 
       
   862     err = lseek(fd, pos, SEEK_SET);
       
   863     if (err == -1)
       
   864       return decode_error(errno);
       
   865 
       
   866     while (len) {
       
   867         if (len > 0x1000)
       
   868             bit = 0x1000;
       
   869         else
       
   870             bit = len;
       
   871         cpu_physical_memory_read(addr, buf, bit);
       
   872         bit = uninterrupted_write(fd, buf, bit);
       
   873         if (bit == -1)
       
   874             return decode_error(errno);
       
   875         if (bit == 0)
       
   876             break;
       
   877         addr += bit;
       
   878         len -= bit;
       
   879     }
       
   880     s->arg[0] = s->arg[3] - len;
       
   881 
       
   882     return HOST_FS_SUCCESS;
       
   883 }
       
   884 
       
   885 static int hostfs_set_size(syborg_hostfs_state * s)
       
   886 {
       
   887     int handle = s->arg[0];
       
   888     int fd;
       
   889     int err;
       
   890 
       
   891     err = get_file_cache_entry(s, handle, &fd);
       
   892     if (err)
       
   893         return err;
       
   894 
       
   895     err = ftruncate(fd, s->arg[1]);
       
   896     if (err)
       
   897         return decode_error(errno);
       
   898 
       
   899     return HOST_FS_SUCCESS;
       
   900 }
       
   901 
       
   902 static int hostfs_flush(syborg_hostfs_state * s)
       
   903 {
       
   904     int handle = s->arg[0];
       
   905     int fd;
       
   906     int err;
       
   907 
       
   908     err = get_file_cache_entry(s, handle, &fd);
       
   909     if (err)
       
   910         return err;
       
   911 
       
   912 #ifdef _WIN32
       
   913     FlushFileBuffers((HANDLE)_get_osfhandle(fd));
       
   914 #else
       
   915     fsync(fd);
       
   916 #endif
       
   917 
       
   918     return HOST_FS_SUCCESS;
       
   919 }
       
   920 
       
   921 static syborg_hostfs_op_fn syborg_hostfs_ops[] =
       
   922 {
       
   923     hostfs_unsupported,          /*  EDummy */
       
   924         
       
   925     /*  CMountCB operations */
       
   926     hostfs_mkdir,                /*  EMkDir, */
       
   927     hostfs_rmdir,                /*  ERmDir, */
       
   928     hostfs_delete,               /*  EDelete, */
       
   929     hostfs_rename,               /*  ERename, */
       
   930     hostfs_replace,              /*  EReplace, */
       
   931     hostfs_unsupported,          /*  EReadUid, */
       
   932     hostfs_entry,                /*  EEntry, */
       
   933     hostfs_set_entry,            /*  EEntry, */
       
   934     hostfs_file_open,            /*  EFileOpen, */
       
   935     hostfs_dir_open,             /*  EDirOpen, */
       
   936     
       
   937     /*  CFileCB operations */
       
   938     hostfs_file_close,           /*  EFileClose,  */
       
   939     hostfs_file_read,            /*  EFileRead, */
       
   940     hostfs_file_write,           /*  EFileWrite, */
       
   941     hostfs_set_size,             /*  EFileSetSize, */
       
   942     hostfs_flush,                /*  EFileFlushAll, */
       
   943 
       
   944     /*  CMountCB operations */
       
   945     hostfs_dir_close,            /*  EDirClose, */
       
   946     hostfs_dir_read,             /*  EDirRead, */
       
   947 };
       
   948 
       
   949 static uint32_t syborg_hostfs_read(void *opaque, target_phys_addr_t offset)
       
   950 {
       
   951     syborg_hostfs_state *s = (syborg_hostfs_state *)opaque;
       
   952     
       
   953     offset &= 0xfff;
       
   954     DPRINTF("read 0x%x\n", (int)offset);
       
   955     switch(offset >>2) {
       
   956     case HOSTFS_ID:
       
   957         return SYBORG_ID_HOSTFS;
       
   958     case HOSTFS_COMMAND:
       
   959         return s->command;
       
   960     case HOSTFS_RESULT:
       
   961         return s->result;
       
   962     case HOSTFS_ARG0:
       
   963         return s->arg[0];
       
   964     case HOSTFS_ARG1:
       
   965         return s->arg[1];
       
   966     case HOSTFS_ARG2:
       
   967         return s->arg[2];
       
   968     case HOSTFS_ARG3:
       
   969         return s->arg[3];
       
   970 
       
   971     default:
       
   972         cpu_abort(cpu_single_env, "syborg_hostfs_read: Bad offset %x\n",
       
   973                   (int)offset);
       
   974         return 0;  
       
   975     }
       
   976 }
       
   977 
       
   978 static void syborg_hostfs_write(void *opaque, target_phys_addr_t offset,
       
   979                                 uint32_t value)
       
   980 {
       
   981     syborg_hostfs_state *s = (syborg_hostfs_state *)opaque;
       
   982     
       
   983     offset &= 0xfff;
       
   984     DPRINTF("Write 0x%x=0x%x\n", (int)offset, value);
       
   985     switch (offset >> 2) {
       
   986     case HOSTFS_COMMAND:
       
   987         s->command = value;
       
   988         if (s->command >= ARRAY_SIZE(syborg_hostfs_ops)) {
       
   989             DPRINTF("Bad command %d\n", s->command);
       
   990             s->result = HOST_FS_UNSUPPORTED;
       
   991         } else {
       
   992             s->result = syborg_hostfs_ops[s->command](s);
       
   993             DPRINTF("Result %d\n", s->result);
       
   994         }
       
   995         break;
       
   996     case HOSTFS_RESULT:
       
   997         s->result = value;
       
   998         break;
       
   999     case HOSTFS_ARG0:
       
  1000         s->arg[0] = value;
       
  1001         break;
       
  1002     case HOSTFS_ARG1:
       
  1003         s->arg[1] = value;
       
  1004         break;
       
  1005     case HOSTFS_ARG2:
       
  1006         s->arg[2] = value;
       
  1007         break;
       
  1008     case HOSTFS_ARG3:
       
  1009         s->arg[3] = value;
       
  1010         break;
       
  1011     default:
       
  1012         cpu_abort(cpu_single_env, "syborg_hostfs_write: Bad offset %x\n",
       
  1013                   (int)offset);
       
  1014         break;
       
  1015     }
       
  1016 }
       
  1017 
       
  1018 static CPUReadMemoryFunc *syborg_hostfs_readfn[] = {
       
  1019      syborg_hostfs_read,
       
  1020      syborg_hostfs_read,
       
  1021      syborg_hostfs_read
       
  1022 };
       
  1023 
       
  1024 static CPUWriteMemoryFunc *syborg_hostfs_writefn[] = {
       
  1025      syborg_hostfs_write,
       
  1026      syborg_hostfs_write,
       
  1027      syborg_hostfs_write
       
  1028 };
       
  1029 
       
  1030 static void syborg_hostfs_reset(void *opaque)
       
  1031 {
       
  1032     syborg_hostfs_state *s = opaque;
       
  1033     hostfs_handle_cache *p;
       
  1034     s->command = 0;
       
  1035     s->arg[0] = s->arg[1] = s->arg[2] = s->arg[3] = 0;
       
  1036     s->result = 0;
       
  1037     /* Close all open handles.  */
       
  1038     for (p = s->handle_cache; p; p = p->next) {
       
  1039         if (p->is_fd) {
       
  1040             close(p->val.fd);
       
  1041         } else {
       
  1042 #ifdef _WIN32
       
  1043             _findclose(p->val.d->handle);
       
  1044 #else
       
  1045             closedir(p->val.d->dir);
       
  1046 #endif
       
  1047             qemu_free(p->val.d);
       
  1048         }
       
  1049         if (!p->next) {
       
  1050             p->next = s->free_handle;
       
  1051             s->free_handle = s->handle_cache;
       
  1052             break;
       
  1053         }
       
  1054     }
       
  1055 }
       
  1056 
       
  1057 static void syborg_hostfs_save(QEMUFile *f, void *opaque)
       
  1058 {
       
  1059     syborg_hostfs_state *s = opaque;
       
  1060 
       
  1061     qemu_put_be32(f, s->command);
       
  1062     qemu_put_be32(f, s->result);
       
  1063     qemu_put_be32(f, s->arg[0]);
       
  1064     qemu_put_be32(f, s->arg[1]);
       
  1065     qemu_put_be32(f, s->arg[2]);
       
  1066     qemu_put_be32(f, s->arg[3]);
       
  1067     /* If the guest has any handles open then restoring state is
       
  1068        probably going to break stuff.  */
       
  1069     qemu_put_be32(f, s->handle_cache != NULL);
       
  1070 }
       
  1071 
       
  1072 static int syborg_hostfs_load(QEMUFile *f, void *opaque, int version_id)
       
  1073 {
       
  1074     syborg_hostfs_state *s = opaque;
       
  1075     int broken;
       
  1076 
       
  1077     if (version_id != 1)
       
  1078         return -EINVAL;
       
  1079 
       
  1080     /* Reset the device to clear out any open handles.  */
       
  1081     syborg_hostfs_reset(s);
       
  1082     s->command = qemu_get_be32(f);
       
  1083     s->result = qemu_get_be32(f);
       
  1084     s->arg[0] = qemu_get_be32(f);
       
  1085     s->arg[1] = qemu_get_be32(f);
       
  1086     s->arg[2] = qemu_get_be32(f);
       
  1087     s->arg[3] = qemu_get_be32(f);
       
  1088     broken = qemu_get_be32(f);
       
  1089     if (broken) {
       
  1090         fprintf(stderr, "syborg_hostfs: Open files lost after restore\n");
       
  1091         s->result = HOST_FS_GENERAL_ERROR;
       
  1092     }
       
  1093     return 0;
       
  1094 }
       
  1095 
       
  1096 static void syborg_hostfs_create(QEMUDevice *dev)
       
  1097 {
       
  1098     syborg_hostfs_state *s;
       
  1099     int drive;
       
  1100     s = (syborg_hostfs_state *)qemu_mallocz(sizeof(syborg_hostfs_state));
       
  1101     s->qdev = dev;
       
  1102     qdev_set_opaque(dev, s);
       
  1103     drive = qdev_get_property_int(dev, "drive-number");
       
  1104     if (drive == 0 || drive > 26) {
       
  1105         fprintf(stderr, "syborg_hostfs: Bad drive-number");
       
  1106         exit(1);
       
  1107     }
       
  1108     s->drive_letter = drive + 'A' - 1;
       
  1109     {
       
  1110     int i;
       
  1111 #ifdef _WIN32
       
  1112     const char *str = qdev_get_property_string(dev, "host-path");
       
  1113     int len = _mbslen(str);
       
  1114     s->host_prefix = (wchar_t *)qemu_mallocz((len + 1) * 2);
       
  1115     mbstowcs(s->host_prefix, str, len + 1);
       
  1116     s->host_prefix_len = wcslen(s->host_prefix);
       
  1117     for (i = 0; i < s->host_prefix_len; i++) {
       
  1118         if (s->host_prefix[i] == '/')
       
  1119             s->host_prefix[i] = '\\';
       
  1120     }
       
  1121 #else
       
  1122     s->host_prefix = qemu_strdup(qdev_get_property_string(dev, "host-path"));
       
  1123     s->host_prefix_len = strlen(s->host_prefix);
       
  1124     for (i = 0; i < s->host_prefix_len; i++) {
       
  1125         if (s->host_prefix[i] == '\\')
       
  1126             s->host_prefix[i] = '/';
       
  1127     }
       
  1128     setlocale(LC_ALL, "");
       
  1129     DPRINTF("Host charset: %s\n", nl_langinfo(CODESET));
       
  1130     s->iconv_guest_to_host = iconv_open(nl_langinfo(CODESET), "UTF-16LE");
       
  1131     s->iconv_host_to_guest = iconv_open("UTF-16LE", nl_langinfo(CODESET));
       
  1132 #endif
       
  1133     }
       
  1134 }
       
  1135 
       
  1136 void syborg_hostfs_register(void)
       
  1137 {
       
  1138     QEMUDeviceClass *dc;
       
  1139     dc = qdev_new("syborg,hostfs", syborg_hostfs_create, 0);
       
  1140     qdev_add_registers(dc, syborg_hostfs_readfn, syborg_hostfs_writefn, 0x1000);
       
  1141     qdev_add_property_int(dc, "drive-number", 14);
       
  1142     qdev_add_property_string(dc, "host-path", "./");
       
  1143     qdev_add_savevm(dc, 1, syborg_hostfs_save, syborg_hostfs_load);
       
  1144 }