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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a46e56b was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • 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 fs
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 wchar_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 wchar_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.