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
RevLine 
[6ebaff9]1/*
2 * Copyright (c) 2008 Jakub Jermar
[c4bbca8]3 * Copyright (c) 2011 Oleg Romanenko
[6ebaff9]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
[b1834a01]30/** @addtogroup fat
[6ebaff9]31 * @{
[1b20da0]32 */
[6ebaff9]33
34/**
35 * @file fat_dentry.c
36 * @brief Functions that work with FAT directory entries.
37 */
38
[033ef7d3]39#include "fat_dentry.h"
[0fdd6bb]40#include <ctype.h>
[19f857a]41#include <str.h>
[34fdb75]42#include <errno.h>
[e65e406]43#include <byteorder.h>
[4372b49]44#include <assert.h>
[582a0b8]45#include <stddef.h>
[8d2dd7f2]46#include <stdint.h>
[033ef7d3]47
[14c331a]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;
[92fd52d7]63 size_t size;
64
[0e7c3d9]65 if (!(rc = str_casecmp(name, component)))
[14c331a]66 return rc;
[7afb4a5]67 if (!str_chr(name, '.')) {
[14c331a]68 /*
69 * There is no '.' in the name, so we know that there is enough
70 * space for appending an extra '.' to name.
71 */
[92fd52d7]72 size = str_size(name);
73 name[size] = '.';
74 name[size + 1] = '\0';
[0e7c3d9]75 rc = str_casecmp(name, component);
[14c331a]76 }
77 return rc;
78}
79
[0fdd6bb]80void fat_dentry_name_get(const fat_dentry_t *d, char *buf)
[033ef7d3]81{
[a248234]82 unsigned int i;
[a35b458]83
[033ef7d3]84 for (i = 0; i < FAT_NAME_LEN; i++) {
85 if (d->name[i] == FAT_PAD)
86 break;
[a35b458]87
[033ef7d3]88 if (d->name[i] == FAT_DENTRY_E5_ESC)
89 *buf++ = 0xe5;
[a248234]90 else {
91 if (d->lcase & FAT_LCASE_LOWER_NAME)
92 *buf++ = tolower(d->name[i]);
93 else
94 *buf++ = d->name[i];
95 }
[033ef7d3]96 }
[a35b458]97
[033ef7d3]98 if (d->ext[0] != FAT_PAD)
99 *buf++ = '.';
[a35b458]100
[033ef7d3]101 for (i = 0; i < FAT_EXT_LEN; i++) {
102 if (d->ext[i] == FAT_PAD) {
103 *buf = '\0';
104 return;
105 }
[a35b458]106
[033ef7d3]107 if (d->ext[i] == FAT_DENTRY_E5_ESC)
108 *buf++ = 0xe5;
[a248234]109 else {
110 if (d->lcase & FAT_LCASE_LOWER_EXT)
111 *buf++ = tolower(d->ext[i]);
112 else
113 *buf++ = d->ext[i];
114 }
[033ef7d3]115 }
[a35b458]116
[033ef7d3]117 *buf = '\0';
118}
119
[0fdd6bb]120void fat_dentry_name_set(fat_dentry_t *d, const char *name)
121{
[a248234]122 unsigned int i;
[0fdd6bb]123 const char fake_ext[] = " ";
[a248234]124 bool lower_name = true;
125 bool lower_ext = true;
[a35b458]126
[0fdd6bb]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:
[a248234]138 if (isalpha(*name)) {
139 if (!islower(*name))
140 lower_name = false;
141 }
[a35b458]142
[0fdd6bb]143 d->name[i] = toupper(*name++);
144 break;
145 }
146 }
[a35b458]147
[0fdd6bb]148 if (*name++ != '.')
149 name = fake_ext;
[a35b458]150
[0fdd6bb]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:
[a248234]161 if (isalpha(*name)) {
162 if (!islower(*name))
163 lower_ext = false;
164 }
[a35b458]165
[0fdd6bb]166 d->ext[i] = toupper(*name++);
167 break;
168 }
169 }
[a35b458]170
[a248234]171 if (lower_name)
172 d->lcase |= FAT_LCASE_LOWER_NAME;
173 else
174 d->lcase &= ~FAT_LCASE_LOWER_NAME;
[a35b458]175
[a248234]176 if (lower_ext)
177 d->lcase |= FAT_LCASE_LOWER_EXT;
178 else
179 d->lcase &= ~FAT_LCASE_LOWER_EXT;
[0fdd6bb]180}
181
[39b0a51]182void fat_dentry_vollabel_get(const fat_dentry_t *d, char *buf)
183{
184 unsigned int i;
[a35b458]185
[39b0a51]186 for (i = 0; i < FAT_NAME_LEN; i++) {
187 if (d->name[i] == FAT_PAD)
188 break;
[a35b458]189
[39b0a51]190 if (d->name[i] == FAT_DENTRY_E5_ESC)
191 *buf++ = 0xe5;
192 else
193 *buf++ = d->name[i];
194 }
[a35b458]195
[39b0a51]196 for (i = 0; i < FAT_EXT_LEN; i++) {
197 if (d->ext[i] == FAT_PAD) {
198 *buf = '\0';
199 return;
200 }
[a35b458]201
[39b0a51]202 if (d->ext[i] == FAT_DENTRY_E5_ESC)
203 *buf++ = 0xe5;
204 else
205 *buf++ = d->ext[i];
206 }
[a35b458]207
[39b0a51]208 *buf = '\0';
209}
210
[0fdd6bb]211fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *d)
[033ef7d3]212{
[65ccd23]213 if (d->attr == FAT_ATTR_LFN) {
[34fdb75]214 /* long name entry */
[c6aca755]215 if (FAT_LFN_ORDER(d) & FAT_LFN_ERASED)
[34fdb75]216 return FAT_DENTRY_FREE;
217 else
218 return FAT_DENTRY_LFN;
[65ccd23]219 }
[033ef7d3]220 if (d->attr & FAT_ATTR_VOLLABEL) {
221 /* volume label entry */
[39b0a51]222 return FAT_DENTRY_VOLLABEL;
[033ef7d3]223 }
224 if (d->name[0] == FAT_DENTRY_ERASED) {
225 /* not-currently-used entry */
[0fdd6bb]226 return FAT_DENTRY_FREE;
[033ef7d3]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}
[6ebaff9]241
[ed19497]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{
[5d95f02]254 uint8_t i, sum = 0;
255
256 for (i = 0; i < (FAT_NAME_LEN + FAT_EXT_LEN); i++)
[ed19497]257 sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + name[i];
[5d95f02]258
[ed19497]259 return sum;
260}
261
[34fdb75]262/** Get number of bytes in a string with size limit.
263 *
[a21d837]264 * @param str NULL-terminated (or not) string. The pointer comes from a packed
[1b20da0]265 * structure and as such is expected to be unaligned.
[34fdb75]266 * @param size Maximum number of bytes to consider.
267 *
268 * @return Number of bytes in string (without 0 and ff).
269 *
270 */
[a21d837]271size_t fat_lfn_str_nlength(const unaligned_uint16_t *str, size_t size)
[34fdb75]272{
273 size_t offset = 0;
274
275 while (offset < size) {
[1b20da0]276 if (str[offset] == 0 || str[offset] == FAT_LFN_PAD)
[34fdb75]277 break;
[4372b49]278 offset++;
[34fdb75]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;
[a35b458]293
[34fdb75]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);
[1b20da0]296 size += fat_lfn_str_nlength(FAT_LFN_PART3(d), FAT_LFN_PART3_SIZE);
[a35b458]297
[34fdb75]298 return size;
299}
300
[7234617]301size_t fat_lfn_get_entry(const fat_dentry_t *d, uint16_t *dst, size_t *offset)
[34fdb75]302{
[7234617]303 int i;
[5d95f02]304 for (i = FAT_LFN_PART3_SIZE - 1; i >= 0 && *offset > 0; i--) {
[7234617]305 if (d->lfn.part3[i] == 0 || d->lfn.part3[i] == FAT_LFN_PAD)
[34fdb75]306 continue;
[4372b49]307 (*offset)--;
[7234617]308 dst[(*offset)] = uint16_t_le2host(d->lfn.part3[i]);
309 }
[5d95f02]310 for (i = FAT_LFN_PART2_SIZE - 1; i >= 0 && *offset > 0; i--) {
[7234617]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 }
[5d95f02]316 for (i = FAT_LFN_PART1_SIZE - 1; i >= 0 && *offset > 0; i--) {
[7234617]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]);
[34fdb75]321 }
[4372b49]322 return *offset;
[34fdb75]323}
324
[5d95f02]325size_t fat_lfn_set_entry(const uint16_t *src, size_t *offset, size_t size,
326 fat_dentry_t *d)
[34fdb75]327{
[7194a60]328 size_t idx;
[5d95f02]329 for (idx = 0; idx < FAT_LFN_PART1_SIZE; idx++) {
[7234617]330 if (*offset < size) {
331 d->lfn.part1[idx] = host2uint16_t_le(src[*offset]);
[7194a60]332 (*offset)++;
[5d95f02]333 } else
[7234617]334 d->lfn.part1[idx] = FAT_LFN_PAD;
335 }
[5d95f02]336 for (idx = 0; idx < FAT_LFN_PART2_SIZE; idx++) {
[7234617]337 if (*offset < size) {
338 d->lfn.part2[idx] = host2uint16_t_le(src[*offset]);
339 (*offset)++;
[5d95f02]340 } else
[7234617]341 d->lfn.part2[idx] = FAT_LFN_PAD;
342 }
[5d95f02]343 for (idx = 0; idx < FAT_LFN_PART3_SIZE; idx++) {
[7234617]344 if (*offset < size) {
345 d->lfn.part3[idx] = host2uint16_t_le(src[*offset]);
346 (*offset)++;
[5d95f02]347 } else
[7234617]348 d->lfn.part3[idx] = FAT_LFN_PAD;
[34fdb75]349 }
350
[7194a60]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;
[a35b458]356
[7194a60]357 return *offset;
[9553d7d]358}
359
[411e9ca]360void str_to_ascii(char *dst, const char *src, size_t count, uint8_t pad)
[7194a60]361{
[28a5ebd]362 char32_t ch;
[411e9ca]363 size_t off = 0;
[7194a60]364 size_t i = 0;
[a35b458]365
[7194a60]366 while (i < count) {
[411e9ca]367 if ((ch = str_decode(src, &off, STR_NO_LIMIT)) != 0) {
[a1d7b4b]368 if (ascii_check(ch) && IS_D_CHAR(ch))
[411e9ca]369 *dst = toupper(ch);
[7194a60]370 else
371 *dst = pad;
[5d95f02]372 } else
[7194a60]373 break;
374
375 dst++;
376 i++;
377 }
378 *dst = '\0';
[2d0d637]379}
380
[411e9ca]381bool fat_valid_name(const char *name)
[2d0d637]382{
[28a5ebd]383 char32_t ch;
[1433ecda]384 size_t offset = 0;
[411e9ca]385 bool result = true;
[a35b458]386
[411e9ca]387 while ((ch = str_decode(name, &offset, STR_NO_LIMIT)) != 0) {
[980311e]388 if (str_chr(FAT_STOP_CHARS, ch) != NULL) {
[411e9ca]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
[2d0d637]426 return true;
427}
428
[6ebaff9]429/**
430 * @}
[1b20da0]431 */
Note: See TracBrowser for help on using the repository browser.