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_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_directory_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 directory. */
50 /* If found, the rename request is valid and the directory will be */
51 /* changed to the new name. Otherwise, if the directory is not found, */
52 /* the appropriate error code is returned to the caller. */
53 /* */
54 /* INPUT */
55 /* */
56 /* media_ptr Media control block pointer */
57 /* old_directory_name Old file directory pointer */
58 /* new_directory_name New file directory 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 */
69 /* _fx_directory_name_extract Extract directory name */
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 /* _fx_fault_tolerant_reset_log_file Reset the log file */
77 /* */
78 /* CALLED BY */
79 /* */
80 /* Application Code */
81 /* */
82 /* RELEASE HISTORY */
83 /* */
84 /* DATE NAME DESCRIPTION */
85 /* */
86 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
87 /* 09-30-2020 William E. Lamie Modified comment(s), */
88 /* resulting in version 6.1 */
89 /* */
90 /**************************************************************************/
_fx_directory_rename(FX_MEDIA * media_ptr,CHAR * old_directory_name,CHAR * new_directory_name)91 UINT _fx_directory_rename(FX_MEDIA *media_ptr, CHAR *old_directory_name, CHAR *new_directory_name)
92 {
93
94 UINT status;
95 FX_DIR_ENTRY old_dir_entry;
96 FX_DIR_ENTRY new_dir_entry;
97 FX_DIR_ENTRY search_directory;
98 CHAR *new_name_ptr;
99 ULONG i;
100 CHAR *work_ptr;
101 CHAR alpha, beta;
102 #ifdef FX_RENAME_PATH_INHERIT
103 UINT j;
104 #endif
105
106
107 #ifndef FX_MEDIA_STATISTICS_DISABLE
108
109 /* Increment the number of times this service has been called. */
110 media_ptr -> fx_media_directory_renames++;
111 #endif
112
113 /* Setup pointers to media name buffers. */
114 old_dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
115 new_dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 2;
116 search_directory.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 3;
117
118 /* Clear the short name strings. */
119 old_dir_entry.fx_dir_entry_short_name[0] = 0;
120 new_dir_entry.fx_dir_entry_short_name[0] = 0;
121 search_directory.fx_dir_entry_short_name[0] = 0;
122
123 /* Determine if the supplied name is less than the maximum supported name size. The
124 maximum name (FX_MAX_LONG_NAME_LEN) is defined in fx_api.h. */
125 i = 0;
126 work_ptr = (CHAR *)new_directory_name;
127 while (*work_ptr && (i < FX_MAX_LONG_NAME_LEN))
128 {
129
130 /* Determine if the character designates a new path. */
131 if ((*work_ptr == '\\') || (*work_ptr == '/'))
132 {
133 /* Yes, reset the name size. */
134 i = 0;
135 }
136 /* Check for leading spaces. */
137 else if ((*work_ptr != ' ') || (i != 0))
138 {
139
140 /* No leading spaces, increment the name size. */
141 i++;
142 }
143
144 /* Move to the next character. */
145 work_ptr++;
146 }
147
148 /* Determine if the supplied name is valid. */
149 if ((i == 0) || (i >= FX_MAX_LONG_NAME_LEN))
150 {
151
152 /* Return an invalid name value. */
153 return(FX_INVALID_NAME);
154 }
155
156 /* Check the media to make sure it is open. */
157 if (media_ptr -> fx_media_id != FX_MEDIA_ID)
158 {
159
160 /* Return the media not opened error. */
161 return(FX_MEDIA_NOT_OPEN);
162 }
163
164 /* If trace is enabled, insert this event into the trace buffer. */
165 FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_RENAME, media_ptr, old_directory_name, new_directory_name, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
166
167 /* Protect against other threads accessing the media. */
168 FX_PROTECT
169
170 #ifdef FX_ENABLE_FAULT_TOLERANT
171 /* Start transaction. */
172 _fx_fault_tolerant_transaction_start(media_ptr);
173 #endif /* FX_ENABLE_FAULT_TOLERANT */
174
175 /* Check for write protect at the media level (set by driver). */
176 if (media_ptr -> fx_media_driver_write_protect)
177 {
178
179 #ifdef FX_ENABLE_FAULT_TOLERANT
180 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
181 #endif /* FX_ENABLE_FAULT_TOLERANT */
182
183 /* Release media protection. */
184 FX_UNPROTECT
185
186 /* Return write protect error. */
187 return(FX_WRITE_PROTECT);
188 }
189
190 /* Search the system for the supplied directory name. */
191 status = _fx_directory_search(media_ptr, old_directory_name, &old_dir_entry, &search_directory, FX_NULL);
192
193 /* Determine if the search was successful. */
194 if (status != FX_SUCCESS)
195 {
196
197 #ifdef FX_ENABLE_FAULT_TOLERANT
198 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
199 #endif /* FX_ENABLE_FAULT_TOLERANT */
200
201 /* Release media protection. */
202 FX_UNPROTECT
203
204 /* Return the error code. */
205 return(status);
206 }
207
208 /* Check to make sure the found entry is a directory. */
209 if (!(old_dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_DIRECTORY)))
210 {
211
212 #ifdef FX_ENABLE_FAULT_TOLERANT
213 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
214 #endif /* FX_ENABLE_FAULT_TOLERANT */
215
216 /* Release media protection. */
217 FX_UNPROTECT
218
219 /* Return the not a directory error code. */
220 return(FX_NOT_DIRECTORY);
221 }
222
223 #ifdef FX_RENAME_PATH_INHERIT
224
225 /* Determine if the source directory name has a path and the target directory name does not. */
226 if (((old_directory_name[0] == '/') || (old_directory_name[0] == '\\')) && (new_directory_name[0] != '/') && (new_directory_name[0] != '\\'))
227 {
228
229 /* In this case, we need to prepend the path of the old directory name to that of the new directory name. */
230
231 /* Setup pointer to the rename buffer. */
232 work_ptr = (CHAR *)media_ptr -> fx_media_rename_buffer;
233
234 /* First, copy the path of the old directory name. */
235 i = 0;
236 j = 0;
237 while ((old_directory_name[i]) && (i < FX_MAXIMUM_PATH))
238 {
239
240 /* Copy a character into the rename buffer. */
241 *work_ptr++ = old_directory_name[i];
242
243 /* Determine if this character is directory separator. */
244 if ((old_directory_name[i] == '/') || (old_directory_name[i] == '\\'))
245 {
246
247 /* Yes, directory separator has been found - remember the index. */
248 j = i;
249 }
250
251 /* Move to next position in the old directory name. */
252 i++;
253 }
254
255 /* At this point, we have the path stored in the rename buffer. */
256
257 /* Position past the last slash or backslash. */
258 j++;
259
260 /* Reset the working pointer to the position after the last directory separator. */
261 work_ptr = (CHAR *)&(media_ptr -> fx_media_rename_buffer[j]);
262
263 /* Now copy the new directory name into the rename buffer. */
264 i = 0;
265 while ((new_directory_name[i]) && (j < FX_MAXIMUM_PATH))
266 {
267
268 /* Copy a character into the rename buffer. */
269 *work_ptr++ = new_directory_name[i];
270
271 /* Move to next character. */
272 i++;
273 j++;
274 }
275
276 /* Determine if the path was successfully prepended. */
277 if (new_directory_name[i])
278 {
279
280 /* No, there was not enough room in the destination buffer. */
281
282 #ifdef FX_ENABLE_FAULT_TOLERANT
283 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
284 #endif /* FX_ENABLE_FAULT_TOLERANT */
285
286 /* Release media protection. */
287 FX_UNPROTECT
288
289 /* Return the invalid path error code. */
290 return(FX_INVALID_PATH);
291 }
292
293 /* Place a NULL at the end of the string. */
294 *work_ptr = (CHAR)FX_NULL;
295
296 /* At this point, we have successfully prepended the path in the new directory name, override
297 the new directory name so it is used from now on. */
298 new_directory_name = (CHAR *)media_ptr -> fx_media_rename_buffer;
299 }
300 #endif
301
302 /* Search the media for the new directory name - including any supplied path. */
303 status = _fx_directory_search(media_ptr, new_directory_name, &new_dir_entry, &search_directory, &new_name_ptr);
304
305 /* Determine if the search found anything. */
306 if (status == FX_SUCCESS)
307 {
308
309 /* Determine if the new name simply has an ASCII case change. If so, simply let the processing
310 continue. */
311 i = 0;
312 do
313 {
314
315 /* Pickup an old name and new name character and convert to upper case if necessary. */
316 alpha = old_directory_name[i];
317 if ((alpha >= 'a') && (alpha <= 'z'))
318 {
319
320 /* Lower case, convert to upper case! */
321 alpha = (CHAR)((INT)alpha - 0x20);
322 }
323 beta = new_directory_name[i];
324 if ((beta >= 'a') && (beta <= 'z'))
325 {
326
327 /* Lower case, convert to upper case! */
328 beta = (CHAR)((INT)beta - 0x20);
329 }
330
331 /* Now compare the characters. */
332 if ((alpha != beta) || (alpha == 0))
333 {
334
335 /* Get out of this loop! */
336 break;
337 }
338
339 /* Move to next character. */
340 i++;
341 } while (i < (FX_MAXIMUM_PATH-1));
342
343 /* Now determine if the names match. */
344 if (alpha != beta)
345 {
346
347 /* Yes, the directory name already exists in the target location. */
348
349 #ifdef FX_ENABLE_FAULT_TOLERANT
350 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
351 #endif /* FX_ENABLE_FAULT_TOLERANT */
352
353 /* Release media protection. */
354 FX_UNPROTECT
355
356 /* Return the error code. */
357 return(FX_ALREADY_CREATED);
358 }
359 }
360
361 /* Make sure the name is valid. */
362 if (_fx_directory_name_extract(new_name_ptr, &new_dir_entry.fx_dir_entry_name[0]))
363 {
364
365 #ifdef FX_ENABLE_FAULT_TOLERANT
366 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
367 #endif /* FX_ENABLE_FAULT_TOLERANT */
368
369 /* Release media protection */
370 FX_UNPROTECT
371
372 /* Return the error code */
373 return(FX_INVALID_NAME);
374 }
375
376 /* Look for a free slot in the target directory. */
377 status = _fx_directory_free_search(media_ptr, &search_directory, &new_dir_entry);
378
379 /* Was a free slot found? */
380 if (status != FX_SUCCESS)
381 {
382
383 #ifdef FX_ENABLE_FAULT_TOLERANT
384 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
385 #endif /* FX_ENABLE_FAULT_TOLERANT */
386
387 /* No, release protection. */
388 FX_UNPROTECT
389
390 /* Return the error code. */
391 return(status);
392 }
393
394 /* Extract the new directory name. */
395 _fx_directory_name_extract(new_name_ptr, &new_dir_entry.fx_dir_entry_name[0]);
396
397 /* Determine if the name was a long directory name. */
398 if (new_dir_entry.fx_dir_entry_long_name_present)
399 {
400
401 /* Yes, clear the short directory name to force a new one. */
402 new_dir_entry.fx_dir_entry_short_name[0] = 0;
403 }
404
405 /* Setup new attributes for the new directory entry. */
406 new_dir_entry.fx_dir_entry_attributes = old_dir_entry.fx_dir_entry_attributes;
407 new_dir_entry.fx_dir_entry_cluster = old_dir_entry.fx_dir_entry_cluster;
408 new_dir_entry.fx_dir_entry_file_size = old_dir_entry.fx_dir_entry_file_size;
409
410 /* Save the reserved field. */
411 new_dir_entry.fx_dir_entry_reserved = old_dir_entry.fx_dir_entry_reserved;
412
413 /* Set time and date stamps. */
414 new_dir_entry.fx_dir_entry_created_time_ms = old_dir_entry.fx_dir_entry_created_time_ms;
415 new_dir_entry.fx_dir_entry_created_time = old_dir_entry.fx_dir_entry_created_time;
416 new_dir_entry.fx_dir_entry_created_date = old_dir_entry.fx_dir_entry_created_date;
417 new_dir_entry.fx_dir_entry_last_accessed_date = old_dir_entry.fx_dir_entry_last_accessed_date;
418 new_dir_entry.fx_dir_entry_time = old_dir_entry.fx_dir_entry_time;
419 new_dir_entry.fx_dir_entry_date = old_dir_entry.fx_dir_entry_date;
420
421
422 /* Is there a leading dot? */
423 if (new_dir_entry.fx_dir_entry_name[0] == '.')
424 {
425
426 /* Yes, toggle the hidden attribute bit. */
427 new_dir_entry.fx_dir_entry_attributes |= FX_HIDDEN;
428 }
429
430 #ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
431
432 /* Invalidate the directory cache. */
433 media_ptr -> fx_media_last_found_name[0] = FX_NULL;
434 #endif
435
436 /* Now write out the directory entry. */
437 status = _fx_directory_entry_write(media_ptr, &new_dir_entry);
438
439 /* Determine if the write was successful. */
440 if (status != FX_SUCCESS)
441 {
442
443 #ifdef FX_ENABLE_FAULT_TOLERANT
444 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
445 #endif /* FX_ENABLE_FAULT_TOLERANT */
446
447 /* Release media protection. */
448 FX_UNPROTECT
449
450 /* Return the error code. */
451 return(status);
452 }
453
454 /* Set the old directory entry to free. */
455 old_dir_entry.fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
456 old_dir_entry.fx_dir_entry_short_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
457
458 /* Now wipe out the old directory entry. */
459 status = _fx_directory_entry_write(media_ptr, &old_dir_entry);
460
461 #ifdef FX_ENABLE_FAULT_TOLERANT
462 /* Check for a bad status. */
463 if (status != FX_SUCCESS)
464 {
465
466 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
467
468 /* Release media protection. */
469 FX_UNPROTECT
470
471 /* Return the bad status. */
472 return(status);
473 }
474
475 /* End transaction. */
476 status = _fx_fault_tolerant_transaction_end(media_ptr);
477 #endif /* FX_ENABLE_FAULT_TOLERANT */
478
479 /* Release media protection. */
480 FX_UNPROTECT
481
482 /* Directory rename is complete, return status. */
483 return(status);
484 }
485
486