UbixOS  2.0
fat_write.c
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 //-----------------------------------------------------------------------------
3 // FAT16/32 File IO Library
4 // V2.6
5 // Ultra-Embedded.com
6 // Copyright 2003 - 2012
7 //
8 // Email: admin@ultra-embedded.com
9 //
10 // License: GPL
11 // If you would like a version with a more permissive license for use in
12 // closed source commercial applications please contact me for details.
13 //-----------------------------------------------------------------------------
14 //
15 // This file is part of FAT File IO Library.
16 //
17 // FAT File IO Library is free software; you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation; either version 2 of the License, or
20 // (at your option) any later version.
21 //
22 // FAT File IO Library is distributed in the hope that it will be useful,
23 // but WITHOUT ANY WARRANTY; without even the implied warranty of
24 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 // GNU General Public License for more details.
26 //
27 // You should have received a copy of the GNU General Public License
28 // along with FAT File IO Library; if not, write to the Free Software
29 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 //-----------------------------------------------------------------------------
31 //-----------------------------------------------------------------------------
32 #include <string.h>
33 #include "fat_defs.h"
34 #include "fat_access.h"
35 #include "fat_table.h"
36 #include "fat_write.h"
37 #include "fat_string.h"
38 #include "fat_misc.h"
39 
40 #if FATFS_INC_WRITE_SUPPORT
41 //-----------------------------------------------------------------------------
42 // fatfs_add_free_space: Allocate another cluster of free space to the end
43 // of a files cluster chain.
44 //-----------------------------------------------------------------------------
45 int fatfs_add_free_space(struct fatfs *fs, uint32 *startCluster, uint32 clusters)
46 {
47  uint32 i;
48  uint32 nextcluster;
49  uint32 start = *startCluster;
50 
51  // Set the next free cluster hint to unknown
52  if (fs->next_free_cluster != FAT32_LAST_CLUSTER)
54 
55  for (i=0;i<clusters;i++)
56  {
57  // Start looking for free clusters from the beginning
58  if (fatfs_find_blank_cluster(fs, fs->rootdir_first_cluster, &nextcluster))
59  {
60  // Point last to this
61  fatfs_fat_set_cluster(fs, start, nextcluster);
62 
63  // Point this to end of file
65 
66  // Adjust argument reference
67  start = nextcluster;
68  if (i == 0)
69  *startCluster = nextcluster;
70  }
71  else
72  return 0;
73  }
74 
75  return 1;
76 }
77 //-----------------------------------------------------------------------------
78 // fatfs_allocate_free_space: Add an ammount of free space to a file either from
79 // 'startCluster' if newFile = false, or allocating a new start to the chain if
80 // newFile = true.
81 //-----------------------------------------------------------------------------
82 int fatfs_allocate_free_space(struct fatfs *fs, int newFile, uint32 *startCluster, uint32 size)
83 {
84  uint32 clusterSize;
85  uint32 clusterCount;
86  uint32 nextcluster;
87 
88  if (size==0)
89  return 0;
90 
91  // Set the next free cluster hint to unknown
92  if (fs->next_free_cluster != FAT32_LAST_CLUSTER)
94 
95  // Work out size and clusters
96  clusterSize = fs->sectors_per_cluster * FAT_SECTOR_SIZE;
97  clusterCount = (size / clusterSize);
98 
99  // If any left over
100  if (size-(clusterSize*clusterCount))
101  clusterCount++;
102 
103  // Allocated first link in the chain if a new file
104  if (newFile)
105  {
106  if (!fatfs_find_blank_cluster(fs, fs->rootdir_first_cluster, &nextcluster))
107  return 0;
108 
109  // If this is all that is needed then all done
110  if (clusterCount==1)
111  {
113  *startCluster = nextcluster;
114  return 1;
115  }
116  }
117  // Allocate from end of current chain (startCluster is end of chain)
118  else
119  nextcluster = *startCluster;
120 
121  if (!fatfs_add_free_space(fs, &nextcluster, clusterCount))
122  return 0;
123 
124  return 1;
125 }
126 //-----------------------------------------------------------------------------
127 // fatfs_find_free_dir_offset: Find a free space in the directory for a new entry
128 // which takes up 'entryCount' blocks (or allocate some more)
129 //-----------------------------------------------------------------------------
130 static int fatfs_find_free_dir_offset(struct fatfs *fs, uint32 dirCluster, int entryCount, uint32 *pSector, uint8 *pOffset)
131 {
133  uint8 item=0;
134  uint16 recordoffset = 0;
135  uint8 i=0;
136  int x=0;
137  int possible_spaces = 0;
138  int start_recorded = 0;
139 
140  // No entries required?
141  if (entryCount == 0)
142  return 0;
143 
144  // Main cluster following loop
145  while (1)
146  {
147  // Read sector
148  if (fatfs_sector_reader(fs, dirCluster, x++, 0))
149  {
150  // Analyse Sector
151  for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
152  {
153  // Create the multiplier for sector access
154  recordoffset = FAT_DIR_ENTRY_SIZE * item;
155 
156  // Overlay directory entry over buffer
157  directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
158 
159  // LFN Entry
161  {
162  // First entry?
163  if (possible_spaces == 0)
164  {
165  // Store start
166  *pSector = x-1;
167  *pOffset = item;
168  start_recorded = 1;
169  }
170 
171  // Increment the count in-case the file turns
172  // out to be deleted...
173  possible_spaces++;
174  }
175  // SFN Entry
176  else
177  {
178  // Has file been deleted?
179  if (fs->currentsector.sector[recordoffset] == FILE_HEADER_DELETED)
180  {
181  // First entry?
182  if (possible_spaces == 0)
183  {
184  // Store start
185  *pSector = x-1;
186  *pOffset = item;
187  start_recorded = 1;
188  }
189 
190  possible_spaces++;
191 
192  // We have found enough space?
193  if (possible_spaces >= entryCount)
194  return 1;
195 
196  // Else continue counting until we find a valid entry!
197  }
198  // Is the file entry empty?
199  else if (fs->currentsector.sector[recordoffset] == FILE_HEADER_BLANK)
200  {
201  // First entry?
202  if (possible_spaces == 0)
203  {
204  // Store start
205  *pSector = x-1;
206  *pOffset = item;
207  start_recorded = 1;
208  }
209 
210  // Increment the blank entries count
211  possible_spaces++;
212 
213  // We have found enough space?
214  if (possible_spaces >= entryCount)
215  return 1;
216  }
217  // File entry is valid
218  else
219  {
220  // Reset all flags
221  possible_spaces = 0;
222  start_recorded = 0;
223  }
224  }
225  } // End of for
226  } // End of if
227  // Run out of free space in the directory, allocate some more
228  else
229  {
230  uint32 newCluster;
231 
232  // Get a new cluster for directory
233  if (!fatfs_find_blank_cluster(fs, fs->rootdir_first_cluster, &newCluster))
234  return 0;
235 
236  // Add cluster to end of directory tree
237  if (!fatfs_fat_add_cluster_to_chain(fs, dirCluster, newCluster))
238  return 0;
239 
240  // Erase new directory cluster
241  memset(fs->currentsector.sector, 0x00, FAT_SECTOR_SIZE);
242  for (i=0;i<fs->sectors_per_cluster;i++)
243  {
244  if (!fatfs_write_sector(fs, newCluster, i, 0))
245  return 0;
246  }
247 
248  // If non of the name fitted on previous sectors
249  if (!start_recorded)
250  {
251  // Store start
252  *pSector = (x-1);
253  *pOffset = 0;
254  start_recorded = 1;
255  }
256 
257  return 1;
258  }
259  } // End of while loop
260 
261  return 0;
262 }
263 //-----------------------------------------------------------------------------
264 // fatfs_add_file_entry: Add a directory entry to a location found by FindFreeOffset
265 //-----------------------------------------------------------------------------
266 int fatfs_add_file_entry(struct fatfs *fs, uint32 dirCluster, char *filename, char *shortfilename, uint32 startCluster, uint32 size, int dir)
267 {
268  uint8 item=0;
269  uint16 recordoffset = 0;
270  uint8 i=0;
271  uint32 x=0;
272  int entryCount;
273  struct fat_dir_entry shortEntry;
274  int dirtySector = 0;
275 
276  uint32 dirSector = 0;
277  uint8 dirOffset = 0;
278  int foundEnd = 0;
279 
280  uint8 checksum;
281  uint8 *pSname;
282 
283  // No write access?
284  if (!fs->disk_io.write_media)
285  return 0;
286 
287 #if FATFS_INC_LFN_SUPPORT
288  // How many LFN entries are required?
289  // NOTE: We always request one LFN even if it would fit in a SFN!
290  entryCount = fatfs_lfn_entries_required(filename);
291  if (!entryCount)
292  return 0;
293 #else
294  entryCount = 0;
295 #endif
296 
297  // Find space in the directory for this filename (or allocate some more)
298  // NOTE: We need to find space for at least the LFN + SFN (or just the SFN if LFNs not supported).
299  if (!fatfs_find_free_dir_offset(fs, dirCluster, entryCount + 1, &dirSector, &dirOffset))
300  return 0;
301 
302  // Generate checksum of short filename
303  pSname = (uint8*)shortfilename;
304  checksum = 0;
305  for (i=11; i!=0; i--) checksum = ((checksum & 1) ? 0x80 : 0) + (checksum >> 1) + *pSname++;
306 
307  // Start from current sector where space was found!
308  x = dirSector;
309 
310  // Main cluster following loop
311  while (1)
312  {
313  // Read sector
314  if (fatfs_sector_reader(fs, dirCluster, x++, 0))
315  {
316  // Analyse Sector
317  for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
318  {
319  // Create the multiplier for sector access
320  recordoffset = FAT_DIR_ENTRY_SIZE * item;
321 
322  // If the start position for the entry has been found
323  if (foundEnd==0)
324  if ( (dirSector==(x-1)) && (dirOffset==item) )
325  foundEnd = 1;
326 
327  // Start adding filename
328  if (foundEnd)
329  {
330  if (entryCount==0)
331  {
332  // Short filename
333  fatfs_sfn_create_entry(shortfilename, size, startCluster, &shortEntry, dir);
334 
335 #if FATFS_INC_TIME_DATE_SUPPORT
336  // Update create, access & modify time & date
337  fatfs_update_timestamps(&shortEntry, 1, 1, 1);
338 #endif
339 
340  memcpy(&fs->currentsector.sector[recordoffset], &shortEntry, sizeof(shortEntry));
341 
342  // Writeback
343  return fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1);
344  }
345 #if FATFS_INC_LFN_SUPPORT
346  else
347  {
348  entryCount--;
349 
350  // Copy entry to directory buffer
351  fatfs_filename_to_lfn(filename, &fs->currentsector.sector[recordoffset], entryCount, checksum);
352  dirtySector = 1;
353  }
354 #endif
355  }
356  } // End of if
357 
358  // Write back to disk before loading another sector
359  if (dirtySector)
360  {
361  if (!fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1))
362  return 0;
363 
364  dirtySector = 0;
365  }
366  }
367  else
368  return 0;
369  } // End of while loop
370 
371  return 0;
372 }
373 #endif
fatfs_fat_add_cluster_to_chain
int fatfs_fat_add_cluster_to_chain(struct fatfs *fs, uint32 start_cluster, uint32 newEntry)
Definition: fat_table.c:414
fatfs_update_timestamps
int fatfs_update_timestamps(struct fat_dir_entry *directoryEntry, int create, int modify, int access)
fat_write.h
fat_access.h
fat_table.h
uint8
unsigned char uint8
Definition: fat_types.h:15
fatfs_add_file_entry
int fatfs_add_file_entry(struct fatfs *fs, uint32 dirCluster, char *filename, char *shortfilename, uint32 startCluster, uint32 size, int dir)
Definition: fat_write.c:266
FAT32_LAST_CLUSTER
#define FAT32_LAST_CLUSTER
Definition: fat_defs.h:108
fatfs_sfn_create_entry
void fatfs_sfn_create_entry(char *shortfilename, uint32 size, uint32 startCluster, struct fat_dir_entry *entry, int dir)
Definition: fat_misc.c:226
string.h
fatfs_lfn_entries_required
int fatfs_lfn_entries_required(char *filename)
Definition: fat_misc.c:173
directoryEntry
Definition: ubixfs.h:98
fatfs_set_fs_info_next_free_cluster
void fatfs_set_fs_info_next_free_cluster(struct fatfs *fs, uint32 newValue)
Definition: fat_table.c:260
FILE_HEADER_BLANK
#define FILE_HEADER_BLANK
Definition: fat_defs.h:82
fat_defs.h
memcpy
void * memcpy(const void *dst, const void *src, size_t length)
fatfs_find_blank_cluster
int fatfs_find_blank_cluster(struct fatfs *fs, uint32 start_cluster, uint32 *free_cluster)
Definition: fat_table.c:288
fs
Definition: fs.h:260
fatfs_entry_lfn_text
int fatfs_entry_lfn_text(struct fat_dir_entry *entry)
Definition: fat_misc.c:110
FAT_DIR_ENTRY_SIZE
#define FAT_DIR_ENTRY_SIZE
Definition: fat_defs.h:67
fatfs_sector_reader
int fatfs_sector_reader(struct fatfs *fs, uint32 start_cluster, uint32 offset, uint8 *target)
Definition: fat_access.c:213
fatfs_write_sector
int fatfs_write_sector(struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target)
Definition: fat_access.c:311
FAT_SECTOR_SIZE
#define FAT_SECTOR_SIZE
Definition: fat_opts.h:70
fat_misc.h
fat_string.h
fat_dir_entry
Definition: fat_defs.h:112
fatfs_filename_to_lfn
void fatfs_filename_to_lfn(char *filename, uint8 *buffer, int entry, uint8 sfnChk)
Definition: fat_misc.c:186
fatfs_add_free_space
int fatfs_add_free_space(struct fatfs *fs, uint32 *startCluster, uint32 clusters)
Definition: fat_write.c:45
memset
void * memset(void *dst, int c, size_t length)
fatfs_allocate_free_space
int fatfs_allocate_free_space(struct fatfs *fs, int newFile, uint32 *startCluster, uint32 size)
Definition: fat_write.c:82
FAT_DIR_ENTRIES_PER_SECTOR
#define FAT_DIR_ENTRIES_PER_SECTOR
Definition: fat_access.h:19
uint16
unsigned short uint16
Definition: fat_types.h:16
FILE_HEADER_DELETED
#define FILE_HEADER_DELETED
Definition: fat_defs.h:83
fatfs_fat_set_cluster
int fatfs_fat_set_cluster(struct fatfs *fs, uint32 cluster, uint32 next_cluster)
Definition: fat_table.c:349
uint32
unsigned long uint32
Definition: fat_types.h:23
fatfs
Definition: fat_access.h:57