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

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

Rewrite fat_directory_xxx api. Add functions for iterating and accessing
directory entries.

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