VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/sharedfolders/vfsmod.c@ 76688

Last change on this file since 76688 was 76688, checked in by vboxsync, 6 years ago

vfsmod.c: Need linux/mount.h for sf_show_options on older kernels. bugref:3544

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.4 KB
Line 
1/** @file
2 *
3 * vboxsf -- VirtualBox Guest Additions for Linux:
4 * Virtual File System for VirtualBox Shared Folders
5 *
6 * Module initialization/finalization
7 * File system registration/deregistration
8 * Superblock reading
9 * Few utility functions
10 */
11
12/*
13 * Copyright (C) 2006-2019 Oracle Corporation
14 *
15 * Permission is hereby granted, free of charge, to any person
16 * obtaining a copy of this software and associated documentation
17 * files (the "Software"), to deal in the Software without
18 * restriction, including without limitation the rights to use,
19 * copy, modify, merge, publish, distribute, sublicense, and/or sell
20 * copies of the Software, and to permit persons to whom the
21 * Software is furnished to do so, subject to the following
22 * conditions:
23 *
24 * The above copyright notice and this permission notice shall be
25 * included in all copies or substantial portions of the Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
29 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
31 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
32 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
34 * OTHER DEALINGS IN THE SOFTWARE.
35 */
36
37/**
38 * @note Anyone wishing to make changes here might wish to take a look at
39 * https://github.com/torvalds/linux/blob/master/Documentation/filesystems/vfs.txt
40 * which seems to be the closest there is to official documentation on
41 * writing filesystem drivers for Linux.
42 */
43
44#include "vfsmod.h"
45#include "version-generated.h"
46#include "revision-generated.h"
47#include "product-generated.h"
48#include "VBoxGuestR0LibInternal.h"
49#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
50# include <linux/mount.h>
51#endif
52
53MODULE_DESCRIPTION(VBOX_PRODUCT " VFS Module for Host File System Access");
54MODULE_AUTHOR(VBOX_VENDOR);
55MODULE_LICENSE("GPL and additional rights");
56#ifdef MODULE_ALIAS_FS
57MODULE_ALIAS_FS("vboxsf");
58#endif
59#ifdef MODULE_VERSION
60MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV));
61#endif
62
63/* globals */
64VBGLSFCLIENT client_handle;
65
66/* forward declarations */
67static struct super_operations sf_super_ops;
68
69/* allocate global info, try to map host share */
70static int sf_glob_alloc(struct vbsf_mount_info_new *info,
71 struct sf_glob_info **sf_gp)
72{
73 int err, rc;
74 SHFLSTRING *str_name;
75 size_t name_len, str_len;
76 struct sf_glob_info *sf_g;
77
78 TRACE();
79 sf_g = kmalloc(sizeof(*sf_g), GFP_KERNEL);
80 if (!sf_g) {
81 err = -ENOMEM;
82 LogRelFunc(("could not allocate memory for global info\n"));
83 goto fail0;
84 }
85
86 RT_ZERO(*sf_g);
87
88 if (info->nullchar != '\0'
89 || info->signature[0] != VBSF_MOUNT_SIGNATURE_BYTE_0
90 || info->signature[1] != VBSF_MOUNT_SIGNATURE_BYTE_1
91 || info->signature[2] != VBSF_MOUNT_SIGNATURE_BYTE_2) {
92 err = -EINVAL;
93 goto fail1;
94 }
95
96 info->name[sizeof(info->name) - 1] = 0;
97 info->nls_name[sizeof(info->nls_name) - 1] = 0;
98
99 name_len = strlen(info->name);
100 str_len = offsetof(SHFLSTRING, String.utf8) + name_len + 1;
101 str_name = kmalloc(str_len, GFP_KERNEL);
102 if (!str_name) {
103 err = -ENOMEM;
104 LogRelFunc(("could not allocate memory for host name\n"));
105 goto fail1;
106 }
107
108 str_name->u16Length = name_len;
109 str_name->u16Size = name_len + 1;
110 memcpy(str_name->String.utf8, info->name, name_len + 1);
111
112#define _IS_UTF8(_str) \
113 (strcmp(_str, "utf8") == 0)
114#define _IS_EMPTY(_str) \
115 (strcmp(_str, "") == 0)
116
117 /* Check if NLS charset is valid and not points to UTF8 table */
118 if (info->nls_name[0]) {
119 if (_IS_UTF8(info->nls_name))
120 sf_g->nls = NULL;
121 else {
122 sf_g->nls = load_nls(info->nls_name);
123 if (!sf_g->nls) {
124 err = -EINVAL;
125 LogFunc(("failed to load nls %s\n",
126 info->nls_name));
127 kfree(str_name);
128 goto fail1;
129 }
130 }
131 } else {
132#ifdef CONFIG_NLS_DEFAULT
133 /* If no NLS charset specified, try to load the default
134 * one if it's not points to UTF8. */
135 if (!_IS_UTF8(CONFIG_NLS_DEFAULT)
136 && !_IS_EMPTY(CONFIG_NLS_DEFAULT))
137 sf_g->nls = load_nls_default();
138 else
139 sf_g->nls = NULL;
140#else
141 sf_g->nls = NULL;
142#endif
143
144#undef _IS_UTF8
145#undef _IS_EMPTY
146 }
147
148 rc = VbglR0SfMapFolder(&client_handle, str_name, &sf_g->map);
149 kfree(str_name);
150
151 if (RT_FAILURE(rc)) {
152 err = -EPROTO;
153 LogFunc(("VbglR0SfMapFolder failed rc=%d\n", rc));
154 goto fail2;
155 }
156
157 sf_g->ttl = info->ttl;
158 sf_g->uid = info->uid;
159 sf_g->gid = info->gid;
160
161 if ((unsigned)info->length >= RT_UOFFSETOF(struct vbsf_mount_info_new, tag)) {
162 /* new fields */
163 sf_g->dmode = info->dmode;
164 sf_g->fmode = info->fmode;
165 sf_g->dmask = info->dmask;
166 sf_g->fmask = info->fmask;
167 } else {
168 sf_g->dmode = ~0;
169 sf_g->fmode = ~0;
170 }
171
172 if ((unsigned)info->length >= sizeof(struct vbsf_mount_info_new)) {
173 AssertCompile(sizeof(sf_g->tag) >= sizeof(info->tag));
174 memcpy(sf_g->tag, info->tag, sizeof(info->tag));
175 sf_g->tag[sizeof(sf_g->tag) - 1] = '\0';
176 } else {
177 sf_g->tag[0] = '\0';
178 }
179
180 *sf_gp = sf_g;
181 return 0;
182
183 fail2:
184 if (sf_g->nls)
185 unload_nls(sf_g->nls);
186
187 fail1:
188 kfree(sf_g);
189
190 fail0:
191 return err;
192}
193
194/* unmap the share and free global info [sf_g] */
195static void sf_glob_free(struct sf_glob_info *sf_g)
196{
197 int rc;
198
199 TRACE();
200 rc = VbglR0SfUnmapFolder(&client_handle, &sf_g->map);
201 if (RT_FAILURE(rc))
202 LogFunc(("VbglR0SfUnmapFolder failed rc=%d\n", rc));
203
204 if (sf_g->nls)
205 unload_nls(sf_g->nls);
206
207 kfree(sf_g);
208}
209
210/**
211 * This is called (by sf_read_super_[24|26] when vfs mounts the fs and
212 * wants to read super_block.
213 *
214 * calls [sf_glob_alloc] to map the folder and allocate global
215 * information structure.
216 *
217 * initializes [sb], initializes root inode and dentry.
218 *
219 * should respect [flags]
220 */
221static int sf_read_super_aux(struct super_block *sb, void *data, int flags)
222{
223 int err;
224 struct dentry *droot;
225 struct inode *iroot;
226 struct sf_inode_info *sf_i;
227 struct sf_glob_info *sf_g;
228 SHFLFSOBJINFO fsinfo;
229 struct vbsf_mount_info_new *info;
230 bool fInodePut = true;
231
232 TRACE();
233 if (!data) {
234 LogFunc(("no mount info specified\n"));
235 return -EINVAL;
236 }
237
238 info = data;
239
240 if (flags & MS_REMOUNT) {
241 LogFunc(("remounting is not supported\n"));
242 return -ENOSYS;
243 }
244
245 err = sf_glob_alloc(info, &sf_g);
246 if (err)
247 goto fail0;
248
249 sf_i = kmalloc(sizeof(*sf_i), GFP_KERNEL);
250 if (!sf_i) {
251 err = -ENOMEM;
252 LogRelFunc(("could not allocate memory for root inode info\n"));
253 goto fail1;
254 }
255
256 sf_i->handle = SHFL_HANDLE_NIL;
257 sf_i->path = kmalloc(sizeof(SHFLSTRING) + 1, GFP_KERNEL);
258 if (!sf_i->path) {
259 err = -ENOMEM;
260 LogRelFunc(("could not allocate memory for root inode path\n"));
261 goto fail2;
262 }
263
264 sf_i->path->u16Length = 1;
265 sf_i->path->u16Size = 2;
266 sf_i->path->String.utf8[0] = '/';
267 sf_i->path->String.utf8[1] = 0;
268 sf_i->force_reread = 0;
269
270 err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
271 if (err) {
272 LogFunc(("could not stat root of share\n"));
273 goto fail3;
274 }
275
276 sb->s_magic = 0xface;
277 sb->s_blocksize = 1024;
278#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 3)
279 /* Required for seek/sendfile.
280 *
281 * Must by less than or equal to INT64_MAX despite the fact that the
282 * declaration of this variable is unsigned long long. See determination
283 * of 'loff_t max' in fs/read_write.c / do_sendfile(). I don't know the
284 * correct limit but MAX_LFS_FILESIZE (8TB-1 on 32-bit boxes) takes the
285 * page cache into account and is the suggested limit. */
286#if defined MAX_LFS_FILESIZE
287 sb->s_maxbytes = MAX_LFS_FILESIZE;
288#else
289 sb->s_maxbytes = 0x7fffffffffffffffULL;
290#endif
291#endif
292 sb->s_op = &sf_super_ops;
293
294#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
295 iroot = iget_locked(sb, 0);
296#else
297 iroot = iget(sb, 0);
298#endif
299 if (!iroot) {
300 err = -ENOMEM; /* XXX */
301 LogFunc(("could not get root inode\n"));
302 goto fail3;
303 }
304
305 if (sf_init_backing_dev(sf_g)) {
306 err = -EINVAL;
307 LogFunc(("could not init bdi\n"));
308#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
309 unlock_new_inode(iroot);
310#endif
311 goto fail4;
312 }
313
314 sf_init_inode(sf_g, iroot, &fsinfo);
315 SET_INODE_INFO(iroot, sf_i);
316
317#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
318 unlock_new_inode(iroot);
319#endif
320
321#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
322 droot = d_make_root(iroot);
323#else
324 droot = d_alloc_root(iroot);
325#endif
326 if (!droot) {
327 err = -ENOMEM; /* XXX */
328 LogFunc(("d_alloc_root failed\n"));
329#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
330 fInodePut = false;
331#endif
332 goto fail5;
333 }
334
335 sb->s_root = droot;
336 SET_GLOB_INFO(sb, sf_g);
337 return 0;
338
339 fail5:
340 sf_done_backing_dev(sf_g);
341
342 fail4:
343 if (fInodePut)
344 iput(iroot);
345
346 fail3:
347 kfree(sf_i->path);
348
349 fail2:
350 kfree(sf_i);
351
352 fail1:
353 sf_glob_free(sf_g);
354
355 fail0:
356 return err;
357}
358
359#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
360static struct super_block *sf_read_super_24(struct super_block *sb, void *data,
361 int flags)
362{
363 int err;
364
365 TRACE();
366 err = sf_read_super_aux(sb, data, flags);
367 if (err)
368 return NULL;
369
370 return sb;
371}
372#endif
373
374/* this is called when vfs is about to destroy the [inode]. all
375 resources associated with this [inode] must be cleared here */
376#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
377static void sf_clear_inode(struct inode *inode)
378{
379 struct sf_inode_info *sf_i;
380
381 TRACE();
382 sf_i = GET_INODE_INFO(inode);
383 if (!sf_i)
384 return;
385
386 BUG_ON(!sf_i->path);
387 kfree(sf_i->path);
388 kfree(sf_i);
389 SET_INODE_INFO(inode, NULL);
390}
391#else
392static void sf_evict_inode(struct inode *inode)
393{
394 struct sf_inode_info *sf_i;
395
396 TRACE();
397 truncate_inode_pages(&inode->i_data, 0);
398#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
399 clear_inode(inode);
400#else
401 end_writeback(inode);
402#endif
403
404 sf_i = GET_INODE_INFO(inode);
405 if (!sf_i)
406 return;
407
408 BUG_ON(!sf_i->path);
409 kfree(sf_i->path);
410 kfree(sf_i);
411 SET_INODE_INFO(inode, NULL);
412}
413#endif
414
415/* this is called by vfs when it wants to populate [inode] with data.
416 the only thing that is known about inode at this point is its index
417 hence we can't do anything here, and let lookup/whatever with the
418 job to properly fill then [inode] */
419#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
420static void sf_read_inode(struct inode *inode)
421{
422}
423#endif
424
425/* vfs is done with [sb] (umount called) call [sf_glob_free] to unmap
426 the folder and free [sf_g] */
427static void sf_put_super(struct super_block *sb)
428{
429 struct sf_glob_info *sf_g;
430
431 sf_g = GET_GLOB_INFO(sb);
432 BUG_ON(!sf_g);
433 sf_done_backing_dev(sf_g);
434 sf_glob_free(sf_g);
435}
436
437#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
438static int sf_statfs(struct super_block *sb, STRUCT_STATFS * stat)
439{
440 return sf_get_volume_info(sb, stat);
441}
442#else
443static int sf_statfs(struct dentry *dentry, STRUCT_STATFS * stat)
444{
445 struct super_block *sb = dentry->d_inode->i_sb;
446 return sf_get_volume_info(sb, stat);
447}
448#endif
449
450static int sf_remount_fs(struct super_block *sb, int *flags, char *data)
451{
452#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 23)
453 struct sf_glob_info *sf_g;
454 struct sf_inode_info *sf_i;
455 struct inode *iroot;
456 SHFLFSOBJINFO fsinfo;
457 int err;
458
459 sf_g = GET_GLOB_INFO(sb);
460 BUG_ON(!sf_g);
461 if (data && data[0] != 0) {
462 struct vbsf_mount_info_new *info =
463 (struct vbsf_mount_info_new *)data;
464 if (info->signature[0] == VBSF_MOUNT_SIGNATURE_BYTE_0
465 && info->signature[1] == VBSF_MOUNT_SIGNATURE_BYTE_1
466 && info->signature[2] == VBSF_MOUNT_SIGNATURE_BYTE_2) {
467 sf_g->uid = info->uid;
468 sf_g->gid = info->gid;
469 sf_g->ttl = info->ttl;
470 if ((unsigned)info->length >= RT_UOFFSETOF(struct vbsf_mount_info_new, tag)) {
471 sf_g->dmode = info->dmode;
472 sf_g->fmode = info->fmode;
473 sf_g->dmask = info->dmask;
474 sf_g->fmask = info->fmask;
475 } else {
476 sf_g->dmode = ~0;
477 sf_g->fmode = ~0;
478 }
479 if ((unsigned)info->length >= sizeof(struct vbsf_mount_info_new)) {
480 AssertCompile(sizeof(sf_g->tag) >= sizeof(info->tag));
481 memcpy(sf_g->tag, info->tag, sizeof(info->tag));
482 sf_g->tag[sizeof(sf_g->tag) - 1] = '\0';
483 } else {
484 sf_g->tag[0] = '\0';
485 }
486 }
487 }
488
489 iroot = ilookup(sb, 0);
490 if (!iroot)
491 return -ENOSYS;
492
493 sf_i = GET_INODE_INFO(iroot);
494 err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
495 BUG_ON(err != 0);
496 sf_init_inode(sf_g, iroot, &fsinfo);
497 /*unlock_new_inode(iroot); */
498 return 0;
499#else
500 return -ENOSYS;
501#endif
502}
503
504/** Show mount options. */
505#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
506static int sf_show_options(struct seq_file *m, struct vfsmount *mnt)
507#else
508static int sf_show_options(struct seq_file *m, struct dentry *root)
509#endif
510{
511#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
512 struct super_block *sb = mnt->mnt_sb;
513#else
514 struct super_block *sb = root->d_sb;
515#endif
516 struct sf_glob_info *sf_g = GET_GLOB_INFO(sb);
517 if (sf_g) {
518 seq_printf(m, ",uid=%u,gid=%u,ttl=%u,dmode=0%o,fmode=0%o,dmask=0%o,fmask=0%o",
519 sf_g->uid, sf_g->gid, sf_g->ttl, sf_g->dmode, sf_g->fmode, sf_g->dmask, sf_g->fmask);
520 if (sf_g->tag[0] != '\0') {
521 seq_puts(m, ",tag=");
522 seq_escape(m, sf_g->tag, " \t\n\\");
523 }
524 }
525
526 return 0;
527}
528
529/** @todo Implement show_options (forever) or maybe set s_options (2.6.25+).
530 * Necessary for the automounter tagging. */
531static struct super_operations sf_super_ops = {
532#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
533 .clear_inode = sf_clear_inode,
534#else
535 .evict_inode = sf_evict_inode,
536#endif
537#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
538 .read_inode = sf_read_inode,
539#endif
540 .put_super = sf_put_super,
541 .statfs = sf_statfs,
542 .remount_fs = sf_remount_fs,
543 .show_options = sf_show_options
544};
545
546#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
547static DECLARE_FSTYPE(vboxsf_fs_type, "vboxsf", sf_read_super_24, 0);
548#else
549static int sf_read_super_26(struct super_block *sb, void *data, int flags)
550{
551 int err;
552
553 TRACE();
554 err = sf_read_super_aux(sb, data, flags);
555 if (err)
556 printk(KERN_DEBUG "sf_read_super_aux err=%d\n", err);
557
558 return err;
559}
560
561#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
562static struct super_block *sf_get_sb(struct file_system_type *fs_type,
563 int flags, const char *dev_name,
564 void *data)
565{
566 TRACE();
567 return get_sb_nodev(fs_type, flags, data, sf_read_super_26);
568}
569#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
570static int sf_get_sb(struct file_system_type *fs_type, int flags,
571 const char *dev_name, void *data, struct vfsmount *mnt)
572{
573 TRACE();
574 return get_sb_nodev(fs_type, flags, data, sf_read_super_26, mnt);
575}
576#else
577static struct dentry *sf_mount(struct file_system_type *fs_type, int flags,
578 const char *dev_name, void *data)
579{
580 TRACE();
581 return mount_nodev(fs_type, flags, data, sf_read_super_26);
582}
583#endif
584
585static struct file_system_type vboxsf_fs_type = {
586 .owner = THIS_MODULE,
587 .name = "vboxsf",
588#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
589 .get_sb = sf_get_sb,
590#else
591 .mount = sf_mount,
592#endif
593 .kill_sb = kill_anon_super
594};
595#endif
596
597#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
598static int follow_symlinks = 0;
599module_param(follow_symlinks, int, 0);
600MODULE_PARM_DESC(follow_symlinks,
601 "Let host resolve symlinks rather than showing them");
602#endif
603
604/* Module initialization/finalization handlers */
605static int __init init(void)
606{
607 int rcVBox;
608 int rcRet = 0;
609 int err;
610
611 TRACE();
612
613 if (sizeof(struct vbsf_mount_info_new) > PAGE_SIZE) {
614 printk(KERN_ERR
615 "Mount information structure is too large %lu\n"
616 "Must be less than or equal to %lu\n",
617 (unsigned long)sizeof(struct vbsf_mount_info_new),
618 (unsigned long)PAGE_SIZE);
619 return -EINVAL;
620 }
621
622 err = register_filesystem(&vboxsf_fs_type);
623 if (err) {
624 LogFunc(("register_filesystem err=%d\n", err));
625 return err;
626 }
627
628 rcVBox = VbglR0HGCMInit();
629 if (RT_FAILURE(rcVBox)) {
630 LogRelFunc(("VbglR0HGCMInit failed, rc=%d\n", rcVBox));
631 rcRet = -EPROTO;
632 goto fail0;
633 }
634
635 rcVBox = VbglR0SfConnect(&client_handle);
636 if (RT_FAILURE(rcVBox)) {
637 LogRelFunc(("VbglR0SfConnect failed, rc=%d\n", rcVBox));
638 rcRet = -EPROTO;
639 goto fail1;
640 }
641
642 rcVBox = VbglR0SfSetUtf8(&client_handle);
643 if (RT_FAILURE(rcVBox)) {
644 LogRelFunc(("VbglR0SfSetUtf8 failed, rc=%d\n", rcVBox));
645 rcRet = -EPROTO;
646 goto fail2;
647 }
648#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
649 if (!follow_symlinks) {
650 rcVBox = VbglR0SfSetSymlinks(&client_handle);
651 if (RT_FAILURE(rcVBox)) {
652 printk(KERN_WARNING
653 "vboxsf: Host unable to show symlinks, rc=%d\n",
654 rcVBox);
655 }
656 }
657#endif
658
659 printk(KERN_DEBUG
660 "vboxsf: Successfully loaded version " VBOX_VERSION_STRING
661 " (interface " RT_XSTR(VMMDEV_VERSION) ")\n");
662
663 return 0;
664
665 fail2:
666 VbglR0SfDisconnect(&client_handle);
667
668 fail1:
669 VbglR0HGCMTerminate();
670
671 fail0:
672 unregister_filesystem(&vboxsf_fs_type);
673 return rcRet;
674}
675
676static void __exit fini(void)
677{
678 TRACE();
679
680 VbglR0SfDisconnect(&client_handle);
681 VbglR0HGCMTerminate();
682 unregister_filesystem(&vboxsf_fs_type);
683}
684
685module_init(init);
686module_exit(fini);
687
688/* C++ hack */
689int __gxx_personality_v0 = 0xdeadbeef;
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette