A lot. Really basic and unmanaged (aside from the logic in libufps) functionality

This commit is contained in:
Innovation 2025-01-13 18:15:10 -06:00
parent fdaa77c872
commit 218cfc4d29
5 changed files with 50 additions and 21 deletions

View file

@ -12,8 +12,9 @@ Naturally, enterprises have solutions to this, but self hosters may not. This pr
The idea is to record all of this information to a text file, which is backed up off-site as a normal file. This file can then be read by the utility to restore permissions, thereby making the restored backup as close as possible to how it was before it crashed. If mounted to the same locations, this solves any permissions issues a self hoster could face getting back up and running after a catastrophe. The idea is to record all of this information to a text file, which is backed up off-site as a normal file. This file can then be read by the utility to restore permissions, thereby making the restored backup as close as possible to how it was before it crashed. If mounted to the same locations, this solves any permissions issues a self hoster could face getting back up and running after a catastrophe.
## Status ## Status
- Recurse a directory (index) - Recurse a directory (index)
- Store Unix file permissions and ownership data - Store Unix file permissions and ownership data
- Restore Unix file permissions and ownership data using index file as an input - Restore Unix file permissions and ownership data using index file as an input
- ❎ Diff index file and restored backup and inform the user of file inconsistencies - ❎ Diff index file and restored backup and inform the user of file inconsistencies
- ❎ Index file encryption with bcrypt - Sort of. It only detects when a file doesn't exist.
- ❎ Index file encryption with bcrypt

12
create.py Normal file
View file

@ -0,0 +1,12 @@
#from libufps import ufps
#import libufps
#from inspect import getmembers, isfunction
#import os
def createIndex(ufps, indexFile):
print("Creating index")
index = ufps.createIndex("") # For ufpsutil we just index from the selected base directory
file = open(indexFile, "w")
file.write(index)
file.close()
print("Index has been written to " + indexFile)

View file

@ -13,10 +13,10 @@ class ufps:
"""I_PERMS = index for permissions""" """I_PERMS = index for permissions"""
I_USERN = 1 I_USERN = 1
"""I_USERN = index for username""" """I_USERN = index for user id"""
I_GROUP = 2 I_GROUP = 2
"""I_GROUP = index for group""" """I_GROUP = index for group id"""
I_ISDIR = 3 I_ISDIR = 3
"""I_ISDIR = index for directory boolean""" """I_ISDIR = index for directory boolean"""
@ -165,11 +165,11 @@ class ufps:
:param path: Path to directory or file :param path: Path to directory or file
:type path: str :type path: str
:return ownername: Owner name :return uid: Owner ID
:rtype ownername: str :rtype uid: int
:return groupname: Group name :return gid: Group ID
:rtype groupname: str :rtype gid: int
""" """
realpath = self.basedir+path realpath = self.basedir+path
@ -179,10 +179,10 @@ class ufps:
gid = stats.st_gid gid = stats.st_gid
# Turn the funny numbers we just got into names. # Turn the funny numbers we just got into names.
ownername = pwd.getpwuid(stats.st_uid).pw_name #ownername = pwd.getpwuid(stats.st_uid).pw_name
groupname = grp.getgrgid(stats.st_gid).gr_name #groupname = grp.getgrgid(stats.st_gid).gr_name
return ownername, groupname return uid, gid
# def getDirectoryContents(self, path): # def getDirectoryContents(self, path):
# realpath = self.basedir + path # realpath = self.basedir + path
@ -222,11 +222,11 @@ class ufps:
# For every item in the list, we get it's permissions and owner/group info. # For every item in the list, we get it's permissions and owner/group info.
for p in fileList: for p in fileList:
pPerms, pIsDir, pIsLink, pLinkTarget = self.getFilePermissions(p) pPerms, pIsDir, pIsLink, pLinkTarget = self.getFilePermissions(p)
ownername, groupname = self.getFileOwner(p) uid, gid = self.getFileOwner(p)
# Stanardized table entry for ufps indexes. # Stanardized table entry for ufps indexes.
# Future additions get added to the end. # Future additions get added to the end.
D_userFriendlyString = pPerms + " | " + ownername + " | " + groupname + " | " + str(pIsDir) + " | " + str(pIsLink) + " | " + p + " | " + str(pLinkTarget) + "\n" D_userFriendlyString = pPerms + " | " + str(uid) + " | " + str(gid) + " | " + str(pIsDir) + " | " + str(pIsLink) + " | " + p + " | " + str(pLinkTarget) + "\n"
outputIndex+=D_userFriendlyString outputIndex+=D_userFriendlyString
# Remove tailing newline once again # Remove tailing newline once again
@ -267,10 +267,13 @@ class ufps:
indexRealPath = realpath + indexEntry[self.I_IPATH] indexRealPath = realpath + indexEntry[self.I_IPATH]
pathExists = os.path.exists(indexRealPath) pathExists = os.path.exists(indexRealPath)
permsToSet = int(indexEntry[self.I_PERMS], base=8) permsToSet = int(indexEntry[self.I_PERMS], base=8)
uid = int(indexEntry[self.I_USERN])
gid = int(indexEntry[self.I_GROUP])
# If the path doesn't exist, we log this. Otherwise, set the permissions. # If the path doesn't exist, we log this. Otherwise, set the permissions.
if pathExists: if pathExists:
os.chmod(indexRealPath, permsToSet) os.chmod(indexRealPath, permsToSet)
os.chown(indexRealPath, uid, gid)
else: else:
# If the path doesn't exist, an inconsistency has been detected. # If the path doesn't exist, an inconsistency has been detected.
# We report this so that the user can manually rectify it. # We report this so that the user can manually rectify it.
@ -279,3 +282,6 @@ class ufps:
return results return results
# def diff(self, index): # def diff(self, index):
def test(self):
print("Test")

