GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_directory_local_path_set.c Lines: 88 88 100.0 %
Date: 2026-03-06 18:49:02 Branches: 70 70 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_file.h"
31
#include "fx_utility.h"
32
#include "fx_directory.h"
33
34
#ifndef FX_NO_LOCAL_PATH
35
FX_LOCAL_PATH_SETUP
36
#endif
37
38
/**************************************************************************/
39
/*                                                                        */
40
/*  FUNCTION                                               RELEASE        */
41
/*                                                                        */
42
/*    _fx_directory_local_path_set                        PORTABLE C      */
43
/*                                                           6.1.5        */
44
/*  AUTHOR                                                                */
45
/*                                                                        */
46
/*    William E. Lamie, Microsoft Corporation                             */
47
/*                                                                        */
48
/*  DESCRIPTION                                                           */
49
/*                                                                        */
50
/*    This function sets the local default directory of the media to the  */
51
/*    path specified by the caller.  If this path is not found, an error  */
52
/*    code is returned.                                                   */
53
/*                                                                        */
54
/*  INPUT                                                                 */
55
/*                                                                        */
56
/*    media_ptr                             Media control block pointer   */
57
/*    local_path                            Local path control block ptr  */
58
/*    new_path_name                         New path to set current local */
59
/*                                            working directory to        */
60
/*                                                                        */
61
/*  OUTPUT                                                                */
62
/*                                                                        */
63
/*    return status                                                       */
64
/*                                                                        */
65
/*  CALLS                                                                 */
66
/*                                                                        */
67
/*    _fx_directory_search                  Search for the directory name */
68
/*                                          in the directory structure    */
69
/*                                                                        */
70
/*  CALLED BY                                                             */
71
/*                                                                        */
72
/*    Application Code                                                    */
73
/*                                                                        */
74
/**************************************************************************/
75
197
UINT  _fx_directory_local_path_set(FX_MEDIA *media_ptr, FX_LOCAL_PATH *local_path_ptr, CHAR *new_path_name)
76
{
77
78
#ifndef FX_NO_LOCAL_PATH
79
UINT         status;
80
CHAR        *path_string_ptr;
81
UINT         path_string_capacity;
82
FX_PATH     *path_ptr;
83
UINT         i, j;
84
#endif
85
FX_DIR_ENTRY dir_entry;
86
87
88
#ifndef FX_MEDIA_STATISTICS_DISABLE
89
90
    /* Increment the number of times this service has been called.  */
91
197
    media_ptr -> fx_media_directory_local_path_sets++;
92
#endif
93
94
    /* Setup pointer to a name buffer.  */
95
197
    dir_entry.fx_dir_entry_name =  media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
96
97
    /* Setup the local path name buffer pointer.  */
98
197
    local_path_ptr -> fx_path_directory.fx_dir_entry_name =  local_path_ptr -> fx_path_name_buffer;
99
100
    /* Clear the short name string.  */
101
197
    dir_entry.fx_dir_entry_short_name[0] =  (CHAR)0;
102
103
    /* Clear the long name string.  */
104
197
    dir_entry.fx_dir_entry_name[0] =  (CHAR)0;
105
106
    /* Check the media to make sure it is open.  */
107
197
    if (media_ptr -> fx_media_id != FX_MEDIA_ID)
108
    {
109
110
        /* Return the media not opened error.  */
111
1
        return(FX_MEDIA_NOT_OPEN);
112
    }
113
114
#ifdef FX_NO_LOCAL_PATH
115
116
    FX_PARAMETER_NOT_USED(new_path_name);
117
118
    /* Error, return to caller.  */
119
    return(FX_NOT_IMPLEMENTED);
120
#else
121
122
    /* If trace is enabled, insert this event into the trace buffer.  */
123
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_LOCAL_PATH_SET, media_ptr, local_path_ptr, new_path_name, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
124
125
    /* Protect against other threads accessing the media.  */
126
196
    FX_PROTECT
127
128
    /* Look for a root directory selection.  */
129


196
    if ((!new_path_name) || (((new_path_name[0] == '\\') || (new_path_name[0] == '/')) && (new_path_name[1] == (CHAR)0)))
130
    {
131
132
        /* Set the default local directory to the root.  */
133
5
        local_path_ptr -> fx_path_directory.fx_dir_entry_name[0] =  (CHAR)0;
134
5
        local_path_ptr -> fx_path_string[0] =                       (CHAR)0;
135
5
        local_path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] =       (CHAR)0;
136
137
        /* Setup thread control block to use this local path pointer.  */
138
5
        _tx_thread_current_ptr -> tx_thread_filex_ptr =  (VOID *)local_path_ptr;
139
    }
140
    else
