VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/sharedfolders/regops.c@ 4353

Last change on this file since 4353 was 4112, checked in by vboxsync, 17 years ago

Changes for new interface

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.3 KB
Line 
1/** @file
2 *
3 * vboxvfs -- VirtualBox Guest Additions for Linux:
4 * Regular file inode and file operations
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/*
20 * Limitations: only COW memory mapping is supported
21 */
22
23#define CHUNK_SIZE 4096
24
25/* fops */
26static int
27sf_reg_read_aux (const char *caller, struct sf_glob_info *sf_g,
28 struct sf_reg_info *sf_r, void *buf, uint32_t *nread,
29 uint64_t pos)
30{
31 int rc = vboxCallRead (&client_handle, &sf_g->map, sf_r->handle,
32 pos, nread, buf, false /* already locked? */);
33 if (VBOX_FAILURE (rc)) {
34 elog3 ("%s: %s: vboxCallRead failed rc=%d\n",
35 caller, __func__, rc);
36 return -EPROTO;
37 }
38 return 0;
39}
40
41static ssize_t
42sf_reg_read (struct file *file, char *buf, size_t size, loff_t *off)
43{
44 int err;
45 void *tmp;
46 size_t left = size;
47 ssize_t total_bytes_read = 0;
48 struct inode *inode = file->f_dentry->d_inode;
49 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
50 struct sf_reg_info *sf_r = file->private_data;
51 loff_t pos = *off;
52
53 TRACE ();
54 if (!S_ISREG (inode->i_mode)) {
55 elog ("read from non regular file %d\n", inode->i_mode);
56 return -EINVAL;
57 }
58
59 if (!size) {
60 return 0;
61 }
62
63 tmp = kmalloc (CHUNK_SIZE, GFP_KERNEL);
64 if (!tmp) {
65 elog ("could not allocate bounce buffer memory %u bytes\n",
66 CHUNK_SIZE);
67 return -ENOMEM;
68 }
69
70 while (left) {
71 uint32_t to_read, nread;
72
73 to_read = CHUNK_SIZE;
74 if (to_read > left) {
75 to_read = (uint32_t) left;
76 }
77 nread = to_read;
78
79 err = sf_reg_read_aux (__func__, sf_g, sf_r, tmp, &nread, pos);
80 if (err) {
81 goto fail;
82 }
83
84 if (copy_to_user (buf, tmp, nread)) {
85 err = -EFAULT;
86 goto fail;
87 }
88
89 pos += nread;
90 left -= nread;
91 buf += nread;
92 total_bytes_read += nread;
93 if (nread != to_read) {
94 break;
95 }
96 }
97
98 *off += total_bytes_read;
99 kfree (tmp);
100 return total_bytes_read;
101
102 fail:
103 kfree (tmp);
104 return err;
105}
106
107static ssize_t
108sf_reg_write (struct file *file, const char *buf, size_t size, loff_t *off)
109{
110 int err;
111 void *tmp;
112 size_t left = size;
113 ssize_t total_bytes_written = 0;
114 struct inode *inode = file->f_dentry->d_inode;
115 struct sf_inode_info *sf_i = GET_INODE_INFO (inode);
116 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
117 struct sf_reg_info *sf_r = file->private_data;
118 loff_t pos = *off;
119
120 TRACE ();
121 BUG_ON (!sf_i);
122 BUG_ON (!sf_g);
123 BUG_ON (!sf_r);
124
125 if (!S_ISREG (inode->i_mode)) {
126 elog ("write to non regular file %d\n", inode->i_mode);
127 return -EINVAL;
128 }
129
130 if (!size) {
131 return 0;
132 }
133
134 tmp = kmalloc (CHUNK_SIZE, GFP_KERNEL);
135 if (!tmp) {
136 elog ("could not allocate bounce buffer memory %u bytes\n",
137 CHUNK_SIZE);
138 return -ENOMEM;
139 }
140
141 while (left) {
142 int rc;
143 uint32_t to_write, nwritten;
144
145 to_write = CHUNK_SIZE;
146 if (to_write > left) {
147 to_write = (uint32_t) left;
148 }
149 nwritten = to_write;
150
151 if (copy_from_user (tmp, buf, to_write)) {
152 err = -EFAULT;
153 goto fail;
154 }
155
156 rc = vboxCallWrite (&client_handle, &sf_g->map, sf_r->handle,
157 pos, &nwritten, tmp, false /* already locked? */);
158 if (VBOX_FAILURE (rc)) {
159 err = -EPROTO;
160 elog ("vboxCallWrite(%s) failed rc=%d\n",
161 sf_i->path->String.utf8, rc);
162 goto fail;
163 }
164
165 pos += nwritten;
166 left -= nwritten;
167 buf += nwritten;
168 total_bytes_written += nwritten;
169 if (nwritten != to_write) {
170 break;
171 }
172 }
173
174#if 1 /* XXX: which way is correct? */
175 *off += total_bytes_written;
176#else
177 file->f_pos += total_bytes_written;
178#endif
179 sf_i->force_restat = 1;
180 kfree (tmp);
181 return total_bytes_written;
182
183 fail:
184 kfree (tmp);
185 return err;
186}
187
188static int
189sf_reg_open (struct inode *inode, struct file *file)
190{
191 int rc;
192 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
193 struct sf_inode_info *sf_i = GET_INODE_INFO (inode);
194 struct sf_reg_info *sf_r;
195 SHFLCREATEPARMS params;
196
197 TRACE ();
198 BUG_ON (!sf_g);
199 BUG_ON (!sf_i);
200
201 sf_r = kmalloc (sizeof (*sf_r), GFP_KERNEL);
202 if (!sf_r) {
203 elog2 ("could not allocate reg info\n");
204 return -ENOMEM;
205 }
206
207#if 0
208 printk ("open %s\n", sf_i->path->String.utf8);
209#endif
210
211 params.CreateFlags = 0;
212 params.Info.cbObject = 0;
213
214 if (file->f_flags & O_CREAT) {
215 if (file->f_flags & O_EXCL) {
216 params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
217 params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS;
218 }
219 else {
220 params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW;
221 params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
222 if (file->f_flags & O_TRUNC) {
223 params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
224 }
225 else {
226 params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
227 }
228 }
229 }
230 else {
231 if (file->f_flags & O_TRUNC) {
232 params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
233 params.CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
234 }
235 else {
236 params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
237 }
238 }
239
240 if (!(params.CreateFlags & SHFL_CF_ACCESS_READWRITE)) {
241 switch (file->f_flags & O_ACCMODE) {
242 case O_RDONLY:
243 params.CreateFlags |= SHFL_CF_ACCESS_READ;
244 break;
245
246 case O_WRONLY:
247 params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
248 break;
249
250 case O_RDWR:
251 params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
252 break;
253
254 default:
255 BUG ();
256 }
257 }
258
259 rc = vboxCallCreate (&client_handle, &sf_g->map, sf_i->path, &params);
260
261 /* XXX: here i probably should check rc and convert some values to
262 EEXISTS ENOENT etc */
263 if (VBOX_FAILURE (rc)) {
264 elog ("vboxCallCreate failed flags=%d,%#x rc=%d\n",
265 file->f_flags, params.CreateFlags, rc);
266 kfree (sf_r);
267 return -EPROTO;
268 }
269
270 sf_i->force_restat = 1;
271 sf_r->handle = params.Handle;
272 file->private_data = sf_r;
273 return 0;
274}
275
276static int
277sf_reg_release (struct inode *inode, struct file *file)
278{
279 int rc;
280 struct sf_reg_info *sf_r;
281 struct sf_glob_info *sf_g;
282
283 TRACE ();
284 sf_g = GET_GLOB_INFO (inode->i_sb);
285 sf_r = file->private_data;
286
287 BUG_ON (!sf_g);
288 BUG_ON (!sf_r);
289
290 rc = vboxCallClose (&client_handle, &sf_g->map, sf_r->handle);
291 if (VBOX_FAILURE (rc)) {
292 elog ("vboxCallClose failed rc=%d\n", rc);
293 }
294
295 kfree (sf_r);
296 file->private_data = NULL;
297 return 0;
298}
299
300static struct page *
301#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
302sf_reg_nopage (struct vm_area_struct *vma, unsigned long vaddr, int unused)
303#define SET_TYPE(t)
304#else
305sf_reg_nopage (struct vm_area_struct *vma, unsigned long vaddr, int *type)
306#define SET_TYPE(t) *type = (t)
307#endif
308{
309 struct page *page;
310 char *buf;
311 loff_t off;
312 uint32_t nread = PAGE_SIZE;
313 int err;
314 struct file *file = vma->vm_file;
315 struct inode *inode = file->f_dentry->d_inode;
316 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
317 struct sf_reg_info *sf_r = file->private_data;
318
319 TRACE ();
320 if (vaddr > vma->vm_end) {
321 SET_TYPE (VM_FAULT_SIGBUS);
322 return NOPAGE_SIGBUS;
323 }
324
325 page = alloc_page (GFP_HIGHUSER);
326 if (!page) {
327 elog2 ("failed to allocate page\n");
328 SET_TYPE (VM_FAULT_OOM);
329 return NOPAGE_OOM;
330 }
331
332 buf = kmap (page);
333 off = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
334
335 err = sf_reg_read_aux (__func__, sf_g, sf_r, buf, &nread, off);
336 if (err) {
337 kunmap (page);
338 put_page (page);
339 SET_TYPE (VM_FAULT_SIGBUS);
340 return NOPAGE_SIGBUS;
341 }
342
343 BUG_ON (nread > PAGE_SIZE);
344 if (!nread) {
345#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
346 clear_user_page (page_address (page), vaddr);
347#else
348 clear_user_page (page_address (page), vaddr, page);
349#endif
350 }
351 else {
352 memset (buf + nread, 0, PAGE_SIZE - nread);
353 }
354
355 flush_dcache_page (page);
356 kunmap (page);
357 SET_TYPE (VM_FAULT_MAJOR);
358 return page;
359}
360
361static struct vm_operations_struct sf_vma_ops = {
362 .nopage = sf_reg_nopage
363};
364
365static int
366sf_reg_mmap (struct file *file, struct vm_area_struct *vma)
367{
368 TRACE ();
369 if (vma->vm_flags & VM_SHARED) {
370 elog2 ("shared mmapping not available\n");
371 return -EINVAL;
372 }
373
374 vma->vm_ops = &sf_vma_ops;
375 return 0;
376}
377
378static struct file_operations sf_reg_fops = {
379 .read = sf_reg_read,
380 .open = sf_reg_open,
381 .write = sf_reg_write,
382 .release = sf_reg_release,
383 .mmap = sf_reg_mmap
384};
385
386
387/* iops */
388
389static struct inode_operations sf_reg_iops = {
390#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
391 .revalidate = sf_inode_revalidate
392#else
393 .getattr = sf_getattr
394#endif
395};
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette