source: mainline/uspace/srv/fs/udf/udf_ops.c@ 44dde42

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 44dde42 was 44dde42, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 5 years ago

Fix a memory leak in udf_mounted function when block_init returns with error

  • Property mode set to 100644
File size: 12.7 KB
RevLine 
[48e3190]1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * Copyright (c) 2012 Julia Medvedeva
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
[b1834a01]30/** @addtogroup udf
[48e3190]31 * @{
32 */
33/**
34 * @file udf_ops.c
35 * @brief Implementation of VFS operations for the UDF file system
36 * server.
37 */
38
39#include <libfs.h>
40#include <block.h>
41#include <ipc/services.h>
42#include <ipc/loc.h>
43#include <macros.h>
44#include <async.h>
45#include <errno.h>
46#include <str.h>
47#include <byteorder.h>
48#include <adt/hash_table.h>
49#include <adt/list.h>
50#include <assert.h>
51#include <fibril_synch.h>
52#include <align.h>
[38d150e]53#include <stdlib.h>
[48e3190]54#include <inttypes.h>
55#include <io/log.h>
56#include "../../vfs/vfs.h"
57#include "udf.h"
58#include "udf_cksum.h"
59#include "udf_volume.h"
60#include "udf_idx.h"
61#include "udf_file.h"
62#include "udf_osta.h"
63
64/** List of cached free nodes. */
65static LIST_INITIALIZE(ffn_list);
66
[b7fd2a0]67static errno_t udf_node_get(fs_node_t **rfn, service_id_t service_id,
[48e3190]68 fs_index_t index)
69{
70 udf_instance_t *instance;
[b7fd2a0]71 errno_t rc = fs_instance_get(service_id, (void **) &instance);
[48e3190]72 if (rc != EOK)
73 return rc;
[a35b458]74
[48e3190]75 udf_node_t *node;
76 rc = udf_idx_get(&node, instance, index);
77 if (rc != EOK) {
78 rc = udf_idx_add(&node, instance, index);
79 if (rc != EOK)
80 return rc;
[a35b458]81
[48e3190]82 rc = udf_node_get_core(node);
83 if (rc != EOK) {
84 udf_idx_del(node);
85 return rc;
86 }
87 }
[a35b458]88
[48e3190]89 *rfn = FS_NODE(node);
90 return EOK;
91}
92
[b7fd2a0]93static errno_t udf_root_get(fs_node_t **rfn, service_id_t service_id)
[48e3190]94{
95 udf_instance_t *instance;
[b7fd2a0]96 errno_t rc = fs_instance_get(service_id, (void **) &instance);
[48e3190]97 if (rc != EOK)
98 return rc;
[a35b458]99
[48e3190]100 return udf_node_get(rfn, service_id,
101 instance->volumes[DEFAULT_VOL].root_dir);
102}
103
104static service_id_t udf_service_get(fs_node_t *node)
105{
106 udf_node_t *udfn = UDF_NODE(node);
107 if (udfn)
108 return udfn->instance->service_id;
[a35b458]109
[48e3190]110 return 0;
111}
112
[b7fd2a0]113static errno_t udf_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
[48e3190]114{
115 char *name = malloc(MAX_FILE_NAME_LEN + 1);
116 if (name == NULL)
117 return ENOMEM;
[a35b458]118
[48e3190]119 block_t *block = NULL;
120 udf_file_identifier_descriptor_t *fid = NULL;
121 size_t pos = 0;
[a35b458]122
[48e3190]123 while (udf_get_fid(&fid, &block, UDF_NODE(pfn), pos) == EOK) {
124 udf_long_ad_t long_ad = fid->icb;
[a35b458]125
[48e3190]126 udf_to_unix_name(name, MAX_FILE_NAME_LEN,
[c477c80]127 (char *) fid->implementation_use + FLE16(fid->length_iu),
128 fid->length_file_id, &UDF_NODE(pfn)->instance->charset);
[a35b458]129
[0e7c3d9]130 if (str_casecmp(name, component) == 0) {
[b7fd2a0]131 errno_t rc = udf_node_get(rfn, udf_service_get(pfn),
[48e3190]132 udf_long_ad_to_pos(UDF_NODE(pfn)->instance, &long_ad));
[a35b458]133
[48e3190]134 if (block != NULL)
135 block_put(block);
[a35b458]136
[48e3190]137 free(name);
138 return rc;
139 }
[a35b458]140
[48e3190]141 if (block != NULL) {
[b7fd2a0]142 errno_t rc = block_put(block);
[48e3190]143 if (rc != EOK)
144 return rc;
145 }
[a35b458]146
[48e3190]147 pos++;
148 }
[a35b458]149
[48e3190]150 free(name);
151 return ENOENT;
152}
153
[b7fd2a0]154static errno_t udf_node_open(fs_node_t *fn)
[48e3190]155{
156 return EOK;
157}
158
[b7fd2a0]159static errno_t udf_node_put(fs_node_t *fn)
[48e3190]160{
161 udf_node_t *node = UDF_NODE(fn);
162 if (!node)
163 return EINVAL;
[a35b458]164
[48e3190]165 fibril_mutex_lock(&node->lock);
166 node->ref_cnt--;
167 fibril_mutex_unlock(&node->lock);
[a35b458]168
[48e3190]169 /* Delete node from hash table and memory */
170 if (!node->ref_cnt)
171 udf_idx_del(node);
[a35b458]172
[48e3190]173 return EOK;
174}
175
[b7fd2a0]176static errno_t udf_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
[48e3190]177{
178 return ENOTSUP;
179}
180
[b7fd2a0]181static errno_t udf_destroy_node(fs_node_t *fn)
[48e3190]182{
183 return ENOTSUP;
184}
185
[b7fd2a0]186static errno_t udf_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
[48e3190]187{
188 return ENOTSUP;
189}
190
[b7fd2a0]191static errno_t udf_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
[48e3190]192{
193 return ENOTSUP;
194}
195
[b7fd2a0]196static errno_t udf_has_children(bool *has_children, fs_node_t *fn)
[48e3190]197{
198 *has_children = true;
199 return EOK;
200}
201
202static fs_index_t udf_index_get(fs_node_t *fn)
203{
204 udf_node_t *node = UDF_NODE(fn);
205 if (node)
206 return node->index;
[a35b458]207
[48e3190]208 return 0;
209}
210
211static aoff64_t udf_size_get(fs_node_t *fn)
212{
213 udf_node_t *node = UDF_NODE(fn);
214 if (node)
215 return node->data_size;
[a35b458]216
[48e3190]217 return 0;
218}
219
220static unsigned int udf_lnkcnt_get(fs_node_t *fn)
221{
222 udf_node_t *node = UDF_NODE(fn);
223 if (node)
224 return node->link_cnt;
[a35b458]225
[48e3190]226 return 0;
227}
228
229static bool udf_is_directory(fs_node_t *fn)
230{
231 udf_node_t *node = UDF_NODE(fn);
232 if (node)
233 return node->type == NODE_DIR;
[a35b458]234
[48e3190]235 return false;
236}
237
238static bool udf_is_file(fs_node_t *fn)
239{
240 udf_node_t *node = UDF_NODE(fn);
241 if (node)
242 return node->type == NODE_FILE;
[a35b458]243
[48e3190]244 return false;
245}
246
[b7fd2a0]247static errno_t udf_size_block(service_id_t service_id, uint32_t *size)
[52ff62d3]248{
249 udf_instance_t *instance;
[b7fd2a0]250 errno_t rc = fs_instance_get(service_id, (void **) &instance);
[52ff62d3]251 if (rc != EOK)
252 return rc;
253
254 if (NULL == instance)
255 return ENOENT;
[a35b458]256
[3dd148d]257 *size = instance->volumes[DEFAULT_VOL].logical_block_size;
[a35b458]258
[3dd148d]259 return EOK;
[52ff62d3]260}
261
[b7fd2a0]262static errno_t udf_total_block_count(service_id_t service_id, uint64_t *count)
[781408e]263{
264 *count = 0;
[a35b458]265
[781408e]266 return EOK;
267}
268
[b7fd2a0]269static errno_t udf_free_block_count(service_id_t service_id, uint64_t *count)
[781408e]270{
271 *count = 0;
[a35b458]272
[781408e]273 return EOK;
274}
275
[48e3190]276libfs_ops_t udf_libfs_ops = {
277 .root_get = udf_root_get,
278 .match = udf_match,
279 .node_get = udf_node_get,
280 .node_open = udf_node_open,
281 .node_put = udf_node_put,
282 .create = udf_create_node,
283 .destroy = udf_destroy_node,
284 .link = udf_link,
285 .unlink = udf_unlink,
286 .has_children = udf_has_children,
287 .index_get = udf_index_get,
288 .size_get = udf_size_get,
289 .lnkcnt_get = udf_lnkcnt_get,
290 .is_directory = udf_is_directory,
291 .is_file = udf_is_file,
[52ff62d3]292 .service_get = udf_service_get,
[781408e]293 .size_block = udf_size_block,
294 .total_block_count = udf_total_block_count,
295 .free_block_count = udf_free_block_count
[48e3190]296};
297
[b7fd2a0]298static errno_t udf_fsprobe(service_id_t service_id, vfs_fs_probe_info_t *info)
[d2c8533]299{
300 return ENOTSUP;
301}
302
[b7fd2a0]303static errno_t udf_mounted(service_id_t service_id, const char *opts,
[4f30222]304 fs_index_t *index, aoff64_t *size)
[48e3190]305{
306 enum cache_mode cmode;
[a35b458]307
[48e3190]308 /* Check for option enabling write through. */
309 if (str_cmp(opts, "wtcache") == 0)
310 cmode = CACHE_MODE_WT;
311 else
312 cmode = CACHE_MODE_WB;
[a35b458]313
[48e3190]314 udf_instance_t *instance = malloc(sizeof(udf_instance_t));
315 if (!instance)
316 return ENOMEM;
[a35b458]317
[48e3190]318 instance->sector_size = 0;
[a35b458]319
[48e3190]320 /* Check for block size. Will be enhanced later */
321 if (str_cmp(opts, "bs=512") == 0)
322 instance->sector_size = 512;
323 else if (str_cmp(opts, "bs=1024") == 0)
324 instance->sector_size = 1024;
325 else if (str_cmp(opts, "bs=2048") == 0)
326 instance->sector_size = 2048;
[a35b458]327
[48e3190]328 /* initialize block cache */
[b7fd2a0]329 errno_t rc = block_init(service_id, MAX_SIZE);
[44dde42]330 if (rc != EOK) {
331 free(instance);
[48e3190]332 return rc;
[44dde42]333 }
[a35b458]334
[48e3190]335 rc = fs_instance_create(service_id, instance);
336 if (rc != EOK) {
337 free(instance);
338 block_fini(service_id);
339 return rc;
340 }
[a35b458]341
[48e3190]342 instance->service_id = service_id;
343 instance->open_nodes_count = 0;
[a35b458]344
[48e3190]345 /* Check Volume Recognition Sequence */
346 rc = udf_volume_recongnition(service_id);
347 if (rc != EOK) {
[70253688]348 log_msg(LOG_DEFAULT, LVL_NOTE, "VRS failed");
[48e3190]349 fs_instance_destroy(service_id);
350 free(instance);
351 block_fini(service_id);
352 return rc;
353 }
[a35b458]354
[48e3190]355 /* Search for Anchor Volume Descriptor */
356 udf_anchor_volume_descriptor_t avd;
357 rc = udf_get_anchor_volume_descriptor(service_id, &avd);
358 if (rc != EOK) {
[70253688]359 log_msg(LOG_DEFAULT, LVL_NOTE, "Anchor read failed");
[48e3190]360 fs_instance_destroy(service_id);
361 free(instance);
362 block_fini(service_id);
363 return rc;
364 }
[a35b458]365
[70253688]366 log_msg(LOG_DEFAULT, LVL_DEBUG,
[48e3190]367 "Volume: Anchor volume descriptor found. Sector size=%" PRIu32,
368 instance->sector_size);
[70253688]369 log_msg(LOG_DEFAULT, LVL_DEBUG,
[48e3190]370 "Anchor: main sequence [length=%" PRIu32 " (bytes), start=%"
371 PRIu32 " (sector)]", avd.main_extent.length,
372 avd.main_extent.location);
[70253688]373 log_msg(LOG_DEFAULT, LVL_DEBUG,
[48e3190]374 "Anchor: reserve sequence [length=%" PRIu32 " (bytes), start=%"
375 PRIu32 " (sector)]", avd.reserve_extent.length,
376 avd.reserve_extent.location);
[a35b458]377
[48e3190]378 /* Initialize the block cache */
379 rc = block_cache_init(service_id, instance->sector_size, 0, cmode);
380 if (rc != EOK) {
381 fs_instance_destroy(service_id);
382 free(instance);
383 block_fini(service_id);
384 return rc;
385 }
[a35b458]386
[48e3190]387 /* Read Volume Descriptor Sequence */
388 rc = udf_read_volume_descriptor_sequence(service_id, avd.main_extent);
389 if (rc != EOK) {
[70253688]390 log_msg(LOG_DEFAULT, LVL_NOTE, "Volume Descriptor Sequence read failed");
[48e3190]391 fs_instance_destroy(service_id);
392 free(instance);
393 block_cache_fini(service_id);
394 block_fini(service_id);
395 return rc;
396 }
[a35b458]397
[48e3190]398 fs_node_t *rfn;
399 rc = udf_node_get(&rfn, service_id, instance->volumes[DEFAULT_VOL].root_dir);
400 if (rc != EOK) {
[70253688]401 log_msg(LOG_DEFAULT, LVL_NOTE, "Can't create root node");
[48e3190]402 fs_instance_destroy(service_id);
403 free(instance);
404 block_cache_fini(service_id);
405 block_fini(service_id);
406 return rc;
407 }
[a35b458]408
[48e3190]409 udf_node_t *node = UDF_NODE(rfn);
410 *index = instance->volumes[DEFAULT_VOL].root_dir;
411 *size = node->data_size;
[a35b458]412
[48e3190]413 return EOK;
414}
415
[b7fd2a0]416static errno_t udf_unmounted(service_id_t service_id)
[48e3190]417{
418 fs_node_t *fn;
[b7fd2a0]419 errno_t rc = udf_root_get(&fn, service_id);
[48e3190]420 if (rc != EOK)
421 return rc;
[a35b458]422
[48e3190]423 udf_node_t *nodep = UDF_NODE(fn);
424 udf_instance_t *instance = nodep->instance;
[a35b458]425
[48e3190]426 /*
427 * We expect exactly two references on the root node.
428 * One for the udf_root_get() above and one created in
429 * udf_mounted().
430 */
431 if (nodep->ref_cnt != 2) {
432 udf_node_put(fn);
433 return EBUSY;
434 }
[a35b458]435
[48e3190]436 /*
437 * Put the root node twice.
438 */
439 udf_node_put(fn);
440 udf_node_put(fn);
[a35b458]441
[48e3190]442 fs_instance_destroy(service_id);
443 free(instance);
444 block_cache_fini(service_id);
445 block_fini(service_id);
[a35b458]446
[48e3190]447 return EOK;
448}
449
[b7fd2a0]450static errno_t udf_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
[48e3190]451 size_t *rbytes)
452{
453 udf_instance_t *instance;
[b7fd2a0]454 errno_t rc = fs_instance_get(service_id, (void **) &instance);
[48e3190]455 if (rc != EOK)
456 return rc;
[a35b458]457
[48e3190]458 fs_node_t *rfn;
459 rc = udf_node_get(&rfn, service_id, index);
460 if (rc != EOK)
461 return rc;
[a35b458]462
[48e3190]463 udf_node_t *node = UDF_NODE(rfn);
[a35b458]464
[984a9ba]465 ipc_call_t call;
[48e3190]466 size_t len = 0;
[984a9ba]467 if (!async_data_read_receive(&call, &len)) {
468 async_answer_0(&call, EINVAL);
[48e3190]469 udf_node_put(rfn);
470 return EINVAL;
471 }
[a35b458]472
[48e3190]473 if (node->type == NODE_FILE) {
474 if (pos >= node->data_size) {
475 *rbytes = 0;
[984a9ba]476 async_data_read_finalize(&call, NULL, 0);
[48e3190]477 udf_node_put(rfn);
478 return EOK;
479 }
[a35b458]480
[48e3190]481 size_t read_len = 0;
482 if (node->data == NULL)
[984a9ba]483 rc = udf_read_file(&read_len, &call, node, pos, len);
[48e3190]484 else {
485 /* File in allocation descriptors area */
486 read_len = (len < node->data_size) ? len : node->data_size;
[984a9ba]487 async_data_read_finalize(&call, node->data + pos, read_len);
[48e3190]488 rc = EOK;
489 }
[a35b458]490
[48e3190]491 *rbytes = read_len;
492 (void) udf_node_put(rfn);
493 return rc;
494 } else {
495 block_t *block = NULL;
496 udf_file_identifier_descriptor_t *fid = NULL;
497 if (udf_get_fid(&fid, &block, node, pos) == EOK) {
498 char *name = malloc(MAX_FILE_NAME_LEN + 1);
[a35b458]499
[48e3190]500 // FIXME: Check for NULL return value
[a35b458]501
[48e3190]502 udf_to_unix_name(name, MAX_FILE_NAME_LEN,
[c477c80]503 (char *) fid->implementation_use + FLE16(fid->length_iu),
504 fid->length_file_id, &node->instance->charset);
[a35b458]505
[984a9ba]506 async_data_read_finalize(&call, name, str_size(name) + 1);
[48e3190]507 *rbytes = 1;
508 free(name);
509 udf_node_put(rfn);
[a35b458]510
[48e3190]511 if (block != NULL)
512 return block_put(block);
[a35b458]513
[48e3190]514 return EOK;
515 } else {
516 *rbytes = 0;
517 udf_node_put(rfn);
[984a9ba]518 async_answer_0(&call, ENOENT);
[48e3190]519 return ENOENT;
520 }
521 }
522}
523
[b7fd2a0]524static errno_t udf_close(service_id_t service_id, fs_index_t index)
[48e3190]525{
526 return EOK;
527}
528
[b7fd2a0]529static errno_t udf_sync(service_id_t service_id, fs_index_t index)
[48e3190]530{
531 return ENOTSUP;
532}
533
[b7fd2a0]534static errno_t udf_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
[48e3190]535 size_t *wbytes, aoff64_t *nsize)
536{
537 return ENOTSUP;
538}
539
[b7fd2a0]540static errno_t udf_truncate(service_id_t service_id, fs_index_t index,
[48e3190]541 aoff64_t size)
542{
543 return ENOTSUP;
544}
545
[b7fd2a0]546static errno_t udf_destroy(service_id_t service_id, fs_index_t index)
[48e3190]547{
548 return ENOTSUP;
549}
550
551vfs_out_ops_t udf_ops = {
[d2c8533]552 .fsprobe = udf_fsprobe,
[48e3190]553 .mounted = udf_mounted,
554 .unmounted = udf_unmounted,
555 .read = udf_read,
556 .write = udf_write,
557 .truncate = udf_truncate,
558 .close = udf_close,
559 .destroy = udf_destroy,
560 .sync = udf_sync
561};
562
563/**
564 * @}
565 */
Note: See TracBrowser for help on using the repository browser.