/** * Get information about host VFS object. * * @param mp Mount point data * @param pSHFLDPath Path to VFS object within mounted shared folder * @param Info Returned info * * @return 0 on success, error code otherwise. */ int vboxvfs_get_info_internal(mount_t mp, PSHFLSTRING pSHFLDPath, PSHFLFSOBJINFO Info) { vboxvfs_mount_t *pMount; SHFLCREATEPARMS parms; int rc; AssertReturn(mp, EINVAL); AssertReturn(pSHFLDPath, EINVAL); AssertReturn(Info, EINVAL); pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL); parms.Handle = 0; parms.Info.cbObject = 0; parms.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW; rc = VbglR0SfCreate(&g_vboxSFClient, &pMount->pMap, pSHFLDPath, &parms); if (rc == 0) *Info = parms.Info; return rc; }
/** * Open existing VBoxVFS object and return its handle. * * @param pMount Mount session data. * @param pPath VFS path to the object relative to mount point. * @param fFlags For directory object it should be * SHFL_CF_DIRECTORY and 0 for any other object. * @param pHandle Returned handle. * * @return 0 on success, error code otherwise. */ int vboxvfs_open_internal(vboxvfs_mount_t *pMount, PSHFLSTRING pPath, uint32_t fFlags, SHFLHANDLE *pHandle) { SHFLCREATEPARMS parms; int rc; AssertReturn(pMount, EINVAL); AssertReturn(pPath, EINVAL); AssertReturn(pHandle, EINVAL); bzero(&parms, sizeof(parms)); vboxvfs_g2h_mode_dump_inernal(fFlags); parms.Handle = SHFL_HANDLE_NIL; parms.Info.cbObject = 0; parms.CreateFlags = fFlags; rc = VbglR0SfCreate(&g_vboxSFClient, &pMount->pMap, pPath, &parms); if (RT_SUCCESS(rc)) { *pHandle = parms.Handle; } else { PDEBUG("vboxvfs_open_internal() failed: %d", rc); } return rc; }
int sf_stat(const char *caller, struct sf_glob_info *sf_g, SHFLSTRING *path, PSHFLFSOBJINFO result, int ok_to_fail) { int rc; SHFLCREATEPARMS params; NOREF(caller); TRACE(); RT_ZERO(params); params.Handle = SHFL_HANDLE_NIL; params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW; LogFunc(("sf_stat: calling VbglR0SfCreate, file %s, flags %#x\n", path->String.utf8, params.CreateFlags)); rc = VbglR0SfCreate(&client_handle, &sf_g->map, path, ¶ms); if (rc == VERR_INVALID_NAME) { /* this can happen for names like 'foo*' on a Windows host */ return -ENOENT; } if (RT_FAILURE(rc)) { LogFunc(("VbglR0SfCreate(%s) failed. caller=%s, rc=%Rrc\n", path->String.utf8, rc, caller)); return -EPROTO; } if (params.Result != SHFL_FILE_EXISTS) { if (!ok_to_fail) LogFunc(("VbglR0SfCreate(%s) file does not exist. caller=%s, result=%d\n", path->String.utf8, params.Result, caller)); return -ENOENT; } *result = params.Info; return 0; }
int sf_setattr(struct dentry *dentry, struct iattr *iattr) { struct sf_glob_info *sf_g; struct sf_inode_info *sf_i; SHFLCREATEPARMS params; SHFLFSOBJINFO info; uint32_t cbBuffer; int rc, err; TRACE(); sf_g = GET_GLOB_INFO(dentry->d_inode->i_sb); sf_i = GET_INODE_INFO(dentry->d_inode); err = 0; RT_ZERO(params); params.Handle = SHFL_HANDLE_NIL; params.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_ATTR_WRITE; /* this is at least required for Posix hosts */ if (iattr->ia_valid & ATTR_SIZE) params.CreateFlags |= SHFL_CF_ACCESS_WRITE; rc = VbglR0SfCreate(&client_handle, &sf_g->map, sf_i->path, ¶ms); if (RT_FAILURE(rc)) { LogFunc(("VbglR0SfCreate(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc)); err = -RTErrConvertToErrno(rc); goto fail2; } if (params.Result != SHFL_FILE_EXISTS) { LogFunc(("file %s does not exist\n", sf_i->path->String.utf8)); err = -ENOENT; goto fail1; } /* Setting the file size and setting the other attributes has to be * handled separately, see implementation of vbsfSetFSInfo() in * vbsf.cpp */ if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME)) { #define mode_set(r) ((iattr->ia_mode & (S_##r)) ? RTFS_UNIX_##r : 0) RT_ZERO(info); if (iattr->ia_valid & ATTR_MODE) { info.Attr.fMode = mode_set(ISUID); info.Attr.fMode |= mode_set(ISGID); info.Attr.fMode |= mode_set(IRUSR); info.Attr.fMode |= mode_set(IWUSR); info.Attr.fMode |= mode_set(IXUSR); info.Attr.fMode |= mode_set(IRGRP); info.Attr.fMode |= mode_set(IWGRP); info.Attr.fMode |= mode_set(IXGRP); info.Attr.fMode |= mode_set(IROTH); info.Attr.fMode |= mode_set(IWOTH); info.Attr.fMode |= mode_set(IXOTH); if (iattr->ia_mode & S_IFDIR) info.Attr.fMode |= RTFS_TYPE_DIRECTORY; else info.Attr.fMode |= RTFS_TYPE_FILE; } if (iattr->ia_valid & ATTR_ATIME) sf_timespec_from_ftime(&info.AccessTime, &iattr->ia_atime); if (iattr->ia_valid & ATTR_MTIME) sf_timespec_from_ftime(&info.ModificationTime, &iattr->ia_mtime); /* ignore ctime (inode change time) as it can't be set from userland anyway */ cbBuffer = sizeof(info); rc = VbglR0SfFsInfo(&client_handle, &sf_g->map, params.Handle, SHFL_INFO_SET | SHFL_INFO_FILE, &cbBuffer, (PSHFLDIRINFO)&info); if (RT_FAILURE(rc)) { LogFunc(("VbglR0SfFsInfo(%s, FILE) failed rc=%Rrc\n", sf_i->path->String.utf8, rc)); err = -RTErrConvertToErrno(rc); goto fail1; } } if (iattr->ia_valid & ATTR_SIZE) { RT_ZERO(info); info.cbObject = iattr->ia_size; cbBuffer = sizeof(info); rc = VbglR0SfFsInfo(&client_handle, &sf_g->map, params.Handle, SHFL_INFO_SET | SHFL_INFO_SIZE, &cbBuffer, (PSHFLDIRINFO)&info); if (RT_FAILURE(rc)) { LogFunc(("VbglR0SfFsInfo(%s, SIZE) failed rc=%Rrc\n", sf_i->path->String.utf8, rc)); err = -RTErrConvertToErrno(rc); goto fail1; } } rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle); if (RT_FAILURE(rc)) LogFunc(("VbglR0SfClose(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc)); return sf_inode_revalidate(dentry); fail1: rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle); if (RT_FAILURE(rc)) LogFunc(("VbglR0SfClose(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc)); fail2: return err; }
/** * Open a regular file. * * @param inode the inode * @param file the file * @returns 0 on success, Linux error code otherwise */ static int sf_reg_open(struct inode *inode, struct file *file) { int rc, rc_linux = 0; struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb); struct sf_inode_info *sf_i = GET_INODE_INFO(inode); struct sf_reg_info *sf_r; SHFLCREATEPARMS params; TRACE(); BUG_ON(!sf_g); BUG_ON(!sf_i); LogFunc(("open %s\n", sf_i->path->String.utf8)); sf_r = kmalloc(sizeof(*sf_r), GFP_KERNEL); if (!sf_r) { LogRelFunc(("could not allocate reg info\n")); return -ENOMEM; } /* Already open? */ if (sf_i->handle != SHFL_HANDLE_NIL) { /* * This inode was created with sf_create_aux(). Check the CreateFlags: * O_CREAT, O_TRUNC: inherent true (file was just created). Not sure * about the access flags (SHFL_CF_ACCESS_*). */ sf_i->force_restat = 1; sf_r->handle = sf_i->handle; sf_i->handle = SHFL_HANDLE_NIL; sf_i->file = file; file->private_data = sf_r; return 0; } RT_ZERO(params); params.Handle = SHFL_HANDLE_NIL; /* We check the value of params.Handle afterwards to find out if * the call succeeded or failed, as the API does not seem to cleanly * distinguish error and informational messages. * * Furthermore, we must set params.Handle to SHFL_HANDLE_NIL to * make the shared folders host service use our fMode parameter */ if (file->f_flags & O_CREAT) { LogFunc(("O_CREAT set\n")); params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW; /* We ignore O_EXCL, as the Linux kernel seems to call create beforehand itself, so O_EXCL should always fail. */ if (file->f_flags & O_TRUNC) { LogFunc(("O_TRUNC set\n")); params.CreateFlags |= ( SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACCESS_WRITE); } else params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS; } else { params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW; if (file->f_flags & O_TRUNC) { LogFunc(("O_TRUNC set\n")); params.CreateFlags |= ( SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACCESS_WRITE); } } if (!(params.CreateFlags & SHFL_CF_ACCESS_READWRITE)) { switch (file->f_flags & O_ACCMODE) { case O_RDONLY: params.CreateFlags |= SHFL_CF_ACCESS_READ; break; case O_WRONLY: params.CreateFlags |= SHFL_CF_ACCESS_WRITE; break; case O_RDWR: params.CreateFlags |= SHFL_CF_ACCESS_READWRITE; break; default: BUG (); } } if (file->f_flags & O_APPEND) { LogFunc(("O_APPEND set\n")); params.CreateFlags |= SHFL_CF_ACCESS_APPEND; } params.Info.Attr.fMode = inode->i_mode; LogFunc(("sf_reg_open: calling VbglR0SfCreate, file %s, flags=%#x, %#x\n", sf_i->path->String.utf8 , file->f_flags, params.CreateFlags)); rc = VbglR0SfCreate(&client_handle, &sf_g->map, sf_i->path, ¶ms); if (RT_FAILURE(rc)) { LogFunc(("VbglR0SfCreate failed flags=%d,%#x rc=%Rrc\n", file->f_flags, params.CreateFlags, rc)); kfree(sf_r); return -RTErrConvertToErrno(rc); } if (SHFL_HANDLE_NIL == params.Handle) { switch (params.Result) { case SHFL_PATH_NOT_FOUND: case SHFL_FILE_NOT_FOUND: rc_linux = -ENOENT; break; case SHFL_FILE_EXISTS: rc_linux = -EEXIST; break; default: break; } } sf_i->force_restat = 1; sf_r->handle = params.Handle; sf_i->file = file; file->private_data = sf_r; return rc_linux; }
/** * Create a new regular file / directory. * * @param parent inode of the directory * @param dentry directory cache entry * @param mode file mode * @param fDirectory true if directory, false otherwise * @returns 0 on success, Linux error code otherwise */ static int sf_create_aux(struct inode *parent, struct dentry *dentry, umode_t mode, int fDirectory) { int rc, err; SHFLCREATEPARMS params; SHFLSTRING *path; struct sf_inode_info *sf_i = GET_INODE_INFO(parent); struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb); TRACE(); BUG_ON(!sf_i); BUG_ON(!sf_g); err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path); if (err) goto fail0; RT_ZERO(params); params.Handle = SHFL_HANDLE_NIL; params.CreateFlags = 0 | SHFL_CF_ACT_CREATE_IF_NEW | SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACCESS_READWRITE | (fDirectory ? SHFL_CF_DIRECTORY : 0) ; params.Info.Attr.fMode = 0 | (fDirectory ? RTFS_TYPE_DIRECTORY : RTFS_TYPE_FILE) | (mode & S_IRWXUGO) ; params.Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING; LogFunc(("sf_create_aux: calling VbglR0SfCreate, folder %s, flags %#x\n", path->String.utf8, params.CreateFlags)); rc = VbglR0SfCreate(&client_handle, &sf_g->map, path, ¶ms); if (RT_FAILURE(rc)) { if (rc == VERR_WRITE_PROTECT) { err = -EROFS; goto fail1; } err = -EPROTO; LogFunc(("(%d): VbglR0SfCreate(%s) failed rc=%Rrc\n", fDirectory, sf_i->path->String.utf8, rc)); goto fail1; } if (params.Result != SHFL_FILE_CREATED) { err = -EPERM; LogFunc(("(%d): could not create file %s result=%d\n", fDirectory, sf_i->path->String.utf8, params.Result)); goto fail1; } err = sf_instantiate(parent, dentry, path, ¶ms.Info, fDirectory ? SHFL_HANDLE_NIL : params.Handle); if (err) { LogFunc(("(%d): could not instantiate dentry for %s err=%d\n", fDirectory, sf_i->path->String.utf8, err)); goto fail2; } /* * Don't close this handle right now. We assume that the same file is * opened with sf_reg_open() and later closed with sf_reg_close(). Save * the handle in between. Does not apply to directories. True? */ if (fDirectory) { rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle); if (RT_FAILURE(rc)) LogFunc(("(%d): VbglR0SfClose failed rc=%Rrc\n", fDirectory, rc)); } sf_i->force_restat = 1; return 0; fail2: rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle); if (RT_FAILURE(rc)) LogFunc(("(%d): VbglR0SfClose failed rc=%Rrc\n", fDirectory, rc)); fail1: kfree(path); fail0: return err; }
/** * Open a directory. Read the complete content into a buffer. * * @param inode inode * @param file file * @returns 0 on success, Linux error code otherwise */ static int sf_dir_open(struct inode *inode, struct file *file) { int rc; int err; struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb); struct sf_dir_info *sf_d; struct sf_inode_info *sf_i = GET_INODE_INFO(inode); SHFLCREATEPARMS params; TRACE(); BUG_ON(!sf_g); BUG_ON(!sf_i); if (file->private_data) { LogFunc(("sf_dir_open() called on already opened directory '%s'\n", sf_i->path->String.utf8)); return 0; } sf_d = sf_dir_info_alloc(); if (!sf_d) { LogRelFunc(("could not allocate directory info for '%s'\n", sf_i->path->String.utf8)); return -ENOMEM; } RT_ZERO(params); params.Handle = SHFL_HANDLE_NIL; params.CreateFlags = 0 | SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ ; LogFunc(("sf_dir_open(): calling VbglR0SfCreate, folder %s, flags %#x\n", sf_i->path->String.utf8, params.CreateFlags)); rc = VbglR0SfCreate(&client_handle, &sf_g->map, sf_i->path, ¶ms); if (RT_SUCCESS(rc)) { if (params.Result == SHFL_FILE_EXISTS) { err = sf_dir_read_all(sf_g, sf_i, sf_d, params.Handle); if (!err) file->private_data = sf_d; } else err = -ENOENT; rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle); if (RT_FAILURE(rc)) LogFunc(("sf_dir_open(): VbglR0SfClose(%s) after err=%d failed rc=%Rrc\n", sf_i->path->String.utf8, err, rc)); } else err = -EPERM; if (err) sf_dir_info_free(sf_d); return err; }
/** * Extract element ([dir]->f_pos) from the directory [dir] into [d_name]. * * @returns 0 for success, 1 for end reached, Linux error code otherwise. */ static int sf_getdent(struct file *dir, char d_name[NAME_MAX], int *d_type) { loff_t cur; struct sf_glob_info *sf_g; struct sf_dir_info *sf_d; struct sf_inode_info *sf_i; struct inode *inode; struct list_head *pos, *list; TRACE(); inode = GET_F_DENTRY(dir)->d_inode; sf_i = GET_INODE_INFO(inode); sf_g = GET_GLOB_INFO(inode->i_sb); sf_d = dir->private_data; BUG_ON(!sf_g); BUG_ON(!sf_d); BUG_ON(!sf_i); if (sf_i->force_reread) { int rc; int err; SHFLCREATEPARMS params; RT_ZERO(params); params.Handle = SHFL_HANDLE_NIL; params.CreateFlags = 0 | SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ ; LogFunc(("sf_getdent: calling VbglR0SfCreate, folder %s, flags %#x\n", sf_i->path->String.utf8, params.CreateFlags)); rc = VbglR0SfCreate(&client_handle, &sf_g->map, sf_i->path, ¶ms); if (RT_FAILURE(rc)) { LogFunc(("VbglR0SfCreate(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc)); return -EPERM; } if (params.Result != SHFL_FILE_EXISTS) { LogFunc(("directory %s does not exist\n", sf_i->path->String.utf8)); sf_dir_info_free(sf_d); return -ENOENT; } sf_dir_info_empty(sf_d); err = sf_dir_read_all(sf_g, sf_i, sf_d, params.Handle); rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle); if (RT_FAILURE(rc)) LogFunc(("VbglR0SfClose(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc)); if (err) return err; sf_i->force_reread = 0; } cur = 0; list = &sf_d->info_list; list_for_each(pos, list) { struct sf_dir_buf *b; SHFLDIRINFO *info; loff_t i; b = list_entry(pos, struct sf_dir_buf, head); if (dir->f_pos >= cur + b->cEntries) { cur += b->cEntries; continue; } for (i = 0, info = b->buf; i < dir->f_pos - cur; ++i) { size_t size; size = offsetof(SHFLDIRINFO, name.String) + info->name.u16Size; info = (SHFLDIRINFO *) ((uintptr_t) info + size); } *d_type = sf_get_d_type(info->Info.Attr.fMode); return sf_nlscpy(sf_g, d_name, NAME_MAX, info->name.String.utf8, info->name.u16Length); } return 1; }