GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_rename.c Lines: 100 100 100.0 %
Date: 2024-01-10 21:53:23 Branches: 62 62 100.0 %

Line Branch Exec Source
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
/**   File                                                                */
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_EXFAT
34
#include "fx_directory_exFAT.h"
35
#endif /* FX_ENABLE_EXFAT */
36
#ifdef FX_ENABLE_FAULT_TOLERANT
37
#include "fx_fault_tolerant.h"
38
#endif /* FX_ENABLE_FAULT_TOLERANT */
39
40
41
/**************************************************************************/
42
/*                                                                        */
43
/*  FUNCTION                                               RELEASE        */
44
/*                                                                        */
45
/*    _fx_file_rename                                     PORTABLE C      */
46
/*                                                           6.1          */
47
/*  AUTHOR                                                                */
48
/*                                                                        */
49
/*    William E. Lamie, Microsoft Corporation                             */
50
/*                                                                        */
51
/*  DESCRIPTION                                                           */
52
/*                                                                        */
53
/*    This function first attempts to find the specified file.  If found, */
54
/*    the rename request is valid and the directory entry will be changed */
55
/*    to the new file name.  Otherwise, if the file is not found, the     */
56
/*    appropriate error code is returned to the caller.                   */
57
/*                                                                        */
58
/*  INPUT                                                                 */
59
/*                                                                        */
60
/*    media_ptr                             Media control block pointer   */
61
/*    old_file_name                         Old file name pointer         */
62
/*    new_file_name                         New file name pointer         */
63
/*                                                                        */
64
/*  OUTPUT                                                                */
65
/*                                                                        */
66
/*    return status                                                       */
67
/*                                                                        */
68
/*  CALLS                                                                 */
69
/*                                                                        */
70
/*    _fx_directory_entry_write             Write the new directory entry */
71
/*    _fx_directory_free_search             Search for a free directory   */
72
/*                                            entry in target directory   */
73
/*    _fx_directory_name_extract            Extract the new filename      */
74
/*    _fx_directory_search                  Search for the file name in   */
75
/*                                          the directory structure       */
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
/*                                                                        */
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
/**************************************************************************/
94
91
UINT  _fx_file_rename(FX_MEDIA *media_ptr, CHAR *old_file_name, CHAR *new_file_name)
95
{
96
97
ULONG        i;
98
CHAR        *work_ptr;
99
CHAR         alpha, beta;
100
UINT         status;
101
102
#ifndef FX_DONT_UPDATE_OPEN_FILES
103
ULONG        open_count;
104
FX_FILE     *search_ptr;
105
#endif
106
CHAR        *new_name_ptr;
107
FX_DIR_ENTRY old_dir_entry, new_dir_entry;
108
FX_DIR_ENTRY search_directory;
109
#ifdef FX_RENAME_PATH_INHERIT
110
UINT         j;
111
#endif
112
UCHAR        not_a_file_attr;
113
114
115
#ifndef FX_MEDIA_STATISTICS_DISABLE
116
117
    /* Increment the number of times this service has been called.  */
118
91
    media_ptr -> fx_media_file_renames++;
119
#endif
120
121
    /* Setup pointers to media name buffers.  */
122
91
    old_dir_entry.fx_dir_entry_name =     media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
123
91
    new_dir_entry.fx_dir_entry_name =     media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 2;
124
91
    search_directory.fx_dir_entry_name =  media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 3;
125
126
    /* Clear the short name strings.  */
127
91
    old_dir_entry.fx_dir_entry_short_name[0] =     0;
128
91
    new_dir_entry.fx_dir_entry_short_name[0] =     0;
129
91
    search_directory.fx_dir_entry_short_name[0] =  0;
130
131
    /* Determine if the supplied name is less than the maximum supported name size. The
132
       maximum name (FX_MAX_LONG_NAME_LEN) is defined in fx_api.h.  */
133
91
    i =  0;
134
91
    work_ptr =  (CHAR *)new_file_name;
135
1845
    while (*work_ptr)
136
    {
137
138
        /* Determine if the character designates a new path.  */
139

1754
        if ((*work_ptr == '\\') || (*work_ptr == '/'))
140
        {
141
            /* Yes, reset the name size.  */
142
10
            i =  0;
143
        }
144
        /* Check for leading spaces.  */
145

1744
        else if ((*work_ptr != ' ') || (i != 0))
146
        {
147
148
            /* No leading spaces, increment the name size.  */
149
1740
            i++;
150
        }
151
152
        /* Move to the next character.  */
153
1754
        work_ptr++;
154
    }
155
156
    /* Determine if the supplied name is valid.  */
157

91
    if ((i == 0) || (i >= FX_MAX_LONG_NAME_LEN))
158
    {
159
160
        /* Return an invalid name value.  */
161
2
        return(FX_INVALID_NAME);
162
    }
163
164
    /* Check the media to make sure it is open.  */
165
89
    if (media_ptr -> fx_media_id != FX_MEDIA_ID)
166
    {
167
168
        /* Return the media not opened error.  */
169
1
        return(FX_MEDIA_NOT_OPEN);
170
    }
171
172
    /* If trace is enabled, insert this event into the trace buffer.  */
173
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_RENAME, media_ptr, old_file_name, new_file_name, 0, FX_TRACE_FILE_EVENTS, 0, 0)
174
175
    /* Protect against other threads accessing the media.  */
