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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b9060a83 was 65ccd23, checked in by Oleg Romanenko <romanenko.oleg@…>, 14 years ago

Initial support for LFN. Long names could be read from
filesystem through common api: readdir()

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