GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_directory_delete.c Lines: 79 79 100.0 %
Date: 2026-03-06 18:49:02 Branches: 42 42 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
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_file.h"
32
#include "fx_utility.h"
33
#ifdef FX_ENABLE_FAULT_TOLERANT
34
#include "fx_fault_tolerant.h"
35
#endif /* FX_ENABLE_FAULT_TOLERANT */
36
37
38
/**************************************************************************/
39
/*                                                                        */
40
/*  FUNCTION                                               RELEASE        */
41
/*                                                                        */
42
/*    _fx_directory_delete                                PORTABLE C      */
43
/*                                                           6.1          */
44
/*  AUTHOR                                                                */
45
/*                                                                        */
46
/*    William E. Lamie, Microsoft Corporation                             */
47
/*                                                                        */
48
/*  DESCRIPTION                                                           */
49
/*                                                                        */
50
/*    This function first attempts to find the specified directory.       */
51
/*    If found, the directory is examined to make sure it is empty.  If   */
52
/*    the directory is not empty, an error code is returned to the        */
53
/*    caller.  Otherwise, the directory will be deleted and its clusters  */
54
/*    will be made available.                                             */
55
/*                                                                        */
56
/*  INPUT                                                                 */
57
/*                                                                        */
58
/*    media_ptr                             Media control block pointer   */
59
/*    directory_name                        Directory name to delete      */
60
/*                                                                        */
61
/*  OUTPUT                                                                */
62
/*                                                                        */
63
/*    return status                                                       */
64
/*                                                                        */
65
/*  CALLS                                                                 */
66
/*                                                                        */
67
/*    _fx_directory_entry_read              Read a directory entry        */
68
/*    _fx_directory_entry_write             Write the new directory entry */
69
/*    _fx_directory_search                  Search for the file name in   */
70
/*                                          the directory structure       */
71
/*    _fx_utility_logical_sector_flush      Flush the written log sector  */
72
/*    _fx_utility_FAT_entry_read            Read FAT entries to calculate */
73
/*                                            the sub-directory size      */
74
/*    _fx_utility_FAT_entry_write           Write FAT entry               */
75
/*    _fx_utility_FAT_flush                 Flush FAT cache               */
76
/*    _fx_fault_tolerant_transaction_start  Start fault tolerant          */
77
/*                                            transaction                 */
78
/*    _fx_fault_tolerant_transaction_end    End fault tolerant transaction*/
79
/*    _fx_fault_tolerant_recover            Recover FAT chain             */
80
/*    _fx_fault_tolerant_reset_log_file     Reset the log file            */
81
/*                                                                        */
82
/*  CALLED BY                                                             */
83
/*                                                                        */
84
/*    Application Code                                                    */
85
/*                                                                        */
86
/**************************************************************************/
87
218
UINT  _fx_directory_delete(FX_MEDIA *media_ptr, CHAR *directory_name)
88
{
89
90
UINT         status;
91
ULONG        cluster, next_cluster;
92
ULONG        i, directory_size;
93
FX_DIR_ENTRY dir_entry;
94
FX_DIR_ENTRY search_directory;
95
FX_DIR_ENTRY search_entry;
96
97
98
99
#ifndef FX_MEDIA_STATISTICS_DISABLE
100
101
    /* Increment the number of times this service has been called.  */
102
218
    media_ptr -> fx_media_directory_deletes++;
103
#endif
104
105
    /* Setup pointer to media name buffer.  */
106
218
    dir_entry.fx_dir_entry_name =  media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
107
108
    /* Setup search pointer to media name buffer.  */
109
218
    search_directory.fx_dir_entry_name =  media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 2;
110
111
    /* Setup search entry pointer to media name buffer.  */
112
218
    search_entry.fx_dir_entry_name =  media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 3;
113
114
    /* Clear the short name string of the three file names that will be worked with.  */
115
218
    dir_entry.fx_dir_entry_short_name[0] =  0;
116
218
    search_directory.fx_dir_entry_short_name[0] =  0;
117
218
    search_entry.fx_dir_entry_short_name[0] =  0;
118
119
    /* Check the media to make sure it is open.  */
120
218
    if (media_ptr -> fx_media_id != FX_MEDIA_ID)
121
    {
122
123
        /* Return the media not opened error.  */
124
1
        return(FX_MEDIA_NOT_OPEN);
125
    }
126
127
    /* If trace is enabled, insert this event into the trace buffer.  */
128
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_DELETE, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
129
130
    /* Protect against other threads accessing the media.  */
131
217
    FX_PROTECT
132
133
#ifdef FX_ENABLE_FAULT_TOLERANT
134
    /* Start transaction. */
135
    _fx_fault_tolerant_transaction_start(media_ptr);
136
#endif /* FX_ENABLE_FAULT_TOLERANT */
137
138
    /* Check for write protect at the media level (set by driver).  */
139
217
    if (media_ptr -> fx_media_driver_write_protect)
140
    {
141
142
#ifdef FX_ENABLE_FAULT_TOLERANT
143
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
144
#endif /* FX_ENABLE_FAULT_TOLERANT */
145
146
        /* Release media protection.  */
147
1
        FX_UNPROTECT
148
149
        /* Return write protect error.  */
150
1
        return(FX_WRITE_PROTECT);
151
    }
152
153
    /* Search the system for the supplied directory name.  */
154
216
    status =  _fx_directory_search(media_ptr, directory_name, &dir_entry, FX_NULL, FX_NULL);
155
156
    /* Determine if the search was successful.  */
157
216
    if (status != FX_SUCCESS)
158
    {
159
160
#ifdef FX_ENABLE_FAULT_TOLERANT
161
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
162
#endif /* FX_ENABLE_FAULT_TOLERANT */
163
164
        /* Release media protection.  */
165
2
        FX_UNPROTECT
166
167
        /* Return the error code.  */
168
2
        return(status);
169
    }
170
171
    /* Check to make sure the found entry is a directory.  */
172
214
    if (!(dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_DIRECTORY)))
173
    {
174
175
#ifdef FX_ENABLE_FAULT_TOLERANT
176
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
177
#endif /* FX_ENABLE_FAULT_TOLERANT */
178
179
        /* Release media protection.  */
180
1
        FX_UNPROTECT
181
182
        /* Return the not a directory error code.  */
183
1
        return(FX_NOT_DIRECTORY);
184
    }
185
186
    /* Check if the entry is read only */
187
213
    if (dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_READ_ONLY))
188
    {
189
#ifdef FX_ENABLE_FAULT_TOLERANT
190
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
191
#endif /* FX_ENABLE_FAULT_TOLERANT */
192
193
        /* Release media protection.  */
194
1
        FX_UNPROTECT
195
196
        /* Return the not a directory error code.  */
197
1
        return(FX_WRITE_PROTECT);
198
    }
199
200
    /* Copy the directory entry to the search directory structure for
201
       looking at the specified sub-directory contents.  */
202
212
    search_directory =  dir_entry;
203
204
    /* Ensure that the search directory's last search cluster is cleared.  */
205
212
    search_directory.fx_dir_entry_last_search_cluster =  0;
206
207
208
    /* Calculate the directory size by counting the allocated
209
       clusters for it.  */
210
212
    i =        0;
211
212
    cluster =  search_directory.fx_dir_entry_cluster;
212
460
    while (cluster < media_ptr -> fx_media_fat_reserved)
213
    {
214
215
        /* Increment the cluster count.  */
216
252
        i++;
217
218
        /* Read the next FAT entry.  */
219
252
        status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
220
221
        /* Check the return status.  */
222
252
        if (status != FX_SUCCESS)
223
        {
224
225
#ifdef FX_ENABLE_FAULT_TOLERANT
226
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
227
#endif /* FX_ENABLE_FAULT_TOLERANT */
228
229
            /* Release media protection.  */
230
1
            FX_UNPROTECT
231
232
            /* Return the bad status.  */
233
1
            return(status);
234
        }
235
236

251
        if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
237
        {
238
#ifdef FX_ENABLE_FAULT_TOLERANT
239
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
240
#endif /* FX_ENABLE_FAULT_TOLERANT */
241
242
            /* Release media protection.  */
243
3
            FX_UNPROTECT
244
245
            /* Return the bad status.  */
246
3
            return(FX_FAT_READ_ERROR);
247
        }
248
249
248
        cluster = next_cluster;
250
    }
251
252
    /* Now we can calculate the directory size.  */
253
208
    directory_size =  (((ULONG)media_ptr -> fx_media_bytes_per_sector) *
254
208
                       ((ULONG)media_ptr -> fx_media_sectors_per_cluster) * i) /
255
                       (ULONG)FX_DIR_ENTRY_SIZE;
256
257
    /* Also save this in the directory entry so we don't have to
258
       calculate it later.  */
259
208
    search_directory.fx_dir_entry_file_size =  directory_size;
260
261
    /* Make sure the new name is not in the current directory.  */
262
    /* The first two entries are skipped because they are just part of the sub-directory.  */
263
208
    i = 2;
264
265
    do
