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
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_bytes(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.