2
restore.py Normal file
View file

@ -0,0 +1,2 @@
def restoreIndex(ufps, indexFile):
ufps.restore(indexFile, "")

View file

@ -3,6 +3,8 @@ import libufps
from inspect import getmembers, isfunction from inspect import getmembers, isfunction
import os import os
import argparse import argparse
import create
import restore
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
prog='ufpsutil', prog='ufpsutil',
@ -17,17 +19,18 @@ parser.add_argument("--i-know-what-im-doing", help = "Force the utility to run w
args = parser.parse_args() args = parser.parse_args()
# Just make argument variables a bit more human readable. # Just make argument variables a bit more human readable.
basedir = args.path
indexFile = args.index indexFile = args.index
m_create = args.create modeCreate = args.create
m_restore = args.restore modeRestore = args.restore
forceWithoutRoot = args.i_know_what_im_doing forceWithoutRoot = args.i_know_what_im_doing
# Check that both -c and -r arent specified. # Check that both -c and -r arent specified.
if m_create and m_restore: if modeCreate and modeRestore:
exit("[Fatal] Both --create and --restore specified. That doesn't make sense!") exit("[Fatal] Both --create and --restore specified. That doesn't make sense!")
# That said, at least -c or -r must be specified. # That said, at least -c or -r must be specified.
if not m_create and not m_restore: if not modeCreate and not modeRestore:
exit("[Fatal] I'm not sure what you want me to do. Must specify --create or --restore.") exit("[Fatal] I'm not sure what you want me to do. Must specify --create or --restore.")
@ -41,14 +44,19 @@ if uid != 0:
else: else:
exit("[Fatal] Root privileges are usually required for this utility to do it's job. If you know what you're doing, try running with --i-know-what-im-doing") exit("[Fatal] Root privileges are usually required for this utility to do it's job. If you know what you're doing, try running with --i-know-what-im-doing")
#print(args) ufps = ufps.ufps(basedir)
if modeCreate:
create.createIndex(ufps, indexFile)
if modeRestore:
restore.restoreIndex(ufps, indexFile)
#basedir = "tests/testfiles/" #basedir = "tests/testfiles/"
#basedirbad = "tests/testfiles_bad/" #basedirbad = "tests/testfiles_bad/"
#ufps = ufps.ufps(basedir) #ufps = ufps.ufps(basedir)
#print("Regular dir: " + ufps.getInformationRecursive(".")) #print("Regular dir: " + ufps.getInformationRecursive("."))
#print("Regular file: " + ufps.getInformationRecursive("0644")) #print("Regular file: " + ufps.getInformationRecursive("0644"))
#print("Linked dir: " + ufps.getInformationRecursive("linktests/link")) #print("Linked dir: " + ufps.getInformationRecursive("linktests/link"))