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

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

Implement free and total count operation for cdfs and udf filesystem.

  • 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 <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
266static int udf_total_block_count(service_id_t service_id, uint64_t *count)
267{
268 *count = 0;
269
270 return EOK;
271}
272
273static int udf_free_block_count(service_id_t service_id, uint64_t *count)
274{
275 *count = 0;
276
277 return EOK;
278}
279
280libfs_ops_t udf_libfs_ops = {
281 .root_get = udf_root_get,
282 .match = udf_match,
283 .node_get = udf_node_get,
284 .node_open = udf_node_open,
285 .node_put = udf_node_put,
286 .create = udf_create_node,
287 .destroy = udf_destroy_node,
288 .link = udf_link,
289 .unlink = udf_unlink,
290 .has_children = udf_has_children,
291 .index_get = udf_index_get,
292 .size_get = udf_size_get,
293 .lnkcnt_get = udf_lnkcnt_get,
294 .is_directory = udf_is_directory,
295 .is_file = udf_is_file,
296 .service_get = udf_service_get,
297 .size_block = udf_size_block,
298 .total_block_count = udf_total_block_count,
299 .free_block_count = udf_free_block_count
300};
301
302static int udf_mounted(service_id_t service_id, const char *opts,
303 fs_index_t *index, aoff64_t *size, unsigned *linkcnt)
304{
305 enum cache_mode cmode;
306
307 /* Check for option enabling write through. */
308 if (str_cmp(opts, "wtcache") == 0)
309 cmode = CACHE_MODE_WT;
310 else
311 cmode = CACHE_MODE_WB;
312
313 udf_instance_t *instance = malloc(sizeof(udf_instance_t));
314 if (!instance)
315 return ENOMEM;
316
317 instance->sector_size = 0;
318
319 /* Check for block size. Will be enhanced later */
320 if (str_cmp(opts, "bs=512") == 0)
321 instance->sector_size = 512;
322 else if (str_cmp(opts, "bs=1024") == 0)
323 instance->sector_size = 1024;
324 else if (str_cmp(opts, "bs=2048") == 0)
325 instance->sector_size = 2048;
326
327 /* initialize block cache */
328 int rc = block_init(EXCHANGE_SERIALIZE, service_id, MAX_SIZE);
329 if (rc != EOK)
330 return rc;
331
332 rc = fs_instance_create(service_id, instance);
333 if (rc != EOK) {
334 free(instance);
335 block_fini(service_id);
336 return rc;
337 }
338
339 instance->service_id = service_id;
340 instance->open_nodes_count = 0;
341
342 /* Check Volume Recognition Sequence */
343 rc = udf_volume_recongnition(service_id);
344 if (rc != EOK) {
345 log_msg(LOG_DEFAULT, LVL_NOTE, "VRS failed");
346 fs_instance_destroy(service_id);
347 free(instance);
348 block_fini(service_id);
349 return rc;
350 }
351
352 /* Search for Anchor Volume Descriptor */
353 udf_anchor_volume_descriptor_t avd;
354 rc = udf_get_anchor_volume_descriptor(service_id, &avd);
355 if (rc != EOK) {
356 log_msg(LOG_DEFAULT, LVL_NOTE, "Anchor read failed");
357 fs_instance_destroy(service_id);
358 free(instance);
359 block_fini(service_id);
360 return rc;
361 }
362
363 log_msg(LOG_DEFAULT, LVL_DEBUG,
364 "Volume: Anchor volume descriptor found. Sector size=%" PRIu32,
365 instance->sector_size);
366 log_msg(LOG_DEFAULT, LVL_DEBUG,
367 "Anchor: main sequence [length=%" PRIu32 " (bytes), start=%"
368 PRIu32 " (sector)]", avd.main_extent.length,
369 avd.main_extent.location);
370 log_msg(LOG_DEFAULT, LVL_DEBUG,
371 "Anchor: reserve sequence [length=%" PRIu32 " (bytes), start=%"
372 PRIu32 " (sector)]", avd.reserve_extent.length,
373 avd.reserve_extent.location);
374
375 /* Initialize the block cache */
376 rc = block_cache_init(service_id, instance->sector_size, 0, cmode);
377 if (rc != EOK) {
378 fs_instance_destroy(service_id);
379 free(instance);
380 block_fini(service_id);
381 return rc;
382 }
383
384 /* Read Volume Descriptor Sequence */
385 rc = udf_read_volume_descriptor_sequence(service_id, avd.main_extent);
386 if (rc != EOK) {
387 log_msg(LOG_DEFAULT, LVL_NOTE, "Volume Descriptor Sequence read failed");
388 fs_instance_destroy(service_id);
389 free(instance);
390 block_cache_fini(service_id);
391 block_fini(service_id);
392 return rc;
393 }
394
395 fs_node_t *rfn;
396 rc = udf_node_get(&rfn, service_id, instance->volumes[DEFAULT_VOL].root_dir);
397 if (rc != EOK) {
398 log_msg(LOG_DEFAULT, LVL_NOTE, "Can't create root node");
399 fs_instance_destroy(service_id);
400 free(instance);
401 block_cache_fini(service_id);
402 block_fini(service_id);
403 return rc;
404 }
405
406 udf_node_t *node = UDF_NODE(rfn);
407 *index = instance->volumes[DEFAULT_VOL].root_dir;
408 *size = node->data_size;
409 *linkcnt = node->link_cnt;
410
411 return EOK;
412}
413
414static int udf_unmounted(service_id_t service_id)
415{
416 fs_node_t *fn;
417 int 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 int 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 int 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_callid_t callid;
464 size_t len = 0;
465 if (!async_data_read_receive(&callid, &len)) {
466 async_answer_0(callid, 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(callid, 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, callid, 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(callid, 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->lenght_iu),
502 fid->lenght_file_id, &node->instance->charset);
503
504 async_data_read_finalize(callid, 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(callid, ENOENT);
517 return ENOENT;
518 }
519 }
520}
521
522static int udf_close(service_id_t service_id, fs_index_t index)
523{
524 return EOK;
525}
526
527static int udf_sync(service_id_t service_id, fs_index_t index)
528{
529 return ENOTSUP;
530}
531
532static int 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 int udf_truncate(service_id_t service_id, fs_index_t index,
539 aoff64_t size)
540{
541 return ENOTSUP;
542}
543
544static int udf_destroy(service_id_t service_id, fs_index_t index)
545{
546 return ENOTSUP;
547}
548
549vfs_out_ops_t udf_ops = {
550 .mounted = udf_mounted,
551 .unmounted = udf_unmounted,
552 .read = udf_read,
553 .write = udf_write,
554 .truncate = udf_truncate,
555 .close = udf_close,
556 .destroy = udf_destroy,
557 .sync = udf_sync
558};
559
560/**
561 * @}
562 */
Note: See TracBrowser for help on using the repository browser.