141
    {
142
143
        /* Search the system for the supplied path and directory name.  */
144
191
        status =  _fx_directory_search(media_ptr, new_path_name, &dir_entry, FX_NULL, FX_NULL);
145
146
        /* Determine if the search failed or if the entry found is not a
147
           directory.  */
148

191
        if ((status != FX_SUCCESS) || (!(dir_entry.fx_dir_entry_attributes & FX_DIRECTORY)))
149
        {
150
151
            /* Release media protection.  */
152
7
            FX_UNPROTECT
153
154
            /* Invalid Path - Return the error code.  */
155
7
            return(FX_INVALID_PATH);
156
        }
157
158
        /* Now update the current path string.  */
159
160
        /* Setup the path string pointer to the start of the current path.  */
161
184
        path_string_ptr =  &(local_path_ptr -> fx_path_string[0]);
162
163
        /* Setup the path string's capacity.  */
164
184
        path_string_capacity =  FX_MAXIMUM_PATH - 1;
165
166
        /* Determine if the new path is relative from the current path.  */
167

184
        if ((new_path_name[0] != '\\') && (new_path_name[0] != '/'))
168
        {
169
170
            /* Yes, a relative path was found.  */
171
172
            /* Setup the default path pointer to the local path.  */
173
180
            path_ptr =  local_path_ptr;
174
175
            /* Determine if the local path is different than the current local path.  */
176
180
            if (local_path_ptr !=  (FX_LOCAL_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr)
177
            {
178
179
                /* Yes, there is a difference.  */
180
181
                /* Should we copy from the default media path or from the previous default
182
                   path.  */
183
81
                if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
184
                {
185
186
                    /* There is a local path so copy the relative path info from it.  */
187
70
                    i =  0;
188
                    do
189
                    {
190
191
                        /* Copy from previous local to new local path.  */
192
1573
                        local_path_ptr -> fx_path_string[i] =
193
1573
                            ((FX_LOCAL_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_string[i];
194
195
                        /* Determine if we are done.  */
196
1573
                        if (local_path_ptr -> fx_path_string[i] == 0)
197
                        {
198
199
                            /* Are we not at the end of the string?  */
200
70
                            if (i < (FX_MAXIMUM_PATH - 1))
201
                            {
202
203
                                /* Yes, break the loop.  */
204
69
                                break;
205
                            }
206
                        }
207
208
                        /* Move to the next character.  */
209
1504
                        i++;
210
211
1504
                    } while (i < FX_MAXIMUM_PATH);
212
                }
213
                else
214
                {
215
216
                    /* No local path, so copy the relative path information from the media
217
                       default.  */
218
11
                    i =  0;
219
                    do
220
                    {
221
222
                        /* Copy from the media default to new local path.  */
223
266
                        local_path_ptr -> fx_path_string[i] =
224
266
                            media_ptr -> fx_media_default_path.fx_path_string[i];
225
226
                        /* Determine if we are done.  */
227
266
                        if (local_path_ptr -> fx_path_string[i] == 0)
228
                        {
229
230
                            /* Are we not at the end of the string?  */
231
11
                            if (i < (FX_MAXIMUM_PATH - 1))
232
                            {
233
234
                                /* Yes, break the loop.  */
235
10
                                break;
236
                            }
237
                        }
238
239
                        /* Move to the next character.  */
240
256
                        i++;
241
242
256
                    } while (i < FX_MAXIMUM_PATH);
243
                }
244
            }
245
246
            /* First, check the current path for string overflow.  If this is set,
247
               don't attempt to update the current path with relative information.
248
               The path won't be valid again until a complete path is given.  */
249
180
            if (path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] == '*')
250
            {
251
252
                /* Yes, don't update the string, just finish the path set processing.  */
253
254
                /* Determine if we are at the root directory.  */
255
47
                if (!dir_entry.fx_dir_entry_cluster)
256
                {
257
                    /* Set the current directory back to the root directory.  */
258
4
                    dir_entry.fx_dir_entry_name[0] =  (CHAR)0;
259
260
                    /* Clear the current path string.  */
261
4
                    path_ptr -> fx_path_string[0] =  (CHAR)0;
262
263
                    /* Clear the overflow flag in the current path string... just in
264
                       case! */
265
4
                    path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] =  (CHAR)0;
266
                }
267
268
                /* Copy the new directory entry into the media control block.  */
269
47
                path_ptr -> fx_path_directory =  dir_entry;
270
271
                /* Reset the local path name buffer pointer, since it was clobbered earlier.  */
272
47
                local_path_ptr -> fx_path_directory.fx_dir_entry_name =  local_path_ptr -> fx_path_name_buffer;
273
274
                /* Copy the directory name entry to the local path name area.  */
275
12079
                for (j = 0; j < FX_MAX_LONG_NAME_LEN; j++)
276
                {
277
278
                    /* Copy the name buffer.  */
279
12032
                    local_path_ptr -> fx_path_directory.fx_dir_entry_name[j] =  dir_entry.fx_dir_entry_name[j];
280
                }
281
282
                /* Setup thread control block to use this local path pointer.  */
283
47
                _tx_thread_current_ptr -> tx_thread_filex_ptr =  (VOID *)local_path_ptr;
284
285
                /* Release media protection.  */
286
47
                FX_UNPROTECT
287
288
                /* Default directory set is complete, return status.  */
289
47
                return(FX_SUCCESS);
290
            }
291
292
            /* Move the current path starting pointer to the end of the current
293
               path string.  */
294

7325
            while ((path_string_capacity) && (*path_string_ptr != FX_NULL))
295
            {
296
7192
                path_string_ptr++;
297
7192
                path_string_capacity--;
298
            }
299
300
            /* If room, place the \ character in the path string.  */
301
133
            if (path_string_capacity)
302
            {
303
304
                /* There is room, place the directory marker in the string.  */
305
132
                *path_string_ptr++ =  '\\';
306
132
                path_string_capacity--;
307
            }
308
        }
309
        else
310
        {
311
312
            /* Setup the default path pointer.  */
313
314
            /* Setup the default path pointer to the local path.  */
315
4
            path_ptr =  local_path_ptr;
316
317
            /* Complete path name given.  Check to see if we need to clear an
318
               overflow character from a previous current path string update.  */
319
4
            if (path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] == '*')
320
            {
321
1
                path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] = (CHAR)0;
322
            }
323
        }
