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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1a37496 was 8fdab9e, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Remove unused variable

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