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

Last change on this file since 08e103d4 was 08e103d4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use clearer naming for string length functions

This and the following commit change the names of functions, as well as
their documentation, to use unambiguous terms "bytes" and "code points"
instead of ambiguous terms "size", "length", and "characters".

  • 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
[08e103d4]504 async_data_read_finalize(&call, name, str_bytes(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.