VirtualBox

source: vbox/trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c@ 28121

Last change on this file since 28121 was 27733, checked in by vboxsync, 15 years ago

Additions/Solaris: Sharedfolders error code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 16.1 KB
Line 
1/** @file
2 * VirtualBox File System for Solaris Guests, provider implementation.
3 */
4
5/*
6 * Copyright (C) 2008 Sun Microsystems, Inc.
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
17 * Clara, CA 95054 USA or visit http://www.sun.com if you need
18 * additional information or have any questions.
19 */
20/*
21 * Provider interfaces for shared folder file system.
22 */
23
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <sys/mntent.h>
27#include <sys/param.h>
28#include <sys/modctl.h>
29#include <sys/mount.h>
30#include <sys/policy.h>
31#include <sys/atomic.h>
32#include <sys/sysmacros.h>
33#include <sys/ddi.h>
34#include <sys/sunddi.h>
35#include "vboxfs_prov.h"
36#ifdef u
37#undef u
38#endif
39#include "../../common/VBoxGuestLib/VBoxCalls.h"
40
41#define SFPROV_VERSION 1
42
43static VBSFCLIENT vbox_client;
44
45/*
46 * utility to create strings
47 */
48static SHFLSTRING *
49sfprov_string(char *path, int *sz)
50{
51 SHFLSTRING *str;
52 int len = strlen(path);
53
54 *sz = len + 1 + sizeof (*str) - sizeof (str->String);
55 str = kmem_zalloc(*sz, KM_SLEEP);
56 str->u16Size = len + 1;
57 str->u16Length = len;
58 strcpy(str->String.utf8, path);
59 return (str);
60}
61
62sfp_connection_t *
63sfprov_connect(int version)
64{
65 /*
66 * only one version for now, so must match
67 */
68 int rc = -1;
69 if (version != SFPROV_VERSION)
70 {
71 cmn_err(CE_WARN, "sfprov_connect: wrong version");
72 return NULL;
73 }
74 rc = vboxInit();
75 if (RT_SUCCESS(rc))
76 {
77 rc = vboxConnect(&vbox_client);
78 if (RT_SUCCESS(rc))
79 {
80 rc = vboxCallSetUtf8(&vbox_client);
81 if (RT_SUCCESS(rc))
82 {
83 return ((sfp_connection_t *)&vbox_client);
84 }
85 else
86 cmn_err(CE_WARN, "sfprov_connect: vboxCallSetUtf8() failed");
87
88 vboxDisconnect(&vbox_client);
89 }
90 else
91 cmn_err(CE_WARN, "sfprov_connect: vboxConnect() failed rc=%d", rc);
92 vboxUninit();
93 }
94 else
95 cmn_err(CE_WARN, "sfprov_connect: vboxInit() failed rc=%d", rc);
96}
97
98void
99sfprov_disconnect(sfp_connection_t *conn)
100{
101 if (conn != (sfp_connection_t *)&vbox_client)
102 cmn_err(CE_WARN, "sfprov_disconnect: bad argument");
103 vboxDisconnect(&vbox_client);
104 vboxUninit();
105}
106
107
108/*
109 * representation of an active mount point
110 */
111struct sfp_mount {
112 VBSFMAP map;
113};
114
115int
116sfprov_mount(sfp_connection_t *conn, char *path, sfp_mount_t **mnt)
117{
118 sfp_mount_t *m;
119 SHFLSTRING *str;
120 int size;
121 int rc;
122
123 m = kmem_zalloc(sizeof (*m), KM_SLEEP);
124 str = sfprov_string(path, &size);
125 rc = vboxCallMapFolder(&vbox_client, str, &m->map);
126 if (!RT_SUCCESS(rc)) {
127 cmn_err(CE_WARN, "sfprov_mount: vboxCallMapFolder() failed");
128 kmem_free(m, sizeof (*m));
129 *mnt = NULL;
130 rc = EINVAL;
131 } else {
132 *mnt = m;
133 rc = 0;
134 }
135 kmem_free(str, size);
136 return (rc);
137}
138
139int
140sfprov_unmount(sfp_mount_t *mnt)
141{
142 int rc;
143
144 rc = vboxCallUnmapFolder(&vbox_client, &mnt->map);
145 if (!RT_SUCCESS(rc)) {
146 cmn_err(CE_WARN, "sfprov_mount: vboxCallUnmapFolder() failed");
147 rc = EINVAL;
148 } else {
149 rc = 0;
150 }
151 kmem_free(mnt, sizeof (*mnt));
152 return (rc);
153}
154
155/*
156 * query information about a mounted file system
157 */
158int
159sfprov_get_blksize(sfp_mount_t *mnt, uint64_t *blksize)
160{
161 int rc;
162 SHFLVOLINFO info;
163 uint32_t bytes = sizeof(SHFLVOLINFO);
164
165 rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
166 (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
167 if (RT_FAILURE(rc))
168 return (EINVAL);
169 *blksize = info.ulBytesPerAllocationUnit;
170 return (0);
171}
172
173int
174sfprov_get_blksused(sfp_mount_t *mnt, uint64_t *blksused)
175{
176 int rc;
177 SHFLVOLINFO info;
178 uint32_t bytes = sizeof(SHFLVOLINFO);
179
180 rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
181 (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
182 if (RT_FAILURE(rc))
183 return (EINVAL);
184 *blksused = (info.ullTotalAllocationBytes -
185 info.ullAvailableAllocationBytes) / info.ulBytesPerAllocationUnit;
186 return (0);
187}
188
189int
190sfprov_get_blksavail(sfp_mount_t *mnt, uint64_t *blksavail)
191{
192 int rc;
193 SHFLVOLINFO info;
194 uint32_t bytes = sizeof(SHFLVOLINFO);
195
196 rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
197 (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
198 if (RT_FAILURE(rc))
199 return (EINVAL);
200 *blksavail =
201 info.ullAvailableAllocationBytes / info.ulBytesPerAllocationUnit;
202 return (0);
203}
204
205int
206sfprov_get_maxnamesize(sfp_mount_t *mnt, uint32_t *maxnamesize)
207{
208 int rc;
209 SHFLVOLINFO info;
210 uint32_t bytes = sizeof(SHFLVOLINFO);
211
212 rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
213 (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
214 if (RT_FAILURE(rc))
215 return (EINVAL);
216 *maxnamesize = info.fsProperties.cbMaxComponent;
217 return (0);
218}
219
220int
221sfprov_get_readonly(sfp_mount_t *mnt, uint32_t *readonly)
222{
223 int rc;
224 SHFLVOLINFO info;
225 uint32_t bytes = sizeof(SHFLVOLINFO);
226
227 rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
228 (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
229 if (RT_FAILURE(rc))
230 return (EINVAL);
231 *readonly = info.fsProperties.fReadOnly;
232 return (0);
233}
234
235/*
236 * File operations: open/close/read/write/etc.
237 *
238 * open/create can return any relevant errno, however ENOENT
239 * generally means that the host file didn't exist.
240 */
241struct sfp_file {
242 SHFLHANDLE handle;
243 VBSFMAP map; /* need this again for the close operation */
244};
245
246int
247sfprov_create(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
248{
249 int rc;
250 SHFLCREATEPARMS parms;
251 SHFLSTRING *str;
252 int size;
253 sfp_file_t *newfp;
254
255 str = sfprov_string(path, &size);
256 parms.Handle = 0;
257 parms.Info.cbObject = 0;
258 parms.CreateFlags = SHFL_CF_ACT_CREATE_IF_NEW |
259 SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACCESS_READWRITE;
260 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
261 kmem_free(str, size);
262
263 if (RT_FAILURE(rc))
264 return (EINVAL);
265 if (parms.Handle == SHFL_HANDLE_NIL) {
266 if (parms.Result == SHFL_FILE_EXISTS)
267 return (EEXIST);
268 return (ENOENT);
269 }
270 newfp = kmem_alloc(sizeof(sfp_file_t), KM_SLEEP);
271 newfp->handle = parms.Handle;
272 newfp->map = mnt->map;
273 *fp = newfp;
274 return (0);
275}
276
277int
278sfprov_open(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
279{
280 int rc;
281 SHFLCREATEPARMS parms;
282 SHFLSTRING *str;
283 int size;
284 sfp_file_t *newfp;
285
286 /*
287 * First we attempt to open it read/write. If that fails we
288 * try read only.
289 */
290 bzero(&parms, sizeof(parms));
291 str = sfprov_string(path, &size);
292 parms.Handle = SHFL_HANDLE_NIL;
293 parms.Info.cbObject = 0;
294 parms.CreateFlags = SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READWRITE;
295 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
296 if (RT_FAILURE(rc) && rc != VERR_ACCESS_DENIED) {
297 kmem_free(str, size);
298 return RTErrConvertToErrno(rc);
299 }
300 if (parms.Handle == SHFL_HANDLE_NIL) {
301 if (parms.Result == SHFL_PATH_NOT_FOUND ||
302 parms.Result == SHFL_FILE_NOT_FOUND) {
303 kmem_free(str, size);
304 return (ENOENT);
305 }
306 parms.CreateFlags =
307 SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ;
308 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
309 if (RT_FAILURE(rc)) {
310 kmem_free(str, size);
311 return RTErrConvertToErrno(rc);
312 }
313 if (parms.Handle == SHFL_HANDLE_NIL) {
314 kmem_free(str, size);
315 return (ENOENT);
316 }
317 }
318 newfp = kmem_alloc(sizeof(sfp_file_t), KM_SLEEP);
319 newfp->handle = parms.Handle;
320 newfp->map = mnt->map;
321 *fp = newfp;
322 return (0);
323}
324
325int
326sfprov_trunc(sfp_mount_t *mnt, char *path)
327{
328 int rc;
329 SHFLCREATEPARMS parms;
330 SHFLSTRING *str;
331 int size;
332 sfp_file_t *newfp;
333
334 /*
335 * open it read/write.
336 */
337 str = sfprov_string(path, &size);
338 parms.Handle = 0;
339 parms.Info.cbObject = 0;
340 parms.CreateFlags = SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READWRITE |
341 SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
342 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
343
344 if (RT_FAILURE(rc)) {
345 kmem_free(str, size);
346 return (EINVAL);
347 }
348 (void)vboxCallClose(&vbox_client, &mnt->map, parms.Handle);
349 return (0);
350}
351
352int
353sfprov_close(sfp_file_t *fp)
354{
355 int rc;
356
357 rc = vboxCallClose(&vbox_client, &fp->map, fp->handle);
358 kmem_free(fp, sizeof(sfp_file_t));
359 return (0);
360}
361
362int
363sfprov_read(sfp_file_t *fp, char *buffer, uint64_t offset, uint32_t *numbytes)
364{
365 int rc;
366
367 rc = vboxCallRead(&vbox_client, &fp->map, fp->handle, offset,
368 numbytes, (uint8_t *)buffer, 0); /* what is that last arg? */
369 if (RT_FAILURE(rc))
370 return (EINVAL);
371 return (0);
372}
373
374int
375sfprov_write(sfp_file_t *fp, char *buffer, uint64_t offset, uint32_t *numbytes)
376{
377 int rc;
378
379 rc = vboxCallWrite(&vbox_client, &fp->map, fp->handle, offset,
380 numbytes, (uint8_t *)buffer, 0); /* what is that last arg? */
381 if (RT_FAILURE(rc))
382 return (EINVAL);
383 return (0);
384}
385
386
387static int
388sfprov_getinfo(sfp_mount_t *mnt, char *path, RTFSOBJINFO *info)
389{
390 int rc;
391 SHFLCREATEPARMS parms;
392 SHFLSTRING *str;
393 int size;
394
395 str = sfprov_string(path, &size);
396 parms.Handle = 0;
397 parms.Info.cbObject = 0;
398 parms.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
399 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
400 kmem_free(str, size);
401
402 if (RT_FAILURE(rc))
403 return (EINVAL);
404 if (parms.Result != SHFL_FILE_EXISTS)
405 return (ENOENT);
406 *info = parms.Info;
407 return (0);
408}
409
410/*
411 * get information about a file (or directory)
412 */
413int
414sfprov_get_mode(sfp_mount_t *mnt, char *path, mode_t *mode)
415{
416 int rc;
417 RTFSOBJINFO info;
418 mode_t m = 0;
419
420 rc = sfprov_getinfo(mnt, path, &info);
421 if (rc)
422 return (rc);
423 if (RTFS_IS_DIRECTORY(info.Attr.fMode))
424 m |= S_IFDIR;
425 else if (RTFS_IS_FILE(info.Attr.fMode))
426 m |= S_IFREG;
427 else if (RTFS_IS_FIFO(info.Attr.fMode))
428 m |= S_IFDIR;
429 else if (RTFS_IS_DEV_CHAR(info.Attr.fMode))
430 m |= S_IFCHR;
431 else if (RTFS_IS_DEV_BLOCK(info.Attr.fMode))
432 m |= S_IFBLK;
433 else if (RTFS_IS_SYMLINK(info.Attr.fMode))
434 m |= S_IFLNK;
435 else if (RTFS_IS_SOCKET(info.Attr.fMode))
436 m |= S_IFSOCK;
437
438 if (info.Attr.fMode & RTFS_UNIX_IRUSR)
439 m |= S_IRUSR;
440 if (info.Attr.fMode & RTFS_UNIX_IWUSR)
441 m |= S_IWUSR;
442 if (info.Attr.fMode & RTFS_UNIX_IXUSR)
443 m |= S_IXUSR;
444 if (info.Attr.fMode & RTFS_UNIX_IRGRP)
445 m |= S_IRGRP;
446 if (info.Attr.fMode & RTFS_UNIX_IWGRP)
447 m |= S_IWGRP;
448 if (info.Attr.fMode & RTFS_UNIX_IXGRP)
449 m |= S_IXGRP;
450 if (info.Attr.fMode & RTFS_UNIX_IROTH)
451 m |= S_IROTH;
452 if (info.Attr.fMode & RTFS_UNIX_IWOTH)
453 m |= S_IWOTH;
454 if (info.Attr.fMode & RTFS_UNIX_IXOTH)
455 m |= S_IXOTH;
456 *mode = m;
457 return (0);
458}
459
460int
461sfprov_get_size(sfp_mount_t *mnt, char *path, uint64_t *size)
462{
463 int rc;
464 RTFSOBJINFO info;
465
466 rc = sfprov_getinfo(mnt, path, &info);
467 if (rc)
468 return (rc);
469 *size = info.cbObject;
470 return (0);
471}
472
473int
474sfprov_get_atime(sfp_mount_t *mnt, char *path, timestruc_t *time)
475{
476 int rc;
477 RTFSOBJINFO info;
478 uint64_t nanosec;
479
480 rc = sfprov_getinfo(mnt, path, &info);
481 if (rc)
482 return (rc);
483 nanosec = RTTimeSpecGetNano(&info.AccessTime);
484 time->tv_sec = nanosec / 1000000000;
485 time->tv_nsec = nanosec % 1000000000;
486 return (0);
487}
488
489int
490sfprov_get_mtime(sfp_mount_t *mnt, char *path, timestruc_t *time)
491{
492 int rc;
493 RTFSOBJINFO info;
494 uint64_t nanosec;
495
496 rc = sfprov_getinfo(mnt, path, &info);
497 if (rc)
498 return (rc);
499 nanosec = RTTimeSpecGetNano(&info.ModificationTime);
500 time->tv_sec = nanosec / 1000000000;
501 time->tv_nsec = nanosec % 1000000000;
502 return (0);
503}
504
505int
506sfprov_get_ctime(sfp_mount_t *mnt, char *path, timestruc_t *time)
507{
508 int rc;
509 RTFSOBJINFO info;
510 uint64_t nanosec;
511
512 rc = sfprov_getinfo(mnt, path, &info);
513 if (rc)
514 return (rc);
515 nanosec = RTTimeSpecGetNano(&info.ChangeTime);
516 time->tv_sec = nanosec / 1000000000;
517 time->tv_nsec = nanosec % 1000000000;
518 return (0);
519}
520
521/*
522 * Directory operations
523 */
524int
525sfprov_mkdir(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
526{
527 int rc;
528 SHFLCREATEPARMS parms;
529 SHFLSTRING *str;
530 int size;
531 sfp_file_t *newfp;
532
533 str = sfprov_string(path, &size);
534 parms.Handle = 0;
535 parms.Info.cbObject = 0;
536 parms.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW |
537 SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACCESS_READ;
538 rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
539 kmem_free(str, size);
540
541 if (RT_FAILURE(rc))
542 return (EINVAL);
543 if (parms.Handle == SHFL_HANDLE_NIL) {
544 if (parms.Result == SHFL_FILE_EXISTS)
545 return (EEXIST);
546 return (ENOENT);
547 }
548 newfp = kmem_alloc(sizeof(sfp_file_t), KM_SLEEP);
549 newfp->handle = parms.Handle;
550 newfp->map = mnt->map;
551 *fp = newfp;
552 return (0);
553}
554
555int
556sfprov_remove(sfp_mount_t *mnt, char *path)
557{
558 int rc;
559 SHFLSTRING *str;
560 int size;
561
562 str = sfprov_string(path, &size);
563 rc = vboxCallRemove(&vbox_client, &mnt->map, str, SHFL_REMOVE_FILE);
564 kmem_free(str, size);
565 if (RT_FAILURE(rc))
566 return (EINVAL);
567 return (0);
568}
569
570int
571sfprov_rmdir(sfp_mount_t *mnt, char *path)
572{
573 int rc;
574 SHFLSTRING *str;
575 int size;
576
577 str = sfprov_string(path, &size);
578 rc = vboxCallRemove(&vbox_client, &mnt->map, str, SHFL_REMOVE_DIR);
579 kmem_free(str, size);
580 if (RT_FAILURE(rc))
581 return (RTErrConvertToErrno(rc));
582 return (0);
583}
584
585int
586sfprov_rename(sfp_mount_t *mnt, char *from, char *to, uint_t is_dir)
587{
588 int rc;
589 SHFLSTRING *old, *new;
590 int old_size, new_size;
591
592 old = sfprov_string(from, &old_size);
593 new = sfprov_string(to, &new_size);
594 rc = vboxCallRename(&vbox_client, &mnt->map, old, new,
595 (is_dir ? SHFL_RENAME_DIR : SHFL_RENAME_FILE) |
596 SHFL_RENAME_REPLACE_IF_EXISTS);
597 kmem_free(old, old_size);
598 kmem_free(new, new_size);
599 if (RT_FAILURE(rc))
600 return (RTErrConvertToErrno(rc));
601 return (0);
602}
603
604
605/*
606 * Read all filenames in a directory.
607 *
608 * - success - all entries read and returned
609 * - ENOENT - Couldn't open the directory for reading
610 * - EINVAL - Internal error of some kind
611 *
612 * On successful return, buffer[0] is the start of an array of "char *"
613 * pointers to the filenames. The array ends with a NULL pointer.
614 * The remaining storage in buffer after that NULL pointer is where the
615 * filename strings actually are.
616 *
617 * On input nents is the max number of filenames the requestor can handle.
618 * On output nents is the number of entries at buff[0]
619 *
620 * The caller is responsible for freeing the returned buffer.
621 */
622int
623sfprov_readdir(
624 sfp_mount_t *mnt,
625 char *path,
626 void **buffer,
627 size_t *buffersize,
628 uint32_t *nents)
629{
630 int error;
631 char *cp;
632 int len;
633 SHFLSTRING *mask_str = NULL; /* must be path with "/*" appended */
634 int mask_size;
635 sfp_file_t *fp;
636 void *buff_start = NULL;
637 char **curr_b;
638 char *buff_end;
639 size_t buff_size;
640 static char infobuff[2 * MAXNAMELEN]; /* not on stack!! */
641 SHFLDIRINFO *info = (SHFLDIRINFO *)&infobuff;
642 uint32_t numbytes = sizeof (infobuff);
643 uint32_t justone;
644 uint32_t cnt;
645 char **name_ptrs;
646
647 *buffer = NULL;
648 *buffersize = 0;
649 if (*nents == 0)
650 return (EINVAL);
651 error = sfprov_open(mnt, path, &fp);
652 if (error != 0)
653 return (ENOENT);
654
655 /*
656 * Create mask that VBox expects. This needs to be the directory path,
657 * plus a "*" wildcard to get all files.
658 */
659 len = strlen(path) + 3;
660 cp = kmem_alloc(len, KM_SLEEP);
661 strcpy(cp, path);
662 strcat(cp, "/*");
663 mask_str = sfprov_string(cp, &mask_size);
664 kmem_free(cp, len);
665
666 /*
667 * Allocate the buffer to use for return values. Each entry
668 * in the buffer will have a pointer and the string itself.
669 * The pointers go in the front of the buffer, the strings
670 * at the end.
671 */
672 buff_size = *nents * (sizeof(char *) + MAXNAMELEN);
673 name_ptrs = buff_start = kmem_alloc(buff_size, KM_SLEEP);
674 cp = (char *)buff_start + buff_size;
675
676 /*
677 * Now loop using vboxCallDirInfo to get one file name at a time
678 */
679 cnt = 0;
680 for (;;) {
681 justone = 1;
682 numbytes = sizeof (infobuff);
683 error = vboxCallDirInfo(&vbox_client, &fp->map, fp->handle,
684 mask_str, SHFL_LIST_RETURN_ONE, cnt, &numbytes, info,
685 &justone);
686 if (error == VERR_NO_MORE_FILES) {
687 break;
688 }
689 if (error == VERR_NO_TRANSLATION) {
690 continue; /* ?? just skip this one */
691 }
692 if (error != VINF_SUCCESS || justone != 1) {
693 error = EINVAL;
694 goto done;
695 }
696
697 /*
698 * Put this name in the buffer, stop if we run out of room.
699 */
700 cp -= strlen(info->name.String.utf8) + 1;
701 if (cp < (char *)(&name_ptrs[cnt + 2]))
702 break;
703 strcpy(cp, info->name.String.utf8);
704 name_ptrs[cnt] = cp;
705 ++cnt;
706 }
707 error = 0;
708 name_ptrs[cnt] = NULL;
709 *nents = cnt;
710 *buffer = buff_start;
711 *buffersize = buff_size;
712done:
713 if (error != 0)
714 kmem_free(buff_start, buff_size);
715 kmem_free(mask_str, mask_size);
716 sfprov_close(fp);
717 return (error);
718}
Note: See TracBrowser for help on using the repository browser.

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