source: mainline/uspace/srv/fs/fat/fat_directory.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 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: 12.5 KB
Line 
1/*
2 * Copyright (c) 2011 Oleg Romanenko
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_directory.c
35 * @brief Functions that work with FAT directory.
36 */
37
38#include "fat_directory.h"
39#include "fat_fat.h"
40#include <block.h>
41#include <errno.h>
42#include <byteorder.h>
43#include <mem.h>
44#include <str.h>
45#include <align.h>
46#include <stdio.h>
47
48errno_t fat_directory_open(fat_node_t *nodep, fat_directory_t *di)
49{
50 di->b = NULL;
51 di->nodep = nodep;
52 if (di->nodep->type != FAT_DIRECTORY)
53 return EINVAL;
54
55 di->bs = block_bb_get(di->nodep->idx->service_id);
56 di->blocks = ROUND_UP(nodep->size, BPS(di->bs)) / BPS(di->bs);
57 di->pos = 0;
58 di->bnum = 0;
59 di->last = false;
60
61 return EOK;
62}
63
64errno_t fat_directory_close(fat_directory_t *di)
65{
66 errno_t rc = EOK;
67
68 if (di->b)
69 rc = block_put(di->b);
70
71 return rc;
72}
73
74static errno_t fat_directory_block_load(fat_directory_t *di)
75{
76 uint32_t i;
77 errno_t rc;
78
79 i = (di->pos * sizeof(fat_dentry_t)) / BPS(di->bs);
80 if (i < di->blocks) {
81 if (di->b && di->bnum != i) {
82 block_put(di->b);
83 di->b = NULL;
84 }
85 if (!di->b) {
86 rc = fat_block_get(&di->b, di->bs, di->nodep, i,
87 BLOCK_FLAGS_NONE);
88 if (rc != EOK) {
89 di->b = NULL;
90 return rc;
91 }
92 di->bnum = i;
93 }
94 return EOK;
95 }
96
97 return ENOENT;
98}
99
100errno_t fat_directory_next(fat_directory_t *di)
101{
102 errno_t rc;
103
104 di->pos += 1;
105 rc = fat_directory_block_load(di);
106 if (rc != EOK)
107 di->pos -= 1;
108
109 return rc;
110}
111
112errno_t fat_directory_prev(fat_directory_t *di)
113{
114 errno_t rc = EOK;
115
116 if (di->pos > 0) {
117 di->pos -= 1;
118 rc = fat_directory_block_load(di);
119 } else
120 return ENOENT;
121
122 if (rc != EOK)
123 di->pos += 1;
124
125 return rc;
126}
127
128errno_t fat_directory_seek(fat_directory_t *di, aoff64_t pos)
129{
130 aoff64_t _pos = di->pos;
131 errno_t rc;
132
133 di->pos = pos;
134 rc = fat_directory_block_load(di);
135 if (rc != EOK)
136 di->pos = _pos;
137
138 return rc;
139}
140
141errno_t fat_directory_get(fat_directory_t *di, fat_dentry_t **d)
142{
143 errno_t rc;
144
145 rc = fat_directory_block_load(di);
146 if (rc == EOK) {
147 aoff64_t o = di->pos % (BPS(di->bs) / sizeof(fat_dentry_t));
148 *d = ((fat_dentry_t *)di->b->data) + o;
149 }
150
151 return rc;
152}
153
154errno_t fat_directory_read(fat_directory_t *di, char *name, fat_dentry_t **de)
155{
156 fat_dentry_t *d = NULL;
157 uint16_t wname[FAT_LFN_NAME_LEN];
158 size_t lfn_offset, lfn_size;
159 bool long_entry = false;
160 int long_entry_count = 0;
161 uint8_t checksum = 0;
162 errno_t rc;
163
164 void *data;
165 fat_instance_t *instance;
166
167 rc = fs_instance_get(di->nodep->idx->service_id, &data);
168 assert(rc == EOK);
169 instance = (fat_instance_t *) data;
170
171 do {
172 rc = fat_directory_get(di, &d);
173 if (rc != EOK)
174 return rc;
175
176 switch (fat_classify_dentry(d)) {
177 case FAT_DENTRY_LAST:
178 long_entry_count = 0;
179 long_entry = false;
180 return ENOENT;
181 case FAT_DENTRY_LFN:
182 if (long_entry) {
183 /* We found long entry */
184 long_entry_count--;
185 if ((FAT_LFN_ORDER(d) == long_entry_count) &&
186 (checksum == FAT_LFN_CHKSUM(d))) {
187 /* Right order! */
188 fat_lfn_get_entry(d, wname,
189 &lfn_offset);
190 } else {
191 /*
192 * Something wrong with order.
193 * Skip this long entries set.
194 */
195 long_entry_count = 0;
196 long_entry = false;
197 }
198 } else if (FAT_IS_LFN(d) && instance->lfn_enabled) {
199 /* We found Last long entry! */
200 if (FAT_LFN_COUNT(d) <= FAT_LFN_MAX_COUNT) {
201 long_entry = true;
202 long_entry_count = FAT_LFN_COUNT(d);
203 lfn_size = (FAT_LFN_ENTRY_SIZE *
204 (FAT_LFN_COUNT(d) - 1)) +
205 fat_lfn_size(d);
206 lfn_offset = lfn_size;
207 fat_lfn_get_entry(d, wname,
208 &lfn_offset);
209 checksum = FAT_LFN_CHKSUM(d);
210 }
211 }
212 break;
213 case FAT_DENTRY_VALID:
214 if (long_entry &&
215 (checksum == fat_dentry_chksum(d->name))) {
216 wname[lfn_size] = '\0';
217 if (utf16_to_str(name, FAT_LFN_NAME_SIZE,
218 wname) != EOK)
219 fat_dentry_name_get(d, name);
220 } else
221 fat_dentry_name_get(d, name);
222
223 *de = d;
224 return EOK;
225 case FAT_DENTRY_SKIP:
226 case FAT_DENTRY_FREE:
227 case FAT_DENTRY_VOLLABEL:
228 default:
229 long_entry_count = 0;
230 long_entry = false;
231 break;
232 }
233 } while (fat_directory_next(di) == EOK);
234
235 return ENOENT;
236}
237
238errno_t fat_directory_erase(fat_directory_t *di)
239{
240 errno_t rc;
241 fat_dentry_t *d;
242 bool flag = false;
243 uint8_t checksum;
244
245 rc = fat_directory_get(di, &d);
246 if (rc != EOK)
247 return rc;
248 checksum = fat_dentry_chksum(d->name);
249
250 d->name[0] = FAT_DENTRY_ERASED;
251 di->b->dirty = true;
252
253 while (!flag && fat_directory_prev(di) == EOK) {
254 if (fat_directory_get(di, &d) == EOK &&
255 fat_classify_dentry(d) == FAT_DENTRY_LFN &&
256 checksum == FAT_LFN_CHKSUM(d)) {
257 if (FAT_IS_LFN(d))
258 flag = true;
259 memset(d, 0, sizeof(fat_dentry_t));
260 d->name[0] = FAT_DENTRY_ERASED;
261 di->b->dirty = true;
262 } else
263 break;
264 }
265
266 return EOK;
267}
268
269errno_t fat_directory_write(fat_directory_t *di, const char *name, fat_dentry_t *de)
270{
271 errno_t rc;
272 void *data;
273 fat_instance_t *instance;
274
275 rc = fs_instance_get(di->nodep->idx->service_id, &data);
276 assert(rc == EOK);
277 instance = (fat_instance_t *) data;
278
279 if (fat_valid_short_name(name)) {
280 /*
281 * NAME could be directly stored in dentry without creating
282 * LFN.
283 */
284 fat_dentry_name_set(de, name);
285 if (fat_directory_is_sfn_exist(di, de))
286 return EEXIST;
287 rc = fat_directory_lookup_free(di, 1);
288 if (rc != EOK)
289 return rc;
290 rc = fat_directory_write_dentry(di, de);
291 return rc;
292 } else if (instance->lfn_enabled && fat_valid_name(name)) {
293 /* We should create long entries to store name */
294 int long_entry_count;
295 uint8_t checksum;
296 uint16_t wname[FAT_LFN_NAME_LEN];
297 size_t lfn_size, lfn_offset;
298
299 rc = str_to_utf16(wname, FAT_LFN_NAME_LEN, name);
300 if (rc != EOK)
301 return rc;
302
303 lfn_size = utf16_wsize(wname);
304 long_entry_count = lfn_size / FAT_LFN_ENTRY_SIZE;
305 if (lfn_size % FAT_LFN_ENTRY_SIZE)
306 long_entry_count++;
307 rc = fat_directory_lookup_free(di, long_entry_count + 1);
308 if (rc != EOK)
309 return rc;
310 aoff64_t start_pos = di->pos;
311
312 /* Write Short entry */
313 rc = fat_directory_create_sfn(di, de, name);
314 if (rc != EOK)
315 return rc;
316 checksum = fat_dentry_chksum(de->name);
317
318 rc = fat_directory_seek(di, start_pos + long_entry_count);
319 if (rc != EOK)
320 return rc;
321 rc = fat_directory_write_dentry(di, de);
322 if (rc != EOK)
323 return rc;
324
325 /* Write Long entry by parts */
326 lfn_offset = 0;
327 fat_dentry_t *d;
328 size_t idx = 0;
329 do {
330 rc = fat_directory_prev(di);
331 if (rc != EOK)
332 return rc;
333 rc = fat_directory_get(di, &d);
334 if (rc != EOK)
335 return rc;
336 fat_lfn_set_entry(wname, &lfn_offset, lfn_size + 1, d);
337 FAT_LFN_CHKSUM(d) = checksum;
338 FAT_LFN_ORDER(d) = ++idx;
339 di->b->dirty = true;
340 } while (lfn_offset < lfn_size);
341 FAT_LFN_ORDER(d) |= FAT_LFN_LAST;
342
343 rc = fat_directory_seek(di, start_pos + long_entry_count);
344 return rc;
345 }
346
347 return ENOTSUP;
348}
349
350errno_t fat_directory_create_sfn(fat_directory_t *di, fat_dentry_t *de,
351 const char *lname)
352{
353 char name[FAT_NAME_LEN + 1];
354 char ext[FAT_EXT_LEN + 1];
355 char number[FAT_NAME_LEN + 1];
356 memset(name, FAT_PAD, FAT_NAME_LEN);
357 memset(ext, FAT_PAD, FAT_EXT_LEN);
358 memset(number, FAT_PAD, FAT_NAME_LEN);
359
360 size_t name_len = str_size(lname);
361 char *pdot = str_rchr(lname, '.');
362 ext[FAT_EXT_LEN] = '\0';
363 if (pdot) {
364 pdot++;
365 str_to_ascii(ext, pdot, FAT_EXT_LEN, FAT_SFN_CHAR);
366 name_len = (pdot - lname - 1);
367 }
368 if (name_len > FAT_NAME_LEN)
369 name_len = FAT_NAME_LEN;
370 str_to_ascii(name, lname, name_len, FAT_SFN_CHAR);
371
372 unsigned idx;
373 for (idx = 1; idx <= FAT_MAX_SFN; idx++) {
374 snprintf(number, sizeof(number), "%u", idx);
375
376 /* Fill de->name with FAT_PAD */
377 memset(de->name, FAT_PAD, FAT_NAME_LEN + FAT_EXT_LEN);
378 /* Copy ext */
379 memcpy(de->ext, ext, str_size(ext));
380 /* Copy name */
381 memcpy(de->name, name, str_size(name));
382
383 /* Copy number */
384 size_t offset;
385 if (str_size(name)+str_size(number) + 1 > FAT_NAME_LEN)
386 offset = FAT_NAME_LEN - str_size(number) - 1;
387 else
388 offset = str_size(name);
389 de->name[offset] = '~';
390 offset++;
391 memcpy(de->name + offset, number, str_size(number));
392
393 if (!fat_directory_is_sfn_exist(di, de))
394 return EOK;
395 }
396
397 return ERANGE;
398}
399
400errno_t fat_directory_write_dentry(fat_directory_t *di, fat_dentry_t *de)
401{
402 fat_dentry_t *d;
403 errno_t rc;
404
405 rc = fat_directory_get(di, &d);
406 if (rc != EOK)
407 return rc;
408 memcpy(d, de, sizeof(fat_dentry_t));
409 di->b->dirty = true;
410
411 return EOK;
412}
413
414errno_t fat_directory_expand(fat_directory_t *di)
415{
416 errno_t rc;
417 fat_cluster_t mcl, lcl;
418
419 if (!FAT_IS_FAT32(di->bs) && di->nodep->firstc == FAT_CLST_ROOT) {
420 /* Can't grow the root directory on FAT12/16. */
421 return ENOSPC;
422 }
423 rc = fat_alloc_clusters(di->bs, di->nodep->idx->service_id, 1, &mcl,
424 &lcl);
425 if (rc != EOK)
426 return rc;
427 rc = fat_zero_cluster(di->bs, di->nodep->idx->service_id, mcl);
428 if (rc != EOK) {
429 (void) fat_free_clusters(di->bs, di->nodep->idx->service_id,
430 mcl);
431 return rc;
432 }
433 rc = fat_append_clusters(di->bs, di->nodep, mcl, lcl);
434 if (rc != EOK) {
435 (void) fat_free_clusters(di->bs, di->nodep->idx->service_id,
436 mcl);
437 return rc;
438 }
439 di->nodep->size += BPS(di->bs) * SPC(di->bs);
440 di->nodep->dirty = true; /* need to sync node */
441 di->blocks = di->nodep->size / BPS(di->bs);
442
443 return EOK;
444}
445
446errno_t fat_directory_lookup_free(fat_directory_t *di, size_t count)
447{
448 fat_dentry_t *d;
449 size_t found;
450 aoff64_t pos;
451 errno_t rc;
452
453 do {
454 found = 0;
455 pos = 0;
456 fat_directory_seek(di, 0);
457 do {
458 rc = fat_directory_get(di, &d);
459 if (rc != EOK)
460 return rc;
461
462 switch (fat_classify_dentry(d)) {
463 case FAT_DENTRY_LAST:
464 case FAT_DENTRY_FREE:
465 if (found == 0)
466 pos = di->pos;
467 found++;
468 if (found == count) {
469 fat_directory_seek(di, pos);
470 return EOK;
471 }
472 break;
473 case FAT_DENTRY_VALID:
474 case FAT_DENTRY_LFN:
475 case FAT_DENTRY_SKIP:
476 case FAT_DENTRY_VOLLABEL:
477 default:
478 found = 0;
479 break;
480 }
481 } while (fat_directory_next(di) == EOK);
482 } while (fat_directory_expand(di) == EOK);
483
484 return ENOSPC;
485}
486
487errno_t fat_directory_lookup_name(fat_directory_t *di, const char *name,
488 fat_dentry_t **de)
489{
490 char entry[FAT_LFN_NAME_SIZE];
491
492 fat_directory_seek(di, 0);
493 while (fat_directory_read(di, entry, de) == EOK) {
494 if (fat_dentry_namecmp(entry, name) == 0) {
495 return EOK;
496 } else {
497 if (fat_directory_next(di) != EOK)
498 break;
499 }
500 }
501
502 return ENOENT;
503}
504
505bool fat_directory_is_sfn_exist(fat_directory_t *di, fat_dentry_t *de)
506{
507 fat_dentry_t *d;
508 errno_t rc;
509
510 fat_directory_seek(di, 0);
511 do {
512 rc = fat_directory_get(di, &d);
513 if (rc != EOK)
514 return false;
515
516 switch (fat_classify_dentry(d)) {
517 case FAT_DENTRY_LAST:
518 return false;
519 case FAT_DENTRY_VALID:
520 if (memcmp(de->name, d->name,
521 FAT_NAME_LEN + FAT_EXT_LEN) == 0)
522 return true;
523 break;
524 default:
525 case FAT_DENTRY_LFN:
526 case FAT_DENTRY_SKIP:
527 case FAT_DENTRY_VOLLABEL:
528 case FAT_DENTRY_FREE:
529 break;
530 }
531 } while (fat_directory_next(di) == EOK);
532
533 return false;
534}
535
536/** Find volume label entry in a directory.
537 *
538 * @return EOK on success, ENOENT if not found, EIO on I/O error
539 */
540errno_t fat_directory_vollabel_get(fat_directory_t *di, char *label)
541{
542 fat_dentry_t *d;
543 errno_t rc;
544
545 fat_directory_seek(di, 0);
546 do {
547 rc = fat_directory_get(di, &d);
548 if (rc != EOK)
549 return EIO;
550
551 switch (fat_classify_dentry(d)) {
552 case FAT_DENTRY_VOLLABEL:
553 fat_dentry_vollabel_get(d, label);
554 return EOK;
555 default:
556 break;
557 }
558 } while (fat_directory_next(di) == EOK);
559
560 /* Not found */
561 return ENOENT;
562}
563
564/**
565 * @}
566 */
Note: See TracBrowser for help on using the repository browser.