File Systems A Semester Project-II, Part-19

23
10231

This article, which is part of the series on Linux device drivers, elaborates on the concept of a file system by simulating one in user space.

In the previous article, Shweta readied the partition on the .sfsf file by formatting it with the format_sfs application. To completely understand a file system, the next step in its simulation is to browse and play around with the file system created. Here is Shweta’s first-cut browser application, for precisely that purpose. Let’s have a closer look. sfs_ds.h is the header file already created by Shweta.

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <time.h>

#include “sfs_ds.h”

sfs_super_block_t sb;

void sfs_list(int sfs_handle)
{
int i;
sfs_file_entry_t fe;

lseek(sfs_handle, sb.entry_table_block_start * sb.block_size, SEEK_SET);
for (i = 0; i < sb.entry_count; i++)
{
read(sfs_handle, &fe, sizeof(sfs_file_entry_t));
if (!fe.name[0]) continue;
printf(“%-15s  %10d bytes  %c%c%c  %s”,
fe.name, fe.size,
fe.perms & 04 ? ‘r’ : ‘-’,
fe.perms & 02 ? ‘w’ : ‘-’,
fe.perms & 01 ? ‘x’ : ‘-’,
ctime((time_t *)&fe.timestamp)
);
}
}
void sfs_create(int sfs_handle, char *fn)
{
int i;
sfs_file_entry_t fe;

lseek(sfs_handle, sb.entry_table_block_start * sb.block_size, SEEK_SET);
for (i = 0; i < sb.entry_count; i++)
{
read(sfs_handle, &fe, sizeof(sfs_file_entry_t));
if (!fe.name[0]) break;
if (strcmp(fe.name, fn) == 0)
{
printf(“File %s already exists\n”, fn);
return;
}
}
if (i == sb.entry_count)
{
printf(“No entries left\n”, fn);
return;
}

lseek(sfs_handle, -sb.entry_size, SEEK_CUR);

strncpy(fe.name, fn, 15);
fe.name[15] = 0;
fe.size = 0;
fe.timestamp = time(NULL);
fe.perms = 07;
for (i = 0; i < SIMULA_FS_DATA_BLOCK_CNT; i++)
{
fe.blocks[i] = 0;
}
write(sfs_handle, &fe, sizeof(sfs_file_entry_t));
}
void sfs_remove(int sfs_handle, char *fn)
{
int i;
sfs_file_entry_t fe;

lseek(sfs_handle, sb.entry_table_block_start * sb.block_size, SEEK_SET);
for (i = 0; i < sb.entry_count; i++)
{
read(sfs_handle, &fe, sizeof(sfs_file_entry_t));
if (!fe.name[0]) continue;
if (strcmp(fe.name, fn) == 0) break;
}
if (i == sb.entry_count)
{
printf(“File %s doesn’t exist\n”, fn);
return;
}

lseek(sfs_handle, -sb.entry_size, SEEK_CUR);

memset(&fe, 0, sizeof(sfs_file_entry_t));
write(sfs_handle, &fe, sizeof(sfs_file_entry_t));
}

void browse_sfs(int sfs_handle)
{
int done;
char cmd[256], *fn;
int ret;

done = 0;

printf(“Welcome to SFS Browsing Shell v1.0\n\n”);
printf(“Block size     : %d bytes\n”, sb.block_size);
printf(“Partition size : %d blocks\n”, sb.partition_size);
printf(“File entry size: %d bytes\n”, sb.entry_size);
printf(“Entry tbl size : %d blocks\n”, sb.entry_table_size);
printf(“Entry count    : %d\n”, sb.entry_count);
printf(“\n”);
while (!done)
{
printf(“ $> “);
ret = scanf(“%[^\n]”, cmd);
if (ret < 0)
{
done = 1;
printf(“\n”);
continue;
}
else
{
getchar();
if (ret == 0) continue;
}
if (strcmp(cmd, “?”) == 0)
{
printf(“Supported commands:\n”);
printf(“\t?\tquit\tlist\tcreate\tremove\n”);
continue;
}
else if (strcmp(cmd, “quit”) == 0)
{
done = 1;
continue;
}
else if (strcmp(cmd, “list”) == 0)
{
sfs_list(sfs_handle);
continue;
}
else if (strncmp(cmd, “create”, 6) == 0)
{
if (cmd[6] == ‘ ‘)
{
fn = cmd + 7;
while (*fn == ‘ ‘) fn++;
if (*fn != ‘\0’)
{
sfs_create(sfs_handle, fn);
continue;
}
}
}
else if (strncmp(cmd, “remove”, 6) == 0)
{
if (cmd[6] == ‘ ‘)
{
fn = cmd + 7;
while (*fn == ‘ ‘) fn++;
if (*fn != ‘\0’)
{
sfs_remove(sfs_handle, fn);
continue;
}
}
}
printf(“Unknown/Incorrect command: %s\n”, cmd);
printf(“Supported commands:\n”);
printf(“\t?\tquit\tlist\tcreate <file>\tremove <file>\n”);
}
}

int main(int argc, char *argv[])
{
char *sfs_file = SIMULA_DEFAULT_FILE;
int sfs_handle;

if (argc > 2)
{
fprintf(stderr, “Incorrect invocation. Possibilities are:\n”);
fprintf(stderr, “\t%s /* Picks up %s as the default partition_file */\n”,
argv[0], SIMULA_DEFAULT_FILE);
fprintf(stderr, “\t%s [ partition_file ]\n”, argv[0]);
return 1;
}
if (argc == 2)
{
sfs_file = argv[1];
}
sfs_handle = open(sfs_file, O_RDWR);
if (sfs_handle == -1)
{
fprintf(stderr, “Unable to browse SFS over %s\n”, sfs_file);
return 2;
}
read(sfs_handle, &sb, sizeof(sfs_super_block_t));
if (sb.type != SIMULA_FS_TYPE)
{
fprintf(stderr, “Invalid SFS detected. Giving up.\n”);
close(sfs_handle);
return 3;
}
browse_sfs(sfs_handle);
close(sfs_handle);
return 0;
}
Note: The sample code from this article is available at https://www.opensourceforu.com/article_source_code/june12/device-part19.zip. Download and experiment with it.

The above (shell like) program primarily reads the super block from the partition file (.sfsf by default, or the file provided from command line), and then gets into browsing the file system based on that information, using the browse_sfs() function. Note the check performed for the valid file system on the partition file using the magic number SIMULA_FS_TYPE.
browse_sfs() prints the file system information and provides four basic file system functionalities using the following commands:
quit – to quit the file system browser
list – to list the current files in the file system (using sfs_list())
create <filename> – to create a new file in the file system (using sfs_create(filename))
remove <filename> – to remove an existing file from the file system (using sfs_remove(filename))
Figure 1 shows the browser in action, using the above commands.
sfs_list() traverses through all the file entries in the partition and prints all the non-null filename entries – with file name, size, permissions, and its creation time stamp. sfs_create() looks up for an available (null filename) entry and then updates it with the given filename, size of 0 bytes, permissions of ‘rwx’, and the current time stamp. And sfs_remove() looks up for an existing file entry with the filename to be removed, and then nullifies it. The other parts in the above code are more of basic error handling cases like invalid commands in browse_sfs(), existing file name in sfs_create(), non-existing file name in sfs_remove(), etc.
Note that the above application is the first-cut of a full-fledged application. So the files created right now come with just the basic fixed parameters and there is no way to change their permissions, content, etc, yet. However, adding these features is just a matter of adding commands and their corresponding functions; Shweta will provide these commands for a few more interesting features, once she works out the details of the browsing application.
Summing up
Once done with the other features as well, the next set of steps would take the project partners closer to their final goals. Watch out for who takes charge of the next step of moving the file system logic to the kernel space.

23 COMMENTS

  1. Hello Mr. Anil,

    Thnx for ur clear explanations & efforts. May I ask you to provide a tutorial demonstrates developing simple CAN, Bluetooth, or wireless driver …. & how to deal with board’s registers & use them for sending data, interrupts, receiving data, etc.

    Thanks in advance

  2. Hi Anil,

    Thanks a lot for sharing the article.

    I tried the code in article

    Problem:
    ————
    In ‘sfs_create’ function
    lseek(sfs_handle,-sb.entry_size, SEEK_CUR);
    will create a file with starting offset of 512(if it is first file).

    while using ‘sfs_list’ unable to print the file entry.
    Tried printing all the files in entry table didn’t find any file written.

    Changes/tries:
    ————–
    In ‘sfs_create’ function modified below line after max entries check:
    try-1: seek_offset= lseek(sfs_handle,0, SEEK_CUR);
    try-2 seek_offset= lseek(sfs_handle,sb.entry_size, SEEK_CUR);

    with try-1 it is creating first file at offset 576.
    with try-2 it is creating first file at offset 640.

    In above tries i am able to see the file created.
    if second file is created first is replacing

    Observations:
    ————-
    When create a first file is taking much time at lseek (as per my understanding write will happen to .sfsf file).delay is excepected or any issue.

    Thanks a lot for sharing

  3. If we have to add compression,encryption and also modifying a file facility to the above set of commands,then what would be the approach for it??Please help me out.

LEAVE A REPLY

Please enter your comment!
Please enter your name here