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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d4d74dc was d4d74dc, checked in by Vojtech Horky <vojtechhorky@…>, 13 years ago

Less includes in library headers

There is no need for errno.h to include fibril.h.
Similarly, tinput.h does not need list.h or async.h.

Unfortunately, many programs depended on the fact that including
errno.h would (recursively) include unistd.h and NULL would be
defined. Most of the fixes remedy this problem.

  • Property mode set to 100644
File size: 9.0 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 <unistd.h>
46
47/** Compare path component with the name read from the dentry.
48 *
49 * This function compares the path component with the name read from the dentry.
50 * The comparison is case insensitive and tolerates a mismatch on the trailing
51 * dot character at the end of the name (i.e. when there is a dot, but no
52 * extension).
53 *
54 * @param name Node name read from the dentry.
55 * @param component Path component.
56 *
57 * @return Zero on match, non-zero otherwise.
58 */
59int fat_dentry_namecmp(char *name, const char *component)
60{
61 int rc;
62 size_t size;
63
64 if (!(rc = stricmp(name, component)))
65 return rc;
66 if (!str_chr(name, '.')) {
67 /*
68 * There is no '.' in the name, so we know that there is enough
69 * space for appending an extra '.' to name.
70 */
71 size = str_size(name);
72 name[size] = '.';
73 name[size + 1] = '\0';
74 rc = stricmp(name, component);
75 }
76 return rc;
77}
78
79void fat_dentry_name_get(const fat_dentry_t *d, char *buf)
80{
81 unsigned int i;
82
83 for (i = 0; i < FAT_NAME_LEN; i++) {
84 if (d->name[i] == FAT_PAD)
85 break;
86
87 if (d->name[i] == FAT_DENTRY_E5_ESC)
88 *buf++ = 0xe5;
89 else {
90 if (d->lcase & FAT_LCASE_LOWER_NAME)
91 *buf++ = tolower(d->name[i]);
92 else
93 *buf++ = d->name[i];
94 }
95 }
96
97 if (d->ext[0] != FAT_PAD)
98 *buf++ = '.';
99
100 for (i = 0; i < FAT_EXT_LEN; i++) {
101 if (d->ext[i] == FAT_PAD) {
102 *buf = '\0';
103 return;
104 }
105
106 if (d->ext[i] == FAT_DENTRY_E5_ESC)
107 *buf++ = 0xe5;
108 else {
109 if (d->lcase & FAT_LCASE_LOWER_EXT)
110 *buf++ = tolower(d->ext[i]);
111 else
112 *buf++ = d->ext[i];
113 }
114 }
115
116 *buf = '\0';
117}
118
119void fat_dentry_name_set(fat_dentry_t *d, const char *name)
120{
121 unsigned int i;
122 const char fake_ext[] = " ";
123 bool lower_name = true;
124 bool lower_ext = true;
125
126 for (i = 0; i < FAT_NAME_LEN; i++) {
127 switch ((uint8_t) *name) {
128 case 0xe5:
129 d->name[i] = FAT_DENTRY_E5_ESC;
130 name++;
131 break;
132 case '\0':
133 case '.':
134 d->name[i] = FAT_PAD;
135 break;
136 default:
137 if (isalpha(*name)) {
138 if (!islower(*name))
139 lower_name = false;
140 }
141
142 d->name[i] = toupper(*name++);
143 break;
144 }
145 }
146
147 if (*name++ != '.')
148 name = fake_ext;
149
150 for (i = 0; i < FAT_EXT_LEN; i++) {
151 switch ((uint8_t) *name) {
152 case 0xe5:
153 d->ext[i] = FAT_DENTRY_E5_ESC;
154 name++;
155 break;
156 case '\0':
157 d->ext[i] = FAT_PAD;
158 break;
159 default:
160 if (isalpha(*name)) {
161 if (!islower(*name))
162 lower_ext = false;
163 }
164
165 d->ext[i] = toupper(*name++);
166 break;
167 }
168 }
169
170 if (lower_name)
171 d->lcase |= FAT_LCASE_LOWER_NAME;
172 else
173 d->lcase &= ~FAT_LCASE_LOWER_NAME;
174
175 if (lower_ext)
176 d->lcase |= FAT_LCASE_LOWER_EXT;
177 else
178 d->lcase &= ~FAT_LCASE_LOWER_EXT;
179}
180
181fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *d)
182{
183 if (d->attr == FAT_ATTR_LFN) {
184 /* long name entry */
185 if (FAT_LFN_ORDER(d) & FAT_LFN_ERASED)
186 return FAT_DENTRY_FREE;
187 else
188 return FAT_DENTRY_LFN;
189 }
190 if (d->attr & FAT_ATTR_VOLLABEL) {
191 /* volume label entry */
192 return FAT_DENTRY_SKIP;
193 }
194 if (d->name[0] == FAT_DENTRY_ERASED) {
195 /* not-currently-used entry */
196 return FAT_DENTRY_FREE;
197 }
198 if (d->name[0] == FAT_DENTRY_UNUSED) {
199 /* never used entry */
200 return FAT_DENTRY_LAST;
201 }
202 if (d->name[0] == FAT_DENTRY_DOT) {
203 /*
204 * Most likely '.' or '..'.
205 * It cannot occur in a regular file name.
206 */
207 return FAT_DENTRY_SKIP;
208 }
209 return FAT_DENTRY_VALID;
210}
211
212/** Compute checksum of Node name.
213 *
214 * Returns an unsigned byte checksum computed on an unsigned byte
215 * array. The array must be 11 bytes long and is assumed to contain
216 * a name stored in the format of a MS-DOS directory entry.
217 *
218 * @param name Node name read from the dentry.
219 *
220 * @return An 8-bit unsigned checksum of the name.
221 */
222uint8_t fat_dentry_chksum(uint8_t *name)
223{
224 uint8_t i, sum = 0;
225
226 for (i = 0; i < (FAT_NAME_LEN + FAT_EXT_LEN); i++)
227 sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + name[i];
228
229 return sum;
230}
231
232/** Get number of bytes in a string with size limit.
233 *
234 * @param str NULL-terminated (or not) string.
235 * @param size Maximum number of bytes to consider.
236 *
237 * @return Number of bytes in string (without 0 and ff).
238 *
239 */
240size_t fat_lfn_str_nlength(const uint16_t *str, size_t size)
241{
242 size_t offset = 0;
243
244 while (offset < size) {
245 if (str[offset] == 0 || str[offset] == FAT_LFN_PAD)
246 break;
247 offset++;
248 }
249 return offset;
250}
251
252/** Get number of bytes in a FAT long entry occuped by characters.
253 *
254 * @param d FAT long entry.
255 *
256 * @return Number of bytes.
257 *
258 */
259size_t fat_lfn_size(const fat_dentry_t *d)
260{
261 size_t size = 0;
262
263 size += fat_lfn_str_nlength(FAT_LFN_PART1(d), FAT_LFN_PART1_SIZE);
264 size += fat_lfn_str_nlength(FAT_LFN_PART2(d), FAT_LFN_PART2_SIZE);
265 size += fat_lfn_str_nlength(FAT_LFN_PART3(d), FAT_LFN_PART3_SIZE);
266
267 return size;
268}
269
270size_t fat_lfn_get_entry(const fat_dentry_t *d, uint16_t *dst, size_t *offset)
271{
272 int i;
273 for (i = FAT_LFN_PART3_SIZE - 1; i >= 0 && *offset > 0; i--) {
274 if (d->lfn.part3[i] == 0 || d->lfn.part3[i] == FAT_LFN_PAD)
275 continue;
276 (*offset)--;
277 dst[(*offset)] = uint16_t_le2host(d->lfn.part3[i]);
278 }
279 for (i = FAT_LFN_PART2_SIZE - 1; i >= 0 && *offset > 0; i--) {
280 if (d->lfn.part2[i] == 0 || d->lfn.part2[i] == FAT_LFN_PAD)
281 continue;
282 (*offset)--;
283 dst[(*offset)] = uint16_t_le2host(d->lfn.part2[i]);
284 }
285 for (i = FAT_LFN_PART1_SIZE - 1; i >= 0 && *offset > 0; i--) {
286 if (d->lfn.part1[i] == 0 || d->lfn.part1[i] == FAT_LFN_PAD)
287 continue;
288 (*offset)--;
289 dst[(*offset)] = uint16_t_le2host(d->lfn.part1[i]);
290 }
291 return *offset;
292}
293
294size_t fat_lfn_set_entry(const uint16_t *src, size_t *offset, size_t size,
295 fat_dentry_t *d)
296{
297 size_t idx;
298 for (idx = 0; idx < FAT_LFN_PART1_SIZE; idx++) {
299 if (*offset < size) {
300 d->lfn.part1[idx] = host2uint16_t_le(src[*offset]);
301 (*offset)++;
302 } else
303 d->lfn.part1[idx] = FAT_LFN_PAD;
304 }
305 for (idx = 0; idx < FAT_LFN_PART2_SIZE; idx++) {
306 if (*offset < size) {
307 d->lfn.part2[idx] = host2uint16_t_le(src[*offset]);
308 (*offset)++;
309 } else
310 d->lfn.part2[idx] = FAT_LFN_PAD;
311 }
312 for (idx = 0; idx < FAT_LFN_PART3_SIZE; idx++) {
313 if (*offset < size) {
314 d->lfn.part3[idx] = host2uint16_t_le(src[*offset]);
315 (*offset)++;
316 } else
317 d->lfn.part3[idx] = FAT_LFN_PAD;
318 }
319
320 if (src[*offset] == 0)
321 offset++;
322 FAT_LFN_ATTR(d) = FAT_ATTR_LFN;
323 d->lfn.type = 0;
324 d->lfn.firstc_lo = 0;
325
326 return *offset;
327}
328
329void str_to_ascii(char *dst, const char *src, size_t count, uint8_t pad)
330{
331 wchar_t ch;
332 size_t off = 0;
333 size_t i = 0;
334
335 while (i < count) {
336 if ((ch = str_decode(src, &off, STR_NO_LIMIT)) != 0) {
337 if (ascii_check(ch) & IS_D_CHAR(ch))
338 *dst = toupper(ch);
339 else
340 *dst = pad;
341 } else
342 break;
343
344 dst++;
345 i++;
346 }
347 *dst = '\0';
348}
349
350bool fat_valid_name(const char *name)
351{
352 wchar_t ch;
353 size_t offset=0;
354 bool result = true;
355
356 while ((ch = str_decode(name, &offset, STR_NO_LIMIT)) != 0) {
357 if (str_chr(FAT_STOP_CHARS, ch) != NULL) {
358 result = false;
359 break;
360 }
361 }
362 return result;
363}
364
365bool fat_valid_short_name(const char *name)
366{
367 unsigned int i;
368 unsigned int dot = 0;
369 bool dot_found = false;
370
371 for (i = 0; name[i]; i++) {
372 if (name[i] == '.') {
373 if (dot_found) {
374 return false;
375 } else {
376 dot_found = true;
377 dot = i;
378 }
379 } else {
380 if (!IS_D_CHAR(name[i]))
381 return false;
382 }
383 }
384
385 if (dot_found) {
386 if (dot > FAT_NAME_LEN)
387 return false;
388 if (i - dot > FAT_EXT_LEN + 1)
389 return false;
390 } else {
391 if (i > FAT_NAME_LEN)
392 return false;
393 }
394
395 return true;
396}
397
398size_t utf16_length(const uint16_t *wstr)
399{
400 size_t len = 0;
401
402 while (*wstr++ != 0)
403 len++;
404
405 return len;
406}
407
408/**
409 * @}
410 */
Note: See TracBrowser for help on using the repository browser.