From 8ab9ae7ea31c6628e486e5f7026a9ca02e7aa358 Mon Sep 17 00:00:00 2001 From: philemon Date: Tue, 26 Jul 2016 22:43:24 +0300 Subject: [PATCH] Windows bugfixes, including read/write corruption with incog format Windows test suite runs without errors --- mmgen/filename.py | 4 ++-- mmgen/rpc.py | 5 ++++- mmgen/seed.py | 8 ++++++-- mmgen/term.py | 9 ++++++--- mmgen/tool.py | 3 ++- mmgen/tx.py | 4 ++-- mmgen/util.py | 22 +++------------------- test/test.py | 5 +++-- 8 files changed, 28 insertions(+), 32 deletions(-) diff --git a/mmgen/filename.py b/mmgen/filename.py index 87bb97cb..e4ba0bdc 100755 --- a/mmgen/filename.py +++ b/mmgen/filename.py @@ -48,10 +48,10 @@ class Filename(MMGenObject): die(3,"'%s': not a recognized extension for SeedSource" % self.ext) - # TODO: Check for Windows - mode = (os.O_RDONLY,os.O_RDWR)[bool(write)] import stat if stat.S_ISBLK(os.stat(fn).st_mode): + mode = (os.O_RDONLY,os.O_RDWR)[bool(write)] + if sys.platform[:3] == 'win': mode |= os.O_BINARY try: fd = os.open(fn, mode) except OSError as e: diff --git a/mmgen/rpc.py b/mmgen/rpc.py index 7f473103..c7b12743 100755 --- a/mmgen/rpc.py +++ b/mmgen/rpc.py @@ -26,6 +26,8 @@ from mmgen.common import * class BitcoinRPCConnection(object): + client_version = 0 + def __init__( self, host='localhost',port=8332, @@ -79,10 +81,11 @@ class BitcoinRPCConnection(object): dmsg(' RPC POST data ==> %s\n' % p) from mmgen.obj import BTCAmt + caller = self class MyJSONEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, BTCAmt): - return str(obj) + return (float,str)[caller.client_version>=120000](obj) return json.JSONEncoder.default(self, obj) # pp_msg(json.dumps(p,cls=MyJSONEncoder)) diff --git a/mmgen/seed.py b/mmgen/seed.py index 065b183d..17e29f48 100755 --- a/mmgen/seed.py +++ b/mmgen/seed.py @@ -806,11 +806,13 @@ to exit and re-run the program with the '--old-incog-fmt' option. def _format(self): d = self.ssdata +# print len(d.iv), len(d.salt), len(d.enc_seed), len(d.wrapper_key) self.fmt_data = d.iv + encrypt_data( d.salt + d.enc_seed, d.wrapper_key, int(hexlify(d.iv),16), self.desc) +# print len(self.fmt_data) def _filename(self): s = self.seed @@ -953,7 +955,8 @@ harder to find, you're advised to choose a much larger file size than this. d.target_data_len = self._get_incog_data_len(opt.seed_len) self._check_valid_offset(self.infile,'read') - fh = os.open(self.infile.name,os.O_RDONLY) + flgs = os.O_RDONLY|os.O_BINARY if sys.platform[:3] == 'win' else os.O_RDONLY + fh = os.open(self.infile.name,flgs) os.lseek(fh,int(d.hincog_offset),os.SEEK_SET) self.fmt_data = os.read(fh,d.target_data_len) os.close(fh) @@ -1002,7 +1005,8 @@ harder to find, you're advised to choose a much larger file size than this. self._check_valid_offset(f,'write') if not opt.quiet: confirm_or_exit('',"alter file '%s'" % f.name) - fh = os.open(f.name,os.O_RDWR) + flgs = os.O_RDWR|os.O_BINARY if sys.platform[:3] == 'win' else os.O_RDWR + fh = os.open(f.name,flgs) os.lseek(fh, int(d.hincog_offset), os.SEEK_SET) os.write(fh, self.fmt_data) os.close(fh) diff --git a/mmgen/term.py b/mmgen/term.py index ab92dc08..ad3ca82c 100755 --- a/mmgen/term.py +++ b/mmgen/term.py @@ -224,9 +224,12 @@ def do_pager(text): # 'print' instead of the pager. # We risk assuming that 'more' will always be available on a stock # Windows installation. - if sys.platform.startswith('win') and 'HOME' not in environ: - shell = True - pagers = ['more'] + if sys.platform.startswith('win'): + if 'HOME' not in environ: # native Windows terminal + shell = True + pagers = ['more'] + else: # MSYS + environ['LESS'] = '-cR' # clear screen, disable line chopping if 'PAGER' in environ and environ['PAGER'] != pagers[0]: pagers = [environ['PAGER']] + pagers diff --git a/mmgen/tool.py b/mmgen/tool.py index 8991178d..9410157c 100755 --- a/mmgen/tool.py +++ b/mmgen/tool.py @@ -572,7 +572,8 @@ def decrypt(infile,outfile='',hash_preset=''): def find_incog_data(filename,iv_id,keep_searching=False): ivsize,bsize,mod = g.aesctr_iv_len,4096,4096*8 n,carry = 0,' '*ivsize - f = os.open(filename,os.O_RDONLY) + flgs = os.O_RDONLY|os.O_BINARY if sys.platform[:3] == 'win' else os.O_RDONLY + f = os.open(filename,flgs) for ch in iv_id: if ch not in '0123456789ABCDEF': die(2,"'%s': invalid Incog ID" % iv_id) diff --git a/mmgen/tx.py b/mmgen/tx.py index e9c1c3df..ba633144 100755 --- a/mmgen/tx.py +++ b/mmgen/tx.py @@ -228,12 +228,12 @@ class MMGenTX(MMGenObject): self.txid, self.send_amt, self.timestamp, - (self.blockcount or 'None') + self.blockcount ), self.hex, repr([e.__dict__ for e in self.inputs]), repr([e.__dict__ for e in self.outputs]) - ) + ((b58encode(self.label),) if self.label else ()) + ) + ((b58encode(self.label.encode('utf8')),) if self.label else ()) self.chksum = make_chksum_6(' '.join(lines)) self.fmt_data = '\n'.join((self.chksum,) + lines)+'\n' diff --git a/mmgen/util.py b/mmgen/util.py index 18559254..2d3f7eb8 100755 --- a/mmgen/util.py +++ b/mmgen/util.py @@ -561,7 +561,6 @@ def get_words(infile,desc,prompt): return get_words_from_user(prompt) def remove_comments(lines): - # re.sub(pattern, repl, string, count=0, flags=0) ret = [] for i in lines: i = re.sub(ur'#.*',u'',i,1) @@ -617,7 +616,6 @@ def get_mmgen_passphrase(desc,passchg=False): else: return ' '.join(get_words_from_user(prompt)) - def get_bitcoind_passphrase(prompt): if opt.passwd_file: pwfile_reuse_warning() @@ -626,22 +624,6 @@ def get_bitcoind_passphrase(prompt): return my_raw_input(prompt, echo=opt.echo_passphrase) -def check_data_fits_file_at_offset(fname,offset,dlen,action): - # TODO: Check for Windows - if stat.S_ISBLK(os.stat(fname).st_mode): - fd = os.open(fname, os.O_RDONLY) - fsize = os.lseek(fd, 0, os.SEEK_END) - os.close(fd) - else: - fsize = os.stat(fname).st_size - - if fsize < offset + dlen: - m = ('Input','Destination')[action == 'write'] - die(1, - '%s file has length %s, too short to %s %s bytes of data at offset %s' - % (m,fsize,action,dlen,offset)) - - def get_hash_preset_from_user(hp=g.hash_preset,desc='data'): p = """Enter hash preset for %s, or hit ENTER to accept the default value ('%s'): """ % (desc,hp) @@ -766,5 +748,7 @@ def bitcoin_connection(): auth_cookie = get_bitcoind_auth_cookie() import mmgen.rpc - return mmgen.rpc.BitcoinRPCConnection( + c = mmgen.rpc.BitcoinRPCConnection( host,port,cfg[user],cfg[passwd],auth_cookie=auth_cookie) + c.client_version = int(c.getinfo()['version']) + return c diff --git a/test/test.py b/test/test.py index 20df29e1..b6edeffa 100755 --- a/test/test.py +++ b/test/test.py @@ -668,7 +668,8 @@ class MMGenExpect(object): if extra_desc: desc += ' ' + extra_desc for i in cmd_args: if type(i) not in (str,unicode): - die(2,'Error: missing input files in cmd line?:\n%s' % cmd_args) + fs = 'Error: missing input files in cmd line?:\nName: {}\nCmd: {}\nCmd args: {}' + die(2,fs.format(name,mmgen_cmd,cmd_args)) cmd_str = mmgen_cmd + ' ' + ' '.join(cmd_args) if opt.log: log_fd.write(cmd_str+'\n') @@ -1215,7 +1216,7 @@ class MMGenTestSuite(object): add_args = ([],['-q'])[ni] if ni: m = '\nAnswer the interactive prompts as follows:\n' + \ - " 'y', 'y', 'q', '1-8', ENTER, ENTER, ENTER, 'y'" + " 'y', 'y', 'q', '1-9', ENTER, ENTER, ENTER, 'y'" msg(grnbg(m)) t = MMGenExpect(name,'mmgen-txcreate',['-f','0.0001'] + add_args + cmd_args) if ni: return