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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 44dde42 was 44dde42, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 5 years ago

Fix a memory leak in udf_mounted function when block_init returns with error

  • 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 free(instance);
332 return rc;
333 }
334
335 rc = fs_instance_create(service_id, instance);
336 if (rc != EOK) {
337 free(instance);
338 block_fini(service_id);
339 return rc;
340 }
341
342 instance->service_id = service_id;
343 instance->open_nodes_count = 0;
344
345 /* Check Volume Recognition Sequence */
346 rc = udf_volume_recongnition(service_id);
347 if (rc != EOK) {
348 log_msg(LOG_DEFAULT, LVL_NOTE, "VRS failed");
349 fs_instance_destroy(service_id);
350 free(instance);
351 block_fini(service_id);
352 return rc;
353 }
354
355 /* Search for Anchor Volume Descriptor */
356 udf_anchor_volume_descriptor_t avd;
357 rc = udf_get_anchor_volume_descriptor(service_id, &avd);
358 if (rc != EOK) {
359 log_msg(LOG_DEFAULT, LVL_NOTE, "Anchor read failed");
360 fs_instance_destroy(service_id);
361 free(instance);
362 block_fini(service_id);
363 return rc;
364 }
365
366 log_msg(LOG_DEFAULT, LVL_DEBUG,
367 "Volume: Anchor volume descriptor found. Sector size=%" PRIu32,
368 instance->sector_size);
369 log_msg(LOG_DEFAULT, LVL_DEBUG,
370 "Anchor: main sequence [length=%" PRIu32 " (bytes), start=%"
371 PRIu32 " (sector)]", avd.main_extent.length,
372 avd.main_extent.location);
373 log_msg(LOG_DEFAULT, LVL_DEBUG,
374 "Anchor: reserve sequence [length=%" PRIu32 " (bytes), start=%"
375 PRIu32 " (sector)]", avd.reserve_extent.length,
376 avd.reserve_extent.location);
377
378 /* Initialize the block cache */
379 rc = block_cache_init(service_id, instance->sector_size, 0, cmode);
380 if (rc != EOK) {
381 fs_instance_destroy(service_id);
382 free(instance);
383 block_fini(service_id);
384 return rc;
385 }
386
387 /* Read Volume Descriptor Sequence */
388 rc = udf_read_volume_descriptor_sequence(service_id, avd.main_extent);
389 if (rc != EOK) {
390 log_msg(LOG_DEFAULT, LVL_NOTE, "Volume Descriptor Sequence read failed");
391 fs_instance_destroy(service_id);
392 free(instance);
393 block_cache_fini(service_id);
394 block_fini(service_id);
395 return rc;
396 }
397
398 fs_node_t *rfn;
399 rc = udf_node_get(&rfn, service_id, instance->volumes[DEFAULT_VOL].root_dir);
400 if (rc != EOK) {
401 log_msg(LOG_DEFAULT, LVL_NOTE, "Can't create root node");
402 fs_instance_destroy(service_id);
403 free(instance);
404 block_cache_fini(service_id);
405 block_fini(service_id);
406 return rc;
407 }
408
409 udf_node_t *node = UDF_NODE(rfn);
410 *index = instance->volumes[DEFAULT_VOL].root_dir;
411 *size = node->data_size;
412
413 return EOK;
414}
415
416static errno_t udf_unmounted(service_id_t service_id)
417{
418 fs_node_t *fn;
419 errno_t rc = udf_root_get(&fn, service_id);
420 if (rc != EOK)
421 return rc;
422
423 udf_node_t *nodep = UDF_NODE(fn);
424 udf_instance_t *instance = nodep->instance;
425
426 /*
427 * We expect exactly two references on the root node.
428 * One for the udf_root_get() above and one created in
429 * udf_mounted().
430 */
431 if (nodep->ref_cnt != 2) {
432 udf_node_put(fn);
433 return EBUSY;
434 }
435
436 /*
437 * Put the root node twice.
438 */
439 udf_node_put(fn);
440 udf_node_put(fn);
441
442 fs_instance_destroy(service_id);
443 free(instance);
444 block_cache_fini(service_id);
445 block_fini(service_id);
446
447 return EOK;
448}
449
450static errno_t udf_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
451 size_t *rbytes)
452{
453 udf_instance_t *instance;
454 errno_t rc = fs_instance_get(service_id, (void **) &instance);
455 if (rc != EOK)
456 return rc;
457
458 fs_node_t *rfn;
459 rc = udf_node_get(&rfn, service_id, index);
460 if (rc != EOK)
461 return rc;
462
463 udf_node_t *node = UDF_NODE(rfn);
464
465 ipc_call_t call;
466 size_t len = 0;
467 if (!async_data_read_receive(&call, &len)) {
468 async_answer_0(&call, EINVAL);
469 udf_node_put(rfn);
470 return EINVAL;
471 }
472
473 if (node->type == NODE_FILE) {
474 if (pos >= node->data_size) {
475 *rbytes = 0;
476 async_data_read_finalize(&call, NULL, 0);
477 udf_node_put(rfn);
478 return EOK;
479 }
480
481 size_t read_len = 0;
482 if (node->data == NULL)
483 rc = udf_read_file(&read_len, &call, node, pos, len);
484 else {
485 /* File in allocation descriptors area */
486 read_len = (len < node->data_size) ? len : node->data_size;
487 async_data_read_finalize(&call, node->data + pos, read_len);
488 rc = EOK;
489 }
490
491 *rbytes = read_len;
492 (void) udf_node_put(rfn);
493 return rc;
494 } else {
495 block_t *block = NULL;
496 udf_file_identifier_descriptor_t *fid = NULL;
497 if (udf_get_fid(&fid, &block, node, pos) == EOK) {
498 char *name = malloc(MAX_FILE_NAME_LEN + 1);
499
500 // FIXME: Check for NULL return value
501
502 udf_to_unix_name(name, MAX_FILE_NAME_LEN,
503 (char *) fid->implementation_use + FLE16(fid->length_iu),
504 fid->length_file_id, &node->instance->charset);
505
506 async_data_read_finalize(&call, name, str_size(name) + 1);
507 *rbytes = 1;
508 free(name);
509 udf_node_put(rfn);
510
511 if (block != NULL)
512 return block_put(block);
513
514 return EOK;
515 } else {
516 *rbytes = 0;
517 udf_node_put(rfn);
518 async_answer_0(&call, ENOENT);
519 return ENOENT;
520 }
521 }
522}
523
524static errno_t udf_close(service_id_t service_id, fs_index_t index)
525{
526 return EOK;
527}
528
529static errno_t udf_sync(service_id_t service_id, fs_index_t index)
530{
531 return ENOTSUP;
532}
533
534static errno_t udf_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
535 size_t *wbytes, aoff64_t *nsize)
536{
537 return ENOTSUP;
538}
539
540static errno_t udf_truncate(service_id_t service_id, fs_index_t index,
541 aoff64_t size)
542{
543 return ENOTSUP;
544}
545
546static errno_t udf_destroy(service_id_t service_id, fs_index_t index)
547{
548 return ENOTSUP;
549}
550
551vfs_out_ops_t udf_ops = {
552 .fsprobe = udf_fsprobe,
553 .mounted = udf_mounted,
554 .unmounted = udf_unmounted,
555 .read = udf_read,
556 .write = udf_write,
557 .truncate = udf_truncate,
558 .close = udf_close,
559 .destroy = udf_destroy,
560 .sync = udf_sync
561};
562
563/**
564 * @}
565 */
Note: See TracBrowser for help on using the repository browser.