diff options
-rw-r--r-- | HGBD.HC | 257 | ||||
-rw-r--r-- | LICENSE | 116 | ||||
-rw-r--r-- | README.md | 72 | ||||
-rw-r--r-- | example.gif | bin | 0 -> 320373 bytes | |||
-rw-r--r-- | hgbdd | 311 | ||||
-rw-r--r-- | hgbdd.conf.example | 10 |
6 files changed, 766 insertions, 0 deletions
@@ -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; @@ -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 Binary files differnew file mode 100644 index 0000000..62321a4 --- /dev/null +++ b/example.gif @@ -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":{} +} |