Sindbad~EG File Manager

Current Path : /opt/microsoft/omsconfig/Scripts/2.4x-2.5x/Scripts/
Upload File :
Current File : //opt/microsoft/omsconfig/Scripts/2.4x-2.5x/Scripts/nxFileInventory.py

#!/usr/bin/env python
# ====================================
#  Copyright (c) Microsoft Corporation.
#  All rights reserved.
#  See license.txt for license information.
# ====================================

import os
import sys
import pwd
import grp
import codecs
import fnmatch
import copy
import imp
protocol = imp.load_source('protocol', '../protocol.py')
nxDSCLog = imp.load_source('nxDSCLog', '../nxDSCLog.py')
LG = nxDSCLog.DSCLog
try:
    import hashlib
    md5const = hashlib.md5
    shaconst = hashlib.sha256
except ImportError: # Only sha-1 is available for python2.4.
    import md5
    md5const = md5.md5
    import sha
    shaconst = sha.sha

# [ClassVersion("1.0.0"), Description("The configuration provider for files and directories."), FriendlyName("nxFileInventory")]
# class MSFT_nxFileInventoryResource:OMI_BaseResource
# {
#   [Key, InventoryFilter] string DestinationPath;
#   [Write, InventoryFilter] boolean Recurse;  //default = false
#   [Write, InventoryFilter] boolean UseSudo;  //default = false
#   [Write, ValueMap{"follow", "manage", "ignore" }, Values{"follow", "manage", "ignore"},InventoryFilter] string Links; //default follow
#   [Write, ValueMap{"md5", "sha-256", "mtime", "ctime"}, Values{"md5","sha-256","mtime","ctime"},InventoryFilter] string Checksum; //default md5
#   [Write, ValueMap{"file", "directory", "*"},Values{"file", "directory","*"}, InventoryFilter] string Type; //default *
#   [Write, InventoryFilter] uint32 MaxContentsReturnable;  //default 1024 bytes
#   [Write, InventoryFilter] uint64 MaxOutputSize; //default 10485760 bytes
#   [Read] string Contents;
#   [Read] datetime ModifiedDate;
#   [Read] datetime CreatedDate; 
#   [Read] string Mode;
#   [Read] string Group;
#   [Read] string Owner;     
#   [Read] uint64 FileSize;
# };

#{'Links': u'ignore', 'MaxOutputSize': None, 'Checksum': u'md5', 'Recurse': None, 'MaxContentsReturnable': None, 'DestinationPath': u'/tmp', 'Type': u'directory'}

def init_locals(DestinationPath, Recurse, Links, Checksum, Type, MaxContentsReturnable, MaxOutputSize, UseSudo):
    if DestinationPath is None :
        DestinationPath = ''
    if Recurse is None :
        Recurse = False
    if UseSudo is None :
        UseSudo = False
    if Links is None :
        Links = 'follow'
    if Checksum is None :
        Checksum = 'md5'
    if Type is None :
        Type = '*'
    if MaxContentsReturnable is None or MaxContentsReturnable < 0:
        MaxContentsReturnable = 1024
    if MaxOutputSize is None or MaxOutputSize < 0:
        MaxOutputSize = 10485760
    return DestinationPath.encode('ascii', 'ignore'), Recurse, Links.encode('ascii', 'ignore').lower(), \
        Checksum.encode('ascii', 'ignore').lower(), Type.encode('ascii', 'ignore').lower(), \
        MaxContentsReturnable, MaxOutputSize, UseSudo


def Set_Marshall(DestinationPath, Recurse, Links, Checksum, Type, MaxContentsReturnable, MaxOutputSize, UseSudo):
    return [0]

def Test_Marshall(DestinationPath, Recurse, Links, Checksum, Type, MaxContentsReturnable, MaxOutputSize, UseSudo):
    return [0]

