GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_extended_truncate.c Lines: 63 63 100.0 %
Date: 2024-01-10 21:53:23 Branches: 28 28 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_FAULT_TOLERANT
34
#include "fx_fault_tolerant.h"
35
#endif /* FX_ENABLE_FAULT_TOLERANT */
36
37
38
/**************************************************************************/
39
/*                                                                        */
40
/*  FUNCTION                                               RELEASE        */
41
/*                                                                        */
42
/*    _fx_file_extended_truncate                          PORTABLE C      */
43
/*                                                           6.1          */
44
/*  AUTHOR                                                                */
45
/*                                                                        */
46
/*    William E. Lamie, Microsoft Corporation                             */
47
/*                                                                        */
48
/*  DESCRIPTION                                                           */
49
/*                                                                        */
50
/*    This function sets the file to the specified size, if smaller than  */
51
/*    the current file size.  If the new file size is less than the       */
52
/*    current file read/write position, the internal file pointers will   */
53
/*    also be modified.                                                   */
54
/*                                                                        */
55
/*  INPUT                                                                 */
56
/*                                                                        */
57
/*    file_ptr                              File control block pointer    */
58
/*    size                                  New size of the file in bytes */
59
/*                                                                        */
60
/*  OUTPUT                                                                */
61
/*                                                                        */
62
/*    return status                                                       */
63
/*                                                                        */
64
/*  CALLS                                                                 */
65
/*                                                                        */
66
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
67
/*    _fx_fault_tolerant_transaction_start  Start fault tolerant          */
68
/*                                            transaction                 */
69
/*    _fx_fault_tolerant_transaction_end    End fault tolerant transaction*/
70
/*    _fx_fault_tolerant_recover            Recover FAT chain             */
71
/*    _fx_fault_tolerant_reset_log_file     Reset the log file            */
72
/*                                                                        */
73
/*  CALLED BY                                                             */
74
/*                                                                        */
75
/*    Application Code                                                    */
76
/*                                                                        */
77
/*  RELEASE HISTORY                                                       */
78
/*                                                                        */
79
/*    DATE              NAME                      DESCRIPTION             */
80
/*                                                                        */
81
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
82
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
83
/*                                            resulting in version 6.1    */
84
/*                                                                        */
85
/**************************************************************************/
86
11
UINT  _fx_file_extended_truncate(FX_FILE *file_ptr, ULONG64 size)
87
{
88
89
UINT                   status;
90
ULONG                  cluster;
91
11
ULONG                  contents = 0;
92
ULONG                  bytes_per_cluster;
93
ULONG                  last_cluster;
94
ULONG                  cluster_count;
95
ULONG64                bytes_remaining;
96
FX_MEDIA              *media_ptr;
97
98
#ifndef FX_DONT_UPDATE_OPEN_FILES
99
ULONG                  open_count;
100
FX_FILE               *search_ptr;
101
#endif
102
103
#ifdef TX_ENABLE_EVENT_TRACE
104
TX_TRACE_BUFFER_ENTRY *trace_event;
105
ULONG                  trace_timestamp;
106
#endif
107
108
109
    /* First, determine if the file is still open.  */
110
11
    if (file_ptr -> fx_file_id != FX_FILE_ID)
111
    {
112
113
        /* Return the file not open error status.  */
114
1
        return(FX_NOT_OPEN);
115
    }
116
117
#ifndef FX_MEDIA_STATISTICS_DISABLE
118
    /* Setup pointer to media structure.  */
119
10
    media_ptr =  file_ptr -> fx_file_media_ptr;
120
121
    /* Increment the number of times this service has been called.  */
122
10
    media_ptr -> fx_media_file_truncates++;
123
#endif
124
125
    /* Setup pointer to associated media control block.  */
126
10
    media_ptr =  file_ptr -> fx_file_media_ptr;
127
128
    /* If trace is enabled, insert this event into the trace buffer.  */
129
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_TRUNCATE, file_ptr, size, file_ptr -> fx_file_current_file_size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
130
131
    /* Protect against other threads accessing the media.  */
132
10
    FX_PROTECT
133
134
    /* Make sure this file is open for writing.  */
135
10
    if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
136
    {
137
138
        /* Release media protection.  */
139
1
        FX_UNPROTECT
140
141
        /* Return the access error exception - a write was attempted from
142
           a file opened for reading!  */
143
1
        return(FX_ACCESS_ERROR);
144
    }
145
146
    /* Check for write protect at the media level (set by driver).  */
147
9
    if (media_ptr -> fx_media_driver_write_protect)
148
    {
149
150
        /* Release media protection.  */
151
1
        FX_UNPROTECT
152
153
        /* Return write protect error.  */
154
1
        return(FX_WRITE_PROTECT);
155
    }
156
157
    /* Setup the new file size - if less than the current size.  */
158
8
    if (size < file_ptr -> fx_file_current_file_size)
159
    {
160
161
        /* Setup the new size.  */
162
7
        file_ptr -> fx_file_current_file_size =  size;
163
164
        /* Set the modified flag as well.  */
165
7
        file_ptr -> fx_file_modified =  FX_TRUE;
166
167
        /* Update the trace event with the truncated size.  */
168
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE, 0, 0, 0, size)
169
    }
