import base64 import glob import sys import getopt import os import tempfile OUTPUT_EXTENSION = '.hid' #--------------------------------------------------------------------------- def usage(): print 'This program will "hide" (i.e., reformat and rename) the files specified' print 'using the options below, and can "unhide" those files later.' print "There's nothing particularly sophisticated about the way the files are" print '"hidden", so don\'t trust it blindly! Hidden files are given a new name' print 'with a .hid extension. The original name is restored when the file is' print 'unhidden.' print print "Options:" print "-?: shows this message." print "-h [wildcard]: to hide (i.e., encode) files." print "-u [directory]: to unhide (i.e., decode) .hid files." print "Either -h or -u is required." print "If you pass a wildcard with -h, only matching files will be hidden," print "otherwise, all files in the current directory will be hidden." print " Eg.: -h c:\\images\\*.jpg, or -h *.doc" print "If you pass a directory with -u, *.hid files in that directory will be unhidden," print "otherwise, all *.hid files in the current directory will be unhidden." print " Eg.: -u c:\\images" print "If there is a space in a directory name, surround the entire path in quotes." print "-f : to hide/unhide a specific file only. Use with -h or -u." #--------------------------------------------------------------------------- # Class to add original file name to files being written, and to extract that # filename from files being read. class HiderFile(file): BYTES_FOR_FILENAME_LENGTH = 4 #-------------------- def __init__(self, filename, mode, originalFilename = ''): file.__init__(self, filename, mode) if 'w' in mode: assert(originalFilename != '') # When opened for writing, originalFilename is passed in and holds the original file name # which will be embedded into the encoded file. filename = base64.encodestring(os.path.basename(originalFilename)) file.write(self, "%%%dd%%s" % self.BYTES_FOR_FILENAME_LENGTH % (len(filename), filename)) else: # When opened for reading, self.originalFilename will hold the original file name extracted. # Read first bytes to see how many more bytes to read to get filename. filenameLength = int(file.read(self, self.BYTES_FOR_FILENAME_LENGTH)) self.originalFilename = base64.decodestring(file.read(self, filenameLength)) #--------------------------------------------------------------------------- def parseArgs(args_): try: opts, args = getopt.getopt(args_, "?huf:") #print opts, args assert(len(args) < 2) except (getopt.GetoptError, AssertionError): usage() sys.exit(1) bareArgs = [x for (x,y) in opts] invalidOptions = '-u' in bareArgs and '-h' in bareArgs if invalidOptions: usage() sys.exit(1) wildcard = None directory = None specificFile = None mode = None for o, a in opts: if o == "-?": usage() sys.exit(1) if o == "-u": if mode is not None: usage() sys.exit(1) mode = 'unhide' directory = len(args) == 1 and args[0] or '' if o == "-h": if mode is not None: usage() sys.exit(1) mode = 'hide' wildcard = len(args) == 1 and args[0] or '*' if o == "-f": specificFile = a if mode is None: usage() sys.exit(1) return mode, wildcard or directory, specificFile #--------------------------------------------------------------------------- def hideFiles(files_): if len(files_) == 0: print "No files to hide" return for filename in files_: try: fin = open(filename, 'rb') handle, outfilename = tempfile.mkstemp(prefix = '', suffix = OUTPUT_EXTENSION, dir = os.path.dirname(filename)) # Just close the low level handle so we can use normal file operations. os.close(handle) print "Encoding %s --> %s" % (filename, outfilename) fout = HiderFile(outfilename, 'w', filename) base64.encode(fin, fout) fin.close() fout.close() os.unlink(filename) except: print "Oops, that file failed" raise #--------------------------------------------------------------------------- def unhideFiles(files_): if len(files_) == 0: print "No *.hid files found" return for filename in files_: try: fin = HiderFile(filename, 'r') outfilename = os.path.join(os.path.dirname(filename), fin.originalFilename) print "Decoding %s --> %s" % (filename, outfilename) fout = open(outfilename, 'wb') base64.decode(fin, fout) fin.close() fout.close() os.unlink(filename) except: print "Oops, that file failed" raise #--------------------------------------------------------------------------- def main(args_): mode, path, specificFile = parseArgs(args_) #print mode, path, specificFile if mode == 'hide': files = specificFile and [specificFile] or glob.glob(path) files = filter(os.path.isfile, files) hideFiles(files) elif mode == 'unhide': files = specificFile and [specificFile] or glob.glob(os.path.join(path, "*%s" % OUTPUT_EXTENSION)) files = filter(os.path.isfile, files) unhideFiles(files) #--------------------------------------------------------------------------- if __name__ == '__main__': main(sys.argv[1:])