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