FAT support

Collaboration diagram for FAT support:

Files

file  fat.c
file  fat.h
file  fat_config.h

Modules

 FAT configuration
 FAT access
 FAT file functions
 FAT directory functions

Data Structures

struct  fat_dir_entry_struct

Defines

#define fat_delete_dir   fat_delete_file

Functions

struct fat_fs_structfat_open (struct partition_struct *partition)
void fat_close (struct fat_fs_struct *fs)
struct fat_file_structfat_open_file (struct fat_fs_struct *fs, const struct fat_dir_entry_struct *dir_entry)
void fat_close_file (struct fat_file_struct *fd)
intptr_t fat_read_file (struct fat_file_struct *fd, uint8_t *buffer, uintptr_t buffer_len)
intptr_t fat_write_file (struct fat_file_struct *fd, const uint8_t *buffer, uintptr_t buffer_len)
uint8_t fat_seek_file (struct fat_file_struct *fd, int32_t *offset, uint8_t whence)
uint8_t fat_resize_file (struct fat_file_struct *fd, uint32_t size)
struct fat_dir_structfat_open_dir (struct fat_fs_struct *fs, const struct fat_dir_entry_struct *dir_entry)
void fat_close_dir (struct fat_dir_struct *dd)
uint8_t fat_read_dir (struct fat_dir_struct *dd, struct fat_dir_entry_struct *dir_entry)
uint8_t fat_reset_dir (struct fat_dir_struct *dd)
uint8_t fat_create_file (struct fat_dir_struct *parent, const char *file, struct fat_dir_entry_struct *dir_entry)
uint8_t fat_delete_file (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry)
uint8_t fat_create_dir (struct fat_dir_struct *parent, const char *dir, struct fat_dir_entry_struct *dir_entry)
void fat_get_file_modification_date (const struct fat_dir_entry_struct *dir_entry, uint16_t *year, uint8_t *month, uint8_t *day)
void fat_get_file_modification_time (const struct fat_dir_entry_struct *dir_entry, uint8_t *hour, uint8_t *min, uint8_t *sec)
uint8_t fat_get_dir_entry_of_path (struct fat_fs_struct *fs, const char *path, struct fat_dir_entry_struct *dir_entry)
offset_t fat_get_fs_size (const struct fat_fs_struct *fs)
offset_t fat_get_fs_free (const struct fat_fs_struct *fs)
void get_datetime (uint16_t *year, uint8_t *month, uint8_t *day, uint8_t *hour, uint8_t *min, uint8_t *sec)

Detailed Description

This module implements FAT16/FAT32 read and write access.

The following features are supported:


Define Documentation

#define fat_delete_dir   fat_delete_file

Definition at line 110 of file fat.h.


Function Documentation

void fat_close ( struct fat_fs_struct fs  ) 

Closes a FAT filesystem.

When this function returns, the given filesystem descriptor will be invalid.

Parameters:
[in] fs The filesystem to close.
See also:
fat_open

Definition at line 291 of file fat.c.

References fat_fs_struct::partition.

Referenced by WaspSD::close().

00292 {
00293     if(!fs)
00294         return;
00295 
00296 #if USE_DYNAMIC_MEMORY
00297     free(fs);
00298 #else
00299     fs->partition = 0;
00300 #endif
00301 }

Here is the caller graph for this function:

void fat_close_dir ( struct fat_dir_struct dd  ) 

Closes a directory descriptor.

This function destroys a directory descriptor which was previously obtained by calling fat_open_dir(). When this function returns, the given descriptor will be invalid.

Parameters:
[in] dd The directory descriptor to close.
See also:
fat_open_dir

Definition at line 1418 of file fat.c.

References fat_dir_struct::fs.

Referenced by WaspSD::cd(), WaspSD::close(), and fat_get_dir_entry_of_path().

01419 {
01420     if(dd)
01421 #if USE_DYNAMIC_MEMORY
01422         free(dd);
01423 #else
01424         dd->fs = 0;
01425 #endif
01426 }

Here is the caller graph for this function:

void fat_close_file ( struct fat_file_struct fd  ) 

Closes a file.

Parameters:
[in] fd The file handle of the file to close.
See also:
fat_open_file

Definition at line 964 of file fat.c.

References fat_file_struct::dir_entry, fat_write_dir_entry(), and fat_file_struct::fs.

Referenced by WaspSD::cat(), WaspSD::catBin(), WaspSD::catln(), WaspSD::closeFile(), WaspSD::indexOf(), WaspSD::numln(), and WaspSD::writeSD().

00965 {
00966     if(fd)
00967     {
00968 #if FAT_DELAY_DIRENTRY_UPDATE
00969         /* write directory entry */
00970         fat_write_dir_entry(fd->fs, &fd->dir_entry);
00971 #endif
00972 
00973 #if USE_DYNAMIC_MEMORY
00974         free(fd);
00975 #else
00976         fd->fs = 0;
00977 #endif
00978     }
00979 }

Here is the call graph for this function:

Here is the caller graph for this function:

uint8_t fat_create_dir ( struct fat_dir_struct parent,
const char *  dir,
struct fat_dir_entry_struct dir_entry 
)

Creates a directory.

Creates a directory and obtains its directory entry. If the directory to create already exists, its directory entry will be returned within the dir_entry parameter.

Note:
The notes which apply to fat_create_file also apply to this function.
Parameters:
[in] parent The handle of the parent directory of the new directory.
[in] dir The name of the directory to create.
[out] dir_entry The directory entry to fill for the new directory.
Returns:
0 on failure, 1 on success.
See also:
fat_delete_dir

Definition at line 2170 of file fat.c.

