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(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 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(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 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(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 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(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 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(SHFL_FN_UNMAP_FOLDER, &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(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 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(SHFL_FN_CLOSE, &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(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 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(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 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(SHFL_FN_READ, &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(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 */ 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(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 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(SHFL_FN_INFORMATION, &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(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 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(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 363 int vboxsf_set_utf8(void) 364 { 365 return vboxsf_call(SHFL_FN_SET_UTF8, NULL, 0, NULL); 366 } 367 368 int vboxsf_set_symlinks(void) 369 { 370 return vboxsf_call(SHFL_FN_SET_SYMLINKS, NULL, 0, NULL); 371 } 372