This exercise is about object oriented programming in Python. Your task is to use objects to implement a representation of a simple file system. In computer science, a file system is a data structure that the Operating System uses to control how data is stored and retrieved from a hard (or solid state) drive. A file system could be represented as a tree, in which files and directories may be organised as a hierarchy, so that, directories may contain subdirectories. For example, a file gatos.jpg may be under Isaac directory, but that is a subdirectory of the home folder. In file systems, a directory is just a file, but it is a special kind of file that contains a list of files. Here is an example:
Figure 1: An example of a file system as a tree. Directories are represented in circles, plain files in squared boxes
You can test your code with the test in test-fs.py . 1.Implement the following classes to represent a simple file system: File: everything is a file PlainFile: a plain file has a name (we are ignoring its contents) Directory: has a name and a list of files with constructors (i.e. init methods), so that, we can define the following directory tree (i.e. file system) based on the image above:
2.Add methods that print (recursively) the entire file system tree (i.e. define appropriate str methods). You don’t need to produce a pretty output - it is ok if it looks like this:
3.A File may have other attributes such as owner. If not indicated, the owner will be set to “default”. Implement a method chown(new_owner) that will allow you to modify the owner of a file or directory.
4.Implement a method ls() that recursively prints the content of the direc- tory and all the subdirectories, using indentation to represent how deep in the tree structure the file/directory is.
# if we run ls() on the previous object root: >> root.ls() root boot.exe home thor hunde.jpg quatsch.txt isaac gatos.jpg 5.Implement a new class, FileSystem , which will allow us to navigate and manipulate a file system as if it was a UNIX file system. In particular, this class will allow us to keep track of the working directory. It should be initialised as follows:
>> fs = FileSystem(root) (a)Implement a method pwd() that tells you the current working direc- tory. This might be useful later when moving across directories. It should work like this: >> fs.pwd() 'root' (b)Implement ls() for the FileSystem class, so that, fs.ls() would work as question 4, but only printing from the current directory. (c)Implement a method cd() that will allow you to move to a different directory (changing the working directory). It should work as follows: # if you try to move to a non existing directory or to a file, # the method should complain: >> fs.cd("casa") The directory does not exist! # But you can move to an existing directory in the working directory. >> fs.cd("home") # if we now do ls(), you should only see the content in home: >> fs.ls() home thor hunde.jpg quatsch.txt isaac gatos.jpg Note that our filesystem is case sensitive, if the user searches for “Home”, the method won’t find the folder, because “home” is a dif- ferent folder. (d)Implement methods to create files create_file(name) and directo- ries mkdir(name) within the working directory. Both methods should make sure that the file or directory to be created doesn’t already ex- ist within the working directory. Directories must be empty when creating them with mkdir(name). The method mkdir may allow you to indicate the owner when creating it, but files will share the owner of the working directory. (e)Modify the method cd() to allow us to go back to a parent directory. We will indicate the parent directory as “..”. For example: >> fs.cd("home") >> fs.pwd() 'home' >> fs.cd("..") >> fs.pwd() 'root' Note that applying fs.cd("..") in a root node with no parent di- rectory will have no effect, but won’t return an error. (f)Implement a method rm(name) that will allow you to remove a file from the current working directory. A directory can only be deleted if it is empty. >> fs.rm("home") Sorry, the directory is not empty (g)Implement a method find(name) which tries to find a file name in a file system and returns the path to the first occurrence of the file if it finds it but False otherwise. For example: >> fs.find("gatos.jpg") 'root/home/isaac/gatos.jpg' >> fs.find("thor") 'root/home/thor' >> fs.find("unix") False Note that if you moved deeper in the directory tree using cd(), find(name) should only look from the current working directory. (h)The UNIX file system has many other operations that you could implement here. Here are some ideas, but feel free to implement any functionality you find useful. Discuss ideas with us, but please add enough comments to understand what you are aiming to achieve. •chown -R: we have implemented chown() to change the owner of a single file or directory. Add an efficient way to apply this function recursively to all files and sub directories of a folder. •Files and directories usually have permissions (read, write, and execution). Can you add that and functions to manipulate the permissions? (e.g. chmod). •Improve the ls() to show the owner, permissions (similar to what ls -l would do in UNIX. •In UNIX we can also move files from one directory to another using the command mv, indicating the destination PATH.
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ """ from file_system import Directory, PlainFile, FileSystem print("Testing question 1") # question 1 should allow to create simple files and folders: file = PlainFile("boot.exe") folder = Directory("Downloads",[]) root = Directory("root",[PlainFile("boot.exe"), Directory("home",[ Directory("thor", [PlainFile("hunde.jpg"), PlainFile("quatsch.txt")]), Directory("isaac", [PlainFile("gatos.jpg")])])]) print("Testing question 2") # question 2: implement the str print(root) """ Directory(root,[PlainFile(boot.exe),Directory(home,[Directory(thor,[PlainFile(hunde.jpg),PlainFile(quatsch.txt)],Directory(isaac,[PlainFile(gatos.jpg)]]] """ print("Testing question 3") # question 3: test chown() file = PlainFile("boot.exe") folder = Directory("Downloads",[]) print(f'file.owner: {file.owner}; folder: {folder.owner}') file.chown("root") folder.chown("isaac") print(f'file.owner: {file.owner}; folder: {folder.owner}') print("Testing question 4") #question 4: ls() doesn't return anything but prints. root.ls() """ root boot.exe home thor hunde.jpg quatsch.txt isaac gatos.jpg """ # question 5: create FileSystem print("Testing question 5a: basic filesystem and pwd") fs = FileSystem(root) # 5a: print(fs.pwd()) print("Testing question 5b: ls in working directory") # 5b: fs.ls() # 5c: print("Testing question 5c: cd") # if you try to move to a non existing directory or to a file, # the method should complain: fs.cd("casa") # But you can move to an existing directory in the working directory. fs.cd("home") # if we now do ls(), you should only see the content in home: fs.ls() # you can't go backwards yet... print("Testing question 5d: mkdir and create file") fs = FileSystem(root) # re-initialise fs fs.mkdir("test") # the owner of the directory should be 'default' as not indicated. fs.mkdir("test","isaac") would set the owner to isaac fs.cd("test") fs.create_file("test.txt") fs.ls() print("Testing question 5e: dot dot" # to test this properly, let's create the entire file system using our previous functions! root = Directory("root",[],owner="root") fs = FileSystem(root) fs.create_file("boot.exe") # when creating a file we do not need to indicate owner, it will be the same as the working directory fs.mkdir("test") fs.mkdir("home",owner="root") fs.cd("home") fs.mkdir("thor",owner="thor") fs.mkdir("isaac",owner="isaac") fs.cd("thor") fs.create_file("hunde.jpg") fs.create_file("quatsch.txt") fs.cd("..") fs.cd("isaac") fs.create_file("gatos.jpg") fs.cd("..") fs.cd("..") fs.ls() print("Testing question 5f: rm")
classFile(object): """ Everything is a file """ def__init__(self, name, owner) -> None: super().__init__() self.name = name self.owner = "default" classPlainFile(File): """ A plain file has a name ignoring its contents """ def__init__(self, name, owner="default") -> None: super().__init__(name, owner) pass defchown(self, new_owner) -> None: """ Allow to modify the owner of a file or directory. """ self.owner = new_owner
1 2 3 4 5 6 7 8 9
classDirectory(object): """ Includes a name and a list of files, recursively store the folder """ def__init__(self, root, args, owner="default") -> None: super().__init__() self.root = root self.sub = args self.owner = owner
def_find(self, name, workspace): """ Using DFS to find the File or Directory If found ,return path otherwise return False """ subs = workspace.sub namelist = [] for file in subs: iftype(file) == PlainFile: namelist.append(file.name) eliftype(file) == Directory: namelist.append(file.root) for file in subs: if name in namelist: return workspace.root + "/" + name else: iftype(file) == Directory: if self._find(name, file): return workspace.root + "/" + self._find(name, file)