Compare commits
8 Commits
72a02047d5
...
lab5
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e0c37abee | |||
| d5c8b24c64 | |||
| ae0a2c0430 | |||
| b6bc6da235 | |||
| 049405989b | |||
| 1dbdbd20d3 | |||
| db6187be39 | |||
| 552e574cde |
7
config.h
7
config.h
@@ -14,9 +14,9 @@
|
|||||||
|
|
||||||
|
|
||||||
/* CLI config section */
|
/* CLI config section */
|
||||||
#define CLI_MAX_LINE_LENGTH 256
|
#define CLI_MAX_LINE_LENGTH 1024
|
||||||
#define CLI_MAX_ACCEPTED_ARGS 4
|
#define CLI_MAX_ACCEPTED_ARGS 4
|
||||||
#define CLI_MAX_TOKEN_LENGTH 64
|
#define CLI_MAX_TOKEN_LENGTH 256
|
||||||
|
|
||||||
|
|
||||||
/* FS config section */
|
/* FS config section */
|
||||||
@@ -26,7 +26,8 @@
|
|||||||
#define FS_MAX_PATH_LEN 512
|
#define FS_MAX_PATH_LEN 512
|
||||||
#define FS_MAX_OPEN_FD 32
|
#define FS_MAX_OPEN_FD 32
|
||||||
#define FS_MAX_FNAME_LEN 11
|
#define FS_MAX_FNAME_LEN 11
|
||||||
#define FS_MAX_DIRECTORY_DEPTH 512
|
#define FS_MAX_DIRECTORY_DEPTH 2048
|
||||||
|
#define FS_MAX_SYMLINK_FOLLOWS 1024
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
4
inc/fs.h
4
inc/fs.h
@@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
enum fs_filetype {
|
enum fs_filetype {
|
||||||
REGULAR,
|
REGULAR,
|
||||||
DIRECTORY
|
DIRECTORY,
|
||||||
|
SYMLINK
|
||||||
};
|
};
|
||||||
|
|
||||||
__attribute__((packed))
|
__attribute__((packed))
|
||||||
@@ -73,6 +74,7 @@ int fs_close(void *d);
|
|||||||
int fs_mkdir(void *d);
|
int fs_mkdir(void *d);
|
||||||
int fs_rmdir(void *d);
|
int fs_rmdir(void *d);
|
||||||
int fs_cd(void *d);
|
int fs_cd(void *d);
|
||||||
|
int fs_symlink(void *d);
|
||||||
int fs_truncate(void *d);
|
int fs_truncate(void *d);
|
||||||
int fs_allow_write(void *d);
|
int fs_allow_write(void *d);
|
||||||
int fs_prohibit_write(void *d);
|
int fs_prohibit_write(void *d);
|
||||||
|
|||||||
15
src/cli.c
15
src/cli.c
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
static const struct CliCommandEntry cmd[] = {
|
static const struct CliCommandEntry cmd[] = {
|
||||||
@@ -29,6 +30,7 @@ static const struct CliCommandEntry cmd[] = {
|
|||||||
{"mkdir", 1, (enum CliArgType[]) {STR}, fs_mkdir},
|
{"mkdir", 1, (enum CliArgType[]) {STR}, fs_mkdir},
|
||||||
{"rmdir", 1, (enum CliArgType[]) {STR}, fs_rmdir},
|
{"rmdir", 1, (enum CliArgType[]) {STR}, fs_rmdir},
|
||||||
{"cd", 1, (enum CliArgType[]) {STR}, fs_cd},
|
{"cd", 1, (enum CliArgType[]) {STR}, fs_cd},
|
||||||
|
{"symlink", 2, (enum CliArgType[]) {STR, STR}, fs_symlink},
|
||||||
|
|
||||||
// custom commands
|
// custom commands
|
||||||
{"use", 1, (enum CliArgType[]) {STR}, fs_use},
|
{"use", 1, (enum CliArgType[]) {STR}, fs_use},
|
||||||
@@ -207,11 +209,11 @@ abandon_struct:
|
|||||||
|
|
||||||
unsigned int cli_poll_process_next(void)
|
unsigned int cli_poll_process_next(void)
|
||||||
{
|
{
|
||||||
for ( ;; ) {
|
int echo_commands = !isatty(STDIN_FILENO);
|
||||||
fputs(fs_get_cwd(), stdout);
|
|
||||||
|
|
||||||
|
for ( ;; ) {
|
||||||
if (fs_get_cwd()[0]) {
|
if (fs_get_cwd()[0]) {
|
||||||
printf(" $ ");
|
printf("%s $ ", fs_get_cwd());
|
||||||
} else {
|
} else {
|
||||||
printf("$ ");
|
printf("$ ");
|
||||||
}
|
}
|
||||||
@@ -220,8 +222,13 @@ unsigned int cli_poll_process_next(void)
|
|||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
|
|
||||||
ssize_t result = getline(&line, &buf_size, stdin);
|
ssize_t result = getline(&line, &buf_size, stdin);
|
||||||
if (result == -1)
|
if (result == -1) {
|
||||||
|
printf("\n");
|
||||||
return 0x1;
|
return 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (echo_commands)
|
||||||
|
printf(line);
|
||||||
|
|
||||||
char **tokenized_line = tokenize_line(line, result);
|
char **tokenized_line = tokenize_line(line, result);
|
||||||
free(line);
|
free(line);
|
||||||
|
|||||||
447
src/fs.c
447
src/fs.c
@@ -24,6 +24,7 @@ static unsigned int fs_cwd_inode_ptr;
|
|||||||
static struct fs_file_description fs_file_descriptions[FS_MAX_OPEN_FD];
|
static struct fs_file_description fs_file_descriptions[FS_MAX_OPEN_FD];
|
||||||
|
|
||||||
static int extract_basename(char *path, char *name);
|
static int extract_basename(char *path, char *name);
|
||||||
|
static int read_symlink(int symlink_inode_ptr, char *path);
|
||||||
|
|
||||||
|
|
||||||
static int read_block(unsigned int block_no, void *data)
|
static int read_block(unsigned int block_no, void *data)
|
||||||
@@ -190,6 +191,16 @@ static unsigned int find_free_block(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int claim_free_block(void)
|
||||||
|
{
|
||||||
|
int free_block = find_free_block();
|
||||||
|
|
||||||
|
if (free_block)
|
||||||
|
mark_used(free_block);
|
||||||
|
|
||||||
|
return free_block;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned int find_free_inode_ptr(void)
|
static unsigned int find_free_inode_ptr(void)
|
||||||
{
|
{
|
||||||
unsigned int i = 1; // inode0 always points to root dir, so can't be free
|
unsigned int i = 1; // inode0 always points to root dir, so can't be free
|
||||||
@@ -897,18 +908,21 @@ fs_remove_fname_from_directory_finish:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resolve_path(struct resolved_path *rp, char *path, unsigned int params)
|
static void resolve_path(struct resolved_path * const rp, const char * const original_path, const unsigned int params)
|
||||||
{
|
{
|
||||||
rp->parent_inode_ptr = -1;
|
rp->parent_inode_ptr = -1;
|
||||||
rp->target_inode_ptr = -1;
|
rp->target_inode_ptr = -1;
|
||||||
|
|
||||||
int path_len = strlen(path);
|
int path_len = strlen(original_path);
|
||||||
|
|
||||||
if (!path_len) {
|
if (!path_len) {
|
||||||
pr_err("no path specified\n");
|
pr_err("no path specified\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char path[FS_MAX_PATH_LEN+1];
|
||||||
|
strcpy(path, original_path);
|
||||||
|
|
||||||
if (!strcmp(path, "/")) {
|
if (!strcmp(path, "/")) {
|
||||||
rp->parent_inode_ptr = 0;
|
rp->parent_inode_ptr = 0;
|
||||||
rp->target_inode_ptr = 0;
|
rp->target_inode_ptr = 0;
|
||||||
@@ -921,6 +935,8 @@ static void resolve_path(struct resolved_path *rp, char *path, unsigned int para
|
|||||||
int current_inode_ptr;
|
int current_inode_ptr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
unsigned int symlinks_followed = 0;
|
||||||
|
|
||||||
if (path[0] == '/') {
|
if (path[0] == '/') {
|
||||||
current_inode_ptr = 0;
|
current_inode_ptr = 0;
|
||||||
rp->parent_inode_ptr = 0;
|
rp->parent_inode_ptr = 0;
|
||||||
@@ -940,65 +956,156 @@ static void resolve_path(struct resolved_path *rp, char *path, unsigned int para
|
|||||||
if (path[i] != '/') {
|
if (path[i] != '/') {
|
||||||
next_fname[next_fname_ptr] = path[i];
|
next_fname[next_fname_ptr] = path[i];
|
||||||
next_fname_ptr++;
|
next_fname_ptr++;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// path[i] == '/', trying to change current directory
|
if ((path[i] != '/') && (i+1 < path_len))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!next_fname_ptr)
|
if (!next_fname_ptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (i+1 == path_len)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
{
|
|
||||||
int res = find_fname_in_directory(current_inode_ptr, next_fname);
|
int res = find_fname_in_directory(current_inode_ptr, next_fname);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
pr_warn("directory '%s' does not exist\n", next_fname);
|
if (i+1 < path_len) {
|
||||||
|
pr_warn("parent '%s' does not exist\n", next_fname);
|
||||||
rp->parent_inode_ptr = -1;
|
rp->parent_inode_ptr = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rp->target_inode_ptr = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
struct fs_inode d;
|
struct fs_inode d;
|
||||||
read_block(read_inode_ptr(res), &d);
|
read_block(read_inode_ptr(res), &d);
|
||||||
|
|
||||||
if (d.ftype == REGULAR) {
|
if (d.ftype == SYMLINK) {
|
||||||
pr_warn("'%s' is a regular file\n", next_fname);
|
if (i+1 < path_len) {
|
||||||
|
symlinks_followed++;
|
||||||
|
if (symlinks_followed > FS_MAX_SYMLINK_FOLLOWS) {
|
||||||
|
pr_err("too many symlink follows\n");
|
||||||
rp->parent_inode_ptr = -1;
|
rp->parent_inode_ptr = -1;
|
||||||
|
rp->target_inode_ptr = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char symlink_path[FS_MAX_PATH_LEN+1];
|
||||||
|
int symlink_path_len = read_symlink(res, symlink_path);
|
||||||
|
|
||||||
|
if (symlink_path_len < 0) {
|
||||||
|
pr_warn("broken symlink\n");
|
||||||
|
rp->parent_inode_ptr = -1;
|
||||||
|
rp->target_inode_ptr = -1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr("Found directory '%s'\n", next_fname);
|
pr("Found symlink '%s', following (-> '%s')\n", next_fname, symlink_path);
|
||||||
current_inode_ptr = res;
|
|
||||||
rp->parent_inode_ptr = res;
|
if (symlink_path[0] == '/') {
|
||||||
}
|
memmove(&(path[symlink_path_len]), &(path[i+1]), path_len-i-1);
|
||||||
|
strcpy(path, &(symlink_path[1]));
|
||||||
|
path[symlink_path_len-1] = '/';
|
||||||
|
path_len = symlink_path_len + path_len - i - 1;
|
||||||
|
i = -1;
|
||||||
|
|
||||||
|
next_fname_ptr = 0;
|
||||||
|
strcpy(current_fname, "/");
|
||||||
|
memset(next_fname, 0, FS_MAX_FNAME_LEN);
|
||||||
|
} else {
|
||||||
|
memmove(&(path[symlink_path_len+1]), &(path[i+1]), path_len-i-1);
|
||||||
|
strcpy(path, symlink_path);
|
||||||
|
path[symlink_path_len] = '/';
|
||||||
|
path_len = symlink_path_len + path_len - i;
|
||||||
|
i = -1;
|
||||||
|
|
||||||
next_fname_ptr = 0;
|
next_fname_ptr = 0;
|
||||||
strcpy(current_fname, next_fname);
|
strcpy(current_fname, next_fname);
|
||||||
memset(next_fname, 0, FS_MAX_FNAME_LEN);
|
memset(next_fname, 0, FS_MAX_FNAME_LEN);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if (rp->parent_inode_ptr < 0) {
|
if (!(params & FOLLOW_LAST_SYMLINK)) {
|
||||||
rp->target_inode_ptr = -1;
|
pr("Stopping at symlink '%s', not following\n", next_fname);
|
||||||
return;
|
rp->target_inode_ptr = res;
|
||||||
|
strcpy(rp->parent_fname, current_fname);
|
||||||
|
strcpy(rp->target_fname, next_fname);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(rp->parent_fname, current_fname);
|
symlinks_followed++;
|
||||||
|
if (symlinks_followed > FS_MAX_SYMLINK_FOLLOWS) {
|
||||||
{
|
pr_err("too many symlink follows\n");
|
||||||
int res = find_fname_in_directory(current_inode_ptr, next_fname);
|
rp->parent_inode_ptr = -1;
|
||||||
if (res < 0) {
|
|
||||||
pr_warn("target fname '%s' does not exist\n", next_fname);
|
|
||||||
rp->target_inode_ptr = -1;
|
rp->target_inode_ptr = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char symlink_path[FS_MAX_PATH_LEN+1];
|
||||||
|
int symlink_path_len = read_symlink(res, symlink_path);
|
||||||
|
|
||||||
|
if (symlink_path_len < 0) {
|
||||||
|
pr_warn("broken symlink\n");
|
||||||
|
rp->parent_inode_ptr = -1;
|
||||||
|
rp->target_inode_ptr = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr("Found symlink '%s' at last position, following (-> '%s')\n", next_fname, symlink_path);
|
||||||
|
|
||||||
|
if (!strcmp(symlink_path, "/")) {
|
||||||
|
rp->parent_inode_ptr = 0;
|
||||||
|
rp->target_inode_ptr = 0;
|
||||||
|
strcpy(rp->parent_fname, "/");
|
||||||
|
strcpy(rp->target_fname, "/");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symlink_path[0] == '/') {
|
||||||
|
strcpy(path, &(symlink_path[1]));
|
||||||
|
path_len = symlink_path_len - 1;
|
||||||
|
i = -1;
|
||||||
|
|
||||||
|
next_fname_ptr = 0;
|
||||||
|
strcpy(current_fname, "/");
|
||||||
|
memset(next_fname, 0, FS_MAX_FNAME_LEN);
|
||||||
} else {
|
} else {
|
||||||
|
strcpy(path, symlink_path);
|
||||||
|
path_len = symlink_path_len;
|
||||||
|
i = -1;
|
||||||
|
|
||||||
|
next_fname_ptr = 0;
|
||||||
|
strcpy(current_fname, next_fname);
|
||||||
|
memset(next_fname, 0, FS_MAX_FNAME_LEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (d.ftype == REGULAR) {
|
||||||
|
if (i+1 < path_len) {
|
||||||
|
pr_warn("'%s': regular file not in the end of a path\n", next_fname);
|
||||||
|
rp->parent_inode_ptr = -1;
|
||||||
|
rp->target_inode_ptr = -1;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
pr("Stopping at regular file '%s'\n", next_fname);
|
||||||
rp->target_inode_ptr = res;
|
rp->target_inode_ptr = res;
|
||||||
|
strcpy(rp->parent_fname, current_fname);
|
||||||
|
strcpy(rp->target_fname, next_fname);
|
||||||
|
}
|
||||||
|
} else if (d.ftype == DIRECTORY) {
|
||||||
|
if (i+1 < path_len) {
|
||||||
|
pr("Found directory '%s'\n", next_fname);
|
||||||
|
current_inode_ptr = res;
|
||||||
|
rp->parent_inode_ptr = res;
|
||||||
|
|
||||||
|
next_fname_ptr = 0;
|
||||||
|
strcpy(current_fname, next_fname);
|
||||||
|
memset(next_fname, 0, FS_MAX_FNAME_LEN);
|
||||||
|
} else {
|
||||||
|
pr("Stopping at directory '%s'\n", next_fname);
|
||||||
|
rp->target_inode_ptr = res;
|
||||||
|
strcpy(rp->parent_fname, current_fname);
|
||||||
strcpy(rp->target_fname, next_fname);
|
strcpy(rp->target_fname, next_fname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1584,6 +1691,12 @@ int fs_ln(void *d)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: add support for directory as target, e. g.:
|
||||||
|
* $ create file1
|
||||||
|
* $ mkdir dir2
|
||||||
|
* $ ln file1 dir2 -> creates hardlink 'dir2/file1'
|
||||||
|
*/
|
||||||
resolve_path(&new_rp, new_path, 1);
|
resolve_path(&new_rp, new_path, 1);
|
||||||
if (new_rp.parent_inode_ptr < 0) {
|
if (new_rp.parent_inode_ptr < 0) {
|
||||||
pr_err("failed to create hard link: no such directory: '%s'\n", new_path);
|
pr_err("failed to create hard link: no such directory: '%s'\n", new_path);
|
||||||
@@ -1615,6 +1728,223 @@ int fs_ln(void *d)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int read_symlink(int symlink_inode_ptr, char *path)
|
||||||
|
{
|
||||||
|
struct fs_inode i;
|
||||||
|
read_block(read_inode_ptr(symlink_inode_ptr), &i);
|
||||||
|
|
||||||
|
path[0] = '\0';
|
||||||
|
int bytes_read = 0;
|
||||||
|
|
||||||
|
for (int j = 0; j < BLOCK_ADDRESSES_PER_INODE; j++) {
|
||||||
|
if (!i.blocks[j]) {
|
||||||
|
pr_err("inode size (%d) indicates existing block but it's address is absent in inode, symlink at inode_ptr=%d might be broken\n",
|
||||||
|
i.size, symlink_inode_ptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char data[FS_BLOCK_SIZE];
|
||||||
|
read_block(i.blocks[j], data);
|
||||||
|
|
||||||
|
if (i.size - bytes_read < FS_BLOCK_SIZE) {
|
||||||
|
memcpy(&(path[bytes_read]), data, i.size - bytes_read);
|
||||||
|
bytes_read = i.size;
|
||||||
|
path[bytes_read] = '\0';
|
||||||
|
} else {
|
||||||
|
memcpy(&(path[bytes_read]), data, FS_BLOCK_SIZE);
|
||||||
|
bytes_read += FS_BLOCK_SIZE;
|
||||||
|
path[bytes_read] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.size == bytes_read)
|
||||||
|
goto finish_reading;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int next_ext = i.next_extension; ; ) {
|
||||||
|
struct fs_inode_extension ext;
|
||||||
|
read_block(next_ext, &ext);
|
||||||
|
|
||||||
|
for (int j = 0; j < BLOCK_ADDRESSES_PER_INODE_EXTENSION; j++) {
|
||||||
|
if (!ext.blocks[j]) {
|
||||||
|
pr_err("inode size (%d) indicates existing block but it's address is absent in inode extension, symlink at inode_ptr=%d might be broken\n",
|
||||||
|
i.size, symlink_inode_ptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char data[FS_BLOCK_SIZE];
|
||||||
|
read_block(ext.blocks[j], data);
|
||||||
|
|
||||||
|
if (i.size - bytes_read < FS_BLOCK_SIZE) {
|
||||||
|
memcpy(&(path[bytes_read]), data, i.size - bytes_read);
|
||||||
|
bytes_read = i.size;
|
||||||
|
path[bytes_read] = '\0';
|
||||||
|
} else {
|
||||||
|
memcpy(&(path[bytes_read]), data, FS_BLOCK_SIZE);
|
||||||
|
bytes_read += FS_BLOCK_SIZE;
|
||||||
|
path[bytes_read] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.size == bytes_read)
|
||||||
|
goto finish_reading;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_ext = ext.next_extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_reading:
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_symlink(void *d)
|
||||||
|
{
|
||||||
|
char *target_path = ((char **) d)[0];
|
||||||
|
char *link_path = ((char **)d)[1];
|
||||||
|
|
||||||
|
int target_path_len = strlen(target_path);
|
||||||
|
|
||||||
|
struct resolved_path rp;
|
||||||
|
resolve_path(&rp, link_path, FOLLOW_LAST_SYMLINK);
|
||||||
|
|
||||||
|
if (rp.parent_inode_ptr < 0) {
|
||||||
|
pr_err("failed to create symlink: no such directory: '%s'\n", link_path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char link_fname[FS_MAX_FNAME_LEN+1];
|
||||||
|
unsigned int dir_inode_ptr;
|
||||||
|
|
||||||
|
if (rp.target_inode_ptr >= 0) {
|
||||||
|
{
|
||||||
|
struct fs_inode i;
|
||||||
|
read_block(read_inode_ptr(rp.target_inode_ptr), &i);
|
||||||
|
|
||||||
|
if (i.ftype == REGULAR) {
|
||||||
|
pr_err("file already exists: '%s'\n", rp.target_fname);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
int link_fname_len = extract_basename(target_path, link_fname);
|
||||||
|
if (link_fname_len > FS_MAX_FNAME_LEN) {
|
||||||
|
pr_err("new filename too long (%d > %d)\n", link_fname_len, FS_MAX_FNAME_LEN);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_inode_ptr = rp.target_inode_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int link_fname_len = extract_basename(link_path, link_fname);
|
||||||
|
if (link_fname_len > FS_MAX_FNAME_LEN) {
|
||||||
|
pr_err("new filename too long (%d > %d)\n", link_fname_len, FS_MAX_FNAME_LEN);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_inode_ptr = rp.parent_inode_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int inode_ptr = find_free_inode_ptr();
|
||||||
|
if (!inode_ptr) {
|
||||||
|
pr_err("no free inode_ptr found\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int inode_addr = claim_free_block();
|
||||||
|
if (!inode_addr) {
|
||||||
|
pr_err("no space left on device\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_inode_ptr(inode_ptr, inode_addr);
|
||||||
|
|
||||||
|
int required_block_amount = target_path_len % FS_BLOCK_SIZE
|
||||||
|
? target_path_len / FS_BLOCK_SIZE + 1
|
||||||
|
: target_path_len / FS_BLOCK_SIZE;
|
||||||
|
|
||||||
|
int inode_blocks[required_block_amount];
|
||||||
|
|
||||||
|
for (int i = 0; i < required_block_amount; i++) {
|
||||||
|
inode_blocks[i] = claim_free_block();
|
||||||
|
if (!inode_blocks[i]) {
|
||||||
|
pr_err("no space left on device\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytes_written = 0;
|
||||||
|
int blocks_written = 0;
|
||||||
|
|
||||||
|
struct fs_inode i;
|
||||||
|
memset(&i, 0, sizeof(i));
|
||||||
|
|
||||||
|
i.ftype = SYMLINK;
|
||||||
|
i.ref_count = 1;
|
||||||
|
i.size = target_path_len;
|
||||||
|
|
||||||
|
for (int j = 0; j < BLOCK_ADDRESSES_PER_INODE; j++, blocks_written++) {
|
||||||
|
i.blocks[j] = inode_blocks[blocks_written];
|
||||||
|
write_block(inode_addr, &i);
|
||||||
|
|
||||||
|
if (target_path_len - bytes_written < FS_BLOCK_SIZE) {
|
||||||
|
char data_block[FS_BLOCK_SIZE];
|
||||||
|
memset(data_block, 0, sizeof(data_block));
|
||||||
|
memcpy(data_block, &(target_path[bytes_written]), target_path_len - bytes_written);
|
||||||
|
write_block(inode_blocks[blocks_written], data_block);
|
||||||
|
bytes_written = target_path_len;
|
||||||
|
} else {
|
||||||
|
write_block(inode_blocks[blocks_written], &(target_path[bytes_written]));
|
||||||
|
bytes_written += FS_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_path_len == bytes_written)
|
||||||
|
goto finish_writing;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.next_extension = claim_free_block();
|
||||||
|
if (!i.next_extension) {
|
||||||
|
pr_err("no space left on device\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
write_block(inode_addr, &i);
|
||||||
|
|
||||||
|
for (unsigned int next_ext = i.next_extension; ; ) {
|
||||||
|
struct fs_inode_extension ext;
|
||||||
|
memset(&ext, 0, sizeof(ext));
|
||||||
|
|
||||||
|
for (int j = 0; j < BLOCK_ADDRESSES_PER_INODE_EXTENSION; j++, blocks_written++) {
|
||||||
|
ext.blocks[j] = inode_blocks[blocks_written];
|
||||||
|
write_block(next_ext, &ext);
|
||||||
|
|
||||||
|
if (target_path_len - bytes_written < FS_BLOCK_SIZE) {
|
||||||
|
char data_block[FS_BLOCK_SIZE];
|
||||||
|
memset(data_block, 0, sizeof(data_block));
|
||||||
|
memcpy(data_block, &(target_path[bytes_written]), target_path_len - bytes_written);
|
||||||
|
write_block(inode_blocks[blocks_written], data_block);
|
||||||
|
bytes_written = target_path_len;
|
||||||
|
} else {
|
||||||
|
write_block(inode_blocks[blocks_written], &(target_path[bytes_written]));
|
||||||
|
bytes_written += FS_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_path_len == bytes_written)
|
||||||
|
goto finish_writing;
|
||||||
|
}
|
||||||
|
|
||||||
|
ext.next_extension = claim_free_block();
|
||||||
|
if (!ext.next_extension) {
|
||||||
|
pr_err("no space left on device\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
write_block(next_ext, &ext);
|
||||||
|
|
||||||
|
next_ext = ext.next_extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_writing:
|
||||||
|
pr("Symlink '%s' written successfully (%d/%d bytes)\n", link_fname, bytes_written, target_path_len);
|
||||||
|
|
||||||
|
fs_add_fname_to_directory(dir_inode_ptr, inode_ptr, link_fname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int last_significant_slash_position(char *path, int path_len)
|
static int last_significant_slash_position(char *path, int path_len)
|
||||||
{
|
{
|
||||||
@@ -1637,12 +1967,9 @@ static int extract_basename(char *path, char *name)
|
|||||||
if (fname_len > FS_MAX_FNAME_LEN) {
|
if (fname_len > FS_MAX_FNAME_LEN) {
|
||||||
pr_err("filename too long (%d > %d)",
|
pr_err("filename too long (%d > %d)",
|
||||||
fname_len, FS_MAX_FNAME_LEN);
|
fname_len, FS_MAX_FNAME_LEN);
|
||||||
return -1;
|
} else if (name) {
|
||||||
}
|
|
||||||
|
|
||||||
// allow the usage of NULL ptr to discard basename string
|
|
||||||
if (name)
|
|
||||||
strcpy(name, &(path[lsp+1]));
|
strcpy(name, &(path[lsp+1]));
|
||||||
|
}
|
||||||
|
|
||||||
return fname_len;
|
return fname_len;
|
||||||
}
|
}
|
||||||
@@ -2099,13 +2426,27 @@ int fs_la(void *d)
|
|||||||
struct fs_inode f_inode;
|
struct fs_inode f_inode;
|
||||||
read_block(read_inode_ptr(recs[k].inode_no), (void *) &f_inode);
|
read_block(read_inode_ptr(recs[k].inode_no), (void *) &f_inode);
|
||||||
|
|
||||||
if (f_inode.ftype == DIRECTORY) {
|
if (f_inode.ftype == REGULAR) {
|
||||||
|
pr_stdout("%s (inode_ptr=%d -> inode=%d, ref_count=%d, size=%d, type=reg)\n",
|
||||||
|
recs[k].fname, recs[k].inode_no, read_inode_ptr(recs[k].inode_no),
|
||||||
|
f_inode.ref_count, f_inode.size);
|
||||||
|
} else if (f_inode.ftype == DIRECTORY) {
|
||||||
pr_stdout(COLOR_BLUE "%s" COLOR_RESET
|
pr_stdout(COLOR_BLUE "%s" COLOR_RESET
|
||||||
" (inode_ptr=%d -> inode=%d, ref_count=%d, size=%d, type=dir)\n",
|
" (inode_ptr=%d -> inode=%d, ref_count=%d, size=%d, type=dir)\n",
|
||||||
recs[k].fname, recs[k].inode_no, read_inode_ptr(recs[k].inode_no),
|
recs[k].fname, recs[k].inode_no, read_inode_ptr(recs[k].inode_no),
|
||||||
f_inode.ref_count, f_inode.size);
|
f_inode.ref_count, f_inode.size);
|
||||||
} else {
|
} else if (f_inode.ftype == SYMLINK) {
|
||||||
pr_stdout("%s (inode_ptr=%d -> inode=%d, ref_count=%d, size=%d, type=reg)\n",
|
char l_path[FS_MAX_PATH_LEN+1];
|
||||||
|
int l_path_len = read_symlink(recs[k].inode_no, l_path);
|
||||||
|
|
||||||
|
if (l_path_len > 0)
|
||||||
|
pr_stdout(COLOR_CYAN "%s" COLOR_RESET
|
||||||
|
" (inode_ptr=%d -> inode=%d, ref_count=%d, size=%d, type=lnk, -> '%s')\n",
|
||||||
|
recs[k].fname, recs[k].inode_no, read_inode_ptr(recs[k].inode_no),
|
||||||
|
f_inode.ref_count, f_inode.size, l_path);
|
||||||
|
else
|
||||||
|
pr_stdout(COLOR_RED "%s" COLOR_RESET
|
||||||
|
" (inode_ptr=%d -> inode=%d, ref_count=%d, size=%d, type=lnk)\n",
|
||||||
recs[k].fname, recs[k].inode_no, read_inode_ptr(recs[k].inode_no),
|
recs[k].fname, recs[k].inode_no, read_inode_ptr(recs[k].inode_no),
|
||||||
f_inode.ref_count, f_inode.size);
|
f_inode.ref_count, f_inode.size);
|
||||||
}
|
}
|
||||||
@@ -2134,13 +2475,27 @@ int fs_la(void *d)
|
|||||||
struct fs_inode f_inode;
|
struct fs_inode f_inode;
|
||||||
read_block(read_inode_ptr(recs[k].inode_no), (void *) &f_inode);
|
read_block(read_inode_ptr(recs[k].inode_no), (void *) &f_inode);
|
||||||
|
|
||||||
if (f_inode.ftype == DIRECTORY) {
|
if (f_inode.ftype == REGULAR) {
|
||||||
|
pr_stdout("%s (inode_ptr=%d -> inode=%d, ref_count=%d, size=%d, type=reg)\n",
|
||||||
|
recs[k].fname, recs[k].inode_no, read_inode_ptr(recs[k].inode_no),
|
||||||
|
f_inode.ref_count, f_inode.size);
|
||||||
|
} else if (f_inode.ftype == DIRECTORY) {
|
||||||
pr_stdout(COLOR_BLUE "%s" COLOR_RESET
|
pr_stdout(COLOR_BLUE "%s" COLOR_RESET
|
||||||
" (inode_ptr=%d -> inode=%d, ref_count=%d, size=%d, type=dir)\n",
|
" (inode_ptr=%d -> inode=%d, ref_count=%d, size=%d, type=dir)\n",
|
||||||
recs[k].fname, recs[k].inode_no, read_inode_ptr(recs[k].inode_no),
|
recs[k].fname, recs[k].inode_no, read_inode_ptr(recs[k].inode_no),
|
||||||
f_inode.ref_count, f_inode.size);
|
f_inode.ref_count, f_inode.size);
|
||||||
} else {
|
} else if (f_inode.ftype == SYMLINK) {
|
||||||
pr_stdout("%s (inode_ptr=%d -> inode=%d, ref_count=%d, size=%d, type=reg)\n",
|
char l_path[FS_MAX_PATH_LEN+1];
|
||||||
|
int l_path_len = read_symlink(recs[k].inode_no, l_path);
|
||||||
|
|
||||||
|
if (l_path_len > 0)
|
||||||
|
pr_stdout(COLOR_CYAN "%s" COLOR_RESET
|
||||||
|
" (inode_ptr=%d -> inode=%d, ref_count=%d, size=%d, type=lnk, -> '%s')\n",
|
||||||
|
recs[k].fname, recs[k].inode_no, read_inode_ptr(recs[k].inode_no),
|
||||||
|
f_inode.ref_count, f_inode.size, l_path);
|
||||||
|
else
|
||||||
|
pr_stdout(COLOR_RED "%s" COLOR_RESET
|
||||||
|
" (inode_ptr=%d -> inode=%d, ref_count=%d, size=%d, type=lnk)\n",
|
||||||
recs[k].fname, recs[k].inode_no, read_inode_ptr(recs[k].inode_no),
|
recs[k].fname, recs[k].inode_no, read_inode_ptr(recs[k].inode_no),
|
||||||
f_inode.ref_count, f_inode.size);
|
f_inode.ref_count, f_inode.size);
|
||||||
}
|
}
|
||||||
@@ -2166,13 +2521,23 @@ int fs_stat(void *d)
|
|||||||
struct fs_inode i;
|
struct fs_inode i;
|
||||||
read_block(read_inode_ptr(rp.target_inode_ptr), &i);
|
read_block(read_inode_ptr(rp.target_inode_ptr), &i);
|
||||||
|
|
||||||
if (i.ftype == DIRECTORY) {
|
if (i.ftype == REGULAR) {
|
||||||
pr_stdout("inode_ptr=%d -> inode=%d\nref_count=%d\nsize=%d\ntype=dir\n",
|
pr_stdout("inode_ptr=%d -> inode=%d\nref_count=%d\nsize=%d\ntype=regular\n",
|
||||||
rp.target_inode_ptr, read_inode_ptr(rp.target_inode_ptr), i.ref_count, i.size);
|
rp.target_inode_ptr, read_inode_ptr(rp.target_inode_ptr), i.ref_count, i.size);
|
||||||
|
} else if (i.ftype == DIRECTORY) {
|
||||||
|
pr_stdout("inode_ptr=%d -> inode=%d\nref_count=%d\nsize=%d\ntype=directory\n",
|
||||||
|
rp.target_inode_ptr, read_inode_ptr(rp.target_inode_ptr), i.ref_count, i.size);
|
||||||
|
} else if (i.ftype == SYMLINK) {
|
||||||
|
char l_path[FS_MAX_PATH_LEN+1];
|
||||||
|
int l_path_len = read_symlink(rp.target_inode_ptr, l_path);
|
||||||
|
if (l_path_len > 0) {
|
||||||
|
pr_stdout("inode_ptr=%d -> inode=%d\nref_count=%d\nsize=%d\ntype=symlink\npoints to: %s\n",
|
||||||
|
rp.target_inode_ptr, read_inode_ptr(rp.target_inode_ptr), i.ref_count, i.size, l_path);
|
||||||
} else {
|
} else {
|
||||||
pr_stdout("inode_ptr=%d -> inode=%d\nref_count=%d\nsize=%d\ntype=reg\n",
|
pr_stdout("inode_ptr=%d -> inode=%d\nref_count=%d\nsize=%d\ntype=symlink\n<broken>\n",
|
||||||
rp.target_inode_ptr, read_inode_ptr(rp.target_inode_ptr), i.ref_count, i.size);
|
rp.target_inode_ptr, read_inode_ptr(rp.target_inode_ptr), i.ref_count, i.size);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
55
testing_script.t
Normal file
55
testing_script.t
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
use disk1
|
||||||
|
mkfs 32
|
||||||
|
|
||||||
|
mkdir test1
|
||||||
|
mkdir test2
|
||||||
|
la
|
||||||
|
|
||||||
|
cd test1
|
||||||
|
la
|
||||||
|
|
||||||
|
create hello1
|
||||||
|
mkdir inside
|
||||||
|
symlink ../../test2/ inside/hello3
|
||||||
|
stat inside/hello3
|
||||||
|
|
||||||
|
cd ../test2
|
||||||
|
la
|
||||||
|
|
||||||
|
symlink ../test1/inside hello2
|
||||||
|
stat hello2
|
||||||
|
|
||||||
|
cd /
|
||||||
|
cd test1/../test2/hello2/../../test2/.././././test1/inside/hello3/./hello2/.
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
create inside/././hello3/.././test1/f7
|
||||||
|
symlink /test1/f7 ../f1
|
||||||
|
la
|
||||||
|
cd ..
|
||||||
|
la
|
||||||
|
cd test1
|
||||||
|
open ../test2/hello2/../../f1
|
||||||
|
write 0 data
|
||||||
|
la
|
||||||
|
close 0
|
||||||
|
|
||||||
|
cd /
|
||||||
|
rm test1
|
||||||
|
rmdir test1
|
||||||
|
rm test1/inside/hello3
|
||||||
|
rmdir test1/inside
|
||||||
|
rm test1/hello1
|
||||||
|
rm test1/f7
|
||||||
|
rmdir test1
|
||||||
|
|
||||||
|
cd test2
|
||||||
|
la
|
||||||
|
cd hello2
|
||||||
|
|
||||||
|
symlink garbage/ttttt ..
|
||||||
|
cd ..
|
||||||
|
la
|
||||||
|
|
||||||
|
cd ttttt
|
||||||
|
rm ttttt
|
||||||
Reference in New Issue
Block a user