I’m trying to understand how FAT file systems work from a higher (more logical) level. A FAT file system has a file allocation table, with 1 entry for each available allocation unit (cluster) in the disk. This data structure is used to map a file with the address of the first cluster in which the file appears on the disk (a file almost certainly occupies more than 1 cluster, and these clusters are connected together in a linked-list style). So far so good. But what is the key in the file allocation table? Is the file name with full path?
For instance, let’s say that I need to access file C:\folder1\myFile.txt, the I/O manager searches the file name (including the path) in the file allocation table until it finds an entry, and if so, it returns the address of the first cluster. Is that how it works?
I read a lot of documentation online about this topic, but somehow the access to the file allocation table is still fuzzy for me. Thank you in advance for your help.
[EDIT]
The more I read on line, the more confused I am. I'm going to try with this simple example, hopefully it will clarify my question.
Let's say I have only 2 files in my C drive:
C:\myFile.txt
C:\folder1\myFile.txt
The file allocation table (in a very abstract way) would have 3 entries:
| Filename | Extension | First Cluster |
|----------|-----------|---------------|
1 | MYFILE | TXT | 150 |
2 | FOLDER1 | | 300 |
3 | MYFILE | TXT | 900 |
Assuming I'm correct so far, let's say that I want to access myFile.txt in C:\folder1: I cannot use the file name (MYFILE.TXT) itself as my key, because I have 2 entries with the same name (I wouldn't know which entry to pick).
At this point I guess I have to start from the folder, so I scan the FAT to find FOLDER1: I get entry #2 (cluster 300). What's next? How I would I keep scanning the table to find the directory entry that I need for "MYFILE.TXT", so that I can access the hard drive at specified cluster?
Maybe I'm looking at this from the wrong perspective, I don't know.
Thanks everyone for your help.
Take a look at this code, It is a somehow dir command which print all the names of directories and file in a root directory from disk D:\
#include<dos.h>
#include<stdio.h>
#include<iostream.h>
struct Boot {
char ignore1[11];
int Byte_Per_Sector;
char Serctors_Per_Cluster;
int Number_Of_Reserved_sectors;
char Number_of_FATS;
int Maximum_Number_of_root_dir;
int Total_Sector_count;
char Ignore2;
int Sectors_per_fat;
int Sectors_per_trach;
int Number_of_heads;
char ignore3[4];
char Total_sector_count_for_fat[4];
int ignore4;
char boot_signature;
char Volume_id[4];
char Volume_lable[11];
char File_system_type[8];
char Rest_of_boot_sector[450];
};
struct FCB {
char file_name[8];
char extension[3];
char attribute;
int reserved;
int creation_time;
int creation_date;
int last_access_date;
int ignore_in_fat;
int last_write_time;
int last_write_date;
int first_logic_cluster;
char file_size[4];
};
void main(){
FCB root[16]; //to read all the Root directory
if(absread(3,1,217,&root) ==0) { // start read from disk number 3 , 1 sector and the first sector number is 217 (from the hard disk)
cout<<"Read of Root Directory started:"<<endl;
for(int j=1;j<15;j++){
if(root[j].file_name[0]==0x00){//0x00 represents Unused file
break;
}
if(root[j].attribute!=0x0F) //0x0f mean this directory entry is part of a long file name
if(root[j].file_name[0]!='?')
for(int i=0;i<7;i++){
printf("%c",root[j].file_name[i]); // print the name of all files and directories
}
cout<<endl<<root[j].first_logic_cluster; to locate where is the first cluster contains the data on HD
cout<<endl;
}
cout<<"end of dirs in this cluster"<<endl;
}
else {
cout<<"error"<<endl;
}
cout<<"===================="<<endl;
char buffer[512];
//here to read what a file contains after calculating the physical address of that file
if(absread(3,1,283,&buffer) ==0) {
for(int i=0;i<512;i++ ){
cout<<buffer[i];
}
}
}
Things to notice
1-The first struct is the most important thing in FAT because allinformation is stored here
2- FCB contains information about files and directories in root directory
3- This code can be run on Windows 3.11 and (Turbo c++) is the program to code and compile
4- the code represent FAT12 and Integer is 2 bytes
If you have any questions i hope i can help you
Related
I have a data file with a known key, that is, it has many entries (devices) with the same properties and I have this structure in code to capture it.
struct deviceData{
int id;
char serial[10];
float temperature;
float speed;
long timestamp;
}
struct deviceData fileItems;
It's 4 bytes for the ID, 10 bytes for the serial code, 4 bytes for both the temperature and speed and 8 bytes for the timestamp. 30 bytes in total.
What I would like to achieve is to be able to read all those entries and run a calculation in the quickest way I can.
What I initially thought of doing was to simply create a giant array to capture all the entries but that causes errors.
Secondly I thought of allocating space from a pointer to that structure and reading the whole file to that. That worked in execution but I had trouble processing the data. Possibly a gap in fundamentals on my part.
The way I'm currently looking at is to loop through readings where I capture a single entry using fread(), process that and then move the file to put the next entry into the buffer.
Something like this:
fread(&fileItems, 30, 1, filename)
What happens though is that when I view what actually gets read I see that the ID and the serial code were read correctly but the following data points are garbage. Reading a little bit about it I came across something about padding which I don't fully understand but the fix seems to be to make my char array 100 which seems to work for the first entry but I suspect it's causing problems with subsequent readings because it's throwing my calculations off.
I'm kind of at a wall here because every strategy I try seems to have something that works strangely. If I could at least be pointed in the right direction I'll at least know I'm putting effort in the right thing.
If you are just wanting to process a group of data record by record, you probably can utilize the methodology of defining a structure, then reading the data from a file into the structure, and then processing the data. To make things consistent, it would make sense to store the data as a structure in a binary file. Following is a code snippet creating some sample data and then processing it following the spirit of your project.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct deviceData{
int id;
char serial[10];
float temperature;
float speed;
long timestamp;
};
struct deviceData fileItems;
void create_data(char * file_name)
{
FILE* fp = fopen(file_name, "wb");
if(!fp)
{
printf("\n\tFile open error\n");
return;
}
for (int i = 0; i < 10; i++)
{
fileItems.id = i + 20000 + i * 3;
sprintf(fileItems.serial, "SN%d", fileItems.id);
fileItems.temperature = 166.0 + i;
fileItems.speed = 2400.0;
fileItems.timestamp = 20220830;
fwrite(&fileItems, sizeof(struct deviceData), 1, fp);
}
fclose(fp);
}
void read_data(char *file_name)
{
FILE* fp = fopen(file_name, "rb");
if(!fp)
{
printf("\n\tFile open error\n");
return;
}
while(fread(&fileItems, sizeof(struct deviceData), 1, fp))
{
printf("ID. . . . . . .: %d\n", fileItems.id);
printf("Serial number. .: %s\n", fileItems.serial);
printf("Temparature. . .: %f\n", fileItems.temperature);
printf("Speed. . . . . .: %f\n", fileItems.speed);
printf("Timestamp. . . .: %ld\n", fileItems.timestamp);
}
}
int main()
{
create_data("device.dat"); /* Create some sample data to be read */
read_data("device.dat"); /* Read and print the data to the terminal */
return 0;
}
The storage of device data probably would occur in some other monitor program, but for this snippet a one-off function was included to produce some data to process.
Analyze that code and see if it meets the spirit of your project.
I am working my way through an SD card application code example provided by TI for their MSP530 LaunchPad microcontroller development kit. It appears that the example restricts the number of directories and number of files to 10 each (a total of 100 files) which seems overly restrictive for a 32GB SD card. The current code compiles to use less than half of the program space and less than half of available RAM. I am wondering if I misunderstand the code, or if the code is limited by some other reason, such as the available stack size in memory. Below is the code and my comments.
There are several layers: SDCardLogMode, sdcard (SDCardLib), and ff (HAL layer). I've reduced the code below to illustrate the constructions but not runnable - I am more interested if I understand it correctly and if my solution to increase the number of allowed files and directories is flawed.
SDCardLogMode.c there are two places of interest here. The first is the declaration of char dirs[10][MAX_DIR_LEN] and files[10][MAX_FILE_LEN]. the MAX LENs are 8 and 12 respectively and are the maximum allowed length of a name.
/*******************************************************************************
*
* SDCardLogMode.c
* ******************************************************************************/
#include "stdlib.h"
#include "string.h"
#include "SDCardLogMode.h"
#include "driverlib.h"
#include "sdcard.h"
#include "HAL_SDCard.h"
#pragma PERSISTENT(numLogFiles)
uint8_t numLogFiles = 0;
SDCardLib sdCardLib;
char dirs[10][MAX_DIR_LEN];
char files[10][MAX_FILE_LEN]; //10 file names. MAX_FILE_LEN =10
uint8_t dirNum = 0;
uint8_t fileNum = 0;
#define MAX_BUF_SIZE 32
char buffer[MAX_BUF_SIZE];
// FatFs Static Variables
static FIL fil; /* File object */
static char filename[31];
static FRESULT rc;
//....
Later in the same SDCardLogMode.c file is the following function (also reduced for readability). Here the interesting thing is that the code calls SDCardLib_getDirectory(&sdCardLib, "data_log", dirs, &dirNum, files, &fileNum) which consume the "data_log" path and produces dir, and updates &dirNum, files, and &fileNum. I do not believe &sdCardLib (which holds a handle to the FATFS and an interface pointer) is used in this function. At least not that I can tell.
What is puzzling is what's the point of calling SDCardLib_getDirectory() and then not using anything it produces? I did not find any downstream use of the dirs and files char arrays. Nor did I find any use of dirNum and fileNum either.
In the code snippets I show the code for SDCardLib_getDirectory(). I could not find where SDCardLib parameter is used. And as mentioned earlier, I found no use of files and dirs arrays. I can see where the file and directory count could be used to generate new names, but there are already static variables to hold the file count. Can anyone see a reason why the SDCard_getDirectory() was called?
/*
* Store TimeStamp from PC when logging starts to SDCard
*/
void storeTimeStampSDCard()
{
int i = 0;
uint16_t bw = 0;
unsigned long long epoch;
// FRESULT rc;
// Increment log file number
numLogFiles++;
,
//Detect SD card
SDCardLib_Status st = SDCardLib_detectCard(&sdCardLib);
if (st == SDCARDLIB_STATUS_NOT_PRESENT) {
SDCardLib_unInit(&sdCardLib);
mode = '0';
noSDCard = 1; //jn added
return;
}
// Read directory and file
rc = SDCardLib_getDirectory(&sdCardLib, "data_log", dirs, &dirNum, files, &fileNum);
//Create the directory under the root directory
rc = SDCardLib_createDirectory(&sdCardLib, "data_log");
if (rc != FR_OK && rc != FR_EXIST) {
SDCardLib_unInit(&sdCardLib);
mode = '0';
return;
}
//........
}
Now jumping to sdcard.c (SDCardLib layer) to look at SDCardLib_getDirectory() is interesting. It takes the array pointer assigns it to a one dimensional array (e.g. char (*fileList)[MAX_FILE_LEN] and indexes it each time it writes a filename). This code seem fragile since the SDCardLib_createDirectory() simply returns f_mkdir(directoryName), it does not check how many files already exist. Perhaps TI assumes this checking should be done at the application layer above SDCardLogMode....
void SDCardLib_unInit(SDCardLib * lib)
{
/* Unregister work area prior to discard it */
f_mount(0, NULL);
}
FRESULT SDCardLib_getDirectory(SDCardLib * lib,
char * directoryName,
char (*dirList)[MAX_DIR_LEN], uint8_t *dirNum,
char (*fileList)[MAX_FILE_LEN], uint8_t *fileNum)
{
FRESULT rc; /* Result code */
DIRS dir; /* Directory object */
FILINFO fno; /* File information object */
uint8_t dirCnt = 0; /* track current directory count */
uint8_t fileCnt = 0; /* track current directory count */
rc = f_opendir(&dir, directoryName);
for (;;)
{
rc = f_readdir(&dir, &fno); // Read a directory item
if (rc || !fno.fname[0]) break; // Error or end of dir
if (fno.fattrib & AM_DIR) //this is a directory
{
strcat(*dirList, fno.fname); //add this to our list of names
dirCnt++;
dirList++;
}
else //this is a file
{
strcat(*fileList, fno.fname); //add this to our list of names
fileCnt++;
fileList++;
}
}
*dirNum = dirCnt;
*fileNum = fileCnt;
return rc;
}
Below is SDCardLib_createDirectory(SDCardLib *lib, char *directoryName). It just creates a directory, it does not check on the existing number of files.
FRESULT SDCardLib_createDirectory(SDCardLib * lib, char * directoryName)
{
return f_mkdir(directoryName);
}
So coming back to my questions:
Did I understand this code correctly, does it really does limit the number of directories and files to 10 each?
If so, why would the number of files and directories be so limited? The particular MSP430 that this example code came with has 256KB of program space and 8KB of RAM. The compiled code consumes less than half of the available resources (68KB of program space and about 2.5KB of RAM). Is it because any larger would overflow the stack segment?
I want to increase the number of files that can be stored. If I look at the underlying FATFS code, it does not to impose a limit on the number of files or directories (at least not until the sd card is full). If I never intend to display or search the contents of a directory on the MSP430 my thought is to remove SDCard_getDirectory() and the two char arrays (files and dirs). Would there a reason why this would be a bad idea?
There are other microcontrollers with less memory.
The SDCardLib_getDirectory() function treats its dirList and fileList parameters as simple strings, i.e., it calls strcat() on the same pointers. This means that it can read as many names as fit into 10*8 or 10*12 bytes.
And calling strcat() without adding a delimiter means that it is impossible to get the individual names out of the string.
This codes demonstrates that it is possible to use the FatFs library, and in which order its functions need to be called, but it is not necessarily a good example of how to do that. I recommend that you write your own code.
I know that a hard drive are system's files (/dev/sdXX) –then treated like files-, I have questions about this:
I tried those following lines of code but nothing positive
-------first attempt----------
int numSecteur=2;
char secteur [512];
FILE* disqueF=fopen("/dev/sda","r"); //tried "rb" and sda1 ...every thing
fseek(disqueF, numSecteur*512,SEEK_SET);
fread(secteur, 512, 1, disqueF);
fclose(disqueF);
-------Second attempt----------
int i=open("/dev/sda1",O_RDONLY);
lseek(i, 0, SEEK_SET);
read(i,secteur,512);
close(i);
------printing the results----------
printf("hex : %04x\n",secteur);
printf("string : %s\n",secteur);
Why the size is of the file /dev/sda1 is just 8 KBytes ?
How the data is stored (binary or hex….) "for the printing"
Please, I need some clues, and if someone need more details just he ask.
Thanks a lot.
Ps: Running kali 2 64bits ”debian” on VMware and i am RooT.
I tried those following lines of code but nothing positive
That's not a question.
Why the size is of the file /dev/sda1 is just 8 KBytes ?
That isn't the file size, it's the device number. (There are two parts, so the device number of sda1 is 8,1)
How the data is stored (binary or hex….) "for the printing"
Data isn't "stored for the printing". Data is stored (in electrical voltages representing binary, but you don't need to know that), and you can print it any way you want.
You cannot printf() array of chat like that, you need right print result. For example as hex dump:
for (int i = 0; i < sizeof(secteur); i++) {
printf ("%02x ", secteur[i]);
if ((i + 1) % 16 == 0)
printf ("\n");
}
I'm working in C on 64-bit Ubuntu 14.04.
I have a number of .txt files, each containing lines of floating point values (1 value per line). The lines represent parts of a complex sample, and they're stored as real(a1) \n imag(a1) \n real(a2) \n imag(a2), if that makes sense.
In a specific scenario there are 4 text files each containing 32768 samples (thus 65536 values), but I need to make the final version dynamic to accommodate up to 32 files (the maximum samples per file would not exceed 32768 though). I'll only be reading the first 19800 samples (depending on other things) though, since the entire signal is contained in those 39600 points (19800 samples).
A common abstraction is to represent the files / samples as a matrix, where columns represent return signals and rows represent the value of each signal at a sampling instant, up until the maximum duration.
What I'm trying to do is take the first sample from each return signal and move it into an array of double-precision floating point values to do some work on, move on to the second sample for each signal (which will overwrite the previous array) and do some work on them, and so forth, until the last row of samples have been processed.
Is there a way in which I can dynamically open files for each signal (depending on the number of pulses I'm using in that particular instance), read the first sample from each file into a buffer and ship that off to be processed. On the next iteration, the file pointers will all be aligned to the second sample, it would then move those into an array and ship it off again, until the desired amount of samples (19800 in our hypothetical case) has been reached.
I can read samples just fine from the files using fscanf:
rx_length = 19800;
int x;
float buf;
double *range_samples = calloc(num_pulses, 2 * sizeof(range_samples));
for (i=0; i < 2 * rx_length; i++){
x = fscanf(pulse_file, "%f", &buf);
*(range_samples) = buf;
}
All that needs to happen (in my mind) is that I need to cycle both sample# and pulse# (in that order), so when finished with one pulse it would move on to the next set of samples for the next pulse, and so forth. What I don't know how to do is to somehow declare file pointers for all return signal files, when the number of them can vary inbetween calls (e.g. do the whole thing for 4 pulses, and on the next call it can be 16 or 64).
If there are any ideas / comments / suggestions I would love to hear them.
Thanks.
I would make the code you posted a function that takes an array of file names as an argument:
void doPulse( const char **file_names, const int size )
{
FILE *file = 0;
// declare your other variables
for ( int i = 0; i < size; ++i )
{
file = fopen( file_names[i] );
// make sure file is open
// do the work on that file
fclose( file );
file = 0;
}
}
What you need is a generator. It would be reasonably easy in C++, but as you tagged C, I can imagine a function, taking a custom struct (the state of the object) as parameter. It could be something like (pseudo code) :
struct GtorState {
char *files[];
int filesIndex;
FILE *currentFile;
};
void gtorInit(GtorState *state, char **files) {
// loads the array of file into state, set index to 0, and open first file
}
int nextValue(GtorState *state, double *real, double *imag) {
// read 2 values from currentFile and affect them to real and imag
// if eof, close currentFile and open files[++currentIndex]
// if real and imag were found returns 0, else 1 if eof on last file, 2 if error
}
Then you main program could contain :
GtorState state;
// initialize the list of files to process
gtorInit(&state, files);
double real, imag);
int cr;
while (0 == (cr = nextValue(&state, &real, &imag)) {
// process (real, imag)
}
if (cr == 2) {
// process (at least display) error
}
Alternatively, your main program could iterate the values of the different files and call a function with state analog of the above generator that processes the values, and at the end uses the state of the processing function to get the results.
Tried a slightly different approach and it's working really well.
In stead of reading from the different files each time I want to do something, I read the entire contents of each file into a 2D array range_phase_data[sample_number][pulse_number], and then access different parts of the array depending on which range bin I'm currently working on.
Here's an excerpt:
#define REAL(z,i) ((z)[2*(i)])
#define IMAG(z,i) ((z)[2*(i)+1])
for (i=0; i<rx_length; i++){
printf("\t[%s] Range bin %i. Samples %i to %i.\n", __FUNCTION__, i, 2*i, 2*i+1);
for (j=0; j<num_pulses; j++){
REAL(fft_buf, j) = range_phase_data[2*i][j];
IMAG(fft_buf, j) = range_phase_data[2*i+1][j];
}
printf("\t[%s] Range bin %i done, ready to FFT.\n", __FUNCTION__, i);
// do stuff with the data
}
This alleviates the need to dynamically allocate file pointers and in stead just opens the files one at a time and writes the data to the corresponding column in the matrix.
Cheers.
I have two files, file1.txt and file2.txt:
file1.txt:
1234:James Smith:100:110
1111:Steve Jones:150:130
4321:Bob Wilson:110:140
file2.txt
100;Area 1;0.00
110;Area 2;3.00
120;Area 3;4.75
130;Area 4;5.95
140;Area 5;10.00
150;Area 6;12.00
What I would like to do is read file1.txt line by line and record some of the information to a file3.txt (output file) such as field 1 (number) and field 2 (name). To test that I could retrieve these, I used:
while (fscanf(file1, "%[^:]:%[^:]:%d:%d", number, name, &on, &off) == 4)
{
printf("Name contains: %s", name);
}
As expected, this retrieved all of the "name" (field 2) values and displayed them on screen.
I would now like to use the data stored in "on" and "off" to retrieve additional information from file2.txt. As you can see above, file1.txt fields 3 and 4 match up with field 1 in file2.txt. What I'm looking at getting in the final output file is:
1234 James Smith Area 1 to Area 2 3.00
1111 Steve Jones Area 6 to Area 4 6.05
4321 Bob Wilson Area 2 to Area 5 7.00
I'm not sure how to accomplish reading file1.txt line by line and performing the "check" with file2.txt at the same time and outputting. I also require a simple subtraction calculation in there as well.
Any help would be greatly appreciated. I don't have much experience with fscanf, fgets, reading files, etc.
This is an example of the struct definitions required-:
#define MAX_LINES 1000
struct rec1
{
int n;
char name[30];
int area1;
int area2;
};
struct rec1 rec1_list[MAX_LINES];
struct rec2
{
int area;
char desc[20];
int rating;
};
struct rec2 rec2_list[MAX_LINES];