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

Last change on this file since bdd9e92 was f783081, checked in by jxsvoboda <5887334+jxsvoboda@…>, 4 years ago

libfs's service_get() returns service ID for service-special files

Not the service ID of the owning file system. Any file-system except
locfs should return zero.

  • Property mode set to 100644
File size: 12.6 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 return 0;
107}
108
109static errno_t udf_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
110{
111 char *name = malloc(MAX_FILE_NAME_LEN + 1);
112 if (name == NULL)
113 return ENOMEM;
114
115 block_t *block = NULL;
116 udf_file_identifier_descriptor_t *fid = NULL;
117 size_t pos = 0;
118
119 while (udf_get_fid(&fid, &block, UDF_NODE(pfn), pos) == EOK) {
120 udf_long_ad_t long_ad = fid->icb;
121
122 udf_to_unix_name(name, MAX_FILE_NAME_LEN,
123 (char *) fid->implementation_use + FLE16(fid->length_iu),
124 fid->length_file_id, &UDF_NODE(pfn)->instance->charset);
125
126 if (str_casecmp(name, component) == 0) {
127 errno_t rc = udf_node_get(rfn, udf_service_get(pfn),
128 udf_long_ad_to_pos(UDF_NODE(pfn)->instance, &long_ad));
129
130 if (block != NULL)
131 block_put(block);
132
133 free(name);
134 return rc;
135 }
136
137 if (block != NULL) {
138 errno_t rc = block_put(block);
139 if (rc != EOK)
140 return rc;
141 }
142
143 pos++;
144 }
145
146 free(name);
147 return ENOENT;
148}
149
150static errno_t udf_node_open(fs_node_t *fn)
151{
152 return EOK;
153}
154
155static errno_t udf_node_put(fs_node_t *fn)
156{
157 udf_node_t *node = UDF_NODE(fn);
158 if (!node)
159 return EINVAL;
160
161 fibril_mutex_lock(&node->lock);
162 node->ref_cnt--;
163 fibril_mutex_unlock(&node->lock);
164
165 /* Delete node from hash table and memory */
166 if (!node->ref_cnt)
167 udf_idx_del(node);
168
169 return EOK;
170}
171
172static errno_t udf_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
173{
174 return ENOTSUP;
175}
176
177static errno_t udf_destroy_node(fs_node_t *fn)
178{
179 return ENOTSUP;
180}
181
182static errno_t udf_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
183{
184 return ENOTSUP;
185}
186
187static errno_t udf_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
188{
189 return ENOTSUP;
190}
191
192static errno_t udf_has_children(bool *has_children, fs_node_t *fn)
193{
194 *has_children = true;
195 return EOK;
196}
197
198static fs_index_t udf_index_get(fs_node_t *fn)
199{
200 udf_node_t *node = UDF_NODE(fn);
201 if (node)
202 return node->index;
203
204 return 0;
205}
206
207static aoff64_t udf_size_get(fs_node_t *fn)
208{
209 udf_node_t *node = UDF_NODE(fn);
210 if (node)
211 return node->data_size;
212
213 return 0;
214}
215
216static unsigned int udf_lnkcnt_get(fs_node_t *fn)
217{
218 udf_node_t *node = UDF_NODE(fn);
219 if (node)
220 return node->link_cnt;
221
222 return 0;
223}
224
225static bool udf_is_directory(fs_node_t *fn)
226{
227 udf_node_t *node = UDF_NODE(fn);
228 if (node)
229 return node->type == NODE_DIR;
230
231 return false;
232}
233
234static bool udf_is_file(fs_node_t *fn)
235{
236 udf_node_t *node = UDF_NODE(fn);
237 if (node)
238 return node->type == NODE_FILE;
239
240 return false;
241}
242
243static errno_t udf_size_block(service_id_t service_id, uint32_t *size)
244{
245 udf_instance_t *instance;
246 errno_t rc = fs_instance_get(service_id, (void **) &instance);
247 if (rc != EOK)
248 return rc;
249
250 if (NULL == instance)
251 return ENOENT;
252
253 *size = instance->volumes[DEFAULT_VOL].logical_block_size;
254
255 return EOK;
256}
257
258static errno_t udf_total_block_count(service_id_t service_id, uint64_t *count)
259{
260 *count = 0;
261
262 return EOK;
263}
264
265static errno_t udf_free_block_count(service_id_t service_id, uint64_t *count)
266{
267 *count = 0;
268
269 return EOK;
270}
271
272libfs_ops_t udf_libfs_ops = {
273 .root_get = udf_root_get,
274 .match = udf_match,
275 .node_get = udf_node_get,
276 .node_open = udf_node_open,
277 .node_put = udf_node_put,
278 .create = udf_create_node,
279 .destroy = udf_destroy_node,
280 .link = udf_link,
281 .unlink = udf_unlink,
282 .has_children = udf_has_children,
283 .index_get = udf_index_get,
284 .size_get = udf_size_get,
285 .lnkcnt_get = udf_lnkcnt_get,
286 .is_directory = udf_is_directory,
287 .is_file = udf_is_file,
288 .service_get = udf_service_get,
289 .size_block = udf_size_block,
290 .total_block_count = udf_total_block_count,
291 .free_block_count = udf_free_block_count
292};
293
294static errno_t udf_fsprobe(service_id_t service_id, vfs_fs_probe_info_t *info)
295{
296 return ENOTSUP;
297}
298
299static errno_t udf_mounted(service_id_t service_id, const char *opts,
300 fs_index_t *index, aoff64_t *size)
301{
302 enum cache_mode cmode;
303
304 /* Check for option enabling write through. */
305 if (str_cmp(opts, "wtcache") == 0)
306 cmode = CACHE_MODE_WT;
307 else
308 cmode = CACHE_MODE_WB;
309
310 udf_instance_t *instance = malloc(sizeof(udf_instance_t));
311 if (!instance)
312 return ENOMEM;
313
314 instance->sector_size = 0;
315
316 /* Check for block size. Will be enhanced later */
317 if (str_cmp(opts, "bs=512") == 0)
318 instance->sector_size = 512;
319 else if (str_cmp(opts, "bs=1024") == 0)
320 instance->sector_size = 1024;
321 else if (str_cmp(opts, "bs=2048") == 0)
322 instance->sector_size = 2048;
323
324 /* initialize block cache */
325 errno_t rc = block_init(service_id, MAX_SIZE);
326 if (rc != EOK) {
327 free(instance);
328 return rc;
329 }
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
409 return EOK;
410}
411
412static errno_t udf_unmounted(service_id_t service_id)
413{
414 fs_node_t *fn;
415 errno_t rc = udf_root_get(&fn, service_id);
416 if (rc != EOK)
417 return rc;
418
419 udf_node_t *nodep = UDF_NODE(fn);
420 udf_instance_t *instance = nodep->instance;
421
422 /*
423 * We expect exactly two references on the root node.
424 * One for the udf_root_get() above and one created in
425 * udf_mounted().
426 */
427 if (nodep->ref_cnt != 2) {
428 udf_node_put(fn);
429 return EBUSY;
430 }
431
432 /*
433 * Put the root node twice.
434 */
435 udf_node_put(fn);
436 udf_node_put(fn);
437
438 fs_instance_destroy(service_id);
439 free(instance);
440 block_cache_fini(service_id);
441 block_fini(service_id);
442
443 return EOK;
444}
445
446static errno_t udf_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
447 size_t *rbytes)
448{
449 udf_instance_t *instance;
450 errno_t rc = fs_instance_get(service_id, (void **) &instance);
451 if (rc != EOK)
452 return rc;
453
454 fs_node_t *rfn;
455 rc = udf_node_get(&rfn, service_id, index);
456 if (rc != EOK)
457 return rc;
458
459 udf_node_t *node = UDF_NODE(rfn);
460
461 ipc_call_t call;
462 size_t len = 0;
463 if (!async_data_read_receive(&call, &len)) {
464 async_answer_0(&call, EINVAL);
465 udf_node_put(rfn);
466 return EINVAL;
467 }
468
469 if (node->type == NODE_FILE) {
470 if (pos >= node->data_size) {
471 *rbytes = 0;
472 async_data_read_finalize(&call, NULL, 0);
473 udf_node_put(rfn);
474 return EOK;
475 }
476
477 size_t read_len = 0;
478 if (node->data == NULL)
479 rc = udf_read_file(&read_len, &call, node, pos, len);
480 else {
481 /* File in allocation descriptors area */
482 read_len = (len < node->data_size) ? len : node->data_size;
483 async_data_read_finalize(&call, node->data + pos, read_len);
484 rc = EOK;
485 }
486
487 *rbytes = read_len;
488 (void) udf_node_put(rfn);
489 return rc;
490 } else {
491 block_t *block = NULL;
492 udf_file_identifier_descriptor_t *fid = NULL;
493 if (udf_get_fid(&fid, &block, node, pos) == EOK) {
494 char *name = malloc(MAX_FILE_NAME_LEN + 1);
495
496 // FIXME: Check for NULL return value
497
498 udf_to_unix_name(name, MAX_FILE_NAME_LEN,
499 (char *) fid->implementation_use + FLE16(fid->length_iu),
500 fid->length_file_id, &node->instance->charset);
501
502 async_data_read_finalize(&call, name, str_size(name) + 1);
503 *rbytes = 1;
504 free(name);
505 udf_node_put(rfn);
506
507 if (block != NULL)
508 return block_put(block);
509
510 return EOK;
511 } else {
512 *rbytes = 0;
513 udf_node_put(rfn);
514 async_answer_0(&call, ENOENT);
515 return ENOENT;
516 }
517 }
518}
519
520static errno_t udf_close(service_id_t service_id, fs_index_t index)
521{
522 return EOK;
523}
524
525static errno_t udf_sync(service_id_t service_id, fs_index_t index)
526{
527 return ENOTSUP;
528}
529
530static errno_t udf_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
531 size_t *wbytes, aoff64_t *nsize)
532{
533 return ENOTSUP;
534}
535
536static errno_t udf_truncate(service_id_t service_id, fs_index_t index,
537 aoff64_t size)
538{
539 return ENOTSUP;
540}
541
542static errno_t udf_destroy(service_id_t service_id, fs_index_t index)
543{
544 return ENOTSUP;
545}
546
547vfs_out_ops_t udf_ops = {
548 .fsprobe = udf_fsprobe,
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.