]>
Commit | Line | Data |
---|---|---|
39adb5c3 TG |
1 | /** @file |
2 | * | |
3 | * vboxsf -- VirtualBox Guest Additions for Linux: | |
4 | * Operations for symbolic links. | |
5 | */ | |
6 | ||
7 | /* | |
8 | * Copyright (C) 2010-2016 Oracle Corporation | |
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 | ||
19 | #include "vfsmod.h" | |
20 | ||
21 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) | |
22 | ||
23 | # if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) | |
24 | # if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) | |
25 | static const char *sf_follow_link(struct dentry *dentry, void **cookie) | |
26 | # else | |
27 | static void *sf_follow_link(struct dentry *dentry, struct nameidata *nd) | |
28 | # endif | |
29 | { | |
30 | struct inode *inode = dentry->d_inode; | |
31 | struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb); | |
32 | struct sf_inode_info *sf_i = GET_INODE_INFO(inode); | |
33 | int error = -ENOMEM; | |
34 | char *path = (char*)get_zeroed_page(GFP_KERNEL); | |
35 | int rc; | |
36 | ||
37 | if (path) | |
38 | { | |
39 | error = 0; | |
40 | rc = VbglR0SfReadLink(&client_handle, &sf_g->map, sf_i->path, PATH_MAX, path); | |
41 | if (RT_FAILURE(rc)) | |
42 | { | |
43 | LogFunc(("VbglR0SfReadLink failed, caller=%s, rc=%Rrc\n", __func__, rc)); | |
44 | free_page((unsigned long)path); | |
45 | error = -EPROTO; | |
46 | } | |
47 | } | |
48 | # if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) | |
49 | return error ? ERR_PTR(error) : (*cookie = path); | |
50 | # else | |
51 | nd_set_link(nd, error ? ERR_PTR(error) : path); | |
52 | return NULL; | |
53 | # endif | |
54 | } | |
55 | ||
56 | # if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) | |
57 | static void sf_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) | |
58 | { | |
59 | char *page = nd_get_link(nd); | |
60 | if (!IS_ERR(page)) | |
61 | free_page((unsigned long)page); | |
62 | } | |
63 | # endif | |
64 | ||
65 | # else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) */ | |
66 | static const char *sf_get_link(struct dentry *dentry, struct inode *inode, | |
67 | struct delayed_call *done) | |
68 | { | |
69 | struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb); | |
70 | struct sf_inode_info *sf_i = GET_INODE_INFO(inode); | |
71 | char *path; | |
72 | int rc; | |
73 | ||
74 | if (!dentry) | |
75 | return ERR_PTR(-ECHILD); | |
76 | path = kzalloc(PAGE_SIZE, GFP_KERNEL); | |
77 | if (!path) | |
78 | return ERR_PTR(-ENOMEM); | |
79 | rc = VbglR0SfReadLink(&client_handle, &sf_g->map, sf_i->path, PATH_MAX, path); | |
80 | if (RT_FAILURE(rc)) | |
81 | { | |
82 | LogFunc(("VbglR0SfReadLink failed, caller=%s, rc=%Rrc\n", __func__, rc)); | |
83 | kfree(path); | |
84 | return ERR_PTR(-EPROTO); | |
85 | } | |
86 | set_delayed_call(done, kfree_link, path); | |
87 | return path; | |
88 | } | |
89 | # endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) */ | |
90 | ||
91 | struct inode_operations sf_lnk_iops = | |
92 | { | |
39adb5c3 TG |
93 | # if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) |
94 | .get_link = sf_get_link | |
95 | # elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) | |
96 | .follow_link = sf_follow_link, | |
97 | .put_link = free_page_put_link, | |
98 | # else | |
99 | .follow_link = sf_follow_link, | |
100 | .put_link = sf_put_link | |
101 | # endif | |
102 | }; | |
103 | ||
104 | #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ |