source: mainline/uspace/srv/fs/udf/udf_ops.c

Last change on this file was 7ae01d5, checked in by Jiri Svoboda <jiri@…>, 14 months ago

Remove unused comm_size parameter of block_init()

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