GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_rename.c Lines: 100 100 100.0 %
Date: 2024-03-11 05:15:45 Branches: 62 62 100.0 %

Line Branch Exec Source
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
/**   File                                                                */
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_file_rename                                     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 file.  If found, */
50
/*    the rename request is valid and the directory entry will be changed */
51
/*    to the new file name.  Otherwise, if the file is not found, the     */
52
/*    appropriate error code is returned to the caller.                   */
53
/*                                                                        */
54
/*  INPUT                                                                 */
55
/*                                                                        */
56
/*    media_ptr                             Media control block pointer   */
57
/*    old_file_name                         Old file name pointer         */
58
/*    new_file_name                         New file name pointer         */
59
/*                                                                        */
60
/*  OUTPUT                                                                */
61
/*                                                                        */
62
/*    return status                                                       */
63
/*                                                                        */
64
/*  CALLS                                                                 */
65
/*                                                                        */
66
/*    _fx_directory_entry_write             Write the new directory entry */
67
/*    _fx_directory_free_search             Search for a free directory   */
68
/*                                            entry in target directory   */
69
/*    _fx_directory_name_extract            Extract the new filename      */
70
/*    _fx_directory_search                  Search for the file name in   */
71
/*                                          the directory structure       */
72
/*    _fx_fault_tolerant_transaction_start  Start fault tolerant          */
73
/*                                            transaction                 */
74
/*    _fx_fault_tolerant_transaction_end    End fault tolerant transaction*/
75
/*    _fx_fault_tolerant_recover            Recover FAT chain             */
76
/*                                                                        */
77
/*  CALLED BY                                                             */
78
/*                                                                        */
79
/*    Application Code                                                    */
80
/*                                                                        */
81
/*  RELEASE HISTORY                                                       */
82
/*                                                                        */
83
/*    DATE              NAME                      DESCRIPTION             */
84
/*                                                                        */
85
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
86
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
87
/*                                            resulting in version 6.1    */
88
/*                                                                        */
89
/**************************************************************************/
90
91
UINT  _fx_file_rename(FX_MEDIA *media_ptr, CHAR *old_file_name, CHAR *new_file_name)
91
{
92
93
ULONG        i;
94
CHAR        *work_ptr;
95
CHAR         alpha, beta;
96
UINT         status;
97
98
#ifndef FX_DONT_UPDATE_OPEN_FILES
99
ULONG        open_count;
100
FX_FILE     *search_ptr;
101
#endif
102
CHAR        *new_name_ptr;
103
FX_DIR_ENTRY old_dir_entry, new_dir_entry;
104
FX_DIR_ENTRY search_directory;
105
#ifdef FX_RENAME_PATH_INHERIT
106
UINT         j;
107
#endif
108
UCHAR        not_a_file_attr;
109
110
111
#ifndef FX_MEDIA_STATISTICS_DISABLE
112
113
    /* Increment the number of times this service has been called.  */
114
91
    media_ptr -> fx_media_file_renames++;
115
#endif
116
117
    /* Setup pointers to media name buffers.  */
118
91
    old_dir_entry.fx_dir_entry_name =     media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
119
91
    new_dir_entry.fx_dir_entry_name =     media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 2;
120
91
    search_directory.fx_dir_entry_name =  media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 3;
121
122
    /* Clear the short name strings.  */
123
91
    old_dir_entry.fx_dir_entry_short_name[0] =     0;
124
91
    new_dir_entry.fx_dir_entry_short_name[0] =     0;
125
91
    search_directory.fx_dir_entry_short_name[0] =  0;
126
127
    /* Determine if the supplied name is less than the maximum supported name size. The
128
       maximum name (FX_MAX_LONG_NAME_LEN) is defined in fx_api.h.  */
129
91
    i =  0;
130
91
    work_ptr =  (CHAR *)new_file_name;
131
1845
    while (*work_ptr)
132
    {
133
134
        /* Determine if the character designates a new path.  */
135

1754
        if ((*work_ptr == '\\') || (*work_ptr == '/'))
136
        {
137
            /* Yes, reset the name size.  */
138
10
            i =  0;
139
        }
140
        /* Check for leading spaces.  */
141

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

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

1136
            if ((alpha >= 'a') && (alpha <= 'z'))
324
            {
325
326
                /* Lower case, convert to upper case!  */
327
1023
                alpha =  (CHAR)((INT)alpha - 0x20);
328
            }
329
1136
            beta =   new_file_name[i];
330

1136
            if ((beta >= 'a') && (beta <= 'z'))
331
            {
332
333
                /* Lower case, convert to upper case!  */
334
1078
                beta = (CHAR)((INT)beta - 0x20);
335
            }
336
337
            /* Now compare the characters.  */
338

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