| // Copyright 2017 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| package ramdisk | |
| // #cgo LDFLAGS: -lramdevice-client -lfdio | |
| // #include <ramdevice-client/ramdisk.h> | |
| // #include <lib/fdio/fd.h> | |
| // #include <lib/fdio/fdio.h> | |
| // #include <lib/fdio/spawn.h> | |
| // #include <lib/fdio/vfs.h> | |
| // #include <string.h> | |
| // | |
| // zx_status_t ramdisk_blobfs_mkfs(const ramdisk_client_t* client, zx_handle_t* process_out) { | |
| // zx_status_t status = ZX_OK; | |
| // fdio_spawn_action_t actions[1] = { | |
| // { | |
| // .action = FDIO_SPAWN_ACTION_ADD_HANDLE, | |
| // .h = { | |
| // .id = FS_HANDLE_BLOCK_DEVICE_ID, | |
| // .handle = ZX_HANDLE_INVALID, | |
| // } | |
| // }, | |
| // }; | |
| // | |
| // status = fdio_fd_clone(ramdisk_get_block_fd(client), &actions[0].h.handle); | |
| // if (status != ZX_OK) { | |
| // fprintf(stderr, "failed to get service handle! %d\n", status); | |
| // return status; | |
| // } | |
| // if (actions[0].h.handle == ZX_HANDLE_INVALID) { | |
| // fprintf(stderr, "handle invalid after clone\n"); | |
| // return ZX_ERR_INTERNAL; | |
| // } | |
| // char* argv[5] = {"/pkg/bin/blobfs", "-m", "-j", "mkfs", 0}; | |
| // return fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, argv[0], (const char* const *)argv, NULL, 1, actions, process_out, NULL); | |
| // } | |
| // | |
| // zx_status_t ramdisk_blobfs_mount(const ramdisk_client_t* client, zx_handle_t dir_request, zx_handle_t* process_out) { | |
| // zx_status_t status = ZX_OK; | |
| // fdio_spawn_action_t actions[2] = { | |
| // { | |
| // .action = FDIO_SPAWN_ACTION_ADD_HANDLE, | |
| // .h = { | |
| // .id = FS_HANDLE_BLOCK_DEVICE_ID, | |
| // .handle = ZX_HANDLE_INVALID, | |
| // } | |
| // }, | |
| // { | |
| // .action = FDIO_SPAWN_ACTION_ADD_HANDLE, | |
| // .h = { | |
| // .id = FS_HANDLE_ROOT_ID, | |
| // .handle = dir_request, | |
| // } | |
| // } | |
| // }; | |
| // | |
| // status = fdio_fd_clone(ramdisk_get_block_fd(client), &actions[0].h.handle); | |
| // if (status != ZX_OK) { | |
| // fprintf(stderr, "failed to get service handle! %d\n", status); | |
| // return status; | |
| // } | |
| // if (actions[0].h.handle == ZX_HANDLE_INVALID) { | |
| // fprintf(stderr, "handle invalid after clone\n"); | |
| // return ZX_ERR_INTERNAL; | |
| // } | |
| // char* argv[5] = {"/pkg/bin/blobfs", "-m", "-j", "mount", 0}; | |
| // return fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, argv[0], (const char* const *)argv, NULL, 2, actions, process_out, NULL); | |
| // } | |
| import "C" | |
| import ( | |
| "os" | |
| "runtime" | |
| "syscall/zx" | |
| "syscall/zx/fdio" | |
| zxio "syscall/zx/io" | |
| "go.fuchsia.dev/fuchsia/src/sys/pkg/bin/pkgfs/iou" | |
| ) | |
| type Ramdisk struct { | |
| ramdisk_client *C.struct_ramdisk_client | |
| proc zx.Handle | |
| dir *fdio.Directory | |
| } | |
| // New constructs and creates a ramdisk of size bytes at the given path. | |
| func New(size int) (*Ramdisk, error) { | |
| r := &Ramdisk{} | |
| return r, r.create(512, uint64(size)/512) | |
| } | |
| func (r *Ramdisk) create(blkSz uint64, blkCnt uint64) error { | |
| n := C.ramdisk_create(C.uint64_t(blkSz), C.uint64_t(blkCnt), &r.ramdisk_client) | |
| if n == 0 { | |
| runtime.SetFinalizer(r, finalizeRamdisk) | |
| return nil | |
| } | |
| return &zx.Error{Status: zx.Status(n), Text: "ramdisk_create"} | |
| } | |
| func (r *Ramdisk) Destroy() error { | |
| if r.proc != zx.HandleInvalid { | |
| r.dir.Unmount() | |
| zx.Sys_task_kill(r.proc) | |
| r.dir.Close() | |
| } | |
| n := C.ramdisk_destroy(r.ramdisk_client) | |
| if n == 0 { | |
| return nil | |
| } | |
| return &zx.Error{Status: zx.Status(n), Text: "ramdisk_destroy"} | |
| } | |
| func (r *Ramdisk) StartBlobfs() error { | |
| status := C.ramdisk_blobfs_mkfs(r.ramdisk_client, (*C.uint)(&r.proc)) | |
| if zx.Status(status) != zx.ErrOk { | |
| return &zx.Error{Status: zx.Status(status), Text: "ramdisk_blobfs_mkfs"} | |
| } | |
| zx.Sys_object_wait_one(r.proc, zx.SignalTaskTerminated, zx.TimensecInfinite, nil) | |
| pxy, req, err := zx.NewChannel(0) | |
| if err != nil { | |
| return err | |
| } | |
| status = C.ramdisk_blobfs_mount(r.ramdisk_client, C.uint(uint32(zx.Handle(req))), (*C.uint)(&r.proc)) | |
| if zx.Status(status) != zx.ErrOk { | |
| pxy.Close() | |
| return &zx.Error{Status: zx.Status(status), Text: "ramdisk_blobfs_mount"} | |
| } | |
| r.dir = fdio.NewDirectoryWithCtx(&zxio.DirectoryAdminWithCtxInterface{Channel: pxy}) | |
| return nil | |
| } | |
| func (r *Ramdisk) Open(path string, flags int, mode uint32) (*os.File, error) { | |
| return iou.OpenFrom(r.dir, path, flags, mode) | |
| } | |
| func finalizeRamdisk(r *Ramdisk) { | |
| r.Destroy() | |
| } |