855 lines
42 KiB
C#
855 lines
42 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Windows.Forms;
|
|
using System.Net.Sockets;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Collections.Generic;
|
|
|
|
namespace saviine_server
|
|
{
|
|
class Program
|
|
{
|
|
public const byte BYTE_NORMAL = 0xff;
|
|
public const byte BYTE_SPECIAL = 0xfe;
|
|
public const byte BYTE_OPEN = 0x00;
|
|
public const byte BYTE_READ = 0x01;
|
|
public const byte BYTE_CLOSE = 0x02;
|
|
public const byte BYTE_OK = 0x03;
|
|
public const byte BYTE_SETPOS = 0x04;
|
|
//public const byte BYTE_STATFILE = 0x05;
|
|
//public const byte BYTE_EOF = 0x06;
|
|
//public const byte BYTE_GETPOS = 0x07;
|
|
public const byte BYTE_REQUEST = 0x08;
|
|
public const byte BYTE_REQUEST_SLOW = 0x09;
|
|
public const byte BYTE_HANDLE = 0x0A;
|
|
public const byte BYTE_DUMP = 0x0B;
|
|
public const byte BYTE_PING = 0x0C;
|
|
public const byte BYTE_G_MODE = 0x0D;
|
|
public const byte BYTE_MODE_D = 0x0E;
|
|
public const byte BYTE_MODE_I = 0x0F;
|
|
public const byte BYTE_CLOSE_DUMP = 0x10;
|
|
public const byte BYTE_LOG_STR = 0xFB;
|
|
public const byte BYTE_FILE = 0xC0;
|
|
public const byte BYTE_FOLDER = 0xC1;
|
|
public const byte BYTE_READ_DIR = 0xCC;
|
|
public const byte BYTE_INJECTSTART = 0x40;
|
|
public const byte BYTE_INJECTEND = 0x41;
|
|
public const byte BYTE_DUMPSTART = 0x42;
|
|
public const byte BYTE_DUMPEND = 0x43;
|
|
public const byte BYTE_END = 0xfd;
|
|
|
|
|
|
public const int MASK_NORMAL = 0x8000;
|
|
public const int MASK_USER = 0x0100;
|
|
public const int MASK_COMMON = 0x0200;
|
|
public const int MASK_COMMON_CLEAN = 0x0400;
|
|
|
|
|
|
private static long currentPersistentID = 0x0;
|
|
private static long COMMON_PERSISTENTID = 0x1;
|
|
|
|
|
|
[Flags]
|
|
public enum FSStatFlag : uint
|
|
{
|
|
None = 0,
|
|
unk_14_present = 0x01000000,
|
|
mtime_present = 0x04000000,
|
|
ctime_present = 0x08000000,
|
|
entid_present = 0x10000000,
|
|
directory = 0x80000000,
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct FSStat
|
|
{
|
|
public FSStatFlag flags;
|
|
public uint permission;
|
|
public uint owner;
|
|
public uint group;
|
|
public uint file_size;
|
|
public uint unk_14_nonzero;
|
|
public uint unk_18_zero;
|
|
public uint unk_1c_zero;
|
|
public uint ent_id;
|
|
public uint ctime_u;
|
|
public uint ctime_l;
|
|
public uint mtime_u;
|
|
public uint mtime_l;
|
|
public uint unk_34_zero;
|
|
public uint unk_38_zero;
|
|
public uint unk_3c_zero;
|
|
public uint unk_40_zero;
|
|
public uint unk_44_zero;
|
|
public uint unk_48_zero;
|
|
public uint unk_4c_zero;
|
|
public uint unk_50_zero;
|
|
public uint unk_54_zero;
|
|
public uint unk_58_zero;
|
|
public uint unk_5c_zero;
|
|
public uint unk_60_zero;
|
|
}
|
|
|
|
public static string root = "saviine_root";
|
|
public static string logs_root = "logs";
|
|
public static string injectfolder = "inject";
|
|
public static string dumpfolder = "dump";
|
|
public static string common = "common";
|
|
|
|
const uint BUFFER_SIZE = 64 * 1024;
|
|
static Boolean fastmode = false;
|
|
static byte op_mode = BYTE_MODE_D;
|
|
[STAThread]
|
|
static void Main(string[] args)
|
|
{
|
|
if (args.Length > 1)
|
|
{
|
|
Console.Error.WriteLine("Usage: saviine_server [fastmode|fast]");
|
|
return;
|
|
}
|
|
if (args.Length == 1)
|
|
{
|
|
if (args[0].Equals("fastmode") || args[0].Equals("fast") || args[0].Equals("-fast"))
|
|
{
|
|
op_mode = BYTE_MODE_D;
|
|
fastmode = true;
|
|
}else if(args[0].Equals("inject")) {
|
|
op_mode = BYTE_MODE_I;
|
|
}
|
|
|
|
}
|
|
if (args.Length == 2)
|
|
{
|
|
if (args[0].Equals("dump")) {
|
|
op_mode = BYTE_MODE_D;
|
|
if (args[1].Equals("fastmode") || args[1].Equals("fast") || args[1].Equals("-fast"))
|
|
{
|
|
fastmode = true;
|
|
}
|
|
}else if(args[0].Equals("inject")) {
|
|
op_mode = BYTE_MODE_I;
|
|
}
|
|
}
|
|
|
|
if (op_mode == BYTE_MODE_D)
|
|
{
|
|
currentPersistentID = 0x01;
|
|
Console.WriteLine("Dump mode");
|
|
if(fastmode)Console.WriteLine("Now using fastmode");
|
|
}
|
|
else if(op_mode == BYTE_MODE_I)
|
|
{
|
|
Console.WriteLine("Injection mode!");
|
|
}
|
|
|
|
// Check for cafiine_root and logs folder
|
|
if (!Directory.Exists(root))
|
|
{
|
|
Console.Error.WriteLine("Root directory `{0}' does not exist!", root);
|
|
Directory.CreateDirectory(root);
|
|
Console.WriteLine("Root directory `{0}' created!", root);
|
|
}
|
|
if (!Directory.Exists(logs_root))
|
|
{
|
|
Console.Error.WriteLine("Logs directory `{0}' does not exist!", logs_root);
|
|
Directory.CreateDirectory(logs_root);
|
|
Console.WriteLine("Logs directory `{0}' created!", logs_root);
|
|
}
|
|
// Delete logs
|
|
System.IO.DirectoryInfo downloadedMessageInfo = new DirectoryInfo(logs_root);
|
|
foreach (FileInfo file in downloadedMessageInfo.GetFiles())
|
|
{
|
|
file.Delete();
|
|
}
|
|
|
|
// Start server
|
|
string name = "[listener]";
|
|
try
|
|
{
|
|
TcpListener listener = new TcpListener(IPAddress.Any, 7332);
|
|
listener.Start();
|
|
Console.WriteLine(name + " Listening on 7332");
|
|
|
|
int index = 0;
|
|
while (true)
|
|
{
|
|
TcpClient client = listener.AcceptTcpClient();
|
|
Console.WriteLine("connected");
|
|
Thread thread = new Thread(Handle);
|
|
thread.Name = "[" + index.ToString() + "]";
|
|
thread.Start(client);
|
|
index++;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine(name + " " + e.Message);
|
|
}
|
|
Console.WriteLine(name + " Exit");
|
|
}
|
|
|
|
static void Log(StreamWriter log, String str)
|
|
{
|
|
log.WriteLine(str);
|
|
log.Flush();
|
|
Console.WriteLine(str);
|
|
}
|
|
static void LogNoLine(StreamWriter log, String str)
|
|
{
|
|
log.Write(str);
|
|
log.Flush();
|
|
Console.Write(str);
|
|
}
|
|
public static int countDirectory(string targetDirectory)
|
|
{
|
|
int x = 0;
|
|
// Process the list of files found in the directory.
|
|
string [] fileEntries = Directory.GetFiles(targetDirectory);
|
|
foreach(string fileName in fileEntries)
|
|
x++;
|
|
|
|
// Recurse into subdirectories of this directory.
|
|
string [] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
|
|
foreach(string subdirectory in subdirectoryEntries)
|
|
x++;
|
|
|
|
return x;
|
|
}
|
|
|
|
|
|
static void Handle(object client_obj)
|
|
{
|
|
string name = Thread.CurrentThread.Name;
|
|
FileStream[] files = new FileStream[256];
|
|
Dictionary<int, FileStream> files_request = new Dictionary<int, FileStream>();
|
|
StreamWriter log = null;
|
|
Dictionary<string, Dictionary<string, byte>> dir_files = new Dictionary<string, Dictionary<string, byte>>();
|
|
|
|
|
|
try
|
|
{
|
|
TcpClient client = (TcpClient)client_obj;
|
|
using (NetworkStream stream = client.GetStream())
|
|
{
|
|
EndianBinaryReader reader = new EndianBinaryReader(stream);
|
|
EndianBinaryWriter writer = new EndianBinaryWriter(stream);
|
|
|
|
uint[] ids = reader.ReadUInt32s(4);
|
|
|
|
|
|
|
|
|
|
string LocalRootDump = root + "\\" + "dump" + "\\" + ids[0].ToString("X8") + "-" + ids[1].ToString("X8") + "\\";
|
|
string LocalRootInject = root + "\\" + "inject" + "\\" + ids[0].ToString("X8") + "-" + ids[1].ToString("X8") + "\\";
|
|
|
|
if (!ids[0].ToString("X8").Equals("00050000"))
|
|
{
|
|
writer.Write(BYTE_NORMAL);
|
|
throw new Exception("Not interested.");
|
|
}
|
|
else
|
|
{
|
|
if (!Directory.Exists(LocalRootDump))
|
|
{
|
|
Directory.CreateDirectory(LocalRootDump);
|
|
}
|
|
if (!Directory.Exists(LocalRootInject))
|
|
{
|
|
Directory.CreateDirectory(LocalRootInject);
|
|
}
|
|
}
|
|
// Log connection
|
|
Console.WriteLine(name + " Accepted connection from client " + client.Client.RemoteEndPoint.ToString());
|
|
Console.WriteLine(name + " TitleID: " + ids[0].ToString("X8") + "-" + ids[1].ToString("X8"));
|
|
|
|
// Create log file for current thread
|
|
log = new StreamWriter(logs_root + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + "-" + name + "-" + ids[0].ToString("X8") + "-" + ids[1].ToString("X8") + ".txt", true, Encoding.ASCII, 1024*64);
|
|
log.WriteLine(name + " Accepted connection from client " + client.Client.RemoteEndPoint.ToString());
|
|
string title_id = ids[0].ToString("X8") + "-" + ids[1].ToString("X8");
|
|
log.WriteLine(name + " TitleID: " + title_id);
|
|
|
|
writer.Write(BYTE_SPECIAL);
|
|
|
|
while (true)
|
|
{
|
|
//Log(log, "cmd_byte");
|
|
byte cmd_byte = reader.ReadByte();
|
|
switch (cmd_byte)
|
|
{
|
|
case BYTE_OPEN:
|
|
{
|
|
//Log(log, "BYTE_OPEN");
|
|
Boolean failed = false;
|
|
|
|
int len_path = reader.ReadInt32();
|
|
int len_mode = reader.ReadInt32();
|
|
string path = reader.ReadString(Encoding.ASCII, len_path - 1);
|
|
if (reader.ReadByte() != 0) throw new InvalidDataException();
|
|
string mode = reader.ReadString(Encoding.ASCII, len_mode - 1);
|
|
if (reader.ReadByte() != 0) throw new InvalidDataException();
|
|
|
|
|
|
//Log(log, "old path" + path);
|
|
//Log(log, "currentID: " + currentPersistentID);
|
|
if (op_mode == BYTE_MODE_I)
|
|
path = getRealPathCurrentInject(path, title_id);
|
|
|
|
//Log(log, "new path" + path);
|
|
if (path.Length == 0) failed = true;
|
|
|
|
if (File.Exists(path) && !failed)
|
|
{
|
|
//Log(log, "path exits");
|
|
int handle = -1;
|
|
for (int i = 1; i < files.Length; i++)
|
|
{
|
|
if (files[i] == null)
|
|
{
|
|
handle = i;
|
|
break;
|
|
}
|
|
}
|
|
if (handle == -1)
|
|
{
|
|
Log(log, name + " Out of file handles!");
|
|
writer.Write(BYTE_SPECIAL);
|
|
writer.Write(-19);
|
|
writer.Write(0);
|
|
break;
|
|
}
|
|
//Log(log, name + " -> fopen(\"" + path + "\", \"" + mode + "\") = " + handle.ToString());
|
|
|
|
files[handle] = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
|
|
|
writer.Write(BYTE_SPECIAL);
|
|
writer.Write(0);
|
|
writer.Write(handle);
|
|
break;
|
|
}
|
|
//Log(log, "error fopen");
|
|
//else on error:
|
|
writer.Write(BYTE_NORMAL);
|
|
|
|
break;
|
|
}
|
|
case BYTE_SETPOS:
|
|
{
|
|
//Log(log, "BYTE_SETPOS");
|
|
int fd = reader.ReadInt32();
|
|
int pos = reader.ReadInt32();
|
|
if ((fd & 0x0fff00ff) == 0x0fff00ff)
|
|
{
|
|
int handle = (fd >> 8) & 0xff;
|
|
if (files[handle] == null)
|
|
{
|
|
writer.Write(BYTE_SPECIAL);
|
|
writer.Write(-38);
|
|
break;
|
|
}
|
|
FileStream f = files[handle];
|
|
Log(log, "Postion was set to " + pos + "for handle " + handle);
|
|
f.Position = pos;
|
|
writer.Write(BYTE_SPECIAL);
|
|
writer.Write(0);
|
|
}
|
|
else
|
|
{
|
|
writer.Write(BYTE_NORMAL);
|
|
}
|
|
break;
|
|
}
|
|
case BYTE_INJECTSTART:
|
|
{
|
|
long wiiUpersistentID = (long)reader.ReadUInt32();
|
|
int dumpCommon = 0;
|
|
Boolean injectioncanceled = false;
|
|
SaveSelectorDialog ofd = new SaveSelectorDialog(title_id, wiiUpersistentID);
|
|
try
|
|
{
|
|
DialogResult result = ofd.ShowDialog();
|
|
if (result == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
currentPersistentID = ofd.NewPersistentID;
|
|
dumpCommon = ofd.DumpCommon;
|
|
//Console.WriteLine("Injecting " + currentPersistentID.ToString() + " into " + wiiUpersistentID.ToString() + " for title id " + title_id);
|
|
if (dumpCommon == 1) Console.WriteLine("clean and inject common folder");
|
|
if (dumpCommon == 2) Console.WriteLine("inject common folder");
|
|
if (dumpCommon > 0 && currentPersistentID == 0) currentPersistentID = COMMON_PERSISTENTID;
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Injection canceled");
|
|
injectioncanceled = true;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine("Injection canceled");
|
|
injectioncanceled = true;
|
|
}
|
|
if (injectioncanceled)
|
|
{
|
|
writer.Write(BYTE_NORMAL);
|
|
}
|
|
else
|
|
{
|
|
writer.Write(BYTE_SPECIAL);
|
|
}
|
|
int dumpmask = MASK_NORMAL;
|
|
if (currentPersistentID != 0 && currentPersistentID != COMMON_PERSISTENTID)
|
|
dumpmask |= MASK_USER;
|
|
|
|
if (dumpCommon >= 1) {
|
|
dumpmask |= MASK_COMMON;
|
|
if(dumpCommon == 2)
|
|
dumpmask |= MASK_COMMON_CLEAN;
|
|
}
|
|
writer.Write(dumpmask);
|
|
writer.Write(BYTE_SPECIAL);
|
|
|
|
break;
|
|
}
|
|
case BYTE_INJECTEND:
|
|
{
|
|
currentPersistentID = 0;
|
|
//close all opened files
|
|
for (int i = 1; i < files.Length; i++)
|
|
{
|
|
if (files[i] != null)
|
|
{
|
|
files[i].Close();
|
|
files[i] = null;
|
|
}
|
|
}
|
|
writer.Write(BYTE_OK);
|
|
//Console.WriteLine("InjectionEND");
|
|
|
|
break;
|
|
}
|
|
case BYTE_DUMPSTART:
|
|
{
|
|
long wiiUpersistentID = (long)reader.ReadUInt32();
|
|
Boolean dumpCommon = false;
|
|
Boolean dumpUser = false;
|
|
currentPersistentID = wiiUpersistentID;
|
|
|
|
Boolean dumpcanceled = false;
|
|
DumpDialog ofd = new DumpDialog(title_id, wiiUpersistentID);
|
|
try
|
|
{
|
|
DialogResult result = ofd.ShowDialog();
|
|
if (result == System.Windows.Forms.DialogResult.OK)
|
|
{
|
|
dumpUser = ofd.DumpUser;
|
|
dumpCommon = ofd.DumpCommon;
|
|
//Console.WriteLine("Injecting " + currentPersistentID.ToString() + " into " + wiiUpersistentID.ToString() + " for title id " + title_id);
|
|
if (dumpCommon) Console.WriteLine("dumping common data");
|
|
if (dumpUser) Console.WriteLine("dumping user data");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("dump canceled");
|
|
dumpcanceled = true;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine("dump canceled");
|
|
dumpcanceled = true;
|
|
}
|
|
if (dumpcanceled)
|
|
{
|
|
writer.Write(BYTE_NORMAL);
|
|
}
|
|
else
|
|
{
|
|
writer.Write(BYTE_SPECIAL);
|
|
}
|
|
|
|
int dumpmask = MASK_NORMAL;
|
|
if (dumpUser)
|
|
dumpmask |= MASK_USER;
|
|
|
|
if (dumpCommon)
|
|
{
|
|
dumpmask |= MASK_COMMON;
|
|
}
|
|
writer.Write(dumpmask);
|
|
writer.Write(BYTE_SPECIAL);
|
|
|
|
break;
|
|
}
|
|
case BYTE_DUMPEND:
|
|
{
|
|
currentPersistentID = 0;
|
|
//close all opened files
|
|
for (int i = 1; i < files.Length; i++)
|
|
{
|
|
if (files[i] != null)
|
|
{
|
|
files[i].Close();
|
|
files[i] = null;
|
|
}
|
|
}
|
|
writer.Write(BYTE_OK);
|
|
//Console.WriteLine("dumpEND");
|
|
|
|
break;
|
|
}
|
|
case BYTE_READ_DIR:
|
|
{
|
|
Boolean failed = false;
|
|
int len_path = reader.ReadInt32();
|
|
string path = reader.ReadString(Encoding.ASCII, len_path-1);
|
|
if (reader.ReadByte() != 0) throw new InvalidDataException();
|
|
int x = 0;
|
|
//Console.WriteLine("old" + path);
|
|
if(op_mode == BYTE_MODE_I)
|
|
path = getRealPathCurrentInject(path, title_id);
|
|
//Console.WriteLine("new" + path);
|
|
if(path.Length == 0)failed = true;
|
|
|
|
if (Directory.Exists(path) && !failed)
|
|
{
|
|
x = countDirectory(path);
|
|
if (x > 0)
|
|
{
|
|
Dictionary<string, byte> value;
|
|
if (!dir_files.TryGetValue(path, out value))
|
|
{
|
|
//Console.Write("found no \"" + path + "\" in dic \n");
|
|
value = new Dictionary<string, byte>();
|
|
string[] fileEntries = Directory.GetFiles(path);
|
|
foreach (string fn in fileEntries)
|
|
{
|
|
string fileName = Path.GetFileName(fn);
|
|
value.Add(fileName, BYTE_FILE);
|
|
}
|
|
string[] subdirectoryEntries = Directory.GetDirectories(path);
|
|
foreach (string sd in subdirectoryEntries)
|
|
{
|
|
string subdirectory = Path.GetFileName(sd);
|
|
value.Add(subdirectory, BYTE_FOLDER);
|
|
}
|
|
dir_files.Add(path, value);
|
|
//Console.Write("added \"" + path + "\" to dic \n");
|
|
}
|
|
else
|
|
{
|
|
//Console.Write("dic for \"" + path + "\" ready \n");
|
|
}
|
|
|
|
if (value.Count > 0)
|
|
{
|
|
writer.Write(BYTE_OK);
|
|
//Console.Write("sent ok byte \n");
|
|
foreach (var item in value)
|
|
{ //Write
|
|
writer.Write(item.Value);
|
|
//Console.Write("type : " + item.Value);
|
|
writer.Write(item.Key.Length);
|
|
//Console.Write("length : " + item.Key.Length);
|
|
writer.Write(item.Key, Encoding.ASCII, true);
|
|
//Console.Write("filename : " + item.Key);
|
|
int length = 0;
|
|
if (item.Value == BYTE_FILE) length = (int)new System.IO.FileInfo(path + "/" + item.Key).Length;
|
|
writer.Write(length);
|
|
//Console.Write("filesize : " + length + " \n");
|
|
value.Remove(item.Key);
|
|
//Console.Write("removed from list! " + value.Count + " remaining\n");
|
|
break;
|
|
}
|
|
writer.Write(BYTE_SPECIAL); //
|
|
//Console.Write("file sent, wrote special byte \n");
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
|
|
dir_files.Remove(path);
|
|
//Console.Write("removed \"" + path + "\" from dic \n");
|
|
}
|
|
}
|
|
}
|
|
writer.Write(BYTE_END); //
|
|
//Console.Write("list was empty return BYTE_END \n");
|
|
|
|
//Console.Write("in break \n");
|
|
break;
|
|
}
|
|
case BYTE_READ:
|
|
{
|
|
//Log(log,"BYTE_READ");
|
|
int size = reader.ReadInt32();
|
|
int fd = reader.ReadInt32();
|
|
|
|
FileStream f = files[fd];
|
|
|
|
byte[] buffer = new byte[size];
|
|
int sz = (int)f.Length;
|
|
int rd = 0;
|
|
|
|
//Log(log, "want size:" + size + " for handle: " + fd);
|
|
|
|
writer.Write(BYTE_SPECIAL);
|
|
|
|
rd = f.Read(buffer, 0, buffer.Length);
|
|
//Log(log,"rd:" + rd);
|
|
writer.Write(rd);
|
|
writer.Write(buffer, 0, rd);
|
|
|
|
int offset = (int)f.Position;
|
|
int progress = (int)(((float)offset / (float)sz) * 100);
|
|
string strProgress = progress.ToString().PadLeft(3, ' ');
|
|
string strSize = (sz / 1024).ToString();
|
|
string strCurrent = (offset / 1024).ToString().PadLeft(strSize.Length, ' ');
|
|
Console.Write("\r\t--> {0}% ({1} kB / {2} kB)", strProgress, strCurrent, strSize);
|
|
|
|
//Console.Write("send " + rd );
|
|
if (offset == sz)
|
|
{
|
|
Console.Write("\n");
|
|
log.Write("\r\t--> {0}% ({1} kB / {2} kB)\n", strProgress, strCurrent, strSize);
|
|
}
|
|
int ret = -5;
|
|
if ((ret =reader.ReadByte()) != BYTE_OK)
|
|
{
|
|
Console.Write("error, got " + ret + " instead of " + BYTE_OK);
|
|
//throw new InvalidDataException();
|
|
}
|
|
|
|
//Log(log, "break READ");
|
|
|
|
break;
|
|
}
|
|
case BYTE_HANDLE:
|
|
{
|
|
//Log(log,"BYTE_HANDLE");
|
|
// Read buffer params : fd, path length, path string
|
|
int fd = reader.ReadInt32();
|
|
int len_path = reader.ReadInt32();
|
|
string path = reader.ReadString(Encoding.ASCII, len_path - 1);
|
|
if (reader.ReadByte() != 0) throw new InvalidDataException();
|
|
//Console.WriteLine("old " + path);
|
|
if (op_mode == BYTE_MODE_D)
|
|
path = getRealPathCurrentDump(path, title_id);
|
|
//Console.WriteLine("new " + path);
|
|
|
|
if (path.Length == 0)
|
|
{
|
|
writer.Write(BYTE_SPECIAL);
|
|
break;
|
|
}
|
|
|
|
if (!Directory.Exists(path))
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
|
}
|
|
|
|
// Add new file for incoming data
|
|
files_request.Add(fd, new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write));
|
|
// Send response
|
|
if (fastmode) {
|
|
writer.Write(BYTE_REQUEST);
|
|
}
|
|
else
|
|
{
|
|
writer.Write(BYTE_REQUEST_SLOW);
|
|
}
|
|
LogNoLine(log, "-> [");
|
|
// Send response
|
|
writer.Write(BYTE_SPECIAL);
|
|
break;
|
|
}
|
|
case BYTE_DUMP:
|
|
{
|
|
//Log(log,"BYTE_DUMP");
|
|
// Read buffer params : fd, size, file data
|
|
int fd = reader.ReadInt32();
|
|
int sz = reader.ReadInt32();
|
|
byte[] buffer = new byte[sz];
|
|
buffer = reader.ReadBytes(sz);
|
|
|
|
// Look for file descriptor
|
|
foreach (var item in files_request)
|
|
{
|
|
if (item.Key == fd)
|
|
{
|
|
FileStream dump_file = item.Value;
|
|
if (dump_file == null)
|
|
break;
|
|
|
|
LogNoLine(log, ".");
|
|
|
|
// Write to file
|
|
dump_file.Write(buffer, 0, sz);
|
|
|
|
break;
|
|
}
|
|
}
|
|
// Send response
|
|
writer.Write(BYTE_SPECIAL);
|
|
break;
|
|
}
|
|
case BYTE_CLOSE:
|
|
{
|
|
//Log(log, "BYTE_CLOSE");
|
|
int fd = reader.ReadInt32();
|
|
|
|
|
|
if (files[fd] == null)
|
|
{
|
|
writer.Write(BYTE_SPECIAL);
|
|
writer.Write(-38);
|
|
break;
|
|
}
|
|
//Log(log, name + " close(" + fd.ToString() + ")");
|
|
FileStream f = files[fd];
|
|
|
|
writer.Write(BYTE_SPECIAL);
|
|
writer.Write(0);
|
|
f.Close();
|
|
files[fd] = null;
|
|
|
|
|
|
break;
|
|
}
|
|
case BYTE_CLOSE_DUMP:
|
|
{
|
|
int fd = reader.ReadInt32();
|
|
if ((fd & 0x0fff00ff) != 0x0fff00ff)
|
|
{
|
|
// Check if it is a file to dump
|
|
foreach (var item in files_request)
|
|
{
|
|
if (item.Key == fd)
|
|
{
|
|
FileStream dump_file = item.Value;
|
|
if (dump_file == null)
|
|
break;
|
|
|
|
LogNoLine(log,"]");
|
|
Log(log, "");
|
|
// Close file and remove from request list
|
|
dump_file.Close();
|
|
files_request.Remove(fd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Send response
|
|
writer.Write(BYTE_NORMAL);
|
|
}
|
|
break;
|
|
}
|
|
case BYTE_PING:
|
|
{
|
|
//Log(log, "BYTE_PING");
|
|
int val1 = reader.ReadInt32();
|
|
int val2 = reader.ReadInt32();
|
|
|
|
Log(log, name + " PING RECEIVED with values : " + val1.ToString() + " - " + val2.ToString());
|
|
break;
|
|
}
|
|
case BYTE_G_MODE:
|
|
{
|
|
if (op_mode == BYTE_MODE_D)
|
|
{
|
|
writer.Write(BYTE_MODE_D);
|
|
}
|
|
else if (op_mode == BYTE_MODE_I)
|
|
{
|
|
writer.Write(BYTE_MODE_I);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case BYTE_LOG_STR:
|
|
{
|
|
//Log(log, "BYTE_LOG_STR");
|
|
int len_str = reader.ReadInt32();
|
|
string str = reader.ReadString(Encoding.ASCII, len_str - 1);
|
|
if (reader.ReadByte() != 0) throw new InvalidDataException();
|
|
|
|
Log(log,"-> " + str);
|
|
break;
|
|
}
|
|
default:
|
|
Log(log, "xx" + cmd_byte);
|
|
throw new InvalidDataException();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (log != null)
|
|
Log(log, name + " " + e.Message);
|
|
else
|
|
Console.WriteLine(name + " " + e.Message);
|
|
}
|
|
finally
|
|
{
|
|
foreach (var item in files)
|
|
{
|
|
if (item != null)
|
|
item.Close();
|
|
}
|
|
foreach (var item in files_request)
|
|
{
|
|
if (item.Value != null)
|
|
item.Value.Close();
|
|
}
|
|
|
|
if (log != null)
|
|
log.Close();
|
|
}
|
|
Console.WriteLine(name + " Exit");
|
|
}
|
|
|
|
private static string getRealPathCurrentInject(string path, string title_id)
|
|
{
|
|
return getRealPathCurrent(injectfolder, path, title_id);
|
|
}
|
|
private static string getRealPathCurrentDump(string path, string title_id)
|
|
{
|
|
return getRealPathCurrent(dumpfolder, path, title_id);
|
|
}
|
|
|
|
private static string getRealPathCurrent(string prefix, string path, string title_id)
|
|
{
|
|
string savePath = Program.root + "/" + prefix + "/" + title_id;
|
|
if (currentPersistentID == 0) return "";
|
|
string[] stringSeparators = new string[] { "vol/save/", "vol\\save\\" };
|
|
string[] result;
|
|
string resultstr = "";
|
|
result = path.Split(stringSeparators, StringSplitOptions.None);
|
|
if (result.Length < 2) return "";
|
|
resultstr = result[result.Length-1];
|
|
stringSeparators = new string[] { "/", "\\" };
|
|
result = resultstr.Split(stringSeparators, StringSplitOptions.None);
|
|
if (result.Length < 2)
|
|
{
|
|
if (result[0] != "common") return savePath + "/" + String.Format("{0:X}", currentPersistentID);
|
|
return savePath + "/" + "common";
|
|
}
|
|
resultstr = "";
|
|
if (result[0] != "common")
|
|
savePath += "/" + String.Format("{0:X}", currentPersistentID);
|
|
else
|
|
savePath += "/" + "common";
|
|
for (int i = 1; i < result.Length; i++)
|
|
{
|
|
resultstr += "/" + result[i];
|
|
}
|
|
|
|
savePath += resultstr;
|
|
|
|
return savePath;
|
|
}
|
|
}
|
|
}
|