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

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

Update implementation size, total, free block operations like new stucture statfs.

  • 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 uint32_t udf_size_block(service_id_t service_id)
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 return instance->volumes[DEFAULT_VOL].logical_block_size;
262}
263
264libfs_ops_t udf_libfs_ops = {
265 .root_get = udf_root_get,
266 .match = udf_match,
267 .node_get = udf_node_get,
268 .node_open = udf_node_open,
269 .node_put = udf_node_put,
270 .create = udf_create_node,
271 .destroy = udf_destroy_node,
272 .link = udf_link,
273 .unlink = udf_unlink,
274 .has_children = udf_has_children,
275 .index_get = udf_index_get,
276 .size_get = udf_size_get,
277 .lnkcnt_get = udf_lnkcnt_get,
278 .is_directory = udf_is_directory,
279 .is_file = udf_is_file,
280 .service_get = udf_service_get,
281 .size_block = udf_size_block
282};
283
284static int udf_mounted(service_id_t service_id, const char *opts,
285 fs_index_t *index, aoff64_t *size, unsigned *linkcnt)
286{
287 enum cache_mode cmode;
288
289 /* Check for option enabling write through. */
290 if (str_cmp(opts, "wtcache") == 0)
291 cmode = CACHE_MODE_WT;
292 else
293 cmode = CACHE_MODE_WB;
294
295 udf_instance_t *instance = malloc(sizeof(udf_instance_t));
296 if (!instance)
297 return ENOMEM;
298
299 instance->sector_size = 0;
300
301 /* Check for block size. Will be enhanced later */
302 if (str_cmp(opts, "bs=512") == 0)
303 instance->sector_size = 512;
304 else if (str_cmp(opts, "bs=1024") == 0)
305 instance->sector_size = 1024;
306 else if (str_cmp(opts, "bs=2048") == 0)
307 instance->sector_size = 2048;
308
309 /* initialize block cache */
310 int rc = block_init(EXCHANGE_SERIALIZE, service_id, MAX_SIZE);
311 if (rc != EOK)
312 return rc;
313
314 rc = fs_instance_create(service_id, instance);
315 if (rc != EOK) {
316 free(instance);
317 block_fini(service_id);
318 return rc;
319 }
320
321 instance->service_id = service_id;
322 instance->open_nodes_count = 0;
323
324 /* Check Volume Recognition Sequence */
325 rc = udf_volume_recongnition(service_id);
326 if (rc != EOK) {
327 log_msg(LOG_DEFAULT, LVL_NOTE, "VRS failed");
328 fs_instance_destroy(service_id);
329 free(instance);
330 block_fini(service_id);
331 return rc;
332 }
333
334 /* Search for Anchor Volume Descriptor */
335 udf_anchor_volume_descriptor_t avd;
336 rc = udf_get_anchor_volume_descriptor(service_id, &avd);
337 if (rc != EOK) {
338 log_msg(LOG_DEFAULT, LVL_NOTE, "Anchor read failed");
339 fs_instance_destroy(service_id);
340 free(instance);
341 block_fini(service_id);
342 return rc;
343 }
344
345 log_msg(LOG_DEFAULT, LVL_DEBUG,
346 "Volume: Anchor volume descriptor found. Sector size=%" PRIu32,
347 instance->sector_size);
348 log_msg(LOG_DEFAULT, LVL_DEBUG,
349 "Anchor: main sequence [length=%" PRIu32 " (bytes), start=%"
350 PRIu32 " (sector)]", avd.main_extent.length,
351 avd.main_extent.location);
352 log_msg(LOG_DEFAULT, LVL_DEBUG,
353 "Anchor: reserve sequence [length=%" PRIu32 " (bytes), start=%"
354 PRIu32 " (sector)]", avd.reserve_extent.length,
355 avd.reserve_extent.location);
356
357 /* Initialize the block cache */
358 rc = block_cache_init(service_id, instance->sector_size, 0, cmode);
359 if (rc != EOK) {
360 fs_instance_destroy(service_id);
361 free(instance);
362 block_fini(service_id);
363 return rc;
364 }
365
366 /* Read Volume Descriptor Sequence */
367 rc = udf_read_volume_descriptor_sequence(service_id, avd.main_extent);
368 if (rc != EOK) {
369 log_msg(LOG_DEFAULT, LVL_NOTE, "Volume Descriptor Sequence read failed");
370 fs_instance_destroy(service_id);
371 free(instance);
372 block_cache_fini(service_id);
373 block_fini(service_id);
374 return rc;
375 }
376
377 fs_node_t *rfn;
378 rc = udf_node_get(&rfn, service_id, instance->volumes[DEFAULT_VOL].root_dir);
379 if (rc != EOK) {
380 log_msg(LOG_DEFAULT, LVL_NOTE, "Can't create root node");
381 fs_instance_destroy(service_id);
382 free(instance);
383 block_cache_fini(service_id);
384 block_fini(service_id);
385 return rc;
386 }
387
388 udf_node_t *node = UDF_NODE(rfn);
389 *index = instance->volumes[DEFAULT_VOL].root_dir;
390 *size = node->data_size;
391 *linkcnt = node->link_cnt;
392
393 return EOK;
394}
395
396static int udf_unmounted(service_id_t service_id)
397{
398 fs_node_t *fn;
399 int rc = udf_root_get(&fn, service_id);
400 if (rc != EOK)
401 return rc;
402
403 udf_node_t *nodep = UDF_NODE(fn);
404 udf_instance_t *instance = nodep->instance;
405
406 /*
407 * We expect exactly two references on the root node.
408 * One for the udf_root_get() above and one created in
409 * udf_mounted().
410 */
411 if (nodep->ref_cnt != 2) {
412 udf_node_put(fn);
413 return EBUSY;
414 }
415
416 /*
417 * Put the root node twice.
418 */
419 udf_node_put(fn);
420 udf_node_put(fn);
421
422 fs_instance_destroy(service_id);
423 free(instance);
424 block_cache_fini(service_id);
425 block_fini(service_id);
426
427 return EOK;
428}
429
430static int udf_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
431 size_t *rbytes)
432{
433 udf_instance_t *instance;
434 int rc = fs_instance_get(service_id, (void **) &instance);
435 if (rc != EOK)
436 return rc;
437
438 fs_node_t *rfn;
439 rc = udf_node_get(&rfn, service_id, index);
440 if (rc != EOK)
441 return rc;
442
443 udf_node_t *node = UDF_NODE(rfn);
444
445 ipc_callid_t callid;
446 size_t len = 0;
447 if (!async_data_read_receive(&callid, &len)) {
448 async_answer_0(callid, EINVAL);
449 udf_node_put(rfn);
450 return EINVAL;
451 }
452
453 if (node->type == NODE_FILE) {
454 if (pos >= node->data_size) {
455 *rbytes = 0;
456 async_data_read_finalize(callid, NULL, 0);
457 udf_node_put(rfn);
458 return EOK;
459 }
460
461 size_t read_len = 0;
462 if (node->data == NULL)
463 rc = udf_read_file(&read_len, callid, node, pos, len);
464 else {
465 /* File in allocation descriptors area */
466 read_len = (len < node->data_size) ? len : node->data_size;
467 async_data_read_finalize(callid, node->data + pos, read_len);
468 rc = EOK;
469 }
470
471 *rbytes = read_len;
472 (void) udf_node_put(rfn);
473 return rc;
474 } else {
475 block_t *block = NULL;
476 udf_file_identifier_descriptor_t *fid = NULL;
477 if (udf_get_fid(&fid, &block, node, pos) == EOK) {
478 char *name = malloc(MAX_FILE_NAME_LEN + 1);
479
480 // FIXME: Check for NULL return value
481
482 udf_to_unix_name(name, MAX_FILE_NAME_LEN,
483 (char *) fid->implementation_use + FLE16(fid->lenght_iu),
484 fid->lenght_file_id, &node->instance->charset);
485
486 async_data_read_finalize(callid, name, str_size(name) + 1);
487 *rbytes = 1;
488 free(name);
489 udf_node_put(rfn);
490
491 if (block != NULL)
492 return block_put(block);
493
494 return EOK;
495 } else {
496 *rbytes = 0;
497 udf_node_put(rfn);
498 async_answer_0(callid, ENOENT);
499 return ENOENT;
500 }
501 }
502}
503
504static int udf_close(service_id_t service_id, fs_index_t index)
505{
506 return EOK;
507}
508
509static int udf_sync(service_id_t service_id, fs_index_t index)
510{
511 return ENOTSUP;
512}
513
514static int udf_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
515 size_t *wbytes, aoff64_t *nsize)
516{
517 return ENOTSUP;
518}
519
520static int udf_truncate(service_id_t service_id, fs_index_t index,
521 aoff64_t size)
522{
523 return ENOTSUP;
524}
525
526static int udf_destroy(service_id_t service_id, fs_index_t index)
527{
528 return ENOTSUP;
529}
530
531vfs_out_ops_t udf_ops = {
532 .mounted = udf_mounted,
533 .unmounted = udf_unmounted,
534 .read = udf_read,
535 .write = udf_write,
536 .truncate = udf_truncate,
537 .close = udf_close,
538 .destroy = udf_destroy,
539 .sync = udf_sync
540};
541
542/**
543 * @}
544 */
Note: See TracBrowser for help on using the repository browser.