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

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