def Get_Marshall(DestinationPath, Recurse, Links, Checksum, Type, MaxContentsReturnable, MaxOutputSize, UseSudo):
    arg_names = list(locals().keys())
    DestinationPath, Recurse, Links, Checksum, Type, MaxContentsReturnable, MaxOutputSize, UseSudo \
            = init_locals(DestinationPath, Recurse, Links, Checksum, Type, MaxContentsReturnable, MaxOutputSize, UseSudo)
    retval = 0
    DestinationPath = protocol.MI_String(DestinationPath)
    Type = protocol.MI_String(Type)
    MaxContentsReturnable =  protocol.MI_Uint32(MaxContentsReturnable)
    MaxOutputSize =  protocol.MI_Uint64(MaxOutputSize)
    Recurse = protocol.MI_Boolean(Recurse)
    UseSudo = protocol.MI_Boolean(UseSudo)
    Links = protocol.MI_String(Links)
    Checksum = protocol.MI_String(Checksum)
    Contents = protocol.MI_String('')
    ModifiedDate = protocol.MI_Timestamp.from_time(0)
    CreatedDate = protocol.MI_Timestamp.from_time(0)
    Mode = protocol.MI_String('')
    Group = protocol.MI_String('')
    Owner = protocol.MI_String('')
    FileSize = protocol.MI_Uint64(0)
    arg_names.extend(['Contents', 'ModifiedDate', 'CreatedDate', 'Mode', 'Group', 'Owner', 'FileSize'])
    retd = {}
    ld = locals()
    for k in arg_names :
        retd[k] = ld[k]
    return retval, retd

def Inventory_Marshall(DestinationPath, Recurse, Links, Checksum, Type, MaxContentsReturnable, MaxOutputSize, UseSudo):
    DestinationPath, Recurse, Links, Checksum, Type, MaxContentsReturnable, MaxOutputSize, UseSudo \
                     = init_locals(DestinationPath, Recurse, Links, Checksum, Type, MaxContentsReturnable, MaxOutputSize, UseSudo)
    retval = 0
    out_size_cur = 158 # xml output header + footer length.
    xml_overhead_array_element = 99 # xml output overhead per Inventory array entry.
    xml_overhead_param = 102 # xml output overhead per Inventory parameter.
    _Inventory = []
    Inventory = DoInventory(DestinationPath, Recurse, Links, Checksum, Type, MaxContentsReturnable, MaxOutputSize, UseSudo)
    for d in Inventory:
        if out_size_cur <  MaxOutputSize:
            out_size_cur += xml_overhead_array_element
            for k,v in d.items():
                out_size_cur += xml_overhead_param
                if 'Date' in k:
                    out_size_cur += len(k) + 25 + 3 # The final date format wil be 25 chars, +3 for type tag. 
                else:
                    out_size_cur += len(k) + len(repr(v)) -2 # The repr(v) will add two quotes.
        if out_size_cur >=  MaxOutputSize:
            break
        d['DestinationPath'] = protocol.MI_String(d['DestinationPath'])
        d['Checksum'] = protocol.MI_String(d['Checksum'])
        d['Type'] = protocol.MI_String(d['Type'])
        d['Contents'] = protocol.MI_String(str(MaxContentsReturnable))
        d['ModifiedDate'] = protocol.MI_Timestamp.from_time(d['ModifiedDate'])
        d['CreatedDate'] = protocol.MI_Timestamp.from_time(d['CreatedDate'])
        d['Mode'] = protocol.MI_String(d['Mode'])
        d['Group'] = protocol.MI_String(d['Group'])
        d['Owner'] = protocol.MI_String(d['Owner'])
        d['FileSize'] = protocol.MI_Uint64(d['FileSize'])
        _Inventory.append(d)
    _Inventory = protocol.MI_InstanceA(_Inventory)
    retd = {}
    retd["__Inventory"] = _Inventory
    return retval, retd


