1 | // SPDX-License-Identifier: MIT |
2 | /* |
3 | * Wrapper functions for the shfl host calls. |
4 | * |
5 | * Copyright (C) 2006-2018 Oracle Corporation |
6 | */ |
7 | |
8 | #include <linux/mm.h> |
9 | #include <linux/slab.h> |
10 | #include <linux/vbox_err.h> |
11 | #include <linux/vbox_utils.h> |
12 | #include "vfsmod.h" |
13 | |
14 | #define SHFL_REQUEST \ |
15 | (VMMDEV_REQUESTOR_KERNEL | VMMDEV_REQUESTOR_USR_DRV_OTHER | \ |
16 | VMMDEV_REQUESTOR_CON_DONT_KNOW | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN) |
17 | |
18 | static u32 vboxsf_client_id; |
19 | |
20 | int vboxsf_connect(void) |
21 | { |
22 | struct vbg_dev *gdev; |
23 | struct vmmdev_hgcm_service_location loc; |
24 | int err, vbox_status; |
25 | |
26 | loc.type = VMMDEV_HGCM_LOC_LOCALHOST_EXISTING; |
27 | strcpy(p: loc.u.localhost.service_name, q: "VBoxSharedFolders" ); |
28 | |
29 | gdev = vbg_get_gdev(); |
30 | if (IS_ERR(ptr: gdev)) |
31 | return -ENODEV; /* No guest-device */ |
32 | |
33 | err = vbg_hgcm_connect(gdev, SHFL_REQUEST, loc: &loc, |
34 | client_id: &vboxsf_client_id, vbox_status: &vbox_status); |
35 | vbg_put_gdev(gdev); |
36 | |
37 | return err ? err : vbg_status_code_to_errno(rc: vbox_status); |
38 | } |
39 | |
40 | void vboxsf_disconnect(void) |
41 | { |
42 | struct vbg_dev *gdev; |
43 | int vbox_status; |
44 | |
45 | gdev = vbg_get_gdev(); |
46 | if (IS_ERR(ptr: gdev)) |
47 | return; /* guest-device is gone, already disconnected */ |
48 | |
49 | vbg_hgcm_disconnect(gdev, SHFL_REQUEST, client_id: vboxsf_client_id, vbox_status: &vbox_status); |
50 | vbg_put_gdev(gdev); |
51 | } |
52 | |
53 | static int vboxsf_call(u32 function, void *parms, u32 parm_count, int *status) |
54 | { |
55 | struct vbg_dev *gdev; |
56 | int err, vbox_status; |
57 | |
58 | gdev = vbg_get_gdev(); |
59 | if (IS_ERR(ptr: gdev)) |
60 | return -ESHUTDOWN; /* guest-dev removed underneath us */ |
61 | |
62 | err = vbg_hgcm_call(gdev, SHFL_REQUEST, client_id: vboxsf_client_id, function, |
63 | U32_MAX, parms, parm_count, vbox_status: &vbox_status); |
64 | vbg_put_gdev(gdev); |
65 | |
66 | if (err < 0) |
67 | return err; |
68 | |
69 | if (status) |
70 | *status = vbox_status; |
71 | |
72 | return vbg_status_code_to_errno(rc: vbox_status); |
73 | } |
74 | |
75 | int vboxsf_map_folder(struct shfl_string *folder_name, u32 *root) |
76 | { |
77 | struct shfl_map_folder parms; |
78 | int err, status; |
79 | |
80 | parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL; |
81 | parms.path.u.pointer.size = shfl_string_buf_size(string: folder_name); |
82 | parms.path.u.pointer.u.linear_addr = (uintptr_t)folder_name; |
83 | |
84 | parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
85 | parms.root.u.value32 = 0; |
86 | |
87 | parms.delimiter.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
88 | parms.delimiter.u.value32 = '/'; |
89 | |
90 | parms.case_sensitive.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
91 | parms.case_sensitive.u.value32 = 1; |
92 | |
93 | err = vboxsf_call(function: SHFL_FN_MAP_FOLDER, parms: &parms, SHFL_CPARMS_MAP_FOLDER, |
94 | status: &status); |
95 | if (err == -ENOSYS && status == VERR_NOT_IMPLEMENTED) |
96 | vbg_err(fmt: "%s: Error host is too old\n" , __func__); |
97 | |
98 | *root = parms.root.u.value32; |
99 | return err; |
100 | } |
101 | |
102 | int vboxsf_unmap_folder(u32 root) |
103 | { |
104 | struct shfl_unmap_folder parms; |
105 | |
106 | parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
107 | parms.root.u.value32 = root; |
108 | |
109 | return vboxsf_call(function: SHFL_FN_UNMAP_FOLDER, parms: &parms, |
110 | SHFL_CPARMS_UNMAP_FOLDER, NULL); |
111 | } |
112 | |
113 | /** |
114 | * vboxsf_create - Create a new file or folder |
115 | * @root: Root of the shared folder in which to create the file |
116 | * @parsed_path: The path of the file or folder relative to the shared folder |
117 | * @create_parms: Parameters for file/folder creation. |
118 | * |
119 | * Create a new file or folder or open an existing one in a shared folder. |
120 | * Note this function always returns 0 / success unless an exceptional condition |
121 | * occurs - out of memory, invalid arguments, etc. If the file or folder could |
122 | * not be opened or created, create_parms->handle will be set to |
123 | * SHFL_HANDLE_NIL on return. In this case the value in create_parms->result |
124 | * provides information as to why (e.g. SHFL_FILE_EXISTS), create_parms->result |
125 | * is also set on success as additional information. |
126 | * |
127 | * Returns: |
128 | * 0 or negative errno value. |
129 | */ |
130 | int vboxsf_create(u32 root, struct shfl_string *parsed_path, |
131 | struct shfl_createparms *create_parms) |
132 | { |
133 | struct shfl_create parms; |
134 | |
135 | parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
136 | parms.root.u.value32 = root; |
137 | |
138 | parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL; |
139 | parms.path.u.pointer.size = shfl_string_buf_size(string: parsed_path); |
140 | parms.path.u.pointer.u.linear_addr = (uintptr_t)parsed_path; |
141 | |
142 | parms.parms.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL; |
143 | parms.parms.u.pointer.size = sizeof(struct shfl_createparms); |
144 | parms.parms.u.pointer.u.linear_addr = (uintptr_t)create_parms; |
145 | |
146 | return vboxsf_call(function: SHFL_FN_CREATE, parms: &parms, SHFL_CPARMS_CREATE, NULL); |
147 | } |
148 | |
149 | int vboxsf_close(u32 root, u64 handle) |
150 | { |
151 | struct shfl_close parms; |
152 | |
153 | parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
154 | parms.root.u.value32 = root; |
155 | |
156 | parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; |
157 | parms.handle.u.value64 = handle; |
158 | |
159 | return vboxsf_call(function: SHFL_FN_CLOSE, parms: &parms, SHFL_CPARMS_CLOSE, NULL); |
160 | } |
161 | |
162 | int vboxsf_remove(u32 root, struct shfl_string *parsed_path, u32 flags) |
163 | { |
164 | struct shfl_remove parms; |
165 | |
166 | parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
167 | parms.root.u.value32 = root; |
168 | |
169 | parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; |
170 | parms.path.u.pointer.size = shfl_string_buf_size(string: parsed_path); |
171 | parms.path.u.pointer.u.linear_addr = (uintptr_t)parsed_path; |
172 | |
173 | parms.flags.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
174 | parms.flags.u.value32 = flags; |
175 | |
176 | return vboxsf_call(function: SHFL_FN_REMOVE, parms: &parms, SHFL_CPARMS_REMOVE, NULL); |
177 | } |
178 | |
179 | int vboxsf_rename(u32 root, struct shfl_string *src_path, |
180 | struct shfl_string *dest_path, u32 flags) |
181 | { |
182 | struct shfl_rename parms; |
183 | |
184 | parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
185 | parms.root.u.value32 = root; |
186 | |
187 | parms.src.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; |
188 | parms.src.u.pointer.size = shfl_string_buf_size(string: src_path); |
189 | parms.src.u.pointer.u.linear_addr = (uintptr_t)src_path; |
190 | |
191 | parms.dest.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; |
192 | parms.dest.u.pointer.size = shfl_string_buf_size(string: dest_path); |
193 | parms.dest.u.pointer.u.linear_addr = (uintptr_t)dest_path; |
194 | |
195 | parms.flags.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
196 | parms.flags.u.value32 = flags; |
197 | |
198 | return vboxsf_call(function: SHFL_FN_RENAME, parms: &parms, SHFL_CPARMS_RENAME, NULL); |
199 | } |
200 | |
201 | int vboxsf_read(u32 root, u64 handle, u64 offset, u32 *buf_len, u8 *buf) |
202 | { |
203 | struct shfl_read parms; |
204 | int err; |
205 | |
206 | parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
207 | parms.root.u.value32 = root; |
208 | |
209 | parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; |
210 | parms.handle.u.value64 = handle; |
211 | parms.offset.type = VMMDEV_HGCM_PARM_TYPE_64BIT; |
212 | parms.offset.u.value64 = offset; |
213 | parms.cb.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
214 | parms.cb.u.value32 = *buf_len; |
215 | parms.buffer.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT; |
216 | parms.buffer.u.pointer.size = *buf_len; |
217 | parms.buffer.u.pointer.u.linear_addr = (uintptr_t)buf; |
218 | |
219 | err = vboxsf_call(function: SHFL_FN_READ, parms: &parms, SHFL_CPARMS_READ, NULL); |
220 | |
221 | *buf_len = parms.cb.u.value32; |
222 | return err; |
223 | } |
224 | |
225 | int vboxsf_write(u32 root, u64 handle, u64 offset, u32 *buf_len, u8 *buf) |
226 | { |
227 | struct shfl_write parms; |
228 | int err; |
229 | |
230 | parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
231 | parms.root.u.value32 = root; |
232 | |
233 | parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; |
234 | parms.handle.u.value64 = handle; |
235 | parms.offset.type = VMMDEV_HGCM_PARM_TYPE_64BIT; |
236 | parms.offset.u.value64 = offset; |
237 | parms.cb.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
238 | parms.cb.u.value32 = *buf_len; |
239 | parms.buffer.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; |
240 | parms.buffer.u.pointer.size = *buf_len; |
241 | parms.buffer.u.pointer.u.linear_addr = (uintptr_t)buf; |
242 | |
243 | err = vboxsf_call(function: SHFL_FN_WRITE, parms: &parms, SHFL_CPARMS_WRITE, NULL); |
244 | |
245 | *buf_len = parms.cb.u.value32; |
246 | return err; |
247 | } |
248 | |
249 | /* Returns 0 on success, 1 on end-of-dir, negative errno otherwise */ |
250 | int vboxsf_dirinfo(u32 root, u64 handle, |
251 | struct shfl_string *parsed_path, u32 flags, u32 index, |
252 | u32 *buf_len, struct shfl_dirinfo *buf, u32 *file_count) |
253 | { |
254 | struct shfl_list parms; |
255 | int err, status; |
256 | |
257 | parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
258 | parms.root.u.value32 = root; |
259 | |
260 | parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; |
261 | parms.handle.u.value64 = handle; |
262 | parms.flags.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
263 | parms.flags.u.value32 = flags; |
264 | parms.cb.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
265 | parms.cb.u.value32 = *buf_len; |
266 | if (parsed_path) { |
267 | parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; |
268 | parms.path.u.pointer.size = shfl_string_buf_size(string: parsed_path); |
269 | parms.path.u.pointer.u.linear_addr = (uintptr_t)parsed_path; |
270 | } else { |
271 | parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_IN; |
272 | parms.path.u.pointer.size = 0; |
273 | parms.path.u.pointer.u.linear_addr = 0; |
274 | } |
275 | |
276 | parms.buffer.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT; |
277 | parms.buffer.u.pointer.size = *buf_len; |
278 | parms.buffer.u.pointer.u.linear_addr = (uintptr_t)buf; |
279 | |
280 | parms.resume_point.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
281 | parms.resume_point.u.value32 = index; |
282 | parms.file_count.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
283 | parms.file_count.u.value32 = 0; /* out parameter only */ |
284 | |
285 | err = vboxsf_call(function: SHFL_FN_LIST, parms: &parms, SHFL_CPARMS_LIST, status: &status); |
286 | if (err == -ENODATA && status == VERR_NO_MORE_FILES) |
287 | err = 1; |
288 | |
289 | *buf_len = parms.cb.u.value32; |
290 | *file_count = parms.file_count.u.value32; |
291 | return err; |
292 | } |
293 | |
294 | int vboxsf_fsinfo(u32 root, u64 handle, u32 flags, |
295 | u32 *buf_len, void *buf) |
296 | { |
297 | struct shfl_information parms; |
298 | int err; |
299 | |
300 | parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
301 | parms.root.u.value32 = root; |
302 | |
303 | parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; |
304 | parms.handle.u.value64 = handle; |
305 | parms.flags.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
306 | parms.flags.u.value32 = flags; |
307 | parms.cb.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
308 | parms.cb.u.value32 = *buf_len; |
309 | parms.info.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL; |
310 | parms.info.u.pointer.size = *buf_len; |
311 | parms.info.u.pointer.u.linear_addr = (uintptr_t)buf; |
312 | |
313 | err = vboxsf_call(function: SHFL_FN_INFORMATION, parms: &parms, SHFL_CPARMS_INFORMATION, |
314 | NULL); |
315 | |
316 | *buf_len = parms.cb.u.value32; |
317 | return err; |
318 | } |
319 | |
320 | int vboxsf_readlink(u32 root, struct shfl_string *parsed_path, |
321 | u32 buf_len, u8 *buf) |
322 | { |
323 | struct shfl_readLink parms; |
324 | |
325 | parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
326 | parms.root.u.value32 = root; |
327 | |
328 | parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; |
329 | parms.path.u.pointer.size = shfl_string_buf_size(string: parsed_path); |
330 | parms.path.u.pointer.u.linear_addr = (uintptr_t)parsed_path; |
331 | |
332 | parms.buffer.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT; |
333 | parms.buffer.u.pointer.size = buf_len; |
334 | parms.buffer.u.pointer.u.linear_addr = (uintptr_t)buf; |
335 | |
336 | return vboxsf_call(function: SHFL_FN_READLINK, parms: &parms, SHFL_CPARMS_READLINK, |
337 | NULL); |
338 | } |
339 | |
340 | int vboxsf_symlink(u32 root, struct shfl_string *new_path, |
341 | struct shfl_string *old_path, struct shfl_fsobjinfo *buf) |
342 | { |
343 | struct shfl_symlink parms; |
344 | |
345 | parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; |
346 | parms.root.u.value32 = root; |
347 | |
348 | parms.new_path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; |
349 | parms.new_path.u.pointer.size = shfl_string_buf_size(string: new_path); |
350 | parms.new_path.u.pointer.u.linear_addr = (uintptr_t)new_path; |
351 | |
352 | parms.old_path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; |
353 | parms.old_path.u.pointer.size = shfl_string_buf_size(string: old_path); |
354 | parms.old_path.u.pointer.u.linear_addr = (uintptr_t)old_path; |
355 | |
356 | parms.info.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT; |
357 | parms.info.u.pointer.size = sizeof(struct shfl_fsobjinfo); |
358 | parms.info.u.pointer.u.linear_addr = (uintptr_t)buf; |
359 | |
360 | return vboxsf_call(function: SHFL_FN_SYMLINK, parms: &parms, SHFL_CPARMS_SYMLINK, NULL); |
361 | } |
362 | |
363 | int vboxsf_set_utf8(void) |
364 | { |
365 | return vboxsf_call(function: SHFL_FN_SET_UTF8, NULL, parm_count: 0, NULL); |
366 | } |
367 | |
368 | int vboxsf_set_symlinks(void) |
369 | { |
370 | return vboxsf_call(function: SHFL_FN_SET_SYMLINKS, NULL, parm_count: 0, NULL); |
371 | } |
372 | |