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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 582a0b8 was fc22069, checked in by Martin Decky <martin@…>, 10 years ago

block devices use the same interface, therefore the API of libblock should not expose the implementation details

  • Property mode set to 100644
File size: 12.7 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 fs
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 <malloc.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 int udf_node_get(fs_node_t **rfn, service_id_t service_id,
71 fs_index_t index)
72{
73 udf_instance_t *instance;
74 int 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 int udf_root_get(fs_node_t **rfn, service_id_t service_id)
97{
98 udf_instance_t *instance;
99 int 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 int 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->lenght_iu),
131 fid->lenght_file_id, &UDF_NODE(pfn)->instance->charset);
132
133 if (stricmp(name, component) == 0) {
134 int 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 int 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 int udf_node_open(fs_node_t *fn)
158{
159 return EOK;
160}
161
162static int 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 int udf_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
180{
181 return ENOTSUP;
182}
183
184static int udf_destroy_node(fs_node_t *fn)
185{
186 return ENOTSUP;
187}
188
189static int udf_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
190{
191 return ENOTSUP;
192}
193
194static int udf_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
195{
196 return ENOTSUP;
197}
198
199static int 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 int udf_size_block(service_id_t service_id, uint32_t *size)
251{
252 udf_instance_t *instance;
253 int 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 int udf_total_block_count(service_id_t service_id, uint64_t *count)
266{
267 *count = 0;
268
269 return EOK;
270}
271
272static int 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 int udf_mounted(service_id_t service_id, const char *opts,
302 fs_index_t *index, aoff64_t *size, unsigned *linkcnt)
303{
304 enum cache_mode cmode;
305
306 /* Check for option enabling write through. */
307 if (str_cmp(opts, "wtcache") == 0)
308 cmode = CACHE_MODE_WT;
309 else
310 cmode = CACHE_MODE_WB;
311
312 udf_instance_t *instance = malloc(sizeof(udf_instance_t));
313 if (!instance)
314 return ENOMEM;
315
316 instance->sector_size = 0;
317
318 /* Check for block size. Will be enhanced later */
319 if (str_cmp(opts, "bs=512") == 0)
320 instance->sector_size = 512;
321 else if (str_cmp(opts, "bs=1024") == 0)
322 instance->sector_size = 1024;
323 else if (str_cmp(opts, "bs=2048") == 0)
324 instance->sector_size = 2048;
325
326 /* initialize block cache */
327 int rc = block_init(service_id, MAX_SIZE);
328 if (rc != EOK)
329 return rc;
330
331 rc = fs_instance_create(service_id, instance);
332 if (rc != EOK) {
333 free(instance);
334 block_fini(service_id);
335 return rc;
336 }
337
338 instance->service_id = service_id;
339 instance->open_nodes_count = 0;
340
341 /* Check Volume Recognition Sequence */
342 rc = udf_volume_recongnition(service_id);
343 if (rc != EOK) {
344 log_msg(LOG_DEFAULT, LVL_NOTE, "VRS failed");
345 fs_instance_destroy(service_id);
346 free(instance);
347 block_fini(service_id);
348 return rc;
349 }
350
351 /* Search for Anchor Volume Descriptor */
352 udf_anchor_volume_descriptor_t avd;
353 rc = udf_get_anchor_volume_descriptor(service_id, &avd);
354 if (rc != EOK) {
355 log_msg(LOG_DEFAULT, LVL_NOTE, "Anchor read failed");
356 fs_instance_destroy(service_id);
357 free(instance);
358 block_fini(service_id);
359 return rc;
360 }
361
362 log_msg(LOG_DEFAULT, LVL_DEBUG,
363 "Volume: Anchor volume descriptor found. Sector size=%" PRIu32,
364 instance->sector_size);
365 log_msg(LOG_DEFAULT, LVL_DEBUG,
366 "Anchor: main sequence [length=%" PRIu32 " (bytes), start=%"
367 PRIu32 " (sector)]", avd.main_extent.length,
368 avd.main_extent.location);
369 log_msg(LOG_DEFAULT, LVL_DEBUG,
370 "Anchor: reserve sequence [length=%" PRIu32 " (bytes), start=%"
371 PRIu32 " (sector)]", avd.reserve_extent.length,
372 avd.reserve_extent.location);
373
374 /* Initialize the block cache */
375 rc = block_cache_init(service_id, instance->sector_size, 0, cmode);
376 if (rc != EOK) {
377 fs_instance_destroy(service_id);
378 free(instance);
379 block_fini(service_id);
380 return rc;
381 }
382
383 /* Read Volume Descriptor Sequence */
384 rc = udf_read_volume_descriptor_sequence(service_id, avd.main_extent);
385 if (rc != EOK) {
386 log_msg(LOG_DEFAULT, LVL_NOTE, "Volume Descriptor Sequence read failed");
387 fs_instance_destroy(service_id);
388 free(instance);
389 block_cache_fini(service_id);
390 block_fini(service_id);
391 return rc;
392 }
393
394 fs_node_t *rfn;
395 rc = udf_node_get(&rfn, service_id, instance->volumes[DEFAULT_VOL].root_dir);
396 if (rc != EOK) {
397 log_msg(LOG_DEFAULT, LVL_NOTE, "Can't create root node");
398 fs_instance_destroy(service_id);
399 free(instance);
400 block_cache_fini(service_id);
401 block_fini(service_id);
402 return rc;
403 }
404
405 udf_node_t *node = UDF_NODE(rfn);
406 *index = instance->volumes[DEFAULT_VOL].root_dir;
407 *size = node->data_size;
408 *linkcnt = node->link_cnt;
409
410 return EOK;
411}
412
413static int udf_unmounted(service_id_t service_id)
414{
415 fs_node_t *fn;
416 int 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 int 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 int 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_callid_t callid;
463 size_t len = 0;
464 if (!async_data_read_receive(&callid, &len)) {
465 async_answer_0(callid, 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(callid, 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, callid, 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(callid, 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->lenght_iu),
501 fid->lenght_file_id, &node->instance->charset);
502
503 async_data_read_finalize(callid, 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(callid, ENOENT);
516 return ENOENT;
517 }
518 }
519}
520
521static int udf_close(service_id_t service_id, fs_index_t index)
522{
523 return EOK;
524}
525
526static int udf_sync(service_id_t service_id, fs_index_t index)
527{
528 return ENOTSUP;
529}
530
531static int 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 int udf_truncate(service_id_t service_id, fs_index_t index,
538 aoff64_t size)
539{
540 return ENOTSUP;
541}
542
543static int udf_destroy(service_id_t service_id, fs_index_t index)
544{
545 return ENOTSUP;
546}
547
548vfs_out_ops_t udf_ops = {
549 .mounted = udf_mounted,
550 .unmounted = udf_unmounted,
551 .read = udf_read,
552 .write = udf_write,
553 .truncate = udf_truncate,
554 .close = udf_close,
555 .destroy = udf_destroy,
556 .sync = udf_sync
557};
558
559/**
560 * @}
561 */
Note: See TracBrowser for help on using the repository browser.