source: mainline/uspace/srv/fs/udf/udf_file.c@ 38d150e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 38d150e was 38d150e, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Prefer to get memory allocation functions through the standard stdlib header.

  • Property mode set to 100644
File size: 16.7 KB
Line 
1/*
2 * Copyright (c) 2012 Julia Medvedeva
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 * @file udf_file.c
34 * @brief Implementation of file operations. Reading and writing functions.
35 */
36
37#include <block.h>
38#include <libfs.h>
39#include <errno.h>
40#include <stdlib.h>
41#include <inttypes.h>
42#include <io/log.h>
43#include <mem.h>
44#include "udf.h"
45#include "udf_file.h"
46#include "udf_cksum.h"
47#include "udf_volume.h"
48
49/** Read extended allocator in allocation sequence
50 *
51 * @paran node UDF node
52 * @param icb_flag Type of allocators in sequence.
53 * According to ECMA 167 4/14.8.8
54 * @param pos Position with which we read
55 *
56 * @return EOK on success or a negative error code.
57 *
58 */
59static int udf_read_extended_allocator(udf_node_t *node, uint16_t icb_flag,
60 uint32_t pos)
61{
62 block_t *block = NULL;
63 int rc = block_get(&block, node->instance->service_id, pos,
64 BLOCK_FLAGS_NONE);
65 if (rc != EOK)
66 return rc;
67
68 udf_ext_ad_t *exd = (udf_ext_ad_t *) block->data;
69 uint32_t start = node->instance->partitions[
70 FLE16(exd->extent_location.partition_num)].start +
71 FLE32(exd->extent_location.lblock_num);
72
73 log_msg(LOG_DEFAULT, LVL_DEBUG,
74 "Extended allocator: start=%d, block_num=%d, len=%d", start,
75 FLE32(exd->extent_location.lblock_num), FLE32(exd->info_length));
76
77 uint32_t len = FLE32(exd->info_length);
78 block_put(block);
79
80 return udf_read_allocation_sequence(node, NULL, icb_flag, start, len);
81}
82
83/** Read ICB sequence of allocators in (Extended) File entry descriptor
84 *
85 * @parem node UDF node
86 * @param af (Extended) File entry descriptor
87 * @param icb_flag Type of allocators in sequence.
88 * According to ECMA 167 4/14.8.8
89 * @param start_alloc Offset of the allocator
90 * @param len Length of sequence
91 *
92 * @return EOK on success or a negative error code.
93 *
94 */
95int udf_read_allocation_sequence(udf_node_t *node, uint8_t *af,
96 uint16_t icb_flag, uint32_t start_alloc, uint32_t len)
97{
98 node->alloc_size = 0;
99
100 switch (icb_flag) {
101 case UDF_SHORT_AD:
102 log_msg(LOG_DEFAULT, LVL_DEBUG,
103 "ICB: sequence of allocation descriptors - icbflag = short_ad_t");
104
105 /*
106 * Identify number of current partition. Virtual partition
107 * could placed inside of physical partition. It means that same
108 * sector could be inside of both partition physical and virtual.
109 */
110 size_t pd_num = (size_t) -1;
111 size_t min_start = 0;
112
113 for (size_t i = 0; i < node->instance->partition_cnt; i++) {
114 if ((node->index >= node->instance->partitions[i].start) &&
115 (node->index < node->instance->partitions[i].start +
116 node->instance->partitions[i].lenght)) {
117 if (node->instance->partitions[i].start >= min_start) {
118 min_start = node->instance->partitions[i].start;
119 pd_num = i;
120 }
121 }
122 }
123
124 if (pd_num == (size_t) -1)
125 return ENOENT;
126
127 /*
128 * According to doc, in this we should stop our loop if pass
129 * all allocators. Count of items in sequence of allocators
130 * cnt = len / sizeof(udf_long_ad_t)
131 * But in case of Blu-Ray data len could be zero.
132 * It means that we have only two conditions for stopping
133 * which we check inside of loop.
134 */
135
136 while (true) {
137 udf_short_ad_t *short_d =
138 (udf_short_ad_t *) (af + start_alloc +
139 node->alloc_size * sizeof(udf_short_ad_t));
140
141 if (FLE32(short_d->length) == 0)
142 break;
143
144 /*
145 * ECMA 167 4/12 - next sequence of allocation descriptors
146 * condition according to 167 4/14.6.8
147 */
148 if (FLE32(short_d->length) >> 30 == 3) {
149 udf_read_extended_allocator(node, icb_flag,
150 node->instance->partitions[pd_num].start +
151 FLE32(short_d->position));
152 break;
153 }
154
155 node->allocators = realloc(node->allocators,
156 (node->alloc_size + 1) * sizeof(udf_allocator_t));
157 node->allocators[node->alloc_size].length =
158 EXT_LENGTH(FLE32(short_d->length));
159 node->allocators[node->alloc_size].position =
160 node->instance->partitions[pd_num].start + FLE32(short_d->position);
161 node->alloc_size++;
162 }
163
164 node->allocators = realloc(node->allocators,
165 node->alloc_size * sizeof(udf_allocator_t));
166 break;
167
168 case UDF_LONG_AD:
169 log_msg(LOG_DEFAULT, LVL_DEBUG,
170 "ICB: sequence of allocation descriptors - icbflag = long_ad_t");
171
172 while (true) {
173 udf_long_ad_t *long_d =
174 (udf_long_ad_t *) (af + start_alloc +
175 node->alloc_size * sizeof(udf_long_ad_t));
176
177 if (FLE32(long_d->length) == 0)
178 break;
179
180 uint32_t pos_long_ad = udf_long_ad_to_pos(node->instance, long_d);
181
182 /*
183 * ECMA 167 4/12 - next sequence of allocation descriptors
184 * condition according to 167 4/14.6.8
185 */
186 if (FLE32(long_d->length) >> 30 == 3) {
187 udf_read_extended_allocator(node, icb_flag, pos_long_ad);
188 break;
189 }
190
191 node->allocators = realloc(node->allocators,
192 (node->alloc_size + 1) * sizeof(udf_allocator_t));
193 node->allocators[node->alloc_size].length =
194 EXT_LENGTH(FLE32(long_d->length));
195 node->allocators[node->alloc_size].position = pos_long_ad;
196
197 node->alloc_size++;
198 }
199
200 node->allocators = realloc(node->allocators,
201 node->alloc_size * sizeof(udf_allocator_t));
202 break;
203
204 case UDF_EXTENDED_AD:
205 log_msg(LOG_DEFAULT, LVL_DEBUG,
206 "ICB: sequence of allocation descriptors - icbflag = extended_ad_t");
207 break;
208
209 case UDF_DATA_AD:
210 log_msg(LOG_DEFAULT, LVL_DEBUG,
211 "ICB: sequence of allocation descriptors - icbflag = 3, node contains data itself");
212
213 node->data = malloc(node->data_size);
214 if (!node->data)
215 return ENOMEM;
216
217 memcpy(node->data, (af + start_alloc), node->data_size);
218 node->alloc_size = 0;
219 break;
220 }
221
222 return EOK;
223}
224
225/** Read ICB sequence of descriptors
226 *
227 * Read sequence of descriptors (file entry descriptors or
228 * extended file entry descriptors). Each descriptor contains
229 * sequence of allocators.
230 *
231 * @param node UDF node
232 *
233 * @return EOK on success or a negative error code.
234 */
235int udf_read_icb(udf_node_t *node)
236{
237 while (true) {
238 fs_index_t pos = node->index;
239
240 block_t *block = NULL;
241 int rc = block_get(&block, node->instance->service_id, pos,
242 BLOCK_FLAGS_NONE);
243 if (rc != EOK)
244 return rc;
245
246 udf_descriptor_tag_t *data = (udf_descriptor_tag_t *) block->data;
247 if (data->checksum != udf_tag_checksum((uint8_t *) data)) {
248 block_put(block);
249 return EINVAL;
250 }
251
252 /* One sector size descriptors */
253 switch (FLE16(data->id)) {
254 case UDF_FILE_ENTRY:
255 log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: File entry descriptor found");
256
257 udf_file_entry_descriptor_t *file =
258 (udf_file_entry_descriptor_t *) block->data;
259 uint16_t icb_flag = FLE16(file->icbtag.flags) & UDF_ICBFLAG_MASK;
260 node->data_size = FLE64(file->info_lenght);
261 node->type = (file->icbtag.file_type == UDF_ICBTYPE_DIR) ? NODE_DIR : NODE_FILE;
262
263 rc = udf_read_allocation_sequence(node, (uint8_t *) file, icb_flag,
264 FLE32(file->ea_lenght) + UDF_FE_OFFSET, FLE32(file->ad_lenght));
265 block_put(block);
266 return rc;
267
268 case UDF_EFILE_ENTRY:
269 log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Extended file entry descriptor found");
270
271 udf_extended_file_entry_descriptor_t *efile =
272 (udf_extended_file_entry_descriptor_t *) block->data;
273 icb_flag = FLE16(efile->icbtag.flags) & UDF_ICBFLAG_MASK;
274 node->data_size = FLE64(efile->info_lenght);
275 node->type = (efile->icbtag.file_type == UDF_ICBTYPE_DIR) ? NODE_DIR : NODE_FILE;
276
277 rc = udf_read_allocation_sequence(node, (uint8_t *) efile, icb_flag,
278 FLE32(efile->ea_lenght) + UDF_EFE_OFFSET, FLE32(efile->ad_lenght));
279 block_put(block);
280 return rc;
281
282 case UDF_ICB_TERMINAL:
283 log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Terminal entry descriptor found");
284 block_put(block);
285 return EOK;
286 }
287
288 pos++;
289
290 rc = block_put(block);
291 if (rc != EOK)
292 return rc;
293 }
294
295 return EOK;
296}
297
298/** Read data from disk - filling UDF node by allocators
299 *
300 * @param node UDF node
301 *
302 * @return EOK on success or a negative error code.
303 *
304 */
305int udf_node_get_core(udf_node_t *node)
306{
307 node->link_cnt = 1;
308 return udf_read_icb(node);
309}
310
311/** Read directory entry if all FIDs is saved inside of descriptor
312 *
313 * @param fid Returned value
314 * @param node UDF node
315 * @param pos Number of FID which we need to find
316 *
317 * @return EOK on success or a negative error code.
318 *
319 */
320static int udf_get_fid_in_data(udf_file_identifier_descriptor_t **fid,
321 udf_node_t *node, aoff64_t pos)
322{
323 size_t fid_sum = 0;
324 size_t n = 0;
325
326 while (node->data_size - fid_sum >= MIN_FID_LEN) {
327 udf_descriptor_tag_t *desc =
328 (udf_descriptor_tag_t *) (node->data + fid_sum);
329 if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
330 if (fid_sum == 0)
331 return EINVAL;
332 else
333 return ENOENT;
334 }
335
336 *fid = (udf_file_identifier_descriptor_t *)
337 (node->data + fid_sum);
338
339 /* According to ECMA 167 4/14.4.9 */
340 size_t padding = 4 * (((*fid)->lenght_file_id +
341 FLE16((*fid)->lenght_iu) + 38 + 3) / 4) -
342 ((*fid)->lenght_file_id + FLE16((*fid)->lenght_iu) + 38);
343 size_t size_fid = (*fid)->lenght_file_id +
344 FLE16((*fid)->lenght_iu) + padding + 38;
345
346 fid_sum += size_fid;
347
348 /* aAcording to ECMA 167 4/8.6 */
349 if (((*fid)->lenght_file_id != 0) &&
350 (((*fid)->file_characteristics & 4) == 0)) {
351 n++;
352
353 if (n == pos + 1)
354 return EOK;
355 }
356 }
357
358 return ENOENT;
359}
360
361/** Read directory entry
362 *
363 * @param fid Returned value
364 * @param block Returned value
365 * @param node UDF node
366 * @param pos Number of FID which we need to find
367 *
368 * @return EOK on success or a negative error code.
369 *
370 */
371int udf_get_fid(udf_file_identifier_descriptor_t **fid, block_t **block,
372 udf_node_t *node, aoff64_t pos)
373{
374 if (node->data == NULL)
375 return udf_get_fid_in_allocator(fid, block, node, pos);
376
377 return udf_get_fid_in_data(fid, node, pos);
378}
379
380/** Read directory entry if all FIDS is saved in allocators.
381 *
382 * @param fid Returned value
383 * @param block Returned value
384 * @param node UDF node
385 * @param pos Number of FID which we need to find
386 *
387 * @return EOK on success or a negative error code.
388 *
389 */
390int udf_get_fid_in_allocator(udf_file_identifier_descriptor_t **fid,
391 block_t **block, udf_node_t *node, aoff64_t pos)
392{
393 void *buf = malloc(node->instance->sector_size);
394
395 // FIXME: Check for NULL return value
396
397 size_t j = 0;
398 size_t n = 0;
399 size_t len = 0;
400
401 while (j < node->alloc_size) {
402 size_t i = 0;
403 while (i * node->instance->sector_size < node->allocators[j].length) {
404 int rc = block_get(block, node->instance->service_id,
405 node->allocators[j].position + i, BLOCK_FLAGS_NONE);
406 if (rc != EOK) {
407 // FIXME: Memory leak
408 return rc;
409 }
410
411 /*
412 * Last item in allocator is a part of sector. We take
413 * this fragment and join it to part of sector in next allocator.
414 */
415 if ((node->allocators[j].length / node->instance->sector_size == i) &&
416 (node->allocators[j].length - i * node->instance->sector_size <
417 MIN_FID_LEN)) {
418 size_t len = node->allocators[j].length - i * node->instance->sector_size;
419 memcpy(buf, (*block)->data, len);
420 block_put(*block);
421 *block = NULL;
422 break;
423 }
424
425 rc = udf_get_fid_in_sector(fid, block, node, pos, &n, &buf, &len);
426 if (rc == EOK) {
427 // FIXME: Memory leak
428 return EOK;
429 }
430
431 if (rc == EINVAL) {
432 // FIXME: Memory leak
433 return ENOENT;
434 }
435
436 if (rc == ENOENT) {
437 if (block) {
438 rc = block_put(*block);
439 *block = NULL;
440
441 if (rc != EOK)
442 return rc;
443 }
444 }
445
446 i++;
447 }
448
449 j++;
450 }
451
452 if (buf)
453 free(buf);
454
455 return ENOENT;
456}
457
458/** Read FIDs in sector inside of current allocator
459 *
460 * @param fid Returned value.
461 * @param block Returned value
462 * @param node UDF node
463 * @param pos Number FID which we need to find
464 * @param n Count of FIDs which we already have passed
465 * @param buf Part of FID from last sector (current allocator or previous)
466 * @param len Length of buf
467 *
468 * @return EOK on success or a negative error code.
469 *
470 */
471int udf_get_fid_in_sector(udf_file_identifier_descriptor_t **fid,
472 block_t **block, udf_node_t *node, aoff64_t pos, size_t *n, void **buf,
473 size_t *len)
474{
475 void *fidbuf = malloc(node->instance->sector_size);
476
477 // FIXME: Check for NULL return value
478
479 bool buf_flag;
480
481 if (*len > 0) {
482 memcpy(fidbuf, *buf, *len);
483 buf_flag = true;
484 } else
485 buf_flag = false;
486
487 size_t fid_sum = 0;
488 while (node->instance->sector_size - fid_sum > 0) {
489 if (node->instance->sector_size - fid_sum >= MIN_FID_LEN) {
490 void *fid_data;
491
492 if (buf_flag) {
493 memcpy((fidbuf + *len), (*block)->data,
494 node->instance->sector_size - *len);
495 fid_data = fidbuf;
496 } else
497 fid_data = (*block)->data + fid_sum;
498
499 udf_descriptor_tag_t *desc =
500 (udf_descriptor_tag_t *) fid_data;
501
502 if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
503 if (fidbuf)
504 free(fidbuf);
505
506 if (*buf) {
507 free(*buf);
508 *buf = NULL;
509 *len = 0;
510 }
511
512 return EINVAL;
513 }
514
515 *fid = (udf_file_identifier_descriptor_t *) fid_data;
516
517 /* According to ECMA 167 4/14.4.9 */
518 size_t padding = 4 * (((*fid)->lenght_file_id +
519 FLE16((*fid)->lenght_iu) + 38 + 3) / 4) -
520 ((*fid)->lenght_file_id + FLE16((*fid)->lenght_iu) + 38);
521 size_t size_fid = (*fid)->lenght_file_id +
522 FLE16((*fid)->lenght_iu) + padding + 38;
523 if (buf_flag)
524 fid_sum += size_fid - *len;
525 else
526 fid_sum += size_fid;
527
528 /* According to ECMA 167 4/8.6 */
529 if (((*fid)->lenght_file_id != 0) &&
530 (((*fid)->file_characteristics & 4) == 0)) {
531 (*n)++;
532 if (*n == pos + 1) {
533 if (fidbuf)
534 free(fidbuf);
535
536 return EOK;
537 }
538 }
539
540 if (fidbuf) {
541 buf_flag = false;
542 free(fidbuf);
543 fidbuf = NULL;
544 }
545
546 if (*buf) {
547 free(*buf);
548 *buf = NULL;
549 *len = 0;
550 }
551 } else {
552 if (*buf)
553 free(*buf);
554
555 *len = node->instance->sector_size - fid_sum;
556 *buf = malloc(*len);
557 buf_flag = false;
558 memcpy(*buf, ((*block)->data + fid_sum), *len);
559
560 return ENOENT;
561 }
562 }
563
564 return ENOENT;
565}
566
567/** Read file if it is saved in allocators.
568 *
569 * @param read_len Returned value. Length file or part file which we could read.
570 * @param callid
571 * @param node UDF node
572 * @param pos Position in file since we have to read.
573 * @param len Length of data for reading
574 *
575 * @return EOK on success or a negative error code.
576 *
577 */
578int udf_read_file(size_t *read_len, ipc_callid_t callid, udf_node_t *node,
579 aoff64_t pos, size_t len)
580{
581 size_t i = 0;
582 size_t l = 0;
583
584 while (i < node->alloc_size) {
585 if (pos >= l + node->allocators[i].length) {
586 l += node->allocators[i].length;
587 i++;
588 } else
589 break;
590 }
591
592 size_t sector_cnt = ALL_UP(l, node->instance->sector_size);
593 size_t sector_num = pos / node->instance->sector_size;
594
595 block_t *block = NULL;
596 int rc = block_get(&block, node->instance->service_id,
597 node->allocators[i].position + (sector_num - sector_cnt),
598 BLOCK_FLAGS_NONE);
599 if (rc != EOK) {
600 async_answer_0(callid, rc);
601 return rc;
602 }
603
604 size_t sector_pos = pos % node->instance->sector_size;
605
606 if (sector_pos + len < node->instance->sector_size)
607 *read_len = len;
608 else
609 *read_len = node->instance->sector_size - sector_pos;
610
611 if (ALL_UP(node->allocators[i].length, node->instance->sector_size) ==
612 sector_num - sector_cnt + 1) {
613 if (pos + len > node->allocators[i].length + l)
614 *read_len = node->allocators[i].length -
615 (sector_num - sector_cnt) * node->instance->sector_size -
616 sector_pos;
617 else
618 *read_len = len;
619 }
620
621 async_data_read_finalize(callid, block->data + sector_pos, *read_len);
622 return block_put(block);
623}
624
625/**
626 * @}
627 */
Note: See TracBrowser for help on using the repository browser.