324
325
        /* Copy what we can into the current path.  */
326
3091
        while (*new_path_name)
327
        {
328
329
            /* Determine if there is a ".." character sequence that specifies the
330
               previous path.  */
331

2959
            if ((*new_path_name == '.') && (*(new_path_name + 1) == '.'))
332
            {
333
334
                /* Yes, a backward path is found.  The current path pointer
335
                   must be moved back to just after the previous \ character.  */
336
337
                /* Skip the current \0 that is at the end of the current path.  */
338
6
                path_string_capacity =  path_string_capacity + 2;
339
6
                path_string_ptr =       path_string_ptr - 2;
340
341
109
                while (path_string_capacity <= (FX_MAXIMUM_PATH - 1))
342
                {
343
344
                    /* Move the current path pointer backwards until
345
                       a \ character is found.  */
346
347

107
                    if ((*path_string_ptr == '\\') || (*path_string_ptr == '/'))
348
                    {
349
350
                        /* Yes, we have successfully backed up one directory.  */
351
                        break;
352
                    }
353
354
                    /* Backup another character.  */
355
103
                    path_string_capacity++;
356
103
                    path_string_ptr--;
357
                }
358
359
                /* Adjust the new directory pointer past the .. characters  */
360
6
                new_path_name =  new_path_name + 2;
361
            }
362
            else
363
            {
364
365
                /* Normal characters that need to be copied into the current path.  */
366
367
2953
                if (path_string_capacity)
368
                {
369
370
                    /* Copy character from the new path into the current path string.  */
371
2948
                    *path_string_ptr++ =  *new_path_name++;
372
373
2948
                    path_string_capacity--;
374
                }
375
                else
376
                {
377
378
                    /* No more room in the current path string!  */
379
5
                    break;
380
                }
381
            }
382
        }
383
384
        /* Determine if there is still room in the current path string.  */
385
137
        if (path_string_capacity)
386
        {
387
388
            /* Yes, there is still room, place a NULL character at the
389
               end of the path.  */
390
130
            *path_string_ptr =  (CHAR)FX_NULL;
391
        }
392
        else
393
        {
394
395
            /* No more room.  Determine if the entire path was successfully
396
               copied into the current path.  */
397
7
            if (*new_path_name)
398
            {
399
400
                /* No, we couldn't fit the entire path.  Place a "*" character
401
                   at the end to indicate that we had overflow.  Note that
402
                   the path is kept just the the directory default get call, so
403
                   the new default path is valid.  */
404
5
                path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] =  '*';
405
            }
406
        }
407
408
        /* Determine if we are at the root directory.  */
409
137
        if (!dir_entry.fx_dir_entry_cluster)
410
        {
411
            /* Set the current directory back to the root directory.  */
412
3
            dir_entry.fx_dir_entry_name[0] =            (CHAR)0;
413
3
            local_path_ptr -> fx_path_name_buffer[0] =  (CHAR)0;
414
        }
415
416
        /* Copy the new directory entry into the media control block.  */
417
137
        path_ptr -> fx_path_directory =  dir_entry;
418
419
        /* Reset the local path name buffer pointer, since it was clobbered earlier.  */
420
137
        local_path_ptr -> fx_path_directory.fx_dir_entry_name =  local_path_ptr -> fx_path_name_buffer;
421
422
        /* Copy the directory name entry to the local path name area.  */
423
35209
        for (j = 0; j < FX_MAX_LONG_NAME_LEN; j++)
424
        {
425
426
            /* Copy the name buffer.  */
427
35072
            local_path_ptr -> fx_path_directory.fx_dir_entry_name[j] =  dir_entry.fx_dir_entry_name[j];
428
        }
429
430
        /* Setup thread control block to use this local path pointer.  */
431
137
        _tx_thread_current_ptr -> tx_thread_filex_ptr =  (VOID *)local_path_ptr;
432
    }
433
434
    /* Release media protection.  */
435
142
    FX_UNPROTECT
436
437
    /* Default directory set is complete, return status.  */
438
142
    return(FX_SUCCESS);
439
#endif
440
}
441