170
    else
171
    {
172
173
        /* Update the trace event with the truncated size.  */
174
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE, 0, 0, 0, file_ptr -> fx_file_current_file_size)
175
176
        /* Release media protection.  */
177
1
        FX_UNPROTECT
178
179
        /* Just return, the new size is larger than the current size.  */
180
1
        return(FX_SUCCESS);
181
    }
182
183
#ifndef FX_DONT_UPDATE_OPEN_FILES
184
185
    /* Search the opened files list to see if the same file is opened for reading.  */
186
7
    open_count =  media_ptr -> fx_media_opened_file_count;
187
7
    search_ptr =  media_ptr -> fx_media_opened_file_list;
188
31
    while (open_count)
189
    {
190
191
        /* Is this file the same file opened for reading?  */
192
24
        if ((search_ptr != file_ptr) &&
193
17
            (search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
194
17
             file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
195
12
            (search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
196
12
             file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset))
197
        {
198
199
            /* Yes, the same file is opened for reading.  */
200
201
            /* Setup the new file size.  */
202
5
            search_ptr -> fx_file_current_file_size =  size;
203
5
            search_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = size;
204
        }
205
206
        /* Adjust the pointer and decrement the search count.  */
207
24
        search_ptr =  search_ptr -> fx_file_opened_next;
208
24
        open_count--;
209
    }
210
#endif
211
212
    /* Now check to see if the read/write internal file pointers need
213
       to be adjusted.  */
214
7
    if (file_ptr -> fx_file_current_file_offset > file_ptr -> fx_file_current_file_size)
215
    {
216
217
        /* Calculate the number of bytes per cluster.  */
218
6
        bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
219
6
            ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
220
221
        /* At this point, we are ready to walk list of clusters to setup the
222
           seek position of this file.  */
223
6
        cluster =           file_ptr -> fx_file_first_physical_cluster;
224
6
        bytes_remaining =   size;
225
6
        last_cluster =      0;
226
6
        cluster_count =     0;
227
228
        /* Follow the link of FAT entries.  */
229

270
        while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
230
        {
231
232
            /* Increment the number of clusters.  */
233
268
            cluster_count++;
234
#ifdef FX_ENABLE_EXFAT
235
            if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
236
            {
237
                if (cluster >= file_ptr -> fx_file_last_physical_cluster)
238
                {
239
                    contents = FX_LAST_CLUSTER_exFAT;
240
                }
241
                else
242
                {
243
                    contents = cluster + 1;
244
                }
245
            }
246
            else
247
            {
248
#endif /* FX_ENABLE_EXFAT */
249
250
                /* Read the current cluster entry from the FAT.  */
251
268
                status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
252
253
                /* Check the return value.  */
254
268
                if (status != FX_SUCCESS)
255
                {
256
257
                    /* Release media protection.  */
258
1
                    FX_UNPROTECT
259
260
                    /* Return the error status.  */
261
1
                    return(status);
262
                }
263
#ifdef FX_ENABLE_EXFAT
264
            }
265
#endif /* FX_ENABLE_EXFAT */
266
267
            /* Save the last valid cluster.  */
268
267
            last_cluster =  cluster;
269
270
            /* Setup for the next cluster.  */
271
267
            cluster =  contents;
272
273
            /* Determine if this is the last written cluster.  */
274
267
            if (bytes_remaining >= bytes_per_cluster)
275
            {
276
277
                /* Still more seeking, just decrement the working byte offset.  */
278
264
                bytes_remaining =  bytes_remaining - bytes_per_cluster;
279
            }
280
            else
281
            {
282
283
                /* This is the cluster that contains the seek position.  */
284
3
                break;
285
            }
286
        }
287
288
        /* Check for errors in traversal of the FAT chain.  */
289
5
        if (size > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
290
        {
291
292
            /* Release media protection.  */
293
2
            FX_UNPROTECT
294
295
            /* This is an error that suggests a corrupt file.  */
296
2
            return(FX_FILE_CORRUPT);
297
        }
298
299
        /* Position the pointers to the new offset.  */
300
3
        file_ptr -> fx_file_current_physical_cluster =  last_cluster;
301
3
        file_ptr -> fx_file_current_relative_cluster =  cluster_count - 1;
302
3
        file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
303
3
            (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
304
3
             ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
305
3
            (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector);
306
3
        file_ptr -> fx_file_current_relative_sector =   (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
307
3
        file_ptr -> fx_file_current_file_offset =       size;
308
3
        file_ptr -> fx_file_current_logical_offset =    (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
309
    }
310
311
#ifdef FX_ENABLE_FAULT_TOLERANT
312
    if (media_ptr -> fx_media_fault_tolerant_enabled)
313
    {
314
315
        /* Start transaction. */
316
        _fx_fault_tolerant_transaction_start(media_ptr);
317
318
        /* Copy the new file size into the directory entry.  */
319
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
320
321
        /* Write the directory entry to the media.  */
322
#ifdef FX_ENABLE_EXFAT
323
        if (media_ptr -> fx_media_FAT_type == FX_exFAT)
324
        {
325
326
            status = _fx_directory_exFAT_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
327
        }
328
        else
329
        {
330
#endif /* FX_ENABLE_EXFAT */
331
            status =  _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
332
#ifdef FX_ENABLE_EXFAT
333
        }
334
#endif /* FX_ENABLE_EXFAT */
335
336
        /* Check for a good status.  */
337
        if (status != FX_SUCCESS)
338
        {
339
340
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
341
342
            /* Release media protection.  */
343
            FX_UNPROTECT
344
345
            /* Error writing the directory.  */
346
            return(status);
347
        }
348
349
        /* End transaction. */
350
        status = _fx_fault_tolerant_transaction_end(media_ptr);
351
352
        /* Check for a good status.  */
353
        if (status != FX_SUCCESS)
354
        {
355
356
            /* Release media protection.  */
357
            FX_UNPROTECT
358
359
            /* Error writing the directory.  */
360
            return(status);
361
        }
362
363
        /* Update maximum size used if necessary. */
364
        if (size < file_ptr -> fx_file_maximum_size_used)
365
        {
366
            file_ptr -> fx_file_maximum_size_used = size;
367
        }
368
    }
369
#endif /* FX_ENABLE_FAULT_TOLERANT */
370
371
    /* Release media protection.  */
372
4
    FX_UNPROTECT
373
374
    /* Truncate is complete, return successful status.  */
375
4
    return(FX_SUCCESS);
376
}
377