References fat_dir_entry_struct::attributes, fat_dir_entry_struct::cluster, fat_header_struct::cluster_size, fat_header_struct::cluster_zero_offset, fat_dir_struct::dir_entry, fat_dir_entry_struct::entry_offset, fat_append_clusters(), FAT_ATTRIB_DIR, fat_clear_cluster(), fat_find_offset_for_dir_entry(), fat_free_clusters(), fat_read_dir(), fat_reset_dir(), fat_write_dir_entry(), fat_dir_struct::fs, fat_fs_struct::header, and fat_dir_entry_struct::long_name.

Referenced by WaspSD::mkdir().

02171 {
02172     if(!parent || !dir || !dir[0] || !dir_entry)
02173         return 0;
02174 
02175     /* check if the file or directory already exists */
02176     while(fat_read_dir(parent, dir_entry))
02177     {
02178         if(strcmp(dir, dir_entry->long_name) == 0)
02179         {
02180             fat_reset_dir(parent);
02181             return 0;
02182         }
02183     }
02184 
02185     struct fat_fs_struct* fs = parent->fs;
02186 
02187     /* allocate cluster which will hold directory entries */
02188     cluster_t dir_cluster = fat_append_clusters(fs, 0, 1);
02189     if(!dir_cluster)
02190         return 0;
02191 
02192     /* clear cluster to prevent bogus directory entries */
02193     fat_clear_cluster(fs, dir_cluster);
02194     
02195     memset(dir_entry, 0, sizeof(*dir_entry));
02196     dir_entry->attributes = FAT_ATTRIB_DIR;
02197 
02198     /* create "." directory self reference */
02199     dir_entry->entry_offset = fs->header.cluster_zero_offset +
02200                               (offset_t) (dir_cluster - 2) * fs->header.cluster_size;
02201     dir_entry->long_name[0] = '.';
02202     dir_entry->cluster = dir_cluster;
02203     if(!fat_write_dir_entry(fs, dir_entry))
02204     {
02205         fat_free_clusters(fs, dir_cluster);
02206         return 0;
02207     }
02208 
02209     /* create ".." parent directory reference */
02210     dir_entry->entry_offset += 32;
02211     dir_entry->long_name[1] = '.';
02212     dir_entry->cluster = parent->dir_entry.cluster;
02213     if(!fat_write_dir_entry(fs, dir_entry))
02214     {
02215         fat_free_clusters(fs, dir_cluster);
02216         return 0;
02217     }
02218 
02219     /* fill directory entry */
02220     strncpy(dir_entry->long_name, dir, sizeof(dir_entry->long_name) - 1);
02221     dir_entry->cluster = dir_cluster;
02222 
02223     /* find place where to store directory entry */
02224     if(!(dir_entry->entry_offset = fat_find_offset_for_dir_entry(fs, parent, dir_entry)))
02225     {
02226         fat_free_clusters(fs, dir_cluster);
02227         return 0;
02228     }
02229 
02230     /* write directory to disk */
02231     if(!fat_write_dir_entry(fs, dir_entry))
02232     {
02233         fat_free_clusters(fs, dir_cluster);
02234         return 0;
02235     }
02236 
02237     return 1;
02238 }

Here is the call graph for this function:

Here is the caller graph for this function:

uint8_t fat_create_file ( struct fat_dir_struct parent,
const char *  file,
struct fat_dir_entry_struct dir_entry 
)

Creates a file.

Creates a file and obtains the directory entry of the new file. If the file to create already exists, the directory entry of the existing file will be returned within the dir_entry parameter.

Note:
The file name is not checked for invalid characters.

The generation of the short 8.3 file name is quite simple. The first eight characters are used for the filename. The extension, if any, is made up of the first three characters following the last dot within the long filename. If the filename (without the extension) is longer than eight characters, the lower byte of the cluster number replaces the last two characters to avoid name clashes. In any other case, it is your responsibility to avoid name clashes.

Parameters:
[in] parent The handle of the directory in which to create the file.
[in] file The name of the file to create.
[out] dir_entry The directory entry to fill for the new file.
Returns:
0 on failure, 1 on success.
See also:
fat_delete_file

Definition at line 2055 of file fat.c.

References fat_dir_entry_struct::entry_offset, fat_find_offset_for_dir_entry(), fat_read_dir(), fat_reset_dir(), fat_write_dir_entry(), fat_dir_struct::fs, and fat_dir_entry_struct::long_name.

Referenced by WaspSD::create().

02056 {
02057     if(!parent || !file || !file[0] || !dir_entry)
02058         return 0;
02059 
02060     /* check if the file already exists */
02061     while(1)
02062     {
02063         if(!fat_read_dir(parent, dir_entry))
02064             break;
02065 
02066         if(strcmp(file, dir_entry->long_name) == 0)
02067         {
02068             fat_reset_dir(parent);
02069             return 0;
02070         }
02071     }
02072 
02073     struct fat_fs_struct* fs = parent->fs;
02074 
02075     /* prepare directory entry with values already known */
02076     memset(dir_entry, 0, sizeof(*dir_entry));
02077     strncpy(dir_entry->long_name, file, sizeof(dir_entry->long_name) - 1);
02078 
02079     /* find place where to store directory entry */
02080     if(!(dir_entry->entry_offset = fat_find_offset_for_dir_entry(fs, parent, dir_entry)))
02081         return 0;
02082     
02083     /* write directory entry to disk */
02084     if(!fat_write_dir_entry(fs, dir_entry))
02085         return 0;
02086     
02087     return 1;
02088 }

Here is the call graph for this function:

Here is the caller graph for this function:

uint8_t fat_delete_file ( struct fat_fs_struct fs,
struct fat_dir_entry_struct dir_entry 
)

Deletes a file or directory.

If a directory is deleted without first deleting its subdirectories and files, disk space occupied by these files will get wasted as there is no chance to release it and mark it as free.

Parameters:
[in] fs The filesystem on which to operate.
[in] dir_entry The directory entry of the file to delete.
Returns:
0 on failure, 1 on success.
See also:
fat_create_file

