372 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Wrapper functions for the shfl host calls.4 *5 * Copyright (C) 2006-2018 Oracle Corporation6 */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 18static u32 vboxsf_client_id;19 20int 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(loc.u.localhost.service_name, "VBoxSharedFolders");28 29 gdev = vbg_get_gdev();30 if (IS_ERR(gdev))31 return -ENODEV; /* No guest-device */32 33 err = vbg_hgcm_connect(gdev, SHFL_REQUEST, &loc,34 &vboxsf_client_id, &vbox_status);35 vbg_put_gdev(gdev);36 37 return err ? err : vbg_status_code_to_errno(vbox_status);38}39 40void vboxsf_disconnect(void)41{42 struct vbg_dev *gdev;43 int vbox_status;44 45 gdev = vbg_get_gdev();46 if (IS_ERR(gdev))47 return; /* guest-device is gone, already disconnected */48 49 vbg_hgcm_disconnect(gdev, SHFL_REQUEST, vboxsf_client_id, &vbox_status);50 vbg_put_gdev(gdev);51}52 53static 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(gdev))60 return -ESHUTDOWN; /* guest-dev removed underneath us */61 62 err = vbg_hgcm_call(gdev, SHFL_REQUEST, vboxsf_client_id, function,63 U32_MAX, parms, parm_count, &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(vbox_status);73}74 75int 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(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(SHFL_FN_MAP_FOLDER, &parms, SHFL_CPARMS_MAP_FOLDER,94 &status);95 if (err == -ENOSYS && status == VERR_NOT_IMPLEMENTED)96 vbg_err("%s: Error host is too old\n", __func__);97 98 *root = parms.root.u.value32;99 return err;100}101 102int 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(SHFL_FN_UNMAP_FOLDER, &parms,110 SHFL_CPARMS_UNMAP_FOLDER, NULL);111}112 113/**114 * vboxsf_create - Create a new file or folder115 * @root: Root of the shared folder in which to create the file116 * @parsed_path: The path of the file or folder relative to the shared folder117 * @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 condition121 * occurs - out of memory, invalid arguments, etc. If the file or folder could122 * not be opened or created, create_parms->handle will be set to123 * SHFL_HANDLE_NIL on return. In this case the value in create_parms->result124 * provides information as to why (e.g. SHFL_FILE_EXISTS), create_parms->result125 * is also set on success as additional information.126 *127 * Returns:128 * 0 or negative errno value.129 */130int 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(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(SHFL_FN_CREATE, &parms, SHFL_CPARMS_CREATE, NULL);147}148 149int 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(SHFL_FN_CLOSE, &parms, SHFL_CPARMS_CLOSE, NULL);160}161 162int 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(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(SHFL_FN_REMOVE, &parms, SHFL_CPARMS_REMOVE, NULL);177}178 179int 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(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(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(SHFL_FN_RENAME, &parms, SHFL_CPARMS_RENAME, NULL);199}200 201int 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(SHFL_FN_READ, &parms, SHFL_CPARMS_READ, NULL);220 221 *buf_len = parms.cb.u.value32;222 return err;223}224 225int 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(SHFL_FN_WRITE, &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 */250int 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(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(SHFL_FN_LIST, &parms, SHFL_CPARMS_LIST, &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 294int 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(SHFL_FN_INFORMATION, &parms, SHFL_CPARMS_INFORMATION,314 NULL);315 316 *buf_len = parms.cb.u.value32;317 return err;318}319 320int 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(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(SHFL_FN_READLINK, &parms, SHFL_CPARMS_READLINK,337 NULL);338}339 340int 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(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(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(SHFL_FN_SYMLINK, &parms, SHFL_CPARMS_SYMLINK, NULL);361}362 363int vboxsf_set_utf8(void)364{365 return vboxsf_call(SHFL_FN_SET_UTF8, NULL, 0, NULL);366}367 368int vboxsf_set_symlinks(void)369{370 return vboxsf_call(SHFL_FN_SET_SYMLINKS, NULL, 0, NULL);371}372