📄 magic.py
字号:
print >>sys.stderr, '$$', m.groupdict() raise return raise OffsetError(`s`) def __call__(self,file=None): if self.value is not None : return self.value pos = file.tell() try: if not self.relative : file.seek( self.offset, 0 ) frmt = Offset.pos_format.get( self.type, 'I' ) size = struct.calcsize( frmt ) data = struct.unpack( frmt, file.read( size ) ) if self.offs : data += self.offs return data finally: file.seek( pos, 0 ) def __str__(self): return self.source def __repr__(self): return 'Offset(%s)' % `self.source`#end class Offsetclass MagicFileError(MagicError): passclass MagicFile: def __init__(self,filename=_magic): self.file = None self.tests = [] self.total_tests = 0 self.load( filename ) self.ack_tests = None self.nak_tests = None def __del__(self): self.close() def load(self,filename=None): self.open( filename ) self.parse() self.close() def open(self,filename=None): self.close() if filename is not None : self.filename = filename self.file = open( self.filename, 'r', BUFFER_SIZE ) def close(self): if self.file : self.file.close() self.file = None def parse(self): line_no = 0 for line in self.file.xreadlines() : line_no += 1 if not line or line[0]=='#' : continue line = line.lstrip().rstrip('\r\n') if not line or line[0]=='#' : continue try: x = self.parse_line( line ) if x is None : print >>sys.stderr, '#[%04d]#'%line_no, line continue except: print >>sys.stderr, '###[%04d]###'%line_no, line raise self.total_tests += 1 level, offset, mtype, test, message = x new_test = MagicTest(offset,mtype,test,message, line=line_no,level=level) try: if level == 0 : self.tests.append( new_test ) else: self.tests[-1].add( new_test ) except: if 1 : print >>sys.stderr, 'total tests=%s' % ( `self.total_tests`, ) print >>sys.stderr, 'level=%s' % ( `level`, ) print >>sys.stderr, 'tests=%s' % ( pprint.pformat(self.tests), ) raise else: while self.tests[-1].level > 0 : self.tests.pop() def parse_line(self,line): # print >>sys.stderr, 'line=[%s]' % line if (not line) or line[0]=='#' : return None level = 0 offset = mtype = test = message = '' mask = None # get optional level (count leading '>') while line and line[0]=='>' : line, level = line[1:], level+1 # get offset while line and not line[0].isspace() : offset, line = offset+line[0], line[1:] try: offset = Offset(offset) except: print >>sys.stderr, 'line=[%s]' % line raise # skip spaces line = line.lstrip() # get type c = None while line : last_c, c, line = c, line[0], line[1:] if last_c!='\\' and c.isspace() : break # unescaped space - end of field else: mtype += c if last_c == '\\' : c = None # don't fuck my brain with sequential backslashes # skip spaces line = line.lstrip() # get test c = None while line : last_c, c, line = c, line[0], line[1:] if last_c!='\\' and c.isspace() : break # unescaped space - end of field else: test += c if last_c == '\\' : c = None # don't fuck my brain with sequential backslashes # skip spaces line = line.lstrip() # get message message = line if mime and line.find("\t") != -1: message=line[0:line.find("\t")] # # print '>>', level, offset, mtype, test, message return level, offset, mtype, test, message def detect(self,file): self.ack_tests = 0 self.nak_tests = 0 answers = [] for test in self.tests : message = test.run( file ) if message : self.ack_tests += 1 answers.append( message ) else: self.nak_tests += 1 if answers : return '; '.join( answers )#end class MagicFiledef username(uid): try: return pwd.getpwuid( uid )[0] except: return '#%s'%uiddef groupname(gid): try: return grp.getgrgid( gid )[0] except: return '#%s'%giddef get_file_type(fname,follow): t = None if not follow : try: st = os.lstat( fname ) # stat that entry, don't follow links! except os.error, why : pass else: if stat.S_ISLNK(st[stat.ST_MODE]) : t = 'symbolic link' try: lnk = os.readlink( fname ) except: t += ' (unreadable)' else: t += ' to '+lnk if t is None : try: st = os.stat( fname ) except os.error, why : return "can't stat `%s' (%s)." % (why.filename,why.strerror) dmaj, dmin = (st.st_rdev>>8)&0x0FF, st.st_rdev&0x0FF if 0 : pass elif stat.S_ISSOCK(st.st_mode) : t = 'socket' elif stat.S_ISLNK (st.st_mode) : t = follow and 'symbolic link' or t elif stat.S_ISREG (st.st_mode) : t = 'file' elif stat.S_ISBLK (st.st_mode) : t = 'block special (%d/%d)'%(dmaj,dmin) elif stat.S_ISDIR (st.st_mode) : t = 'directory' elif stat.S_ISCHR (st.st_mode) : t = 'character special (%d/%d)'%(dmaj,dmin) elif stat.S_ISFIFO(st.st_mode) : t = 'pipe' else: t = '<unknown>' if st.st_mode & stat.S_ISUID : t = 'setuid(%d=%s) %s'%(st.st_uid,username(st.st_uid),t) if st.st_mode & stat.S_ISGID : t = 'setgid(%d=%s) %s'%(st.st_gid,groupname(st.st_gid),t) if st.st_mode & stat.S_ISVTX : t = 'sticky '+t return tHELP = '''%s [options] [files...]Options: -?, --help -- this help -m, --magic=<file> -- use this magic <file> instead of %s -f, --files=<namefile> -- read filenames for <namefile>* -C, --compile -- write "compiled" magic file -b, --brief -- don't prepend filenames to output lines+ -c, --check -- check the magic file -i, --mime -- output MIME types* -k, --keep-going -- don't stop st the first match -n, --flush -- flush stdout after each line -v, --verson -- print version and exit* -z, --compressed -- try to look inside compressed files -L, --follow -- follow symlinks -s, --special -- don't skip special files* -- not implemented so far ;-)+ -- implemented, but in another way...'''def main(): import getopt global _magic try: brief = 0 flush = 0 follow= 0 mime = 0 check = 0 special=0 try: opts, args = getopt.getopt( sys.argv[1:], '?m:f:CbciknvzLs', ( 'help', 'magic=', 'names=', 'compile', 'brief', 'check', 'mime', 'keep-going', 'flush', 'version', 'compressed', 'follow', 'special', ) ) except getopt.error, why: print >>sys.stderr, sys.argv[0], why return 1 else: files = None for o,v in opts : if o in ('-?','--help'): print HELP % ( sys.argv[0], _magic, ) return 0 elif o in ('-f','--files='): files = v elif o in ('-m','--magic='): _magic = v[:] elif o in ('-C','--compile'): pass elif o in ('-b','--brief'): brief = 1 elif o in ('-c','--check'): check = 1 elif o in ('-i','--mime'): mime = 1 if os.path.exists( _magic+'.mime' ) : _magic += '.mime' print >>sys.stderr,sys.argv[0]+':',\ "Using regular magic file `%s'" % _magic elif o in ('-k','--keep-going'): pass elif o in ('-n','--flush'): flush = 1 elif o in ('-v','--version'): print 'VERSION' return 0 elif o in ('-z','--compressed'): pass elif o in ('-L','--follow'): follow = 1 elif o in ('-s','--special'): special = 1 else: if files : files = map(lambda x: x.strip(), v.split(',')) if '-' in files and '-' in args : error( 1, 'cannot use STDIN simultaneously for file list and data' ) for file in files : for name in ( (file=='-') and sys.stdin or open(file,'r',BUFFER_SIZE) ).xreadlines(): name = name.strip() if name not in args : args.append( name ) try: if check : print >>sys.stderr, 'Loading magic database...' t0 = time.time() m = MagicFile(_magic) t1 = time.time() if check : print >>sys.stderr, \ m.total_tests, 'tests loaded', \ 'for', '%.2f' % (t1-t0), 'seconds' print >>sys.stderr, len(m.tests), 'tests at top level' return 0 # XXX "shortened" form ;-) mlen = max( map(len, args) )+1 for arg in args : if not brief : print (arg + ':').ljust(mlen), ftype = get_file_type( arg, follow ) if (special and ftype.find('special')>=0) \ or ftype[-4:] == 'file' : t0 = time.time() try: t = m.detect( arg ) except (IOError,os.error), why: t = "can't read `%s' (%s)" % (why.filename,why.strerror) if ftype[-4:] == 'file' : t = ftype[:-4] + t t1 = time.time() print t and t or 'data' if 0 : print \ '#\t%d tests ok, %d tests failed for %.2f seconds'%\ (m.ack_tests, m.nak_tests, t1-t0) else: print mime and 'application/x-not-regular-file' or ftype if flush : sys.stdout.flush() # print >>sys.stderr, 'DONE' except: if check : return 1 raise else: return 0 finally: passif __name__ == '__main__' : sys.exit( main() )# vim:ai# EOF #
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -