Skip to content

Commit 17c9673

Browse files
committed
implemented VZLinuxRosettaDirectoryShare caching options
1 parent c70d0c2 commit 17c9673

4 files changed

+237
-1
lines changed

shared_directory_arm64.go

+125
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ package vz
77
#cgo darwin CFLAGS: -mmacosx-version-min=11 -x objective-c -fno-objc-arc
88
#cgo darwin LDFLAGS: -lobjc -framework Foundation -framework Virtualization
99
# include "virtualization_13_arm64.h"
10+
# include "virtualization_14_arm64.h"
1011
*/
1112
import "C"
1213
import (
14+
"fmt"
15+
"os"
1316
"runtime/cgo"
1417
"unsafe"
1518

@@ -79,6 +82,16 @@ func NewLinuxRosettaDirectoryShare() (*LinuxRosettaDirectoryShare, error) {
7982
return ds, nil
8083
}
8184

85+
// SetOptions enables translation caching and configure the socket communication type for Rosetta.
86+
//
87+
// This is only supported on macOS 14 and newer. Older versions do nothing.
88+
func (ds *LinuxRosettaDirectoryShare) SetOptions(options LinuxRosettaCachingOptions) {
89+
if err := macOSAvailable(14); err != nil {
90+
return
91+
}
92+
C.setOptionsVZLinuxRosettaDirectoryShare(objc.Ptr(ds), objc.Ptr(options))
93+
}
94+
8295
// LinuxRosettaDirectoryShareInstallRosetta download and install Rosetta support
8396
// for Linux binaries if necessary.
8497
//
@@ -107,3 +120,115 @@ func LinuxRosettaDirectoryShareAvailability() LinuxRosettaAvailability {
107120
}
108121
return LinuxRosettaAvailability(C.availabilityVZLinuxRosettaDirectoryShare())
109122
}
123+
124+
// LinuxRosettaCachingOptions for a directory sharing device configuration.
125+
type LinuxRosettaCachingOptions interface {
126+
objc.NSObject
127+
128+
linuxRosettaCachingOptions()
129+
}
130+
131+
type baseLinuxRosettaCachingOptions struct{}
132+
133+
func (*baseLinuxRosettaCachingOptions) linuxRosettaCachingOptions() {}
134+
135+
// LinuxRosettaUnixSocketCachingOptions is an struct that represents caching options
136+
// for a UNIX domain socket.
137+
//
138+
// This struct configures Rosetta to communicate with the Rosetta daemon using a UNIX domain socket.
139+
type LinuxRosettaUnixSocketCachingOptions struct {
140+
*pointer
141+
142+
*baseLinuxRosettaCachingOptions
143+
}
144+
145+
var _ LinuxRosettaCachingOptions = (*LinuxRosettaUnixSocketCachingOptions)(nil)
146+
147+
// NewLinuxRosettaUnixSocketCachingOptions creates a new Rosetta caching options object for
148+
// a UNIX domain socket with the path you specify.
149+
//
150+
// The path of the Unix Domain Socket to be used to communicate with the Rosetta translation daemon.
151+
//
152+
// This is only supported on macOS 14 and newer, error will
153+
// be returned on older versions.
154+
func NewLinuxRosettaUnixSocketCachingOptions(path string) (*LinuxRosettaUnixSocketCachingOptions, error) {
155+
if err := macOSAvailable(14); err != nil {
156+
return nil, err
157+
}
158+
maxPathLen := maximumPathLengthLinuxRosettaUnixSocketCachingOptions()
159+
if maxPathLen < len(path) {
160+
return nil, fmt.Errorf("path length exceeds maximum allowed length of %d", maxPathLen)
161+
}
162+
if _, err := os.Stat(path); err != nil {
163+
return nil, fmt.Errorf("invalid path: %w", err)
164+
}
165+
166+
cs := charWithGoString(path)
167+
defer cs.Free()
168+
169+
nserrPtr := newNSErrorAsNil()
170+
usco := &LinuxRosettaUnixSocketCachingOptions{
171+
pointer: objc.NewPointer(
172+
C.newVZLinuxRosettaUnixSocketCachingOptionsWithPath(cs.CString(), &nserrPtr),
173+
),
174+
}
175+
if err := newNSError(nserrPtr); err != nil {
176+
return nil, err
177+
}
178+
objc.SetFinalizer(usco, func(self *LinuxRosettaUnixSocketCachingOptions) {
179+
objc.Release(self)
180+
})
181+
return usco, nil
182+
}
183+
184+
func maximumPathLengthLinuxRosettaUnixSocketCachingOptions() int {
185+
return int(uint32(C.maximumPathLengthVZLinuxRosettaUnixSocketCachingOptions()))
186+
}
187+
188+
// LinuxRosettaAbstractSocketCachingOptions is caching options for an abstract socket.
189+
//
190+
// Use this object to configure Rosetta to communicate with the Rosetta daemon using an abstract socket.
191+
type LinuxRosettaAbstractSocketCachingOptions struct {
192+
*pointer
193+
194+
*baseLinuxRosettaCachingOptions
195+
}
196+
197+
var _ LinuxRosettaCachingOptions = (*LinuxRosettaAbstractSocketCachingOptions)(nil)
198+
199+
// NewLinuxRosettaAbstractSocketCachingOptions creates a new LinuxRosettaAbstractSocketCachingOptions.
200+
//
201+
// The name of the Abstract Socket to be used to communicate with the Rosetta translation daemon.
202+
//
203+
// This is only supported on macOS 14 and newer, error will
204+
// be returned on older versions.
205+
func NewLinuxRosettaAbstractSocketCachingOptions(name string) (*LinuxRosettaAbstractSocketCachingOptions, error) {
206+
if err := macOSAvailable(14); err != nil {
207+
return nil, err
208+
}
209+
maxNameLen := maximumNameLengthVZLinuxRosettaAbstractSocketCachingOptions()
210+
if maxNameLen < len(name) {
211+
return nil, fmt.Errorf("name length exceeds maximum allowed length of %d", maxNameLen)
212+
}
213+
214+
cs := charWithGoString(name)
215+
defer cs.Free()
216+
217+
nserrPtr := newNSErrorAsNil()
218+
asco := &LinuxRosettaAbstractSocketCachingOptions{
219+
pointer: objc.NewPointer(
220+
C.newVZLinuxRosettaAbstractSocketCachingOptionsWithName(cs.CString(), &nserrPtr),
221+
),
222+
}
223+
if err := newNSError(nserrPtr); err != nil {
224+
return nil, err
225+
}
226+
objc.SetFinalizer(asco, func(self *LinuxRosettaAbstractSocketCachingOptions) {
227+
objc.Release(self)
228+
})
229+
return asco, nil
230+
}
231+
232+
func maximumNameLengthVZLinuxRosettaAbstractSocketCachingOptions() int {
233+
return int(uint32(C.maximumNameLengthVZLinuxRosettaAbstractSocketCachingOptions()))
234+
}

shared_directory_arm64_test.go

+52
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
package vz_test
55

66
import (
7+
"os"
8+
"path/filepath"
9+
"strings"
710
"testing"
811

912
"github.com/Code-Hex/vz/v3"
@@ -34,3 +37,52 @@ func TestLinuxRosettaAvailabilityString(t *testing.T) {
3437
}
3538
}
3639
}
40+
41+
func TestNewLinuxRosettaUnixSocketCachingOptions(t *testing.T) {
42+
if vz.Available(14) {
43+
t.Skip("NewLinuxRosettaUnixSocketCachingOptions is supported from macOS 14")
44+
}
45+
dir := t.TempDir()
46+
t.Run("invalid filename length", func(t *testing.T) {
47+
filename := filepath.Join(dir, strings.Repeat("a", 150)) + ".txt"
48+
f, err := os.Create(filename)
49+
if err != nil {
50+
t.Fatal(err)
51+
}
52+
defer f.Close()
53+
54+
_, err = vz.NewLinuxRosettaUnixSocketCachingOptions(filename)
55+
if err == nil {
56+
t.Fatal("expected error")
57+
}
58+
if got := err.Error(); !strings.Contains(got, "maximum allowed length of") {
59+
t.Fatalf("unexpected error: %q", got)
60+
}
61+
})
62+
t.Run("invalid filename does not exists", func(t *testing.T) {
63+
filename := "doesnotexists.txt"
64+
_, err := vz.NewLinuxRosettaUnixSocketCachingOptions(filename)
65+
if err == nil {
66+
t.Fatal("expected error")
67+
}
68+
if got := err.Error(); !strings.Contains(got, "invalid path") {
69+
t.Fatalf("unexpected error: %q", got)
70+
}
71+
})
72+
}
73+
74+
func TestNewLinuxRosettaAbstractSocketCachingOptions(t *testing.T) {
75+
if vz.Available(14) {
76+
t.Skip("NewLinuxRosettaAbstractSocketCachingOptions is supported from macOS 14")
77+
}
78+
t.Run("invalid name length", func(t *testing.T) {
79+
name := strings.Repeat("a", 350)
80+
_, err := vz.NewLinuxRosettaAbstractSocketCachingOptions(name)
81+
if err == nil {
82+
t.Fatal("expected error")
83+
}
84+
if got := err.Error(); !strings.Contains(got, "maximum allowed length of") {
85+
t.Fatalf("unexpected error: %q", got)
86+
}
87+
})
88+
}

