File Systems A Semester Project-II, Part-19

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 http://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.

  • Jeff

    Where is part 18, the beginning of the semester project? I can not find any links to it.

    • anil_pugalia

      Seems like it is not yet uploaded.

      • vk

        Could you please upload part 18 and 20, that is project-I and project-III ?
        Thanks

        • anil_pugalia

          It is not under my control – managed by LFY folks.

  • Machindra

    This is very good link to know about linux file system ..

    http://roundoverlinux.blogspot.com/2012/09/file-system-in-linux.html

    • http://twitter.com/anil_pugalia Anil Pugalia

      Thanks for sharing it.

  • suresh

    We are waiting for Linux device driver article 18

    • http://twitter.com/anil_pugalia Anil Pugalia

      Seems like it is not going to be uploaded. You may start following my blog @ http://sysplay.in/blog/linux-device-drivers/ But there also it will take a while till I get my 18th article, as I have started uploading there from the first one.

  • Gokum

    can you please provide some more information for practice~like references

  • Gautham

    sir, can you please provide steps to simulate this and how to use SIMULA_DEFAULT_FILE ?

  • Ahmed

    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

  • anil_pugalia

    Finally!!! I have been able to put up the “File Systems: A Semester Project – Part I”, the Part 18 of this article series, on my blog. Check it out at http://sysplay.in/blog/linux-device-drivers/2014/07/file-systems-the-semester-project/

    This is the article preceding the above one. Thanks to all of my article readers for having patience waiting for this.

  • Pramod Krishna

    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

    • anil_pugalia

      Frankly speaking, not even clear with your problem. As to why in first place, you are doing a trial & error of changing the lseek value.

      • Pramod Krishna

        Unable to see the file created by using list command. so to find the actual problem i did some trails.

        • anil_pugalia

          Rather print the return value of lseek in sfs_list() function – that would tell you the offset from which it is listing the values.

          • Pramod Krishna

            Thanks for reply

            In sfs_create function, for lseek added the cast to off_t as below.
            lseek(sfs_handle, -(off_t)sb.entry_size, SEEK_CUR);

            lseek expects singed integer(off_t) as offset.
            sb.entry_size is unsigned int abnormal behavior is observed
            when we pass it as -ve value

            After cast its working as expected. Please correct my understanding.

          • anil_pugalia

            Yes, you are correct. I guess, your system is a 64-bit system, and off_t is long which is 64-bit on your system. This brings out the bug in the code. I tested it on a 32-bit system, where off_t is also 32-bit, thus hiding the bug. I’ll fix the same, when I upload it on my SysPlay blog at http://sysplay.in/blog/linux-device-drivers

          • Pramod Krishna

            Yes, Its 64-bit system.

            Thanks a lot anil

All published articles are released under Creative Commons Attribution-NonCommercial 3.0 Unported License, unless otherwise noted.
Open Source For You is powered by WordPress, which gladly sits on top of a CentOS-based LEMP stack.

Creative Commons License.