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 /**   Directory                                                           */
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_file.h"
30 #include "fx_utility.h"
31 #include "fx_directory.h"
32 
33 #ifndef FX_NO_LOCAL_PATH
34 FX_LOCAL_PATH_SETUP
35 #endif
36 
37 /**************************************************************************/
38 /*                                                                        */
39 /*  FUNCTION                                               RELEASE        */
40 /*                                                                        */
41 /*    _fx_directory_local_path_set                        PORTABLE C      */
42 /*                                                           6.1.5        */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    William E. Lamie, Microsoft Corporation                             */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This function sets the local default directory of the media to the  */
50 /*    path specified by the caller.  If this path is not found, an error  */
51 /*    code is returned.                                                   */
52 /*                                                                        */
53 /*  INPUT                                                                 */
54 /*                                                                        */
55 /*    media_ptr                             Media control block pointer   */
56 /*    local_path                            Local path control block ptr  */
57 /*    new_path_name                         New path to set current local */
58 /*                                            working directory to        */
59 /*                                                                        */
60 /*  OUTPUT                                                                */
61 /*                                                                        */
62 /*    return status                                                       */
63 /*                                                                        */
64 /*  CALLS                                                                 */
65 /*                                                                        */
66 /*    _fx_directory_search                  Search for the directory name */
67 /*                                          in the directory structure    */
68 /*                                                                        */
69 /*  CALLED BY                                                             */
70 /*                                                                        */
71 /*    Application Code                                                    */
72 /*                                                                        */
73 /*  RELEASE HISTORY                                                       */
74 /*                                                                        */
75 /*    DATE              NAME                      DESCRIPTION             */
76 /*                                                                        */
77 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
78 /*  09-30-2020     William E. Lamie         Modified comment(s),          */
79 /*                                            resulting in version 6.1    */
80 /*  03-02-2021     William E. Lamie         Modified comment(s),          */
81 /*                                            resulting in version 6.1.5  */
82 /*                                                                        */
83 /**************************************************************************/
_fx_directory_local_path_set(FX_MEDIA * media_ptr,FX_LOCAL_PATH * local_path_ptr,CHAR * new_path_name)84 UINT  _fx_directory_local_path_set(FX_MEDIA *media_ptr, FX_LOCAL_PATH *local_path_ptr, CHAR *new_path_name)
85 {
86 
87 #ifndef FX_NO_LOCAL_PATH
88 UINT         status;
89 CHAR        *path_string_ptr;
90 UINT         path_string_capacity;
91 FX_PATH     *path_ptr;
92 UINT         i, j;
93 #endif
94 FX_DIR_ENTRY dir_entry;
95 
96 
97 #ifndef FX_MEDIA_STATISTICS_DISABLE
98 
99     /* Increment the number of times this service has been called.  */
100     media_ptr -> fx_media_directory_local_path_sets++;
101 #endif
102 
103     /* Setup pointer to a name buffer.  */
104     dir_entry.fx_dir_entry_name =  media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
105 
106     /* Setup the local path name buffer pointer.  */
107     local_path_ptr -> fx_path_directory.fx_dir_entry_name =  local_path_ptr -> fx_path_name_buffer;
108 
109     /* Clear the short name string.  */
110     dir_entry.fx_dir_entry_short_name[0] =  (CHAR)0;
111 
112     /* Clear the long name string.  */
113     dir_entry.fx_dir_entry_name[0] =  (CHAR)0;
114 
115     /* Check the media to make sure it is open.  */
116     if (media_ptr -> fx_media_id != FX_MEDIA_ID)
117     {
118 
119         /* Return the media not opened error.  */
120         return(FX_MEDIA_NOT_OPEN);
121     }
122 
123 #ifdef FX_NO_LOCAL_PATH
124 
125     FX_PARAMETER_NOT_USED(new_path_name);
126 
127     /* Error, return to caller.  */
128     return(FX_NOT_IMPLEMENTED);
129 #else
130 
131     /* If trace is enabled, insert this event into the trace buffer.  */
132     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)
133 
134     /* Protect against other threads accessing the media.  */
135     FX_PROTECT
136 
137     /* Look for a root directory selection.  */
138     if ((!new_path_name) || (((new_path_name[0] == '\\') || (new_path_name[0] == '/')) && (new_path_name[1] == (CHAR)0)))
139     {
140 
141         /* Set the default local directory to the root.  */
142         local_path_ptr -> fx_path_directory.fx_dir_entry_name[0] =  (CHAR)0;
143         local_path_ptr -> fx_path_string[0] =                       (CHAR)0;
144         local_path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] =       (CHAR)0;
145 
146         /* Setup thread control block to use this local path pointer.  */
147         _tx_thread_current_ptr -> tx_thread_filex_ptr =  (VOID *)local_path_ptr;
148     }
149     else
150     {
151 
152         /* Search the system for the supplied path and directory name.  */
153         status =  _fx_directory_search(media_ptr, new_path_name, &dir_entry, FX_NULL, FX_NULL);
154 
155         /* Determine if the search failed or if the entry found is not a
156            directory.  */
157         if ((status != FX_SUCCESS) || (!(dir_entry.fx_dir_entry_attributes & FX_DIRECTORY)))
158         {
159 
160             /* Release media protection.  */
161             FX_UNPROTECT
162 
163             /* Invalid Path - Return the error code.  */
164             return(FX_INVALID_PATH);
165         }
166 
167         /* Now update the current path string.  */
168 
169         /* Setup the path string pointer to the start of the current path.  */
170         path_string_ptr =  &(local_path_ptr -> fx_path_string[0]);
171 
172         /* Setup the path string's capacity.  */
173         path_string_capacity =  FX_MAXIMUM_PATH - 1;
174 
175         /* Determine if the new path is relative from the current path.  */
176         if ((new_path_name[0] != '\\') && (new_path_name[0] != '/'))
177         {
178 
179             /* Yes, a relative path was found.  */
180 
181             /* Setup the default path pointer to the local path.  */
182             path_ptr =  local_path_ptr;
183 
184             /* Determine if the local path is different than the current local path.  */
185             if (local_path_ptr !=  (FX_LOCAL_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr)
186             {
187 
188                 /* Yes, there is a difference.  */
189 
190                 /* Should we copy from the default media path or from the previous default
191                    path.  */
192                 if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
193                 {
194 
195                     /* There is a local path so copy the relative path info from it.  */
196                     i =  0;
197                     do
198                     {
199 
200                         /* Copy from previous local to new local path.  */
201                         local_path_ptr -> fx_path_string[i] =
202                             ((FX_LOCAL_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_string[i];
203 
204                         /* Determine if we are done.  */
205                         if (local_path_ptr -> fx_path_string[i] == 0)
206                         {
207 
208                             /* Are we not at the end of the string?  */
209                             if (i < (FX_MAXIMUM_PATH - 1))
210                             {
211 
212                                 /* Yes, break the loop.  */
213                                 break;
214                             }
215                         }
216 
217                         /* Move to the next character.  */
218                         i++;
219 
220                     } while (i < FX_MAXIMUM_PATH);
221                 }
222                 else
223                 {
224 
225                     /* No local path, so copy the relative path information from the media
226                        default.  */
227                     i =  0;
228                     do
229                     {
230 
231                         /* Copy from the media default to new local path.  */
232                         local_path_ptr -> fx_path_string[i] =
233                             media_ptr -> fx_media_default_path.fx_path_string[i];
234 
235                         /* Determine if we are done.  */
236                         if (local_path_ptr -> fx_path_string[i] == 0)
237                         {
238 
239                             /* Are we not at the end of the string?  */
240                             if (i < (FX_MAXIMUM_PATH - 1))
241                             {
242 
243                                 /* Yes, break the loop.  */
244                                 break;
245                             }
246                         }
247 
248                         /* Move to the next character.  */
249                         i++;
250 
251                     } while (i < FX_MAXIMUM_PATH);
252                 }
253             }
254 
255             /* First, check the current path for string overflow.  If this is set,
256                don't attempt to update the current path with relative information.
257                The path won't be valid again until a complete path is given.  */
258             if (path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] == '*')
259             {
260 
261                 /* Yes, don't update the string, just finish the path set processing.  */
262 
263                 /* Determine if we are at the root directory.  */
264                 if (!dir_entry.fx_dir_entry_cluster)
265                 {
266                     /* Set the current directory back to the root directory.  */
267                     dir_entry.fx_dir_entry_name[0] =  (CHAR)0;
268 
269                     /* Clear the current path string.  */
270                     path_ptr -> fx_path_string[0] =  (CHAR)0;
271 
272                     /* Clear the overflow flag in the current path string... just in
273                        case! */
274                     path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] =  (CHAR)0;
275                 }
276 
277                 /* Copy the new directory entry into the media control block.  */
278                 path_ptr -> fx_path_directory =  dir_entry;
279 
280                 /* Reset the local path name buffer pointer, since it was clobbered earlier.  */
281                 local_path_ptr -> fx_path_directory.fx_dir_entry_name =  local_path_ptr -> fx_path_name_buffer;
282 
283                 /* Copy the directory name entry to the local path name area.  */
284                 for (j = 0; j < FX_MAX_LONG_NAME_LEN; j++)
285                 {
286 
287                     /* Copy the name buffer.  */
288                     local_path_ptr -> fx_path_directory.fx_dir_entry_name[j] =  dir_entry.fx_dir_entry_name[j];
289                 }
290 
291                 /* Setup thread control block to use this local path pointer.  */
292                 _tx_thread_current_ptr -> tx_thread_filex_ptr =  (VOID *)local_path_ptr;
293 
294                 /* Release media protection.  */
295                 FX_UNPROTECT
296 
297                 /* Default directory set is complete, return status.  */
298                 return(FX_SUCCESS);
299             }
300 
301             /* Move the current path starting pointer to the end of the current
302                path string.  */
303             while ((path_string_capacity) && (*path_string_ptr != FX_NULL))
304             {
305                 path_string_ptr++;
306                 path_string_capacity--;
307             }
308 
309             /* If room, place the \ character in the path string.  */
310             if (path_string_capacity)
311             {
312 
313                 /* There is room, place the directory marker in the string.  */
314                 *path_string_ptr++ =  '\\';
315                 path_string_capacity--;
316             }
317         }
318         else
319         {
320 
321             /* Setup the default path pointer.  */
322 
323             /* Setup the default path pointer to the local path.  */
324             path_ptr =  local_path_ptr;
325 
326             /* Complete path name given.  Check to see if we need to clear an
327                overflow character from a previous current path string update.  */
328             if (path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] == '*')
329             {
330                 path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] = (CHAR)0;
331             }
332         }
333 
334         /* Copy what we can into the current path.  */
335         while (*new_path_name)
336         {
337 
338             /* Determine if there is a ".." character sequence that specifies the
339                previous path.  */
340             if ((*new_path_name == '.') && (*(new_path_name + 1) == '.'))
341             {
342 
343                 /* Yes, a backward path is found.  The current path pointer
344                    must be moved back to just after the previous \ character.  */
345 
346                 /* Skip the current \0 that is at the end of the current path.  */
347                 path_string_capacity =  path_string_capacity + 2;
348                 path_string_ptr =       path_string_ptr - 2;
349 
350                 while (path_string_capacity <= (FX_MAXIMUM_PATH - 1))
351                 {
352 
353                     /* Move the current path pointer backwards until
354                        a \ character is found.  */
355 
356                     if ((*path_string_ptr == '\\') || (*path_string_ptr == '/'))
357                     {
358 
359                         /* Yes, we have successfully backed up one directory.  */
360                         break;
361                     }
362 
363                     /* Backup another character.  */
364                     path_string_capacity++;
365                     path_string_ptr--;
366                 }
367 
368                 /* Adjust the new directory pointer past the .. characters  */
369                 new_path_name =  new_path_name + 2;
370             }
371             else
372             {
373 
374                 /* Normal characters that need to be copied into the current path.  */
375 
376                 if (path_string_capacity)
377                 {
378 
379                     /* Copy character from the new path into the current path string.  */
380                     *path_string_ptr++ =  *new_path_name++;
381 
382                     path_string_capacity--;
383                 }
384                 else
385                 {
386 
387                     /* No more room in the current path string!  */
388                     break;
389                 }
390             }
391         }
392 
393         /* Determine if there is still room in the current path string.  */
394         if (path_string_capacity)
395         {
396 
397             /* Yes, there is still room, place a NULL character at the
398                end of the path.  */
399             *path_string_ptr =  (CHAR)FX_NULL;
400         }
401         else
402         {
403 
404             /* No more room.  Determine if the entire path was successfully
405                copied into the current path.  */
406             if (*new_path_name)
407             {
408 
409                 /* No, we couldn't fit the entire path.  Place a "*" character
410                    at the end to indicate that we had overflow.  Note that
411                    the path is kept just the the directory default get call, so
412                    the new default path is valid.  */
413                 path_ptr -> fx_path_string[FX_MAXIMUM_PATH - 2] =  '*';
414             }
415         }
416 
417         /* Determine if we are at the root directory.  */
418         if (!dir_entry.fx_dir_entry_cluster)
419         {
420             /* Set the current directory back to the root directory.  */
421             dir_entry.fx_dir_entry_name[0] =            (CHAR)0;
422             local_path_ptr -> fx_path_name_buffer[0] =  (CHAR)0;
423         }
424 
425         /* Copy the new directory entry into the media control block.  */
426         path_ptr -> fx_path_directory =  dir_entry;
427 
428         /* Reset the local path name buffer pointer, since it was clobbered earlier.  */
429         local_path_ptr -> fx_path_directory.fx_dir_entry_name =  local_path_ptr -> fx_path_name_buffer;
430 
431         /* Copy the directory name entry to the local path name area.  */
432         for (j = 0; j < FX_MAX_LONG_NAME_LEN; j++)
433         {
434 
435             /* Copy the name buffer.  */
436             local_path_ptr -> fx_path_directory.fx_dir_entry_name[j] =  dir_entry.fx_dir_entry_name[j];
437         }
438 
439         /* Setup thread control block to use this local path pointer.  */
440         _tx_thread_current_ptr -> tx_thread_filex_ptr =  (VOID *)local_path_ptr;
441     }
442 
443     /* Release media protection.  */
444     FX_UNPROTECT
445 
446     /* Default directory set is complete, return status.  */
447     return(FX_SUCCESS);
448 #endif
449 }
450 
451