864 lines
28 KiB
Python
864 lines
28 KiB
Python
#!/usr/bin/env python3.5
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
A single file for each command file we implemented.
|
|
"""
|
|
|
|
|
|
import os
|
|
import shutil
|
|
import datetime
|
|
import threading
|
|
import subprocess
|
|
|
|
from Common.socketCommands import sendData
|
|
from Server.errorHandler import serverSendErrHandler
|
|
from .CommandException import CommandException
|
|
|
|
|
|
__authors__ = "HorlogeSkynet, Tatiyk, CaumartinYann"
|
|
__copyright__ = "Copyright 2017, ACMS"
|
|
__license__ = "GPLv3"
|
|
__status__ = "Production"
|
|
__date__ = "03/03/2017"
|
|
|
|
|
|
# Default path for Data
|
|
DATA_PATH = 'Server/Data/'
|
|
|
|
|
|
class sendOutput(threading.Thread):
|
|
def __init__(self, sock, pipeOutput):
|
|
threading.Thread.__init__(self)
|
|
|
|
self.sock = sock
|
|
self.keepGoing = True
|
|
self.pipeOutput = pipeOutput
|
|
|
|
def run(self):
|
|
while True:
|
|
c = ''
|
|
while not c:
|
|
if not self.keepGoing:
|
|
return
|
|
|
|
else:
|
|
c = self.pipeOutput.read()
|
|
|
|
sendData(self.sock, c.decode(), serverSendErrHandler, self.sock)
|
|
|
|
def stop(self):
|
|
self.keepGoing = False
|
|
self.join()
|
|
|
|
|
|
class recvInput(threading.Thread):
|
|
def __init__(self, sock, pipeInput):
|
|
threading.Thread.__init__(self)
|
|
|
|
self.sock = sock
|
|
self.keepGoing = True
|
|
self.pipeInput = pipeInput
|
|
|
|
def run(self):
|
|
while True:
|
|
c = self.sock.recv(1)
|
|
|
|
if not self.keepGoing:
|
|
break
|
|
|
|
else:
|
|
self.pipeInput.write(c)
|
|
|
|
def stop(self):
|
|
self.keepGoing = False
|
|
self.join()
|
|
|
|
|
|
def rmController(command, client, acl):
|
|
def updateAcl(path, acl):
|
|
for file in os.listdir(path):
|
|
if os.path.isdir(path + file):
|
|
acl.deleteFile(client.username, path + file + '/')
|
|
updateAcl(path + file + '/', acl)
|
|
|
|
else:
|
|
acl.deleteFile(client.username, path + file)
|
|
|
|
nbArgs = len(command)
|
|
if nbArgs == 2:
|
|
path = interpretPath(command[1], client)
|
|
if os.path.exists(path):
|
|
with client.mutex:
|
|
if os.path.isdir(path):
|
|
if acl.isAllowedToOn(client.username, 'write', path + '/') or acl.isAdministrator(client.username):
|
|
try:
|
|
os.rmdir(path)
|
|
acl.deleteFile(client.username, path + '/')
|
|
|
|
except:
|
|
raise CommandException("The directory is not empty. Use \'-r\' option.")
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
else:
|
|
if acl.isAllowedToOn(client.username, 'write', path) or acl.isAdministrator(client.username):
|
|
try:
|
|
os.remove(path)
|
|
acl.deleteFile(client.username, path)
|
|
|
|
except:
|
|
raise CommandException("The file couldn't be removed")
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
else:
|
|
raise CommandException("Unknown path.")
|
|
|
|
elif nbArgs == 3:
|
|
if command.count("-r") == 1:
|
|
if command[1] == "-r":
|
|
command[1], command[2] = command[2], command[1]
|
|
|
|
path = interpretPath(command[1], client)
|
|
if os.path.exists(path):
|
|
with client.mutex:
|
|
if acl.isAllowedToOn(client.username, 'write', path + '/') or acl.isAdministrator(client.username):
|
|
if os.path.isdir(path):
|
|
try:
|
|
acl.deleteFile(client.username, path + '/')
|
|
updateAcl(path + '/', acl)
|
|
shutil.rmtree(path, ignore_errors=True)
|
|
|
|
except:
|
|
raise CommandException("The directory \"" + command[1] + "\" couldn\'t be removed.")
|
|
|
|
else:
|
|
try:
|
|
os.remove(path)
|
|
acl.deleteFile(client.username, path)
|
|
|
|
except:
|
|
raise CommandException("Omitted option \'-r\', but \"" + command[1] + "\" couldn\'t be removed.")
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
else:
|
|
raise CommandException("Unknown path.")
|
|
|
|
else:
|
|
raise CommandException("Unknown arguments.")
|
|
|
|
else:
|
|
raise CommandException("Wrong number of arguments.")
|
|
|
|
|
|
def mvController(command, client, acl):
|
|
def updateAcl(client, source, destination, acl):
|
|
for file in os.listdir(source):
|
|
if os.path.isdir(source + file):
|
|
read, write, execute = acl.getRightsOnFile(source + file + '/')
|
|
owner = acl.getOwnerOnFile(source + file + '/')
|
|
acl.deleteFile(client.username, source + file + '/')
|
|
acl.addFile(client.username, destination + file + '/')
|
|
acl.setRightsOnFile(client.username, destination + file + '/', read, write, execute)
|
|
acl.changeOwnOnFile(client.username, destination + file + '/', owner)
|
|
updateAcl(client, source + file + '/', destination + file + '/', acl)
|
|
else:
|
|
read, write, execute = acl.getRightsOnFile(source + file)
|
|
acl.deleteFile(client.username, source + file)
|
|
acl.addFile(client.username, destination + file)
|
|
acl.setRightsOnFile(client.username, destination + file, read, write, execute)
|
|
|
|
nbArgs = len(command)
|
|
if nbArgs == 3:
|
|
if command[1].endswith('/'):
|
|
command[1] = command[1].rpartition('/')[0]
|
|
|
|
source = interpretPath(command[1], client)
|
|
destination = interpretPath(command[2], client)
|
|
|
|
if source == destination or command[1] == command[2].partition('/')[0]:
|
|
raise CommandException("You just can't do that.")
|
|
|
|
if not os.path.exists(destination):
|
|
with client.mutex:
|
|
if os.path.isdir(source):
|
|
try:
|
|
if (acl.isAllowedToOn(client.username, 'write', source + '/') and acl.isAllowedToOn(client.username, 'write', destination.rpartition('/')[0] + '/')) or acl.isAdministrator(client.username):
|
|
read, write, execute = acl.getRightsOnFile(source + '/')
|
|
owner = acl.getOwnerOnFile(source + '/')
|
|
acl.addFile(client.username, destination + '/')
|
|
acl.deleteFile(client.username, source + '/')
|
|
acl.setRightsOnFile(client.username, destination + '/', read, write, execute)
|
|
acl.changeOwnOnFile(client.username, destination + '/', owner)
|
|
updateAcl(client, source + '/', destination + '/', acl)
|
|
shutil.move(source, destination)
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
except:
|
|
raise CommandException("An error occurred while moving your directory...")
|
|
else:
|
|
try:
|
|
shutil.move(source, destination)
|
|
acl.addFile(client.username, destination)
|
|
acl.deleteFile(client.username, source)
|
|
except:
|
|
raise CommandException("An error occurred while moving your file...")
|
|
|
|
# If the second argument is an existing directory, let's move it inside...
|
|
elif os.path.isdir(destination):
|
|
with client.mutex:
|
|
if (acl.isAllowedToOn(client.username, 'write', source.rpartition('/')[0] + '/') and acl.isAllowedToOn(client.username, 'write', destination.rpartition('/')[0] + '/')) or acl.isAdministrator(client.username):
|
|
if not destination.endswith('/'):
|
|
destination += '/'
|
|
if command[1].startswith('/'):
|
|
command[1] = command[1].partition('/')[2]
|
|
|
|
if command[1].endswith('/'):
|
|
command[1] = command[1].rpartition('/')[0]
|
|
|
|
command[1] = command[1].rpartition('/')[2]
|
|
|
|
if os.path.isdir(source):
|
|
if not source.endswith('/'):
|
|
source += '/'
|
|
try:
|
|
read, write, execute = acl.getRightsOnFile(source)
|
|
owner = acl.getOwnerOnFile(source)
|
|
acl.deleteFile(client.username, source)
|
|
acl.addFile(client.username, destination + command[1] + '/')
|
|
acl.setRightsOnFile(client.username, destination + command[1] + '/', read, write, execute)
|
|
acl.changeOwnOnFile(client.username, destination + command[1] + '/', owner)
|
|
updateAcl(client, source, destination + command[1] + '/', acl)
|
|
shutil.move(source, destination + command[1] + '/')
|
|
except:
|
|
raise CommandException("An error occurred while moving your directory...")
|
|
|
|
else:
|
|
try:
|
|
acl.deleteFile(client.username, source)
|
|
acl.addFile(client.username, destination + command[1].rpartition('/')[2])
|
|
shutil.move(source, destination + command[1].rpartition('/')[2])
|
|
except:
|
|
raise CommandException("An error occurred while moving your file...")
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
else:
|
|
raise CommandException("The destination specified already exist !")
|
|
|
|
else:
|
|
raise CommandException("Wrong number of arguments.")
|
|
|
|
|
|
def mkdirController(command, client, acl):
|
|
def updateAcl(pathKnown, directories, acl):
|
|
for directory in directories:
|
|
acl.addFile(client.username, pathKnown + directory + '/')
|
|
pathKnown = pathKnown + directory + '/'
|
|
|
|
nbArgs = len(command)
|
|
if nbArgs == 3:
|
|
pathKnown = ''
|
|
if command.count("-p") == 1:
|
|
if command[2] == "-p":
|
|
command[2] = command[1]
|
|
|
|
path = interpretPath(command[2], client)
|
|
|
|
directories = path.split('/')
|
|
while os.path.isdir(pathKnown + directories[0]):
|
|
pathKnown = pathKnown + directories[0] + '/'
|
|
directories.remove(directories[0])
|
|
|
|
try:
|
|
if acl.isAllowedToOn(client.username, 'write', pathKnown) or acl.isAdministrator(client.username):
|
|
with client.mutex:
|
|
os.makedirs(path)
|
|
updateAcl(pathKnown, directories, acl)
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
except:
|
|
raise CommandException("Permission denied.")
|
|
|
|
else:
|
|
raise CommandException("One argument is invalid.")
|
|
|
|
elif nbArgs == 2:
|
|
try:
|
|
path = interpretPath(command[1], client)
|
|
if acl.isAllowedToOn(client.username, 'write', path.rpartition('/')[0] + '/') or acl.isAdministrator(client.username):
|
|
with client.mutex:
|
|
os.mkdir(path)
|
|
acl.addFile(client.username, path + '/')
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
except:
|
|
raise CommandException("The directory couldn\'t be created.")
|
|
|
|
else:
|
|
raise CommandException("Wrong number of arguments.")
|
|
|
|
|
|
def cdController(command, client, acl):
|
|
nbArgs = len(command)
|
|
if nbArgs == 1:
|
|
path = interpretPath('~', client)
|
|
if not path.endswith('/'):
|
|
path += '/'
|
|
|
|
if not os.path.exists(path):
|
|
raise CommandException("This directory does not exist.")
|
|
|
|
else:
|
|
if acl.isAllowedToOn(client.username, 'execute', path) or acl.isAdministrator(client.username):
|
|
client.currentWorkingDir = path
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
elif nbArgs == 2:
|
|
path = interpretPath(command[1], client)
|
|
if not path.endswith('/'):
|
|
path += '/'
|
|
|
|
if not os.path.exists(path):
|
|
raise CommandException("This directory does not exist.")
|
|
|
|
else:
|
|
if acl.isAllowedToOn(client.username, 'execute', path) or acl.isAdministrator(client.username):
|
|
client.currentWorkingDir = path
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
else:
|
|
raise CommandException("Wrong number of arguments.")
|
|
|
|
|
|
def lsController(command, client, acl):
|
|
nbArgs = len(command)
|
|
if nbArgs == 1 or (nbArgs == 2 and command.count("-l") == 0):
|
|
path = None
|
|
files = None
|
|
|
|
if nbArgs == 2:
|
|
path = interpretPath(command[1], client)
|
|
if not path.endswith('/'):
|
|
path += '/'
|
|
|
|
else:
|
|
path = client.currentWorkingDir
|
|
|
|
if not os.path.exists(path) or not os.path.isdir(path):
|
|
raise CommandException("Unknown path (or is it really a directory ?).")
|
|
|
|
else:
|
|
message = ''
|
|
|
|
if acl.isAllowedToOn(client.username, 'read', path) or acl.isAdministrator(client.username):
|
|
files = os.listdir(path)
|
|
if len(files) == 0:
|
|
message = "This directory is empty."
|
|
|
|
else:
|
|
message = "\n".join(files)
|
|
|
|
return message
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
elif (nbArgs == 2 or nbArgs == 3) and command.count("-l") == 1:
|
|
path = client.currentWorkingDir
|
|
|
|
if nbArgs == 3:
|
|
if command[1] == "-l":
|
|
command[1], command[2] = command[2], command[1]
|
|
|
|
path = interpretPath(command[1], client)
|
|
if os.path.isdir(path):
|
|
path = path + "/"
|
|
|
|
if not os.path.exists(path) or not os.path.isdir(path):
|
|
raise CommandException("Unknown path (or is it really a directory ?).")
|
|
|
|
message = ''
|
|
tailleOwnerMax = 0
|
|
|
|
if acl.isAllowedToOn(client.username, 'read', path) or acl.isAdministrator(client.username):
|
|
files = os.listdir(path)
|
|
if len(files) == 0:
|
|
message = "This directory is empty."
|
|
|
|
else:
|
|
tailleMax = max([len(str(os.path.getsize(path + file))) for file in files])
|
|
for file in files:
|
|
if os.path.isdir(path + file):
|
|
if os.path.isdir(path + file):
|
|
file += '/'
|
|
if tailleOwnerMax < len(str(acl.getOwnerOnFile(path + file))):
|
|
tailleOwnerMax = len(str(acl.getOwnerOnFile(path + file)))
|
|
for file in files:
|
|
if message:
|
|
message += '\n'
|
|
|
|
if os.path.isdir(path + file):
|
|
message += "d "
|
|
elif os.path.isfile(path + file):
|
|
message += "- "
|
|
elif os.path.isabs(path + file):
|
|
message += "a "
|
|
elif os.path.islink(path + file):
|
|
message += "l "
|
|
else:
|
|
message += "? "
|
|
|
|
if os.path.isdir(path + file):
|
|
message += acl.getOwnerOnFile(path + file + '/') + ' '
|
|
message += ' ' * (tailleOwnerMax - len(str(acl.getOwnerOnFile(path + file + '/'))))
|
|
else:
|
|
message += acl.getOwnerOnFile(path + file) + ' '
|
|
message += ' ' * (tailleOwnerMax - len(str(acl.getOwnerOnFile(path + file))))
|
|
|
|
message += ' ' * (tailleMax - len(str(os.path.getsize(path + file))))
|
|
message += str(os.path.getsize(path + file)) + ' ' + str(datetime.datetime.fromtimestamp(os.path.getmtime(path + file))).split('.')[0] + ' ' + file
|
|
|
|
return message
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
else:
|
|
raise CommandException("Wrong number of (or invalid) arguments.")
|
|
|
|
|
|
def cpController(command, client, acl):
|
|
def updateAcl(client, source, destination, acl):
|
|
for file in os.listdir(source):
|
|
if os.path.isdir(source + file):
|
|
read, write, execute = acl.getRightsOnFile(source + file + '/')
|
|
owner = acl.getOwnerOnFile(source + file + '/')
|
|
acl.addFile(client.username, destination + file + '/')
|
|
acl.setRightsOnFile(client.username, destination + file + '/', read, write, execute)
|
|
acl.changeOwnOnFile(client.username, destination + file + '/', owner)
|
|
updateAcl(client, source + file + '/', destination + file + '/', acl)
|
|
else:
|
|
read, write, execute = acl.getRightsOnFile(source + file)
|
|
acl.addFile(client.username, destination + file)
|
|
acl.setRightsOnFile(client.username, destination + file, read, write, execute)
|
|
|
|
nbArgs = len(command)
|
|
if nbArgs == 3:
|
|
source = interpretPath(command[1], client)
|
|
destination = interpretPath(command[2], client)
|
|
if not os.path.exists(destination):
|
|
if not os.path.isdir(source):
|
|
with client.mutex:
|
|
try:
|
|
if (acl.isAllowedToOn(client.username, 'read', source) and acl.isAllowedToOn(client.username, 'write', destination.rpartition('/')[0] + "/")) or acl.isAdministrator(client.username):
|
|
shutil.copy(source, destination)
|
|
read, write, execute = acl.getRightsOnFile(source)
|
|
owner = acl.getOwnerOnFile(source)
|
|
acl.addFile(client.username, destination)
|
|
acl.setRightsOnFile(client.username, destination, read, write, execute)
|
|
acl.changeOwnOnFile(client.username, destination, owner)
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
except:
|
|
raise CommandException("An error occurred while copying your file...")
|
|
|
|
else:
|
|
raise CommandException("You want to copy a directory ? Use \'-r\' option.")
|
|
|
|
elif os.path.isdir(destination):
|
|
if not os.path.isdir(source):
|
|
with client.mutex:
|
|
try:
|
|
if (acl.isAllowedToOn(client.username, 'read', source) and acl.isAllowedToOn(client.username, 'write', destination.rpartition('/')[0] + '/')) or acl.isAdministrator(client.username):
|
|
shutil.copy(source, destination)
|
|
read, write, execute = acl.getRightsOnFile(source)
|
|
owner = acl.getOwnerOnFile(source)
|
|
acl.addFile(client.username, destination + '/' + command[1])
|
|
acl.setRightsOnFile(client.username, destination + '/' + command[1], read, write, execute)
|
|
acl.changeOwnOnFile(client.username, destination + '/' + command[1], owner)
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
except:
|
|
raise CommandException("An error occurred while copying your directory...")
|
|
else:
|
|
raise CommandException("You want to copy a directory ? Use \'-r\' option.")
|
|
else:
|
|
raise CommandException("The destination specified already exist !")
|
|
|
|
elif nbArgs == 4:
|
|
if command[2] == "-r":
|
|
command[2], command[1] = command[1], command[2]
|
|
elif command[3] == "-r":
|
|
command[3], command[1] = command[1], command[3]
|
|
if command[2].endswith('/'):
|
|
command[2] = command[2].rpartition('/')[0]
|
|
|
|
source = interpretPath(command[2], client)
|
|
destination = interpretPath(command[3], client)
|
|
|
|
if not os.path.exists(destination):
|
|
with client.mutex:
|
|
if os.path.isdir(source):
|
|
try:
|
|
if (acl.isAllowedToOn(client.username, 'read', source + '/') and acl.isAllowedToOn(client.username, 'write', destination.rpartition('/')[0] + '/')) or acl.isAdministrator(client.username):
|
|
shutil.copytree(source, destination)
|
|
read, write, execute = acl.getRightsOnFile(source + '/')
|
|
owner = acl.getOwnerOnFile(source + '/')
|
|
acl.addFile(client.username, destination + '/')
|
|
acl.setRightsOnFile(client.username, destination + '/', read, write, execute)
|
|
acl.changeOwnOnFile(client.username, destination + '/', owner)
|
|
updateAcl(client, source + '/', destination + '/', acl)
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
except:
|
|
raise CommandException("An error occurred while copying your directory...")
|
|
|
|
else:
|
|
try:
|
|
if (acl.isAllowedToOn(client.username, 'read', source) and acl.isAllowedToOn(client.username, 'write', destination.rpartition('/')[0] + '/')) or acl.isAdministrator(client.username):
|
|
shutil.copy(source, destination)
|
|
read, write, execute = acl.getRightsOnFile(source)
|
|
owner = acl.getOwnerOnFile(source)
|
|
acl.addFile(client.username, destination)
|
|
acl.setRightsOnFile(client.username, destination, read, write, execute)
|
|
acl.changeOwnOnFile(client.username, destination, owner)
|
|
|
|
except:
|
|
raise CommandException("An error occurred while copying your file...")
|
|
|
|
# If the second argument is an existing directory...
|
|
elif os.path.isdir(destination):
|
|
with client.mutex:
|
|
if os.path.isdir(source):
|
|
try:
|
|
if (acl.isAllowedToOn(client.username, 'read', source + '/') and acl.isAllowedToOn(client.username, 'write', destination.rpartition('/')[0] + '/')) or acl.isAdministrator(client.username):
|
|
shutil.copytree(source, destination + '/' + command[2])
|
|
read, write, execute = acl.getRightsOnFile(source + '/')
|
|
owner = acl.getOwnerOnFile(source + '/')
|
|
acl.addFile(client.username, destination + '/' + command[2] + '/')
|
|
acl.setRightsOnFile(client.username, destination + '/' + command[2] + '/', read, write, execute)
|
|
acl.changeOwnOnFile(client.username, destination + '/' + command[2] + '/', owner)
|
|
updateAcl(client, source + '/', destination + '/' + command[2] + '/', acl)
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
except:
|
|
raise CommandException("An error occurred while copying your directory...")
|
|
|
|
else:
|
|
try:
|
|
if (acl.isAllowedToOn(client.username, 'read', source) and acl.isAllowedToOn(client.username, 'write', destination.rpartition('/')[0] + '/')) or acl.isAdministrator(client.username):
|
|
shutil.copy(source, destination)
|
|
read, write, execute = acl.getRightsOnFile(source)
|
|
owner = acl.getOwnerOnFile(source)
|
|
acl.addFile(client.username, destination + '/' + command[2])
|
|
acl.setRightsOnFile(client.username, destination + '/' + command[2], read, write, execute)
|
|
acl.changeOwnOnFile(client.username, destination + '/' + command[2], owner)
|
|
|
|
except:
|
|
raise CommandException("An error occurred while copying your file...")
|
|
else:
|
|
raise CommandException("The destination specified already exist !")
|
|
|
|
else:
|
|
raise CommandException("Wrong number of arguments.")
|
|
|
|
|
|
def vimController(command, client, acl, readOnly=False):
|
|
if len(command) != 2:
|
|
raise CommandException("Wrong number of arguments.")
|
|
|
|
if command[0] == 'vim':
|
|
command.append('-Z') # Do not allow VIM to run shell commands !
|
|
command.append('-n') # Do not allow swap files creation !
|
|
|
|
# Make VIM uses the .vimrc present in the ACMS Server directory (`-u` option is bugged)
|
|
os.environ['HOME'] = os.getcwd() + "/Server"
|
|
|
|
if readOnly:
|
|
command.append('-R')
|
|
|
|
else:
|
|
raise CommandException("This case is not handled yet.") # Towards Windows compatibility ?
|
|
|
|
path = interpretPath(command[1], client)
|
|
command[1] = os.getcwd() + '/' + path
|
|
|
|
wasPresent = None
|
|
|
|
if readOnly:
|
|
if not os.path.exists(path):
|
|
raise CommandException("This file does not exist.")
|
|
|
|
if not acl.isAllowedToOn(client.username, 'read', path) and not acl.isAdministrator(client.username):
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
else:
|
|
if not os.path.exists(path):
|
|
if not acl.isAllowedToOn(client.username, 'write', path.rpartition('/')[0] + '/') and not acl.isAdministrator(client.username):
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
else:
|
|
wasPresent = False
|
|
|
|
else:
|
|
if not acl.isAllowedToOn(client.username, 'write', path):
|
|
raise CommandException("You\'re not allowed to perform this operation.")
|
|
|
|
else:
|
|
wasPresent = True
|
|
|
|
# Asks the client to change its mode to "STREAMS REDIRECTION"
|
|
sendData(client.sock, 'REDIRECT', serverSendErrHandler, client.sock)
|
|
|
|
# Runs the local text editor and handles the redirections
|
|
p = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=0)
|
|
|
|
# Let's set the output subprocess' pipe to NO_BLOCK mode (otherwise the reading would be biased)
|
|
os.set_blocking(p.stdout.fileno(), False)
|
|
|
|
# Two external threads in order to handle the pipes to and (output from) VIM
|
|
outputThread = sendOutput(client.sock, p.stdout)
|
|
inputThread = recvInput(client.sock, p.stdin)
|
|
|
|
# Let's start them !
|
|
outputThread.start()
|
|
inputThread.start()
|
|
|
|
# Let's wait for termination of the editor
|
|
p.wait()
|
|
|
|
# Let's check if the file has appeared or not
|
|
if not readOnly and not wasPresent and os.path.exists(path):
|
|
acl.addFile(client.username, path)
|
|
|
|
# The editor has stopped, let's demand to the client to re-change to its "normal" mode with a token that could be sent only in this case
|
|
sendData(client.sock, "VIM_STOP_REDIRECT_ACMS_2017_TOKEN:$}a*M-2i5<9Ù3(+$", serverSendErrHandler, client.sock)
|
|
|
|
# Once the process has stopped, let's kill and wait the threads termination
|
|
outputThread.stop()
|
|
inputThread.stop()
|
|
|
|
# Everything has now stopped, let's inform the client to leave the file edition statement, and empty its buffer
|
|
sendData(client.sock, "VIM_EMPTY_BUFFER_PROCEDURE_2017_TOKEN:$}a*M-2i5<9Ù3(+$", serverSendErrHandler, client.sock)
|
|
|
|
|
|
def findController(command, client, acl):
|
|
def searchFile(command, acl, client, chemin, message):
|
|
for file in os.listdir(chemin):
|
|
if os.path.isdir(chemin + file):
|
|
file = file + '/'
|
|
if acl.isAllowedToOn(client.username, 'read', chemin + file) or acl.isAdministrator(client.username):
|
|
if command[1] in file:
|
|
if os.path.isdir(chemin + file):
|
|
message = message + chemin + file + "\n"
|
|
else:
|
|
message = message + chemin + file + "\n"
|
|
if os.path.isdir(chemin + file):
|
|
message = searchFile(command, acl, client, chemin + file, message)
|
|
return message
|
|
|
|
if len(command) != 2:
|
|
raise CommandException("Wrong number of arguments.")
|
|
message = ""
|
|
racine = interpretPath('/', client)
|
|
message = searchFile(command, acl, client, racine, message)
|
|
if message == "":
|
|
message = command[1] + " not found"
|
|
return message
|
|
|
|
|
|
def rightsController(command, client, acl):
|
|
if len(command) == 2:
|
|
try:
|
|
file = interpretPath(command[1], client)
|
|
if os.path.isdir(file):
|
|
file += '/'
|
|
read, write, execute = acl.getRightsOnFile(file)
|
|
|
|
return "Rights set on \"" + command[1] + "\"\n\n\tRead : " + (', '.join(read) if len(read) != 0 else 'Nobody') + "\n\tWrite : " + (', '.join(write) if len(write) != 0 else 'Nobody') + "\n\tExecute : " + (', '.join(execute) if len(execute) != 0 else 'Nobody')
|
|
|
|
except:
|
|
raise
|
|
|
|
else:
|
|
raise CommandException("Wrong number of arguments.")
|
|
|
|
|
|
def chmodController(command, client, acl):
|
|
def moreRights(path, acl, user, right, client, recursive):
|
|
if not user:
|
|
user = acl.getOwnerOnFile(path)
|
|
|
|
read, write, execute = acl.getRightsOnFile(path)
|
|
if 'r' in right and not read.count(user):
|
|
read.append(user)
|
|
if 'w' in right and not write.count(user):
|
|
write.append(user)
|
|
if 'x' in right and not execute.count(user):
|
|
execute.append(user)
|
|
|
|
acl.setRightsOnFile(client, path, read, write, execute)
|
|
if recursive:
|
|
for file in os.listdir(path):
|
|
if os.path.isdir(path + file):
|
|
file += '/'
|
|
moreRights(path + file, acl, user, right, client, True)
|
|
else:
|
|
moreRights(path + file, acl, user, right, client, False)
|
|
|
|
def lessRights(path, acl, user, right, client, recursive):
|
|
if not user:
|
|
user = acl.getOwnerOnFile(path)
|
|
|
|
read, write, execute = acl.getRightsOnFile(path)
|
|
if 'r' in right and read.count(user):
|
|
read.remove(user)
|
|
if 'w' in right and write.count(user):
|
|
write.remove(user)
|
|
if 'x' in right and execute.count(user):
|
|
execute.remove(user)
|
|
acl.setRightsOnFile(client, path, read, write, execute)
|
|
if recursive:
|
|
for file in os.listdir(path):
|
|
if os.path.isdir(path + file):
|
|
file += '/'
|
|
lessRights(path + file, acl, user, right, client, True)
|
|
else:
|
|
lessRights(path + file, acl, user, right, client, False)
|
|
|
|
def makeRights(path, acl, user, right, client, recursive):
|
|
if not user:
|
|
user = acl.getOwnerOnFile(path)
|
|
|
|
read, write, execute = acl.getRightsOnFile(path)
|
|
if 'r' in right:
|
|
read[:] = []
|
|
read.append(user)
|
|
if 'w' in right:
|
|
write[:] = []
|
|
write.append(user)
|
|
if 'x' in right:
|
|
execute[:] = []
|
|
execute.append(user)
|
|
acl.setRightsOnFile(client, path, read, write, execute)
|
|
if recursive:
|
|
for file in os.listdir(path):
|
|
if os.path.isdir(path + file):
|
|
file += '/'
|
|
makeRights(path + file, acl, user, right, client, True)
|
|
else:
|
|
makeRights(path + file, acl, user, right, client, False)
|
|
|
|
nbArgs = len(command)
|
|
if nbArgs == 3 or nbArgs == 4:
|
|
if nbArgs == 4:
|
|
if command[1] == '-r':
|
|
command[1], command[2], command[3] = command[2], command[3], command[1]
|
|
|
|
elif command[2] == '-r':
|
|
command[1], command[2], command[3] = command[1], command[3], command[2]
|
|
|
|
elif command[3] != '-r':
|
|
raise CommandException("Unknown argument.")
|
|
|
|
command[1] = interpretPath(command[1], client)
|
|
|
|
if os.path.isdir(command[1]):
|
|
command[1] += '/'
|
|
|
|
if '-' in command[2]:
|
|
right = command[2].partition('-')[2]
|
|
user = command[2].partition('-')[0]
|
|
lessRights(command[1], acl, user, right, client.username, True if nbArgs == 4 else False)
|
|
return("Done.")
|
|
|
|
elif '+' in command[2]:
|
|
right = command[2].partition('+')[2]
|
|
user = command[2].partition('+')[0]
|
|
moreRights(command[1], acl, user, right, client.username, True if nbArgs == 4 else False)
|
|
return "Done."
|
|
|
|
elif '=' in command[2]:
|
|
right = command[2].partition('=')[2]
|
|
user = command[2].partition('=')[0]
|
|
makeRights(command[1], acl, user, right, client.username, True if nbArgs == 4 else False)
|
|
return "Done."
|
|
|
|
else:
|
|
raise CommandException("Unknown command")
|
|
|
|
else:
|
|
raise CommandException("Wrong number of arguments.")
|
|
|
|
|
|
def chownController(command, client, acl):
|
|
if len(command) == 3:
|
|
command[1] = interpretPath(command[1], client)
|
|
if os.path.isdir(command[1]):
|
|
command[1] += '/'
|
|
try:
|
|
acl.changeOwnOnFile(client.username, command[1], command[2])
|
|
return "The owner of " + command[1] + " is now " + command[2]
|
|
|
|
except:
|
|
raise
|
|
|
|
else:
|
|
raise CommandException("Wrong number of arguments.")
|
|
|
|
|
|
#################
|
|
# Miscellaneous #
|
|
#################
|
|
|
|
def interpretPath(path, client):
|
|
# Absolute and relative paths are managed here
|
|
if path.startswith('/'):
|
|
path = path.split('/', 1)[1]
|
|
path = DATA_PATH + path
|
|
|
|
elif path.startswith('~'):
|
|
path = path.split('~', 1)[1]
|
|
path = client.HOME_DIR + path
|
|
|
|
else:
|
|
path = client.currentWorkingDir + path
|
|
|
|
# '//' (bad thing !!) is managed here
|
|
path.replace('//', '/')
|
|
|
|
# '..' is managed here
|
|
while path.count('/..') != 0 or path.count('../') != 0:
|
|
temp = path.partition('..')
|
|
path = temp[0].rsplit('/', 2)[0] + temp[2]
|
|
|
|
if path.endswith('/'):
|
|
path = path.rpartition('/')[0]
|
|
|
|
# If the user typed too many times '..' in, let's put him in the root directory
|
|
if not path.startswith(DATA_PATH):
|
|
path = DATA_PATH
|
|
|
|
return path
|