GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_directory_rename.c Lines: 78 78 100.0 %
Date: 2026-03-06 18:49:02 Branches: 52 52 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_rename                                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 rename request is valid and the directory will be     */
52
/*    changed to the new name.  Otherwise, if the directory is not found, */
53
/*    the appropriate error code is returned to the caller.               */
54
/*                                                                        */
55
/*  INPUT                                                                 */
56
/*                                                                        */
57
/*    media_ptr                             Media control block pointer   */
58
/*    old_directory_name                    Old file directory pointer    */
59
/*    new_directory_name                    New file directory pointer    */
60
/*                                                                        */
61
/*  OUTPUT                                                                */
62
/*                                                                        */
63
/*    return status                                                       */
64
/*                                                                        */
65
/*  CALLS                                                                 */
66
/*                                                                        */
67
/*    _fx_directory_entry_write             Write the new directory entry */
68
/*    _fx_directory_free_search             Search for a free directory   */
69
/*                                            entry                       */
70
/*    _fx_directory_name_extract            Extract directory name        */
71
/*    _fx_directory_search                  Search for the file name in   */
72
/*                                          the directory structure       */
73
/*    _fx_fault_tolerant_transaction_start  Start fault tolerant          */
74
/*                                            transaction                 */
75
/*    _fx_fault_tolerant_transaction_end    End fault tolerant transaction*/
76
/*    _fx_fault_tolerant_recover            Recover FAT chain             */
77
/*    _fx_fault_tolerant_reset_log_file     Reset the log file            */
78
/*                                                                        */
79
/*  CALLED BY                                                             */
80
/*                                                                        */
81
/*    Application Code                                                    */
82
/*                                                                        */
83
/**************************************************************************/
84
88
UINT  _fx_directory_rename(FX_MEDIA *media_ptr, CHAR *old_directory_name, CHAR *new_directory_name)
85
{
86
87
UINT         status;
88
FX_DIR_ENTRY old_dir_entry;
89
FX_DIR_ENTRY new_dir_entry;
90
FX_DIR_ENTRY search_directory;
91
CHAR        *new_name_ptr;
92
ULONG        i;
93
CHAR        *work_ptr;
94
CHAR         alpha, beta;
95
#ifdef FX_RENAME_PATH_INHERIT
96
UINT         j;
97
#endif
98
99
100
#ifndef FX_MEDIA_STATISTICS_DISABLE
101
102
    /* Increment the number of times this service has been called.  */
103
88
    media_ptr -> fx_media_directory_renames++;
104
#endif
105
106
    /* Setup pointers to media name buffers.  */
107
88
    old_dir_entry.fx_dir_entry_name =     media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
108
88
    new_dir_entry.fx_dir_entry_name =     media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 2;
109
88
    search_directory.fx_dir_entry_name =  media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 3;
110
111
    /* Clear the short name strings.  */
112
88
    old_dir_entry.fx_dir_entry_short_name[0] =     0;
113
88
    new_dir_entry.fx_dir_entry_short_name[0] =     0;
114
88
    search_directory.fx_dir_entry_short_name[0] =  0;
115
116
    /* Determine if the supplied name is less than the maximum supported name size. The
117
       maximum name (FX_MAX_LONG_NAME_LEN) is defined in fx_api.h.  */
118
88
    i =  0;
119
88
    work_ptr =  (CHAR *)new_directory_name;
120

1537
    while (*work_ptr && (i < FX_MAX_LONG_NAME_LEN))
121
    {
122
123
        /* Determine if the character designates a new path.  */
124

1449
        if ((*work_ptr == '\\') || (*work_ptr == '/'))
125
        {
126
            /* Yes, reset the name size.  */
127
12
            i =  0;
128
        }
129
        /* Check for leading spaces.  */
130

1437
        else if ((*work_ptr != ' ') || (i != 0))
131
        {
132
133
            /* No leading spaces, increment the name size.  */
134
1432
            i++;
135
        }
136
137
        /* Move to the next character.  */
138
1449
        work_ptr++;
139
    }
140
141
    /* Determine if the supplied name is valid.  */
142

88
    if ((i == 0) || (i >= FX_MAX_LONG_NAME_LEN))
143
    {
144
145
        /* Return an invalid name value.  */
146
3
        return(FX_INVALID_NAME);
147
    }
148
149
    /* Check the media to make sure it is open.  */
150
85
    if (media_ptr -> fx_media_id != FX_MEDIA_ID)
151
    {
152
153
        /* Return the media not opened error.  */
154
1
        return(FX_MEDIA_NOT_OPEN);
155
    }
156
157
    /* If trace is enabled, insert this event into the trace buffer.  */
158
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_RENAME, media_ptr, old_directory_name, new_directory_name, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
159
160
    /* Protect against other threads accessing the media.  */
161
84
    FX_PROTECT
162
163
#ifdef FX_ENABLE_FAULT_TOLERANT
164
    /* Start transaction. */
165
    _fx_fault_tolerant_transaction_start(media_ptr);
166
#endif /* FX_ENABLE_FAULT_TOLERANT */
167
168
    /* Check for write protect at the media level (set by driver).  */
169
84
    if (media_ptr -> fx_media_driver_write_protect)
170
    {
171
172
#ifdef FX_ENABLE_FAULT_TOLERANT
173
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
174
#endif /* FX_ENABLE_FAULT_TOLERANT */
175
176
        /* Release media protection.  */
177
1
        FX_UNPROTECT
178
179
        /* Return write protect error.  */
180
1
        return(FX_WRITE_PROTECT);
181
    }
182
183
    /* Search the system for the supplied directory name.  */
184
83
    status =  _fx_directory_search(media_ptr, old_directory_name, &old_dir_entry, &search_directory, FX_NULL);
185
186
    /* Determine if the search was successful.  */
187
83
    if (status != FX_SUCCESS)
188
    {
189
190
#ifdef FX_ENABLE_FAULT_TOLERANT
191
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
192
#endif /* FX_ENABLE_FAULT_TOLERANT */
193
194
        /* Release media protection.  */
195
1
        FX_UNPROTECT
196
197
        /* Return the error code.  */
198
1
        return(status);
199
    }
200
201
    /* Check to make sure the found entry is a directory.  */
202
82
    if (!(old_dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_DIRECTORY)))