Definition at line 2106 of file fat.c.

References fat_dir_entry_struct::cluster, partition_struct::device_read, partition_struct::device_write, fat_dir_entry_struct::entry_offset, FAT_DIRENTRY_DELETED, fat_free_clusters(), and fat_fs_struct::partition.

Referenced by WaspSD::delDir(), and WaspSD::delFile().

02107 {
02108     if(!fs || !dir_entry)
02109         return 0;
02110 
02111     /* get offset of the file's directory entry */
02112     offset_t dir_entry_offset = dir_entry->entry_offset;
02113     if(!dir_entry_offset)
02114         return 0;
02115 
02116 #if FAT_LFN_SUPPORT
02117     uint8_t buffer[12];
02118     while(1)
02119     {
02120         /* read directory entry */
02121         if(!fs->partition->device_read(dir_entry_offset, buffer, sizeof(buffer)))
02122             return 0;
02123         
02124         /* mark the directory entry as deleted */
02125         buffer[0] = FAT_DIRENTRY_DELETED;
02126         
02127         /* write back entry */
02128         if(!fs->partition->device_write(dir_entry_offset, buffer, sizeof(buffer)))
02129             return 0;
02130 
02131         /* check if we deleted the whole entry */
02132         if(buffer[11] != 0x0f)
02133             break;
02134 
02135         dir_entry_offset += 32;
02136     }
02137 #else
02138     /* mark the directory entry as deleted */
02139     uint8_t first_char = FAT_DIRENTRY_DELETED;
02140     if(!fs->partition->device_write(dir_entry_offset, &first_char, 1))
02141         return 0;
02142 #endif
02143 
02144     /* We deleted the directory entry. The next thing to do is
02145      * marking all occupied clusters as free.
02146      */
02147     return (dir_entry->cluster == 0 || fat_free_clusters(fs, dir_entry->cluster));
02148 }

Here is the call graph for this function:

Here is the caller graph for this function:

uint8_t fat_get_dir_entry_of_path ( struct fat_fs_struct fs,
const char *  path,
struct fat_dir_entry_struct dir_entry 
)

Retrieves the directory entry of a path.

The given path may both describe a file or a directory.

Parameters:
[in] fs The FAT filesystem on which to search.
[in] path The path of which to read the directory entry.
[out] dir_entry The directory entry to fill.
Returns:
0 on failure, 1 on success.
See also:
fat_read_dir

Definition at line 850 of file fat.c.

References fat_dir_entry_struct::attributes, FAT_ATTRIB_DIR, fat_close_dir(), fat_open_dir(), fat_read_dir(), and fat_dir_entry_struct::long_name.

Referenced by WaspSD::init().

00851 {
00852     if(!fs || !path || path[0] == '\0' || !dir_entry)
00853         return 0;
00854 
00855     if(path[0] == '/')
00856         ++path;
00857 
00858     /* begin with the root directory */
00859     memset(dir_entry, 0, sizeof(*dir_entry));
00860     dir_entry->attributes = FAT_ATTRIB_DIR;
00861 
00862     while(1)
00863     {
00864         if(path[0] == '\0')
00865             return 1;
00866 
00867         struct fat_dir_struct* dd = fat_open_dir(fs, dir_entry);
00868         if(!dd)
00869             break;
00870 
00871         /* extract the next hierarchy we will search for */
00872         const char* sub_path = strchr(path, '/');
00873         uint8_t length_to_sep;
00874         if(sub_path)
00875         {
00876             length_to_sep = sub_path - path;
00877             ++sub_path;
00878         }
00879         else
00880         {
00881             length_to_sep = strlen(path);
00882             sub_path = path + length_to_sep;
00883         }
00884         
00885         /* read directory entries */
00886         while(fat_read_dir(dd, dir_entry))
00887         {
00888             /* check if we have found the next hierarchy */
00889             if((strlen(dir_entry->long_name) != length_to_sep ||
00890                 strncmp(path, dir_entry->long_name, length_to_sep) != 0))
00891                 continue;
00892 
00893             fat_close_dir(dd);
00894             dd = 0;
00895 
00896             if(path[length_to_sep] == '\0')
00897                 /* we iterated through the whole path and have found the file */
00898                 return 1;
00899 
00900             if(dir_entry->attributes & FAT_ATTRIB_DIR)
00901             {
00902                 /* we found a parent directory of the file we are searching for */
00903                 path = sub_path;
00904                 break;
00905             }
00906 
00907             /* a parent of the file exists, but not the file itself */
00908             return 0;
00909         }
00910 
00911         fat_close_dir(dd);
00912     }
00913     
00914     return 0;
00915 }

Here is the call graph for this function:

Here is the caller graph for this function:

void fat_get_file_modification_date ( const struct fat_dir_entry_struct dir_entry,
uint16_t *  year,
uint8_t *  month,
uint8_t *  day 
)

void fat_get_file_modification_time ( const struct fat_dir_entry_struct dir_entry,
uint8_t *  hour,
uint8_t *  min,
uint8_t *  sec 
)

offset_t fat_get_fs_free ( const struct fat_fs_struct fs  ) 

Returns the amount of free storage capacity on the filesystem in bytes.

Note:
As the FAT filesystem is cluster based, this function does not return continuous values but multiples of the cluster size.
Parameters:
[in] fs The filesystem on which to operate.
Returns:
0 on failure, the free filesystem space in bytes otherwise.

Definition at line 2376 of file fat.c.

References fat_usage_count_callback_arg::buffer_size, fat_usage_count_callback_arg::cluster_count, fat_header_struct::cluster_size, partition_struct::device_read_interval, FAT_FAT32_SUPPORT, fat_get_fs_free_16_callback(), fat_header_struct::fat_offset, fat_header_struct::fat_size, fat_fs_struct::header, fat_fs_struct::partition, PARTITION_TYPE_FAT16, and partition_struct::type.

Referenced by WaspSD::getDiskFree(), and WaspSD::print_disk_info().

02377 {
02378     if(!fs)
02379         return 0;
02380 
02381     uint8_t fat[32];
02382     struct fat_usage_count_callback_arg count_arg;
02383     count_arg.cluster_count = 0;
02384     count_arg.buffer_size = sizeof(fat);
02385 
02386     offset_t fat_offset = fs->header.fat_offset;
02387     uint32_t fat_size = fs->header.fat_size;
02388     while(fat_size > 0)
02389     {
02390         uintptr_t length = UINTPTR_MAX - 1;
02391         if(fat_size < length)
02392             length = fat_size;
02393 
02394         if(!fs->partition->device_read_interval(fat_offset,
02395                                                 fat,
02396                                                 sizeof(fat),
02397                                                 length,
02398 #if FAT_FAT32_SUPPORT
02399                                                 (fs->partition->type == PARTITION_TYPE_FAT16) ?
02400                                                     fat_get_fs_free_16_callback :
02401                                                     fat_get_fs_free_32_callback,
02402 #else
02403                                                 fat_get_fs_free_16_callback,
02404 #endif
02405                                                 &count_arg
02406                                                )
02407           )
02408             return 0;
02409 
02410         fat_offset += length;
02411         fat_size -= length;
02412     }
02413 
02414     return (offset_t) count_arg.cluster_count * fs->header.cluster_size;
02415 }

Here is the call graph for this function:

Here is the caller graph for this function:

offset_t fat_get_fs_size ( const struct fat_fs_struct fs  ) 

Deletes a directory.

This is just a synonym for fat_delete_file(). If a directory is deleted without first deleting its subdirectories and files, disk space occupied by these files will get wasted as there is no chance to release it and mark it as free.

Parameters:
[in] fs The filesystem on which to operate.
[in] dir_entry The directory entry of the directory to delete.
Returns:
0 on failure, 1 on success.
See also:
fat_create_dir
Returns the amount of total storage capacity of the filesystem in bytes.

Parameters:
[in] fs The filesystem on which to operate.
Returns:
0 on failure, the filesystem size in bytes otherwise.

Definition at line 2353 of file fat.c.

References fat_header_struct::cluster_size, fat_header_struct::fat_size, fat_fs_struct::header, fat_fs_struct::partition, PARTITION_TYPE_FAT32, and partition_struct::type.

Referenced by WaspSD::getDiskSize(), and WaspSD::print_disk_info().

02354 {
02355     if(!fs)
02356         return 0;
02357 
02358 #if FAT_FAT32_SUPPORT
02359     if(fs->partition->type == PARTITION_TYPE_FAT32)
02360         return (offset_t) (fs->header.fat_size / 4 - 2) * fs->header.cluster_size;
02361     else
02362 #endif
02363         return (offset_t) (fs->header.fat_size / 2 - 2) * fs->header.cluster_size;
02364 }

Here is the caller graph for this function:

struct fat_fs_struct* fat_open ( struct partition_struct partition  )  [read]

Opens a FAT filesystem.

Parameters:
[in] partition Discriptor of partition on which the filesystem resides.
Returns:
0 on error, a FAT filesystem descriptor on success.
See also:
fat_close

Definition at line 235 of file fat.c.

References partition_struct::device_write, partition_struct::device_write_interval, FAT_FS_COUNT, fat_fs_handles, fat_read_header(), FAT_WRITE_SUPPORT, and fat_fs_struct::partition.

Referenced by WaspSD::init().

00236 {
00237     if(!partition ||
00238 #if FAT_WRITE_SUPPORT
00239        !partition->device_write ||
00240        !partition->device_write_interval
00241 #else
00242        0
00243 #endif
00244       )
00245         return 0;
00246 
00247 #if USE_DYNAMIC_MEMORY
00248     struct fat_fs_struct* fs = malloc(sizeof(*fs));
00249     if(!fs)
00250         return 0;
00251 #else
00252     struct fat_fs_struct* fs = fat_fs_handles;
00253     uint8_t i;
00254     for(i = 0; i < FAT_FS_COUNT; ++i)
00255     {
00256         if(!fs->partition)
00257             break;
00258 
00259         ++fs;
00260     }
00261     if(i >= FAT_FS_COUNT)
00262         return 0;
00263 #endif
00264 
00265     memset(fs, 0, sizeof(*fs));
00266 
00267     fs->partition = partition;
00268     if(!fat_read_header(fs))
00269     {
00270 #if USE_DYNAMIC_MEMORY
00271         free(fs);
00272 #else
00273         fs->partition = 0;
00274 #endif
00275         return 0;
00276     }
00277     
00278     return fs;
00279 }

Here is the call graph for this function:

Here is the caller graph for this function:

struct fat_dir_struct* fat_open_dir ( struct fat_fs_struct fs,
const struct fat_dir_entry_struct dir_entry 
) [read]

Opens a directory.

Parameters:
[in] fs The filesystem on which the directory to open resides.
[in] dir_entry The directory entry which stands for the directory to open.
Returns:
An opaque directory descriptor on success, 0 on failure.
See also:
fat_close_dir

Definition at line 1376 of file fat.c.

References fat_dir_entry_struct::attributes, fat_dir_entry_struct::cluster, fat_dir_struct::dir_entry, fat_dir_struct::entry_cluster, fat_dir_struct::entry_offset, FAT_ATTRIB_DIR, FAT_DIR_COUNT, fat_dir_handles, and fat_dir_struct::fs.

Referenced by WaspSD::cd(), fat_get_dir_entry_of_path(), and WaspSD::init().

01377 {
01378     if(!fs || !dir_entry || !(dir_entry->attributes & FAT_ATTRIB_DIR))
01379         return 0;
01380 
01381 #if USE_DYNAMIC_MEMORY
01382     struct fat_dir_struct* dd = malloc(sizeof(*dd));
01383     if(!dd)
01384         return 0;
01385 #else
01386     struct fat_dir_struct* dd = fat_dir_handles;
01387     uint8_t i;
01388     for(i = 0; i < FAT_DIR_COUNT; ++i)
01389     {
01390         if(!dd->fs)
01391             break;
01392 
01393         ++dd;
01394     }
01395     if(i >= FAT_DIR_COUNT)
01396         return 0;
01397 #endif
01398     
01399     memcpy(&dd->dir_entry, dir_entry, sizeof(*dir_entry));
01400     dd->fs = fs;
01401     dd->entry_cluster = dir_entry->cluster;
01402     dd->entry_offset = 0;
01403 
01404     return dd;
01405 }

Here is the caller graph for this function:

struct fat_file_struct* fat_open_file ( struct fat_fs_struct fs,
const struct fat_dir_entry_struct dir_entry 
) [read]

Opens a file on a FAT filesystem.

Parameters:
[in] fs The filesystem on which the file to open lies.
[in] dir_entry The directory entry of the file to open.
Returns:
The file handle, or 0 on failure.
See also:
fat_close_file

Definition at line 926 of file fat.c.

References fat_dir_entry_struct::attributes, fat_dir_entry_struct::cluster, fat_file_struct::dir_entry, FAT_ATTRIB_DIR, FAT_FILE_COUNT, fat_file_handles, fat_file_struct::fs, fat_file_struct::pos, and fat_file_struct::pos_cluster.

Referenced by WaspSD::openFile().

00927 {
00928     if(!fs || !dir_entry || (dir_entry->attributes & FAT_ATTRIB_DIR))
00929         return 0;
00930 
00931 #if USE_DYNAMIC_MEMORY
00932     struct fat_file_struct* fd = malloc(sizeof(*fd));
00933     if(!fd)
00934         return 0;
00935 #else
00936     struct fat_file_struct* fd = fat_file_handles;
00937     uint8_t i;
00938     for(i = 0; i < FAT_FILE_COUNT; ++i)
00939     {
00940         if(!fd->fs)
00941             break;
00942 
00943         ++fd;
00944     }
00945     if(i >= FAT_FILE_COUNT)
00946         return 0;
00947 #endif
00948     
00949     memcpy(&fd->dir_entry, dir_entry, sizeof(*dir_entry));
00950     fd->fs = fs;
00951     fd->pos = 0;
00952     fd->pos_cluster = dir_entry->cluster;
00953 
00954     return fd;
00955 }

Here is the caller graph for this function:

uint8_t fat_read_dir ( struct fat_dir_struct dd,
struct fat_dir_entry_struct dir_entry 
)

Reads the next directory entry contained within a parent directory.

Parameters:
[in] dd The descriptor of the parent directory from which to read the entry.
[out] dir_entry Pointer to a buffer into which to write the directory entry information.
Returns:
0 on failure, 1 on success.
See also:
fat_reset_dir

Definition at line 1437 of file fat.c.

References fat_read_dir_callback_arg::bytes_read, fat_header_struct::cluster_size, fat_header_struct::cluster_zero_offset, partition_struct::device_read_interval, fat_read_dir_callback_arg::dir_entry, fat_dir_struct::entry_cluster, fat_dir_struct::entry_offset, fat_cluster_offset(), fat_dir_entry_read_callback(), fat_get_next_cluster(), fat_reset_dir(), fat_read_dir_callback_arg::finished, fat_dir_struct::fs, fat_fs_struct::header, fat_fs_struct::partition, PARTITION_TYPE_FAT32, fat_header_struct::root_dir_offset, and partition_struct::type.

Referenced by WaspSD::delDir(), fat_create_dir(), fat_create_file(), fat_get_dir_entry_of_path(), WaspSD::find_file_in_dir(), WaspSD::ls(), and WaspSD::numFiles().

01438 {
01439     if(!dd || !dir_entry)
01440         return 0;
01441 
01442     /* get current position of directory handle */
01443     struct fat_fs_struct* fs = dd->fs;
01444     const struct fat_header_struct* header = &fs->header;
01445     uint16_t cluster_size = header->cluster_size;
01446     cluster_t cluster_num = dd->entry_cluster;
01447     uint16_t cluster_offset = dd->entry_offset;
01448     struct fat_read_dir_callback_arg arg;
01449 
01450     if(cluster_offset >= cluster_size)
01451     {
01452         /* The latest call hit the border of the last cluster in
01453          * the chain, but it still returned a directory entry.
01454          * So we now reset the handle and signal the caller the
01455          * end of the listing.
01456          */
01457         fat_reset_dir(dd);
01458         return 0;
01459     }
01460 
01461     /* reset callback arguments */
01462     memset(&arg, 0, sizeof(arg));
01463     memset(dir_entry, 0, sizeof(*dir_entry));
01464     arg.dir_entry = dir_entry;
01465 
01466     /* check if we read from the root directory */
01467     if(cluster_num == 0)
01468     {
01469 #if FAT_FAT32_SUPPORT
01470         if(fs->partition->type == PARTITION_TYPE_FAT32)
01471             cluster_num = header->root_dir_cluster;
01472         else
01473 #endif
01474             cluster_size = header->cluster_zero_offset - header->root_dir_offset;
01475     }
01476 
01477     /* read entries */
01478     uint8_t buffer[32];
01479     while(!arg.finished)
01480     {
01481         /* read directory entries up to the cluster border */
01482         uint16_t cluster_left = cluster_size - cluster_offset;
01483         offset_t pos = cluster_offset;
01484         if(cluster_num == 0)
01485             pos += header->root_dir_offset;
01486         else
01487             pos += fat_cluster_offset(fs, cluster_num);
01488 
01489         arg.bytes_read = 0;
01490         if(!fs->partition->device_read_interval(pos,
01491                                                 buffer,
01492                                                 sizeof(buffer),
01493                                                 cluster_left,
01494                                                 fat_dir_entry_read_callback,
01495                                                 &arg)
01496           )
01497             return 0;
01498 
01499         cluster_offset += arg.bytes_read;
01500 
01501         if(cluster_offset >= cluster_size)
01502         {
01503             /* we reached the cluster border and switch to the next cluster */
01504 
01505             /* get number of next cluster */
01506             if((cluster_num = fat_get_next_cluster(fs, cluster_num)) != 0)
01507             {
01508                 cluster_offset = 0;
01509                 continue;
01510             }
01511 
01512             /* we are at the end of the cluster chain */
01513             if(!arg.finished)
01514             {
01515                 /* directory entry not found, reset directory handle */
01516                 fat_reset_dir(dd);
01517                 return 0;
01518             }
01519             else
01520             {
01521                 /* The current execution of the function has been successful,
01522                  * so we can not signal an end of the directory listing to
01523                  * the caller, but must wait for the next call. So we keep an
01524                  * invalid cluster offset to mark this directory handle's
01525                  * traversal as finished.
01526                  */
01527             }
01528 
01529             break;
01530         }
01531     }
01532 
01533     dd->entry_cluster = cluster_num;
01534     dd->entry_offset = cluster_offset;
01535 
01536     return arg.finished;
01537 }

Here is the call graph for this function:

Here is the caller graph for this function:

intptr_t fat_read_file ( struct fat_file_struct fd,
uint8_t *  buffer,
uintptr_t  buffer_len 
)

Reads data from a file.

The data requested is read from the current file location.

Parameters:
[in] fd The file handle of the file from which to read.
[out] buffer The buffer into which to write.
[in] buffer_len The amount of data to read.
Returns:
The number of bytes read, 0 on end of file, or -1 on failure.
See also:
fat_write_file

Definition at line 993 of file fat.c.

References fat_dir_entry_struct::cluster, fat_header_struct::cluster_size, partition_struct::device_read, fat_file_struct::dir_entry, fat_cluster_offset(), fat_get_next_cluster(), fat_dir_entry_struct::file_size, fat_file_struct::fs, fat_fs_struct::header, fat_fs_struct::partition, fat_file_struct::pos, and fat_file_struct::pos_cluster.

Referenced by WaspSD::cat(), WaspSD::catBin(), WaspSD::catln(), WaspSD::indexOf(), and WaspSD::numln().

00994 {
00995     /* check arguments */
00996     if(!fd || !buffer || buffer_len < 1)
00997         return -1;
00998 
00999     /* determine number of bytes to read */
01000     if(fd->pos + buffer_len > fd->dir_entry.file_size)
01001         buffer_len = fd->dir_entry.file_size - fd->pos;
01002     if(buffer_len == 0)
01003         return 0;
01004     
01005     uint16_t cluster_size = fd->fs->header.cluster_size;
01006     cluster_t cluster_num = fd->pos_cluster;
01007     uintptr_t buffer_left = buffer_len;
01008     uint16_t first_cluster_offset = (uint16_t) (fd->pos & (cluster_size - 1));
01009 
01010     /* find cluster in which to start reading */
01011     if(!cluster_num)
01012     {
01013         cluster_num = fd->dir_entry.cluster;
01014         
01015         if(!cluster_num)
01016         {
01017             if(!fd->pos)
01018                 return 0;
01019             else
01020                 return -1;
01021         }
01022 
01023         if(fd->pos)
01024         {
01025             uint32_t pos = fd->pos;
01026             while(pos >= cluster_size)
01027             {
01028                 pos -= cluster_size;
01029                 cluster_num = fat_get_next_cluster(fd->fs, cluster_num);
01030                 if(!cluster_num)
01031                     return -1;
01032             }
01033         }
01034     }
01035     
01036     /* read data */
01037     do
01038     {
01039         /* calculate data size to copy from cluster */
01040         offset_t cluster_offset = fat_cluster_offset(fd->fs, cluster_num) + first_cluster_offset;
01041         uint16_t copy_length = cluster_size - first_cluster_offset;
01042         if(copy_length > buffer_left)
01043             copy_length = buffer_left;
01044 
01045         /* read data */
01046         if(!fd->fs->partition->device_read(cluster_offset, buffer, copy_length))
01047             return buffer_len - buffer_left;
01048 
01049         /* calculate new file position */
01050         buffer += copy_length;
01051         buffer_left -= copy_length;
01052         fd->pos += copy_length;
01053 
01054         if(first_cluster_offset + copy_length >= cluster_size)
01055         {
01056             /* we are on a cluster boundary, so get the next cluster */
01057             if((cluster_num = fat_get_next_cluster(fd->fs, cluster_num)))
01058             {
01059                 first_cluster_offset = 0;
01060             }
01061             else
01062             {
01063                 fd->pos_cluster = 0;
01064                 return buffer_len - buffer_left;
01065             }
01066         }
01067 
01068         fd->pos_cluster = cluster_num;
01069 
01070     } while(buffer_left > 0); /* check if we are done */
01071 
01072     return buffer_len;
01073 }

Here is the call graph for this function:

Here is the caller graph for this function:

uint8_t fat_reset_dir ( struct fat_dir_struct dd  ) 

Resets a directory handle.

Resets the directory handle such that reading restarts with the first directory entry.

Parameters:
[in] dd The directory handle to reset.
Returns:
0 on failure, 1 on success.
See also:
fat_read_dir

Definition at line 1550 of file fat.c.

References fat_dir_entry_struct::cluster, fat_dir_struct::dir_entry, fat_dir_struct::entry_cluster, and fat_dir_struct::entry_offset.

Referenced by fat_create_dir(), fat_create_file(), fat_read_dir(), and WaspSD::find_file_in_dir().

01551 {
01552     if(!dd)
01553         return 0;
01554 
01555     dd->entry_cluster = dd->dir_entry.cluster;
01556     dd->entry_offset = 0;
01557     return 1;
01558 }

Here is the caller graph for this function:

uint8_t fat_resize_file ( struct fat_file_struct fd,
uint32_t  size 
)

Resizes a file to have a specific size.

Enlarges or shrinks the file pointed to by the file descriptor to have exactly the specified size.

If the file is truncated, all bytes having an equal or larger offset than the given size are lost. If the file is expanded, the additional bytes are allocated.

Note:
Please be aware that this function just allocates or deallocates disk space, it does not explicitely clear it. To avoid data leakage, this must be done manually.
Parameters:
[in] fd The file decriptor of the file which to resize.
[in] size The new size of the file.
Returns:
0 on failure, 1 on success.

Definition at line 1288 of file fat.c.

References fat_dir_entry_struct::cluster, fat_header_struct::cluster_size, fat_file_struct::dir_entry, fat_append_clusters(), fat_free_clusters(), fat_get_next_cluster(), fat_terminate_clusters(), fat_write_dir_entry(), fat_dir_entry_struct::file_size, fat_file_struct::fs, fat_fs_struct::header, fat_file_struct::pos, and fat_file_struct::pos_cluster.

Referenced by fat_seek_file().

01289 {
01290     if(!fd)
01291         return 0;
01292 
01293     cluster_t cluster_num = fd->dir_entry.cluster;
01294     uint16_t cluster_size = fd->fs->header.cluster_size;
01295     uint32_t size_new = size;
01296 
01297     do
01298     {
01299         if(cluster_num == 0 && size_new == 0)
01300             /* the file stays empty */
01301             break;
01302 
01303         /* seek to the next cluster as long as we need the space */
01304         while(size_new > cluster_size)
01305         {
01306             /* get next cluster of file */
01307             cluster_t cluster_num_next = fat_get_next_cluster(fd->fs, cluster_num);
01308             if(cluster_num_next)
01309             {
01310                 cluster_num = cluster_num_next;
01311                 size_new -= cluster_size;
01312             }
01313             else
01314             {
01315                 break;
01316             }
01317         }
01318 
01319         if(size_new > cluster_size || cluster_num == 0)
01320         {
01321             /* Allocate new cluster chain and append
01322              * it to the existing one, if available.
01323              */
01324             cluster_t cluster_count = (size_new + cluster_size - 1) / cluster_size;
01325             cluster_t cluster_new_chain = fat_append_clusters(fd->fs, cluster_num, cluster_count);
01326             if(!cluster_new_chain)
01327                 return 0;
01328 
01329             if(!cluster_num)
01330             {
01331                 cluster_num = cluster_new_chain;
01332                 fd->dir_entry.cluster = cluster_num;
01333             }
01334         }
01335 
01336         /* write new directory entry */
01337         fd->dir_entry.file_size = size;
01338         if(size == 0)
01339             fd->dir_entry.cluster = 0;
01340         if(!fat_write_dir_entry(fd->fs, &fd->dir_entry))
01341             return 0;
01342 
01343         if(size == 0)
01344         {
01345             /* free all clusters of file */
01346             fat_free_clusters(fd->fs, cluster_num);
01347         }
01348         else if(size_new <= cluster_size)
01349         {
01350             /* free all clusters no longer needed */
01351             fat_terminate_clusters(fd->fs, cluster_num);
01352         }
01353 
01354     } while(0);
01355 
01356     /* correct file position */
01357     if(size < fd->pos)
01358     {
01359         fd->pos = size;
01360         fd->pos_cluster = 0;
01361     }
01362 
01363     return 1;
01364 }

Here is the call graph for this function:

Here is the caller graph for this function:

uint8_t fat_seek_file ( struct fat_file_struct fd,
int32_t *  offset,
uint8_t  whence 
)

Repositions the read/write file offset.

Changes the file offset where the next call to fat_read_file() or fat_write_file() starts reading/writing.

If the new offset is beyond the end of the file, fat_resize_file() is implicitly called, i.e. the file is expanded.

The new offset can be given in different ways determined by the whence parameter:

  • FAT_SEEK_SET: *offset is relative to the beginning of the file.
  • FAT_SEEK_CUR: *offset is relative to the current file position.
  • FAT_SEEK_END: *offset is relative to the end of the file.

The resulting absolute offset is written to the location the offset parameter points to.

Parameters:
[in] fd The file decriptor of the file on which to seek.
[in,out] offset A pointer to the new offset, as affected by the whence parameter. The function writes the new absolute offset to this location before it returns.
[in] whence Affects the way offset is interpreted, see above.
Returns:
0 on failure, 1 on success.

Definition at line 1233 of file fat.c.

References fat_file_struct::dir_entry, fat_resize_file(), FAT_SEEK_CUR, FAT_SEEK_END, FAT_SEEK_SET, FAT_WRITE_SUPPORT, fat_dir_entry_struct::file_size, fat_file_struct::pos, and fat_file_struct::pos_cluster.

Referenced by WaspSD::cat(), WaspSD::catBin(), and WaspSD::writeSD().

01234 {
01235     if(!fd || !offset)
01236         return 0;
01237 
01238     uint32_t new_pos = fd->pos;
01239     switch(whence)
01240     {
01241         case FAT_SEEK_SET:
01242             new_pos = *offset;
01243             break;
01244         case FAT_SEEK_CUR:
01245             new_pos += *offset;
01246             break;
01247         case FAT_SEEK_END:
01248             new_pos = fd->dir_entry.file_size + *offset;
01249             break;
01250         default:
01251             return 0;
01252     }
01253 
01254     if(new_pos > fd->dir_entry.file_size
01255 #if FAT_WRITE_SUPPORT
01256        && !fat_resize_file(fd, new_pos)
01257 #endif
01258        )
01259         return 0;
01260 
01261     fd->pos = new_pos;
01262     fd->pos_cluster = 0;
01263 
01264     *offset = (int32_t) new_pos;
01265     return 1;
01266 }

Here is the call graph for this function:

Here is the caller graph for this function:

intptr_t fat_write_file ( struct fat_file_struct fd,
const uint8_t *  buffer,
uintptr_t  buffer_len 
)

Writes data to a file.

The data is written to the current file location.

Parameters:
[in] fd The file handle of the file to which to write.
[in] buffer The buffer from which to read the data to be written.
[in] buffer_len The amount of data to write.
Returns:
The number of bytes written, 0 on disk full, or -1 on failure.
See also:
fat_read_file

Definition at line 1088 of file fat.c.

References fat_dir_entry_struct::cluster, fat_header_struct::cluster_size, partition_struct::device_write, fat_file_struct::dir_entry, fat_append_clusters(), fat_cluster_offset(), fat_get_next_cluster(), fat_write_dir_entry(), fat_dir_entry_struct::file_size, fat_file_struct::fs, fat_fs_struct::header, fat_fs_struct::partition, fat_file_struct::pos, and fat_file_struct::pos_cluster.

Referenced by WaspSD::writeSD().

01089 {
01090     /* check arguments */
01091     if(!fd || !buffer || buffer_len < 1)
01092         return -1;
01093     if(fd->pos > fd->dir_entry.file_size)
01094         return -1;
01095 
01096     uint16_t cluster_size = fd->fs->header.cluster_size;
01097     cluster_t cluster_num = fd->pos_cluster;
01098     uintptr_t buffer_left = buffer_len;
01099     uint16_t first_cluster_offset = (uint16_t) (fd->pos & (cluster_size - 1));
01100 
01101     /* find cluster in which to start writing */
01102     if(!cluster_num)
01103     {
01104         cluster_num = fd->dir_entry.cluster;
01105         
01106         if(!cluster_num)
01107         {
01108             if(!fd->pos)
01109             {
01110                 /* empty file */
01111                 fd->dir_entry.cluster = cluster_num = fat_append_clusters(fd->fs, 0, 1);
01112                 if(!cluster_num)
01113                     return -1;
01114             }
01115             else
01116             {
01117                 return -1;
01118             }
01119         }
01120 
01121         if(fd->pos)
01122         {
01123             uint32_t pos = fd->pos;
01124             cluster_t cluster_num_next;
01125             while(pos >= cluster_size)
01126             {
01127                 pos -= cluster_size;
01128                 cluster_num_next = fat_get_next_cluster(fd->fs, cluster_num);
01129                 if(!cluster_num_next && pos == 0)
01130                     /* the file exactly ends on a cluster boundary, and we append to it */
01131                     cluster_num_next = fat_append_clusters(fd->fs, cluster_num, 1);
01132                 if(!cluster_num_next)
01133                     return -1;
01134 
01135                 cluster_num = cluster_num_next;
01136             }
01137         }
01138     }
01139     
01140     /* write data */
01141     do
01142     {
01143         /* calculate data size to write to cluster */
01144         offset_t cluster_offset = fat_cluster_offset(fd->fs, cluster_num) + first_cluster_offset;
01145         uint16_t write_length = cluster_size - first_cluster_offset;
01146         if(write_length > buffer_left)
01147             write_length = buffer_left;
01148 
01149         /* write data which fits into the current cluster */
01150         if(!fd->fs->partition->device_write(cluster_offset, buffer, write_length))
01151             break;
01152 
01153         /* calculate new file position */
01154         buffer += write_length;
01155         buffer_left -= write_length;
01156         fd->pos += write_length;
01157 
01158         if(first_cluster_offset + write_length >= cluster_size)
01159         {
01160             /* we are on a cluster boundary, so get the next cluster */
01161             cluster_t cluster_num_next = fat_get_next_cluster(fd->fs, cluster_num);
01162             if(!cluster_num_next && buffer_left > 0)
01163                 /* we reached the last cluster, append a new one */
01164                 cluster_num_next = fat_append_clusters(fd->fs, cluster_num, 1);
01165             if(!cluster_num_next)
01166             {
01167                 fd->pos_cluster = 0;
01168                 break;
01169             }
01170 
01171             cluster_num = cluster_num_next;
01172             first_cluster_offset = 0;
01173         }
01174 
01175         fd->pos_cluster = cluster_num;
01176 
01177     } while(buffer_left > 0); /* check if we are done */
01178 
01179     /* update directory entry */
01180     if(fd->pos > fd->dir_entry.file_size)
01181     {
01182 #if !FAT_DELAY_DIRENTRY_UPDATE
01183         uint32_t size_old = fd->dir_entry.file_size;
01184 #endif
01185 
01186         /* update file size */
01187         fd->dir_entry.file_size = fd->pos;
01188 
01189 #if !FAT_DELAY_DIRENTRY_UPDATE
01190         /* write directory entry */
01191         if(!fat_write_dir_entry(fd->fs, &fd->dir_entry))
01192         {
01193             /* We do not return an error here since we actually wrote
01194              * some data to disk. So we calculate the amount of data
01195              * we wrote to disk and which lies within the old file size.
01196              */
01197             buffer_left = fd->pos - size_old;
01198             fd->pos = size_old;
01199         }
01200 #endif
01201     }
01202 
01203     return buffer_len - buffer_left;
01204 }

Here is the call graph for this function:

Here is the caller graph for this function:

void get_datetime ( uint16_t *  year,
uint8_t *  month,
uint8_t *  day,
uint8_t *  hour,
uint8_t *  min,
uint8_t *  sec 
)


Generated on Tue Jul 20 09:30:59 2010 for WaspmoteAPI by  doxygen 1.5.6