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

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