def DoInventory(DestinationPath, Recurse, Links, Checksum, Type, MaxContentsReturnable, MaxOutputSize, UseSudo):
    Inventory = []
    full_path = DestinationPath.split('/')
    if full_path[-1] == '':
        full_path[-1] = '*'
    wildcard_path = False
    for p in full_path:
        if '*' in p or '?' in p:
            wildc_start=full_path.index(p)
            wildcard_path = True
            break
    if wildcard_path:
        top = '/' + os.path.join(*full_path[:wildc_start])
    else :
        top = '/' + os.path.join(*full_path)
    if not os.path.exists(top):
        print("Error: Unable to read 'DestinationPath': " + DestinationPath)
        LG().Log("ERROR","Unable to read 'DestinationPath': " + DestinationPath)
        return Inventory
    if not wildcard_path:
        if Links == 'ignore' and os.path.islink(top):
            return Inventory
        if Type != 'directory' and os.path.isfile(top): # This is s single file.
            d = GetFileInfo(top, Links, MaxContentsReturnable, Checksum)
            if 'DestinationPath' in d.keys():
                Inventory.append(copy.deepcopy(d))
            return Inventory
        if '*' not in full_path[-1] and '?' not in full_path[-1]:
            full_path.append('*') # It is a directory without the trailing '/', so add it.
    dirs = set()
    full_path_len =  len(full_path)
    for dirpath, dirnames, filenames in walk(top, followlinks=(Links == 'follow'), topdown=True):
        dlen = len(dirpath.split('/'))
        if dirpath.split('/')[-1] == '':
            dlen -= 1
        if wildcard_path and full_path_len >= dlen+1:
            do_wildcard = True
        else :
            do_wildcard = False
        st = os.stat(dirpath)
        scandirs = []
        if dlen+1 == full_path_len  or ( Recurse and dlen >= full_path_len ):
            for filename in filenames:
                if (dlen+1 == full_path_len  or ( Recurse and dlen >= full_path_len )) \
                       and not fnmatch.fnmatch(filename, full_path[-1]):
                    continue
                if Type != 'directory':
                    d = GetFileInfo(os.path.join(dirpath, filename),\
                                    Links, MaxContentsReturnable, Checksum)
                    if 'DestinationPath' in d.keys():
                        Inventory.append(copy.deepcopy(d))
        for dirname in dirnames:
            if not ( Recurse and dlen+1 >= full_path_len ):
                if ( do_wildcard and not fnmatch.fnmatch(dirname, full_path[dlen]) ) or \
                       ( not Recurse and dlen > full_path_len ):
                    continue
            st = os.stat(os.path.join(dirpath, dirname)) # use Lstat if follow?
            dirkey = st.st_dev, st.st_ino
            if dirkey not in dirs:
                if Recurse or (not Recurse and dlen+1 < full_path_len)  :
                    dirs.add(dirkey)
                    scandirs.append(dirname)
            if Type != 'file' and ( dlen+1 == full_path_len  or  ( Recurse and dlen >= full_path_len ) ) :
                d = GetDirInfo(os.path.join(dirpath, dirname), st, Checksum, Links)
                if 'DestinationPath' in d.keys():
                    Inventory.append(copy.deepcopy(d))
        dirnames[:] = scandirs
    return Inventory


def GetFileInfo(fname, Links, MaxContentsReturnable, Checksum):
    """
    Return a dictionary of info for file.
    If 'Links' == 'follow', no link files will appear here,
    those links will be sent to GetDirInfo() as direcroties.
    Therefore only LStatFile is used.
    If file is link and 'Links' == 'ignore' {} is returned.
    """
    fileContentChecksum = "@{{Algoritm=%s Hash=%s Path=%s}}"
    d = {}

    if fname.endswith("omsadmin.conf"):
        return d

    if os.path.islink(fname):
        d['Type'] = 'link'
    else :
        d['Type'] = 'file'
    if d['Type'] == 'link' and Links == 'ignore':
        return {}
    stat_info = None
    stat_info = LStatFile(fname)
    if stat_info == None:
        return {}
    d['DestinationPath'] = fname
    try:
        d['Owner'] = pwd.getpwuid(stat_info.st_uid).pw_name
    except:
        d['Owner'] = str(stat_info.st_uid)
    try:
        d['Group'] = grp.getgrgid(stat_info.st_gid).gr_name
    except:
        d['Group'] = str(stat_info.st_gid)
    d['Mode'] = str(oct(stat_info.st_mode))[-3:]
    d['ModifiedDate'] = int(stat_info.st_mtime)
    d['CreatedDate'] = int(stat_info.st_ctime)
    d['FileSize'] = stat_info.st_size
    # if file size is 0 
    # dont attempt to read the file
    if stat_info.st_size == 0:
       d['Contents'] = ''
       if Checksum == 'md5' or Checksum == 'sha-256':
        d['Checksum'] = "" 
       elif Checksum == "ctime":
        d['Checksum']= str(int(stat_info.st_ctime))
       else : # Checksum == "mtime":
        d['Checksum']= str(int(stat_info.st_mtime))
       return d

    if Checksum == 'md5' or Checksum == 'sha-256':
        fileHash = GetChecksum(fname,Checksum)
        d['Checksum'] = fileContentChecksum % (Checksum.upper(), fileHash.upper(), fname)
    elif Checksum == "ctime":
        d['Checksum']= str(int(stat_info.st_ctime))
    else : # Checksum == "mtime":
        d['Checksum']= str(int(stat_info.st_mtime))
    if d['Type'] == 'link' and Links == 'manage' :
        d['Contents'] = 'Symlink to ' + os.readlink(fname) 
    else :
        d['Contents'], error = ReadFileLimited(fname,MaxContentsReturnable)
    if d['Contents'] is None:
        d['Contents'] = ''
    return d