176
88
    FX_PROTECT
177
178
#ifdef FX_ENABLE_FAULT_TOLERANT
179
    /* Start transaction. */
180
    _fx_fault_tolerant_transaction_start(media_ptr);
181
#endif /* FX_ENABLE_FAULT_TOLERANT */
182
183
    /* Check for write protect at the media level (set by driver).  */
184
88
    if (media_ptr -> fx_media_driver_write_protect)
185
    {
186
187
#ifdef FX_ENABLE_FAULT_TOLERANT
188
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
189
#endif /* FX_ENABLE_FAULT_TOLERANT */
190
191
        /* Release media protection.  */
192
1
        FX_UNPROTECT
193
194
        /* Return write protect error.  */
195
1
        return(FX_WRITE_PROTECT);
196
    }
197
198
    /* Search the system for the supplied file name.  */
199
87
    status =  _fx_directory_search(media_ptr, old_file_name, &old_dir_entry, &search_directory, FX_NULL);
200
201
    /* Determine if the search was successful.  */
202
87
    if (status != FX_SUCCESS)
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
1
        FX_UNPROTECT
211
212
        /* Return the error code.  */
213
1
        return(status);
214
    }
215
216
#ifdef FX_ENABLE_EXFAT
217
    if (media_ptr -> fx_media_FAT_type == FX_exFAT)
218
    {
219
        not_a_file_attr = FX_DIRECTORY;
220
    }
221
    else
222
    {
223
#endif /* FX_ENABLE_EXFAT */
224
86
        not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
225
#ifdef FX_ENABLE_EXFAT
226
    }
227
#endif /* FX_ENABLE_EXFAT */
228
229
    /* Check to make sure the found entry is a file.  */
230
86
    if (old_dir_entry.fx_dir_entry_attributes & not_a_file_attr)
231
    {
232
233
#ifdef FX_ENABLE_FAULT_TOLERANT
234
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
235
#endif /* FX_ENABLE_FAULT_TOLERANT */
236
237
        /* Release media protection.  */
238
1
        FX_UNPROTECT
239
240
        /* Return the not a file error code.  */
241
1
        return(FX_NOT_A_FILE);
242
    }
243
244
#ifdef FX_RENAME_PATH_INHERIT
245
246
    /* Determine if the source file name has a path and the target file name does not.  */
247
    if (((old_file_name[0] == '/') || (old_file_name[0] == '\\')) && (new_file_name[0] != '/') && (new_file_name[0] != '\\'))
