// filesys.cpp
//
// Created by Kyle Westphal on 10/1/19.
//
#include "filesys.h"
#include <sstream>
#include <iostream>
using namespace std;
Filesys::Filesys(string disk, int numberOfBlocks, int blockSize):Sdisk(disk, numberOfBlocks, blockSize) {
rootSize = getBlockSize()/13;
fatSize = (4 * getNumberOfBlocks()) / getBlockSize() + 1; //getBlockSize()/4 + 1;
string buffer;
getBlock(1, buffer);
if (buffer[0] == '#') {
// no filesys
cout << "No file system exits. Creating file system..." << endl;
ostringstream outstream;
for (int i = 1; i <= rootSize; i++) {
filename.push_back("xxxxxxxx");
firstBlock.push_back(0);
}
fat.push_back(fatSize + 1);
for (int i = 1; i <= fatSize; i++) { // to fatSize
fat.push_back(-1);
}
for (int i = fatSize + 1; i < getNumberOfBlocks(); i++) {
fat.push_back(i + 1);
}
fat[fat.size()-1] = 0;
fsSynch();
cout << "File system created." << endl;
}
else {
// read in filesys
cout << "File system exits. Reading in file system..." << endl;
istringstream instream;
buffer.clear();
getBlock(1, buffer);
instream.str(buffer);
for (int i = 0; i < rootSize; i++) {
string f;
int b;
instream >> f >> b;
filename.push_back(f);
firstBlock.push_back(b);
}
instream.str("");
for (int i = 2; i <= fatSize + 2; i++) {
getBlock(i, buffer);
instream.str(instream.str() + buffer);
}
for(int s; instream >> s;) {
fat.push_back(s);
}
cout << "Complete." << endl;
}
}
int Filesys::fsClose() {
return 0;
}
int Filesys::fsSynch() {
string buffer;
ostringstream outstream;
for (int i = 0; i < rootSize; i++) {
outstream << filename[i] << " " << firstBlock[i] << " ";
}
buffer = outstream.str();
vector<string> blocks = block(buffer, getBlockSize());
for (int i = 0; i < blocks.size(); i++) {
putBlock(i + 1, blocks[i]);
}
outstream.str("");
for (int i = 0; i < fat.size(); i++) {
outstream << fat[i] << " ";
}
buffer = outstream.str();
blocks = block(buffer, getBlockSize());
for (int i = 0; i < blocks.size(); i++) {
putBlock(i + 2, blocks[i]);
}
return 0; // Success
}
int Filesys::newFile(string file) {
for (int i = 0; i < rootSize; i++) {
if (filename[i] == file) {
return 0;
}
}
for (int i = 0; i < rootSize; i++){
if (filename[i] == "xxxxxxxx") {
filename[i] = file;
fsSynch();
return 1;
}
}
fsSynch();
return 0;
}
int Filesys::rmFile(string file) {
for (int i = 0; i < rootSize; i++) {
if(filename[i] == file) {
if (firstBlock[i] != 0) {
cout << "file is not empty" << endl;
return 0;
}
else {
filename[i] = "xxxxxxxx";
fsSynch();
return 1;
}
}
}
return 0;
}
int Filesys::getFirstBlock(string file) {
for (int i = 0; i < rootSize; i++) {
if (filename[i] == file) {
return firstBlock[i];
}
}
return -1;
}
int Filesys::addBlock(string file, string buffer) {
int first = getFirstBlock(file);
if (first == -1) {
return 0;
}
int allocate = fat[0];
if (allocate == 0) {
// no free blocks
return 0;
}
fat[0] = fat[fat[0]];
fat[allocate] = 0;
if(first == 0) { // First block to be added to the file
for (int i = 0; i < rootSize; i++) {
if (filename[i] == file) {
firstBlock[i] = allocate;
fsSynch();
putBlock(allocate, buffer);
return allocate;
}
}
}
else { // find the previous last block
int block = first;
while(block != 0) {
if(fat[block] != 0) {
block = fat[block];
}
else break;
}
// update free list
fat[block] = allocate;
fsSynch();
putBlock(allocate, buffer);
return allocate;
}
return allocate;
}
int Filesys::delBlock(string file, int blockNumber) {
if (!checkBlock(file,blockNumber)) {
return 0;
}
int deallocate = blockNumber;
// check to see if block to be deleted is the first block
if(blockNumber == getFirstBlock(file)) {
for (int i = 0; i < filename.size(); i++) {
// check to see if block to be deleted has subsequent blocks
// if so, connect previous block to next block
if(file == filename[i]) {
if(nextBlock(file, blockNumber) != -1) {
firstBlock[i] = nextBlock(file, blockNumber);
}
// if not, add blockNumber to free list
else firstBlock[i] = fat[deallocate];
break;
}
}
}
// otherwise, delete the block and add the block to the free list
else {
int iBlock = getFirstBlock(file);
while (fat[iBlock] != deallocate) {
iBlock = fat[iBlock];
}
fat[iBlock] = fat[deallocate];
}
fat[deallocate] = fat[0];
fat[0] = deallocate;
fsSynch();
return 1;
}
int Filesys::readBlock(string file, int blockNumber, string& buffer) {
if (checkBlock(file, blockNumber)) {
getBlock(blockNumber, buffer);
return 1;
}
else return 0;
}
int Filesys::writeBlock(string file, int blockNumber, string buffer) {
if (checkBlock(file, blockNumber)) {
putBlock(blockNumber, buffer);
return 1;
}
else return 0;
}
int Filesys::nextBlock(string file, int blockNumber) {
if(checkBlock(file, blockNumber)) {
return fat[blockNumber];
}
else return -1;
}
bool Filesys::checkBlock(string file, int blockNumber) {
int iBlock = getFirstBlock(file);
while(iBlock != 0) {
if(iBlock == blockNumber) {
return true;
}
iBlock = fat[iBlock];
}
return false;
}
vector<string> Filesys::ls() {
vector<string> fileList;
for (int i = 0; i < filename.size(); i++) {
if (filename[i] != "xxxxxxxx") {
fileList.push_back(filename[i]);
}
}
return fileList;
}