203
    {
204
205
#ifdef FX_ENABLE_FAULT_TOLERANT
206
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
207
#endif /* FX_ENABLE_FAULT_TOLERANT */
208
209
        /* Release media protection.  */
210
2
        FX_UNPROTECT
211
212
        /* Return the not a directory error code.  */
213
2
        return(FX_NOT_DIRECTORY);
214
    }
215
216
#ifdef FX_RENAME_PATH_INHERIT
217
218
    /* Determine if the source directory name has a path and the target directory name does not.  */
219
    if (((old_directory_name[0] == '/') || (old_directory_name[0] == '\\')) && (new_directory_name[0] != '/') && (new_directory_name[0] != '\\'))
220
    {
221
222
        /* In this case, we need to prepend the path of the old directory name to that of the new directory name.  */
223
224
        /* Setup pointer to the rename buffer.  */
225
        work_ptr =  (CHAR *)media_ptr -> fx_media_rename_buffer;
226
227
        /* First, copy the path of the old directory name.  */
228
        i =  0;
229
        j =  0;
230
        while ((old_directory_name[i]) && (i < FX_MAXIMUM_PATH))
231
        {
232
233
            /* Copy a character into the rename buffer.  */
234
            *work_ptr++ =  old_directory_name[i];
235
236
            /* Determine if this character is directory separator.  */
237
            if ((old_directory_name[i] == '/') || (old_directory_name[i] == '\\'))
238
            {
239
240
                /* Yes, directory separator has been found - remember the index.  */
241
                j =  i;
242
            }
243
244
            /* Move to next position in the old directory name.  */
245
            i++;
246
        }
247
248
        /* At this point, we have the path stored in the rename buffer.  */
249
250
        /* Position past the last slash or backslash.  */
251
        j++;
252
253
        /* Reset the working pointer to the position after the last directory separator.  */
254
        work_ptr =  (CHAR *)&(media_ptr -> fx_media_rename_buffer[j]);
255
256
        /* Now copy the new directory name into the rename buffer.  */
257
        i =  0;
258
        while ((new_directory_name[i]) && (j < FX_MAXIMUM_PATH))
259
        {
260
261
            /* Copy a character into the rename buffer.  */
262
            *work_ptr++ =  new_directory_name[i];
263
264
            /* Move to next character.  */
265
            i++;
266
            j++;
267
        }
268
269
        /* Determine if the path was successfully prepended.  */
270
        if (new_directory_name[i])
271
        {
272
273
            /* No, there was not enough room in the destination buffer.  */
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
            FX_UNPROTECT
281
282
            /* Return the invalid path error code.  */
283
            return(FX_INVALID_PATH);
284
        }
285
286
        /* Place a NULL at the end of the string.  */
287
        *work_ptr =  (CHAR)FX_NULL;
288
289
        /* At this point, we have successfully prepended the path in the new directory name, override
290
           the new directory name so it is used from now on.  */
291
        new_directory_name =  (CHAR *)media_ptr -> fx_media_rename_buffer;
292
    }