248
    {
249
250
        /* In this case, we need to prepend the path of the old file name to that of the new file name.  */
251
252
        /* Setup pointer to the rename buffer.  */
253
        work_ptr =  (CHAR *)media_ptr -> fx_media_rename_buffer;
254
255
        /* First, copy the path of the old file name.  */
256
        i =  0;
257
        j =  0;
258
        while ((old_file_name[i]) && (i < FX_MAXIMUM_PATH))
259
        {
260
261
            /* Copy a character into the rename buffer.  */
262
            *work_ptr++ =  old_file_name[i];
263
264
            /* Determine if this character is directory separator.  */
265
            if ((old_file_name[i] == '/') || (old_file_name[i] == '\\'))
266
            {
267
268
                /* Yes, directory separator has been found - remember the index.  */
269
                j =  i;
270
            }
271
272
            /* Move to next position in the old file name.  */
273
            i++;
274
        }
275
276
        /* At this point, we have the path stored in the rename buffer.  */
277
278
        /* Position past the last slash or backslash.  */
279
        j++;
280
281
        /* Reset the working pointer to the position after the last directory separator.  */
282
        work_ptr =  (CHAR *)&(media_ptr -> fx_media_rename_buffer[j]);
283
284
        /* Now copy the new file name into the rename buffer.  */
285
        i =  0;
286
        while ((new_file_name[i]) && (j < FX_MAXIMUM_PATH))
287
        {
288
289
            /* Copy a character into the rename buffer.  */
290
            *work_ptr++ =  new_file_name[i];
291
292
            /* Move to next character.  */
293
            i++;
294
            j++;
295
        }
296
297
        /* Determine if the path was successfully prepended.  */
298
        if (new_file_name[i])
299
        {
300
301
            /* No, there was not enough room in the destination buffer.  */
302
303
#ifdef FX_ENABLE_FAULT_TOLERANT
304
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
305
#endif /* FX_ENABLE_FAULT_TOLERANT */
306
307
            /* Release media protection.  */
308
            FX_UNPROTECT
309
310
            /* Return the invalid path error code.  */
311
            return(FX_INVALID_PATH);
312
        }
313
314
        /* Place a NULL at the end of the string.  */
315
        *work_ptr =  (CHAR)FX_NULL;
316
317
        /* At this point, we have successfully prepended the path in the new file name, override
318
           the new file name so it is used from now on.  */
319
        new_file_name =  (CHAR *)media_ptr -> fx_media_rename_buffer;
320
    }
321
#endif
322
323
    /* Search the target directory for the same file name.  */
324
85
    status = _fx_directory_search(media_ptr, new_file_name, &new_dir_entry, &search_directory, &new_name_ptr);
325
326
    /* Determine if the name already exists.  */
327
85
    if (status == FX_SUCCESS)
328
    {
329
330
        /* Determine if the new name simply has an ASCII case change. If so, simply let the processing
331
           continue.  */
332
61
        i =  0;
333
        do
334
        {
335
336
            /* Pickup an old name and new name character and convert to upper case if necessary.  */
337
1136
            alpha =  old_file_name[i];
338

1136
            if ((alpha >= 'a') && (alpha <= 'z'))
339
            {
340
341
                /* Lower case, convert to upper case!  */
342
1023
                alpha =  (CHAR)((INT)alpha - 0x20);
343
            }
344
1136
            beta =   new_file_name[i];
345

1136
            if ((beta >= 'a') && (beta <= 'z'))
346
            {
347
348
                /* Lower case, convert to upper case!  */
349
1078
                beta = (CHAR)((INT)beta - 0x20);
350
            }
351
352
            /* Now compare the characters.  */
353

1136
            if ((alpha != beta) || (alpha == 0))
354
            {
355
356
                /* Get out of this loop!  */
357
                break;
358
            }
359
360
            /* Move to next character.  */
361
1079
            i++;
362
1079
        } while (i < (FX_MAXIMUM_PATH-1));
363
364
        /* Now determine if the names match.  */
365
61
        if (alpha != beta)
366
        {
367
368
            /* No, the names do not match so simply return an error
369
               to the caller.  */
370
371
#ifdef FX_ENABLE_FAULT_TOLERANT
372
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
373
#endif /* FX_ENABLE_FAULT_TOLERANT */
374
375
            /* Release media protection.  */
376
42
            FX_UNPROTECT
377
378
            /* Return the not a file error code.  */
379
42
            return(FX_ALREADY_CREATED);
380
        }
381
    }
382
383
    /* Change the file name and look for extra stuff at the end.  */
384
43
    if (_fx_directory_name_extract(new_name_ptr, &new_dir_entry.fx_dir_entry_name[0]))
385
    {
386
387
#ifdef FX_ENABLE_FAULT_TOLERANT
388
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
389
#endif /* FX_ENABLE_FAULT_TOLERANT */
390
391
        /* Release media protection.  */
392
1
        FX_UNPROTECT
393
394
        /* Invalid name, return error status.  */
395
1
        return(FX_INVALID_NAME);
396
    }
397
398
    /* Search for a free spot in the target directory.  */
