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 /**   Media                                                               */
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_media.h"
31 #include "fx_utility.h"
32 
33 
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _fx_media_volume_set                                PORTABLE C      */
39 /*                                                           6.1          */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    William E. Lamie, Microsoft Corporation                             */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function sets the volume name to the name supplied by the      */
47 /*    caller.                                                             */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    media_ptr                             Media control block pointer   */
52 /*    volume_name                           New volume name               */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    return status                                                       */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    _fx_directory_entry_read              Read a directory entry        */
61 /*    _fx_utility_logical_sector_read       Read directory sector         */
62 /*    _fx_utility_logical_sector_write      Write directory sector        */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    Application Code                                                    */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
73 /*  09-30-2020     William E. Lamie         Modified comment(s),          */
74 /*                                            resulting in version 6.1    */
75 /*                                                                        */
76 /**************************************************************************/
_fx_media_volume_set(FX_MEDIA * media_ptr,CHAR * volume_name)77 UINT  _fx_media_volume_set(FX_MEDIA *media_ptr, CHAR *volume_name)
78 {
79 
80 ULONG        i, j;
81 FX_DIR_ENTRY dir_entry, dir_entry1;
82 UINT         status, offset;
83 UCHAR       *work_ptr;
84 CHAR         alpha;
85 
86 
87     /* Check the media to make sure it is open.  */
88     if (media_ptr -> fx_media_id != FX_MEDIA_ID)
89     {
90 
91         /* Return the media not opened error.  */
92         return(FX_MEDIA_NOT_OPEN);
93     }
94 
95     dir_entry.fx_dir_entry_log_sector = 0;
96     dir_entry.fx_dir_entry_byte_offset = 0;
97 
98     /* If trace is enabled, insert this event into the trace buffer.  */
99     FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_VOLUME_SET, media_ptr, volume_name, 0, 0, FX_TRACE_MEDIA_EVENTS, 0, 0)
100 
101     /* Protect against other threads accessing the media.  */
102     FX_PROTECT
103 
104 
105    /* First, check for an invalid volume name.  */
106         if (volume_name[0] == 0)
107         {
108 
109         /* Yes, volume name is invalid.  Return an error.  */
110         return(FX_INVALID_NAME);
111     }
112 
113     /* Read the logical directory sector 0 - we just do this to get a memory_buffer pointer */
114     status =  _fx_utility_logical_sector_read(media_ptr, ((ULONG64) 0),
115                                               media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
116 
117     /* Check the read status.  */
118     if (status != FX_SUCCESS)
119     {
120 
121         /* Release media protection.  */
122         FX_UNPROTECT
123 
124         /* Return the error status.  */
125         return(status);
126     }
127 
128 #ifndef FX_MEDIA_STATISTICS_DISABLE
129 
130     /* Increment the number of driver read boot sector requests.  */
131     media_ptr -> fx_media_driver_boot_read_requests++;
132 #endif
133 
134     /* Build a driver request to read the boot record.  */
135     media_ptr -> fx_media_driver_request =      FX_DRIVER_BOOT_READ;
136     media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
137     media_ptr -> fx_media_driver_buffer =       media_ptr -> fx_media_memory_buffer;
138     media_ptr -> fx_media_driver_sectors =      1;
139     media_ptr -> fx_media_driver_sector_type =  FX_BOOT_SECTOR;
140 
141     /* If trace is enabled, insert this event into the trace buffer.  */
142     FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_BOOT_READ, media_ptr, media_ptr -> fx_media_memory_buffer, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
143 
144     /* Invoke the driver to read the boot sector.  */
145         (media_ptr -> fx_media_driver_entry) (media_ptr);
146 
147     /* Determine if the request is successful.  */
148     if (media_ptr -> fx_media_driver_status)
149     {
150 
151         /* Release media protection.  */
152         FX_UNPROTECT
153 
154         /* An error occurred in the driver.  */
155         return(media_ptr -> fx_media_driver_status);
156     }
157 
158     /* Calculate the offset based on the FAT present.  */
159     if (media_ptr -> fx_media_32_bit_FAT)
160     {
161 
162         /* FAT32 is present.  */
163         offset =  FX_VOLUME_LABEL_32;
164     }
165     else
166     {
167 
168         /* FAT12/16 is present.  */
169         offset =  FX_VOLUME_LABEL;
170     }
171 
172     /* Loop to store the volume name.  */
173     for (i = 0; volume_name[i]; i++)
174     {
175 
176         /* Have we reached the end?  */
177         if (i == 11)
178         {
179 
180             break;
181         }
182 
183         /* Pickup volume name byte.  */
184         alpha =  volume_name[i];
185 
186         /* Determine if alpha needs to be converted to upper case.  */
187         if ((alpha >= 'a') && (alpha <= 'z'))
188         {
189 
190             /* Convert alpha to upper case.  */
191             alpha =  (CHAR)((INT)alpha - 0x20);
192         }
193 
194         /* Store a byte of the volume name.  */
195         media_ptr -> fx_media_memory_buffer[offset + i] =  (UCHAR)alpha;
196     }
197 
198     /* Now pad with spaces.  */
199     for (; i < 11; i++)
200     {
201 
202         /* Append space character to volume name.  */
203         media_ptr -> fx_media_memory_buffer[offset + i] =  0x20;
204     }
205 
206 #ifndef FX_MEDIA_STATISTICS_DISABLE
207 
208     /* Increment the number of driver write boot sector requests.  */
209     media_ptr -> fx_media_driver_boot_write_requests++;
210 #endif
211 
212     /* Write the boot sector with the new volume name.  */
213     media_ptr -> fx_media_driver_request =      FX_DRIVER_BOOT_WRITE;
214     media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
215     media_ptr -> fx_media_driver_buffer =       media_ptr -> fx_media_memory_buffer;
216     media_ptr -> fx_media_driver_sectors =      1;
217     media_ptr -> fx_media_driver_sector_type =  FX_BOOT_SECTOR;
218 
219     /* Set the system write flag since we are writing the boot sector.  */
220     media_ptr -> fx_media_driver_system_write =  FX_TRUE;
221 
222     /* If trace is enabled, insert this event into the trace buffer.  */
223     FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_BOOT_WRITE, media_ptr, media_ptr -> fx_media_memory_buffer, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
224 
225     /* Invoke the driver to write the boot sector.  */
226         (media_ptr -> fx_media_driver_entry) (media_ptr);
227 
228     /* Clear the system write flag.  */
229     media_ptr -> fx_media_driver_system_write =  FX_FALSE;
230 
231     /* Determine if the request is successful.  */
232     if (media_ptr -> fx_media_driver_status)
233     {
234 
235         /* Release media protection.  */
236         FX_UNPROTECT
237 
238         /* An error occurred in the driver.  */
239         return(media_ptr -> fx_media_driver_status);
240     }
241 
242     /* Setup pointer to media name buffer.  */
243     dir_entry1.fx_dir_entry_name =  media_ptr -> fx_media_name_buffer;
244 
245     /* Clear the short name string.  */
246     dir_entry1.fx_dir_entry_short_name[0] =  0;
247 
248     /* Now we need to find the copy of the volume name in the root directory.  */
249     i =  0;
250     j =  media_ptr -> fx_media_root_directory_entries + 1;
251     do
252     {
253 
254         /* Read an entry from the root directory.  */
255         status =  _fx_directory_entry_read(media_ptr, FX_NULL, &i, &dir_entry1);
256 
257         /* Check for error status.  */
258         if (status != FX_SUCCESS)
259         {
260 
261             /* Release media protection.  */
262             FX_UNPROTECT
263 
264             /* Return to caller.  */
265             return(status);
266         }
267 
268         /* Determine if this is an empty entry.  */
269         if ((dir_entry1.fx_dir_entry_name[0] == (CHAR)FX_DIR_ENTRY_FREE) && (dir_entry1.fx_dir_entry_short_name[0] == 0))
270         {
271 
272             /* Yes, this is free entry.  Is it the first?  */
273             if (i < j)
274             {
275 
276                 /* Yes, first free entry - remember it.  */
277                 dir_entry =  dir_entry1;
278                 j =  i;
279             }
280         }
281         /* Determine if the directory entries are exhausted.  */
282         else if (dir_entry1.fx_dir_entry_name[0] == FX_DIR_ENTRY_DONE)
283         {
284 
285             /* Yes, this we are at the end of the directory.  Have there
286             been any other free entries?  */
287             if (i < j)
288             {
289 
290                 /* No, we need to remember this as the free entry.  */
291                 dir_entry =  dir_entry1;
292                 j =  i;
293             }
294             break;
295         }
296         /* Check for a volume name.  */
297         else if (dir_entry1.fx_dir_entry_attributes & FX_VOLUME)
298         {
299 
300             /* Yes, we have found a previously set volume name - use this entry.  */
301             dir_entry =  dir_entry1;
302             j =  i;
303             break;
304         }
305 
306         /* Move to next directory entry.  */
307         i++;
308     } while (i < media_ptr -> fx_media_root_directory_entries);
309 
310     /* Determine if a volume entry was not found and there are no more empty slots.  */
311     if (i == media_ptr -> fx_media_root_directory_entries)
312     {
313 
314         /* Determine if there was a free or previous volume name.  */
315         if (j == (media_ptr -> fx_media_root_directory_entries + 1))
316         {
317 
318             /* No, nothing was available in the root directory.  */
319 
320             /* Release media protection.  */
321             FX_UNPROTECT
322 
323             /* No, existing volume name or space in the root directly was found, return an error.  */
324             return(FX_MEDIA_INVALID);
325         }
326     }
327 
328     /* Now set the volume name and attribute.  */
329 
330     /* Read the logical directory sector.  */
331     status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) dir_entry.fx_dir_entry_log_sector,
332                                               media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_BOOT_SECTOR);
333 
334     /* Check the status of reading the directory entry. */
335     if (status != FX_SUCCESS)
336     {
337 
338         /* Release media protection.  */
339         FX_UNPROTECT
340 
341         /* Return the error status.  */
342         return(status);
343     }
344 
345     /* Calculate pointer into directory buffer.  */
346     work_ptr =  media_ptr -> fx_media_memory_buffer +
347         (UINT)dir_entry.fx_dir_entry_byte_offset;
348 
349     /* Copy the volume name into the directory entry.  */
350     for (i = 0; volume_name[i]; i++)
351     {
352 
353         /* Have we reached the end?  */
354         if (i == 11)
355         {
356 
357             break;
358         }
359 
360         /* Pickup volume name byte.  */
361         alpha =  volume_name[i];
362 
363         /* Determine if alpha needs to be converted to upper case.  */
364         if ((alpha >= 'a') && (alpha <= 'z'))
365         {
366 
367             /* Convert alpha to upper case.  */
368             alpha =  (CHAR)((INT)alpha - 0x20);
369         }
370 
371         /* Store volume name.  */
372         work_ptr[i] =  (UCHAR)alpha;
373     }
374 
375     /* Pad with space characters.  */
376     for (; i < 11; i++)
377     {
378         work_ptr[i] =  0x20;
379     }
380 
381     /* Set the appropriate attributes.  */
382     work_ptr[11] =  FX_VOLUME | FX_ARCHIVE;
383 
384     /* Set the other parts of the volume entry.  */
385 
386     /* Clear the hi word of cluster.  */
387     work_ptr[20] =  0;
388     work_ptr[21] =  0;
389 
390     /* Clear the low word of cluster.  */
391     work_ptr[26] =  0;
392     work_ptr[27] =  0;
393 
394     /* Clear the file size.  */
395     work_ptr[28] =  0;
396     work_ptr[29] =  0;
397     work_ptr[30] =  0;
398     work_ptr[31] =  0;
399 
400     /* Write the directory sector to the media.  */
401     status =  _fx_utility_logical_sector_write(media_ptr, (ULONG64) dir_entry.fx_dir_entry_log_sector,
402                                                media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
403 
404     /* Release media protection.  */
405     FX_UNPROTECT
406 
407     /* Return the status.  */
408     return(status);
409 }
410 
411