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_file.h"
31 #include "fx_utility.h"
32 #ifdef FX_ENABLE_FAULT_TOLERANT
33 #include "fx_fault_tolerant.h"
34 #endif /* FX_ENABLE_FAULT_TOLERANT */
35
36
37 /**************************************************************************/
38 /* */
39 /* FUNCTION RELEASE */
40 /* */
41 /* _fx_directory_delete PORTABLE C */
42 /* 6.1 */
43 /* AUTHOR */
44 /* */
45 /* William E. Lamie, Microsoft Corporation */
46 /* */
47 /* DESCRIPTION */
48 /* */
49 /* This function first attempts to find the specified directory. */
50 /* If found, the directory is examined to make sure it is empty. If */
51 /* the directory is not empty, an error code is returned to the */
52 /* caller. Otherwise, the directory will be deleted and its clusters */
53 /* will be made available. */
54 /* */
55 /* INPUT */
56 /* */
57 /* media_ptr Media control block pointer */
58 /* directory_name Directory name to delete */
59 /* */
60 /* OUTPUT */
61 /* */
62 /* return status */
63 /* */
64 /* CALLS */
65 /* */
66 /* _fx_directory_entry_read Read a directory entry */
67 /* _fx_directory_entry_write Write the new directory entry */
68 /* _fx_directory_search Search for the file name in */
69 /* the directory structure */
70 /* _fx_utility_logical_sector_flush Flush the written log sector */
71 /* _fx_utility_FAT_entry_read Read FAT entries to calculate */
72 /* the sub-directory size */
73 /* _fx_utility_FAT_entry_write Write FAT entry */
74 /* _fx_utility_FAT_flush Flush FAT cache */
75 /* _fx_fault_tolerant_transaction_start Start fault tolerant */
76 /* transaction */
77 /* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
78 /* _fx_fault_tolerant_recover Recover FAT chain */
79 /* _fx_fault_tolerant_reset_log_file Reset the log file */
80 /* */
81 /* CALLED BY */
82 /* */
83 /* Application Code */
84 /* */
85 /* RELEASE HISTORY */
86 /* */
87 /* DATE NAME DESCRIPTION */
88 /* */
89 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
90 /* 09-30-2020 William E. Lamie Modified comment(s), */
91 /* resulting in version 6.1 */
92 /* */
93 /**************************************************************************/
_fx_directory_delete(FX_MEDIA * media_ptr,CHAR * directory_name)94 UINT _fx_directory_delete(FX_MEDIA *media_ptr, CHAR *directory_name)
95 {
96
97 UINT status;
98 ULONG cluster, next_cluster;
99 ULONG i, directory_size;
100 FX_DIR_ENTRY dir_entry;
101 FX_DIR_ENTRY search_directory;
102 FX_DIR_ENTRY search_entry;
103
104
105
106 #ifndef FX_MEDIA_STATISTICS_DISABLE
107
108 /* Increment the number of times this service has been called. */
109 media_ptr -> fx_media_directory_deletes++;
110 #endif
111
112 /* Setup pointer to media name buffer. */
113 dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
114
115 /* Setup search pointer to media name buffer. */
116 search_directory.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 2;
117
118 /* Setup search entry pointer to media name buffer. */
119 search_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 3;
120
121 /* Clear the short name string of the three file names that will be worked with. */
122 dir_entry.fx_dir_entry_short_name[0] = 0;
123 search_directory.fx_dir_entry_short_name[0] = 0;
124 search_entry.fx_dir_entry_short_name[0] = 0;
125
126 /* Check the media to make sure it is open. */
127 if (media_ptr -> fx_media_id != FX_MEDIA_ID)
128 {
129
130 /* Return the media not opened error. */
131 return(FX_MEDIA_NOT_OPEN);
132 }
133
134 /* If trace is enabled, insert this event into the trace buffer. */
135 FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_DELETE, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
136
137 /* Protect against other threads accessing the media. */
138 FX_PROTECT
139
140 #ifdef FX_ENABLE_FAULT_TOLERANT
141 /* Start transaction. */
142 _fx_fault_tolerant_transaction_start(media_ptr);
143 #endif /* FX_ENABLE_FAULT_TOLERANT */
144
145 /* Check for write protect at the media level (set by driver). */
146 if (media_ptr -> fx_media_driver_write_protect)
147 {
148
149 #ifdef FX_ENABLE_FAULT_TOLERANT
150 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
151 #endif /* FX_ENABLE_FAULT_TOLERANT */
152
153 /* Release media protection. */
154 FX_UNPROTECT
155
156 /* Return write protect error. */
157 return(FX_WRITE_PROTECT);
158 }
159
160 /* Search the system for the supplied directory name. */
161 status = _fx_directory_search(media_ptr, directory_name, &dir_entry, FX_NULL, FX_NULL);
162
163 /* Determine if the search was successful. */
164 if (status != FX_SUCCESS)
165 {
166
167 #ifdef FX_ENABLE_FAULT_TOLERANT
168 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
169 #endif /* FX_ENABLE_FAULT_TOLERANT */
170
171 /* Release media protection. */
172 FX_UNPROTECT
173
174 /* Return the error code. */
175 return(status);
176 }
177
178 /* Check to make sure the found entry is a directory. */
179 if (!(dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_DIRECTORY)))
180 {
181
182 #ifdef FX_ENABLE_FAULT_TOLERANT
183 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
184 #endif /* FX_ENABLE_FAULT_TOLERANT */
185
186 /* Release media protection. */
187 FX_UNPROTECT
188
189 /* Return the not a directory error code. */
190 return(FX_NOT_DIRECTORY);
191 }
192
193 /* Check if the entry is read only */
194 if (dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_READ_ONLY))
195 {
196 #ifdef FX_ENABLE_FAULT_TOLERANT
197 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
198 #endif /* FX_ENABLE_FAULT_TOLERANT */
199
200 /* Release media protection. */
201 FX_UNPROTECT
202
203 /* Return the not a directory error code. */
204 return(FX_WRITE_PROTECT);
205 }
206
207 /* Copy the directory entry to the search directory structure for
208 looking at the specified sub-directory contents. */
209 search_directory = dir_entry;
210
211 /* Ensure that the search directory's last search cluster is cleared. */
212 search_directory.fx_dir_entry_last_search_cluster = 0;
213
214
215 /* Calculate the directory size by counting the allocated
216 clusters for it. */
217 i = 0;
218 cluster = search_directory.fx_dir_entry_cluster;
219 while (cluster < media_ptr -> fx_media_fat_reserved)
220 {
221
222 /* Increment the cluster count. */
223 i++;
224
225 /* Read the next FAT entry. */
226 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
227
228 /* Check the return status. */
229 if (status != FX_SUCCESS)
230 {
231
232 #ifdef FX_ENABLE_FAULT_TOLERANT
233 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
234 #endif /* FX_ENABLE_FAULT_TOLERANT */
235
236 /* Release media protection. */
237 FX_UNPROTECT
238
239 /* Return the bad status. */
240 return(status);
241 }
242
243 if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
244 {
245 #ifdef FX_ENABLE_FAULT_TOLERANT
246 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
247 #endif /* FX_ENABLE_FAULT_TOLERANT */
248
249 /* Release media protection. */
250 FX_UNPROTECT
251
252 /* Return the bad status. */
253 return(FX_FAT_READ_ERROR);
254 }
255
256 cluster = next_cluster;
257 }
258
259 /* Now we can calculate the directory size. */
260 directory_size = (((ULONG)media_ptr -> fx_media_bytes_per_sector) *
261 ((ULONG)media_ptr -> fx_media_sectors_per_cluster) * i) /
262 (ULONG)FX_DIR_ENTRY_SIZE;
263
264 /* Also save this in the directory entry so we don't have to
265 calculate it later. */
266 search_directory.fx_dir_entry_file_size = directory_size;
267
268 /* Make sure the new name is not in the current directory. */
269 /* The first two entries are skipped because they are just part of the sub-directory. */
270 i = 2;
271
272 do
273 {
274
275 /* Read an entry from the directory. */
276 status = _fx_directory_entry_read(media_ptr, &search_directory, &i, &search_entry);
277
278 /* Check for error status. */
279 if (status != FX_SUCCESS)
280 {
281
282 #ifdef FX_ENABLE_FAULT_TOLERANT
283 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
284 #endif /* FX_ENABLE_FAULT_TOLERANT */
285
286 /* Release media protection. */
287 FX_UNPROTECT
288
289 /* Return error condition. */
290 return(status);
291 }
292
293 /* Determine if this is the last directory entry. */
294 if (search_entry.fx_dir_entry_name[0] == FX_DIR_ENTRY_DONE)
295 {
296 break;
297 }
298
299
300 /* Determine if this is an empty entry. */
301 if ((UCHAR)search_entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_FREE)
302 {
303
304 #ifdef FX_ENABLE_FAULT_TOLERANT
305 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
306 #endif /* FX_ENABLE_FAULT_TOLERANT */
307
308 /* Release media protection. */
309 FX_UNPROTECT
310
311 /* Return error status. */
312 return(FX_DIR_NOT_EMPTY);
313 }
314
315 i++;
316 } while (i < directory_size);
317
318 /* At this point, we are going to delete the empty directory. */
319
320 #ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
321
322 /* Invalidate the directory search saved information. */
323 media_ptr -> fx_media_last_found_name[0] = FX_NULL;
324 #endif
325
326 /* Mark the sub-directory entry as available. */
327 dir_entry.fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
328 dir_entry.fx_dir_entry_short_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
329
330 /* Now write out the directory entry. */
331 status = _fx_directory_entry_write(media_ptr, &dir_entry);
332
333 /* Determine if the write was successful. */
334 if (status != FX_SUCCESS)
335 {
336
337 #ifdef FX_ENABLE_FAULT_TOLERANT
338 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
339 #endif /* FX_ENABLE_FAULT_TOLERANT */
340
341 /* Release media protection. */
342 FX_UNPROTECT
343
344 /* Return the error code. */
345 return(status);
346 }
347
348
349 /* Walk through the directory's clusters and release them. */
350 cluster = search_directory.fx_dir_entry_cluster;
351
352 while (cluster < media_ptr -> fx_media_fat_reserved)
353 {
354
355 /* Increment the cluster count. */
356 i++;
357
358
359 /* Read the next FAT entry. */
360 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
361
362 /* Check the return status. */
363 if (status != FX_SUCCESS)
364 {
365
366 #ifdef FX_ENABLE_FAULT_TOLERANT
367 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
368 #endif /* FX_ENABLE_FAULT_TOLERANT */
369
370 /* Release media protection. */
371 FX_UNPROTECT
372
373 /* Return the bad status. */
374 return(status);
375 }
376
377 if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
378 {
379
380 #ifdef FX_ENABLE_FAULT_TOLERANT
381 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
382 #endif /* FX_ENABLE_FAULT_TOLERANT */
383
384 /* Release media protection. */
385 FX_UNPROTECT
386
387 /* Return the bad status. */
388 return(FX_FAT_READ_ERROR);
389 }
390
391 /* Release the current cluster. */
392
393 status = _fx_utility_FAT_entry_write(media_ptr, cluster, FX_FREE_CLUSTER);
394
395 /* Check the return status. */
396 if (status != FX_SUCCESS)
397 {
398
399 #ifdef FX_ENABLE_FAULT_TOLERANT
400 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
401 #endif /* FX_ENABLE_FAULT_TOLERANT */
402
403 /* Release media protection. */
404 FX_UNPROTECT
405
406 /* Return the bad status. */
407 return(status);
408 }
409
410 /* Increment the number of available clusters for the media. */
411 media_ptr -> fx_media_available_clusters++;
412
413 /* Copy next cluster to current cluster. */
414 cluster = next_cluster;
415 }
416
417 #ifdef FX_FAULT_TOLERANT
418
419 /* Flush the cached individual FAT entries */
420 _fx_utility_FAT_flush(media_ptr);
421 #endif
422
423 /* Flush the logical sector cache. */
424 status = _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64)(media_ptr -> fx_media_sectors_per_FAT), FX_FALSE);
425
426 #ifdef FX_ENABLE_FAULT_TOLERANT
427 /* Check for a bad status. */
428 if (status != FX_SUCCESS)
429 {
430
431 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
432
433 /* Release media protection. */
434 FX_UNPROTECT
435
436 /* Return the bad status. */
437 return(status);
438 }
439
440 /* End transaction. */
441 status = _fx_fault_tolerant_transaction_end(media_ptr);
442 #endif /* FX_ENABLE_FAULT_TOLERANT */
443
444 /* Release media protection. */
445 FX_UNPROTECT
446
447 /* Directory delete is complete, return status. */
448 return(status);
449 }
450
451