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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b1834a01 was b1834a01, checked in by Jakub Jermar <jakub@…>, 7 years ago

Categorize the remaining orphan doxygroups

  • Property mode set to 100644
File size: 16.5 KB
RevLine 
[48e3190]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
[b1834a01]29/** @addtogroup udf
[48e3190]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>
[38d150e]40#include <stdlib.h>
[48e3190]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 *
[cde999a]56 * @return EOK on success or an error code.
[48e3190]57 *
58 */
[b7fd2a0]59static errno_t udf_read_extended_allocator(udf_node_t *node, uint16_t icb_flag,
[48e3190]60 uint32_t pos)
61{
62 block_t *block = NULL;
[b7fd2a0]63 errno_t rc = block_get(&block, node->instance->service_id, pos,
[48e3190]64 BLOCK_FLAGS_NONE);
65 if (rc != EOK)
66 return rc;
[a35b458]67
[48e3190]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);
[a35b458]72
[70253688]73 log_msg(LOG_DEFAULT, LVL_DEBUG,
[48e3190]74 "Extended allocator: start=%d, block_num=%d, len=%d", start,
75 FLE32(exd->extent_location.lblock_num), FLE32(exd->info_length));
[a35b458]76
[48e3190]77 uint32_t len = FLE32(exd->info_length);
78 block_put(block);
[a35b458]79
[48e3190]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 *
[cde999a]92 * @return EOK on success or an error code.
[48e3190]93 *
94 */
[b7fd2a0]95errno_t udf_read_allocation_sequence(udf_node_t *node, uint8_t *af,
[48e3190]96 uint16_t icb_flag, uint32_t start_alloc, uint32_t len)
97{
98 node->alloc_size = 0;
[a35b458]99
[48e3190]100 switch (icb_flag) {
101 case UDF_SHORT_AD:
[70253688]102 log_msg(LOG_DEFAULT, LVL_DEBUG,
[48e3190]103 "ICB: sequence of allocation descriptors - icbflag = short_ad_t");
[a35b458]104
[48e3190]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;
[a35b458]112
[48e3190]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 }
[a35b458]123
[48e3190]124 if (pd_num == (size_t) -1)
125 return ENOENT;
[a35b458]126
[48e3190]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 */
[a35b458]135
[48e3190]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));
[a35b458]140
[48e3190]141 if (FLE32(short_d->length) == 0)
142 break;
[a35b458]143
[48e3190]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 }
[a35b458]154
[48e3190]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 }
[a35b458]163
[48e3190]164 node->allocators = realloc(node->allocators,
165 node->alloc_size * sizeof(udf_allocator_t));
166 break;
[a35b458]167
[48e3190]168 case UDF_LONG_AD:
[70253688]169 log_msg(LOG_DEFAULT, LVL_DEBUG,
[48e3190]170 "ICB: sequence of allocation descriptors - icbflag = long_ad_t");
[a35b458]171
[48e3190]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));
[a35b458]176
[48e3190]177 if (FLE32(long_d->length) == 0)
178 break;
[a35b458]179
[48e3190]180 uint32_t pos_long_ad = udf_long_ad_to_pos(node->instance, long_d);
[a35b458]181
[48e3190]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) {
[5c702a8]187 udf_read_extended_allocator(node, icb_flag, pos_long_ad);
[48e3190]188 break;
189 }
[a35b458]190
[48e3190]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;
[a35b458]196
[48e3190]197 node->alloc_size++;
198 }
[a35b458]199
[48e3190]200 node->allocators = realloc(node->allocators,
201 node->alloc_size * sizeof(udf_allocator_t));
202 break;
[a35b458]203
[48e3190]204 case UDF_EXTENDED_AD:
[70253688]205 log_msg(LOG_DEFAULT, LVL_DEBUG,
[48e3190]206 "ICB: sequence of allocation descriptors - icbflag = extended_ad_t");
207 break;
[a35b458]208
[48e3190]209 case UDF_DATA_AD:
[70253688]210 log_msg(LOG_DEFAULT, LVL_DEBUG,
[48e3190]211 "ICB: sequence of allocation descriptors - icbflag = 3, node contains data itself");
[a35b458]212
[48e3190]213 node->data = malloc(node->data_size);
214 if (!node->data)
215 return ENOMEM;
[a35b458]216
[48e3190]217 memcpy(node->data, (af + start_alloc), node->data_size);
218 node->alloc_size = 0;
219 break;
220 }
[a35b458]221
[48e3190]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 *
[cde999a]233 * @return EOK on success or an error code.
[48e3190]234 */
[b7fd2a0]235errno_t udf_read_icb(udf_node_t *node)
[48e3190]236{
237 while (true) {
238 fs_index_t pos = node->index;
[a35b458]239
[48e3190]240 block_t *block = NULL;
[b7fd2a0]241 errno_t rc = block_get(&block, node->instance->service_id, pos,
[48e3190]242 BLOCK_FLAGS_NONE);
243 if (rc != EOK)
244 return rc;
[a35b458]245
[48e3190]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 }
[a35b458]251
[48e3190]252 /* One sector size descriptors */
253 switch (FLE16(data->id)) {
254 case UDF_FILE_ENTRY:
[70253688]255 log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: File entry descriptor found");
[a35b458]256
[48e3190]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;
[a35b458]262
[48e3190]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;
[a35b458]267
[48e3190]268 case UDF_EFILE_ENTRY:
[70253688]269 log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Extended file entry descriptor found");
[a35b458]270
[48e3190]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;
[a35b458]276
[48e3190]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;
[a35b458]281
[48e3190]282 case UDF_ICB_TERMINAL:
[70253688]283 log_msg(LOG_DEFAULT, LVL_DEBUG, "ICB: Terminal entry descriptor found");
[48e3190]284 block_put(block);
285 return EOK;
286 }
[a35b458]287
[48e3190]288 pos++;
[a35b458]289
[48e3190]290 rc = block_put(block);
291 if (rc != EOK)
292 return rc;
293 }
[a35b458]294
[48e3190]295 return EOK;
296}
297
298/** Read data from disk - filling UDF node by allocators
299 *
300 * @param node UDF node
301 *
[cde999a]302 * @return EOK on success or an error code.
[48e3190]303 *
304 */
[b7fd2a0]305errno_t udf_node_get_core(udf_node_t *node)
[48e3190]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 *
[cde999a]317 * @return EOK on success or an error code.
[48e3190]318 *
319 */
[b7fd2a0]320static errno_t udf_get_fid_in_data(udf_file_identifier_descriptor_t **fid,
[48e3190]321 udf_node_t *node, aoff64_t pos)
322{
323 size_t fid_sum = 0;
324 size_t n = 0;
[a35b458]325
[48e3190]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 }
[a35b458]335
[48e3190]336 *fid = (udf_file_identifier_descriptor_t *)
337 (node->data + fid_sum);
[a35b458]338
[48e3190]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;
[a35b458]345
[48e3190]346 fid_sum += size_fid;
[a35b458]347
[48e3190]348 /* aAcording to ECMA 167 4/8.6 */
349 if (((*fid)->lenght_file_id != 0) &&
350 (((*fid)->file_characteristics & 4) == 0)) {
351 n++;
[a35b458]352
[48e3190]353 if (n == pos + 1)
354 return EOK;
355 }
356 }
[a35b458]357
[48e3190]358 return ENOENT;
359}
360
[5c702a8]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 *
[cde999a]368 * @return EOK on success or an error code.
[5c702a8]369 *
370 */
[b7fd2a0]371errno_t udf_get_fid(udf_file_identifier_descriptor_t **fid, block_t **block,
[5c702a8]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);
[a35b458]376
[5c702a8]377 return udf_get_fid_in_data(fid, node, pos);
378}
379
[48e3190]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 *
[cde999a]387 * @return EOK on success or an error code.
[48e3190]388 *
389 */
[b7fd2a0]390errno_t udf_get_fid_in_allocator(udf_file_identifier_descriptor_t **fid,
[48e3190]391 block_t **block, udf_node_t *node, aoff64_t pos)
392{
393 void *buf = malloc(node->instance->sector_size);
[a35b458]394
[48e3190]395 // FIXME: Check for NULL return value
[a35b458]396
[48e3190]397 size_t j = 0;
398 size_t n = 0;
399 size_t len = 0;
[a35b458]400
[48e3190]401 while (j < node->alloc_size) {
402 size_t i = 0;
403 while (i * node->instance->sector_size < node->allocators[j].length) {
[b7fd2a0]404 errno_t rc = block_get(block, node->instance->service_id,
[48e3190]405 node->allocators[j].position + i, BLOCK_FLAGS_NONE);
406 if (rc != EOK) {
407 // FIXME: Memory leak
408 return rc;
409 }
[a35b458]410
[48e3190]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 }
[a35b458]424
[48e3190]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 }
[a35b458]430
[48e3190]431 if (rc == EINVAL) {
432 // FIXME: Memory leak
433 return ENOENT;
434 }
[a35b458]435
[48e3190]436 if (rc == ENOENT) {
437 if (block) {
438 rc = block_put(*block);
439 *block = NULL;
[a35b458]440
[48e3190]441 if (rc != EOK)
442 return rc;
443 }
444 }
[a35b458]445
[48e3190]446 i++;
447 }
[a35b458]448
[48e3190]449 j++;
450 }
[a35b458]451
[48e3190]452 if (buf)
453 free(buf);
[a35b458]454
[48e3190]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 *
[cde999a]468 * @return EOK on success or an error code.
[48e3190]469 *
470 */
[b7fd2a0]471errno_t udf_get_fid_in_sector(udf_file_identifier_descriptor_t **fid,
[48e3190]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);
[a35b458]476
[48e3190]477 // FIXME: Check for NULL return value
[a35b458]478
[48e3190]479 bool buf_flag;
[a35b458]480
[48e3190]481 if (*len > 0) {
482 memcpy(fidbuf, *buf, *len);
483 buf_flag = true;
484 } else
485 buf_flag = false;
[a35b458]486
[48e3190]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;
[a35b458]491
[48e3190]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;
[a35b458]498
[48e3190]499 udf_descriptor_tag_t *desc =
500 (udf_descriptor_tag_t *) fid_data;
[a35b458]501
[48e3190]502 if (desc->checksum != udf_tag_checksum((uint8_t *) desc)) {
503 if (fidbuf)
504 free(fidbuf);
[a35b458]505
[48e3190]506 if (*buf) {
507 free(*buf);
508 *buf = NULL;
509 *len = 0;
510 }
[a35b458]511
[48e3190]512 return EINVAL;
513 }
[a35b458]514
[48e3190]515 *fid = (udf_file_identifier_descriptor_t *) fid_data;
[a35b458]516
[48e3190]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;
[a35b458]527
[48e3190]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);
[a35b458]535
[48e3190]536 return EOK;
537 }
538 }
[a35b458]539
[48e3190]540 if (fidbuf) {
541 buf_flag = false;
542 free(fidbuf);
543 fidbuf = NULL;
544 }
[a35b458]545
[48e3190]546 if (*buf) {
547 free(*buf);
548 *buf = NULL;
549 *len = 0;
550 }
551 } else {
552 if (*buf)
553 free(*buf);
[a35b458]554
[48e3190]555 *len = node->instance->sector_size - fid_sum;
556 *buf = malloc(*len);
557 buf_flag = false;
558 memcpy(*buf, ((*block)->data + fid_sum), *len);
[a35b458]559
[48e3190]560 return ENOENT;
561 }
562 }
[a35b458]563
[48e3190]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.
[984a9ba]570 * @param call IPC call
[48e3190]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 *
[cde999a]575 * @return EOK on success or an error code.
[48e3190]576 *
577 */
[984a9ba]578errno_t udf_read_file(size_t *read_len, ipc_call_t *call, udf_node_t *node,
[48e3190]579 aoff64_t pos, size_t len)
580{
581 size_t i = 0;
582 size_t l = 0;
[a35b458]583
[48e3190]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 }
[a35b458]591
[48e3190]592 size_t sector_cnt = ALL_UP(l, node->instance->sector_size);
593 size_t sector_num = pos / node->instance->sector_size;
[a35b458]594
[48e3190]595 block_t *block = NULL;
[b7fd2a0]596 errno_t rc = block_get(&block, node->instance->service_id,
[48e3190]597 node->allocators[i].position + (sector_num - sector_cnt),
598 BLOCK_FLAGS_NONE);
599 if (rc != EOK) {
[984a9ba]600 async_answer_0(call, rc);
[48e3190]601 return rc;
602 }
[a35b458]603
[48e3190]604 size_t sector_pos = pos % node->instance->sector_size;
[a35b458]605
[48e3190]606 if (sector_pos + len < node->instance->sector_size)
607 *read_len = len;
608 else
609 *read_len = node->instance->sector_size - sector_pos;
[a35b458]610
[48e3190]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 }
[a35b458]620
[984a9ba]621 async_data_read_finalize(call, block->data + sector_pos, *read_len);
[48e3190]622 return block_put(block);
623}
624
625/**
626 * @}
627 */
Note: See TracBrowser for help on using the repository browser.