VirtualBox

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

Last change on this file since 11507 was 11507, checked in by vboxsync, 16 years ago

Linux guest additions: allow to specify dmode, fmode, umask, dmask, fmask when mounting a shared folder. Note: read/write permissions currently not checked by vboxvfs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.7 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 Sun Microsystems, Inc.
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 (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23/*
24 * Limitations: only COW memory mapping is supported
25 */
26
27#include "vfsmod.h"
28
29#define CHUNK_SIZE 4096
30
31/* fops */
32static int
33sf_reg_read_aux (const char *caller, struct sf_glob_info *sf_g,
34 struct sf_reg_info *sf_r, void *buf, uint32_t *nread,
35 uint64_t pos)
36{
37 int rc = vboxCallRead (&client_handle, &sf_g->map, sf_r->handle,
38 pos, nread, buf, false /* already locked? */);
39 if (VBOX_FAILURE (rc)) {
40 LogFunc(("vboxCallRead failed. caller=%s, rc=%Vrc\n",
41 caller, rc));
42 return -EPROTO;
43 }
44 return 0;
45}
46
47static ssize_t
48sf_reg_read (struct file *file, char *buf, size_t size, loff_t *off)
49{
50 int err;
51 void *tmp;
52 size_t left = size;
53 ssize_t total_bytes_read = 0;
54 struct inode *inode = file->f_dentry->d_inode;
55 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
56 struct sf_reg_info *sf_r = file->private_data;
57 loff_t pos = *off;
58
59 TRACE ();
60 if (!S_ISREG (inode->i_mode)) {
61 LogFunc(("read from non regular file %d\n", inode->i_mode));
62 return -EINVAL;
63 }
64
65 /** XXX Check read permission accoring to inode->i_mode! */
66
67 if (!size) {
68 return 0;
69 }
70
71 tmp = kmalloc (CHUNK_SIZE, GFP_KERNEL);
72 if (!tmp) {
73 LogRelFunc(("could not allocate bounce buffer memory %d bytes\n", CHUNK_SIZE));
74 return -ENOMEM;
75 }
76
77 while (left) {
78 uint32_t to_read, nread;
79
80 to_read = CHUNK_SIZE;
81 if (to_read > left) {
82 to_read = (uint32_t) left;
83 }
84 nread = to_read;
85
86 err = sf_reg_read_aux (__func__, sf_g, sf_r, tmp, &nread, pos);
87 if (err) {
88 goto fail;
89 }
90
91 if (copy_to_user (buf, tmp, nread)) {
92 err = -EFAULT;
93 goto fail;
94 }
95
96 pos += nread;
97 left -= nread;
98 buf += nread;
99 total_bytes_read += nread;
100 if (nread != to_read) {
101 break;
102 }
103 }
104
105 *off += total_bytes_read;
106 kfree (tmp);
107 return total_bytes_read;
108
109 fail:
110 kfree (tmp);
111 return err;
112}
113
114static ssize_t
115sf_reg_write (struct file *file, const char *buf, size_t size, loff_t *off)
116{
117 int err;
118 void *tmp;
119 size_t left = size;
120 ssize_t total_bytes_written = 0;
121 struct inode *inode = file->f_dentry->d_inode;
122 struct sf_inode_info *sf_i = GET_INODE_INFO (inode);
123 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
124 struct sf_reg_info *sf_r = file->private_data;
125 loff_t pos = *off;
126
127 TRACE ();
128 BUG_ON (!sf_i);
129 BUG_ON (!sf_g);
130 BUG_ON (!sf_r);
131
132 if (!S_ISREG (inode->i_mode)) {
133 LogFunc(("write to non regular file %d\n", inode->i_mode));
134 return -EINVAL;
135 }
136
137 /** XXX Check write permission accoring to inode->i_mode! */
138
139 if (!size) {
140 return 0;
141 }
142
143 tmp = kmalloc (CHUNK_SIZE, GFP_KERNEL);
144 if (!tmp) {
145 LogRelFunc(("could not allocate bounce buffer memory %d bytes\n", CHUNK_SIZE));
146 return -ENOMEM;
147 }
148
149 while (left) {
150 int rc;
151 uint32_t to_write, nwritten;
152
153 to_write = CHUNK_SIZE;
154 if (to_write > left) {
155 to_write = (uint32_t) left;
156 }
157 nwritten = to_write;
158
159 if (copy_from_user (tmp, buf, to_write)) {
160 err = -EFAULT;
161 goto fail;
162 }
163
164 rc = vboxCallWrite (&client_handle, &sf_g->map, sf_r->handle,
165 pos, &nwritten, tmp, false /* already locked? */);
166 if (VBOX_FAILURE (rc)) {
167 err = -EPROTO;
168 LogFunc(("vboxCallWrite(%s) failed rc=%Vrc\n",
169 sf_i->path->String.utf8, rc));
170 goto fail;
171 }
172
173 pos += nwritten;
174 left -= nwritten;
175 buf += nwritten;
176 total_bytes_written += nwritten;
177 if (nwritten != to_write) {
178 break;
179 }
180 }
181
182#if 1 /* XXX: which way is correct? */
183 *off += total_bytes_written;
184#else
185 file->f_pos += total_bytes_written;
186#endif
187 sf_i->force_restat = 1;
188 kfree (tmp);
189 return total_bytes_written;
190
191 fail:
192 kfree (tmp);
193 return err;
194}
195
196static int
197sf_reg_open (struct inode *inode, struct file *file)
198{
199 int rc, rc_linux = 0;
200 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
201 struct sf_inode_info *sf_i = GET_INODE_INFO (inode);
202 struct sf_reg_info *sf_r;
203 SHFLCREATEPARMS params;
204
205 TRACE ();
206 BUG_ON (!sf_g);
207 BUG_ON (!sf_i);
208
209 sf_r = kmalloc (sizeof (*sf_r), GFP_KERNEL);
210 if (!sf_r) {
211 LogRelFunc(("could not allocate reg info\n"));
212 return -ENOMEM;
213 }
214
215 LogFunc(("open %s\n", sf_i->path->String.utf8));
216
217 params.CreateFlags = 0;
218 params.Info.cbObject = 0;
219 /* We check this afterwards to find out if the call succeeded
220 or failed, as the API does not seem to cleanly distinguish
221 error and informational messages. */
222 params.Handle = 0;
223
224 if (file->f_flags & O_CREAT) {
225 LogFunc(("O_CREAT set\n"));
226 params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW;
227 /* We ignore O_EXCL, as the Linux kernel seems to call create
228 beforehand itself, so O_EXCL should always fail. */
229 if (file->f_flags & O_TRUNC) {
230 LogFunc(("O_TRUNC set\n"));
231 params.CreateFlags |= ( SHFL_CF_ACT_OVERWRITE_IF_EXISTS
232 | SHFL_CF_ACCESS_WRITE);
233 }
234 else {
235 params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
236 }
237 }
238 else {
239 params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
240 if (file->f_flags & O_TRUNC) {
241 LogFunc(("O_TRUNC set\n"));
242 params.CreateFlags |= ( SHFL_CF_ACT_OVERWRITE_IF_EXISTS
243 | SHFL_CF_ACCESS_WRITE);
244 }
245 }
246
247 if (!(params.CreateFlags & SHFL_CF_ACCESS_READWRITE)) {
248 switch (file->f_flags & O_ACCMODE) {
249 case O_RDONLY:
250 params.CreateFlags |= SHFL_CF_ACCESS_READ;
251 break;
252
253 case O_WRONLY:
254 params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
255 break;
256
257 case O_RDWR:
258 params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
259 break;
260
261 default:
262 BUG ();
263 }
264 }
265
266 LogFunc(("sf_reg_open: calling vboxCallCreate, file %s, flags=%d, %#x\n",
267 sf_i->path->String.utf8 , file->f_flags, params.CreateFlags));
268 rc = vboxCallCreate (&client_handle, &sf_g->map, sf_i->path, &params);
269
270 if (VBOX_FAILURE (rc)) {
271 LogFunc(("vboxCallCreate failed flags=%d,%#x rc=%Vrc\n",
272 file->f_flags, params.CreateFlags, rc));
273 kfree (sf_r);
274 return -RTErrConvertToErrno(rc);
275 }
276
277 if (SHFL_HANDLE_NIL == params.Handle) {
278 switch (params.Result) {
279 case SHFL_PATH_NOT_FOUND:
280 case SHFL_FILE_NOT_FOUND:
281 rc_linux = -ENOENT;
282 break;
283 case SHFL_FILE_EXISTS:
284 rc_linux = -EEXIST;
285 break;
286 default:
287 break;
288 }
289 }
290
291 sf_i->force_restat = 1;
292 sf_r->handle = params.Handle;
293 file->private_data = sf_r;
294 return rc_linux;
295}
296
297static int
298sf_reg_release (struct inode *inode, struct file *file)
299{
300 int rc;
301 struct sf_reg_info *sf_r;
302 struct sf_glob_info *sf_g;
303
304 TRACE ();
305 sf_g = GET_GLOB_INFO (inode->i_sb);
306 sf_r = file->private_data;
307
308 BUG_ON (!sf_g);
309 BUG_ON (!sf_r);
310
311 rc = vboxCallClose (&client_handle, &sf_g->map, sf_r->handle);
312 if (VBOX_FAILURE (rc)) {
313 LogFunc(("vboxCallClose failed rc=%Vrc\n", rc));
314 }
315
316 kfree (sf_r);
317 file->private_data = NULL;
318 return 0;
319}
320
321#if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 25)
322static int
323sf_reg_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
324#elif LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
325static struct page *
326sf_reg_nopage (struct vm_area_struct *vma, unsigned long vaddr, int *type)
327# define SET_TYPE(t) *type = (t)
328#else /* LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0) */
329static struct page *
330sf_reg_nopage (struct vm_area_struct *vma, unsigned long vaddr, int unused)
331# define SET_TYPE(t)
332#endif
333{
334 struct page *page;
335 char *buf;
336 loff_t off;
337 uint32_t nread = PAGE_SIZE;
338 int err;
339 struct file *file = vma->vm_file;
340 struct inode *inode = file->f_dentry->d_inode;
341 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
342 struct sf_reg_info *sf_r = file->private_data;
343
344 TRACE ();
345#if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 25)
346 if (vmf->pgoff > vma->vm_end)
347 return VM_FAULT_SIGBUS;
348#else
349 if (vaddr > vma->vm_end) {
350 SET_TYPE (VM_FAULT_SIGBUS);
351 return NOPAGE_SIGBUS;
352 }
353#endif
354
355 page = alloc_page (GFP_HIGHUSER);
356 if (!page) {
357 LogRelFunc(("failed to allocate page\n"));
358#if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 25)
359 return VM_FAULT_OOM;
360#else
361 SET_TYPE (VM_FAULT_OOM);
362 return NOPAGE_OOM;
363#endif
364 }
365
366 buf = kmap (page);
367#if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 25)
368 off = (vmf->pgoff << PAGE_SHIFT);
369#else
370 off = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
371#endif
372 err = sf_reg_read_aux (__func__, sf_g, sf_r, buf, &nread, off);
373 if (err) {
374 kunmap (page);
375 put_page (page);
376#if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 25)
377 return VM_FAULT_SIGBUS;
378#else
379 SET_TYPE (VM_FAULT_SIGBUS);
380 return NOPAGE_SIGBUS;
381#endif
382 }
383
384 BUG_ON (nread > PAGE_SIZE);
385 if (!nread) {
386#if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 25)
387 clear_user_page (page_address (page), vmf->pgoff, page);
388#elif LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
389 clear_user_page (page_address (page), vaddr, page);
390#else
391 clear_user_page (page_address (page), vaddr);
392#endif
393 }
394 else {
395 memset (buf + nread, 0, PAGE_SIZE - nread);
396 }
397
398 flush_dcache_page (page);
399 kunmap (page);
400#if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 25)
401 vmf->page = page;
402 return 0;
403#else
404 SET_TYPE (VM_FAULT_MAJOR);
405 return page;
406#endif
407}
408
409static struct vm_operations_struct sf_vma_ops = {
410#if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 25)
411 .fault = sf_reg_fault
412#else
413 .nopage = sf_reg_nopage
414#endif
415};
416
417static int
418sf_reg_mmap (struct file *file, struct vm_area_struct *vma)
419{
420 TRACE ();
421 if (vma->vm_flags & VM_SHARED) {
422 LogFunc(("shared mmapping not available\n"));
423 return -EINVAL;
424 }
425
426 vma->vm_ops = &sf_vma_ops;
427 return 0;
428}
429
430struct file_operations sf_reg_fops = {
431 .read = sf_reg_read,
432 .open = sf_reg_open,
433 .write = sf_reg_write,
434 .release = sf_reg_release,
435 .mmap = sf_reg_mmap,
436#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
437# if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 23)
438 .splice_read = generic_file_splice_read,
439# else
440 .sendfile = generic_file_sendfile,
441# endif
442 .aio_read = generic_file_aio_read,
443 .aio_write = generic_file_aio_write,
444 .fsync = simple_sync_file,
445 .llseek = generic_file_llseek,
446#endif
447};
448
449
450struct inode_operations sf_reg_iops = {
451#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
452 .revalidate = sf_inode_revalidate
453#else
454 .getattr = sf_getattr
455#endif
456};
457
458
459#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
460static int
461sf_readpage(struct file *file, struct page *page)
462{
463 char *buf = kmap(page);
464 struct inode *inode = file->f_dentry->d_inode;
465 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
466 struct sf_reg_info *sf_r = file->private_data;
467 uint32_t nread = PAGE_SIZE;
468 loff_t off = page->index << PAGE_SHIFT;
469 int ret;
470
471 TRACE ();
472
473 ret = sf_reg_read_aux (__func__, sf_g, sf_r, buf, &nread, off);
474 if (ret) {
475 kunmap (page);
476 return ret;
477 }
478 flush_dcache_page (page);
479 kunmap (page);
480 SetPageUptodate(page);
481 if (PageLocked(page))
482 unlock_page(page);
483 return 0;
484}
485
486struct address_space_operations sf_reg_aops = {
487 .readpage = sf_readpage,
488# if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 24)
489 .write_begin = simple_write_begin,
490 .write_end = simple_write_end,
491# else
492 .prepare_write = simple_prepare_write,
493 .commit_write = simple_commit_write,
494# endif
495};
496#endif
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