266
    {
267
268
        /* Read an entry from the directory.  */
269
408
        status = _fx_directory_entry_read(media_ptr, &search_directory, &i, &search_entry);
270
271
        /* Check for error status.  */
272
408
        if (status != FX_SUCCESS)
273
        {
274
275
#ifdef FX_ENABLE_FAULT_TOLERANT
276
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
277
#endif /* FX_ENABLE_FAULT_TOLERANT */
278
279
            /* Release media protection.  */
280
1
            FX_UNPROTECT
281
282
            /* Return error condition.  */
283
1
            return(status);
284
        }
285
286
        /* Determine if this is the last directory entry.  */
287
407
        if (search_entry.fx_dir_entry_name[0] == FX_DIR_ENTRY_DONE)
288
        {
289
195
            break;
290
        }
291
292
293
        /* Determine if this is an empty entry.  */
294
212
        if ((UCHAR)search_entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_FREE)
295
        {
296
297
#ifdef FX_ENABLE_FAULT_TOLERANT
298
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
299
#endif /* FX_ENABLE_FAULT_TOLERANT */
300
301
            /* Release media protection.  */
302
1
            FX_UNPROTECT
303
304
            /* Return error status.  */
305
1
            return(FX_DIR_NOT_EMPTY);
306
        }
307
308
211
        i++;
309
211
    } while (i < directory_size);
310
311
    /* At this point, we are going to delete the empty directory.  */
312
313
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
314
315
    /* Invalidate the directory search saved information.  */
316
206
    media_ptr -> fx_media_last_found_name[0] =  FX_NULL;
317
#endif
318
319
    /* Mark the sub-directory entry as available.  */
320
206
    dir_entry.fx_dir_entry_name[0] =  (CHAR)FX_DIR_ENTRY_FREE;
321
206
    dir_entry.fx_dir_entry_short_name[0] =  (CHAR)FX_DIR_ENTRY_FREE;
322
323
    /* Now write out the directory entry.  */
324
206
    status =  _fx_directory_entry_write(media_ptr, &dir_entry);
325
326
    /* Determine if the write was successful.  */
327
206
    if (status != FX_SUCCESS)
328
    {
329
330
#ifdef FX_ENABLE_FAULT_TOLERANT
331
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
332
#endif /* FX_ENABLE_FAULT_TOLERANT */
333
334
        /* Release media protection.  */
335
1
        FX_UNPROTECT
336
337
        /* Return the error code.  */
338
1
        return(status);
339
    }
340
341
342
    /* Walk through the directory's clusters and release them.  */
343
205
    cluster =  search_directory.fx_dir_entry_cluster;
344
345
444
    while (cluster < media_ptr -> fx_media_fat_reserved)
346
    {
347
348
        /* Increment the cluster count.  */
349
244
        i++;
350
351
352
        /* Read the next FAT entry.  */
353
244
        status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
354
355
        /* Check the return status.  */
356
244
        if (status != FX_SUCCESS)
357
        {
358
359
#ifdef FX_ENABLE_FAULT_TOLERANT
360
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
361
#endif /* FX_ENABLE_FAULT_TOLERANT */
362
363
            /* Release media protection.  */
364
1
            FX_UNPROTECT
365
366
            /* Return the bad status.  */
367
1
            return(status);
368
        }
369
370

243
        if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
371
        {
372
373
#ifdef FX_ENABLE_FAULT_TOLERANT
374
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
375
#endif /* FX_ENABLE_FAULT_TOLERANT */
376
377
            /* Release media protection.  */
378
3
            FX_UNPROTECT
379
380
            /* Return the bad status.  */
381
3
            return(FX_FAT_READ_ERROR);
382
        }
383
384
        /* Release the current cluster.  */
385
386
240
        status =  _fx_utility_FAT_entry_write(media_ptr, cluster, FX_FREE_CLUSTER);
387
388
        /* Check the return status.  */
389
240
        if (status != FX_SUCCESS)
390
        {
391
392
#ifdef FX_ENABLE_FAULT_TOLERANT
393
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
394
#endif /* FX_ENABLE_FAULT_TOLERANT */
395
396
            /* Release media protection.  */
397
1
            FX_UNPROTECT
398
399
            /* Return the bad status.  */
400
1
            return(status);
401
        }
402
403
        /* Increment the number of available clusters for the media.  */
404
239
        media_ptr -> fx_media_available_clusters++;
405
406
        /* Copy next cluster to current cluster.  */
407
239
        cluster =  next_cluster;
408
    }
409
410
#ifdef FX_FAULT_TOLERANT
411
412
    /* Flush the cached individual FAT entries */
413
    _fx_utility_FAT_flush(media_ptr);
414
#endif
415
416
    /* Flush the logical sector cache.  */
417
200
    status =  _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64)(media_ptr -> fx_media_sectors_per_FAT), FX_FALSE);
418
419
#ifdef FX_ENABLE_FAULT_TOLERANT
420
    /* Check for a bad status.  */
421
    if (status != FX_SUCCESS)
422
    {
423
424
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
425
426
        /* Release media protection.  */
427
        FX_UNPROTECT
428
429
        /* Return the bad status.  */
430
        return(status);
431
    }
432
433
    /* End transaction. */
434
    status = _fx_fault_tolerant_transaction_end(media_ptr);
435
#endif /* FX_ENABLE_FAULT_TOLERANT */
436
437
    /* Release media protection.  */
438
200
    FX_UNPROTECT
439
440
    /* Directory delete is complete, return status.  */
441
200
    return(status);
442
}
443