VirtualBox

source: vbox/trunk/src/VBox/Additions/solaris/SharedFolders/vboxvfs_vfsops.c@ 10307

最後變更 在這個檔案從10307是 10307,由 vboxsync 提交於 17 年 前

Solaris vboxvfs: added mount wrapper.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keyword 設為 Id
  • 屬性 svn:keywords 設為 Id
檔案大小: 18.8 KB
 
1/* $Id: vboxvfs_vfsops.c 10307 2008-07-07 11:18:16Z vboxsync $ */
2/** @file
3 * VirtualBox File System Driver for Solaris Guests. VFS operations.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * Sun Microsystems, Inc. confidential
10 * All rights reserved
11 */
12
13
14/*******************************************************************************
15* Header Files *
16*******************************************************************************/
17#include <sys/types.h>
18#include <sys/mntent.h>
19#include <sys/param.h>
20#include <sys/modctl.h>
21#include <sys/mount.h>
22#include <sys/policy.h>
23#include <sys/ddi.h>
24#include <sys/sunddi.h>
25#include "vboxvfs.h"
26
27#if defined(DEBUG_ramshankar) && !defined(LOG_ENABLED)
28# define LOG_ENABLED
29# define LOG_TO_BACKDOOR
30#endif
31#include <VBox/log.h>
32#include <iprt/string.h>
33#include <iprt/mem.h>
34#include <iprt/err.h>
35#if defined(DEBUG_ramshankar)
36# undef LogFlow
37# define LogFlow LogRel
38# undef Log
39# define Log LogRel
40#endif
41
42/*******************************************************************************
43* Defined Constants And Macros *
44*******************************************************************************/
45/** Mount Options */
46#define MNTOPT_VBOXVFS_UID "uid"
47#define MNTOPT_VBOXVFS_GID "gid"
48
49
50/*******************************************************************************
51* Internal Functions *
52*******************************************************************************/
53static int VBoxVFS_Init(int fType, char *pszName);
54static int VBoxVFS_Mount(vfs_t *pVFS, vnode_t *pVNode, struct mounta *pMount, cred_t *pCred);
55static int VBoxVFS_Unmount(vfs_t *pVFS, int fFlags, cred_t *pCred);
56static int VBoxVFS_Root(vfs_t *pVFS, vnode_t **ppVNode);
57static int VBoxVFS_Statfs(register vfs_t *pVFS, struct statvfs64 *pStat);
58static int VBoxVFS_VGet(vfs_t *pVFS, vnode_t **ppVNode, struct fid *pFid);
59static void VBoxVFS_FreeVFS(vfs_t *pVFS);
60
61static int vboxvfs_CheckMountPerm(vfs_t *pVFS, struct mounta *pMount, vnode_t *pVNodeSpec, cred_t *pCred);
62static int vboxvfs_GetIntOpt(vfs_t *pVFS, char *pszOpt, int *pValue);
63
64
65/*******************************************************************************
66* Structures and Typedefs *
67*******************************************************************************/
68/**
69 * mntopts_t: mount options table array
70 */
71static mntopt_t g_VBoxVFSMountOptions[] =
72{
73 /* Option Name Cancel Opt. Default Arg Flags Data */
74 { MNTOPT_VBOXVFS_UID, NULL, "0", MO_DEFAULT | MO_HASVALUE, NULL },
75 { MNTOPT_VBOXVFS_GID, NULL, "0", MO_DEFAULT | MO_HASVALUE, NULL }
76};
77
78/**
79 * mntopts_t: mount options table prototype
80 */
81static mntopts_t g_VBoxVFSMountTableProt =
82{
83 sizeof(g_VBoxVFSMountOptions) / sizeof(mntopt_t),
84 g_VBoxVFSMountOptions
85};
86
87/**
88 * vfsdef_t: driver specific mount options
89 */
90static vfsdef_t g_VBoxVFSDef =
91{
92 VFSDEF_VERSION,
93 DEVICE_NAME,
94 VBoxVFS_Init,
95 VSW_HASPROTO,
96 &g_VBoxVFSMountTableProt
97};
98
99/**
100 * modlfs: loadable file system
101 */
102static struct modlfs g_VBoxVFSLoadMod =
103{
104 &mod_fsops, /* extern from kernel */
105 DEVICE_DESC,
106 &g_VBoxVFSDef
107};
108
109/**
110 * modlinkage: export install/remove/info to the kernel
111 */
112static struct modlinkage g_VBoxVFSModLinkage =
113{
114 MODREV_1, /* loadable module system revision */
115 &g_VBoxVFSLoadMod,
116 NULL /* terminate array of linkage structures */
117};
118
119
120/*******************************************************************************
121* Global Variables *
122*******************************************************************************/
123/** Opaque pointer to list of states. */
124static void *g_pVBoxVFSState;
125/** GCC C++ hack. */
126unsigned __gxx_personality_v0 = 0xdecea5ed;
127/** Global connection to the client. */
128VBSFCLIENT g_VBoxVFSClient;
129/** Global VFS Operations pointer. */
130vfsops_t *g_pVBoxVFS_vfsops;
131/** The file system type identifier. */
132static int g_VBoxVFSType;
133
134
135/**
136 * Kernel entry points
137 */
138int _init(void)
139{
140 LogFlow((DEVICE_NAME ":_init\n"));
141
142 return mod_install(&g_VBoxVFSModLinkage);;
143}
144
145
146int _fini(void)
147{
148 LogFlow((DEVICE_NAME ":_fini\n"));
149
150 int rc = mod_remove(&g_VBoxVFSModLinkage);
151 if (rc)
152 return rc;
153
154 /* Blow away the operation vectors*/
155 vfs_freevfsops_by_type(g_VBoxVFSType);
156 vn_freevnodeops(g_pVBoxVFS_vnodeops);
157}
158
159
160int _info(struct modinfo *pModInfo)
161{
162 LogFlow((DEVICE_NAME ":_info\n"));
163
164 return mod_info(&g_VBoxVFSModLinkage, pModInfo);
165}
166
167
168static int VBoxVFS_Init(int fType, char *pszName)
169{
170 int rc;
171
172 LogFlow((DEVICE_NAME ":VBoxVFS_Init\n"));
173
174 g_VBoxVFSType = fType;
175
176 /* Initialize the R0 guest library. */
177 rc = vboxInit();
178 if (VBOX_SUCCESS(rc))
179 {
180 /* Connect to the host service. */
181 rc = vboxConnect(&g_VBoxVFSClient);
182 if (VBOX_SUCCESS(rc))
183 {
184 /* Use UTF-8 encoding. */
185 rc = vboxCallSetUtf8 (&g_VBoxVFSClient);
186 if (VBOX_SUCCESS(rc))
187 {
188 /* Fill up VFS user entry points. */
189 static const fs_operation_def_t s_VBoxVFS_vfsops_template[] =
190 {
191 VFSNAME_MOUNT, { .vfs_mount = VBoxVFS_Mount },
192 VFSNAME_UNMOUNT, { .vfs_unmount = VBoxVFS_Unmount },
193 VFSNAME_ROOT, { .vfs_root = VBoxVFS_Root },
194 VFSNAME_STATVFS, { .vfs_statvfs = VBoxVFS_Statfs },
195 VFSNAME_VGET, { .vfs_vget = VBoxVFS_VGet },
196 VFSNAME_FREEVFS, { .vfs_freevfs = VBoxVFS_FreeVFS },
197 NULL, NULL
198 };
199
200 rc = vfs_setfsops(fType, s_VBoxVFS_vfsops_template, &g_pVBoxVFS_vfsops);
201 if (!rc)
202 {
203 /* Set VNode operations. */
204 rc = vn_make_ops(pszName, g_VBoxVFS_vnodeops_template, &g_pVBoxVFS_vnodeops);
205 if (!rc)
206 {
207 LogFlow((DEVICE_NAME ":Successfully loaded vboxvfs.\n"));
208 return 0;
209 }
210 else
211 LogRel((DEVICE_NAME ":vn_make_ops failed. rc=%d\n", rc));
212 }
213 else
214 LogRel((DEVICE_NAME ":vfs_setfsops failed. rc=%d\n", rc));
215 }
216 else
217 {
218 LogRel((DEVICE_NAME ":vboxCallSetUtf8 failed. rc=%d\n", rc));
219 rc = EPROTO;
220 }
221 vboxDisconnect(&g_VBoxVFSClient);
222 }
223 else
224 {
225 LogRel((DEVICE_NAME ":Failed to connect to host! rc=%d\n", rc));
226 rc = ENXIO;
227 }
228 vboxUninit();
229 }
230 else
231 {
232 LogRel((DEVICE_NAME ":Failed to initialize R0 lib. rc=%d\n", rc));
233 rc = ENXIO;
234 }
235 return rc;
236}
237
238static int VBoxVFS_Mount(vfs_t *pVFS, vnode_t *pVNode, struct mounta *pMount, cred_t *pCred)
239{
240 int rc = 0;
241 int Uid = 0;
242 int Gid = 0;
243 char *pszShare = NULL;
244 size_t cbShare = NULL;
245 pathname_t PathName;
246 vboxvfs_vnode_t *pVNodeRoot = NULL;
247 vnode_t *pVNodeSpec = NULL;
248 vnode_t *pVNodeDev = NULL;
249 dev_t Dev = 0;
250 SHFLSTRING *pShflShareName = NULL;
251 RTFSOBJINFO FSInfo;
252 size_t cbShflShareName = 0;
253 vboxvfs_globinfo_t *pVBoxVFSGlobalInfo = NULL;
254 int AddrSpace = (pMount->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE;
255
256 LogFlow((DEVICE_NAME ":VBoxVFS_Mount\n"));
257
258 /* Check user credentials for mounting in the specified target. */
259 rc = secpolicy_fs_mount(pCred, pVNode, pVFS);
260 if (rc)
261 {
262 LogRel((DEVICE_NAME ":VBoxVFS_Mount: secpolicy_fs_mount failed! invalid credentials.rc=%d\n", rc));
263 return EPERM;
264 }
265
266 /* We can mount to only directories. */
267 if (pVNode->v_type != VDIR)
268 return ENOTDIR;
269
270 /* We don't support remounting. */
271 if (pMount->flags & MS_REMOUNT)
272 return ENOTSUP;
273
274 mutex_enter(&pVNode->v_lock);
275 if ( !(pMount->flags & MS_REMOUNT)
276 && !(pMount->flags & MS_OVERLAY)
277 && (pVNode->v_count != -1 || (pVNode->v_flag & VROOT)))
278 {
279 LogRel((DEVICE_NAME ":VBoxVFS_Mount: device busy.\n"));
280 mutex_exit(&pVNode->v_lock);
281 return EBUSY;
282 }
283 mutex_exit(&pVNode->v_lock);
284
285 /* From what I understood the options are already parsed at a higher level */
286 if ( (pMount->flags & MS_DATA)
287 && pMount->datalen > 0)
288 {
289 LogRel((DEVICE_NAME ":VBoxVFS_Mount: unparsed options not supported.\n"));
290 return EINVAL;
291 }
292
293 /* Get UID argument (optional). */
294 rc = vboxvfs_GetIntOpt(pVFS, MNTOPT_VBOXVFS_UID, &Uid);
295 if (rc < 0)
296 {
297 LogRel((DEVICE_NAME ":VBoxVFS_Mount: invalid uid value.\n"));
298 return EINVAL;
299 }
300
301 /* Get GID argument (optional). */
302 rc = vboxvfs_GetIntOpt(pVFS, MNTOPT_VBOXVFS_GID, &Gid);
303 if (rc < 0)
304 {
305 LogRel((DEVICE_NAME ":VBoxVFS_Mount: invalid gid value.\n"));
306 return EINVAL;
307 }
308
309 /* Get special (sharename). */
310 rc = pn_get(pMount->spec, AddrSpace, &PathName);
311 if (!rc)
312 {
313 /* Get the vnode for the special file for storing the device identifier and path. */
314 rc = lookupname(PathName.pn_path, AddrSpace, FOLLOW, NULLVPP, &pVNodeSpec);
315 if (!rc)
316 {
317 /* Check if user has permission to use the special file for mounting. */
318 rc = vboxvfs_CheckMountPerm(pVFS, pMount, pVNodeSpec, pCred);
319 VN_RELE(pVNodeSpec);
320 if (!rc)
321 {
322 Dev = pVNodeSpec->v_rdev;
323 memcpy(pszShare, PathName.pn_path, strlen(PathName.pn_path));
324 cbShare = strlen(pszShare);
325 }
326 else
327 LogRel((DEVICE_NAME ":VBoxVFS_Mount: invalid permissions to mount %s.rc=%d\n", pszShare, rc));
328 rc = EPERM;
329 }
330 else
331 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to lookup sharename.rc=%d\n", rc));
332 rc = EINVAL;
333 }
334 else
335 {
336 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to get special file path.rc=%d\n", rc));
337 rc = EINVAL;
338 }
339 pn_free(&PathName);
340
341 if (!rc)
342 return rc;
343
344 /* Get VNode of the special file being mounted. */
345 pVNodeDev = makespecvp(Dev, VBLK);
346 if (!IS_SWAPVP(pVNodeDev))
347 {
348 /* Open the vnode for mounting. */
349 rc = VOP_OPEN(&pVNodeDev, (pVFS->vfs_flag & VFS_RDONLY) ? FREAD : FREAD | FWRITE, pCred, NULL);
350 if (rc)
351 {
352 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to mount.\n"));
353 rc = EINVAL;
354 }
355 }
356 else
357 {
358 LogRel((DEVICE_NAME ":VBoxVFS_Mount: cannot mount from swap.\n"));
359 rc = EINVAL;
360 }
361 if (!rc)
362 {
363 VN_RELE(pVNodeDev);
364 return rc;
365 }
366
367 /* Allocate the global info. structure. */
368 pVBoxVFSGlobalInfo = RTMemAlloc(sizeof(*pVBoxVFSGlobalInfo));
369 if (pVBoxVFSGlobalInfo)
370 {
371 cbShflShareName = offsetof(SHFLSTRING, String.utf8) + cbShare + 1;
372 pShflShareName = RTMemAllocZ(cbShflShareName);
373 if (pShflShareName)
374 {
375 pShflShareName->u16Length = cbShflShareName;
376 pShflShareName->u16Size = cbShflShareName + 1;
377 memcpy (pShflShareName->String.utf8, pszShare, cbShare + 1);
378
379 rc = vboxCallMapFolder(&g_VBoxVFSClient, pShflShareName, &pVBoxVFSGlobalInfo->Map);
380 RTMemFree(pShflShareName);
381 if (VBOX_SUCCESS(rc))
382 rc = 0;
383 else
384 {
385 LogRel((DEVICE_NAME ":VBoxVFS_Mount: vboxCallMapFolder failed rc=%d\n", rc));
386 rc = EPROTO;
387 }
388 }
389 else
390 {
391 LogRel((DEVICE_NAME ":VBoxVFS_Mount: RTMemAllocZ failed to alloc %d bytes for ShFlShareName.\n", cbShflShareName));
392 rc = ENOMEM;
393 }
394 RTMemFree(pVBoxVFSGlobalInfo);
395 }
396 else
397 {
398 LogRel((DEVICE_NAME ":VBoxVFS_Mount: RTMemAlloc failed to alloc %d bytes for global struct.\n", sizeof(*pVBoxVFSGlobalInfo)));
399 rc = ENOMEM;
400 }
401
402 /* Undo work on failure. */
403 if (rc)
404 goto mntError1;
405
406 /* Initialize the per-filesystem mutex */
407 mutex_init(&pVBoxVFSGlobalInfo->MtxFS, "VBoxVFS_FSMtx", MUTEX_DEFAULT, NULL);
408
409 pVBoxVFSGlobalInfo->Uid = Uid;
410 pVBoxVFSGlobalInfo->Gid = Gid;
411 pVBoxVFSGlobalInfo->pVFS = pVFS;
412 pVBoxVFSGlobalInfo->pVNodeDev = pVNodeDev;
413 pVFS->vfs_data = pVBoxVFSGlobalInfo;
414 pVFS->vfs_fstype = g_VBoxVFSType;
415 pVFS->vfs_dev = Dev;
416 vfs_make_fsid(&pVFS->vfs_fsid, Dev, g_VBoxVFSType);
417
418 /* Allocate root vboxvfs_vnode_t object */
419 pVNodeRoot = RTMemAlloc(sizeof(*pVNodeRoot));
420 if (pVNodeRoot)
421 {
422 /* Initialize vnode protection mutex */
423 mutex_init(&pVNodeRoot->MtxContents, "VBoxVFS_VNodeMtx", MUTEX_DEFAULT, NULL);
424
425 pVBoxVFSGlobalInfo->pVNodeRoot = pVNodeRoot;
426
427 /* Allocate root path */
428 pVNodeRoot->pPath = RTMemAllocZ(sizeof(SHFLSTRING) + 1);
429 if (pVNodeRoot->pPath)
430 {
431 /* Initialize root path */
432 pVNodeRoot->pPath->u16Length = 1;
433 pVNodeRoot->pPath->u16Size = 2;
434 pVNodeRoot->pPath->String.utf8[0] = '/';
435 pVNodeRoot->pPath->String.utf8[1] = '\0';
436
437 /* Stat root node info from host */
438 rc = vboxvfs_Stat(__func__, pVBoxVFSGlobalInfo, pVNodeRoot->pPath, &FSInfo, B_FALSE);
439 if (!rc)
440 {
441 /* Initialize the root vboxvfs_node_t object */
442 vboxvfs_InitVNode(pVBoxVFSGlobalInfo, pVNodeRoot, &FSInfo);
443
444 /* Success! */
445 return 0;
446 }
447 else
448 LogRel((DEVICE_NAME ":VBoxVFS_Mount: vboxvfs_Stat failed rc(errno)=%d\n", rc));
449 RTMemFree(pVNodeRoot->pPath);
450 }
451 else
452 {
453 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to alloc memory for root node path.\n"));
454 rc = ENOMEM;
455 }
456 RTMemFree(pVNodeRoot);
457 }
458 else
459 {
460 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to alloc memory for root node.\n"));
461 rc = ENOMEM;
462 }
463
464 /* Undo work in reverse. */
465mntError1:
466 /* Just release the mount location. */
467 VOP_CLOSE(pVNodeDev, (pVFS->vfs_flag & VFS_RDONLY) ? FREAD : FREAD | FWRITE, 1, (offset_t)0, pCred, NULL);
468 VN_RELE(pVNodeDev);
469 return rc;
470}
471
472static int VBoxVFS_Unmount(vfs_t *pVFS, int fUnmount, cred_t *pCred)
473{
474 int rc;
475 vboxvfs_globinfo_t *pVBoxVFSGlobalInfo;
476
477 LogFlow((DEVICE_NAME ":VBoxVFS_Unmount.\n"));
478
479 /* Check if user can unmount. */
480 rc = secpolicy_fs_unmount(pCred, pVFS);
481 if (rc)
482 {
483 LogRel((DEVICE_NAME ":VBoxVFS_Unmount: insufficient privileges to unmount.rc=%d\n", rc));
484 return EPERM;
485 }
486
487 /* @todo -XXX - Not sure of supporting force unmounts. What this means is that a failed force mount could bring down
488 * the entire system as hanging about vnode releases would no longer be valid after unloading ourselves...
489 */
490 if (fUnmount & MS_FORCE)
491 pVFS->vfs_flag |= VFS_UNMOUNTED;
492
493 /* @todo implement ref-counting of active vnodes & check for busy state here. */
494 /* @todo mutex protection needed here */
495 pVBoxVFSGlobalInfo = VFS_TO_VBOXVFS(pVFS);
496
497 rc = vboxCallUnmapFolder(&g_VBoxVFSClient, &pVBoxVFSGlobalInfo->Map);
498 if (VBOX_FAILURE(rc))
499 LogRel((DEVICE_NAME ":VBoxVFS_Unmount: failed to unmap shared folder. rc=%d\n", rc));
500
501 VN_RELE(VBOXVN_TO_VN(pVBoxVFSGlobalInfo->pVNodeRoot));
502
503 RTMemFree(pVBoxVFSGlobalInfo->pVNodeRoot->pPath);
504 RTMemFree(pVBoxVFSGlobalInfo->pVNodeRoot);
505 RTMemFree(pVBoxVFSGlobalInfo);
506 pVBoxVFSGlobalInfo = NULL;
507 pVFS->vfs_data = NULL;
508
509 return 0;
510}
511
512static int VBoxVFS_Root(vfs_t *pVFS, vnode_t **ppVNode)
513{
514 vboxvfs_globinfo_t *pVBoxVFSGlobalInfo = VFS_TO_VBOXVFS(pVFS);
515 *ppVNode = VBOXVN_TO_VN(pVBoxVFSGlobalInfo->pVNodeRoot);
516 VN_HOLD(*ppVNode);
517
518 return 0;
519}
520
521static int VBoxVFS_Statfs(register vfs_t *pVFS, struct statvfs64 *pStat)
522{
523 SHFLVOLINFO VolumeInfo;
524 uint32_t cbBuffer;
525 vboxvfs_globinfo_t *pVBoxVFSGlobalInfo;
526 dev32_t Dev32;
527 int rc;
528
529 pVBoxVFSGlobalInfo = VFS_TO_VBOXVFS(pVFS);
530 cbBuffer = sizeof(VolumeInfo);
531 rc = vboxCallFSInfo(&g_VBoxVFSClient, &pVBoxVFSGlobalInfo->Map, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbBuffer,
532 (PSHFLDIRINFO)&VolumeInfo);
533 if (VBOX_FAILURE(rc))
534 return RTErrConvertToErrno(rc);
535
536 bzero(pStat, sizeof(*pStat));
537 cmpldev(&Dev32, pVFS->vfs_dev);
538 pStat->f_fsid = Dev32;
539 pStat->f_flag = vf_to_stf(pVFS->vfs_flag);
540 pStat->f_bsize = VolumeInfo.ulBytesPerAllocationUnit;
541 pStat->f_frsize = VolumeInfo.ulBytesPerAllocationUnit;
542 pStat->f_bfree = VolumeInfo.ullAvailableAllocationBytes / VolumeInfo.ulBytesPerAllocationUnit;
543 pStat->f_bavail = VolumeInfo.ullAvailableAllocationBytes / VolumeInfo.ulBytesPerAllocationUnit;
544 pStat->f_blocks = VolumeInfo.ullTotalAllocationBytes / VolumeInfo.ulBytesPerAllocationUnit;
545 pStat->f_files = 1000;
546 pStat->f_ffree = 1000; /* don't return 0 here since the guest may think that it is not possible to create any more files */
547 pStat->f_namemax = 255; /* @todo is this correct?? */
548
549 strlcpy(pStat->f_basetype, vfssw[pVFS->vfs_fstype].vsw_name, sizeof(pStat->f_basetype));
550 strlcpy(pStat->f_fstr, DEVICE_NAME, sizeof(pStat->f_fstr));
551
552 return 0;
553}
554
555static int VBoxVFS_VGet(vfs_t *pVFS, vnode_t **ppVNode, struct fid *pFid)
556{
557 /* -- TODO -- */
558 return 0;
559}
560
561static void VBoxVFS_FreeVFS(vfs_t *pVFS)
562{
563 vboxDisconnect(&g_VBoxVFSClient);
564 vboxUninit();
565}
566
567static int vboxvfs_CheckMountPerm(vfs_t *pVFS, struct mounta *pMount, vnode_t *pVNodeSpec, cred_t *pCred)
568{
569 /* Check if user has the rights to mount the special file. */
570 int fOpen = FREAD | FWRITE;
571 int fAccess = VREAD | VWRITE;
572 int rc;
573
574 if (pVNodeSpec->v_type != VBLK)
575 return ENOTBLK;
576
577 if ( (pVFS->vfs_flag & VFS_RDONLY)
578 || (pMount->flags & MS_RDONLY))
579 {
580 fOpen = FREAD;
581 fAccess = VREAD;
582 }
583
584 rc = VOP_ACCESS(pVNodeSpec, fAccess, 0, pCred, NULL /* caller_context */);
585 if (!rc)
586 rc = secpolicy_spec_open(pCred, pVNodeSpec, fOpen);
587
588 return rc;
589}
590
591static int vboxvfs_GetIntOpt(vfs_t *pVFS, char *pszOpt, int *pValue)
592{
593 int rc;
594 long Val;
595 char *pchOpt = NULL;
596 char *pchEnd = NULL;
597
598 rc = vfs_optionisset(pVFS, pszOpt, &pchOpt);
599 if (rc)
600 {
601 rc = ddi_strtol(pchOpt, &pchEnd, 10 /* base */, &Val);
602 if ( !rc
603 && Val > INT_MIN
604 && Val < INT_MAX
605 && pchEnd == pchOpt + strlen(pchOpt))
606 {
607 *pValue = (int)Val;
608 return 0;
609 }
610 return -1;
611 }
612 return 1;
613}
614
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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