399
42
    status = _fx_directory_free_search(media_ptr, &search_directory, &new_dir_entry);
400
401
    /* Determine if a free spot was found.  */
402
42
    if (status != FX_SUCCESS)
403
    {
404
405
#ifdef FX_ENABLE_FAULT_TOLERANT
406
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
407
#endif /* FX_ENABLE_FAULT_TOLERANT */
408
409
        /* Release media protection.  */
410
1
        FX_UNPROTECT
411
412
        /* Return the error code.  */
413
1
        return(status);
414
    }
415
416
    /* Extract the new file name.  */
417
41
    _fx_directory_name_extract(new_name_ptr, &new_dir_entry.fx_dir_entry_name[0]);
418
419
    /* Determine if a long name is present.  */
420
41
    if (new_dir_entry.fx_dir_entry_long_name_present)
421
    {
422
423
        /* Yes, clear the short file name.  */
424
35
        new_dir_entry.fx_dir_entry_short_name[0] =  0;
425
    }
426
427
    /* Save the updated directory parameters.  */
428
41
    new_dir_entry.fx_dir_entry_attributes =          old_dir_entry.fx_dir_entry_attributes;
429
41
    new_dir_entry.fx_dir_entry_cluster    =          old_dir_entry.fx_dir_entry_cluster;
430
41
    new_dir_entry.fx_dir_entry_file_size  =          old_dir_entry.fx_dir_entry_file_size;
431
432
    /* Save the reserved field.  */
433
41
    new_dir_entry.fx_dir_entry_reserved =            old_dir_entry.fx_dir_entry_reserved;
434
435
    /* Set time and date stamps.  */
436
41
    new_dir_entry.fx_dir_entry_created_time_ms =     old_dir_entry.fx_dir_entry_created_time_ms;
437
41
    new_dir_entry.fx_dir_entry_created_time =        old_dir_entry.fx_dir_entry_created_time;
438
41
    new_dir_entry.fx_dir_entry_created_date =        old_dir_entry.fx_dir_entry_created_date;
439
41
    new_dir_entry.fx_dir_entry_last_accessed_date =  old_dir_entry.fx_dir_entry_last_accessed_date;
440
41
    new_dir_entry.fx_dir_entry_time =                old_dir_entry.fx_dir_entry_time;
441
41
    new_dir_entry.fx_dir_entry_date =                old_dir_entry.fx_dir_entry_date;
442
443
#ifdef FX_ENABLE_EXFAT
444
    if (media_ptr -> fx_media_FAT_type == FX_exFAT)
445
    {
446
447
        new_dir_entry.fx_dir_entry_dont_use_fat =              old_dir_entry.fx_dir_entry_dont_use_fat;
448
        new_dir_entry.fx_dir_entry_type =                  old_dir_entry.fx_dir_entry_type;
449
        new_dir_entry.fx_dir_entry_available_file_size =   old_dir_entry.fx_dir_entry_available_file_size;
450
        new_dir_entry.fx_dir_entry_secondary_count =       old_dir_entry.fx_dir_entry_secondary_count;
451
    }
452
#endif /* FX_ENABLE_EXFAT */
453
454
    /* Is there a leading dot?  */
455
41
    if (new_dir_entry.fx_dir_entry_name[0] == '.')
456
    {
457
458
        /* Yes, toggle the hidden attribute bit.  */
459
1
        new_dir_entry.fx_dir_entry_attributes |=  FX_HIDDEN;
460
    }
461
462
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
463
464
    /* Invalidate the directory cache.  */
465
41
    media_ptr -> fx_media_last_found_name[0] =  FX_NULL;
466
#endif
467
468
    /* Now write out the directory entry.  */
469
#ifdef FX_ENABLE_EXFAT
470
    if (media_ptr -> fx_media_FAT_type == FX_exFAT)
471
    {
472
473
        status = _fx_directory_exFAT_entry_write(media_ptr, &new_dir_entry, UPDATE_FULL);
474
    }
475
    else
476
    {
477
#endif /* FX_ENABLE_EXFAT */
478
41
        status =  _fx_directory_entry_write(media_ptr, &new_dir_entry);
479
#ifdef FX_ENABLE_EXFAT
480
    }
481
#endif /* FX_ENABLE_EXFAT */
482
483
    /* Determine if the write was successful.  */
484
41
    if (status != FX_SUCCESS)
485
    {
486
487
#ifdef FX_ENABLE_FAULT_TOLERANT
488
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
489
#endif /* FX_ENABLE_FAULT_TOLERANT */
490
491
        /* Release media protection.  */
492
1
        FX_UNPROTECT
493
494
        /* Return the error code.  */
495
1
        return(status);
496
    }
497
498
#ifndef FX_DONT_UPDATE_OPEN_FILES
499
500
    /* Search the opened files to update any currently opened files.  */
501
40
    open_count =  media_ptr -> fx_media_opened_file_count;
502
40
    search_ptr =  media_ptr -> fx_media_opened_file_list;
503
49
    while (open_count)
504
    {
505
506
        /* Look at each opened file to see if it matches the file being renamed.  */
507
9
        if ((search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
508
9
             old_dir_entry.fx_dir_entry_log_sector) &&
509
4
            (search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
510
4
             old_dir_entry.fx_dir_entry_byte_offset))
511
        {
512
513
            /* Yes, the file being renamed is already open.  Update the file's
514
               information so that it is kept current.  */
515
3
            search_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =      new_dir_entry.fx_dir_entry_cluster;
516
3
            search_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =    new_dir_entry.fx_dir_entry_file_size;
517
3
            search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector =   new_dir_entry.fx_dir_entry_log_sector;
518
3
            search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset =  new_dir_entry.fx_dir_entry_byte_offset;
519
520
            /* Copy the new name into the file's name buffer.  */
521
3
            i =  0;
522
284
            while (i < (FX_MAX_LONG_NAME_LEN - 1))
523
            {
524
525
                /* Copy byte of the new name.  */
526
283
                search_ptr -> fx_file_dir_entry.fx_dir_entry_name[i] =  new_dir_entry.fx_dir_entry_name[i];
527
528
                /* Move to the next character.  */
529
283
                i++;
530
531
                /* Determine if we are at the end of the name.  */
532
283
                if (new_dir_entry.fx_dir_entry_name[i] == FX_NULL)
533
                {
534
535
                    /* Determine if we are not at the maximum name size.  */
536
3
                    if (i < (FX_MAX_LONG_NAME_LEN - 1))
537
                    {
538
539
                        /* Get out of the loop.   */
540
2
                        break;
541
                    }
542
                }
543
            }
544
545
            /* Set the NULL termination in the copy of the new name.  */
546
3
            search_ptr -> fx_file_dir_entry.fx_dir_entry_name[i] =  FX_NULL;
547
        }
548
549
        /* Adjust the pointer and decrement the search count.  */
550
9
        search_ptr =  search_ptr -> fx_file_opened_next;
551
9
        open_count--;
552
    }
553
#endif
554
555
    /* Now we are ready to remove the old directory entry.  */
556
40
    old_dir_entry.fx_dir_entry_name[0] =        (CHAR)FX_DIR_ENTRY_FREE;
557
40
    old_dir_entry.fx_dir_entry_short_name[0] =  (CHAR)FX_DIR_ENTRY_FREE;
558
559
    /* Now wipe out the old directory entry.  */
560
#ifdef FX_ENABLE_EXFAT
561
    if (media_ptr -> fx_media_FAT_type == FX_exFAT)
562
    {
563
564
        status = _fx_directory_exFAT_entry_write(media_ptr, &old_dir_entry, UPDATE_DELETE);
565
    }
566
    else
567
    {
568
#endif /* FX_ENABLE_EXFAT */
569
40
        status =  _fx_directory_entry_write(media_ptr, &old_dir_entry);
570
#ifdef FX_ENABLE_EXFAT
571
    }
572
#endif /* FX_ENABLE_EXFAT */
573
574
#ifdef FX_ENABLE_FAULT_TOLERANT
575
    /* Check for a bad status.  */
576
    if (status != FX_SUCCESS)
577
    {
578
579
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
580
581
        /* Release media protection.  */
582
        FX_UNPROTECT
583
584
        /* Return the bad status.  */
585
        return(status);
586
    }
587
588
    /* End transaction. */
589
    status = _fx_fault_tolerant_transaction_end(media_ptr);
590
#endif /* FX_ENABLE_FAULT_TOLERANT */
591
592
    /* Release media protection.  */
593
40
    FX_UNPROTECT
594
595
    /* File rename is complete, return status.  */
596
40
    return(status);
597
}
598