virtualization_14_arm64.h

+5
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,9 @@
1212
#ifdef __arm64__
1313
void saveMachineStateToURLWithCompletionHandler(void *machine, void *queue, uintptr_t cgoHandle, const char *saveFilePath);
1414
void restoreMachineStateFromURLWithCompletionHandler(void *machine, void *queue, uintptr_t cgoHandle, const char *saveFilePath);
15+
void *newVZLinuxRosettaAbstractSocketCachingOptionsWithName(const char *name, void **error);
16+
void *newVZLinuxRosettaUnixSocketCachingOptionsWithPath(const char *path, void **error);
17+
uint32_t maximumPathLengthVZLinuxRosettaUnixSocketCachingOptions();
18+
uint32_t maximumNameLengthVZLinuxRosettaAbstractSocketCachingOptions();
19+
void setOptionsVZLinuxRosettaDirectoryShare(void *rosetta, void *cachingOptions);
1520
#endif

virtualization_14_arm64.m

+55-1
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,58 @@ void saveMachineStateToURLWithCompletionHandler(void *machine, void *queue, uint
8383
}
8484
#endif
8585
RAISE_UNSUPPORTED_MACOS_EXCEPTION();
86-
}
86+
}
87+
88+
void *newVZLinuxRosettaAbstractSocketCachingOptionsWithName(const char *name, void **error)
89+
{
90+
#ifdef INCLUDE_TARGET_OSX_14
91+
if (@available(macOS 14, *)) {
92+
NSString *nameNSString = [NSString stringWithUTF8String:name];
93+
return [[VZLinuxRosettaAbstractSocketCachingOptions alloc] initWithName:nameNSString error:(NSError *_Nullable *_Nullable)error];
94+
}
95+
#endif
96+
RAISE_UNSUPPORTED_MACOS_EXCEPTION();
97+
}
98+
99+
uint32_t maximumNameLengthVZLinuxRosettaAbstractSocketCachingOptions()
100+
{
101+
#ifdef INCLUDE_TARGET_OSX_14
102+
if (@available(macOS 14, *)) {
103+
return (uint32_t)[VZLinuxRosettaAbstractSocketCachingOptions maximumNameLength];
104+
}
105+
#endif
106+
RAISE_UNSUPPORTED_MACOS_EXCEPTION();
107+
}
108+
109+
void *newVZLinuxRosettaUnixSocketCachingOptionsWithPath(const char *path, void **error)
110+
{
111+
#ifdef INCLUDE_TARGET_OSX_14
112+
if (@available(macOS 14, *)) {
113+
NSString *pathNSString = [NSString stringWithUTF8String:path];
114+
return [[VZLinuxRosettaUnixSocketCachingOptions alloc] initWithPath:pathNSString error:(NSError *_Nullable *_Nullable)error];
115+
}
116+
#endif
117+
RAISE_UNSUPPORTED_MACOS_EXCEPTION();
118+
}
119+
120+
uint32_t maximumPathLengthVZLinuxRosettaUnixSocketCachingOptions()
121+
{
122+
#ifdef INCLUDE_TARGET_OSX_14
123+
if (@available(macOS 14, *)) {
124+
return (uint32_t)[VZLinuxRosettaUnixSocketCachingOptions maximumPathLength];
125+
}
126+
#endif
127+
RAISE_UNSUPPORTED_MACOS_EXCEPTION();
128+
}
129+
130+
131+
void setOptionsVZLinuxRosettaDirectoryShare(void *rosetta, void *cachingOptions)
132+
{
133+
#ifdef INCLUDE_TARGET_OSX_14
134+
if (@available(macOS 14, *)) {
135+
[(VZLinuxRosettaDirectoryShare *)rosetta setOptions:(VZLinuxRosettaCachingOptions *)cachingOptions];
136+
return;
137+
}
138+
#endif
139+
RAISE_UNSUPPORTED_MACOS_EXCEPTION();
140+
}

0 commit comments

Comments
 (0)