source: mainline/uspace/srv/fs/udf/udf_ops.c@ 2eadda9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2eadda9 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: 12.8 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
30/** @addtogroup fs
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/** Mutex protecting the list of cached free nodes. */
65static FIBRIL_MUTEX_INITIALIZE(ffn_mutex);
66
67/** List of cached free nodes. */
68static LIST_INITIALIZE(ffn_list);
69
[b7fd2a0]70static errno_t udf_node_get(fs_node_t **rfn, service_id_t service_id,
[48e3190]71 fs_index_t index)
72{
73 udf_instance_t *instance;
[b7fd2a0]74 errno_t rc = fs_instance_get(service_id, (void **) &instance);
[48e3190]75 if (rc != EOK)
76 return rc;
[a35b458]77
[48e3190]78 udf_node_t *node;
79 rc = udf_idx_get(&node, instance, index);
80 if (rc != EOK) {
81 rc = udf_idx_add(&node, instance, index);
82 if (rc != EOK)
83 return rc;
[a35b458]84
[48e3190]85 rc = udf_node_get_core(node);
86 if (rc != EOK) {
87 udf_idx_del(node);
88 return rc;
89 }
90 }
[a35b458]91
[48e3190]92 *rfn = FS_NODE(node);
93 return EOK;
94}
95
[b7fd2a0]96static errno_t udf_root_get(fs_node_t **rfn, service_id_t service_id)
[48e3190]97{
98 udf_instance_t *instance;
[b7fd2a0]99 errno_t rc = fs_instance_get(service_id, (void **) &instance);
[48e3190]100 if (rc != EOK)
101 return rc;
[a35b458]102
[48e3190]103 return udf_node_get(rfn, service_id,
104 instance->volumes[DEFAULT_VOL].root_dir);
105}
106
107static service_id_t udf_service_get(fs_node_t *node)
108{
109 udf_node_t *udfn = UDF_NODE(node);
110 if (udfn)
111 return udfn->instance->service_id;
[a35b458]112
[48e3190]113 return 0;
114}
115
[b7fd2a0]116static errno_t udf_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
[48e3190]117{
118 char *name = malloc(MAX_FILE_NAME_LEN + 1);
119 if (name == NULL)
120 return ENOMEM;
[a35b458]121
[48e3190]122 block_t *block = NULL;
123 udf_file_identifier_descriptor_t *fid = NULL;
124 size_t pos = 0;
[a35b458]125
[48e3190]126 while (udf_get_fid(&fid, &block, UDF_NODE(pfn), pos) == EOK) {
127 udf_long_ad_t long_ad = fid->icb;
[a35b458]128
[48e3190]129 udf_to_unix_name(name, MAX_FILE_NAME_LEN,
130 (char *) fid->implementation_use + FLE16(fid->lenght_iu),
131 fid->lenght_file_id, &UDF_NODE(pfn)->instance->charset);
[a35b458]132
[0e7c3d9]133 if (str_casecmp(name, component) == 0) {
[b7fd2a0]134 errno_t rc = udf_node_get(rfn, udf_service_get(pfn),
[48e3190]135 udf_long_ad_to_pos(UDF_NODE(pfn)->instance, &long_ad));
[a35b458]136
[48e3190]137 if (block != NULL)
138 block_put(block);
[a35b458]139
[48e3190]140 free(name);
141 return rc;
142 }
[a35b458]143
[48e3190]144 if (block != NULL) {
[b7fd2a0]145 errno_t rc = block_put(block);
[48e3190]146 if (rc != EOK)
147 return rc;
148 }
[a35b458]149
[48e3190]150 pos++;
151 }
[a35b458]152
[48e3190]153 free(name);
154 return ENOENT;
155}
156
[b7fd2a0]157static errno_t udf_node_open(fs_node_t *fn)
[48e3190]158{
159 return EOK;
160}
161
[b7fd2a0]162static errno_t udf_node_put(fs_node_t *fn)
[48e3190]163{
164 udf_node_t *node = UDF_NODE(fn);
165 if (!node)
166 return EINVAL;
[a35b458]167
[48e3190]168 fibril_mutex_lock(&node->lock);
169 node->ref_cnt--;
170 fibril_mutex_unlock(&node->lock);
[a35b458]171
[48e3190]172 /* Delete node from hash table and memory */
173 if (!node->ref_cnt)
174 udf_idx_del(node);
[a35b458]175
[48e3190]176 return EOK;
177}
178
[b7fd2a0]179static errno_t udf_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
[48e3190]180{
181 return ENOTSUP;
182}
183
[b7fd2a0]184static errno_t udf_destroy_node(fs_node_t *fn)
[48e3190]185{
186 return ENOTSUP;
187}
188
[b7fd2a0]189static errno_t udf_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
[48e3190]190{
191 return ENOTSUP;
192}
193
[b7fd2a0]194static errno_t udf_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
[48e3190]195{
196 return ENOTSUP;
197}
198
[b7fd2a0]199static errno_t udf_has_children(bool *has_children, fs_node_t *fn)
[48e3190]200{
201 *has_children = true;
202 return EOK;
203}
204
205static fs_index_t udf_index_get(fs_node_t *fn)
206{
207 udf_node_t *node = UDF_NODE(fn);
208 if (node)
209 return node->index;
[a35b458]210
[48e3190]211 return 0;
212}
213
214static aoff64_t udf_size_get(fs_node_t *fn)
215{
216 udf_node_t *node = UDF_NODE(fn);
217 if (node)
218 return node->data_size;
[a35b458]219
[48e3190]220 return 0;
221}
222
223static unsigned int udf_lnkcnt_get(fs_node_t *fn)
224{
225 udf_node_t *node = UDF_NODE(fn);
226 if (node)
227 return node->link_cnt;
[a35b458]228
[48e3190]229 return 0;
230}
231
232static bool udf_is_directory(fs_node_t *fn)
233{
234 udf_node_t *node = UDF_NODE(fn);
235 if (node)
236 return node->type == NODE_DIR;
[a35b458]237
[48e3190]238 return false;
239}
240
241static bool udf_is_file(fs_node_t *fn)
242{
243 udf_node_t *node = UDF_NODE(fn);
244 if (node)
245 return node->type == NODE_FILE;
[a35b458]246
[48e3190]247 return false;
248}
249
[b7fd2a0]250static errno_t udf_size_block(service_id_t service_id, uint32_t *size)
[52ff62d3]251{
252 udf_instance_t *instance;
[b7fd2a0]253 errno_t rc = fs_instance_get(service_id, (void **) &instance);
[52ff62d3]254 if (rc != EOK)
255 return rc;
256
257 if (NULL == instance)
258 return ENOENT;
[a35b458]259
[3dd148d]260 *size = instance->volumes[DEFAULT_VOL].logical_block_size;
[a35b458]261
[3dd148d]262 return EOK;
[52ff62d3]263}
264
[b7fd2a0]265static errno_t udf_total_block_count(service_id_t service_id, uint64_t *count)
[781408e]266{
267 *count = 0;
[a35b458]268
[781408e]269 return EOK;
270}
271
[b7fd2a0]272static errno_t udf_free_block_count(service_id_t service_id, uint64_t *count)
[781408e]273{
274 *count = 0;
[a35b458]275
[781408e]276 return EOK;
277}
278
[48e3190]279libfs_ops_t udf_libfs_ops = {
280 .root_get = udf_root_get,
281 .match = udf_match,
282 .node_get = udf_node_get,
283 .node_open = udf_node_open,
284 .node_put = udf_node_put,
285 .create = udf_create_node,
286 .destroy = udf_destroy_node,
287 .link = udf_link,
288 .unlink = udf_unlink,
289 .has_children = udf_has_children,
290 .index_get = udf_index_get,
291 .size_get = udf_size_get,
292 .lnkcnt_get = udf_lnkcnt_get,
293 .is_directory = udf_is_directory,
294 .is_file = udf_is_file,
[52ff62d3]295 .service_get = udf_service_get,
[781408e]296 .size_block = udf_size_block,
297 .total_block_count = udf_total_block_count,
298 .free_block_count = udf_free_block_count
[48e3190]299};
300
[b7fd2a0]301static errno_t udf_fsprobe(service_id_t service_id, vfs_fs_probe_info_t *info)
[d2c8533]302{
303 return ENOTSUP;
304}
305
[b7fd2a0]306static errno_t udf_mounted(service_id_t service_id, const char *opts,
[4f30222]307 fs_index_t *index, aoff64_t *size)
[48e3190]308{
309 enum cache_mode cmode;
[a35b458]310
[48e3190]311 /* Check for option enabling write through. */
312 if (str_cmp(opts, "wtcache") == 0)
313 cmode = CACHE_MODE_WT;
314 else
315 cmode = CACHE_MODE_WB;
[a35b458]316
[48e3190]317 udf_instance_t *instance = malloc(sizeof(udf_instance_t));
318 if (!instance)
319 return ENOMEM;
[a35b458]320
[48e3190]321 instance->sector_size = 0;
[a35b458]322
[48e3190]323 /* Check for block size. Will be enhanced later */
324 if (str_cmp(opts, "bs=512") == 0)
325 instance->sector_size = 512;
326 else if (str_cmp(opts, "bs=1024") == 0)
327 instance->sector_size = 1024;
328 else if (str_cmp(opts, "bs=2048") == 0)
329 instance->sector_size = 2048;
[a35b458]330
[48e3190]331 /* initialize block cache */
[b7fd2a0]332 errno_t rc = block_init(service_id, MAX_SIZE);
[48e3190]333 if (rc != EOK)
334 return rc;
[a35b458]335
[48e3190]336 rc = fs_instance_create(service_id, instance);
337 if (rc != EOK) {
338 free(instance);
339 block_fini(service_id);
340 return rc;
341 }
[a35b458]342
[48e3190]343 instance->service_id = service_id;
344 instance->open_nodes_count = 0;
[a35b458]345
[48e3190]346 /* Check Volume Recognition Sequence */
347 rc = udf_volume_recongnition(service_id);
348 if (rc != EOK) {
[70253688]349 log_msg(LOG_DEFAULT, LVL_NOTE, "VRS failed");
[48e3190]350 fs_instance_destroy(service_id);
351 free(instance);
352 block_fini(service_id);
353 return rc;
354 }
[a35b458]355
[48e3190]356 /* Search for Anchor Volume Descriptor */
357 udf_anchor_volume_descriptor_t avd;
358 rc = udf_get_anchor_volume_descriptor(service_id, &avd);
359 if (rc != EOK) {
[70253688]360 log_msg(LOG_DEFAULT, LVL_NOTE, "Anchor read failed");
[48e3190]361 fs_instance_destroy(service_id);
362 free(instance);
363 block_fini(service_id);
364 return rc;
365 }
[a35b458]366
[70253688]367 log_msg(LOG_DEFAULT, LVL_DEBUG,
[48e3190]368 "Volume: Anchor volume descriptor found. Sector size=%" PRIu32,
369 instance->sector_size);
[70253688]370 log_msg(LOG_DEFAULT, LVL_DEBUG,
[48e3190]371 "Anchor: main sequence [length=%" PRIu32 " (bytes), start=%"
372 PRIu32 " (sector)]", avd.main_extent.length,
373 avd.main_extent.location);
[70253688]374 log_msg(LOG_DEFAULT, LVL_DEBUG,
[48e3190]375 "Anchor: reserve sequence [length=%" PRIu32 " (bytes), start=%"
376 PRIu32 " (sector)]", avd.reserve_extent.length,
377 avd.reserve_extent.location);
[a35b458]378
[48e3190]379 /* Initialize the block cache */
380 rc = block_cache_init(service_id, instance->sector_size, 0, cmode);
381 if (rc != EOK) {
382 fs_instance_destroy(service_id);
383 free(instance);
384 block_fini(service_id);
385 return rc;
386 }
[a35b458]387
[48e3190]388 /* Read Volume Descriptor Sequence */
389 rc = udf_read_volume_descriptor_sequence(service_id, avd.main_extent);
390 if (rc != EOK) {
[70253688]391 log_msg(LOG_DEFAULT, LVL_NOTE, "Volume Descriptor Sequence read failed");
[48e3190]392 fs_instance_destroy(service_id);
393 free(instance);
394 block_cache_fini(service_id);
395 block_fini(service_id);
396 return rc;
397 }
[a35b458]398
[48e3190]399 fs_node_t *rfn;
400 rc = udf_node_get(&rfn, service_id, instance->volumes[DEFAULT_VOL].root_dir);
401 if (rc != EOK) {
[70253688]402 log_msg(LOG_DEFAULT, LVL_NOTE, "Can't create root node");
[48e3190]403 fs_instance_destroy(service_id);
404 free(instance);
405 block_cache_fini(service_id);
406 block_fini(service_id);
407 return rc;
408 }
[a35b458]409
[48e3190]410 udf_node_t *node = UDF_NODE(rfn);
411 *index = instance->volumes[DEFAULT_VOL].root_dir;
412 *size = node->data_size;
[a35b458]413
[48e3190]414 return EOK;
415}
416
[b7fd2a0]417static errno_t udf_unmounted(service_id_t service_id)
[48e3190]418{
419 fs_node_t *fn;
[b7fd2a0]420 errno_t rc = udf_root_get(&fn, service_id);
[48e3190]421 if (rc != EOK)
422 return rc;
[a35b458]423
[48e3190]424 udf_node_t *nodep = UDF_NODE(fn);
425 udf_instance_t *instance = nodep->instance;
[a35b458]426
[48e3190]427 /*
428 * We expect exactly two references on the root node.
429 * One for the udf_root_get() above and one created in
430 * udf_mounted().
431 */
432 if (nodep->ref_cnt != 2) {
433 udf_node_put(fn);
434 return EBUSY;
435 }
[a35b458]436
[48e3190]437 /*
438 * Put the root node twice.
439 */
440 udf_node_put(fn);
441 udf_node_put(fn);
[a35b458]442
[48e3190]443 fs_instance_destroy(service_id);
444 free(instance);
445 block_cache_fini(service_id);
446 block_fini(service_id);
[a35b458]447
[48e3190]448 return EOK;
449}
450
[b7fd2a0]451static errno_t udf_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
[48e3190]452 size_t *rbytes)
453{
454 udf_instance_t *instance;
[b7fd2a0]455 errno_t rc = fs_instance_get(service_id, (void **) &instance);
[48e3190]456 if (rc != EOK)
457 return rc;
[a35b458]458
[48e3190]459 fs_node_t *rfn;
460 rc = udf_node_get(&rfn, service_id, index);
461 if (rc != EOK)
462 return rc;
[a35b458]463
[48e3190]464 udf_node_t *node = UDF_NODE(rfn);
[a35b458]465
[984a9ba]466 ipc_call_t call;
[48e3190]467 size_t len = 0;
[984a9ba]468 if (!async_data_read_receive(&call, &len)) {
469 async_answer_0(&call, EINVAL);
[48e3190]470 udf_node_put(rfn);
471 return EINVAL;
472 }
[a35b458]473
[48e3190]474 if (node->type == NODE_FILE) {
475 if (pos >= node->data_size) {
476 *rbytes = 0;
[984a9ba]477 async_data_read_finalize(&call, NULL, 0);
[48e3190]478 udf_node_put(rfn);
479 return EOK;
480 }
[a35b458]481
[48e3190]482 size_t read_len = 0;
483 if (node->data == NULL)
[984a9ba]484 rc = udf_read_file(&read_len, &call, node, pos, len);
[48e3190]485 else {
486 /* File in allocation descriptors area */
487 read_len = (len < node->data_size) ? len : node->data_size;
[984a9ba]488 async_data_read_finalize(&call, node->data + pos, read_len);
[48e3190]489 rc = EOK;
490 }
[a35b458]491
[48e3190]492 *rbytes = read_len;
493 (void) udf_node_put(rfn);
494 return rc;
495 } else {
496 block_t *block = NULL;
497 udf_file_identifier_descriptor_t *fid = NULL;
498 if (udf_get_fid(&fid, &block, node, pos) == EOK) {
499 char *name = malloc(MAX_FILE_NAME_LEN + 1);
[a35b458]500
[48e3190]501 // FIXME: Check for NULL return value
[a35b458]502
[48e3190]503 udf_to_unix_name(name, MAX_FILE_NAME_LEN,
504 (char *) fid->implementation_use + FLE16(fid->lenght_iu),
505 fid->lenght_file_id, &node->instance->charset);
[a35b458]506
[984a9ba]507 async_data_read_finalize(&call, name, str_size(name) + 1);
[48e3190]508 *rbytes = 1;
509 free(name);
510 udf_node_put(rfn);
[a35b458]511
[48e3190]512 if (block != NULL)
513 return block_put(block);
[a35b458]514
[48e3190]515 return EOK;
516 } else {
517 *rbytes = 0;
518 udf_node_put(rfn);
[984a9ba]519 async_answer_0(&call, ENOENT);
[48e3190]520 return ENOENT;
521 }
522 }
523}
524
[b7fd2a0]525static errno_t udf_close(service_id_t service_id, fs_index_t index)
[48e3190]526{
527 return EOK;
528}
529
[b7fd2a0]530static errno_t udf_sync(service_id_t service_id, fs_index_t index)
[48e3190]531{
532 return ENOTSUP;
533}
534
[b7fd2a0]535static errno_t udf_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
[48e3190]536 size_t *wbytes, aoff64_t *nsize)
537{
538 return ENOTSUP;
539}
540
[b7fd2a0]541static errno_t udf_truncate(service_id_t service_id, fs_index_t index,
[48e3190]542 aoff64_t size)
543{
544 return ENOTSUP;
545}
546
[b7fd2a0]547static errno_t udf_destroy(service_id_t service_id, fs_index_t index)
[48e3190]548{
549 return ENOTSUP;
550}
551
552vfs_out_ops_t udf_ops = {
[d2c8533]553 .fsprobe = udf_fsprobe,
[48e3190]554 .mounted = udf_mounted,
555 .unmounted = udf_unmounted,
556 .read = udf_read,
557 .write = udf_write,
558 .truncate = udf_truncate,
559 .close = udf_close,
560 .destroy = udf_destroy,
561 .sync = udf_sync
562};
563
564/**
565 * @}
566 */
Note: See TracBrowser for help on using the repository browser.