1 |
|
|
/**************************************************************************/ |
2 |
|
|
/* */ |
3 |
|
|
/* Copyright (c) Microsoft Corporation. All rights reserved. */ |
4 |
|
|
/* */ |
5 |
|
|
/* This software is licensed under the Microsoft Software License */ |
6 |
|
|
/* Terms for Microsoft Azure RTOS. Full text of the license can be */ |
7 |
|
|
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ |
8 |
|
|
/* and in the root directory of this software. */ |
9 |
|
|
/* */ |
10 |
|
|
/**************************************************************************/ |
11 |
|
|
|
12 |
|
|
|
13 |
|
|
/**************************************************************************/ |
14 |
|
|
/**************************************************************************/ |
15 |
|
|
/** */ |
16 |
|
|
/** FileX Component */ |
17 |
|
|
/** */ |
18 |
|
|
/** Directory */ |
19 |
|
|
/** */ |
20 |
|
|
/**************************************************************************/ |
21 |
|
|
/**************************************************************************/ |
22 |
|
|
|
23 |
|
|
#define FX_SOURCE_CODE |
24 |
|
|
|
25 |
|
|
|
26 |
|
|
/* Include necessary system files. */ |
27 |
|
|
|
28 |
|
|
#include "fx_api.h" |
29 |
|
|
#include "fx_system.h" |
30 |
|
|
#include "fx_directory.h" |
31 |
|
|
#include "fx_utility.h" |
32 |
|
|
#ifdef FX_ENABLE_EXFAT |
33 |
|
|
#include "fx_directory_exFAT.h" |
34 |
|
|
#endif /* FX_ENABLE_EXFAT */ |
35 |
|
|
|
36 |
|
|
|
37 |
|
|
/**************************************************************************/ |
38 |
|
|
/* */ |
39 |
|
|
/* FUNCTION RELEASE */ |
40 |
|
|
/* */ |
41 |
|
|
/* _fx_directory_free_search PORTABLE C */ |
42 |
|
|
/* 6.1.12 */ |
43 |
|
|
/* AUTHOR */ |
44 |
|
|
/* */ |
45 |
|
|
/* William E. Lamie, Microsoft Corporation */ |
46 |
|
|
/* */ |
47 |
|
|
/* DESCRIPTION */ |
48 |
|
|
/* */ |
49 |
|
|
/* This function searches the media for a free directory entry. */ |
50 |
|
|
/* */ |
51 |
|
|
/* INPUT */ |
52 |
|
|
/* */ |
53 |
|
|
/* media_ptr Media control block pointer */ |
54 |
|
|
/* directory_ptr Pointer to directory to */ |
55 |
|
|
/* search in */ |
56 |
|
|
/* entry_ptr Pointer to directory entry */ |
57 |
|
|
/* record */ |
58 |
|
|
/* */ |
59 |
|
|
/* OUTPUT */ |
60 |
|
|
/* */ |
61 |
|
|
/* return status */ |
62 |
|
|
/* */ |
63 |
|
|
/* CALLS */ |
64 |
|
|
/* */ |
65 |
|
|
/* _fx_directory_entry_read Read entries from directory */ |
66 |
|
|
/* _fx_directory_entry_write Write entries to directory */ |
67 |
|
|
/* _fx_utility_FAT_entry_read Read a FAT entry */ |
68 |
|
|
/* _fx_utility_FAT_entry_write Write a FAT entry */ |
69 |
|
|
/* _fx_utility_FAT_flush Flush written FAT entries */ |
70 |
|
|
/* _fx_utility_logical_sector_flush Flush logical sector cache */ |
71 |
|
|
/* _fx_utility_logical_sector_read Read logical sector */ |
72 |
|
|
/* _fx_utility_logical_sector_write Write logical sector */ |
73 |
|
|
/* */ |
74 |
|
|
/* CALLED BY */ |
75 |
|
|
/* */ |
76 |
|
|
/* FileX System Functions */ |
77 |
|
|
/* */ |
78 |
|
|
/* RELEASE HISTORY */ |
79 |
|
|
/* */ |
80 |
|
|
/* DATE NAME DESCRIPTION */ |
81 |
|
|
/* */ |
82 |
|
|
/* 05-19-2020 William E. Lamie Initial Version 6.0 */ |
83 |
|
|
/* 09-30-2020 William E. Lamie Modified comment(s), */ |
84 |
|
|
/* resulting in version 6.1 */ |
85 |
|
|
/* 07-29-2022 Bhupendra Naphade Modified comment(s), */ |
86 |
|
|
/* updated available cluster */ |
87 |
|
|
/* check for sub directory, */ |
88 |
|
|
/* resulting in version 6.1.12 */ |
89 |
|
|
/* */ |
90 |
|
|
/**************************************************************************/ |
91 |
|
74847 |
UINT _fx_directory_free_search(FX_MEDIA *media_ptr, FX_DIR_ENTRY *directory_ptr, FX_DIR_ENTRY *entry_ptr) |
92 |
|
|
{ |
93 |
|
|
|
94 |
|
|
ULONG i, j; |
95 |
|
|
UCHAR *work_ptr; |
96 |
|
|
UINT status, total_entries; |
97 |
|
|
ULONG entry_sector, entry_offset; |
98 |
|
|
ULONG FAT_index, FAT_value; |
99 |
|
|
ULONG cluster, total_clusters, clusters_needed; |
100 |
|
|
ULONG first_new_cluster, last_cluster, clusters; |
101 |
|
|
ULONG directory_index; |
102 |
|
|
ULONG directory_entries; |
103 |
|
|
ULONG logical_sector; |
104 |
|
|
FX_DIR_ENTRY *search_dir_ptr; |
105 |
|
|
ULONG free_entry_start; |
106 |
|
|
UINT sectors; |
107 |
|
|
|
108 |
|
|
FX_INT_SAVE_AREA |
109 |
|
|
|
110 |
|
|
|
111 |
|
|
#ifdef FX_ENABLE_EXFAT |
112 |
|
|
/* Check if media format is exFAT. */ |
113 |
|
|
if (media_ptr -> fx_media_FAT_type == FX_exFAT) |
114 |
|
|
{ |
115 |
|
|
|
116 |
|
|
/* Call exFAT specific function. */ |
117 |
|
|
return(_fx_directory_exFAT_free_search(media_ptr, directory_ptr, entry_ptr)); |
118 |
|
|
} |
119 |
|
|
#endif /* FX_ENABLE_EXFAT */ |
120 |
|
|
|
121 |
|
|
#ifndef FX_MEDIA_STATISTICS_DISABLE |
122 |
|
|
|
123 |
|
|
/* Increment the number of directory free entry search requests. */ |
124 |
|
74847 |
media_ptr -> fx_media_directory_free_searches++; |
125 |
|
|
#endif |
126 |
|
|
|
127 |
|
|
/* Initialize the entry sector values. */ |
128 |
|
74847 |
entry_sector = entry_offset = 0; |
129 |
|
|
|
130 |
|
|
/* Set the long file name flag to false. */ |
131 |
|
74847 |
entry_ptr -> fx_dir_entry_long_name_present = 0; |
132 |
|
|
|
133 |
|
|
/* Are there leading dots? */ |
134 |
✓✓ |
74847 |
if (entry_ptr -> fx_dir_entry_name[0] == '.') |
135 |
|
|
{ |
136 |
|
|
|
137 |
|
|
/* Is there more than 1 dot? */ |
138 |
✓✓ |
7 |
if (entry_ptr -> fx_dir_entry_name[1] == '.') |
139 |
|
|
{ |
140 |
|
|
/* Yes, consider the name invalid. */ |
141 |
|
1 |
return(FX_INVALID_NAME); |
142 |
|
|
} |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
/* Determine if a long file name is present. */ |
146 |
✓✓ |
761992 |
for (i = 0, j = 0; entry_ptr -> fx_dir_entry_name[i]; i++) |
147 |
|
|
{ |
148 |
|
|
|
149 |
|
|
/* Check for upper-case characters. */ |
150 |
✓✓✓✓
|
687147 |
if ((entry_ptr -> fx_dir_entry_name[i] >= 'A') && (entry_ptr -> fx_dir_entry_name[i] <= 'Z')) |
151 |
|
|
{ |
152 |
|
494738 |
continue; |
153 |
|
|
} |
154 |
|
|
/* Check for numeric characters. */ |
155 |
✓✓✓✓
|
192409 |
else if ((entry_ptr -> fx_dir_entry_name[i] >= '0') && (entry_ptr -> fx_dir_entry_name[i] <= '9')) |
156 |
|
|
{ |
157 |
|
121505 |
continue; |
158 |
|
|
} |
159 |
|
|
/* Check for any lower-case characters. */ |
160 |
✓✓✓✓
|
70904 |
else if ((entry_ptr -> fx_dir_entry_name[i] >= 'a') && (entry_ptr -> fx_dir_entry_name[i] <= 'z')) |
161 |
|
|
{ |
162 |
|
15878 |
entry_ptr -> fx_dir_entry_long_name_present = 1; |
163 |
|
|
} |
164 |
|
|
/* Check for a space in the middle of the name. */ |
165 |
✓✓ |
55026 |
else if (entry_ptr -> fx_dir_entry_name[i] == ' ') |
166 |
|
|
{ |
167 |
|
15 |
entry_ptr -> fx_dir_entry_long_name_present = 1; |
168 |
|
|
} |
169 |
|
|
/* Check for a dot in the name. */ |
170 |
✓✓ |
55011 |
else if (entry_ptr -> fx_dir_entry_name[i] == '.') |
171 |
|
|
{ |
172 |
|
|
/* Determine if this is the first dot detected. */ |
173 |
✓✓ |
54497 |
if (j == 0) |
174 |
|
|
{ |
175 |
|
|
/* First dot, remember where it was. */ |
176 |
|
54487 |
j = i; |
177 |
|
|
|
178 |
|
|
/* Determine if this is a leading dot. */ |
179 |
✓✓ |
54487 |
if (i == 0) |
180 |
|
|
{ |
181 |
|
|
|
182 |
|
|
/* Leading dot detected, treat as a long filename. */ |
183 |
|
6 |
entry_ptr -> fx_dir_entry_long_name_present = 1; |
184 |
|
|
} |
185 |
|
|
} |
186 |
|
|
else |
187 |
|
|
{ |
188 |
|
|
/* Second dot detected, must have a long file name. */ |
189 |
|
10 |
entry_ptr -> fx_dir_entry_long_name_present = 1; |
190 |
|
|
} |
191 |
|
|
} |
192 |
|
|
/* Check for a special 0xE5 character. */ |
193 |
✓✓ |
514 |
else if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] == (UCHAR)0xE5) |
194 |
|
|
{ |
195 |
|
10 |
entry_ptr -> fx_dir_entry_long_name_present = 1; |
196 |
|
|
} |
197 |
|
|
/* Check for code point value greater than 127. */ |
198 |
✓✓ |
504 |
else if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] > (UCHAR)127) |
199 |
|
|
{ |
200 |
|
1 |
continue; |
201 |
|
|
} |
202 |
|
|
/* Check for any special characters. */ |
203 |
✓✓ |
503 |
else if ((entry_ptr -> fx_dir_entry_name[i] == '~') || |
204 |
✓✓ |
495 |
(entry_ptr -> fx_dir_entry_name[i] == '-') || |
205 |
✓✓ |
423 |
(entry_ptr -> fx_dir_entry_name[i] == '_') || |
206 |
✓✓ |
23 |
(entry_ptr -> fx_dir_entry_name[i] == '}') || |
207 |
✓✓ |
22 |
(entry_ptr -> fx_dir_entry_name[i] == '{') || |
208 |
✓✓ |
21 |
(entry_ptr -> fx_dir_entry_name[i] == '(') || |
209 |
✓✓ |
19 |
(entry_ptr -> fx_dir_entry_name[i] == ')') || |
210 |
✓✓ |
17 |
(entry_ptr -> fx_dir_entry_name[i] == '`') || |
211 |
✓✓ |
16 |
(entry_ptr -> fx_dir_entry_name[i] == '\'') || |
212 |
✓✓ |
14 |
(entry_ptr -> fx_dir_entry_name[i] == '!') || |
213 |
✓✓ |
13 |
(entry_ptr -> fx_dir_entry_name[i] == '#') || |
214 |
✓✓ |
12 |
(entry_ptr -> fx_dir_entry_name[i] == '$') || |
215 |
✓✓ |
11 |
(entry_ptr -> fx_dir_entry_name[i] == '&') || |
216 |
✓✓ |
10 |
(entry_ptr -> fx_dir_entry_name[i] == '@') || |
217 |
✓✓ |
9 |
(entry_ptr -> fx_dir_entry_name[i] == '^') || |
218 |
✓✓ |
8 |
(entry_ptr -> fx_dir_entry_name[i] == '%')) |
219 |
|
|
{ |
220 |
|
496 |
continue; |
221 |
|
|
} |
222 |
|
|
/* Check for long filename special characters. */ |
223 |
✓✓ |
7 |
else if ((entry_ptr -> fx_dir_entry_name[i] == '+') || |
224 |
✓✓ |
6 |
(entry_ptr -> fx_dir_entry_name[i] == ',') || |
225 |
✓✓ |
5 |
(entry_ptr -> fx_dir_entry_name[i] == ';') || |
226 |
✓✓ |
4 |
(entry_ptr -> fx_dir_entry_name[i] == '=') || |
227 |
✓✓ |
3 |
(entry_ptr -> fx_dir_entry_name[i] == '[') || |
228 |
✓✓ |
2 |
(entry_ptr -> fx_dir_entry_name[i] == ']')) |
229 |
|
|
{ |
230 |
|
6 |
entry_ptr -> fx_dir_entry_long_name_present = 1; |
231 |
|
|
} |
232 |
|
|
/* Something is wrong with the supplied name. */ |
233 |
|
|
else |
234 |
|
|
{ |
235 |
|
1 |
return(FX_INVALID_NAME); |
236 |
|
|
} |
237 |
|
|
} |
238 |
|
|
|
239 |
|
|
/* Determine if a dot was found. */ |
240 |
✓✓ |
74845 |
if (j != 0) |
241 |
|
|
{ |
242 |
|
|
|
243 |
|
|
/* Yes, Determine if the extension exceeds a 3 character extension. */ |
244 |
✓✓ |
54481 |
if ((i - j) > 4) |
245 |
|
|
{ |
246 |
|
|
|
247 |
|
|
/* Yes, long file name is present. */ |
248 |
|
5 |
entry_ptr -> fx_dir_entry_long_name_present = 1; |
249 |
|
|
} |
250 |
|
|
} |
251 |
|
|
|
252 |
|
|
/* Calculate the total entries needed. */ |
253 |
✓✓✓✓
|
74845 |
if ((i <= 12) && (entry_ptr -> fx_dir_entry_long_name_present == 0)) |
254 |
|
|
{ |
255 |
|
|
|
256 |
|
|
/* Initialize the total entries to 1. */ |
257 |
|
73731 |
total_entries = 1; |
258 |
|
|
|
259 |
|
|
/* Check for special instance of long file name. */ |
260 |
✓✓✓✓
|
73731 |
if ((j >= 9) || ((i - j) >= 9)) |
261 |
|
|
{ |
262 |
|
|
|
263 |
|
|
/* The dot is after 8 character or there is no dot and the name |
264 |
|
|
is greater than 8 character. */ |
265 |
|
7 |
entry_ptr -> fx_dir_entry_long_name_present = 1; |
266 |
|
7 |
total_entries = 2; |
267 |
|
|
} |
268 |
|
|
} |
269 |
|
|
else |
270 |
|
|
{ |
271 |
|
|
|
272 |
|
|
/* Long file name is present, calculate how many entries are needed |
273 |
|
|
to represent it. */ |
274 |
✓✓ |
1114 |
if (i % 13 == 0) |
275 |
|
|
{ |
276 |
|
|
/* Exact fit, just add one for the 8.3 short name. */ |
277 |
|
27 |
total_entries = i / 13 + 1; |
278 |
|
|
} |
279 |
|
|
else |
280 |
|
|
{ |
281 |
|
|
/* Non-exact fit, add two for 8.3 short name and overlap. */ |
282 |
|
1087 |
total_entries = i / 13 + 2; |
283 |
|
|
} |
284 |
|
|
} |
285 |
|
|
|
286 |
|
|
/* Determine if the search is in the root directory or in a |
287 |
|
|
sub-directory. Note: the directory search function clears the |
288 |
|
|
first character of the name for the root directory. */ |
289 |
✓✓ |
74845 |
if (directory_ptr -> fx_dir_entry_name[0]) |
290 |
|
|
{ |
291 |
|
|
|
292 |
|
|
/* Search for a free entry in a sub-directory. */ |
293 |
|
|
|
294 |
|
|
/* Pickup the number of entries in this directory. This was placed |
295 |
|
|
into the unused file size field. */ |
296 |
|
14739 |
directory_entries = (ULONG)directory_ptr -> fx_dir_entry_file_size; |
297 |
|
|
|
298 |
|
|
/* Point the search directory pointer to this entry. */ |
299 |
|
14739 |
search_dir_ptr = directory_ptr; |
300 |
|
|
|
301 |
|
|
/* Ensure that the search directory's last search cluster is cleared. */ |
302 |
|
14739 |
search_dir_ptr -> fx_dir_entry_last_search_cluster = 0; |
303 |
|
|
|
304 |
|
|
/* Set the initial index to 2, since the first two directory entries are |
305 |
|
|
always allocated. */ |
306 |
|
14739 |
directory_index = 2; |
307 |
|
|
} |
308 |
|
|
else |
309 |
|
|
{ |
310 |
|
|
|
311 |
|
|
/* Find a free entry in the root directory. */ |
312 |
|
|
|
313 |
|
|
/* Setup the number of directory entries. */ |
314 |
|
60106 |
directory_entries = (ULONG)media_ptr -> fx_media_root_directory_entries; |
315 |
|
|
|
316 |
|
|
/* Set the search pointer to NULL since we are working off of the |
317 |
|
|
root directory. */ |
318 |
|
60106 |
search_dir_ptr = FX_NULL; |
319 |
|
|
|
320 |
|
|
/* Set the initial index to 0, since the first entry of the root directory is valid. */ |
321 |
|
60106 |
directory_index = 0; |
322 |
|
|
} |
323 |
|
|
|
324 |
|
|
/* Loop through entries in the search directory. Yes, this is a |
325 |
|
|
linear search! */ |
326 |
|
74845 |
free_entry_start = directory_entries; |
327 |
|
|
do |
328 |
|
|
{ |
329 |
|
|
|
330 |
|
|
/* Read an entry from the directory. */ |
331 |
|
976091 |
status = _fx_directory_entry_read(media_ptr, search_dir_ptr, &directory_index, entry_ptr); |
332 |
|
|
|
333 |
|
|
/* Check for error status. */ |
334 |
✓✓ |
976091 |
if (status != FX_SUCCESS) |
335 |
|
|
{ |
336 |
|
7 |
return(status); |
337 |
|
|
} |
338 |
|
|
|
339 |
|
|
/* Determine if this is an empty entry. */ |
340 |
✓✓✓✓
|
976084 |
if ((((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0)) || |
341 |
✓✓ |
975528 |
((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_DONE)) |
342 |
|
|
{ |
343 |
|
|
|
344 |
|
|
/* Determine how many entries are needed. */ |
345 |
✓✓ |
77142 |
if (total_entries > 1) |
346 |
|
|
{ |
347 |
|
|
|
348 |
|
|
/* Multiple entries are needed for long file names. Mark this |
349 |
|
|
entry as free. */ |
350 |
✓✓ |
3420 |
if (entry_ptr -> fx_dir_entry_name[0] == FX_DIR_ENTRY_DONE) |
351 |
|
|
{ |
352 |
|
|
|
353 |
|
2890 |
entry_ptr -> fx_dir_entry_long_name_present = 0; |
354 |
|
2890 |
entry_ptr -> fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE; |
355 |
|
2890 |
entry_ptr -> fx_dir_entry_name[1] = (CHAR)0; |
356 |
|
|
|
357 |
|
|
/* Write out the directory entry. */ |
358 |
|
2890 |
status = _fx_directory_entry_write(media_ptr, entry_ptr); |
359 |
✓✓ |
2890 |
if(status != FX_SUCCESS) |
360 |
|
|
{ |
361 |
|
1 |
return(status); |
362 |
|
|
} |
363 |
|
|
|
364 |
|
|
/* Note that for long names we need to avoid holes in the middle, |
365 |
|
|
i.e. entries must be logically contiguous. */ |
366 |
|
|
} |
367 |
|
|
} |
368 |
|
|
|
369 |
|
|
/* Determine if we are at the first free entry. */ |
370 |
✓✓ |
77141 |
if (free_entry_start == directory_entries) |
371 |
|
|
{ |
372 |
|
|
|
373 |
|
|
/* Remember the start of the free entry. */ |
374 |
|
74861 |
free_entry_start = directory_index; |
375 |
|
74861 |
entry_sector = (ULONG)entry_ptr -> fx_dir_entry_log_sector; |
376 |
|
74861 |
entry_offset = entry_ptr -> fx_dir_entry_byte_offset; |
377 |
|
|
} |
378 |
|
|
|
379 |
|
|
/* Determine if there are enough free entries to satisfy the request. */ |
380 |
✓✓ |
77141 |
if ((directory_index - free_entry_start + 1) >= total_entries) |
381 |
|
|
{ |
382 |
|
|
|
383 |
|
|
/* Found an empty slot. Most pertinent information is already |
384 |
|
|
in the entry structure. */ |
385 |
|
|
|
386 |
|
|
/* Setup the the sector and the offset. */ |
387 |
|
74737 |
entry_ptr -> fx_dir_entry_log_sector = entry_sector; |
388 |
|
74737 |
entry_ptr -> fx_dir_entry_byte_offset = entry_offset; |
389 |
|
|
|
390 |
|
|
/* Initialize the additional directory entries. */ |
391 |
|
74737 |
entry_ptr -> fx_dir_entry_reserved = 0; |
392 |
|
74737 |
entry_ptr -> fx_dir_entry_created_time_ms = 0; |
393 |
|
|
|
394 |
|
|
/* Lockout interrupts for time/date access. */ |
395 |
|
74737 |
FX_DISABLE_INTS |
396 |
|
|
|
397 |
|
74737 |
entry_ptr -> fx_dir_entry_created_time = _fx_system_time; |
398 |
|
74737 |
entry_ptr -> fx_dir_entry_created_date = _fx_system_date; |
399 |
|
74737 |
entry_ptr -> fx_dir_entry_last_accessed_date = _fx_system_date; |
400 |
|
|
|
401 |
|
|
/* Restore interrupts. */ |
402 |
|
74737 |
FX_RESTORE_INTS |
403 |
|
|
|
404 |
|
|
/* Determine if a long file name is present. */ |
405 |
✓✓ |
74737 |
if (total_entries == 1) |
406 |
|
|
{ |
407 |
|
73722 |
entry_ptr -> fx_dir_entry_long_name_present = 0; |
408 |
|
|
} |
409 |
|
|
else |
410 |
|
|
{ |
411 |
|
1015 |
entry_ptr -> fx_dir_entry_long_name_present = 1; |
412 |
|
|
} |
413 |
|
|
|
414 |
|
|
/* Return a successful completion. */ |
415 |
|
74737 |
return(FX_SUCCESS); |
416 |
|
|
} |
417 |
|
|
} |
418 |
|
|
else |
419 |
|
|
{ |
420 |
|
|
|
421 |
|
|
/* Reset the free entry start. */ |
422 |
|
898942 |
free_entry_start = directory_entries; |
423 |
|
|
} |
424 |
|
|
|
425 |
|
|
/* Move to the next entry. */ |
426 |
|
901346 |
directory_index++; |
427 |
|
|
|
428 |
|
|
/* Determine if we have exceeded the number of entries in the current directory. */ |
429 |
✓✓ |
901346 |
if (directory_index >= directory_entries) |
430 |
|
|
{ |
431 |
|
|
|
432 |
|
|
/* Calculate how many sectors we need for the new directory entry. */ |
433 |
|
11511 |
sectors = ((total_entries * FX_DIR_ENTRY_SIZE) + (media_ptr -> fx_media_bytes_per_sector - 1))/ |
434 |
|
11511 |
media_ptr -> fx_media_bytes_per_sector; |
435 |
|
|
|
436 |
|
|
/* Now calculate how many clusters we need for the new directory entry. */ |
437 |
|
11511 |
clusters_needed = (sectors + (media_ptr -> fx_media_sectors_per_cluster - 1)) / media_ptr -> fx_media_sectors_per_cluster; |
438 |
|
|
|
439 |
|
|
/* Not enough empty entries were found. If the specified directory is a sub-directory, |
440 |
|
|
attempt to allocate another cluster to it. */ |
441 |
✓✓✓✓ ✓✓ |
11511 |
if (((search_dir_ptr) || (media_ptr -> fx_media_32_bit_FAT)) && (media_ptr -> fx_media_available_clusters >= clusters_needed)) |
442 |
|
|
{ |
443 |
|
|
|
444 |
|
|
/* Search for the additional clusters we need. */ |
445 |
|
11424 |
first_new_cluster = 0; |
446 |
|
11424 |
total_clusters = media_ptr -> fx_media_total_clusters; |
447 |
|
11424 |
last_cluster = 0; |
448 |
|
11424 |
FAT_index = media_ptr -> fx_media_cluster_search_start; |
449 |
|
11424 |
clusters = clusters_needed; |
450 |
|
|
|
451 |
|
|
/* Loop to find the needed clusters. */ |
452 |
✓✓ |
22921 |
while (clusters) |
453 |
|
|
{ |
454 |
|
|
|
455 |
|
|
/* Decrease the cluster count. */ |
456 |
|
11504 |
clusters--; |
457 |
|
|
|
458 |
|
|
/* Loop to find the first available cluster. */ |
459 |
|
|
do |
460 |
|
|
{ |
461 |
|
|
|
462 |
|
|
/* Make sure we stop looking after one pass through the FAT table. */ |
463 |
✓✓ |
11823 |
if (!total_clusters) |
464 |
|
|
{ |
465 |
|
|
|
466 |
|
|
/* Something is wrong with the media - the desired clusters were |
467 |
|
|
not found in the FAT table. */ |
468 |
|
1 |
return(FX_NO_MORE_SPACE); |
469 |
|
|
} |
470 |
|
|
|
471 |
|
|
/* Read FAT entry. */ |
472 |
|
11822 |
status = _fx_utility_FAT_entry_read(media_ptr, FAT_index, &FAT_value); |
473 |
|
|
|
474 |
|
|
/* Check for a bad status. */ |
475 |
✓✓ |
11822 |
if (status != FX_SUCCESS) |
476 |
|
|
{ |
477 |
|
|
|
478 |
|
|
/* Return the bad status. */ |
479 |
|
1 |
return(status); |
480 |
|
|
} |
481 |
|
|
|
482 |
|
|
/* Decrement the total cluster count. */ |
483 |
|
11821 |
total_clusters--; |
484 |
|
|
|
485 |
|
|
/* Determine if the FAT entry is free. */ |
486 |
✓✓ |
11821 |
if (FAT_value == FX_FREE_CLUSTER) |
487 |
|
|
{ |
488 |
|
|
|
489 |
|
|
/* Move cluster search pointer forward. */ |
490 |
|
11502 |
media_ptr -> fx_media_cluster_search_start = FAT_index + 1; |
491 |
|
|
|
492 |
|
|
/* Determine if this needs to be wrapped. */ |
493 |
✓✓ |
11502 |
if (media_ptr -> fx_media_cluster_search_start >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START)) |
494 |
|
|
{ |
495 |
|
|
|
496 |
|
|
/* Wrap the search to the beginning FAT entry. */ |
497 |
|
2 |
media_ptr -> fx_media_cluster_search_start = FX_FAT_ENTRY_START; |
498 |
|
|
} |
499 |
|
|
|
500 |
|
|
/* Break this loop. */ |
501 |
|
11502 |
break; |
502 |
|
|
} |
503 |
|
|
else |
504 |
|
|
{ |
505 |
|
|
|
506 |
|
|
/* FAT entry is not free... Advance the FAT index. */ |
507 |
|
319 |
FAT_index++; |
508 |
|
|
|
509 |
|
|
/* Determine if we need to wrap the FAT index around. */ |
510 |
✓✓ |
319 |
if (FAT_index >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START)) |
511 |
|
|
{ |
512 |
|
|
|
513 |
|
|
/* Wrap the search to the beginning FAT entry. */ |
514 |
|
12 |
FAT_index = FX_FAT_ENTRY_START; |
515 |
|
|
} |
516 |
|
|
} |
517 |
|
|
} while (FX_TRUE); |
518 |
|
|
|
519 |
|
|
/* We found an available cluster. We now need to clear all of entries in |
520 |
|
|
each of the cluster's sectors. */ |
521 |
|
|
|
522 |
|
|
/* Calculate the logical sector of this cluster. */ |
523 |
|
11502 |
logical_sector = ((ULONG) media_ptr -> fx_media_data_sector_start) + |
524 |
|
11502 |
((((ULONG) FAT_index) - FX_FAT_ENTRY_START) * |
525 |
|
11502 |
((ULONG) media_ptr -> fx_media_sectors_per_cluster)); |
526 |
|
|
|
527 |
|
|
/* Pickup the number of sectors for the next directory cluster. */ |
528 |
|
11502 |
sectors = media_ptr -> fx_media_sectors_per_cluster; |
529 |
|
|
|
530 |
|
|
/* Read the logical sector just for cache reasons. */ |
531 |
|
11502 |
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector, |
532 |
|
11502 |
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR); |
533 |
|
|
|
534 |
|
|
/* Check the return value. */ |
535 |
✓✓ |
11502 |
if (status != FX_SUCCESS) |
536 |
|
|
{ |
537 |
|
|
|
538 |
|
|
/* Return the error status. */ |
539 |
|
1 |
return(status); |
540 |
|
|
} |
541 |
|
|
|
542 |
|
|
/* Clear the entire first sector of the new sub-directory cluster. */ |
543 |
|
11501 |
work_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer; |
544 |
|
11501 |
i = 0; |
545 |
✓✓ |
379629 |
while (i < media_ptr -> fx_media_bytes_per_sector) |
546 |
|
|
{ |
547 |
|
|
|
548 |
|
|
/* Clear 4 bytes. */ |
549 |
|
368128 |
*((ULONG *)work_ptr) = (ULONG)0; |
550 |
|
|
|
551 |
|
|
/* Increment pointer. */ |
552 |
|
368128 |
work_ptr = work_ptr + sizeof(ULONG); |
553 |
|
|
|
554 |
|
|
/* Increment counter. */ |
555 |
|
368128 |
i = i + (ULONG)sizeof(ULONG); |
556 |
|
|
} |
557 |
|
|
|
558 |
|
|
/* Write the logical sector to ensure the zeros are written. */ |
559 |
|
11501 |
status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) logical_sector, |
560 |
|
11501 |
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR); |
561 |
|
|
|
562 |
|
|
/* Determine if the write was successful. */ |
563 |
✓✓ |
11501 |
if (status != FX_SUCCESS) |
564 |
|
|
{ |
565 |
|
|
|
566 |
|
|
/* Return the error code. */ |
567 |
|
1 |
return(status); |
568 |
|
|
} |
569 |
|
|
|
570 |
|
|
/* Determine if there are more sectors to clear in the first cluster of the new |
571 |
|
|
sub-directory. */ |
572 |
✓✓ |
11500 |
if (sectors > 1) |
573 |
|
|
{ |
574 |
|
|
|
575 |
|
|
/* Yes, invalidate all cached sectors that are contained in the newly allocated first |
576 |
|
|
cluster of the directory. */ |
577 |
|
|
|
578 |
|
|
/* Flush the internal logical sector cache. */ |
579 |
|
47 |
status = _fx_utility_logical_sector_flush(media_ptr, (ULONG64) (logical_sector + 1), (ULONG64) (sectors - 1), FX_TRUE); |
580 |
|
|
|
581 |
|
|
/* Determine if the flush was successful. */ |
582 |
✓✓ |
47 |
if (status != FX_SUCCESS) |
583 |
|
|
{ |
584 |
|
|
|
585 |
|
|
/* Return the error code. */ |
586 |
|
1 |
return(status); |
587 |
|
|
} |
588 |
|
|
|
589 |
|
|
/* Clear all additional sectors of new sub-directory. */ |
590 |
|
46 |
sectors--; |
591 |
✓✓ |
91 |
while (sectors) |
592 |
|
|
{ |
593 |
|
|
|
594 |
|
|
#ifndef FX_MEDIA_STATISTICS_DISABLE |
595 |
|
|
|
596 |
|
|
/* Increment the number of driver write sector(s) requests. */ |
597 |
|
46 |
media_ptr -> fx_media_driver_write_requests++; |
598 |
|
|
#endif |
599 |
|
|
|
600 |
|
|
/* Build Write request to the driver. */ |
601 |
|
46 |
media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE; |
602 |
|
46 |
media_ptr -> fx_media_driver_status = FX_IO_ERROR; |
603 |
|
46 |
media_ptr -> fx_media_driver_buffer = media_ptr -> fx_media_memory_buffer; |
604 |
|
46 |
media_ptr -> fx_media_driver_logical_sector = (ULONG)logical_sector + ((ULONG)sectors); |
605 |
|
46 |
media_ptr -> fx_media_driver_sectors = 1; |
606 |
|
46 |
media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR; |
607 |
|
|
|
608 |
|
|
/* Set the system write flag since we are writing a directory sector. */ |
609 |
|
46 |
media_ptr -> fx_media_driver_system_write = FX_TRUE; |
610 |
|
|
|
611 |
|
|
/* If trace is enabled, insert this event into the trace buffer. */ |
612 |
|
|
FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, ((ULONG)logical_sector) + ((ULONG)sectors), 1, media_ptr -> fx_media_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0) |
613 |
|
|
|
614 |
|
|
/* Invoke the driver to write the sector. */ |
615 |
|
46 |
(media_ptr -> fx_media_driver_entry) (media_ptr); |
616 |
|
|
|
617 |
|
|
/* Clear the system write flag. */ |
618 |
|
46 |
media_ptr -> fx_media_driver_system_write = FX_FALSE; |
619 |
|
|
|
620 |
|
|
/* Determine if an error occurred. */ |
621 |
✓✓ |
46 |
if (media_ptr -> fx_media_driver_status != FX_SUCCESS) |
622 |
|
|
{ |
623 |
|
|
|
624 |
|
|
/* Return error code. */ |
625 |
|
1 |
return(media_ptr -> fx_media_driver_status); |
626 |
|
|
} |
627 |
|
|
|
628 |
|
|
/* Decrease the number of sectors to clear. */ |
629 |
|
45 |
sectors--; |
630 |
|
|
} |
631 |
|
|
} |
632 |
|
|
|
633 |
|
|
/* Determine if we have found the first new cluster yet. */ |
634 |
✓✓ |
11498 |
if (first_new_cluster == 0) |
635 |
|
|
{ |
636 |
|
|
|
637 |
|
|
/* Remember the first new cluster. */ |
638 |
|
11418 |
first_new_cluster = FAT_index; |
639 |
|
|
} |
640 |
|
|
|
641 |
|
|
/* Check for a valid last cluster to link. */ |
642 |
✓✓ |
11498 |
if (last_cluster) |
643 |
|
|
{ |
644 |
|
|
|
645 |
|
|
/* Normal condition - link the last cluster with the new |
646 |
|
|
found cluster. */ |
647 |
|
80 |
status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, FAT_index); |
648 |
|
|
|
649 |
|
|
/* Check for a bad FAT write status. */ |
650 |
✓✓ |
80 |
if (status != FX_SUCCESS) |
651 |
|
|
{ |
652 |
|
|
|
653 |
|
|
/* Return the bad status. */ |
654 |
|
1 |
return(status); |
655 |
|
|
} |
656 |
|
|
} |
657 |
|
|
|
658 |
|
|
/* Otherwise, remember the new FAT index as the last. */ |
659 |
|
11497 |
last_cluster = FAT_index; |
660 |
|
|
|
661 |
|
|
/* Move to the next FAT entry. */ |
662 |
|
11497 |
FAT_index = media_ptr -> fx_media_cluster_search_start; |
663 |
|
|
} |
664 |
|
|
|
665 |
|
|
/* Place an end-of-file marker on the last cluster. */ |
666 |
|
11417 |
status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last); |
667 |
|
|
|
668 |
|
|
/* Check for a bad FAT write status. */ |
669 |
✓✓ |
11417 |
if (status != FX_SUCCESS) |
670 |
|
|
{ |
671 |
|
|
|
672 |
|
|
/* Return the bad status. */ |
673 |
|
1 |
return(status); |
674 |
|
|
} |
675 |
|
|
|
676 |
|
|
#ifdef FX_FAULT_TOLERANT |
677 |
|
|
|
678 |
|
|
/* Ensure the new FAT chain is properly written to the media. */ |
679 |
|
|
|
680 |
|
|
/* Flush the cached individual FAT entries */ |
681 |
|
|
_fx_utility_FAT_flush(media_ptr); |
682 |
|
|
#endif |
683 |
|
|
|
684 |
|
|
/* Now the new cluster needs to be linked to the sub-directory. */ |
685 |
✓✓ |
11416 |
if (search_dir_ptr) |
686 |
|
|
{ |
687 |
|
4388 |
cluster = search_dir_ptr -> fx_dir_entry_cluster; |
688 |
|
|
} |
689 |
|
|
else |
690 |
|
|
{ |
691 |
|
7028 |
cluster = media_ptr -> fx_media_root_cluster_32; |
692 |
|
|
} |
693 |
|
|
|
694 |
|
|
/* Initialize loop variables. */ |
695 |
|
11416 |
last_cluster = 0; |
696 |
|
11416 |
i = 0; |
697 |
|
|
|
698 |
|
|
/* Follow the link of FAT entries. */ |
699 |
✓✓ |
48085 |
while (cluster < media_ptr -> fx_media_fat_reserved) |
700 |
|
|
{ |
701 |
|
|
|
702 |
|
|
/* Read the current cluster entry from the FAT. */ |
703 |
|
36673 |
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &FAT_value); |
704 |
|
36673 |
i++; |
705 |
|
|
|
706 |
|
|
/* Check the return value. */ |
707 |
✓✓ |
36673 |
if (status != FX_SUCCESS) |
708 |
|
|
{ |
709 |
|
|
|
710 |
|
|
/* Return the error status. */ |
711 |
|
1 |
return(status); |
712 |
|
|
} |
713 |
|
|
|
714 |
|
|
/* Determine if the FAT read was invalid. */ |
715 |
✓✓✓✓ ✓✓ |
36672 |
if ((cluster < FX_FAT_ENTRY_START) || (cluster == FAT_value) || (i > media_ptr -> fx_media_total_clusters)) |
716 |
|
|
{ |
717 |
|
|
|
718 |
|
|
/* Return the bad status. */ |
719 |
|
3 |
return(FX_FAT_READ_ERROR); |
720 |
|
|
} |
721 |
|
|
|
722 |
|
|
/* Save the last valid cluster. */ |
723 |
|
36669 |
last_cluster = cluster; |
724 |
|
|
|
725 |
|
|
/* Setup for the next cluster. */ |
726 |
|
36669 |
cluster = FAT_value; |
727 |
|
|
} |
728 |
|
|
|
729 |
|
|
/* Decrease the available clusters in the media. */ |
730 |
|
11412 |
media_ptr -> fx_media_available_clusters = media_ptr -> fx_media_available_clusters - clusters_needed; |
731 |
|
|
|
732 |
|
|
/* Increase the number of directory entries. */ |
733 |
|
11412 |
directory_entries = directory_entries + ((clusters_needed * media_ptr -> fx_media_sectors_per_cluster) * media_ptr -> fx_media_bytes_per_sector) / FX_DIR_ENTRY_SIZE; |
734 |
|
|
|
735 |
|
|
/* Determine if we need to reset the free entry start since we changed the |
736 |
|
|
number of directory entries. If the last entry was not free, then we |
737 |
|
|
should definitely reset the free entry start. */ |
738 |
✓✓✓✓
|
11412 |
if (!(((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR) FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0))) |
739 |
|
|
{ |
740 |
|
|
|
741 |
|
|
/* Reset the free entry start to indicate we haven't found a starting free entry yet. */ |
742 |
|
11134 |
free_entry_start = directory_entries; |
743 |
|
|
} |
744 |
|
|
|
745 |
|
|
/* Update the directory size field. */ |
746 |
|
11412 |
directory_ptr -> fx_dir_entry_file_size = directory_entries; |
747 |
|
|
|
748 |
|
|
/* Defer the update of the FAT entry and the last cluster of the current |
749 |
|
|
directory entry until after the new cluster is initialized and written out. */ |
750 |
|
|
|
751 |
|
|
/* Determine if a FAT32 is present. */ |
752 |
✓✓✓✓
|
11412 |
if ((media_ptr -> fx_media_32_bit_FAT) && (search_dir_ptr == FX_NULL)) |
753 |
|
|
{ |
754 |
|
|
|
755 |
|
|
/* Change root directory entry count - FAT32 has a variable sized root directory. */ |
756 |
|
7028 |
media_ptr -> fx_media_root_directory_entries = directory_entries; |
757 |
|
|
} |
758 |
|
|
|
759 |
|
|
/* At this point, link up the last cluster with the new cluster. */ |
760 |
|
11412 |
status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, first_new_cluster); |
761 |
|
|
|
762 |
|
|
/* Check the return value. */ |
763 |
✓✓ |
11412 |
if (status != FX_SUCCESS) |
764 |
|
|
{ |
765 |
|
|
|
766 |
|
|
/* Return the error status. */ |
767 |
|
1 |
return(status); |
768 |
|
|
} |
769 |
|
|
|
770 |
|
|
#ifdef FX_FAULT_TOLERANT |
771 |
|
|
|
772 |
|
|
/* Flush the cached individual FAT entries */ |
773 |
|
|
_fx_utility_FAT_flush(media_ptr); |
774 |
|
|
#endif |
775 |
|
|
} |
776 |
|
|
} |
777 |
✓✓ |
901333 |
} while (directory_index < directory_entries); |
778 |
|
|
|
779 |
|
|
/* Return FX_NO_MORE_SPACE status to the caller. */ |
780 |
|
87 |
return(FX_NO_MORE_SPACE); |
781 |
|
|
} |
782 |
|
|
|