From 32b35b8d92075dc25f2e29be5a10648e2e5cbda6 Mon Sep 17 00:00:00 2001 From: Noel Power Date: Mon, 24 Mar 2014 20:35:50 +0000 Subject: [PATCH] script to generate content for libcli/util/nterr.c & libcli/util/ntstatus.h A ropey script to generate some missing NT_STATUS error codes and and descriptions. The script generates ntstatus.c & ntstatus.h whose contents are used to extend the existing contents of libcli/util/nterr.c & libcli/util/ntstatus.h Signed-off-by: Noel Power Reviewed-by: David Disseldorp Reviewed-by: Stefan Metzmacher Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Wed Apr 2 22:40:06 CEST 2014 on sn-devel-104 --- source4/scripting/bin/gen_ntstatus.py | 243 ++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100755 source4/scripting/bin/gen_ntstatus.py diff --git a/source4/scripting/bin/gen_ntstatus.py b/source4/scripting/bin/gen_ntstatus.py new file mode 100755 index 00000000000..3625ad72cac --- /dev/null +++ b/source4/scripting/bin/gen_ntstatus.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python + +# +# Unix SMB/CIFS implementation. +# +# HRESULT Error definitions +# +# Copyright (C) Noel Power 2014 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import sys, os.path, io, string + +# parsed error data +Errors = [] +# error definitions to output +ErrorsToUse = [] +ErrorsToCreatDescFor = [] + +# some lookup dictionaries +DefineToErrCode = {}; +ErrCodeToDefine = {}; + +# error data model +class ErrorDef: + + def __init__(self): + self.err_code = None + self.err_define = None + self.err_string = "" + self.linenum = "" + +def escapeString( input ): + output = input.replace('"','\\"') + output = output.replace("\\<","\\\\<") + output = output.replace('\t',"") + return output + +def transformErrorName( error_name ): + new_name = error_name + if error_name.startswith("STATUS_"): + error_name = error_name.replace("STATUS_","",1) + elif error_name.startswith("RPC_NT_"): + error_name = error_name.replace("RPC_NT_","RPC_",1) + elif error_name.startswith("EPT_NT_"): + error_name = error_name.replace("EPT_NT_","EPT_",1) + new_name = "NT_STATUS_" + error_name + return new_name + +def parseErrorDescriptions( file_contents, isWinError ): + count = 0 + for line in file_contents: + content = line.strip().split(None,1) + # start new error definition ? + if line.startswith("0x"): + newError = ErrorDef() + newError.err_code = int(content[0],0) + # escape the usual suspects + if len(content) > 1: + newError.err_string = escapeString(content[1]) + newError.linenum = count + newError.isWinError = isWinError + Errors.append(newError) + else: + if len(Errors) == 0: + print "Error parsing file as line %d"%count + sys.exit() + err = Errors[-1] + if err.err_define == None: + err.err_define = transformErrorName(content[0]) + else: + if len(content) > 0: + desc = escapeString(line.strip()) + if len(desc): + if err.err_string == "": + err.err_string = desc + else: + err.err_string = err.err_string + " " + desc + count = count + 1 + print "parsed %d lines generated %d error definitions"%(count,len(Errors)) + +def parseErrCodeString(error_code_string): + # we could develop this more and *really* parse it but realistically + # we are only interested in NT_STATUS( mask | code ) or NT_STATUS( code ) + parts = error_code_string.split('|',1) + code = None + try: + if len(parts) > 1: + if len(parts) > 2: #something weird, better warn + print "warning something weird unexpected errorcode format ->%s<-"%error_code_string + code = int(parts[0],0) | int(parts[1],0) + else: + code = int(error_code_string,0) + except: + pass + return code + +def parseHeaderFile(file_contents): + count = 0 + for line in file_contents: + contents = line.strip().split(None,2) + err_code_string = None + err_code = None + + if len(contents) > 2: + if contents[0] == "#define" and contents[2].startswith("NT_STATUS("): + # hairy parsing of lines like + # "#define SOMETHING NT_STATUS( num1 | num2 )" etc... + err_code_string = contents[2].split('(')[1].split(')')[0] + err_code = parseErrCodeString( err_code_string ) + if err_code != None: + const_define = contents[1] +# print "%s 0x%x"%(const_define, err_code) + DefineToErrCode[const_define] = err_code + ErrCodeToDefine[err_code] = const_define + else: + print "warning: failed to process line[%d] ->%s<-"%(count,line) + count = count + 1 + print "read %d error declarations from header file"%len(ErrCodeToDefine) + +def generateHeaderFile(out_file): + out_file.write("\n\n") + out_file.write("/*\n") + out_file.write(" * New descriptions for new errors generated from\n") + out_file.write(" * [MS-ERREF] http://msdn.microsoft.com/en-us/library/cc704588.aspx\n") + out_file.write(" */\n\n") + for err in ErrorsToUse: + line = "#define {0:49} NT_STATUS(0x{1:08X})\n".format(err.err_define ,err.err_code) + out_file.write(line) + + +def generateSourceFile(out_file): + out_file.write("/*\n") + out_file.write(" * New descriptions for existing errors generated from\n") + out_file.write(" * [MS-ERREF] http://msdn.microsoft.com/en-us/library/cc704588.aspx\n") + out_file.write(" */\n") + for err in ErrorsToCreatDescFor: + out_file.write(" { N_(\"%s\"), %s },\n"%(err.err_string, err.err_define)) + out_file.write("\n\n") + out_file.write("/*\n") + out_file.write(" * New descriptions for new errors generated from\n") + out_file.write(" * [MS-ERREF] http://msdn.microsoft.com/en-us/library/cc704588.aspx\n") + out_file.write(" */\n") + for err in ErrorsToUse: + out_file.write(" { N_(\"%s\"), %s },\n"%(err.err_string, err.err_define)) + out_file.write("\n\n"); + out_file.write("/*\n") + out_file.write(" * New descriptions for new errors generated from\n") + out_file.write(" * [MS-ERREF] http://msdn.microsoft.com/en-us/library/cc704588.aspx\n") + out_file.write(" */\n") + for err in ErrorsToUse: + out_file.write(" { \"%s\", %s },\n"%(err.err_define, err.err_define)) + +def def_in_list(define, err_def_with_desc): + for item in err_def_with_desc: + if item.strip() == define: + return True + return False + +def processErrorDescription(err_def_with_desc): + print "processing error descriptions...." + count = 0 + for err in Errors: + # do we have an error with this error code already ? + if ErrCodeToDefine.has_key(err.err_code): + already_has_desc = def_in_list(ErrCodeToDefine[err.err_code], err_def_with_desc) + # no 'full' error description for this error code so create a new + # one + if already_has_desc == False: + # synthesise a new Error object to create desc from + new_error = ErrorDef() + new_error.err_define = ErrCodeToDefine[err.err_code] + new_error.err_code = err.err_code + new_error.err_string = err.err_string + new_error.linenum = err.linenum + ErrorsToCreatDescFor.append(new_error) + count = count + 1 + else: + ErrorsToUse.append(err) + if count > 0: + print "skipped %d existing definitions"%count + print "imported %d new error definitions"%(len(ErrorsToUse)) + print "created %d new error descriptions for existing errors"%(len(ErrorsToCreatDescFor)) + +# Very simple script to generate files ntstatus.c & ntstatus.h, these +# files contain generated content used to add to the existing content +# of files nterr.c & ntstatus.h. +# The script takes 3 inputs +# 1. location of the existing ntstatus.h (which is used to build a list of +# existing error defines +# 2. a text file, format which is very simple and is just the content of a +# html table ( such as that found in +# http://msdn.microsoft.com/en-us/library/cc231200.aspx ) copied and +# pasted into a text file +# 3. finally a text file containing names of the error defines (1 per line) +# that already are in ntstatus.h/nterr.c but that only have the 'short' +# error description ( short error description is where the description is +# the name of the error itself e.g. "NT_STATUS_SUCCESS" etc. + +def main (): + input_file1 = None; + input_file2 = None; + filename = "ntstatus" + headerfile_name = filename + ".h" + sourcefile_name = filename + ".c" + if len(sys.argv) > 3: + input_file1 = sys.argv[1] + input_file2 = sys.argv[2] + input_file3 = sys.argv[3] + else: + print "usage: %s headerfile winerrorfile existing_short_descs"%(sys.argv[0]) + sys.exit() + + # read in the data + file_contents = open(input_file1,"r") + parseHeaderFile(file_contents) + file_contents = open(input_file2,"r") + parseErrorDescriptions(file_contents, False) + file_contents = open(input_file3,"r") + has_already_desc = file_contents.readlines() + processErrorDescription(has_already_desc) + out_file = open(headerfile_name,"w") + generateHeaderFile(out_file) + out_file.close() + out_file = open(sourcefile_name,"w") + generateSourceFile(out_file) + out_file.close() + +if __name__ == '__main__': + + main() -- 2.11.4.GIT