source: mainline/uspace/srv/fs/fat/fat_dentry.c

Last change on this file was 28a5ebd, checked in by Martin Decky <martin@…>, 5 years ago

Use char32_t instead of wchat_t to represent UTF-32 strings

The intention of the native HelenOS string API has been always to
support Unicode in the UTF-8 and UTF-32 encodings as the sole character
representations and ignore the obsolete mess of older single-byte and
multibyte character encodings. Before C11, the wchar_t type has been
slightly misused for the purpose of the UTF-32 strings. The newer
char32_t type is obviously a much more suitable option. The standard
defines char32_t as uint_least32_t, thus we can take the liberty to fix
it to uint32_t.

To maintain compatilibity with the C Standard, the putwchar(wchar_t)
functions has been replaced by our custom putuchar(char32_t) functions
where appropriate.

  • Property mode set to 100644
File size: 9.5 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * Copyright (c) 2011 Oleg Romanenko
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup fat
31 * @{
32 */
33
34/**
35 * @file fat_dentry.c
36 * @brief Functions that work with FAT directory entries.
37 */
38
39#include "fat_dentry.h"
40#include <ctype.h>
41#include <str.h>
42#include <errno.h>
43#include <byteorder.h>
44#include <assert.h>
45#include <stddef.h>
46#include <stdint.h>
47
48/** Compare path component with the name read from the dentry.
49 *
50 * This function compares the path component with the name read from the dentry.
51 * The comparison is case insensitive and tolerates a mismatch on the trailing
52 * dot character at the end of the name (i.e. when there is a dot, but no
53 * extension).
54 *
55 * @param name Node name read from the dentry.
56 * @param component Path component.
57 *
58 * @return Zero on match, non-zero otherwise.
59 */
60int fat_dentry_namecmp(char *name, const char *component)
61{
62 int rc;
63 size_t size;
64
65 if (!(rc = str_casecmp(name, component)))
66 return rc;
67 if (!str_chr(name, '.')) {
68 /*
69 * There is no '.' in the name, so we know that there is enough
70 * space for appending an extra '.' to name.
71 */
72 size = str_size(name);
73 name[size] = '.';
74 name[size + 1] = '\0';
75 rc = str_casecmp(name, component);
76 }
77 return rc;
78}
79
80void fat_dentry_name_get(const fat_dentry_t *d, char *buf)
81{
82 unsigned int i;
83
84 for (i = 0; i < FAT_NAME_LEN; i++) {
85 if (d->name[i] == FAT_PAD)
86 break;
87
88 if (d->name[i] == FAT_DENTRY_E5_ESC)
89 *buf++ = 0xe5;
90 else {
91 if (d->lcase & FAT_LCASE_LOWER_NAME)
92 *buf++ = tolower(d->name[i]);
93 else
94 *buf++ = d->name[i];
95 }
96 }
97
98 if (d->ext[0] != FAT_PAD)
99 *buf++ = '.';
100
101 for (i = 0; i < FAT_EXT_LEN; i++) {
102 if (d->ext[i] == FAT_PAD) {
103 *buf = '\0';
104 return;
105 }
106
107 if (d->ext[i] == FAT_DENTRY_E5_ESC)
108 *buf++ = 0xe5;
109 else {
110 if (d->lcase & FAT_LCASE_LOWER_EXT)
111 *buf++ = tolower(d->ext[i]);
112 else
113 *buf++ = d->ext[i];
114 }
115 }
116
117 *buf = '\0';
118}
119
120void fat_dentry_name_set(fat_dentry_t *d, const char *name)
121{
122 unsigned int i;
123 const char fake_ext[] = " ";
124 bool lower_name = true;
125 bool lower_ext = true;
126
127 for (i = 0; i < FAT_NAME_LEN; i++) {
128 switch ((uint8_t) *name) {
129 case 0xe5:
130 d->name[i] = FAT_DENTRY_E5_ESC;
131 name++;
132 break;
133 case '\0':
134 case '.':
135 d->name[i] = FAT_PAD;
136 break;
137 default:
138 if (isalpha(*name)) {
139 if (!islower(*name))
140 lower_name = false;
141 }
142
143 d->name[i] = toupper(*name++);
144 break;
145 }
146 }
147
148 if (*name++ != '.')
149 name = fake_ext;
150
151 for (i = 0; i < FAT_EXT_LEN; i++) {
152 switch ((uint8_t) *name) {
153 case 0xe5:
154 d->ext[i] = FAT_DENTRY_E5_ESC;
155 name++;
156 break;
157 case '\0':
158 d->ext[i] = FAT_PAD;
159 break;
160 default:
161 if (isalpha(*name)) {
162 if (!islower(*name))
163 lower_ext = false;
164 }
165
166 d->ext[i] = toupper(*name++);
167 break;
168 }
169 }
170
171 if (lower_name)
172 d->lcase |= FAT_LCASE_LOWER_NAME;
173 else
174 d->lcase &= ~FAT_LCASE_LOWER_NAME;
175
176 if (lower_ext)
177 d->lcase |= FAT_LCASE_LOWER_EXT;
178 else
179 d->lcase &= ~FAT_LCASE_LOWER_EXT;
180}
181
182void fat_dentry_vollabel_get(const fat_dentry_t *d, char *buf)
183{
184 unsigned int i;
185
186 for (i = 0; i < FAT_NAME_LEN; i++) {
187 if (d->name[i] == FAT_PAD)
188 break;
189
190 if (d->name[i] == FAT_DENTRY_E5_ESC)
191 *buf++ = 0xe5;
192 else
193 *buf++ = d->name[i];
194 }
195
196 for (i = 0; i < FAT_EXT_LEN; i++) {
197 if (d->ext[i] == FAT_PAD) {
198 *buf = '\0';
199 return;
200 }
201
202 if (d->ext[i] == FAT_DENTRY_E5_ESC)
203 *buf++ = 0xe5;
204 else
205 *buf++ = d->ext[i];
206 }
207
208 *buf = '\0';
209}
210
211fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *d)
212{
213 if (d->attr == FAT_ATTR_LFN) {
214 /* long name entry */
215 if (FAT_LFN_ORDER(d) & FAT_LFN_ERASED)
216 return FAT_DENTRY_FREE;
217 else
218 return FAT_DENTRY_LFN;
219 }
220 if (d->attr & FAT_ATTR_VOLLABEL) {
221 /* volume label entry */
222 return FAT_DENTRY_VOLLABEL;
223 }
224 if (d->name[0] == FAT_DENTRY_ERASED) {
225 /* not-currently-used entry */
226 return FAT_DENTRY_FREE;
227 }
228 if (d->name[0] == FAT_DENTRY_UNUSED) {
229 /* never used entry */
230 return FAT_DENTRY_LAST;
231 }
232 if (d->name[0] == FAT_DENTRY_DOT) {
233 /*
234 * Most likely '.' or '..'.
235 * It cannot occur in a regular file name.
236 */
237 return FAT_DENTRY_SKIP;
238 }
239 return FAT_DENTRY_VALID;
240}
241
242/** Compute checksum of Node name.
243 *
244 * Returns an unsigned byte checksum computed on an unsigned byte
245 * array. The array must be 11 bytes long and is assumed to contain
246 * a name stored in the format of a MS-DOS directory entry.
247 *
248 * @param name Node name read from the dentry.
249 *
250 * @return An 8-bit unsigned checksum of the name.
251 */
252uint8_t fat_dentry_chksum(uint8_t *name)
253{
254 uint8_t i, sum = 0;
255
256 for (i = 0; i < (FAT_NAME_LEN + FAT_EXT_LEN); i++)
257 sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + name[i];
258
259 return sum;
260}
261
262/** Get number of bytes in a string with size limit.
263 *
264 * @param str NULL-terminated (or not) string. The pointer comes from a packed
265 * structure and as such is expected to be unaligned.
266 * @param size Maximum number of bytes to consider.
267 *
268 * @return Number of bytes in string (without 0 and ff).
269 *
270 */
271size_t fat_lfn_str_nlength(const unaligned_uint16_t *str, size_t size)
272{
273 size_t offset = 0;
274
275 while (offset < size) {
276 if (str[offset] == 0 || str[offset] == FAT_LFN_PAD)
277 break;
278 offset++;
279 }
280 return offset;
281}
282
283/** Get number of bytes in a FAT long entry occuped by characters.
284 *
285 * @param d FAT long entry.
286 *
287 * @return Number of bytes.
288 *
289 */
290size_t fat_lfn_size(const fat_dentry_t *d)
291{
292 size_t size = 0;
293
294 size += fat_lfn_str_nlength(FAT_LFN_PART1(d), FAT_LFN_PART1_SIZE);
295 size += fat_lfn_str_nlength(FAT_LFN_PART2(d), FAT_LFN_PART2_SIZE);
296 size += fat_lfn_str_nlength(FAT_LFN_PART3(d), FAT_LFN_PART3_SIZE);
297
298 return size;
299}
300
301size_t fat_lfn_get_entry(const fat_dentry_t *d, uint16_t *dst, size_t *offset)
302{
303 int i;
304 for (i = FAT_LFN_PART3_SIZE - 1; i >= 0 && *offset > 0; i--) {
305 if (d->lfn.part3[i] == 0 || d->lfn.part3[i] == FAT_LFN_PAD)
306 continue;
307 (*offset)--;
308 dst[(*offset)] = uint16_t_le2host(d->lfn.part3[i]);
309 }
310 for (i = FAT_LFN_PART2_SIZE - 1; i >= 0 && *offset > 0; i--) {
311 if (d->lfn.part2[i] == 0 || d->lfn.part2[i] == FAT_LFN_PAD)
312 continue;
313 (*offset)--;
314 dst[(*offset)] = uint16_t_le2host(d->lfn.part2[i]);
315 }
316 for (i = FAT_LFN_PART1_SIZE - 1; i >= 0 && *offset > 0; i--) {
317 if (d->lfn.part1[i] == 0 || d->lfn.part1[i] == FAT_LFN_PAD)
318 continue;
319 (*offset)--;
320 dst[(*offset)] = uint16_t_le2host(d->lfn.part1[i]);
321 }
322 return *offset;
323}
324
325size_t fat_lfn_set_entry(const uint16_t *src, size_t *offset, size_t size,
326 fat_dentry_t *d)
327{
328 size_t idx;
329 for (idx = 0; idx < FAT_LFN_PART1_SIZE; idx++) {
330 if (*offset < size) {
331 d->lfn.part1[idx] = host2uint16_t_le(src[*offset]);
332 (*offset)++;
333 } else
334 d->lfn.part1[idx] = FAT_LFN_PAD;
335 }
336 for (idx = 0; idx < FAT_LFN_PART2_SIZE; idx++) {
337 if (*offset < size) {
338 d->lfn.part2[idx] = host2uint16_t_le(src[*offset]);
339 (*offset)++;
340 } else
341 d->lfn.part2[idx] = FAT_LFN_PAD;
342 }
343 for (idx = 0; idx < FAT_LFN_PART3_SIZE; idx++) {
344 if (*offset < size) {
345 d->lfn.part3[idx] = host2uint16_t_le(src[*offset]);
346 (*offset)++;
347 } else
348 d->lfn.part3[idx] = FAT_LFN_PAD;
349 }
350
351 if (src[*offset] == 0)
352 offset++;
353 FAT_LFN_ATTR(d) = FAT_ATTR_LFN;
354 d->lfn.type = 0;
355 d->lfn.firstc_lo = 0;
356
357 return *offset;
358}
359
360void str_to_ascii(char *dst, const char *src, size_t count, uint8_t pad)
361{
362 char32_t ch;
363 size_t off = 0;
364 size_t i = 0;
365
366 while (i < count) {
367 if ((ch = str_decode(src, &off, STR_NO_LIMIT)) != 0) {
368 if (ascii_check(ch) && IS_D_CHAR(ch))
369 *dst = toupper(ch);
370 else
371 *dst = pad;
372 } else
373 break;
374
375 dst++;
376 i++;
377 }
378 *dst = '\0';
379}
380
381bool fat_valid_name(const char *name)
382{
383 char32_t ch;
384 size_t offset = 0;
385 bool result = true;
386
387 while ((ch = str_decode(name, &offset, STR_NO_LIMIT)) != 0) {
388 if (str_chr(FAT_STOP_CHARS, ch) != NULL) {
389 result = false;
390 break;
391 }
392 }
393 return result;
394}
395
396bool fat_valid_short_name(const char *name)
397{
398 unsigned int i;
399 unsigned int dot = 0;
400 bool dot_found = false;
401
402 for (i = 0; name[i]; i++) {
403 if (name[i] == '.') {
404 if (dot_found) {
405 return false;
406 } else {
407 dot_found = true;
408 dot = i;
409 }
410 } else {
411 if (!IS_D_CHAR(name[i]))
412 return false;
413 }
414 }
415
416 if (dot_found) {
417 if (dot > FAT_NAME_LEN)
418 return false;
419 if (i - dot > FAT_EXT_LEN + 1)
420 return false;
421 } else {
422 if (i > FAT_NAME_LEN)
423 return false;
424 }
425
426 return true;
427}
428
429/**
430 * @}
431 */
Note: See TracBrowser for help on using the repository browser.