diff --git a/libufps/__init__.py b/libufps/__init__.py new file mode 100644 index 0000000..8877c97 --- /dev/null +++ b/libufps/__init__.py @@ -0,0 +1,3 @@ +#import ufps + +#ufps = ufps.UFPS diff --git a/libufps/ufps.py b/libufps/ufps.py new file mode 100644 index 0000000..114c718 --- /dev/null +++ b/libufps/ufps.py @@ -0,0 +1,147 @@ +import os +import stat +import pwd +import grp + +class ufps: + """ + Primary class for libufps + """ + + def __init__(self, basedir): + """ + Constructor method. + :param basedir: The input base directory from the user/program. Gets normalized later. + :type basedir: str + """ + + # Normalize the directory prior to setting it. + self.basedir = self.normalizeInputDir(basedir) + + # Now we check if the path exists and is a directory. + self.checkPathValidity(self.basedir) + + print ("Init ufps with base dir: " + self.basedir) + + def normalizeInputDir(self, dir): + """ + This function normalizes the input directory. + In short, it makes sure the input ends with /, as we expect that to be the case in the rest of the code. + :param dir: The input directory from the user/program. + :type dir: str + :return: A string representing a directory that has been normalized as described above. + :rtype: str + """ + + if(dir[-1] != '/'): + dir=dir+'/' + return dir + + def checkPathValidity(self, dir): + """ + This function checks the validity of an input path. + Path validity means that it (1) exists and (2) is a directory. + :raises FileNotFoundError: The path doesn't exist at all. + :raises NotADirectoryError: The path is a file. + :param dir: Input directory. + :type dir: str + :return: `True` if path is valid, `False` if not. + :rtype: bool + """ + + exist = os.path.exists(dir) + isdir = os.path.isdir(dir) + + # For the purposes of verbosity, we check if a file with the same name + # exists by removing the / at the end of the directory. + vDir = dir[len(dir)-1] + vExist = os.path.exists(vDir) + + # If vExist is False and exist is False, the user input a nothing burger. + # This results in FileNotFoundError being thrown. + + # If that doesn't occur, and isdir is false, they input a file. + # This results in NotADirectoryError being thrown. + + # If none of the above occurs, the path is valid. + + if(not exist and not vExist): + raise FileNotFoundError("The path " + dir + " does not exist.") + + if(not isdir): + raise NotADirectoryError("The path must be a directory.") + + return isdir + + def parsePerms(self, path): + """ + Parses octal permissions stats into a string. Also determines other characteristics of the path: if it's a directory, and if it's a link (and where it goes). Returns this information as well. + :param oct_perm: Permissions of path in octal form (i.e. 0o0100644) + :return pPerms: Path permissions + :rtype pPerms: str + + :return pIsDir: Whether or not the path is a directory + :rtype pIsDir: bool + + :return pIsLink: Whether or not the path is a link + :rtype pIsLink: bool + + :return pLinkTarget: Where the link points to (if applicable) + :rtype pLinkTarget: str + """ + + # Get stats of the file/directory + stats = os.stat(self.basedir+path) + + # Invoke a magic spell + # Magic number -3 is used as for this we only need the last 3 digits. + # Directory and link detection is handled later. + pPerms = oct(stats.st_mode)[-3:] + + # Get whether or not the path is a dir + pIsDir = os.path.isdir(path) + + # Get whether or not the path is a link. + pIsLink = os.path.islink(path) + + pLinkTarget = None + if pIsLink: + pLinkTarget = os.readlink(path) + + return pPerms, pIsDir, pIsLink, pLinkTarget + + def getFilePermissions(self, path): + """ + Gets Unix file permissions of a directory or file. + :param path: Path to directory or file + :type path: str + """ + # Parse oct_perm + permStr, isDir, isLink, linkTarget = self.parsePerms(path) + + # If it's a directory, we also want to figure out if it's a link. + #isDirectoryLink + + D_userFriendlyString = permStr + " | " + str(isDir) + " | " + str(isLink) + " | " + str(linkTarget) + return D_userFriendlyString + + def getFileOwner(self, path): + """ + Gets file owner and group of a directory or file. + :param path: Path to directory or file + :type path: str + + :return ownername: Owner name + :rtype ownername: str + + :return groupname: Group name + :rtype groupname: str + """ + stats = os.stat(path) + uid = stats.st_uid + gid = stats.st_gid + + ownername = pwd.getpwuid(stats.st_uid).pw_name + groupname = grp.getgrgid(stats.st_gid).gr_name + + return ownername, groupname diff --git a/requirements-lib.txt b/requirements-lib.txt new file mode 100644 index 0000000..d7bfe38 --- /dev/null +++ b/requirements-lib.txt @@ -0,0 +1,5 @@ +wheel +setuptools +twine +pytest==4.4.1 +pytest-runner==4.4 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..30acace --- /dev/null +++ b/setup.py @@ -0,0 +1,9 @@ +from setuptools import find_packages, setup + +setup( + name='libufps', + packages=find_packages(), + version='0.0.0', + description='Unix File Permission Supplicant Utility', + author='Innovation Science', +)