Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //============================================================================
- // Name : UNIX-FileSystem.cpp
- // Author : Zdravko Chiflishki
- // Version : 1.01030
- // Copyright : Your copyright notice
- // Description : Unix File System Implementation
- //============================================================================
- /*
- * Created on: Oct 18, 2016
- * Author: Zdravko Chiflishki
- */
- #include<iostream>
- #include<stdio.h>
- #include<fcntl.h>
- #include<string>
- #include<cstring>
- using namespace std;
- //Constant variables.
- const unsigned int NADDR = 16; // The maximum number of blocks a file can use.Used in struct inode
- const unsigned int BLOCK_SIZE = 512; // Size of a block
- const unsigned int FILE_SIZE_MAX = NADDR * BLOCK_SIZE; //The maximum size of a file
- const unsigned int BLOCK_NUM = 512; //The maximum number of data block
- const unsigned int INODE_SIZE = 512; //Size of an inode
- const unsigned int INODE_NUM = 512; //The maximum number of inodes
- /*
- * The start position of inode chain.
- * First four blocks are used for loader sector(empty in this program), super block, inode bitmap and block bitmap.
- */
- const unsigned int INODE_START = 4 * BLOCK_SIZE;
- const unsigned int DATA_START = INODE_START + INODE_NUM * BLOCK_SIZE; //The start position of data blocks
- const unsigned int ACCOUNT_NUM = 10; //The maximum number of the file system users
- const unsigned int DIRECTORY_NUM = 12; //The maximum number of sub-files and sub-directories in one directory
- const unsigned short FILE_NAME_LENGTH = 20; //The maximum length of a file name
- const unsigned short USER_NAME_LENGTH = 10;//The maximum length of a user's name
- const unsigned short USER_PASSWORD_LENGTH = 8;//The maximum length of user's password
- //Data structures.
- struct inode // inode
- {
- unsigned int i_ino; //Identification of the inode.
- unsigned int di_addr[NADDR];//Number of data blocks where the file stored.
- unsigned short di_number; //Number of associated files.
- unsigned short di_mode; //0 stands for a directory, 1 stands for a file.
- unsigned short di_uid; //File's user id.
- unsigned short di_size; //File size. For directories, the value is 0.
- };
- struct filsys // super block
- {
- unsigned short s_num_inode; //Total number of inodes.
- unsigned short s_num_finode; //Total number of free inodes.
- unsigned short s_size_inode; //Size of an inode.
- unsigned short s_num_block; //Total number of blocks.
- unsigned short s_num_fblock; //Total number of free blocks.
- unsigned short s_size_block; //Size of a block.
- };
- struct directory // Directory file
- {
- char fileName[DIRECTORY_NUM][FILE_NAME_LENGTH];
- unsigned int inodeID[DIRECTORY_NUM];
- };
- struct userPsw //Accounting file
- {
- unsigned short userID[ACCOUNT_NUM];
- char userName[ACCOUNT_NUM][USER_NAME_LENGTH];
- char password[ACCOUNT_NUM][USER_PASSWORD_LENGTH];
- };
- //Globle varibles.
- FILE* fd = NULL; //A descriptor of a file where the file system is emulated.
- filsys superBlock; // Super Block
- userPsw users; // Accounting information
- directory currentDirectory; // Current directory
- unsigned short inode_bitmap[INODE_NUM]; // Bitmaps for inode.Element 1 stands for 'used', 0 for 'free'.
- unsigned short block_bitmap[BLOCK_NUM]; // Bitmaps for blocks.Element 1 stands for 'used', 0 for 'free'.
- unsigned short userID = ACCOUNT_NUM; // current user ID
- char userName[USER_NAME_LENGTH + 6]; //current user name used in command line
- /*
- * Formatting function of the file system, including the establishment
- * of superblock, inode chain, root directory, password file and so on.
- *
- * return: the function return true only the file system is initialized
- * successfully.
- */
- bool Format()
- {
- /*
- * 1. Create a empty file to emulate the file system.
- */
- FILE* fd = fopen("./UnixFileSystem.dat", "wb+");
- if (fd == NULL)
- {
- printf("Fail to initialize the file system!\n");
- return false;
- }
- /*
- * 2. Initialize super block.
- */
- filsys superBlock;
- superBlock.s_num_inode = INODE_NUM;
- superBlock.s_num_block = BLOCK_NUM;
- superBlock.s_size_inode = INODE_SIZE;
- superBlock.s_size_block = BLOCK_SIZE;
- //Root directory and accounting file will use some inodes and blocks.
- superBlock.s_num_fblock = BLOCK_NUM - 2;
- superBlock.s_num_finode = INODE_NUM - 2;
- //Write super block into file.
- fseek(fd, BLOCK_SIZE, SEEK_SET);
- fwrite(&superBlock, sizeof(filsys), 1, fd);
- /*
- * 3. Initialize inode and block bitmaps.
- */
- unsigned short inode_bitmap[INODE_NUM];
- unsigned short block_bitmap[BLOCK_NUM];
- //Root directory and accounting file will use some inodes and blocks.
- memset(inode_bitmap, 0, INODE_NUM);
- memset(block_bitmap, 0, BLOCK_NUM);
- inode_bitmap[0] = 1;
- inode_bitmap[1] = 1;
- block_bitmap[0] = 1;
- block_bitmap[1] = 1;
- //Write bitmaps into file.
- fseek(fd, 2 * BLOCK_SIZE, SEEK_SET);
- fwrite(inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd);
- fseek(fd, 3 * BLOCK_SIZE, SEEK_SET);
- fwrite(block_bitmap, sizeof(unsigned short) * BLOCK_NUM, 1, fd);
- /*
- * 4. Create root directory.
- */
- //Create inode
- //Now root directory contain 1 accounting file.
- inode iroot_tmp;
- iroot_tmp.i_ino = 0; //Identification
- iroot_tmp.di_number = 2; //Associations: itself and accouting file
- iroot_tmp.di_mode = 0; //0 stands for directory
- iroot_tmp.di_size = 0; //"For directories, the value is 0."
- memset(iroot_tmp.di_addr, 0xFF, sizeof(unsigned int) * NADDR);
- iroot_tmp.di_addr[0] = 0; //Root directory is stored on 1st block. FFFFFF means empty.
- iroot_tmp.di_uid = 0; //Root user id.
- fseek(fd, INODE_START, SEEK_SET);
- fwrite(&iroot_tmp, sizeof(inode), 1, fd);
- //Create directory file.
- directory droot_tmp;
- memset(droot_tmp.fileName, 0, sizeof(char) * DIRECTORY_NUM * FILE_NAME_LENGTH);
- memset(droot_tmp.inodeID, 0xFF, sizeof(unsigned int) * DIRECTORY_NUM);
- strcpy(droot_tmp.fileName[0], ".");
- droot_tmp.inodeID[0] = 0;
- strcpy(droot_tmp.fileName[1], "..");
- droot_tmp.inodeID[1] = 0;
- //A sub directory for accounting files
- strcpy(droot_tmp.fileName[2], "psw");
- droot_tmp.inodeID[2] = 1;
- //Write
- fseek(fd, DATA_START, SEEK_SET);
- fwrite(&droot_tmp, sizeof(directory), 1, fd);
- /*
- * 5. Create accouting file.
- */
- //Create inode
- inode iaccouting_tmp;
- iaccouting_tmp.i_ino = 1; //Identification
- iaccouting_tmp.di_number = 1; //Associations
- iaccouting_tmp.di_mode = 1; //1 stands for file
- iaccouting_tmp.di_size = sizeof(userPsw); //File size
- memset(iaccouting_tmp.di_addr, 0xFF, sizeof(unsigned int) * NADDR);
- iaccouting_tmp.di_addr[0] = 1; //Root directory is stored on 1st block.
- iaccouting_tmp.di_uid = 0; //Root user id.
- fseek(fd, INODE_START + BLOCK_SIZE, SEEK_SET);
- fwrite(&iaccouting_tmp, sizeof(inode), 1, fd);
- //Create accouting file.
- userPsw paccouting_tmp;
- memset(paccouting_tmp.userName, 0, sizeof(char) * USER_NAME_LENGTH * ACCOUNT_NUM);
- memset(paccouting_tmp.password, 0, sizeof(char) * USER_PASSWORD_LENGTH * ACCOUNT_NUM);
- strcpy(paccouting_tmp.userName[0], "admin");
- strcpy(paccouting_tmp.password[0], "admin");
- //0 stands for super user. Other IDs are only used to identify users.
- for (unsigned short i = 0; i < ACCOUNT_NUM; i++)
- {
- paccouting_tmp.userID[i] = i;
- }
- //Write
- fseek(fd, DATA_START + BLOCK_SIZE, SEEK_SET);
- fwrite(&paccouting_tmp, sizeof(userPsw), 1, fd);
- /*
- userPsw zaccouting_tmp;
- memset(zaccouting_tmp.userName, 0, sizeof(char) * USER_NAME_LENGTH * ACCOUNT_NUM);
- memset(zaccouting_tmp.password, 0, sizeof(char) * USER_PASSWORD_LENGTH * ACCOUNT_NUM);
- strcpy(zaccouting_tmp.userName[0], "zdravko");
- strcpy(zaccouting_tmp.password[0], "chiflishki");
- for (unsigned short i = 0; i < ACCOUNT_NUM; i++)
- {
- zaccouting_tmp.userID[i] = i;
- }
- fseek(fd, DATA_START + BLOCK_SIZE, SEEK_SET);
- fwrite(&zaccouting_tmp, sizeof(userPsw), 1, fd);
- */
- //Close file.
- fclose(fd);
- return true;
- };
- /*
- * Initialization function of the file system. Open an existing file system
- * from 'UnixFileSystem.dat'.
- *
- * return: the function return true only when the file system has been
- * formatted and is complete.
- */
- bool Mount()
- {
- /*
- * 1. Open the emulation file where the file system is installed.
- */
- fd = fopen("./UnixFileSystem.dat", "rb+");
- if (fd == NULL)
- {
- printf("Error: File system not found!\n");
- return false;
- }
- /*
- * 2. Read superblock, bitmaps, accouting file, current directory (root)
- */
- //Read superblock
- fseek(fd, BLOCK_SIZE, SEEK_SET);
- fread(&superBlock, sizeof(superBlock), 1, fd);
- //Read inode bitmap
- fseek(fd, 2 * BLOCK_SIZE, SEEK_SET);
- fread(inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd);
- //Read block bitmap
- fseek(fd, 3 * BLOCK_SIZE, SEEK_SET);
- fread(block_bitmap, sizeof(unsigned short) * BLOCK_NUM, 1, fd);
- //Read current directory, namely root directory
- fseek(fd, DATA_START, SEEK_SET);
- fread(¤tDirectory, sizeof(directory), 1, fd);
- //Read accouting file
- fseek(fd, DATA_START + BLOCK_SIZE, SEEK_SET);
- fread(&users, sizeof(userPsw), 1, fd);
- return true;
- };
- /*
- * Log in function. Update user information by checking log in inputs.
- *
- * return: the function return true only when log in process succeed.
- */
- bool Login(const char* user, const char* password)
- {
- //parameters check
- if (user == NULL || password == NULL)
- {
- printf("Error: User name or password illegal!\n");
- return false;
- }
- if (strlen(user) > USER_NAME_LENGTH || strlen(password) > USER_PASSWORD_LENGTH)
- {
- printf("Error: User name or password illegal!\n");
- return false;
- }
- //have logged in?
- if (userID != ACCOUNT_NUM)
- {
- printf("Login failed: User has been logged in. Please log out first.\n");
- return false;
- }
- //search the user in accouting file
- for (int i = 0; i < ACCOUNT_NUM; i++)
- {
- if (strcmp(users.userName[i], user) == 0)
- {
- //find the user and check password
- if (strcmp(users.password[i], password) == 0)
- {
- //Login successfully
- printf("Login successfully.\n");
- userID = users.userID[i];
- //make user's name, root user is special
- memset(userName, 0, USER_NAME_LENGTH + 6);
- if (userID == 0)
- {
- strcat(userName, "root<");
- strcat(userName, users.userName[i]);
- strcat(userName, "@");
- }
- else
- {
- strcat(userName, users.userName[i]);
- strcat(userName, "#");
- }
- return true;
- }
- else
- {
- //Password wrong
- printf("Login failed: Wrong password.\n");
- return false;
- }
- }
- }
- //User not found
- printf("Login failed: User not found.\n");
- return false;
- };
- /*
- * Log out function. Remove user's states.
- */
- void Logout()
- {
- //remove user's states
- userID = ACCOUNT_NUM;
- memset(&users, 0, sizeof(users));
- memset(userName, 0, 6 + USER_NAME_LENGTH);
- };
- /*
- * Create a new empty file with the specific file name.
- *
- * return: the function return true only when the new file is successfully
- * created.
- */
- bool CreateFile(const char* filename)
- {
- //parameter check
- if (filename == NULL || strlen(filename) > FILE_NAME_LENGTH)
- {
- printf("Error: Illegal file name.\n");
- return false;
- }
- /*
- * 1. Check whether free inodes and blocks are used up.
- */
- if (superBlock.s_num_fblock <= 0 || superBlock.s_num_finode <= 0)
- {
- printf("File creation error: No valid spaces.\n");
- return false;
- }
- //Find new inode number and new block address
- int new_ino = 0;
- int new_block_addr = 0;
- for (; new_ino < INODE_NUM; new_ino++)
- {
- if (inode_bitmap[new_ino] == 0)
- {
- break;
- }
- }
- for (; new_block_addr < BLOCK_NUM; new_block_addr++)
- {
- if (block_bitmap[new_block_addr] == 0)
- {
- break;
- }
- }
- if (new_ino == INODE_NUM || new_block_addr == BLOCK_NUM)
- {
- printf("File creation error: No valid spaces.\n");
- return false;
- }
- /*
- * 2. Check whether file name has been used in current directory.
- */
- for (int i = 0; i < DIRECTORY_NUM; i++)
- {
- if (strcmp(currentDirectory.fileName[i], filename) == 0)
- {
- printf("File creation error: File name '%s' has been used.\n", currentDirectory.fileName[i]);
- return false;
- }
- }
- /*
- * 3. Check whether current directory contains too many items already.
- */
- int itemCounter = 0;
- for (int i = 0; i < DIRECTORY_NUM; i++)
- {
- if (strlen(currentDirectory.fileName[i]) > 0)
- {
- itemCounter++;
- }
- }
- if (itemCounter >= DIRECTORY_NUM)
- {
- printf("File creation error: Too many files or directories in current path.\n");
- return false;
- }
- /*
- * 4. Create new inode.
- */
- //Create inode
- inode ifile_tmp;
- ifile_tmp.i_ino = new_ino; //Identification
- ifile_tmp.di_number = 1; //Associations
- ifile_tmp.di_mode = 1; //1 stands for file
- ifile_tmp.di_size = 0; //New file is empty
- memset(ifile_tmp.di_addr, 0xFF, sizeof(unsigned int) * NADDR);
- ifile_tmp.di_addr[0] = new_block_addr; //0xFFFFFF means empty.
- ifile_tmp.di_uid = userID; //Current user id.
- fseek(fd, INODE_START + new_ino * BLOCK_SIZE, SEEK_SET);
- fwrite(&ifile_tmp, sizeof(inode), 1, fd);
- /*
- * 5. Update bitmaps.
- */
- //Update bitmaps
- inode_bitmap[new_ino] = 1;
- fseek(fd, 2 * BLOCK_SIZE, SEEK_SET);
- fwrite(inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd);
- block_bitmap[new_block_addr] = 1;
- fseek(fd, 3 * BLOCK_SIZE, SEEK_SET);
- fwrite(block_bitmap, sizeof(unsigned short) * BLOCK_NUM, 1, fd);
- /*
- * 6. Update directory.
- */
- //Fetch current directory's inode
- //Inode position of current directory
- int pos_directory_inode = 0;
- pos_directory_inode = currentDirectory.inodeID[0]; //"."
- inode tmp_directory_inode;
- fseek(fd, INODE_START + pos_directory_inode * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_directory_inode, sizeof(inode), 1, fd);
- //Add to current directory item
- for (int i = 2; i < DIRECTORY_NUM; i++)
- {
- if (strlen(currentDirectory.fileName[i]) == 0)
- {
- strcat(currentDirectory.fileName[i], filename);
- currentDirectory.inodeID[i] = new_ino;
- break;
- }
- }
- //write
- fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET);
- fwrite(¤tDirectory, sizeof(directory), 1, fd);
- //Update associations
- directory tmp_directory = currentDirectory;
- int tmp_pos_directory_inode = pos_directory_inode;
- while (true)
- {
- //Update association
- tmp_directory_inode.di_number++;
- fseek(fd, INODE_START + tmp_pos_directory_inode * BLOCK_SIZE, SEEK_SET);
- fwrite(&tmp_directory_inode, sizeof(inode), 1, fd);
- //If reach the root directory, finish updating.
- if (tmp_directory.inodeID[1] == tmp_directory.inodeID[0])
- {
- break;
- }
- //Fetch father directory
- tmp_pos_directory_inode = tmp_directory.inodeID[1]; //".."
- fseek(fd, INODE_START + tmp_pos_directory_inode * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_directory_inode, sizeof(inode), 1, fd);
- fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_directory, sizeof(directory), 1, fd);
- }
- /*
- * 7. Update super block.
- */
- superBlock.s_num_fblock--;
- superBlock.s_num_finode--;
- fseek(fd, BLOCK_SIZE, SEEK_SET);
- fwrite(&superBlock, sizeof(filsys), 1, fd);
- return true;
- };
- /*
- * Delete a file.
- *
- * return: the function returns true only delete the file successfully.
- */
- bool DeleteFile(const char* filename)
- {
- //parameter check
- if (filename == NULL || strlen(filename) > FILE_NAME_LENGTH)
- {
- printf("Error: Illegal file name.\n");
- return false;
- }
- /*
- * 1. Check whether the file exists in current directory.
- */
- int pos_in_directory = 0;
- FILE_NAME_RE_SEARCH:
- for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++)
- {
- if (strcmp(currentDirectory.fileName[pos_in_directory], filename) == 0)
- {
- break;
- }
- }
- if (pos_in_directory == DIRECTORY_NUM)
- {
- printf("Delete error: File not found.\n");
- return false;
- }
- /*
- * 2. Fetch inode and check whether it's a directory.
- */
- //Fetch inode
- int tmp_file_ino = currentDirectory.inodeID[pos_in_directory];
- inode tmp_file_inode;
- fseek(fd, INODE_START + tmp_file_ino * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_file_inode, sizeof(inode), 1, fd);
- //Directory check
- if (tmp_file_inode.di_mode == 0)
- {
- //is a directory, roll back and continue to search the file
- goto FILE_NAME_RE_SEARCH;
- }
- //Access check
- if (userID != 0 && userID != tmp_file_inode.di_uid)
- {
- printf("Delete error: Access deny.\n");
- return -1;
- }
- /*
- * 3. Start deleting. Fill the inode's original space with 0s.
- */
- //Fill original space
- int tmp_fill[sizeof(inode)];
- memset(tmp_fill, 0, sizeof(inode));
- fseek(fd, INODE_START + tmp_file_ino * BLOCK_SIZE, SEEK_SET);
- fwrite(&tmp_fill, sizeof(inode), 1, fd);
- /*
- * 4. Update bitmaps
- */
- //inode bitmap
- inode_bitmap[tmp_file_ino] = 0;
- fseek(fd, 2 * BLOCK_SIZE, SEEK_SET);
- fwrite(&inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd);
- //block bitmap
- for (int i = 0; i < (tmp_file_inode.di_size / BLOCK_SIZE + 1); i++)
- {
- block_bitmap[tmp_file_ino + i] = 0;
- }
- fseek(fd, 3 * BLOCK_SIZE, SEEK_SET);
- fwrite(&block_bitmap, sizeof(unsigned short) * BLOCK_NUM, 1, fd);
- /*
- * 5. Update directories
- */
- //Fetch current directory inode
- int pos_directory_inode = currentDirectory.inodeID[0]; //"."
- inode tmp_directory_inode;
- fseek(fd, INODE_START + pos_directory_inode * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_directory_inode, sizeof(inode), 1, fd);
- //Update current directory item
- memset(currentDirectory.fileName[pos_in_directory], 0, FILE_NAME_LENGTH);
- currentDirectory.inodeID[pos_in_directory] = 0xFFFFFFFF;
- fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET);
- fwrite(¤tDirectory, sizeof(directory), 1, fd);
- //Update associations
- directory tmp_directory = currentDirectory;
- int tmp_pos_directory_inode = pos_directory_inode;
- while (true)
- {
- //Update association
- tmp_directory_inode.di_number--;
- fseek(fd, INODE_START + tmp_pos_directory_inode * BLOCK_SIZE, SEEK_SET);
- fwrite(&tmp_directory_inode, sizeof(inode), 1, fd);
- //If reach the root directory, finish updating.
- if (tmp_directory.inodeID[1] == tmp_directory.inodeID[0])
- {
- break;
- }
- //Fetch father directory
- tmp_pos_directory_inode = tmp_directory.inodeID[1]; //".."
- fseek(fd, INODE_START + tmp_pos_directory_inode * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_directory_inode, sizeof(inode), 1, fd);
- fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_directory, sizeof(directory), 1, fd);
- }
- /*
- * 6. Update super block
- */
- superBlock.s_num_fblock += tmp_file_inode.di_size / BLOCK_SIZE + 1;
- superBlock.s_num_finode++;
- fseek(fd, BLOCK_SIZE, SEEK_SET);
- fwrite(&superBlock, sizeof(filsys), 1, fd);
- return true;
- }
- /*
- * Open the specific file under current directory.
- *
- * return: the function returns a pointer of the file's inode if the file is
- * successfully opened and NULL otherwise.
- */
- inode* OpenFile(const char* filename)
- {
- //parameter check
- if (filename == NULL || strlen(filename) > FILE_NAME_LENGTH)
- {
- printf("Error: Illegal file name.\n");
- return NULL;
- }
- /*
- * 1. Check whether the file exists in current directory.
- */
- int pos_in_directory = 0;
- FILE_NAME_RE_RESEARCH:
- for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++)
- {
- if (strcmp(currentDirectory.fileName[pos_in_directory], filename) == 0)
- {
- break;
- }
- }
- if (pos_in_directory == DIRECTORY_NUM)
- {
- printf("Open file error: File not found.\n");
- return NULL;
- }
- /*
- * 2. Fetch inode and check whether it's a directory.
- */
- //Fetch inode
- int tmp_file_ino = currentDirectory.inodeID[pos_in_directory];
- inode* tmp_file_inode = new inode;
- fseek(fd, INODE_START + tmp_file_ino * BLOCK_SIZE, SEEK_SET);
- fread(tmp_file_inode, sizeof(inode), 1, fd);
- //Directory check
- if (tmp_file_inode->di_mode == 0)
- {
- //is a directory, roll back and continue to search the file
- goto FILE_NAME_RE_RESEARCH;
- }
- return tmp_file_inode;
- };
- /*
- * Append a string "content" to the specific file.
- *
- * return: the function returns the number of bytes it has writen or -1 when
- * some error occur.
- */
- int Write(inode& ifile, const char* content)
- {
- //parameter check
- if (content == NULL)
- {
- printf("Error: Illegal file name.\n");
- return -1;
- }
- //Access check
- if (userID != 0 && userID != ifile.di_uid)
- {
- printf("Write error: Access deny.\n");
- return -1;
- }
- /*
- * 1. Check whether the expected file will be out of length.
- */
- int len_content = strlen(content);
- unsigned int new_file_length = len_content + ifile.di_size;
- if (new_file_length >= FILE_SIZE_MAX)
- {
- printf("Write error: File over length.\n");
- return -1;
- }
- /*
- * 2. Get the number of needed blocks and check is there any enough free spaces.
- */
- //Get the number of needed blocks
- int free_space_firstBlock = BLOCK_SIZE - ifile.di_size % BLOCK_SIZE;
- unsigned int num_block_needed;
- if (len_content - free_space_firstBlock > 0)
- {
- num_block_needed = (len_content - free_space_firstBlock) / BLOCK_SIZE + 1;
- }
- else
- {
- num_block_needed = 0;
- }
- //Check is there any enough free spaces
- if (num_block_needed > superBlock.s_num_fblock)
- {
- printf("Write error: No enough space available.\n");
- return -1;
- }
- /*
- * 3. Write first block.
- */
- fseek(fd, DATA_START + ifile.di_addr[0] * BLOCK_SIZE + ifile.di_size % BLOCK_SIZE, SEEK_SET);
- if (num_block_needed == 0)
- {
- fwrite(content, len_content, 1, fd);
- ifile.di_size += len_content;
- }
- else
- {
- fwrite(content, free_space_firstBlock, 1, fd);
- ifile.di_size += free_space_firstBlock;
- }
- /*
- * 4. Write the other blocks. Update file information in inode and block bitmap in the meanwhile.
- */
- char write_buf[BLOCK_SIZE];
- int new_block_addr = 0;
- unsigned int content_write_pos = free_space_firstBlock;
- //Loop and write each blocks
- for (int i = 0; i < num_block_needed; i++)
- {
- memset(write_buf, 0, BLOCK_SIZE);
- //Find a new empty block
- for (new_block_addr = 0; new_block_addr < BLOCK_NUM; new_block_addr++)
- {
- if (block_bitmap[new_block_addr] == 0)
- {
- block_bitmap[new_block_addr] = 1;
- break;
- }
- }
- //Copy from content to write buffer
- unsigned int tmp_counter = 0;
- for (; tmp_counter < BLOCK_SIZE; tmp_counter++)
- {
- if (content[content_write_pos + tmp_counter] == '\0')
- break;
- write_buf[tmp_counter] = content[content_write_pos + tmp_counter];
- }
- content_write_pos += tmp_counter;
- //Write
- fseek(fd, DATA_START + new_block_addr * BLOCK_SIZE, SEEK_SET);
- fwrite(write_buf, tmp_counter, 1, fd);
- //Update inode information: blocks address and file size
- ifile.di_size += tmp_counter;
- for (int j = 0; j < NADDR; j++)
- {
- if (ifile.di_addr[j] == 0xFFFFFFFF)
- {
- ifile.di_addr[j] = new_block_addr;
- break;
- }
- }
- }
- //Write inode
- fseek(fd, INODE_START + ifile.i_ino * BLOCK_SIZE, SEEK_SET);
- fwrite(&ifile, sizeof(inode), 1, fd);
- //Write block bitmap
- fseek(fd, 3 * BLOCK_SIZE, SEEK_SET);
- fwrite(block_bitmap, sizeof(unsigned short) * BLOCK_SIZE, 1, fd);
- /*
- * 5. Update super block.
- */
- superBlock.s_num_fblock -= num_block_needed;
- fseek(fd, BLOCK_SIZE, SEEK_SET);
- fwrite(&superBlock, sizeof(superBlock), 1, fd);
- return len_content;
- };
- /*
- * Create a new drirectory only with "." and ".." items.
- *
- * return: the function returns true only when the new directory is
- * created successfully.
- */
- bool MakeDir(const char* dirname)
- {
- //parameter check
- if (dirname == NULL || strlen(dirname) > FILE_NAME_LENGTH)
- {
- printf("Error: Illegal directory name.\n");
- return false;
- }
- /*
- * 1. Check whether free inodes and blocks are used up.
- */
- if (superBlock.s_num_fblock <= 0 || superBlock.s_num_finode <= 0)
- {
- printf("File creation error: No valid spaces.\n");
- return false;
- }
- //Find new inode number and new block address
- int new_ino = 0;
- int new_block_addr = 0;
- for (; new_ino < INODE_NUM; new_ino++)
- {
- if (inode_bitmap[new_ino] == 0)
- {
- break;
- }
- }
- for (; new_block_addr < BLOCK_NUM; new_block_addr++)
- {
- if (block_bitmap[new_block_addr] == 0)
- {
- break;
- }
- }
- if (new_ino == INODE_NUM || new_block_addr == BLOCK_NUM)
- {
- printf("File creation error: No valid spaces.\n");
- return false;
- }
- /*
- * 2. Check whether directory name has been used in current directory.
- */
- for (int i = 0; i < DIRECTORY_NUM; i++)
- {
- if (strcmp(currentDirectory.fileName[i], dirname) == 0)
- {
- printf("File creation error: Directory name '%s' has been used.\n", currentDirectory.fileName[i]);
- return false;
- }
- }
- /*
- * 3. Check whether current directory contains too many items already.
- */
- int itemCounter = 0;
- for (int i = 0; i < DIRECTORY_NUM; i++)
- {
- if (strlen(currentDirectory.fileName[i]) > 0)
- {
- itemCounter++;
- }
- }
- if (itemCounter >= DIRECTORY_NUM)
- {
- printf("File creation error: Too many files or directories in current path.\n");
- return false;
- }
- /*
- * 4. Create new inode.
- */
- //Create inode
- inode idir_tmp;
- idir_tmp.i_ino = new_ino; //Identification
- idir_tmp.di_number = 1; //Associations
- idir_tmp.di_mode = 0; //0 stands for directory
- idir_tmp.di_size = sizeof(directory); //"For directories, the value is 0."
- memset(idir_tmp.di_addr, 0xFF, sizeof(unsigned int) * NADDR);
- idir_tmp.di_addr[0] = new_block_addr; //0xFFFFFF means empty.
- idir_tmp.di_uid = userID; //Current user id.
- fseek(fd, INODE_START + new_ino * BLOCK_SIZE, SEEK_SET);
- fwrite(&idir_tmp, sizeof(inode), 1, fd);
- /*
- * 5. Create directory file.
- */
- directory tmp_dir;
- memset(tmp_dir.fileName, 0, sizeof(char) * DIRECTORY_NUM * FILE_NAME_LENGTH);
- memset(tmp_dir.inodeID, 0xFF, sizeof(unsigned int) * DIRECTORY_NUM);
- strcpy(tmp_dir.fileName[0], ".");
- tmp_dir.inodeID[0] = new_ino;
- strcpy(tmp_dir.fileName[1], "..");
- tmp_dir.inodeID[1] = currentDirectory.inodeID[0];
- fseek(fd, DATA_START + new_block_addr * BLOCK_SIZE, SEEK_SET);
- fwrite(&tmp_dir, sizeof(directory), 1, fd);
- /*
- * 6. Update bitmaps.
- */
- //Update bitmaps
- inode_bitmap[new_ino] = 1;
- fseek(fd, 2 * BLOCK_SIZE, SEEK_SET);
- fwrite(inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd);
- block_bitmap[new_block_addr] = 1;
- fseek(fd, 3 * BLOCK_SIZE, SEEK_SET);
- fwrite(block_bitmap, sizeof(unsigned short) * BLOCK_NUM, 1, fd);
- /*
- * 7. Update directory.
- */
- //Fetch current directory's inode
- //Inode position of current directory
- int pos_directory_inode = 0;
- pos_directory_inode = currentDirectory.inodeID[0]; //"."
- inode tmp_directory_inode;
- fseek(fd, INODE_START + pos_directory_inode * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_directory_inode, sizeof(inode), 1, fd);
- //Add to current directory item
- for (int i = 2; i < DIRECTORY_NUM; i++)
- {
- if (strlen(currentDirectory.fileName[i]) == 0)
- {
- strcat(currentDirectory.fileName[i], dirname);
- currentDirectory.inodeID[i] = new_ino;
- break;
- }
- }
- //write
- fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET);
- fwrite(¤tDirectory, sizeof(directory), 1, fd);
- //Update associations
- directory tmp_directory = currentDirectory;
- int tmp_pos_directory_inode = pos_directory_inode;
- while (true)
- {
- //Update association
- tmp_directory_inode.di_number++;
- fseek(fd, INODE_START + tmp_pos_directory_inode * BLOCK_SIZE, SEEK_SET);
- fwrite(&tmp_directory_inode, sizeof(inode), 1, fd);
- //If reach the root directory, finish updating.
- if (tmp_directory.inodeID[1] == tmp_directory.inodeID[0])
- {
- break;
- }
- //Fetch father directory
- tmp_pos_directory_inode = tmp_directory.inodeID[1]; //".."
- fseek(fd, INODE_START + tmp_pos_directory_inode * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_directory_inode, sizeof(inode), 1, fd);
- fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_directory, sizeof(directory), 1, fd);
- }
- /*
- * 8. Update super block.
- */
- superBlock.s_num_fblock--;
- superBlock.s_num_finode--;
- fseek(fd, BLOCK_SIZE, SEEK_SET);
- fwrite(&superBlock, sizeof(filsys), 1, fd);
- return true;
- };
- /*
- * Delete a drirectory as well as all files and sub-directories in it.
- *
- * return: the function returns true only when the directory as well
- * as all files and sub-directories in it is deleted successfully.
- */
- bool RemoveDir(const char* dirname)
- {
- //parameter check
- if (dirname == NULL || strlen(dirname) > FILE_NAME_LENGTH)
- {
- printf("Error: Illegal directory name.\n");
- return false;
- }
- /*
- * 1. Check whether the directory exists in current directory.
- */
- int pos_in_directory = 0;
- DIR_NAME_RE_SEARCH:
- for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++)
- {
- if (strcmp(currentDirectory.fileName[pos_in_directory], dirname) == 0)
- {
- break;
- }
- }
- if (pos_in_directory == DIRECTORY_NUM)
- {
- printf("Delete error: Directory not found.\n");
- return false;
- }
- /*
- * 2. Fetch inode and check whether it's a file.
- */
- //Fetch inode
- int tmp_dir_ino = currentDirectory.inodeID[pos_in_directory];
- inode tmp_dir_inode;
- fseek(fd, INODE_START + tmp_dir_ino * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_dir_inode, sizeof(inode), 1, fd);
- //Directory check
- if (tmp_dir_inode.di_mode == 1)
- {
- //is a file, roll back and continue to search the file
- goto DIR_NAME_RE_SEARCH;
- }
- /*
- * 3. Access check.
- */
- if (userID != 0 && userID != tmp_dir_inode.di_uid)
- {
- printf("Delete error: Access deny.\n");
- return false;
- }
- /*
- * 4. Start deleting. Delete all sub-directories and files first.
- */
- directory tmp_dir;
- fseek(fd, DATA_START + tmp_dir_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_dir, sizeof(directory), 1, fd);
- //Search all sub files and directories and delete them.
- inode tmp_sub_inode;
- char tmp_sub_filename[FILE_NAME_LENGTH];
- memset(tmp_sub_filename, 0, FILE_NAME_LENGTH);
- for (int i = 2; i < DIRECTORY_NUM; i++)
- {
- if (strlen(tmp_dir.fileName[i]) > 0)
- {
- strcpy(tmp_sub_filename, tmp_dir.fileName[i]);
- //Determine whether it's a file or a directory.
- fseek(fd, INODE_START + tmp_dir.inodeID[i] * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_sub_inode, sizeof(inode), 1, fd);
- //Before delete sub files and directories, change current directory first and recover after deleting.
- directory tmp_swp;
- tmp_swp = currentDirectory;
- currentDirectory = tmp_dir;
- tmp_dir = tmp_swp;
- //Is a file.
- if (tmp_sub_inode.di_mode == 1)
- {
- DeleteFile(tmp_sub_filename);
- }
- //Is a directory.
- else if (tmp_sub_inode.di_mode == 0)
- {
- RemoveDir(tmp_sub_filename);
- }
- tmp_swp = currentDirectory;
- currentDirectory = tmp_dir;
- tmp_dir = tmp_swp;
- }
- }
- /*
- * 5. Start deleting itself. Fill the inode's original space with 0s.
- */
- //Fill original space
- int tmp_fill[sizeof(inode)];
- memset(tmp_fill, 0, sizeof(inode));
- fseek(fd, INODE_START + tmp_dir_ino * BLOCK_SIZE, SEEK_SET);
- fwrite(&tmp_fill, sizeof(inode), 1, fd);
- /*
- * 6. Update bitmaps
- */
- //inode bitmap
- inode_bitmap[tmp_dir_ino] = 0;
- fseek(fd, 2 * BLOCK_SIZE, SEEK_SET);
- fwrite(&inode_bitmap, sizeof(unsigned short) * INODE_NUM, 1, fd);
- //block bitmap
- for (int i = 0; i < (tmp_dir_inode.di_size / BLOCK_SIZE + 1); i++)
- {
- block_bitmap[tmp_dir_ino + i] = 0;
- }
- fseek(fd, 3 * BLOCK_SIZE, SEEK_SET);
- fwrite(&block_bitmap, sizeof(unsigned short) * BLOCK_NUM, 1, fd);
- /*
- * 7. Update directories
- */
- //Fetch current directory inode
- int pos_directory_inode = currentDirectory.inodeID[0]; //"."
- inode tmp_directory_inode;
- fseek(fd, INODE_START + pos_directory_inode * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_directory_inode, sizeof(inode), 1, fd);
- //Update current directory item
- memset(currentDirectory.fileName[pos_in_directory], 0, FILE_NAME_LENGTH);
- currentDirectory.inodeID[pos_in_directory] = 0xFFFFFFFF;
- fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET);
- fwrite(¤tDirectory, sizeof(directory), 1, fd);
- //Update associations
- directory tmp_directory = currentDirectory;
- int tmp_pos_directory_inode = pos_directory_inode;
- while (true)
- {
- //Update association
- tmp_directory_inode.di_number--;
- fseek(fd, INODE_START + tmp_pos_directory_inode * BLOCK_SIZE, SEEK_SET);
- fwrite(&tmp_directory_inode, sizeof(inode), 1, fd);
- //If reach the root directory, finish updating.
- if (tmp_directory.inodeID[1] == tmp_directory.inodeID[0])
- {
- break;
- }
- //Fetch father directory
- tmp_pos_directory_inode = tmp_directory.inodeID[1]; //".."
- fseek(fd, INODE_START + tmp_pos_directory_inode * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_directory_inode, sizeof(inode), 1, fd);
- fseek(fd, DATA_START + tmp_directory_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_directory, sizeof(directory), 1, fd);
- }
- /*
- * 78 Update super block
- */
- superBlock.s_num_fblock += tmp_dir_inode.di_size / BLOCK_SIZE + 1;
- superBlock.s_num_finode++;
- fseek(fd, BLOCK_SIZE, SEEK_SET);
- fwrite(&superBlock, sizeof(filsys), 1, fd);
- return true;
- };
- /*
- * Open a directory.
- *
- * return: the function returns true only when the directory is
- * opened successfully.
- */
- bool OpenDir(const char* dirname)
- {
- //parameter check
- if (dirname == NULL || strlen(dirname) > FILE_NAME_LENGTH)
- {
- printf("Error: Illegal directory name.\n");
- return false;
- }
- /*
- * 1. Check whether the directory exists in current directory.
- */
- int pos_in_directory = 0;
- DIR_NAME_RE_RESEARCH:
- for (; pos_in_directory < DIRECTORY_NUM; pos_in_directory++)
- {
- if (strcmp(currentDirectory.fileName[pos_in_directory], dirname) == 0)
- {
- break;
- }
- }
- if (pos_in_directory == DIRECTORY_NUM)
- {
- printf("Delete error: Directory not found.\n");
- return false;
- }
- /*
- * 2. Fetch inode and check whether it's a file.
- */
- //Fetch inode
- int tmp_dir_ino = currentDirectory.inodeID[pos_in_directory];
- inode tmp_dir_inode;
- fseek(fd, INODE_START + tmp_dir_ino * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_dir_inode, sizeof(inode), 1, fd);
- //Directory check
- if (tmp_dir_inode.di_mode == 1)
- {
- //is a file, roll back and continue to search the file
- goto DIR_NAME_RE_RESEARCH;
- }
- /*
- * 3. Update current directory.
- */
- directory new_current_dir;
- fseek(fd, DATA_START + tmp_dir_inode.di_addr[0] * BLOCK_SIZE, SEEK_SET);
- fread(&new_current_dir, sizeof(directory), 1, fd);
- currentDirectory = new_current_dir;
- return true;
- };
- /*
- * Print file and directory information under current directory.
- */
- void List()
- {
- printf("\nname\t\t\tuser\t\tinodeID\t\tsize\t\ttype\n");
- for (int i = 0; i < DIRECTORY_NUM; i++)
- {
- if (strlen(currentDirectory.fileName[i]) > 0)
- {
- inode tmp_inode;
- fseek(fd, INODE_START + currentDirectory.inodeID[i] * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_inode, sizeof(inode), 1, fd);
- const char* tmp_type = tmp_inode.di_mode == 0 ? "dir" : "file";
- const char* tmp_user = users.userName[tmp_inode.di_uid];
- printf("%10s\t\t%s\t\t%d\t\t%u\t\t%s\n", currentDirectory.fileName[i], tmp_user, tmp_inode.i_ino, tmp_inode.di_size, tmp_type);
- }
- }
- printf("\n\n");
- }
- void pwd()
- {
- int current = 0;
- current = currentDirectory.inodeID[0];
- inode tmp_inode;
- fseek(fd, INODE_START + currentDirectory.inodeID[1] * BLOCK_SIZE, SEEK_SET);
- fread(&tmp_inode, sizeof(inode), 1, fd);
- printf("PWD : ", currentDirectory.fileName[]);
- }
- /*
- * Function declaritions.
- */
- void CommParser(inode*&);
- void Help();
- void Tests();
- int main()
- {
- //Check file system has been formatted or not.
- FILE* fs_test = fopen("UnixFileSystem.dat", "r");
- if (fs_test == NULL)
- {
- printf("File system not found... Format file system first...\n");
- Format();
- }
- //Install file system
- Mount();
- //First log in
- char tmp_userName[USER_NAME_LENGTH];
- char tmp_userPassword[USER_PASSWORD_LENGTH];
- do {
- memset(tmp_userName, 0, USER_NAME_LENGTH);
- memset(tmp_userPassword, 0, USER_PASSWORD_LENGTH);
- printf("=================================================================================\n");
- printf("==============THIS IS Zdravko Ivanov Chiflishki UNIX FILE SYSTEM=================\n");
- printf("=============================USER LOG IN=========================================\n");
- printf("User name:\t");
- scanf("%s", tmp_userName);
- printf("Password:\t");
- scanf("%s", tmp_userPassword);
- } while (Login(tmp_userName, tmp_userPassword) != true);
- //User's mode of file system
- inode* currentInode = new inode;
- CommParser(currentInode);
- return 0;
- }
- /*
- * Recieve commands from console and call functions accordingly.
- *
- * para cuurentInode: a global inode used for 'open' and 'write'
- */
- void CommParser(inode*& currentInode)
- {
- char para1[11];
- char para2[1024];
- //Recieve commands
- while (true)
- {
- memset(para1, 0, 11);
- memset(para2, 0, 1024);
- printf("%s>", userName);
- scanf("%s", para1);
- para1[10] = 0; //security protection
- //Choose function
- //Print current directory
- if (strcmp("ls", para1) == 0)
- {
- List();
- }
- //print pwd()
- else if (strcmp("pwd", para1) == 0)
- {
- pwd();
- }
- //Create file
- else if (strcmp("create", para1) == 0)
- {
- scanf("%s", para2);
- para2[1023] = 0; //security protection
- CreateFile(para2);
- }
- //Delete file
- else if (strcmp("del", para1) == 0)
- {
- scanf("%s", para2);
- para2[1023] = 0; //security protection
- DeleteFile(para2);
- }
- //Open file
- else if (strcmp("open", para1) == 0)
- {
- scanf("%s", para2);
- para2[1023] = 0; //security protection
- currentInode = OpenFile(para2);
- }
- //Write file
- else if (strcmp("write", para1) == 0)
- {
- scanf("%s", para2);
- para2[1023] = 0; //security protection
- Write(*currentInode, para2);
- }
- //Open a directory
- else if (strcmp("cd", para1) == 0)
- {
- scanf("%s", para2);
- para2[1023] = 0; //security protection
- OpenDir(para2);
- }
- //Create dirctory
- else if (strcmp("mkdir", para1) == 0)
- {
- scanf("%s", para2);
- para2[1023] = 0; //security protection
- MakeDir(para2);
- }
- //Delete directory
- else if (strcmp("rmdir", para1) == 0)
- {
- scanf("%s", para2);
- para2[1023] = 0; //security protection
- RemoveDir(para2);
- }
- //Log out
- else if (strcmp("Logout", para1) == 0)
- {
- Logout();
- }
- //Log in
- else if (strcmp("Login", para1) == 0)
- {
- char para3[USER_PASSWORD_LENGTH + 1];
- memset(para3, 0, USER_PASSWORD_LENGTH + 1);
- scanf("%s", para2);
- para2[1023] = 0; //security protection
- scanf("%s", para3);
- para3[USER_PASSWORD_LENGTH] = 0; //security protection
- Login(para2, para3);
- }
- //Exit
- else if (strcmp("Exit", para1) == 0)
- {
- break;
- }
- //Error or help
- else
- {
- Help();
- }
- }
- };
- /*
- * Print all commands help information when 'help' is
- * called or input error occurs.
- */
- void Help()
- {
- printf("\n=======================================================\n");
- printf("=================This is Help info=======================\n");
- printf("Command\tParametar\t\tInformation.\n");
- printf("ls\t\t\tPrint current directory information.\n");
- printf("create\t<filename>\tCreate a new empty file in current directory.\n");
- printf("del\t<filename>\tDelete the file in current directory.\n");
- printf("open\t<filename>\tOpen a file. Must be used before 'write'.\n");
- printf("cd\t<dirname>\tOpen a directory.\n");
- printf("mkdir\t<dirname>\tCreate a new directory.\n");
- printf("rmdir\t<dirname>\tDelete the directory and all sub files and directoies in\t\t\tit.\n");
- printf("Logout\t\t\tLog out.\n");
- printf("Login <name> <psd>\tLog in as another user.\n");
- printf("Exit\t\t\tExit the file system console.\n");
- printf("Help\t\t\tShow help info.\n\n");
- };
- void Test() {
- char str[] = "Каждый хороший программист должен знать функцию memset!n";
- memset(str, '_', 12); // заполнить первые 12 байт символом '_'
- std::cout << str;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement