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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d4f9a2a was c477c80, checked in by Jiri Svoboda <jiri@…>, 6 years ago

Fix some common misspellings

  • 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
[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/** 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,
[c477c80]130 (char *) fid->implementation_use + FLE16(fid->length_iu),
131 fid->length_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,
[c477c80]504 (char *) fid->implementation_use + FLE16(fid->length_iu),
505 fid->length_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.