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