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