minimig: support for shared folder.
This commit is contained in:
@@ -30,7 +30,7 @@
|
||||
<NMakeOutput>MiSTer</NMakeOutput>
|
||||
<NMakeCleanCommandLine>git.lnk ./clean.sh</NMakeCleanCommandLine>
|
||||
<NMakePreprocessorDefinitions>__arm__;__GNUC__;__USE_GNU ;_GNU_SOURCE;VDATE="000000";_FILE_OFFSET_BITS=64;_LARGEFILE64_SOURCE;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>
|
||||
<NMakeIncludeSearchPath>c:\Work\Git\opt\gcc54\arm-linux-gnueabihf\libc\usr\include;c:\Work\Git\opt\gcc54\lib\gcc\arm-linux-gnueabihf\5.4.1\include;c:\Work\Git\opt\gcc54\arm-linux-gnueabihf\include\c++\5.4.1;$(NMakeIncludeSearchPath);lib\libco;lib\miniz;lib\lodepng</NMakeIncludeSearchPath>
|
||||
<NMakeIncludeSearchPath>c:\Work\Git\opt\gcc54\arm-linux-gnueabihf\libc\usr\include;c:\Work\Git\opt\gcc54\lib\gcc\arm-linux-gnueabihf\5.4.1\include;c:\Work\Git\opt\gcc54\arm-linux-gnueabihf\include\c++\5.4.1;c:\Work\Git\opt\gcc54\arm-linux-gnueabihf\include\c++\5.4.1\arm-linux-gnueabihf;$(NMakeIncludeSearchPath);lib\libco;lib\miniz;lib\lodepng</NMakeIncludeSearchPath>
|
||||
<OutDir>$(TEMP)</OutDir>
|
||||
<IntDir>$(TEMP)</IntDir>
|
||||
<AdditionalOptions>
|
||||
@@ -86,6 +86,7 @@
|
||||
<ClCompile Include="support\minimig\minimig_config.cpp" />
|
||||
<ClCompile Include="support\minimig\minimig_fdd.cpp" />
|
||||
<ClCompile Include="support\minimig\minimig_hdd.cpp" />
|
||||
<ClCompile Include="support\minimig\minimig_share.cpp" />
|
||||
<ClCompile Include="support\neogeo\neogeo_loader.cpp" />
|
||||
<ClCompile Include="support\pcecd\pcecd.cpp" />
|
||||
<ClCompile Include="support\pcecd\pcecdd.cpp" />
|
||||
@@ -142,11 +143,13 @@
|
||||
<ClInclude Include="support\archie\archie.h" />
|
||||
<ClInclude Include="support\c64\c64.h" />
|
||||
<ClInclude Include="support\megacd\megacd.h" />
|
||||
<ClInclude Include="support\minimig\miminig_fs_messages.h" />
|
||||
<ClInclude Include="support\minimig\minimig_boot.h" />
|
||||
<ClInclude Include="support\minimig\minimig_config.h" />
|
||||
<ClInclude Include="support\minimig\minimig_fdd.h" />
|
||||
<ClInclude Include="support\minimig\minimig_hdd.h" />
|
||||
<ClInclude Include="support\minimig\minimig_hdd_internal.h" />
|
||||
<ClInclude Include="support\minimig\minimig_share.h" />
|
||||
<ClInclude Include="support\neogeo\neogeo_loader.h" />
|
||||
<ClInclude Include="support\pcecd\pcecd.h" />
|
||||
<ClInclude Include="support\sharpmz\sharpmz.h" />
|
||||
|
||||
@@ -196,6 +196,9 @@
|
||||
<ClCompile Include="audio.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="support\minimig\minimig_share.cpp">
|
||||
<Filter>Source Files\support</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="battery.h">
|
||||
@@ -369,5 +372,11 @@
|
||||
<ClInclude Include="audio.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="support\minimig\minimig_share.h">
|
||||
<Filter>Header Files\support</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="support\minimig\miminig_fs_messages.h">
|
||||
<Filter>Header Files\support</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "support/minimig/minimig_boot.h"
|
||||
#include "support/minimig/minimig_fdd.h"
|
||||
#include "support/minimig/minimig_hdd.h"
|
||||
#include "support/minimig/minimig_share.h"
|
||||
|
||||
// SharpMz support
|
||||
#include "support/sharpmz/sharpmz.h"
|
||||
|
||||
378
support/minimig/miminig_fs_messages.h
Normal file
378
support/minimig/miminig_fs_messages.h
Normal file
@@ -0,0 +1,378 @@
|
||||
#define ACTION_NIL 0
|
||||
#define ACTION_GET_BLOCK 2
|
||||
#define ACTION_SET_MAP 4
|
||||
#define ACTION_DIE 5
|
||||
#define ACTION_EVENT 6
|
||||
#define ACTION_CURRENT_VOLUME 7
|
||||
#define ACTION_LOCATE_OBJECT 8
|
||||
#define ACTION_RENAME_DISK 9
|
||||
#define ACTION_WRITE 'W'
|
||||
#define ACTION_READ 'R'
|
||||
#define ACTION_FREE_LOCK 15
|
||||
#define ACTION_DELETE_OBJECT 16
|
||||
#define ACTION_RENAME_OBJECT 17
|
||||
#define ACTION_MORE_CACHE 18
|
||||
#define ACTION_COPY_LOCK 19
|
||||
#define ACTION_WAIT_CHAR 20
|
||||
#define ACTION_SET_PROTECT 21
|
||||
#define ACTION_CREATE_DIR 22
|
||||
#define ACTION_EXAMINE_OBJECT 23
|
||||
#define ACTION_EXAMINE_NEXT 24
|
||||
#define ACTION_DISK_INFO 25
|
||||
#define ACTION_INFO 26
|
||||
#define ACTION_FLUSH 27
|
||||
#define ACTION_SET_COMMENT 28
|
||||
#define ACTION_PARENT 29
|
||||
#define ACTION_TIMER 30
|
||||
#define ACTION_INHIBIT 31
|
||||
#define ACTION_DISK_TYPE 32
|
||||
#define ACTION_DISK_CHANGE 33
|
||||
#define ACTION_SET_DATE 34
|
||||
#define ACTION_SCREEN_MODE 994
|
||||
#define ACTION_READ_RETURN 1001
|
||||
#define ACTION_WRITE_RETURN 1002
|
||||
#define ACTION_FINDUPDATE 1004
|
||||
#define ACTION_FINDINPUT 1005
|
||||
#define ACTION_FINDOUTPUT 1006
|
||||
#define ACTION_END 1007
|
||||
#define ACTION_SEEK 1008
|
||||
#define ACTION_TRUNCATE 1022
|
||||
#define ACTION_WRITE_PROTECT 1023
|
||||
|
||||
#define ERROR_NO_FREE_STORE 103
|
||||
#define ERROR_TASK_TABLE_FULL 105
|
||||
#define ERROR_LINE_TOO_LONG 120
|
||||
#define ERROR_FILE_NOT_OBJECT 121
|
||||
#define ERROR_INVALID_RESIDENT_LIBRARY 122
|
||||
#define ERROR_NO_DEFAULT_DIR 201
|
||||
#define ERROR_OBJECT_IN_USE 202
|
||||
#define ERROR_OBJECT_EXISTS 203
|
||||
#define ERROR_DIR_NOT_FOUND 204
|
||||
#define ERROR_OBJECT_NOT_FOUND 205
|
||||
#define ERROR_BAD_STREAM_NAME 206
|
||||
#define ERROR_OBJECT_TOO_LARGE 207
|
||||
#define ERROR_ACTION_NOT_KNOWN 209
|
||||
#define ERROR_INVALID_COMPONENT_NAME 210
|
||||
#define ERROR_INVALID_LOCK 211
|
||||
#define ERROR_OBJECT_WRONG_TYPE 212
|
||||
#define ERROR_DISK_NOT_VALIDATED 213
|
||||
#define ERROR_DISK_WRITE_PROTECTED 214
|
||||
#define ERROR_RENAME_ACROSS_DEVICES 215
|
||||
#define ERROR_DIRECTORY_NOT_EMPTY 216
|
||||
#define ERROR_TOO_MANY_LEVELS 217
|
||||
#define ERROR_DEVICE_NOT_MOUNTED 218
|
||||
#define ERROR_SEEK_ERROR 219
|
||||
#define ERROR_COMMENT_TOO_BIG 220
|
||||
#define ERROR_DISK_FULL 221
|
||||
#define ERROR_DELETE_PROTECTED 222
|
||||
#define ERROR_WRITE_PROTECTED 223
|
||||
#define ERROR_READ_PROTECTED 224
|
||||
#define ERROR_NOT_A_DOS_DISK 225
|
||||
#define ERROR_NO_DISK 226
|
||||
#define ERROR_NO_MORE_ENTRIES 232
|
||||
|
||||
#define SHARED_LOCK -2
|
||||
#define EXCLUSIVE_LOCK -1
|
||||
|
||||
#define MODE_OLDFILE 1005
|
||||
#define MODE_NEWFILE 1006
|
||||
#define MODE_READWRITE 1004
|
||||
|
||||
#define OFFSET_BEGINNING -1
|
||||
#define OFFSET_CURRENT 0
|
||||
#define OFFSET_END 1
|
||||
|
||||
#define ST_ROOT 1
|
||||
#define ST_USERDIR 2
|
||||
#define ST_SOFTLINK 3
|
||||
#define ST_LINKDIR 4
|
||||
#define ST_FILE -3
|
||||
#define ST_LINKFILE -4
|
||||
#define ST_PIPEFILE -5
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct GenericRequestResponse
|
||||
{
|
||||
long sz;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
long type;
|
||||
long key;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
long success;
|
||||
long error_code;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct LocateObjectRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long key;
|
||||
long mode;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
struct LocateObjectResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
long key;
|
||||
};
|
||||
|
||||
struct FreeLockRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long key;
|
||||
};
|
||||
|
||||
struct FreeLockResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
};
|
||||
|
||||
struct CopyDirRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long key;
|
||||
};
|
||||
|
||||
struct CopyDirResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
long key;
|
||||
};
|
||||
|
||||
struct ParentRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long key;
|
||||
};
|
||||
|
||||
struct ParentResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
long key;
|
||||
};
|
||||
|
||||
struct ExamineObjectRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long key;
|
||||
long disk_key;
|
||||
};
|
||||
|
||||
struct ExamineObjectResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
|
||||
long disk_key;
|
||||
long entry_type;
|
||||
int size;
|
||||
int protection;
|
||||
int date[3];
|
||||
char file_name[1];
|
||||
};
|
||||
|
||||
struct FindXxxRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long key;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
struct FindXxxResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
long arg1;
|
||||
};
|
||||
|
||||
struct ReadRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long arg1;
|
||||
int address;
|
||||
int length;
|
||||
};
|
||||
|
||||
struct ReadResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
int actual;
|
||||
};
|
||||
|
||||
struct WriteRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long arg1;
|
||||
int address;
|
||||
int length;
|
||||
};
|
||||
|
||||
struct WriteResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
int actual;
|
||||
};
|
||||
|
||||
struct SeekRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long arg1;
|
||||
int new_pos;
|
||||
int mode;
|
||||
};
|
||||
|
||||
struct SeekResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
int old_pos;
|
||||
};
|
||||
|
||||
struct EndRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long arg1;
|
||||
};
|
||||
|
||||
struct EndResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
};
|
||||
|
||||
struct DeleteObjectRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long key;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
struct DeleteObjectResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
};
|
||||
|
||||
struct RenameObjectRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long key;
|
||||
long target_dir;
|
||||
unsigned char name_len;
|
||||
unsigned char new_name_len;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
struct RenameObjectResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
};
|
||||
|
||||
struct CreateDirRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long key;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
struct CreateDirResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
long key;
|
||||
};
|
||||
|
||||
struct SetProtectRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long key;
|
||||
long mask;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
struct SetProtectResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
};
|
||||
|
||||
struct SetCommentRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long key;
|
||||
unsigned char name_len;
|
||||
unsigned char comment_len;
|
||||
};
|
||||
|
||||
struct SetCommentResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
};
|
||||
|
||||
struct DiskInfoRequest
|
||||
{
|
||||
long sz;
|
||||
long type;
|
||||
long key;
|
||||
long dummy1;
|
||||
long dummy2;
|
||||
};
|
||||
|
||||
struct DiskInfoResponse
|
||||
{
|
||||
long sz;
|
||||
long success;
|
||||
long error_code;
|
||||
unsigned long total;
|
||||
unsigned long used;
|
||||
long update;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "minimig_fdd.h"
|
||||
#include "minimig_hdd.h"
|
||||
#include "minimig_config.h"
|
||||
#include "minimig_share.h"
|
||||
|
||||
const char *config_memory_chip_msg[] = { "512K", "1M", "1.5M", "2M" };
|
||||
const char *config_memory_slow_msg[] = { "none", "512K", "1M", "1.5M" };
|
||||
@@ -502,6 +503,7 @@ void minimig_reset()
|
||||
{
|
||||
ApplyConfiguration(0);
|
||||
user_io_rtc_reset();
|
||||
minimig_share_reset();
|
||||
}
|
||||
|
||||
void minimig_set_kickstart(char *name)
|
||||
|
||||
751
support/minimig/minimig_share.cpp
Normal file
751
support/minimig/minimig_share.cpp
Normal file
@@ -0,0 +1,751 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../../hardware.h"
|
||||
#include "../../file_io.h"
|
||||
#include "../../user_io.h"
|
||||
#include "../../spi.h"
|
||||
#include "miminig_fs_messages.h"
|
||||
|
||||
#define SHMEM_ADDR 0x27FF4000
|
||||
#define SHMEM_SIZE 0x2000
|
||||
static uint8_t *shmem = 0;
|
||||
|
||||
#define REQUEST_FLG 0 // 4B
|
||||
#define REQUEST_BUFFER 4 // ~512B
|
||||
#define DATA_BUFFER 0x1000 // 4KB
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define dbg_print printf
|
||||
#define dbg_hexdump hexdump
|
||||
#else
|
||||
#define dbg_print(x,...) void()
|
||||
#define dbg_hexdump(x,...) void()
|
||||
#endif
|
||||
|
||||
#define SWAP_INT(a) ((((a)&0x000000ff)<<24)|(((a)&0x0000ff00)<<8)|(((a)&0x00ff0000)>>8)|(((a)&0xff000000)>>24))
|
||||
|
||||
static char basepath[1024] = {};
|
||||
static int baselen = 0;
|
||||
|
||||
struct lock
|
||||
{
|
||||
uint16_t mode;
|
||||
std::string path;
|
||||
std::vector<dirent64> dir_items;
|
||||
};
|
||||
|
||||
static std::map<uint32_t, lock> locks;
|
||||
static uint32_t next_key = 1;
|
||||
|
||||
static uint32_t get_key()
|
||||
{
|
||||
uint32_t key;
|
||||
|
||||
do
|
||||
{
|
||||
key = next_key;
|
||||
if (next_key == INT32_MAX) next_key = 1; else next_key++;
|
||||
|
||||
} while (locks.find(key) != locks.end());
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static uint32_t add_lock(uint16_t mode, const char* path)
|
||||
{
|
||||
uint32_t key = get_key();
|
||||
locks[key] = { mode, path, {} };
|
||||
|
||||
dbg_print("+ add lock: %d, %s\n", key, path);
|
||||
return key;
|
||||
}
|
||||
|
||||
static int has_locks(const char* path)
|
||||
{
|
||||
int has = 0;
|
||||
for (const auto &pair : locks)
|
||||
{
|
||||
if (pair.second.path == path)
|
||||
{
|
||||
if (!has)
|
||||
{
|
||||
dbg_print("! path %s has locks:", path);
|
||||
}
|
||||
|
||||
has = 1;
|
||||
dbg_print(" %d", pair.first);
|
||||
}
|
||||
}
|
||||
|
||||
if (has)
|
||||
{
|
||||
dbg_print("\n");
|
||||
}
|
||||
return has;
|
||||
}
|
||||
|
||||
static std::map<uint32_t, fileTYPE> open_file_handles;
|
||||
static uint32_t next_fp = 1;
|
||||
|
||||
static uint32_t get_fp()
|
||||
{
|
||||
uint32_t fp;
|
||||
|
||||
do
|
||||
{
|
||||
fp = next_fp;
|
||||
if (next_fp == INT32_MAX) next_fp = 1; else next_fp++;
|
||||
|
||||
} while (open_file_handles.find(fp) != open_file_handles.end());
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
static char* find_path(uint32_t key, const char *name)
|
||||
{
|
||||
dbg_print("find_path(%d, %s)\n", key, name);
|
||||
|
||||
static char str[1024] = {};
|
||||
const char* p = strchr(name, ':');
|
||||
if (p)
|
||||
{
|
||||
key = 0;
|
||||
name = p + 1;
|
||||
}
|
||||
|
||||
strcpy(str, basepath);
|
||||
if (key)
|
||||
{
|
||||
auto it = locks.find(key);
|
||||
if (it != locks.end()) strcpy(str, it->second.path.c_str());
|
||||
}
|
||||
|
||||
if (PathIsDir(str))
|
||||
{
|
||||
if (strlen(name))
|
||||
{
|
||||
strcat(str, "/");
|
||||
strcat(str, name);
|
||||
|
||||
dbg_print("check path: %s\n", str);
|
||||
char *p = strrchr(str, '/');
|
||||
if (!p) str[0] = 0;
|
||||
else
|
||||
{
|
||||
*p = 0;
|
||||
if (!PathIsDir(str)) str[0] = 0;
|
||||
else *p = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
str[0] = 0;
|
||||
}
|
||||
|
||||
dbg_print("returned path: %s\n", str);
|
||||
return str;
|
||||
}
|
||||
|
||||
static int process_request(void *reqres_buffer)
|
||||
{
|
||||
static char buf[1024];
|
||||
GenericRequestResponse *reqres = ( GenericRequestResponse *)reqres_buffer;
|
||||
|
||||
int rtype = SWAP_INT(reqres->type);
|
||||
int ret = ERROR_ACTION_NOT_KNOWN;
|
||||
|
||||
int sz = SWAP_INT(reqres->sz);
|
||||
((uint8_t*)reqres_buffer)[sz] = 0;
|
||||
|
||||
int sz_res = sizeof(GenericRequestResponse);
|
||||
|
||||
dbg_print("request type: %d, struct size: %d\n", rtype, sz);
|
||||
dbg_hexdump(reqres_buffer, sz, 0);
|
||||
|
||||
if (!baselen)
|
||||
{
|
||||
strcpy(basepath, HomeDir());
|
||||
strcat(basepath, "/shared");
|
||||
baselen = strlen(basepath);
|
||||
FileCreatePath(basepath);
|
||||
}
|
||||
|
||||
switch (rtype)
|
||||
{
|
||||
case ACTION_LOCATE_OBJECT:
|
||||
{
|
||||
dbg_print("> ACTION_LOCATE_OBJECT\n");
|
||||
LocateObjectRequest *req = (LocateObjectRequest*)reqres_buffer;
|
||||
LocateObjectResponse *res = (LocateObjectResponse*)reqres_buffer;
|
||||
sz_res = sizeof(LocateObjectResponse);
|
||||
|
||||
char *str = find_path(SWAP_INT(req->key), req->name + 1);
|
||||
if (!str[0])
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!FileExists(str) && !PathIsDir(str))
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t key = add_lock(req->mode, str);
|
||||
res->key = SWAP_INT(key);
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_FREE_LOCK:
|
||||
{
|
||||
dbg_print("> ACTION_FREE_LOCK\n");
|
||||
FreeLockRequest *req = (FreeLockRequest*)reqres_buffer;
|
||||
|
||||
uint32_t key = SWAP_INT(req->key);
|
||||
locks.erase(key);
|
||||
dbg_print(" lock: %d\n", key);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_COPY_LOCK:
|
||||
{
|
||||
dbg_print("> ACTION_COPY_LOCK\n");
|
||||
CopyDirRequest *req = (CopyDirRequest*)reqres_buffer;
|
||||
CopyDirResponse *res = (CopyDirResponse*)reqres_buffer;
|
||||
sz_res = sizeof(CopyDirResponse);
|
||||
|
||||
uint32_t key = SWAP_INT(req->key);
|
||||
if (locks.find(key) == locks.end())
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t new_key = add_lock(locks[key].mode, locks[key].path.c_str());
|
||||
dbg_print("CopyDir: %s: %d -> %d\n", locks[new_key].path.c_str(), key, new_key);
|
||||
|
||||
res->key = SWAP_INT(new_key);
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_PARENT:
|
||||
{
|
||||
dbg_print("> ACTION_PARENT\n");
|
||||
ParentRequest *req = (ParentRequest*)reqres_buffer;
|
||||
ParentResponse *res = (ParentResponse*)reqres_buffer;
|
||||
sz_res = sizeof(ParentResponse);
|
||||
|
||||
uint32_t key = SWAP_INT(req->key);
|
||||
dbg_print(" current key: %d\n", key);
|
||||
|
||||
if (locks.find(key) == locks.end())
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
res->key = 0;
|
||||
|
||||
char *name = buf;
|
||||
strcpy(name, locks[key].path.c_str());
|
||||
dbg_print(" current path: %s\n", name);
|
||||
|
||||
if (!strncasecmp(basepath, name, baselen)) name += baselen;
|
||||
|
||||
if (strlen(name))
|
||||
{
|
||||
char* p = strrchr(name, '/');
|
||||
if (p)
|
||||
{
|
||||
*p = 0;
|
||||
uint32_t key = add_lock(SHARED_LOCK, buf);
|
||||
res->key = SWAP_INT(key);
|
||||
dbg_print(" parent path: %s\n", buf);
|
||||
dbg_print(" parent path: %s\n", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_EXAMINE_NEXT:
|
||||
case ACTION_EXAMINE_OBJECT:
|
||||
{
|
||||
dbg_print("> ACTION_EXAMINE\n");
|
||||
ExamineObjectRequest *req = (ExamineObjectRequest*)reqres_buffer;
|
||||
ExamineObjectResponse *res = (ExamineObjectResponse*)reqres_buffer;
|
||||
sz_res = sizeof(ExamineObjectResponse);
|
||||
|
||||
uint32_t key = SWAP_INT(req->key);
|
||||
dbg_print(" key: %d\n", key);
|
||||
|
||||
char *name = buf;
|
||||
name[0] = 0;
|
||||
if (locks.find(key) != locks.end()) strcpy(name, locks[key].path.c_str());
|
||||
if (!strlen(name)) strcpy(name, basepath);
|
||||
|
||||
int disk_key = 666;
|
||||
static char fn[256];
|
||||
if (rtype == ACTION_EXAMINE_OBJECT)
|
||||
{
|
||||
dbg_print(" examine first\n");
|
||||
|
||||
if (!strlen(name + baselen)) strcpy(fn, "MiSTer");
|
||||
else
|
||||
{
|
||||
const char *p = strrchr(name, '/');
|
||||
strcpy(fn, p ? p + 1 : name);
|
||||
}
|
||||
|
||||
locks[key].dir_items.clear();
|
||||
if (PathIsDir(name))
|
||||
{
|
||||
const char* full_path = getFullPath(name);
|
||||
DIR *d = opendir(full_path);
|
||||
if (!d)
|
||||
{
|
||||
printf("Couldn't open dir: %s\n", full_path);
|
||||
ret = ERROR_OBJECT_WRONG_TYPE;
|
||||
break;
|
||||
}
|
||||
|
||||
struct dirent64 *de;
|
||||
while ((de = readdir64(d)))
|
||||
{
|
||||
if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) continue;
|
||||
locks[key].dir_items.push_back(*de);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_print(" examine next\n");
|
||||
|
||||
disk_key = SWAP_INT(req->disk_key);
|
||||
|
||||
uint32_t listed = disk_key - 666;
|
||||
disk_key++;
|
||||
|
||||
if (listed >= locks[key].dir_items.size())
|
||||
{
|
||||
locks[key].dir_items.clear();
|
||||
ret = ERROR_NO_MORE_ENTRIES;
|
||||
break;
|
||||
}
|
||||
|
||||
strcat(name, "/");
|
||||
strcat(name, locks[key].dir_items[listed].d_name);
|
||||
memcpy(fn, locks[key].dir_items[listed].d_name, sizeof(fn));
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
dbg_print(" name: %s\n", name);
|
||||
dbg_print(" fn: %s\n", fn);
|
||||
|
||||
int type = 0;
|
||||
if (FileExists(name)) type = ST_FILE;
|
||||
else if (PathIsDir(name)) type = ST_USERDIR;
|
||||
else
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
time_t time = 0;
|
||||
uint32_t size = 0;
|
||||
|
||||
struct stat64 *st = getPathStat(name);
|
||||
if (st)
|
||||
{
|
||||
time = st->st_mtime;
|
||||
if (type == ST_FILE)
|
||||
{
|
||||
if (st->st_size > UINT32_MAX) size = UINT32_MAX;
|
||||
else size = (uint32_t)st->st_size;
|
||||
}
|
||||
}
|
||||
|
||||
time_t days = time / 86400;
|
||||
time_t left = time - (days * 86400);
|
||||
time_t mins = left / 60;
|
||||
time_t secs = left - (mins * 60);
|
||||
time_t ticks = secs * 50;
|
||||
days -= 2922; // Days between 1970 - 01 - 01 and 1978 - 01 - 01
|
||||
if (days < 0) days = 0;
|
||||
|
||||
res->disk_key = SWAP_INT(disk_key);
|
||||
res->entry_type = SWAP_INT(type);
|
||||
res->size = SWAP_INT(size);
|
||||
res->protection = 0;
|
||||
res->date[0] = SWAP_INT(days);
|
||||
res->date[1] = SWAP_INT(mins);
|
||||
res->date[2] = SWAP_INT(ticks);
|
||||
|
||||
res->file_name[0] = strlen(fn);
|
||||
strcpy(res->file_name + 1, fn);
|
||||
|
||||
sz_res = sizeof(ExamineObjectResponse) + strlen(fn);
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_FINDINPUT: // MODE_OLDFILE
|
||||
case ACTION_FINDOUTPUT: // MODE_NEWFILE
|
||||
case ACTION_FINDUPDATE: // MODE_READWRITE
|
||||
{
|
||||
dbg_print("> ACTION_FIND\n");
|
||||
FindXxxRequest *req = (FindXxxRequest*)reqres_buffer;
|
||||
FindXxxResponse *res = (FindXxxResponse*)reqres_buffer;
|
||||
sz_res = sizeof(FindXxxResponse);
|
||||
|
||||
char *name = find_path(SWAP_INT(req->key), req->name + 1);
|
||||
|
||||
if (!name[0])
|
||||
{
|
||||
ret = ERROR_DIR_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
if (PathIsDir(name))
|
||||
{
|
||||
ret = ERROR_OBJECT_WRONG_TYPE;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t key = get_fp();
|
||||
open_file_handles[key] = {};
|
||||
|
||||
int mode = O_RDWR;
|
||||
|
||||
if (rtype == MODE_NEWFILE) mode = O_RDWR | O_CREAT | O_TRUNC;
|
||||
if (rtype == MODE_READWRITE) mode = O_RDWR | O_CREAT;
|
||||
|
||||
ret = FileOpenEx(&open_file_handles[key], name, mode);
|
||||
if (!ret)
|
||||
{
|
||||
open_file_handles.erase(key);
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
res->arg1 = SWAP_INT(key);
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_READ:
|
||||
{
|
||||
dbg_print("> ACTION_READ\n");
|
||||
ReadRequest *req = (ReadRequest*)reqres_buffer;
|
||||
ReadResponse *res = (ReadResponse*)reqres_buffer;
|
||||
sz_res = sizeof(ReadResponse);
|
||||
|
||||
uint32_t key = SWAP_INT(req->arg1);
|
||||
if (open_file_handles.find(key) == open_file_handles.end())
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t length = SWAP_INT(req->length);
|
||||
length = FileReadAdv(&open_file_handles[key], shmem + DATA_BUFFER, length);
|
||||
|
||||
res->actual = SWAP_INT(length);
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_WRITE:
|
||||
{
|
||||
dbg_print("> ACTION_WRITE\n");
|
||||
WriteRequest *req = (WriteRequest*)reqres_buffer;
|
||||
WriteResponse *res = (WriteResponse*)reqres_buffer;
|
||||
sz_res = sizeof(WriteResponse);
|
||||
|
||||
uint32_t key = SWAP_INT(req->arg1);
|
||||
if (open_file_handles.find(key) == open_file_handles.end())
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t length = SWAP_INT(req->length);
|
||||
length = FileWriteAdv(&open_file_handles[key], shmem + DATA_BUFFER, length);
|
||||
|
||||
res->actual = SWAP_INT(length);
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_SEEK:
|
||||
{
|
||||
dbg_print("> ACTION_SEEK\n");
|
||||
SeekRequest *req = (SeekRequest*)reqres_buffer;
|
||||
SeekResponse *res = (SeekResponse*)reqres_buffer;
|
||||
sz_res = sizeof(SeekResponse);
|
||||
|
||||
uint32_t key = SWAP_INT(req->arg1);
|
||||
if (open_file_handles.find(key) == open_file_handles.end())
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t old_pos = open_file_handles[key].offset;
|
||||
|
||||
uint32_t new_pos = SWAP_INT(req->new_pos);
|
||||
uint32_t mode = SWAP_INT(req->mode);
|
||||
|
||||
int origin = SEEK_SET;
|
||||
if (mode == OFFSET_CURRENT) origin = SEEK_CUR;
|
||||
if (mode == OFFSET_END) origin = SEEK_END;
|
||||
|
||||
ret = FileSeek(&open_file_handles[key], new_pos, origin);
|
||||
|
||||
dbg_print(" mode: %d\n", mode);
|
||||
dbg_print(" old_pos: %d\n", old_pos);
|
||||
dbg_print(" new_pos: %d\n", new_pos);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
ret = ERROR_SEEK_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
res->old_pos = SWAP_INT(old_pos);
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_END:
|
||||
{
|
||||
dbg_print("> ACTION_END\n");
|
||||
EndRequest *req = (EndRequest*)reqres_buffer;
|
||||
uint32_t key = SWAP_INT(req->arg1);
|
||||
|
||||
if (open_file_handles.find(key) != open_file_handles.end())
|
||||
{
|
||||
FileClose(&open_file_handles[key]);
|
||||
open_file_handles.erase(key);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_DELETE_OBJECT:
|
||||
{
|
||||
dbg_print("> ACTION_DELETE_OBJECT\n");
|
||||
DeleteObjectRequest *req = (DeleteObjectRequest*)reqres_buffer;
|
||||
|
||||
char *name = find_path(SWAP_INT(req->key), req->name + 1);
|
||||
if (name[0])
|
||||
{
|
||||
if (has_locks(name))
|
||||
{
|
||||
ret = ERROR_OBJECT_IN_USE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (PathIsDir(name))
|
||||
{
|
||||
ret = DirDelete(name) ? 0 : ERROR_DIRECTORY_NOT_EMPTY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (FileExists(name))
|
||||
{
|
||||
ret = FileDelete(name) ? 0 : ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_RENAME_OBJECT:
|
||||
{
|
||||
dbg_print("> ACTION_RENAME_OBJECT\n");
|
||||
RenameObjectRequest *req = (RenameObjectRequest*)reqres_buffer;
|
||||
|
||||
strncpy(buf, req->name, req->name_len);
|
||||
buf[req->name_len] = 0;
|
||||
|
||||
uint32_t key = SWAP_INT(req->key);
|
||||
char *cp1 = find_path(key, buf);
|
||||
if (!cp1[0])
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!FileExists(cp1) && !PathIsDir(cp1))
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy(buf, cp1);
|
||||
key = SWAP_INT(req->target_dir);
|
||||
char *cp2 = find_path(key, req->name + req->name_len);
|
||||
if (!cp2[0])
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
if (FileExists(cp2) || PathIsDir(cp2))
|
||||
{
|
||||
ret = ERROR_OBJECT_EXISTS;
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy(buf, getFullPath(buf));
|
||||
if (rename(buf, getFullPath(cp2)))
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_CREATE_DIR:
|
||||
{
|
||||
dbg_print("> ACTION_CREATE_DIR\n");
|
||||
CreateDirRequest *req = (CreateDirRequest*)reqres_buffer;
|
||||
CreateDirResponse *res = (CreateDirResponse*)reqres_buffer;
|
||||
sz_res = sizeof(CreateDirResponse);
|
||||
|
||||
char *name = find_path(SWAP_INT(req->key), req->name + 1);
|
||||
if (!FileCreatePath(name))
|
||||
{
|
||||
ret = ERROR_OBJECT_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t key = add_lock(SHARED_LOCK, name);
|
||||
res->key = SWAP_INT(key);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_DISK_INFO:
|
||||
case ACTION_INFO:
|
||||
{
|
||||
dbg_print("> ACTION_INFO\n");
|
||||
DiskInfoResponse *res = (DiskInfoResponse*)reqres_buffer;
|
||||
sz_res = sizeof(DiskInfoResponse);
|
||||
|
||||
uint32_t total = 10;
|
||||
uint32_t used = 1;
|
||||
|
||||
struct statvfs st;
|
||||
if (!statvfs(getFullPath(basepath), &st))
|
||||
{
|
||||
uint64_t sz = st.f_bsize * st.f_blocks;
|
||||
uint64_t avail = st.f_bsize * st.f_bavail;
|
||||
|
||||
total = sz / 512;
|
||||
used = (sz - avail) / 512;
|
||||
}
|
||||
|
||||
res->total = SWAP_INT(total);
|
||||
res->used = SWAP_INT(used);
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_SET_PROTECT:
|
||||
{
|
||||
dbg_print("> ACTION_SET_PROTECT unimplemented\n");
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_SET_COMMENT:
|
||||
{
|
||||
dbg_print("> ACTION_SET_COMMENT unimplemented\n");
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
int success = ret ? 0 : 1;
|
||||
reqres->success = SWAP_INT(success);
|
||||
reqres->error_code = SWAP_INT(ret);
|
||||
|
||||
dbg_print("error: %d\n", ret);
|
||||
dbg_hexdump(shmem + REQUEST_BUFFER, sz_res, 0);
|
||||
dbg_print("\n");
|
||||
|
||||
return sz_res;
|
||||
}
|
||||
|
||||
static void share_init()
|
||||
{
|
||||
int fd;
|
||||
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) return;
|
||||
|
||||
shmem = (uint8_t*)mmap(0, SHMEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, SHMEM_ADDR);
|
||||
close(fd);
|
||||
|
||||
if (shmem == (uint8_t *)-1) printf("minimig_setup_shmem: Unable to mmap(/dev/mem)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
void minimig_share_poll()
|
||||
{
|
||||
if (!shmem)
|
||||
{
|
||||
share_init();
|
||||
}
|
||||
else if(shmem != (uint8_t *)-1)
|
||||
{
|
||||
static uint32_t old_req_id = 0;
|
||||
uint32_t req_id = *(uint32_t*)(shmem + REQUEST_FLG);
|
||||
|
||||
if ((uint16_t)old_req_id != (uint16_t)req_id)
|
||||
{
|
||||
dbg_print("new req: %08X\n", req_id);
|
||||
old_req_id = req_id;
|
||||
if (((req_id>>16) & 0xFFFF) == 0x5AA5 && ((req_id - 77) & 0xFF) == ((req_id >> 8) & 0xFF))
|
||||
{
|
||||
process_request(shmem + REQUEST_BUFFER);
|
||||
*(uint16_t*)(shmem + REQUEST_FLG + 2) = (uint16_t)req_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void minimig_share_reset()
|
||||
{
|
||||
open_file_handles.clear();
|
||||
locks.clear();
|
||||
next_fp = 1;
|
||||
next_key = 1;
|
||||
}
|
||||
10
support/minimig/minimig_share.h
Normal file
10
support/minimig/minimig_share.h
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
#ifndef __MINIMIG_SHARE_H__
|
||||
#define __MINIMIG_SHARE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void minimig_share_poll();
|
||||
void minimig_share_reset();
|
||||
|
||||
#endif
|
||||
@@ -2165,13 +2165,14 @@ void user_io_poll()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!rtc_timer || CheckTimer(rtc_timer))
|
||||
{
|
||||
// Update once per minute should be enough
|
||||
rtc_timer = GetTimer(60000);
|
||||
send_rtc(1);
|
||||
}
|
||||
|
||||
minimig_share_poll();
|
||||
}
|
||||
|
||||
if (core_type == CORE_TYPE_8BIT && !is_menu())
|
||||
|
||||
Reference in New Issue
Block a user