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

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