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 Shwetas first-cut browser application, for precisely that purpose. Lets 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 doesnt 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.
Where is part 18, the beginning of the semester project? I can not find any links to it.
Seems like it is not yet uploaded.
Could you please upload part 18 and 20, that is project-I and project-III ?
Thanks
It is not under my control – managed by LFY folks.
This is very good link to know about linux file system ..
http://roundoverlinux.blogspot.com/2012/09/file-system-in-linux.html
Thanks for sharing it.
We are waiting for Linux device driver article 18
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.
can you please provide some more information for practice~like references
Actually, they are all part of the next set of articles. Meanwhile, you may try out the following: https://github.com/anil-pugalia/Default-FS
sir, can you please provide steps to simulate this and how to use SIMULA_DEFAULT_FILE ?
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
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.
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
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.
Unable to see the file created by using list command. so to find the actual problem i did some trails.
Rather print the return value of lseek in sfs_list() function – that would tell you the offset from which it is listing the values.
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.
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
Yes, Its 64-bit system.
Thanks a lot anil
Finally, the bug has been fixed in the latest version of this article (http://sysplay.in/blog/linux-device-drivers/2014/08/file-systems-the-semester-project-part-ii/) on my SysPlay blog. In fact, there is a similar bug in the sfs_remove() as well. Both of them have been fixed there.
And here is the next article – “File Systems: A Semester
Project – Part III”, the Part 20 of this article series, on my blog @ SysPlay. Check
it out at http://sysplay.in/blog/linux-device-drivers/2014/09/file-systems-the-semester-project-part-iii/
This is the article following the above one. Thanks to all of my article readers for having patience waiting for this.
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.