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
Line 
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>
53#include <stdlib.h>
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
70static errno_t udf_node_get(fs_node_t **rfn, service_id_t service_id,
71 fs_index_t index)
72{
73 udf_instance_t *instance;
74 errno_t rc = fs_instance_get(service_id, (void **) &instance);
75 if (rc != EOK)
76 return rc;
77
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;
84
85 rc = udf_node_get_core(node);
86 if (rc != EOK) {
87 udf_idx_del(node);
88 return rc;
89 }
90 }
91
92 *rfn = FS_NODE(node);
93 return EOK;
94}
95
96static errno_t udf_root_get(fs_node_t **rfn, service_id_t service_id)
97{
98 udf_instance_t *instance;
99 errno_t rc = fs_instance_get(service_id, (void **) &instance);
100 if (rc != EOK)
101 return rc;
102
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;
112
113 return 0;
114}
115
116static errno_t udf_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
117{
118 char *name = malloc(MAX_FILE_NAME_LEN + 1);
119 if (name == NULL)
120 return ENOMEM;
121
122 block_t *block = NULL;
123 udf_file_identifier_descriptor_t *fid = NULL;
124 size_t pos = 0;
125
126 while (udf_get_fid(&fid, &block, UDF_NODE(pfn), pos) == EOK) {
127 udf_long_ad_t long_ad = fid->icb;
128
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);
132
133 if (str_casecmp(name, component) == 0) {
134 errno_t rc = udf_node_get(rfn, udf_service_get(pfn),
135 udf_long_ad_to_pos(UDF_NODE(pfn)->instance, &long_ad));
136
137 if (block != NULL)
138 block_put(block);
139
140 free(name);
141 return rc;
142 }
143
144 if (block != NULL) {
145 errno_t rc = block_put(block);
146 if (rc != EOK)
147 return rc;
148 }
149
150 pos++;
151 }
152
153 free(name);
154 return ENOENT;
155}
156
157static errno_t udf_node_open(fs_node_t *fn)
158{
159 return EOK;
160}
161
162static errno_t udf_node_put(fs_node_t *fn)
163{
164 udf_node_t *node = UDF_NODE(fn);
165 if (!node)
166 return EINVAL;
167
168 fibril_mutex_lock(&node->lock);
169 node->ref_cnt--;
170 fibril_mutex_unlock(&node->lock);
171
172 /* Delete node from hash table and memory */
173 if (!node->ref_cnt)
174 udf_idx_del(node);
175
176 return EOK;
177}
178
179static errno_t udf_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
180{
181 return ENOTSUP;
182}
183
184static errno_t udf_destroy_node(fs_node_t *fn)
185{
186 return ENOTSUP;
187}
188
189static errno_t udf_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
190{
191 return ENOTSUP;
192}
193
194static errno_t udf_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
195{
196 return ENOTSUP;
197}
198
199static errno_t udf_has_children(bool *has_children, fs_node_t *fn)
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;
210
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;
219
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;
228
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;
237
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;
246
247 return false;
248}
249
250static errno_t udf_size_block(service_id_t service_id, uint32_t *size)
251{
252 udf_instance_t *instance;
253 errno_t rc = fs_instance_get(service_id, (void **) &instance);
254 if (rc != EOK)
255 return rc;
256
257 if (NULL == instance)
258 return ENOENT;
259
260 *size = instance->volumes[DEFAULT_VOL].logical_block_size;
261
262 return EOK;
263}
264
265static errno_t udf_total_block_count(service_id_t service_id, uint64_t *count)
266{
267 *count = 0;
268
269 return EOK;
270}
271
272static errno_t udf_free_block_count(service_id_t service_id, uint64_t *count)
273{
274 *count = 0;
275
276 return EOK;
277}
278
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,
295 .service_get = udf_service_get,
296 .size_block = udf_size_block,
297 .total_block_count = udf_total_block_count,
298 .free_block_count = udf_free_block_count
299};
300
301static errno_t udf_fsprobe(service_id_t service_id, vfs_fs_probe_info_t *info)
302{
303 return ENOTSUP;
304}
305
306static errno_t udf_mounted(service_id_t service_id, const char *opts,
307 fs_index_t *index, aoff64_t *size)
308{
309 enum cache_mode cmode;
310
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;
316
317 udf_instance_t *instance = malloc(sizeof(udf_instance_t));
318 if (!instance)
319 return ENOMEM;
320
321 instance->sector_size = 0;
322
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;
330
331 /* initialize block cache */
332 errno_t rc = block_init(service_id, MAX_SIZE);
333 if (rc != EOK)
334 return rc;
335
336 rc = fs_instance_create(service_id, instance);
337 if (rc != EOK) {
338 free(instance);
339 block_fini(service_id);
340 return rc;
341 }
342
343 instance->service_id = service_id;
344 instance->open_nodes_count = 0;
345
346 /* Check Volume Recognition Sequence */
347 rc = udf_volume_recongnition(service_id);
348 if (rc != EOK) {
349 log_msg(LOG_DEFAULT, LVL_NOTE, "VRS failed");
350 fs_instance_destroy(service_id);
351 free(instance);
352 block_fini(service_id);
353 return rc;
354 }
355
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) {
360 log_msg(LOG_DEFAULT, LVL_NOTE, "Anchor read failed");
361 fs_instance_destroy(service_id);
362 free(instance);
363 block_fini(service_id);
364 return rc;
365 }
366
367 log_msg(LOG_DEFAULT, LVL_DEBUG,
368 "Volume: Anchor volume descriptor found. Sector size=%" PRIu32,
369 instance->sector_size);
370 log_msg(LOG_DEFAULT, LVL_DEBUG,
371 "Anchor: main sequence [length=%" PRIu32 " (bytes), start=%"
372 PRIu32 " (sector)]", avd.main_extent.length,
373 avd.main_extent.location);
374 log_msg(LOG_DEFAULT, LVL_DEBUG,
375 "Anchor: reserve sequence [length=%" PRIu32 " (bytes), start=%"
376 PRIu32 " (sector)]", avd.reserve_extent.length,
377 avd.reserve_extent.location);
378
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 }
387
388 /* Read Volume Descriptor Sequence */
389 rc = udf_read_volume_descriptor_sequence(service_id, avd.main_extent);
390 if (rc != EOK) {
391 log_msg(LOG_DEFAULT, LVL_NOTE, "Volume Descriptor Sequence read failed");
392 fs_instance_destroy(service_id);
393 free(instance);
394 block_cache_fini(service_id);
395 block_fini(service_id);
396 return rc;
397 }
398
399 fs_node_t *rfn;
400 rc = udf_node_get(&rfn, service_id, instance->volumes[DEFAULT_VOL].root_dir);
401 if (rc != EOK) {
402 log_msg(LOG_DEFAULT, LVL_NOTE, "Can't create root node");
403 fs_instance_destroy(service_id);
404 free(instance);
405 block_cache_fini(service_id);
406 block_fini(service_id);
407 return rc;
408 }
409
410 udf_node_t *node = UDF_NODE(rfn);
411 *index = instance->volumes[DEFAULT_VOL].root_dir;
412 *size = node->data_size;
413
414 return EOK;
415}
416
417static errno_t udf_unmounted(service_id_t service_id)
418{
419 fs_node_t *fn;
420 errno_t rc = udf_root_get(&fn, service_id);
421 if (rc != EOK)
422 return rc;
423
424 udf_node_t *nodep = UDF_NODE(fn);
425 udf_instance_t *instance = nodep->instance;
426
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 }
436
437 /*
438 * Put the root node twice.
439 */
440 udf_node_put(fn);
441 udf_node_put(fn);
442
443 fs_instance_destroy(service_id);
444 free(instance);
445 block_cache_fini(service_id);
446 block_fini(service_id);
447
448 return EOK;
449}
450
451static errno_t udf_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
452 size_t *rbytes)
453{
454 udf_instance_t *instance;
455 errno_t rc = fs_instance_get(service_id, (void **) &instance);
456 if (rc != EOK)
457 return rc;
458
459 fs_node_t *rfn;
460 rc = udf_node_get(&rfn, service_id, index);
461 if (rc != EOK)
462 return rc;
463
464 udf_node_t *node = UDF_NODE(rfn);
465
466 ipc_call_t call;
467 size_t len = 0;
468 if (!async_data_read_receive(&call, &len)) {
469 async_answer_0(&call, EINVAL);
470 udf_node_put(rfn);
471 return EINVAL;
472 }
473
474 if (node->type == NODE_FILE) {
475 if (pos >= node->data_size) {
476 *rbytes = 0;
477 async_data_read_finalize(&call, NULL, 0);
478 udf_node_put(rfn);
479 return EOK;
480 }
481
482 size_t read_len = 0;
483 if (node->data == NULL)
484 rc = udf_read_file(&read_len, &call, node, pos, len);
485 else {
486 /* File in allocation descriptors area */
487 read_len = (len < node->data_size) ? len : node->data_size;
488 async_data_read_finalize(&call, node->data + pos, read_len);
489 rc = EOK;
490 }
491
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);
500
501 // FIXME: Check for NULL return value
502
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);
506
507 async_data_read_finalize(&call, name, str_size(name) + 1);
508 *rbytes = 1;
509 free(name);
510 udf_node_put(rfn);
511
512 if (block != NULL)
513 return block_put(block);
514
515 return EOK;
516 } else {
517 *rbytes = 0;
518 udf_node_put(rfn);
519 async_answer_0(&call, ENOENT);
520 return ENOENT;
521 }
522 }
523}
524
525static errno_t udf_close(service_id_t service_id, fs_index_t index)
526{
527 return EOK;
528}
529
530static errno_t udf_sync(service_id_t service_id, fs_index_t index)
531{
532 return ENOTSUP;
533}
534
535static errno_t udf_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
536 size_t *wbytes, aoff64_t *nsize)
537{
538 return ENOTSUP;
539}
540
541static errno_t udf_truncate(service_id_t service_id, fs_index_t index,
542 aoff64_t size)
543{
544 return ENOTSUP;
545}
546
547static errno_t udf_destroy(service_id_t service_id, fs_index_t index)
548{
549 return ENOTSUP;
550}
551
552vfs_out_ops_t udf_ops = {
553 .fsprobe = udf_fsprobe,
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.