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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3dd148d was 3dd148d, checked in by Manuele Conti <conti.ma@…>, 12 years ago

Change stafs function operation to allow correct error handling.

  • Property mode set to 100644
File size: 12.4 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 <sys/mman.h>
53#include <align.h>
54#include <malloc.h>
55#include <inttypes.h>
56#include <io/log.h>
57#include "../../vfs/vfs.h"
58#include "udf.h"
59#include "udf_cksum.h"
60#include "udf_volume.h"
61#include "udf_idx.h"
62#include "udf_file.h"
63#include "udf_osta.h"
64
65/** Mutex protecting the list of cached free nodes. */
66static FIBRIL_MUTEX_INITIALIZE(ffn_mutex);
67
68/** List of cached free nodes. */
69static LIST_INITIALIZE(ffn_list);
70
71static int udf_node_get(fs_node_t **rfn, service_id_t service_id,
72 fs_index_t index)
73{
74 udf_instance_t *instance;
75 int rc = fs_instance_get(service_id, (void **) &instance);
76 if (rc != EOK)
77 return rc;
78
79 udf_node_t *node;
80 rc = udf_idx_get(&node, instance, index);
81 if (rc != EOK) {
82 rc = udf_idx_add(&node, instance, index);
83 if (rc != EOK)
84 return rc;
85
86 rc = udf_node_get_core(node);
87 if (rc != EOK) {
88 udf_idx_del(node);
89 return rc;
90 }
91 }
92
93 *rfn = FS_NODE(node);
94 return EOK;
95}
96
97static int udf_root_get(fs_node_t **rfn, service_id_t service_id)
98{
99 udf_instance_t *instance;
100 int rc = fs_instance_get(service_id, (void **) &instance);
101 if (rc != EOK)
102 return rc;
103
104 return udf_node_get(rfn, service_id,
105 instance->volumes[DEFAULT_VOL].root_dir);
106}
107
108static service_id_t udf_service_get(fs_node_t *node)
109{
110 udf_node_t *udfn = UDF_NODE(node);
111 if (udfn)
112 return udfn->instance->service_id;
113
114 return 0;
115}
116
117static int udf_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
118{
119 char *name = malloc(MAX_FILE_NAME_LEN + 1);
120 if (name == NULL)
121 return ENOMEM;
122
123 block_t *block = NULL;
124 udf_file_identifier_descriptor_t *fid = NULL;
125 size_t pos = 0;
126
127 while (udf_get_fid(&fid, &block, UDF_NODE(pfn), pos) == EOK) {
128 udf_long_ad_t long_ad = fid->icb;
129
130 udf_to_unix_name(name, MAX_FILE_NAME_LEN,
131 (char *) fid->implementation_use + FLE16(fid->lenght_iu),
132 fid->lenght_file_id, &UDF_NODE(pfn)->instance->charset);
133
134 if (stricmp(name, component) == 0) {
135 int rc = udf_node_get(rfn, udf_service_get(pfn),
136 udf_long_ad_to_pos(UDF_NODE(pfn)->instance, &long_ad));
137
138 if (block != NULL)
139 block_put(block);
140
141 free(name);
142 return rc;
143 }
144
145 if (block != NULL) {
146 int rc = block_put(block);
147 if (rc != EOK)
148 return rc;
149 }
150
151 pos++;
152 }
153
154 free(name);
155 return ENOENT;
156}
157
158static int udf_node_open(fs_node_t *fn)
159{
160 return EOK;
161}
162
163static int udf_node_put(fs_node_t *fn)
164{
165 udf_node_t *node = UDF_NODE(fn);
166 if (!node)
167 return EINVAL;
168
169 fibril_mutex_lock(&node->lock);
170 node->ref_cnt--;
171 fibril_mutex_unlock(&node->lock);
172
173 /* Delete node from hash table and memory */
174 if (!node->ref_cnt)
175 udf_idx_del(node);
176
177 return EOK;
178}
179
180static int udf_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
181{
182 return ENOTSUP;
183}
184
185static int udf_destroy_node(fs_node_t *fn)
186{
187 return ENOTSUP;
188}
189
190static int udf_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
191{
192 return ENOTSUP;
193}
194
195static int udf_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
196{
197 return ENOTSUP;
198}
199
200static int udf_has_children(bool *has_children, fs_node_t *fn)
201{
202 *has_children = true;
203 return EOK;
204}
205
206static fs_index_t udf_index_get(fs_node_t *fn)
207{
208 udf_node_t *node = UDF_NODE(fn);
209 if (node)
210 return node->index;
211
212 return 0;
213}
214
215static aoff64_t udf_size_get(fs_node_t *fn)
216{
217 udf_node_t *node = UDF_NODE(fn);
218 if (node)
219 return node->data_size;
220
221 return 0;
222}
223
224static unsigned int udf_lnkcnt_get(fs_node_t *fn)
225{
226 udf_node_t *node = UDF_NODE(fn);
227 if (node)
228 return node->link_cnt;
229
230 return 0;
231}
232
233static bool udf_is_directory(fs_node_t *fn)
234{
235 udf_node_t *node = UDF_NODE(fn);
236 if (node)
237 return node->type == NODE_DIR;
238
239 return false;
240}
241
242static bool udf_is_file(fs_node_t *fn)
243{
244 udf_node_t *node = UDF_NODE(fn);
245 if (node)
246 return node->type == NODE_FILE;
247
248 return false;
249}
250
251static int udf_size_block(service_id_t service_id, uint32_t *size)
252{
253 udf_instance_t *instance;
254 int rc = fs_instance_get(service_id, (void **) &instance);
255 if (rc != EOK)
256 return rc;
257
258 if (NULL == instance)
259 return ENOENT;
260
261 *size = instance->volumes[DEFAULT_VOL].logical_block_size;
262
263 return EOK;
264}
265
266libfs_ops_t udf_libfs_ops = {
267 .root_get = udf_root_get,
268 .match = udf_match,
269 .node_get = udf_node_get,
270 .node_open = udf_node_open,
271 .node_put = udf_node_put,
272 .create = udf_create_node,
273 .destroy = udf_destroy_node,
274 .link = udf_link,
275 .unlink = udf_unlink,
276 .has_children = udf_has_children,
277 .index_get = udf_index_get,
278 .size_get = udf_size_get,
279 .lnkcnt_get = udf_lnkcnt_get,
280 .is_directory = udf_is_directory,
281 .is_file = udf_is_file,
282 .service_get = udf_service_get,
283 .size_block = udf_size_block
284};
285
286static int udf_mounted(service_id_t service_id, const char *opts,
287 fs_index_t *index, aoff64_t *size, unsigned *linkcnt)
288{
289 enum cache_mode cmode;
290
291 /* Check for option enabling write through. */
292 if (str_cmp(opts, "wtcache") == 0)
293 cmode = CACHE_MODE_WT;
294 else
295 cmode = CACHE_MODE_WB;
296
297 udf_instance_t *instance = malloc(sizeof(udf_instance_t));
298 if (!instance)
299 return ENOMEM;
300
301 instance->sector_size = 0;
302
303 /* Check for block size. Will be enhanced later */
304 if (str_cmp(opts, "bs=512") == 0)
305 instance->sector_size = 512;
306 else if (str_cmp(opts, "bs=1024") == 0)
307 instance->sector_size = 1024;
308 else if (str_cmp(opts, "bs=2048") == 0)
309 instance->sector_size = 2048;
310
311 /* initialize block cache */
312 int rc = block_init(EXCHANGE_SERIALIZE, service_id, MAX_SIZE);
313 if (rc != EOK)
314 return rc;
315
316 rc = fs_instance_create(service_id, instance);
317 if (rc != EOK) {
318 free(instance);
319 block_fini(service_id);
320 return rc;
321 }
322
323 instance->service_id = service_id;
324 instance->open_nodes_count = 0;
325
326 /* Check Volume Recognition Sequence */
327 rc = udf_volume_recongnition(service_id);
328 if (rc != EOK) {
329 log_msg(LOG_DEFAULT, LVL_NOTE, "VRS failed");
330 fs_instance_destroy(service_id);
331 free(instance);
332 block_fini(service_id);
333 return rc;
334 }
335
336 /* Search for Anchor Volume Descriptor */
337 udf_anchor_volume_descriptor_t avd;
338 rc = udf_get_anchor_volume_descriptor(service_id, &avd);
339 if (rc != EOK) {
340 log_msg(LOG_DEFAULT, LVL_NOTE, "Anchor read failed");
341 fs_instance_destroy(service_id);
342 free(instance);
343 block_fini(service_id);
344 return rc;
345 }
346
347 log_msg(LOG_DEFAULT, LVL_DEBUG,
348 "Volume: Anchor volume descriptor found. Sector size=%" PRIu32,
349 instance->sector_size);
350 log_msg(LOG_DEFAULT, LVL_DEBUG,
351 "Anchor: main sequence [length=%" PRIu32 " (bytes), start=%"
352 PRIu32 " (sector)]", avd.main_extent.length,
353 avd.main_extent.location);
354 log_msg(LOG_DEFAULT, LVL_DEBUG,
355 "Anchor: reserve sequence [length=%" PRIu32 " (bytes), start=%"
356 PRIu32 " (sector)]", avd.reserve_extent.length,
357 avd.reserve_extent.location);
358
359 /* Initialize the block cache */
360 rc = block_cache_init(service_id, instance->sector_size, 0, cmode);
361 if (rc != EOK) {
362 fs_instance_destroy(service_id);
363 free(instance);
364 block_fini(service_id);
365 return rc;
366 }
367
368 /* Read Volume Descriptor Sequence */
369 rc = udf_read_volume_descriptor_sequence(service_id, avd.main_extent);
370 if (rc != EOK) {
371 log_msg(LOG_DEFAULT, LVL_NOTE, "Volume Descriptor Sequence read failed");
372 fs_instance_destroy(service_id);
373 free(instance);
374 block_cache_fini(service_id);
375 block_fini(service_id);
376 return rc;
377 }
378
379 fs_node_t *rfn;
380 rc = udf_node_get(&rfn, service_id, instance->volumes[DEFAULT_VOL].root_dir);
381 if (rc != EOK) {
382 log_msg(LOG_DEFAULT, LVL_NOTE, "Can't create root node");
383 fs_instance_destroy(service_id);
384 free(instance);
385 block_cache_fini(service_id);
386 block_fini(service_id);
387 return rc;
388 }
389
390 udf_node_t *node = UDF_NODE(rfn);
391 *index = instance->volumes[DEFAULT_VOL].root_dir;
392 *size = node->data_size;
393 *linkcnt = node->link_cnt;
394
395 return EOK;
396}
397
398static int udf_unmounted(service_id_t service_id)
399{
400 fs_node_t *fn;
401 int rc = udf_root_get(&fn, service_id);
402 if (rc != EOK)
403 return rc;
404
405 udf_node_t *nodep = UDF_NODE(fn);
406 udf_instance_t *instance = nodep->instance;
407
408 /*
409 * We expect exactly two references on the root node.
410 * One for the udf_root_get() above and one created in
411 * udf_mounted().
412 */
413 if (nodep->ref_cnt != 2) {
414 udf_node_put(fn);
415 return EBUSY;
416 }
417
418 /*
419 * Put the root node twice.
420 */
421 udf_node_put(fn);
422 udf_node_put(fn);
423
424 fs_instance_destroy(service_id);
425 free(instance);
426 block_cache_fini(service_id);
427 block_fini(service_id);
428
429 return EOK;
430}
431
432static int udf_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
433 size_t *rbytes)
434{
435 udf_instance_t *instance;
436 int rc = fs_instance_get(service_id, (void **) &instance);
437 if (rc != EOK)
438 return rc;
439
440 fs_node_t *rfn;
441 rc = udf_node_get(&rfn, service_id, index);
442 if (rc != EOK)
443 return rc;
444
445 udf_node_t *node = UDF_NODE(rfn);
446
447 ipc_callid_t callid;
448 size_t len = 0;
449 if (!async_data_read_receive(&callid, &len)) {
450 async_answer_0(callid, EINVAL);
451 udf_node_put(rfn);
452 return EINVAL;
453 }
454
455 if (node->type == NODE_FILE) {
456 if (pos >= node->data_size) {
457 *rbytes = 0;
458 async_data_read_finalize(callid, NULL, 0);
459 udf_node_put(rfn);
460 return EOK;
461 }
462
463 size_t read_len = 0;
464 if (node->data == NULL)
465 rc = udf_read_file(&read_len, callid, node, pos, len);
466 else {
467 /* File in allocation descriptors area */
468 read_len = (len < node->data_size) ? len : node->data_size;
469 async_data_read_finalize(callid, node->data + pos, read_len);
470 rc = EOK;
471 }
472
473 *rbytes = read_len;
474 (void) udf_node_put(rfn);
475 return rc;
476 } else {
477 block_t *block = NULL;
478 udf_file_identifier_descriptor_t *fid = NULL;
479 if (udf_get_fid(&fid, &block, node, pos) == EOK) {
480 char *name = malloc(MAX_FILE_NAME_LEN + 1);
481
482 // FIXME: Check for NULL return value
483
484 udf_to_unix_name(name, MAX_FILE_NAME_LEN,
485 (char *) fid->implementation_use + FLE16(fid->lenght_iu),
486 fid->lenght_file_id, &node->instance->charset);
487
488 async_data_read_finalize(callid, name, str_size(name) + 1);
489 *rbytes = 1;
490 free(name);
491 udf_node_put(rfn);
492
493 if (block != NULL)
494 return block_put(block);
495
496 return EOK;
497 } else {
498 *rbytes = 0;
499 udf_node_put(rfn);
500 async_answer_0(callid, ENOENT);
501 return ENOENT;
502 }
503 }
504}
505
506static int udf_close(service_id_t service_id, fs_index_t index)
507{
508 return EOK;
509}
510
511static int udf_sync(service_id_t service_id, fs_index_t index)
512{
513 return ENOTSUP;
514}
515
516static int udf_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
517 size_t *wbytes, aoff64_t *nsize)
518{
519 return ENOTSUP;
520}
521
522static int udf_truncate(service_id_t service_id, fs_index_t index,
523 aoff64_t size)
524{
525 return ENOTSUP;
526}
527
528static int udf_destroy(service_id_t service_id, fs_index_t index)
529{
530 return ENOTSUP;
531}
532
533vfs_out_ops_t udf_ops = {
534 .mounted = udf_mounted,
535 .unmounted = udf_unmounted,
536 .read = udf_read,
537 .write = udf_write,
538 .truncate = udf_truncate,
539 .close = udf_close,
540 .destroy = udf_destroy,
541 .sync = udf_sync
542};
543
544/**
545 * @}
546 */
Note: See TracBrowser for help on using the repository browser.