def GetDirInfo(dname, stat_info, Checksum, Links):
    """
    Return a dictionary of info for directory.
    Only if 'Links' == 'follow' will links be
    processed here as directories.
    """
    d = {}
    if stat_info == None:
        return d
    d['Type'] = 'directory'
    d['DestinationPath'] = dname
    try:
        d['Owner'] = pwd.getpwuid(stat_info.st_uid).pw_name
    except:
        d['Owner'] = str(stat_info.st_uid)
    try:
        d['Group'] = grp.getgrgid(stat_info.st_gid).gr_name
    except:
        d['Group'] = str(stat_info.st_gid)
    if Checksum == 'md5' or Checksum == 'sha-256':
        d['Checksum'] = '0'
    elif Checksum == "ctime":
        d['Checksum']= str(int(stat_info.st_ctime))
    else : # Checksum == "mtime":
        d['Checksum']= str(int(stat_info.st_mtime))
    d['Mode'] = str(oct(stat_info.st_mode))[-3:]
    d['ModifiedDate'] = int(stat_info.st_mtime)
    d['CreatedDate'] = int(stat_info.st_ctime)
    d['FileSize'] = stat_info.st_size
    d['Contents'] = ''
    if Links == 'manage' and os.path.islink(dname):
        d['Contents'] = 'Symlink to ' + os.readlink(dname)
    return d

def opened_w_error(filename, mode="r"):
    try:
        f = codecs.open(filename, encoding='utf8', mode=mode)
    except IOError, err:
        return None, err
    return f, None

def opened_bin_w_error(filename, mode="rb"):
    try:
        f = open(filename, mode)
    except IOError, err:
        return None, err
    return f, None

def ReadFileLimited(path, MaxContentsReturnable):
    """
    Safely attempt to read a text file,
    ensuring file is always closed at exit.
    Read up to MaxContentsReturnable.
    """
    d = ''
    error = None
    F, error = opened_w_error(path)
    if not error:
        try:
            d = F.read(MaxContentsReturnable)
        except:
            pass
    F.close()
    return d.encode('ascii', 'ignore'), error

def Print(s, file=sys.stderr):
    file.write(s.encode('utf8') + '\n')
    
def LStatFile(path):
    """
    LStat the file.  Do not follow the symlink.
    """
    d = None
    try:
        d = os.lstat(path)
    except:
        pass
    return d


def StatFile(path):
    """
    Stat the file, following the symlink.
    """
    d = None
    try:
        d = os.stat(path)
    except:
        pass
    return d

def GetChecksum(fname, Checksum):
    src_error = None
    src_block = 'loopme'
    if Checksum == "md5":
        src_hash = md5const()
    else : # sha-256
        src_hash = shaconst()
    src_file, src_error = opened_bin_w_error(fname, 'rb')
    if src_error:
        return ""
    while src_block :
        src_block = src_file.read(8192)
        src_hash.update(src_block)
    return src_hash.hexdigest()

# From python2.7 os.py
def walk(top, topdown=True, onerror=None, followlinks=False):
    islink, join, isdir = os.path.islink, os.path.join, os.path.isdir

    # We may not have read permission for top, in which case we can't
    # get a list of the files the directory contains.  os.path.walk
    # always suppressed the exception then, rather than blow up for a
    # minor reason when (say) a thousand readable directories are still
    # left to visit.  That logic is copied here.
    try:
        # Note that listdir and error are globals in this module due
        # to earlier import-*.
        names = os.listdir(top)
    except os.error, err:
        if onerror is not None:
            onerror(err)
        return

    dirs, nondirs = [], []
    for name in names:
        if isdir(join(top, name)):
            dirs.append(name)
        else:
            nondirs.append(name)

    if topdown:
        yield top, dirs, nondirs
    for name in dirs:
        new_path = join(top, name)
        if followlinks or not islink(new_path):
            for x in walk(new_path, topdown, onerror, followlinks):
                yield x
    if not topdown:
        yield top, dirs, nondirs

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists