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