VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_core.h

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.6 KB
Line 
1/* $Id: fsw_core.h 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * fsw_core.h - Core file system wrapper abstraction layer header.
4 */
5
6/*
7 * Copyright (C) 2010-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 * ---------------------------------------------------------------------------
36 * This code is based on:
37 *
38 * Copyright (c) 2006 Christoph Pfisterer
39 * Portions Copyright (c) The Regents of the University of California.
40 * Portions Copyright (c) UNIX System Laboratories, Inc.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions are
44 * met:
45 *
46 * * Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 *
49 * * Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the
52 * distribution.
53 *
54 * * Neither the name of Christoph Pfisterer nor the names of the
55 * contributors may be used to endorse or promote products derived
56 * from this software without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
59 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
60 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
61 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
62 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
63 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
64 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
65 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
66 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
67 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
68 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
69 */
70
71#ifndef _FSW_CORE_H_
72#define _FSW_CORE_H_
73
74#include "fsw_base.h"
75
76
77/** Maximum size for a path, specifically symlink target paths. */
78#ifndef VBOX
79#define FSW_PATH_MAX (4096)
80#else
81/* Too big allocations are handled with alloca() */
82#define FSW_PATH_MAX (2048)
83#endif
84
85/** Helper macro for token concatenation. */
86#define FSW_CONCAT3(a,b,c) a##b##c
87/** Expands to the name of a fstype dispatch table (fsw_fstype_table) for a named file system type. */
88#define FSW_FSTYPE_TABLE_NAME(t) FSW_CONCAT3(fsw_,t,_table)
89
90/** Indicates that the block cache entry is empty. */
91#define FSW_INVALID_BNO (~0U)
92
93
94//
95// Byte-swapping macros
96//
97
98
99/**
100 * \name Byte Order Macros
101 * Implements big endian vs. little endian awareness and conversion.
102 */
103/*@{*/
104
105typedef fsw_u16 fsw_u16_le;
106typedef fsw_u16 fsw_u16_be;
107typedef fsw_u32 fsw_u32_le;
108typedef fsw_u32 fsw_u32_be;
109typedef fsw_u64 fsw_u64_le;
110typedef fsw_u64 fsw_u64_be;
111
112#define FSW_SWAPVALUE_U16(v) ((((fsw_u16)(v) & 0xff00) >> 8) | \
113 (((fsw_u16)(v) & 0x00ff) << 8))
114#define FSW_SWAPVALUE_U32(v) ((((fsw_u32)(v) & 0xff000000UL) >> 24) | \
115 (((fsw_u32)(v) & 0x00ff0000UL) >> 8) | \
116 (((fsw_u32)(v) & 0x0000ff00UL) << 8) | \
117 (((fsw_u32)(v) & 0x000000ffUL) << 24))
118#define FSW_SWAPVALUE_U64(v) ((((fsw_u64)(v) & 0xff00000000000000ULL) >> 56) | \
119 (((fsw_u64)(v) & 0x00ff000000000000ULL) >> 40) | \
120 (((fsw_u64)(v) & 0x0000ff0000000000ULL) >> 24) | \
121 (((fsw_u64)(v) & 0x000000ff00000000ULL) >> 8) | \
122 (((fsw_u64)(v) & 0x00000000ff000000ULL) << 8) | \
123 (((fsw_u64)(v) & 0x0000000000ff0000ULL) << 24) | \
124 (((fsw_u64)(v) & 0x000000000000ff00ULL) << 40) | \
125 (((fsw_u64)(v) & 0x00000000000000ffULL) << 56))
126
127#ifdef FSW_LITTLE_ENDIAN
128
129#define fsw_u16_le_swap(v) (v)
130#define fsw_u16_be_swap(v) FSW_SWAPVALUE_U16(v)
131#define fsw_u32_le_swap(v) (v)
132#define fsw_u32_be_swap(v) FSW_SWAPVALUE_U32(v)
133#define fsw_u64_le_swap(v) (v)
134#define fsw_u64_be_swap(v) FSW_SWAPVALUE_U64(v)
135
136#define fsw_u16_le_sip(var)
137#define fsw_u16_be_sip(var) (var = FSW_SWAPVALUE_U16(var))
138#define fsw_u32_le_sip(var)
139#define fsw_u32_be_sip(var) (var = FSW_SWAPVALUE_U32(var))
140#define fsw_u64_le_sip(var)
141#define fsw_u64_be_sip(var) (var = FSW_SWAPVALUE_U64(var))
142
143#else
144#ifdef FSW_BIG_ENDIAN
145
146#define fsw_u16_le_swap(v) FSW_SWAPVALUE_U16(v)
147#define fsw_u16_be_swap(v) (v)
148#define fsw_u32_le_swap(v) FSW_SWAPVALUE_U32(v)
149#define fsw_u32_be_swap(v) (v)
150#define fsw_u64_le_swap(v) FSW_SWAPVALUE_U64(v)
151#define fsw_u64_be_swap(v) (v)
152
153#define fsw_u16_le_sip(var) (var = FSW_SWAPVALUE_U16(var))
154#define fsw_u16_be_sip(var)
155#define fsw_u32_le_sip(var) (var = FSW_SWAPVALUE_U32(var))
156#define fsw_u32_be_sip(var)
157#define fsw_u64_le_sip(var) (var = FSW_SWAPVALUE_U64(var))
158#define fsw_u64_be_sip(var)
159
160#else
161#fail Neither FSW_BIG_ENDIAN nor FSW_LITTLE_ENDIAN are defined
162#endif
163#endif
164
165/*@}*/
166
167
168//
169// The following evil hack avoids a lot of casts between generic and fstype-specific
170// structures.
171//
172
173#ifndef VOLSTRUCTNAME
174#define VOLSTRUCTNAME fsw_volume
175#else
176struct VOLSTRUCTNAME;
177#endif
178#ifndef DNODESTRUCTNAME
179#define DNODESTRUCTNAME fsw_dnode
180#else
181struct DNODESTRUCTNAME;
182#endif
183
184
185/**
186 * Status code type, returned from all functions that can fail.
187 */
188typedef int fsw_status_t;
189
190/**
191 * Possible status codes.
192 */
193enum {
194 FSW_SUCCESS,
195 FSW_OUT_OF_MEMORY,
196 FSW_IO_ERROR,
197 FSW_UNSUPPORTED,
198 FSW_NOT_FOUND,
199 FSW_VOLUME_CORRUPTED,
200 FSW_UNKNOWN_ERROR
201};
202
203
204/**
205 * Core: A string with explicit length and encoding information.
206 */
207
208struct fsw_string {
209 int type; //!< Encoding of the string - empty, ISO-8859-1, UTF8, UTF16
210 int len; //!< Length in characters
211 int size; //!< Total data size in bytes
212 void *data; //!< Data pointer (may be NULL if type is EMPTY or len is zero)
213};
214
215/**
216 * Possible string types / encodings. In the case of FSW_STRING_TYPE_EMPTY,
217 * all other members of the fsw_string structure may be invalid.
218 */
219enum {
220 FSW_STRING_TYPE_EMPTY,
221 FSW_STRING_TYPE_ISO88591,
222 FSW_STRING_TYPE_UTF8,
223 FSW_STRING_TYPE_UTF16,
224 FSW_STRING_TYPE_UTF16_SWAPPED
225};
226
227#ifdef FSW_LITTLE_ENDIAN
228#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16
229#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16_SWAPPED
230#else
231#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16_SWAPPED
232#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16
233#endif
234
235/** Static initializer for an empty string. */
236#define FSW_STRING_INIT { FSW_STRING_TYPE_EMPTY, 0, 0, NULL }
237
238
239/* forward declarations */
240
241struct fsw_dnode;
242struct fsw_host_table;
243struct fsw_fstype_table;
244
245struct fsw_blockcache {
246 fsw_u32 refcount; //!< Reference count
247 fsw_u32 cache_level; //!< Level of importance of this block
248 fsw_u32 phys_bno; //!< Physical block number
249 void *data; //!< Block data buffer
250};
251
252/**
253 * Core: Represents a mounted volume.
254 */
255
256struct fsw_volume {
257 fsw_u32 phys_blocksize; //!< Block size for disk access / file system structures
258 fsw_u32 log_blocksize; //!< Block size for logical file data
259
260 struct DNODESTRUCTNAME *root; //!< Root directory dnode
261 struct fsw_string label; //!< Volume label
262
263 struct fsw_dnode *dnode_head; //!< List of all dnodes allocated for this volume
264
265 struct fsw_blockcache *bcache; //!< Array of block cache entries
266 fsw_u32 bcache_size; //!< Number of entries in the block cache array
267
268 void *host_data; //!< Hook for a host-specific data structure
269 struct fsw_host_table *host_table; //!< Dispatch table for host-specific functions
270 struct fsw_fstype_table *fstype_table; //!< Dispatch table for file system specific functions
271 int host_string_type; //!< String type used by the host environment
272};
273
274/**
275 * Core: Represents a "directory node" - a file, directory, symlink, whatever.
276 */
277
278struct fsw_dnode {
279 fsw_u32 refcount; //!< Reference count
280
281 struct VOLSTRUCTNAME *vol; //!< The volume this dnode belongs to
282 struct DNODESTRUCTNAME *parent; //!< Parent directory dnode
283 struct fsw_string name; //!< Name of this item in the parent directory
284
285 fsw_u32 dnode_id; //!< Unique id number (usually the inode number)
286 int type; //!< Type of the dnode - file, dir, symlink, special
287 fsw_u64 size; //!< Data size in bytes
288
289 struct fsw_dnode *next; //!< Doubly-linked list of all dnodes: previous dnode
290 struct fsw_dnode *prev; //!< Doubly-linked list of all dnodes: next dnode
291};
292
293/**
294 * Possible dnode types. FSW_DNODE_TYPE_UNKNOWN may only be used before
295 * fsw_dnode_fill has been called on the dnode.
296 */
297enum {
298 FSW_DNODE_TYPE_UNKNOWN,
299 FSW_DNODE_TYPE_FILE,
300 FSW_DNODE_TYPE_DIR,
301 FSW_DNODE_TYPE_SYMLINK,
302 FSW_DNODE_TYPE_SPECIAL
303};
304
305/**
306 * Core: Stores the mapping of a region of a file to the data on disk.
307 */
308
309struct fsw_extent {
310 int type; //!< Type of extent specification
311 fsw_u32 log_start; //!< Starting logical block number
312 fsw_u32 log_count; //!< Logical block count
313 fsw_u32 phys_start; //!< Starting physical block number (for FSW_EXTENT_TYPE_PHYSBLOCK only)
314 void *buffer; //!< Allocated buffer pointer (for FSW_EXTENT_TYPE_BUFFER only)
315};
316
317/**
318 * Possible extent representation types. FSW_EXTENT_TYPE_INVALID is for shandle's
319 * internal use only, it must not be returned from a get_extent function.
320 */
321enum {
322 FSW_EXTENT_TYPE_INVALID,
323 FSW_EXTENT_TYPE_SPARSE,
324 FSW_EXTENT_TYPE_PHYSBLOCK,
325 FSW_EXTENT_TYPE_BUFFER
326};
327
328/**
329 * Core: An access structure to a dnode's raw data. There can be multiple
330 * shandles per dnode, each of them has its own position pointer.
331 */
332
333struct fsw_shandle {
334 struct fsw_dnode *dnode; //!< The dnode this handle reads data from
335
336 fsw_u64 pos; //!< Current file pointer in bytes
337 struct fsw_extent extent; //!< Current extent
338};
339
340/**
341 * Core: Used in gathering detailed information on a volume.
342 */
343
344struct fsw_volume_stat {
345 fsw_u64 total_bytes; //!< Total size of data area size in bytes
346 fsw_u64 free_bytes; //!< Bytes still available for storing file data
347};
348
349/**
350 * Core: Used in gathering detailed information on a dnode.
351 */
352
353struct fsw_dnode_stat {
354 fsw_u64 used_bytes; //!< Bytes actually used by the file on disk
355 void (*store_time_posix)(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time); //!< Callback for storing a Posix-style timestamp
356 void (*store_attr_posix)(struct fsw_dnode_stat *sb, fsw_u16 posix_mode); //!< Callback for storing a Posix-style file mode
357 void *host_data; //!< Hook for a host-specific data structure
358};
359
360/**
361 * Type of the timestamp passed into store_time_posix.
362 */
363enum {
364 FSW_DNODE_STAT_CTIME,
365 FSW_DNODE_STAT_MTIME,
366 FSW_DNODE_STAT_ATIME
367};
368
369/**
370 * Core: Function table for a host environment.
371 */
372
373struct fsw_host_table
374{
375 int native_string_type; //!< String type used by the host environment
376
377 void (*change_blocksize)(struct fsw_volume *vol,
378 fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
379 fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
380 fsw_status_t (*read_block)(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
381};
382
383/**
384 * Core: Function table for a file system driver.
385 */
386
387struct fsw_fstype_table
388{
389 struct fsw_string name; //!< String giving the name of the file system
390 fsw_u32 volume_struct_size; //!< Size for allocating the fsw_volume structure
391 fsw_u32 dnode_struct_size; //!< Size for allocating the fsw_dnode structure
392
393 fsw_status_t (*volume_mount)(struct VOLSTRUCTNAME *vol);
394 void (*volume_free)(struct VOLSTRUCTNAME *vol);
395 fsw_status_t (*volume_stat)(struct VOLSTRUCTNAME *vol, struct fsw_volume_stat *sb);
396
397 fsw_status_t (*dnode_fill)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno);
398 void (*dnode_free)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno);
399 fsw_status_t (*dnode_stat)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
400 struct fsw_dnode_stat *sb);
401 fsw_status_t (*get_extent)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
402 struct fsw_extent *extent);
403
404 fsw_status_t (*dir_lookup)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
405 struct fsw_string *lookup_name, struct DNODESTRUCTNAME **child_dno);
406 fsw_status_t (*dir_read)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
407 struct fsw_shandle *shand, struct DNODESTRUCTNAME **child_dno);
408 fsw_status_t (*readlink)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
409 struct fsw_string *link_target);
410};
411
412
413/**
414 * \name Volume Functions
415 */
416/*@{*/
417
418fsw_status_t fsw_mount(void *host_data,
419 struct fsw_host_table *host_table,
420 struct fsw_fstype_table *fstype_table,
421 struct fsw_volume **vol_out);
422void fsw_unmount(struct fsw_volume *vol);
423fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb);
424
425void fsw_set_blocksize(struct VOLSTRUCTNAME *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize);
426fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fsw_u32 cache_level, void **buffer_out);
427void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, void *buffer);
428
429/*@}*/
430
431
432/**
433 * \name dnode Functions
434 */
435/*@{*/
436
437fsw_status_t fsw_dnode_create_root(struct VOLSTRUCTNAME *vol, fsw_u32 dnode_id, struct DNODESTRUCTNAME **dno_out);
438fsw_status_t fsw_dnode_create(struct DNODESTRUCTNAME *parent_dno, fsw_u32 dnode_id, int type,
439 struct fsw_string *name, struct DNODESTRUCTNAME **dno_out);
440void fsw_dnode_retain(struct fsw_dnode *dno);
441void fsw_dnode_release(struct fsw_dnode *dno);
442
443fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno);
444fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb);
445
446fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
447 struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out);
448fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
449 struct fsw_string *lookup_path, char separator,
450 struct fsw_dnode **child_dno_out);
451fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out);
452fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *link_target);
453fsw_status_t fsw_dnode_readlink_data(struct DNODESTRUCTNAME *dno, struct fsw_string *link_target);
454fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out);
455
456/*@}*/
457
458
459/**
460 * \name shandle Functions
461 */
462/*@{*/
463
464fsw_status_t fsw_shandle_open(struct DNODESTRUCTNAME *dno, struct fsw_shandle *shand);
465void fsw_shandle_close(struct fsw_shandle *shand);
466fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer);
467
468/*@}*/
469
470
471/**
472 * \name Memory Functions
473 */
474/*@{*/
475
476fsw_status_t fsw_alloc_zero(int len, void **ptr_out);
477fsw_status_t fsw_memdup(void **dest_out, void *src, int len);
478
479/*@}*/
480
481
482/**
483 * \name String Functions
484 */
485/*@{*/
486
487int fsw_strlen(struct fsw_string *s);
488int fsw_streq(struct fsw_string *s1, struct fsw_string *s2);
489int fsw_streq_cstr(struct fsw_string *s1, const char *s2);
490fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src);
491void fsw_strsplit(struct fsw_string *lookup_name, struct fsw_string *buffer, char separator);
492
493void fsw_strfree(struct fsw_string *s);
494fsw_u16 fsw_to_lower(fsw_u16 ch);
495
496/*@}*/
497
498
499/**
500 * \name Posix Mode Macros
501 * These macros can be used globally to test fields and bits in
502 * Posix-style modes.
503 *
504 * Taken from FreeBSD sys/stat.h.
505 */
506/*@{*/
507#ifndef S_IRWXU
508
509#define S_ISUID 0004000 /* set user id on execution */
510#define S_ISGID 0002000 /* set group id on execution */
511#define S_ISTXT 0001000 /* sticky bit */
512
513#define S_IRWXU 0000700 /* RWX mask for owner */
514#define S_IRUSR 0000400 /* R for owner */
515#define S_IWUSR 0000200 /* W for owner */
516#define S_IXUSR 0000100 /* X for owner */
517
518#define S_IRWXG 0000070 /* RWX mask for group */
519#define S_IRGRP 0000040 /* R for group */
520#define S_IWGRP 0000020 /* W for group */
521#define S_IXGRP 0000010 /* X for group */
522
523#define S_IRWXO 0000007 /* RWX mask for other */
524#define S_IROTH 0000004 /* R for other */
525#define S_IWOTH 0000002 /* W for other */
526#define S_IXOTH 0000001 /* X for other */
527
528#define S_IFMT 0170000 /* type of file mask */
529#define S_IFIFO 0010000 /* named pipe (fifo) */
530#define S_IFCHR 0020000 /* character special */
531#define S_IFDIR 0040000 /* directory */
532#define S_IFBLK 0060000 /* block special */
533#define S_IFREG 0100000 /* regular */
534#define S_IFLNK 0120000 /* symbolic link */
535#define S_IFSOCK 0140000 /* socket */
536#define S_ISVTX 0001000 /* save swapped text even after use */
537#define S_IFWHT 0160000 /* whiteout */
538
539#define S_ISDIR(m) (((m) & 0170000) == 0040000) /* directory */
540#define S_ISCHR(m) (((m) & 0170000) == 0020000) /* char special */
541#define S_ISBLK(m) (((m) & 0170000) == 0060000) /* block special */
542#define S_ISREG(m) (((m) & 0170000) == 0100000) /* regular file */
543#define S_ISFIFO(m) (((m) & 0170000) == 0010000) /* fifo or socket */
544#define S_ISLNK(m) (((m) & 0170000) == 0120000) /* symbolic link */
545#define S_ISSOCK(m) (((m) & 0170000) == 0140000) /* socket */
546#define S_ISWHT(m) (((m) & 0170000) == 0160000) /* whiteout */
547
548#define S_BLKSIZE 512 /* block size used in the stat struct */
549
550#endif
551/*@}*/
552
553
554#endif
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use