293
#endif
294
295
    /* Search the media for the new directory name - including any supplied path.  */
296
80
    status = _fx_directory_search(media_ptr, new_directory_name, &new_dir_entry, &search_directory, &new_name_ptr);
297
298
    /* Determine if the search found anything.  */
299
80
    if (status == FX_SUCCESS)
300
    {
301
302
        /* Determine if the new name simply has an ASCII case change. If so, simply let the processing
303
           continue.  */
304
58
        i =  0;
305
        do
306
        {
307
308
            /* Pickup an old name and new name character and convert to upper case if necessary.  */
309
375
            alpha =  old_directory_name[i];
310

375
            if ((alpha >= 'a') && (alpha <= 'z'))
311
            {
312
313
                /* Lower case, convert to upper case!  */
314
260
                alpha =  (CHAR)((INT)alpha - 0x20);
315
            }
316
375
            beta =   new_directory_name[i];
317

375
            if ((beta >= 'a') && (beta <= 'z'))
318
            {
319
320
                /* Lower case, convert to upper case!  */
321
315
                beta =  (CHAR)((INT)beta - 0x20);
322
            }
323
324
            /* Now compare the characters.  */
325

375
            if ((alpha != beta) || (alpha == 0))
326
            {
327
328
                /* Get out of this loop!  */
329
                break;
330
            }
331
332
            /* Move to next character.  */
333
318
            i++;
334
318
        } while (i < (FX_MAXIMUM_PATH-1));
335
336
        /* Now determine if the names match.  */
337
58
        if (alpha != beta)
338
        {
339
340
            /* Yes, the directory name already exists in the target location.  */
341
342
#ifdef FX_ENABLE_FAULT_TOLERANT
343
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
344
#endif /* FX_ENABLE_FAULT_TOLERANT */
345
346
            /* Release media protection.  */
347
43
            FX_UNPROTECT
348
349
            /* Return the error code.  */
350
43
            return(FX_ALREADY_CREATED);
351
        }
352
    }
353
354
    /* Make sure the name is valid.  */
355
37
    if (_fx_directory_name_extract(new_name_ptr, &new_dir_entry.fx_dir_entry_name[0]))
356
    {
357
358
#ifdef FX_ENABLE_FAULT_TOLERANT
359
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
360
#endif /* FX_ENABLE_FAULT_TOLERANT */
361
362
        /* Release media protection */
363
1
        FX_UNPROTECT
364
365
        /* Return the error code */
366
1
        return(FX_INVALID_NAME);
367
    }
368
369
    /* Look for a free slot in the target directory.  */
370
36
    status =  _fx_directory_free_search(media_ptr, &search_directory, &new_dir_entry);
371
372
    /* Was a free slot found?  */
373
36
    if (status != FX_SUCCESS)
374
    {
375
376
#ifdef FX_ENABLE_FAULT_TOLERANT
377
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
378
#endif /* FX_ENABLE_FAULT_TOLERANT */
379
380
        /* No, release protection.  */
381
2
        FX_UNPROTECT
382
383
        /* Return the error code.  */
384
2
        return(status);
385
    }
