aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HGBD.HC257
-rw-r--r--LICENSE116
-rw-r--r--README.md72
-rw-r--r--example.gifbin0 -> 320373 bytes
-rw-r--r--hgbdd311
-rw-r--r--hgbdd.conf.example10
6 files changed, 766 insertions, 0 deletions
diff --git a/HGBD.HC b/HGBD.HC
new file mode 100644
index 0000000..d6d5553
--- /dev/null
+++ b/HGBD.HC
@@ -0,0 +1,257 @@
+#define HGC_PORT 0x02F8
+#define HGC_COPYG 0x01
+#define HGC_COPYH 0x02
+#define HGC_SCREENSHOT 0x03
+#define HGC_DIRH 0x04
+#define HGC_GETURL 0x05
+#define HGC_DELH 0x07
+#define HGC_CDH 0x08
+#define HGC_DIRCURH 0x09
+#define HGC_HCOPY 0x0A
+#define HGC_HPASTE 0x0B
+#define HGC_NOOP 0xFF
+
+#define HGFS_BUF_SIZE 0x4000000
+
+#define SCREENSHOT_FILE "::/Tmp/ScreenShot.bmp"
+
+CBlkDev *HGBD_DEV;
+CDrv *HGBD;
+I64 HGBD_OP=0;
+U8 *HGFS_BUF[HGFS_BUF_SIZE];
+U8 HGBD_PARAM_BUF[BLK_SIZE];
+
+HGBD_DEV = BlkDevNextFreeSlot(0x69,BDT_ATA);
+HGBD_DEV->unit=1;
+HGBD_DEV->base0=496;
+HGBD_DEV->base1=1012;
+BlkDevAdd(HGBD_DEV,0,1,1);
+
+HGBD = Let2Drv(HGBD_DEV->first_drv_let);
+
+U0 FreeHGBD()
+{
+ HGBD_OP=0;
+}
+
+U0 HGExec(I64 cmd, Bool chain=FALSE)
+{
+ while (HGBD_OP>0 && !chain) { Sleep(1+(RandU16/8192)); };
+ HGBD_OP=cmd;
+ OutU8(HGC_PORT,HGC_NOOP);
+ while (InU8(HGC_PORT)!=HGC_NOOP) { Sleep(0); };
+ OutU8(HGC_PORT,cmd);
+ while (InU8(HGC_PORT)!=cmd) { Sleep(0); };
+}
+
+U0 ReadParamBuf() { DskCacheInvalidate(HGBD); BlkRead(HGBD,HGBD_PARAM_BUF,0,1); }
+
+U0 PrintParamBuf() { ReadParamBuf; Print(HGBD_PARAM_BUF); }
+
+U0 WriteParamBuf() { BlkWrite(HGBD,HGBD_PARAM_BUF, 0, 1); }
+
+U0 ZeroParamBuf()
+{
+ I64 z=0;
+ while (z<BLK_SIZE) {
+ HGBD_PARAM_BUF[z] = 0x0;
+ z++;
+ }
+ WriteParamBuf;
+}
+
+I64 CdH(U8 *pathname)
+{
+ I64 result;
+ ZeroParamBuf;
+ StrCpy(HGBD_PARAM_BUF,pathname);
+ WriteParamBuf;
+ HGExec(HGC_CDH);
+ ReadParamBuf;
+ result = Str2I64(HGBD_PARAM_BUF);
+ if (result==0) { Print("%s ", pathname); PrintErr("Path not found.\n"); };
+ FreeHGBD;
+ return result;
+}
+
+I64 CopyG(U8 *filename)
+{
+ I64 size;
+ ZeroParamBuf;
+ StrCpy(HGBD_PARAM_BUF,filename);
+ WriteParamBuf;
+ HGExec(HGC_COPYG);
+ ReadParamBuf;
+ size = Str2I64(HGBD_PARAM_BUF);
+ if (size==-1) { FreeHGBD; return 0; };
+ Print("Copying %s to Guest\n",filename);
+ BlkRead(HGBD,HGFS_BUF,1,(size/BLK_SIZE)+1);
+ if (StrCmp(filename+StrLen(filename)-2,".Z")==0) {
+ U8 uzfilename[28];
+ MemCpy(uzfilename,filename,StrLen(filename)-2);
+ uzfilename[StrLen(filename)-1] = 0x0;
+ FileWrite(uzfilename, HGFS_BUF, size);
+ Move(uzfilename, filename);
+ } else {
+ FileWrite(filename, HGFS_BUF, size);
+ };
+ FreeHGBD;
+ return 1;
+}
+
+I64 CopyH(U8 *filename)
+{
+ I64 size;
+ CDirEntry *de = FilesFind(filename);
+ if (de==NULL) { FreeHGBD; return 0; };
+ Print("Copying %s to Host\n",de->full_name);
+ U8 *file = FileRead(de->full_name, &size);
+ ZeroParamBuf;
+ MemCpy(HGBD_PARAM_BUF,&size,8);
+ StrCpy(HGBD_PARAM_BUF+8,de->name);
+ WriteParamBuf;
+ BlkWrite(HGBD,file,1,(size/BLK_SIZE)+1);
+ HGExec(HGC_COPYH);
+ Free(file);
+ DirEntryDel(de);
+ FreeHGBD;
+ return 1;
+}
+
+I64 DelH(U8 *filename)
+{
+ I64 result;
+ ZeroParamBuf;
+ StrCpy(HGBD_PARAM_BUF,filename);
+ WriteParamBuf;
+ HGExec(HGC_DELH);
+ ReadParamBuf;
+ result = Str2I64(HGBD_PARAM_BUF);
+ if (result==1) { Print("DelH %s\n", filename); };
+ FreeHGBD;
+ return result;
+}
+
+I64 DirH() {
+ I64 entries;
+ I64 size;
+ ZeroParamBuf;
+ HGExec(HGC_DIRH);
+ ReadParamBuf;
+ entries = Str2I64(HGBD_PARAM_BUF);
+ size = Str2I64(HGBD_PARAM_BUF+128);
+ BlkRead(HGBD,HGFS_BUF,1,(size/BLK_SIZE)+1);
+ MemSetU8(ToI64(HGFS_BUF)+size, 0x0, 1);
+ Print(HGFS_BUF);
+ FreeHGBD;
+ return entries;
+}
+
+I64 CopyFindH(U8 *files)
+{
+ I64 cnt=0;
+ CDirEntry *res = FilesFind(files);
+ while (StrCmp(res->name,"")!=0) {
+ if (res->size>0) {
+ cnt += CopyH(res->full_name);
+ };
+ res=res->next;
+ };
+ DirEntryDel(res);
+ return cnt;
+}
+
+U8 *DirCurH()
+{
+ U8 StrDCH[1024];
+ ZeroParamBuf;
+ HGExec(HGC_DIRCURH);
+ ReadParamBuf;
+ StrCpy(StrDCH,HGBD_PARAM_BUF);
+ FreeHGBD;
+ return StrDCH;
+}
+
+U0 ScrShot()
+{
+ I64 size;
+ BMPScrnCapture(SCREENSHOT_FILE);
+ CDirEntry *de = FilesFind(SCREENSHOT_FILE);
+ if (de==NULL) { FreeHGBD; return; };
+ U8 *file = FileRead(de->full_name, &size);
+ ZeroParamBuf;
+ MemCpy(HGBD_PARAM_BUF,&size,8);
+ StrCpy(HGBD_PARAM_BUF+8,de->name);
+ WriteParamBuf;
+ BlkWrite(HGBD,file,1,(size/BLK_SIZE)+1);
+ HGExec(HGC_SCREENSHOT);
+ OutU8(0x03F8, 0x99);
+ Free(file);
+ DirEntryDel(de);
+ FreeHGBD;
+}
+
+U0 GetURL(U8 *url)
+{
+ Print("Downloading %s\n",url);
+ I64 size;
+ U8 localfile[28];
+ if (StrLen(StrLastOcc(url,"/")+1)>0) {
+ StrCpy(localfile, StrLastOcc(url,"/")+1);
+ } else {
+ StrCpy(localfile, "GetURL.OUT");
+ };
+ ZeroParamBuf;
+ StrCpy(HGBD_PARAM_BUF,url);
+ WriteParamBuf;
+ HGExec(HGC_GETURL);
+ ReadParamBuf;
+ size = Str2I64(HGBD_PARAM_BUF);
+ if (size==-1) { PrintErr("Bad URL.\n"); FreeHGBD; return; };
+ BlkRead(HGBD,HGFS_BUF,1,(size/BLK_SIZE)+1);
+ if (StrCmp(localfile+StrLen(localfile)-2,".Z")==0) {
+ U8 uzlocalfile[28];
+ MemCpy(uzlocalfile,localfile,StrLen(localfile)-2);
+ uzlocalfile[StrLen(localfile)-1] = 0x0;
+ FileWrite(uzlocalfile, HGFS_BUF, size);
+ Move(uzlocalfile, localfile);
+ } else {
+ FileWrite(localfile, HGFS_BUF, size);
+ };
+ FreeHGBD;
+}
+
+U0 HCopy()
+{
+ I64 size;
+ U8 *clip = Doc2PlainText(sys_clip_doc,sys_clip_doc->head.next);
+ size = StrLen(clip);
+ ZeroParamBuf;
+ MemCpy(HGBD_PARAM_BUF,&size,8);
+ WriteParamBuf;
+ BlkWrite(HGBD,clip,1,(size/BLK_SIZE)+1);
+ HGExec(HGC_HCOPY);
+ Free(clip);
+ FreeHGBD;
+}
+
+U0 HPaste()
+{
+ I64 size;
+ ZeroParamBuf;
+ HGExec(HGC_HPASTE);
+ ReadParamBuf;
+ size = Str2I64(HGBD_PARAM_BUF);
+ BlkRead(HGBD,HGFS_BUF,1,(size/BLK_SIZE)+1);
+ MemSetU8(ToI64(HGFS_BUF)+size, 0x0, 1);
+ Print(HGFS_BUF);
+ FreeHGBD;
+}
+
+U0 HGBDInit()
+{
+ ZeroParamBuf;
+ Print("HGBD Initialized\n");
+}
+
+HGBDInit;
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..670154e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+<http://creativecommons.org/publicdomain/zero/1.0/>
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f4005b9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,72 @@
+# hgbd
+Host-Guest Block Device for TempleOS
+
+NOTE: This is an older project and hasn't been updated for some time. I am providing it here due to recent requests.
+
+(This can cause some issues with FileMgr if it tries to read a RedSea FS from the block device.)
+
+Makes use of shared memory buffer between TempleOS Guest and Host.
+
+![HGBD](https://raw.githubusercontent.com/obecebo/hgbd/master/example.gif "Host-Guest Block Device")
+
+# Features
+- Copy files between Host-Guest
+- Copy-paste clipboard between Host-Guest
+- Download files to Guest via HTTP/HTTPS
+- Take screenshot from Guest to Host as 4-bit PNG
+
+You can create custom modules for HGBD and include them in `modules` section of the config
+file `/etc/hgbdd.conf`
+
+Start HGBD daemon on Host:
+
+```
+ /usr/sbin/hgbdd
+```
+
+In `/etc/hgbdd.conf`, replace `blk_dev` with the RAM disk block device (not tmpfs) and
+`user` with your username (for shared file write ownership)
+
+To create the block device (64 MiB or larger):
+
+Debian/Ubuntu: `/dev/ram0` builtin
+macOS: `hdiutil attach -nomount ram://131072`
+Windows: Use [ImDisk](http://www.ltr-data.se/opencode.html/#ImDisk) or a similar utility
+
+On your TempleOS VM, connect `COM2` to `TCP4:127.0.0.1:7202` (default) and create a raw
+device mapping to the block device.
+
+Examples:
+
+QEMU: Add `-hdX /dev/ram0` to startup parameters
+VirtualBox: `VBoxManage internalcommands createrawvmdk -filename "ram0.vmdk" -rawdisk /dev/ram0`
+VMware: `Edit VM > Settings > Use a physical disk`
+
+Define `unit`, `base0`, `base1` and drive letter for `HGBD_DEV` in `HGBD.HC` (default is `I:`)
+
+`#include "HGBD"` in your `::/Home/HomeKeyPlugIns.HC` to make use of shortcut keys for
+copy-paste and screenshots.
+
+
+# Commands
+
+`CdH(path);` to change Host directory
+`CopyFindH(files);` to copy FilesFind(files) in Guest to Host
+`CopyG(file);` to copy Host `file` to Guest in current directory
+`CopyH(file);` to copy Guest `file` to Host
+`DelH(file);` Delete file in Host directory
+`DirCurH;` points to current Host directory
+`DirH;` List files in Host directory (click a directory to navigate, or a file to CopyG)
+`GetURL(url)` download `url` to Guest in current directory
+`GetURLStr(url)` return the response text of `url` as a string
+`HCopy;` copies Guest clipboard to Host
+`HPaste;` paste Host clipboard at cursor location
+`ScrShot;` take screenshot to Host directory
+
+
+# Prerequisites
+
+- pip install: clipboard, urlparse
+- wget
+- GraphicsMagick (for screenshots)
+- TOSZ (to transfer .Z files)
diff --git a/example.gif b/example.gif
new file mode 100644
index 0000000..62321a4
--- /dev/null
+++ b/example.gif
Binary files differ
diff --git a/hgbdd b/hgbdd
new file mode 100644
index 0000000..d96cd74
--- /dev/null
+++ b/hgbdd
@@ -0,0 +1,311 @@
+#!/usr/bin/python
+import datetime
+import clipboard
+import glob
+import json
+import logging
+import os
+import socket
+import subprocess
+import sys
+import time
+import urllib
+import urlparse
+import uuid
+
+def builtin(data):
+ if data == HGC_NOOP:
+ conn.send(chr(HGC_NOOP))
+ if data == HGC_CDH:
+ HGCCdH()
+ if data == HGC_COPYG:
+ HGCCopyG()
+ if data == HGC_COPYH:
+ HGCCopyH()
+ if data == HGC_DELH:
+ HGCDelH()
+ if data == HGC_DIRCURH:
+ HGCDirCurH()
+ if data == HGC_DIRH:
+ HGCDirH()
+ if data == HGC_GETURL:
+ HGCGetURL()
+ if data == HGC_HCOPY:
+ HGCHCopy()
+ if data == HGC_HPASTE:
+ HGCHPaste()
+ if data == HGC_SCREENSHOT:
+ HGCScreenShot()
+
+def ZeroParamBuf():
+ os.lseek(HGBD,0,os.SEEK_SET)
+ os.write(HGBD, '\x00'*BLK_SIZE)
+
+def HGCCdH():
+ os.lseek(HGBD,0,os.SEEK_SET)
+ HGBD_PARAM_BUF = os.read(HGBD,BLK_SIZE)
+ pathname = HGBD_PARAM_BUF[:HGBD_PARAM_BUF.find('\x00')]
+ ZeroParamBuf()
+ os.lseek(HGBD,0,os.SEEK_SET)
+ c_pathname = ''
+ if pathname[:1] != '/':
+ c_pathname = HGBD_CONF["hgfs_path"]+"/"+pathname
+ else:
+ c_pathname = pathname
+ if os.path.isdir(c_pathname):
+ newpath = subprocess.Popen('cd "' + c_pathname + '"; pwd',shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE).communicate()[0][:-1]
+ HGBD_CONF["hgfs_path"] = newpath
+ os.write(HGBD,str(1))
+ logger.info("change host directory " + HGBD_CONF["hgfs_path"])
+ else:
+ os.write(HGBD,str(0))
+ logger.error("host path not found " + pathname)
+ conn.send(chr(HGC_CDH))
+
+def HGCCopyG():
+ os.lseek(HGBD,0,os.SEEK_SET)
+ HGBD_PARAM_BUF = os.read(HGBD,BLK_SIZE)
+ filename = HGBD_PARAM_BUF[:HGBD_PARAM_BUF.find('\x00')]
+ try:
+ filedata = open(HGBD_CONF["hgfs_path"]+"/"+filename,"rb").read()
+ if filename[-2:].upper()==".Z":
+ tmp_z_file = "/tmp/" + str(uuid.uuid4()).split('-')[0].upper() + ".Z"
+ while os.path.exists(tmp_z_file):
+ tmp_z_file = "/tmp/" + str(uuid.uuid4()).split('-')[0].upper() + ".Z"
+ open(tmp_z_file,"wb").write(filedata)
+ os.system('tosz "' + tmp_z_file + '"')
+ filedata = open(tmp_z_file.split('.Z')[0],"rb").read()
+ os.remove(tmp_z_file.split('.Z')[0])
+ filesize = len(filedata)
+ ZeroParamBuf()
+ os.lseek(HGBD,0,os.SEEK_SET)
+ os.write(HGBD,str(filesize))
+ os.lseek(HGBD,BLK_SIZE,os.SEEK_SET)
+ os.write(HGBD,filedata)
+ logger.info("sent file " + filename)
+ except:
+ filesize = -1
+ ZeroParamBuf()
+ os.lseek(HGBD,0,os.SEEK_SET)
+ os.write(HGBD,str(filesize))
+ logger.error("file not found " + filename)
+ conn.send(chr(HGC_COPYG))
+
+def HGCCopyH():
+ os.lseek(HGBD,0,os.SEEK_SET)
+ HGBD_PARAM_BUF = os.read(HGBD,BLK_SIZE)
+ filename = HGBD_PARAM_BUF[8:HGBD_PARAM_BUF.find('\x00',9)]
+ filesize = 0
+ fsincr = 0
+ while fsincr<8:
+ fsbyte = ord(HGBD_PARAM_BUF[fsincr:fsincr+1])
+ filesize += fsbyte*(256**fsincr)
+ fsincr += 1
+ os.lseek(HGBD,BLK_SIZE,os.SEEK_SET)
+ if filename[-2:].upper()==".Z":
+ open(HGBD_CONF["hgfs_path"]+"/"+filename[:-2],"wb").write(os.read(HGBD,filesize))
+ SetHGFSPerms(HGBD_CONF["hgfs_path"]+"/"+filename[:-2])
+ else:
+ open(HGBD_CONF["hgfs_path"]+"/"+filename,"wb").write(os.read(HGBD,filesize))
+ SetHGFSPerms(HGBD_CONF["hgfs_path"]+"/"+filename)
+ logger.info("received file " + filename)
+ conn.send(chr(HGC_COPYH))
+
+def HGCScreenShot():
+ os.lseek(HGBD,0,os.SEEK_SET)
+ HGBD_PARAM_BUF = os.read(HGBD,BLK_SIZE)
+ filesize = 0
+ fsincr = 0
+ while fsincr<8:
+ fsbyte = ord(HGBD_PARAM_BUF[fsincr:fsincr+1])
+ filesize += fsbyte*(256**fsincr)
+ fsincr += 1
+ tmp_file = "/tmp/" + str(uuid.uuid4()) + ".bmp"
+ while os.path.exists(tmp_file):
+ tmp_file = "/tmp/" + str(uuid.uuid4()) + ".bmp"
+ os.lseek(HGBD,BLK_SIZE,os.SEEK_SET)
+ open(tmp_file,"wb").write(os.read(HGBD,filesize))
+ ts = str(datetime.datetime.now())
+ screenshot_file = HGBD_CONF["screenshot_path"]+"/"+ts[:19].replace(' ','-').replace(':','-') + '.png'
+ os.system('gm convert "' + tmp_file + '" -colors 16 "' + screenshot_file + '"')
+ SetHGFSPerms(screenshot_file)
+ os.remove(tmp_file)
+ logger.info("screenshot " + screenshot_file)
+ conn.send(chr(HGC_SCREENSHOT))
+
+def HGCDelH():
+ os.lseek(HGBD,0,os.SEEK_SET)
+ HGBD_PARAM_BUF = os.read(HGBD,BLK_SIZE)
+ filename = HGBD_PARAM_BUF[:HGBD_PARAM_BUF.find('\x00')]
+ ZeroParamBuf()
+ os.lseek(HGBD,0,os.SEEK_SET)
+ try:
+ os.remove(HGBD_CONF["hgfs_path"]+"/"+filename)
+ os.write(HGBD,str(1))
+ logger.info("delete host file " + filename)
+ except:
+ os.write(HGBD,str(0))
+ logger.error("delete host file not found " + filename)
+ conn.send(chr(HGC_DELH))
+
+def HGCDirCurH():
+ ZeroParamBuf()
+ os.lseek(HGBD,0,os.SEEK_SET)
+ os.write(HGBD,HGBD_CONF["hgfs_path"])
+ logger.info("get host current directory " + HGBD_CONF["hgfs_path"])
+ conn.send(chr(HGC_DIRCURH))
+
+def HGCDirH():
+ dirdata = ''
+ dirdata += '$MA,"Directory",LM=""$ of Host:' + HGBD_CONF["hgfs_path"] + '\n'
+ dirdata += 'DATE_ TIME_ SIZE\n'
+ bsize = "{0:#0{1}x}".format(0,10)[2:].upper()
+ f = HGBD_CONF["hgfs_path"]+"/."
+ ts = str(datetime.datetime.fromtimestamp(os.path.getmtime(f)))
+ dirdata += ts[5:10].replace('-','/') + ' ' + ts[11:16] + ' ' + bsize + ' $MA,"' + os.path.basename(f) + '",LM="CdH(\\"' + os.path.basename(f) + '\\");DirH;\\n"$\n'
+ f = HGBD_CONF["hgfs_path"]+"/.."
+ ts = str(datetime.datetime.fromtimestamp(os.path.getmtime(f)))
+ dirdata += ts[5:10].replace('-','/') + ' ' + ts[11:16] + ' ' + bsize + ' $MA,"' + os.path.basename(f) + '",LM="CdH(\\"' + os.path.basename(f) + '\\");DirH;\\n"$\n'
+ direntries = 2
+ for f in sorted(glob.glob(HGBD_CONF["hgfs_path"]+"/*")):
+ direntries += 1
+ ts = str(datetime.datetime.fromtimestamp(os.path.getmtime(f)))
+ size = os.path.getsize(f)
+ bsize = "{0:#0{1}x}".format(size,10)[2:].upper()
+ if os.path.isdir(f):
+ bsize = "{0:#0{1}x}".format(0,10)[2:].upper()
+ dirdata += ts[5:10].replace('-','/') + ' ' + ts[11:16] + ' ' + bsize + ' $MA,"' + os.path.basename(f) + '",LM="CdH(\\"' + os.path.basename(f) + '\\");DirH;\\n"$\n'
+ else:
+ dirdata += ts[5:10].replace('-','/') + ' ' + ts[11:16] + ' ' + bsize + ' $MA,"' + os.path.basename(f) + '",LM="CopyG(\\"' + os.path.basename(f) + '\\");\\n"$\n'
+ dirsize = len(dirdata)
+ ZeroParamBuf()
+ os.lseek(HGBD,0,os.SEEK_SET)
+ os.write(HGBD,str(direntries))
+ os.lseek(HGBD,128,os.SEEK_SET)
+ os.write(HGBD,str(dirsize))
+ os.lseek(HGBD,BLK_SIZE,os.SEEK_SET)
+ os.write(HGBD,dirdata)
+ logger.info("list directory")
+ conn.send(chr(HGC_DIRH))
+
+def HGCGetURL():
+ os.lseek(HGBD,0,os.SEEK_SET)
+ HGBD_PARAM_BUF = os.read(HGBD,BLK_SIZE)
+ url_comp = urlparse.urlparse(HGBD_PARAM_BUF[:HGBD_PARAM_BUF.find('\x00')])
+ url = url_comp.scheme + "://" + url_comp.netloc + urllib.quote(url_comp.path)
+ filedata = subprocess.Popen('wget -q -O - -U "" "' + url + '" 2>/dev/null', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate()[0]
+ if url[-2:].upper()==".Z":
+ tmp_z_file = "/tmp/" + str(uuid.uuid4()).split('-')[0].upper() + ".Z"
+ while os.path.exists(tmp_z_file):
+ tmp_z_file = "/tmp/" + str(uuid.uuid4()).split('-')[0].upper() + ".Z"
+ open(tmp_z_file,"wb").write(filedata)
+ os.system('tosz "' + tmp_z_file + '"')
+ filedata = open(tmp_z_file.split('.Z')[0],"rb").read()
+ os.remove(tmp_z_file.split('.Z')[0])
+ filesize = len(filedata)
+ if filesize>0:
+ ZeroParamBuf()
+ os.lseek(HGBD,0,os.SEEK_SET)
+ os.write(HGBD,str(filesize))
+ os.lseek(HGBD,BLK_SIZE,os.SEEK_SET)
+ os.write(HGBD,filedata)
+ logger.info("WGet " + url)
+ else:
+ filesize = -1
+ ZeroParamBuf()
+ os.lseek(HGBD,0,os.SEEK_SET)
+ os.write(HGBD,str(filesize))
+ logger.error("error reading url " + url)
+ conn.send(chr(HGC_GETURL))
+
+def HGCHCopy():
+ os.lseek(HGBD,0,os.SEEK_SET)
+ HGBD_PARAM_BUF = os.read(HGBD,BLK_SIZE)
+ filesize = 0
+ fsincr = 0
+ while fsincr<8:
+ fsbyte = ord(HGBD_PARAM_BUF[fsincr:fsincr+1])
+ filesize += fsbyte*(256**fsincr)
+ fsincr += 1
+ os.lseek(HGBD,BLK_SIZE,os.SEEK_SET)
+ clip = os.read(HGBD,filesize)
+ clipboard.copy(clip[clip.find('"')+1:clip.rfind('"')])
+ logger.info("copy clipboard to host")
+ conn.send(chr(HGC_HCOPY))
+
+def HGCHPaste():
+ filedata = clipboard.paste()
+ filedata = filedata.replace('$','$$')
+ filesize = len(filedata)
+ ZeroParamBuf()
+ os.lseek(HGBD,0,os.SEEK_SET)
+ os.write(HGBD,str(filesize))
+ os.lseek(HGBD,BLK_SIZE,os.SEEK_SET)
+ os.write(HGBD,filedata)
+ logger.info("paste clipboard to guest")
+ conn.send(chr(HGC_HPASTE))
+
+def SetHGFSPerms(file):
+ os.system('chown ' + HGBD_CONF["user"] + ':' + HGBD_CONF["user"] + ' "' + file + '"')
+
+BLK_SIZE = 512
+
+HGC_CDH = 0x08
+HGC_COPYG = 0x01
+HGC_COPYH = 0x02
+HGC_SCREENSHOT = 0x03
+HGC_DELH = 0x07
+HGC_DIRCURH = 0x09
+HGC_DIRH = 0x04
+HGC_GETURL = 0x05
+HGC_GETURLSTR = 0x06
+HGC_HCOPY = 0x0A
+HGC_HPASTE = 0x0B
+HGC_NOOP = 0xFF
+
+HGBD_CONF = json.loads(open("/etc/hgbdd.conf","r").read())
+
+logger = logging.getLogger(__name__)
+logger.setLevel(logging.INFO)
+handler = logging.FileHandler(HGBD_CONF["log_file"])
+handler.setLevel(logging.INFO)
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+handler.setFormatter(formatter)
+logger.addHandler(handler)
+
+for module in HGBD_CONF["modules"]:
+ exec(open(HGBD_CONF["modules"][module],"r").read())
+ logger.info("load module: " + module)
+
+try:
+ HGBD = os.open(HGBD_CONF["blk_dev"],os.O_RDWR)
+except Exception as e:
+ logger.error(e)
+ sys.exit()
+
+logger.info("hgbdd started")
+
+s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+try:
+ s.bind((HGBD_CONF["tcp_addr"],HGBD_CONF["tcp_port"]))
+except Exception as e:
+ logger.error(e)
+ sys.exit()
+s.listen(0)
+
+while 1:
+ conn, addr = s.accept()
+ while 1:
+ try:
+ data = ord(conn.recv(1024)[0:1])
+ builtin(data)
+ for m in HGBD_CONF["modules"]:
+ globals()[m](data)
+
+ except Exception as e:
+ logger.error(e)
+ break
+ conn.close()
+
+logger.info("hgbdd exited")
+sys.exit()
diff --git a/hgbdd.conf.example b/hgbdd.conf.example
new file mode 100644
index 0000000..4f711db
--- /dev/null
+++ b/hgbdd.conf.example
@@ -0,0 +1,10 @@
+{
+ "blk_dev":"/dev/ram0",
+ "hgfs_path":"/home/username/TempleOS",
+ "screenshot_path":"/home/username/TempleOS/Screenshots",
+ "log_file":"/var/log/hgbdd.log",
+ "tcp_addr":"127.0.0.1",
+ "tcp_port":7202,
+ "user":"username",
+ "modules":{}
+}