-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathDriver.java
183 lines (159 loc) · 7.7 KB
/
Driver.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import java.io.IOException;
import java.util.*;
/**
*This is the main class of the program. It provides a way to readBytes an Ext2 Filesystem image,
*based on the path that will be provided by the user, as a string.
*@author Petros Soutzis, 2017-19
*/
public class Driver {
private static Inode inode = null;
private static String currentDir;
private static Stack<String> pathStack = new Stack<>();
//static boolean debug = false;
private static boolean running = false; //could be only in main(), but was added in 'getCommandAndExecute()'
/**
* @return An identifier for the computer that currently runs the program
*/
private static String getComputerName() {
Map<String, String> env = System.getenv();
if (env.containsKey("USER"))
return env.get("USER")+":";
else return env.getOrDefault("USERNAME", "UnknownHost")+":";
}
/**
* Method to get the current-path. Utilises a global stack and String.
* @param pathArray The array containing the path values (leaps)
*/
private static void getCurrentPathName(String[] pathArray) {
for(String path : pathArray){
if(path.equals("..") && !pathStack.peek().equals(Constants.ROOT))
pathStack.pop();
else if(!path.equals(".") && !path.equals("..")){
if(pathStack.peek().equals("/"))
pathStack.push(path);
else
pathStack.push("/"+path);
}
}
Stack<String> pathStackCopy = new Stack<>();
pathStackCopy.addAll(pathStack);
StringBuilder sb = new StringBuilder();
while(!pathStackCopy.empty()){
sb.insert(0,pathStackCopy.pop());
}
currentDir = sb.toString();
}
/**
* If the user enters anything else than Y/y or N/n, they will be prompted to re-enter their decision.
* @return true if user enters Y/y, or false if user enters N/n.
*/
private static boolean getInputYesNo(){
Scanner scanner = new Scanner(System.in);
String yes="y", no="n", input = scanner.nextLine();
while((!input.equalsIgnoreCase(yes)) && (!input.equalsIgnoreCase(no))){
System.out.println("Only acceptable inputs are \"Y\" and \"N\" (case insensitive).");
System.out.print("(Y/N): ");
input = scanner.nextLine();
}
return input.equalsIgnoreCase(yes);
}
/**
* This method will divide the user's input into a command and a target path and execute the given command.
* @param input The user's raw input
* @param inodeSize The size of any inode on this FS.
* @param sBlock The superblock of this FS.
* @param groupDesc The group descriptor of this FS.
* @param ext2 The Ext2File instance of the FS.
* @throws IOException This is not actually correct, the exception should be handled in Ext2File, but who cares.
*/
private static void getCommandAndExecute(String input, int inodeSize,
Superblock sBlock, GroupDescriptor groupDesc, Ext2File ext2)
throws IOException{
String manySpacesRegex = " +";
//Replace 1 or more spaces with a single space, then remove starting and ending spaces and split into array
String[] inputPipeline = (input.replaceAll(manySpacesRegex, " ")).trim().split(" ");
//If ls command is issued with no path, then use current directory
String command = inputPipeline[0], path = inputPipeline.length > 1 ? inputPipeline[1] : ".";
//Split based on foreslash, then remove any elements from the array that are "the empty string".
String[] pathArray = path.split("/");
pathArray = Arrays.stream(pathArray)
.filter(s -> s.length() > 0)
.toArray(String[]::new);
Inode currentInode = Inode.getContainingInode(pathArray, inodeSize, ext2, inode, sBlock, groupDesc);
if(currentInode == null)
return;
//determine what command it is and act appropriately
switch (command){
case Command.EXIT:
running = false;
Command.doExit();
break;
case Command.LS:
if(currentInode.isFile())
System.out.println(pathArray[pathArray.length-1]);
else
Command.doLs(currentInode, inodeSize, ext2, sBlock, groupDesc);
break;
case Command.CAT:
Command.doCat(currentInode, inodeSize, ext2, sBlock, groupDesc, pathArray[pathArray.length-1]);
break;
case Command.CD:
if(currentInode.isFile())
System.out.println("Not a directory");
else {
inode = currentInode;
getCurrentPathName(pathArray);
}
break;
default:
System.out.println(command+": command not found");
}
}
// Main method of program
public static void main (String[] args) throws IOException {
running = true;
String compName = getComputerName(), promptSymbol = "$ ";
System.out.println("EXT2 Filesystem Reader version " + Metadata.VERSION + " BY P.SOUTZIS\n");
//Initialize a Volume instance and pass it to the Ext2File constructor, to readBytes the ext2 fs image
String fsName = Ext2File.getFileSystemName();
Volume vol = new Volume(fsName);
Ext2File ext2 = new Ext2File(vol);
//Byte array to hold the data of the SuperBlock, as returned by Ext2File's readBytes() method
byte[] superBlockData = ext2.readBytes(Constants.SUPERBLOCK_OFFSET, Constants.BLOCK_SIZE);
Superblock sBlock = new Superblock(superBlockData);
/*Extract data from SuperBlock*/
final int blockCount = sBlock.getBlockCount();
final int blocksPerGroup = sBlock.getBlocksPerGroup();
final int inodeSize = sBlock.getInodeSize();
final int blockGroupCount = sBlock.getBlockGroupCount(blockCount, blocksPerGroup);
/*Initialize Group Descriptor*/
byte[] gDescData = ext2.readBytes(Constants.GDESCRIPTOR_OFFSET, Constants.BLOCK_SIZE);
//The Group Descriptor class instance, which reads the group descriptor
GroupDescriptor groupDesc = new GroupDescriptor(gDescData, blockGroupCount);
//If the user chooses to, then print this information.
System.out.print("Would you like to view generic information about the mounted volume? (Y/N): ");
if(getInputYesNo()) {
sBlock.printGenericData(inodeSize, blockGroupCount);
int[] inodeTable = groupDesc.getGDescPointer();
for (int i = 0; i < inodeTable.length; i++)
System.out.println("Inode Table " + (i + 1) + " offset in Group Descriptor is: " + inodeTable[i]);
}
//Push root symbol ("/") into stack and initialize currentDir
pathStack.push(Constants.ROOT);
currentDir = pathStack.peek();
//The containing block offset for the Root Inode
int rootInodeBlockNumber =
Inode.getContainingBlock(Constants.ROOT_INODE_OFFSET, sBlock, groupDesc);
//Initialize root inode
byte[] rootInodeData = ext2.readBytes(rootInodeBlockNumber, inodeSize);
//Contains pointers to the filesystem blocks, which contain the data
inode = new Inode(rootInodeData);
while(running) {
//Get the user input
System.out.print("\n"+compName+currentDir+promptSymbol);
Scanner scan = new Scanner(System.in);
String input = scan.nextLine();
getCommandAndExecute(input, inodeSize, sBlock, groupDesc, ext2);
}
}
}