source: mainline/uspace/srv/fs/udf/udf_file.c@ 498ced1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 498ced1 was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 16.5 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 an error code.
57 *
58 */
59static errno_t udf_read_extended_allocator(udf_node_t *node, uint16_t icb_flag,
60 uint32_t pos)
61{
62 block_t *block = NULL;
63 errno_t 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 an error code.
93 *
94 */
95errno_t 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 an error code.
234 */
235errno_t 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 errno_t 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 an error code.
303 *
304 */
305errno_t 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 an error code.
318 *
319 */
320static errno_t 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 an error code.
369 *
370 */
371errno_t 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 an error code.
388 *
389 */
390errno_t 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 errno_t 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 an error code.
469 *
470 */
471errno_t 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 call IPC call
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 an error code.
576 *
577 */
578errno_t udf_read_file(size_t *read_len, ipc_call_t *call, 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 errno_t 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(call, 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(call, 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.