386
387
    /* Extract the new directory name.  */
388
34
    _fx_directory_name_extract(new_name_ptr, &new_dir_entry.fx_dir_entry_name[0]);
389
390
    /* Determine if the name was a long directory name.   */
391
34
    if (new_dir_entry.fx_dir_entry_long_name_present)
392
    {
393
394
        /* Yes, clear the short directory name to force a new one.  */
395
33
        new_dir_entry.fx_dir_entry_short_name[0] =  0;
396
    }
397
398
    /* Setup new attributes for the new directory entry.  */
399
34
    new_dir_entry.fx_dir_entry_attributes = old_dir_entry.fx_dir_entry_attributes;
400
34
    new_dir_entry.fx_dir_entry_cluster    = old_dir_entry.fx_dir_entry_cluster;
401
34
    new_dir_entry.fx_dir_entry_file_size  = old_dir_entry.fx_dir_entry_file_size;
402
403
    /* Save the reserved field.  */
404
34
    new_dir_entry.fx_dir_entry_reserved =            old_dir_entry.fx_dir_entry_reserved;
405
406
    /* Set time and date stamps.  */
407
34
    new_dir_entry.fx_dir_entry_created_time_ms =     old_dir_entry.fx_dir_entry_created_time_ms;
408
34
    new_dir_entry.fx_dir_entry_created_time =        old_dir_entry.fx_dir_entry_created_time;
409
34
    new_dir_entry.fx_dir_entry_created_date =        old_dir_entry.fx_dir_entry_created_date;
410
34
    new_dir_entry.fx_dir_entry_last_accessed_date =  old_dir_entry.fx_dir_entry_last_accessed_date;
411
34
    new_dir_entry.fx_dir_entry_time =                old_dir_entry.fx_dir_entry_time;
412
34
    new_dir_entry.fx_dir_entry_date =                old_dir_entry.fx_dir_entry_date;
413
414
415
    /* Is there a leading dot?  */
416
34
    if (new_dir_entry.fx_dir_entry_name[0] == '.')
417
    {
418
419
        /* Yes, toggle the hidden attribute bit.  */
420
1
        new_dir_entry.fx_dir_entry_attributes |=  FX_HIDDEN;
421
    }
422
423
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
424
425
    /* Invalidate the directory cache.  */
426
34
    media_ptr -> fx_media_last_found_name[0] =  FX_NULL;
427
#endif
428
429
    /* Now write out the directory entry.  */
430
34
    status =  _fx_directory_entry_write(media_ptr, &new_dir_entry);
431
432
    /* Determine if the write was successful.  */
433
34
    if (status != FX_SUCCESS)
434
    {
435
436
#ifdef FX_ENABLE_FAULT_TOLERANT
437
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
438
#endif /* FX_ENABLE_FAULT_TOLERANT */
439
440
        /* Release media protection.  */
441
1
        FX_UNPROTECT
442
443
        /* Return the error code.  */
444
1
        return(status);
445
    }
446
447
    /* Set the old directory entry to free.  */
448
33
    old_dir_entry.fx_dir_entry_name[0] =        (CHAR)FX_DIR_ENTRY_FREE;
449
33
    old_dir_entry.fx_dir_entry_short_name[0] =  (CHAR)FX_DIR_ENTRY_FREE;
450
451
    /* Now wipe out the old directory entry.  */
452
33
    status =  _fx_directory_entry_write(media_ptr, &old_dir_entry);
453
454
#ifdef FX_ENABLE_FAULT_TOLERANT
455
    /* Check for a bad status.  */
456
    if (status != FX_SUCCESS)
457
    {
458
459
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
460
461
        /* Release media protection.  */
462
        FX_UNPROTECT
463
464
        /* Return the bad status.  */
465
        return(status);
466
    }
467
468
    /* End transaction. */
469
    status = _fx_fault_tolerant_transaction_end(media_ptr);
470
#endif /* FX_ENABLE_FAULT_TOLERANT */
471
472
    /* Release media protection.  */
473
33
    FX_UNPROTECT
474
475
    /* Directory rename is complete, return status.  */
476
33
    return(status);
477
}
478