VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/sharedfolders/lnkops.c@ 96407

Last change on this file since 96407 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
RevLine 
[76733]1/* $Id: lnkops.c 96407 2022-08-22 17:43:14Z vboxsync $ */
[35472]2/** @file
[76733]3 * vboxsf - VBox Linux Shared Folders VFS, operations for symbolic links.
[35472]4 */
5
6/*
[96407]7 * Copyright (C) 2010-2022 Oracle and/or its affiliates.
[35472]8 *
[72627]9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
[35472]29 */
30
[77858]31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
[33439]35#include "vfsmod.h"
36
[33440]37
[77858]38/**
39 * Converts error codes as best we can.
40 */
41DECLINLINE(int) vbsf_convert_symlink_error(int vrc)
42{
43 if ( vrc == VERR_IS_A_DIRECTORY
44 || vrc == VERR_IS_A_FIFO
45 || vrc == VERR_IS_A_FILE
46 || vrc == VERR_IS_A_BLOCK_DEVICE
47 || vrc == VERR_IS_A_CHAR_DEVICE
48 || vrc == VERR_IS_A_SOCKET
49 || vrc == VERR_NOT_SYMLINK)
50 return -EINVAL;
51 if (vrc == VERR_PATH_NOT_FOUND)
52 return -ENOTDIR;
53 if (vrc == VERR_FILE_NOT_FOUND)
54 return -ENOENT;
55 return -EPROTO;
56}
[77529]57
[77858]58
59/**
60 * Does the NLS conversion of the symlink target.
61 */
62static int vbsf_symlink_nls_convert_slow(struct vbsf_super_info *pSuperInfo, char *pszTarget, size_t cbTargetBuf)
63{
64 int rc;
65 size_t const cchUtf8 = RTStrNLen(pszTarget, cbTargetBuf);
66 if (cchUtf8 < cbTargetBuf) {
67 /*
68 * If the target is short and there is a lot of space left in the target
69 * buffer (typically PAGE_SIZE in size), we move the input to the end
70 * instead of allocating a temporary buffer for it. This works because
71 * there shouldn't be anything that is more than 8x worse than UTF-8
72 * when it comes to efficiency.
73 */
74 char *pszFree = NULL;
75 char *pszUtf8;
76 if (cchUtf8 - 1 <= cbTargetBuf / 8) {
77 pszUtf8 = &pszTarget[cbTargetBuf - cchUtf8 - 1];
78 cbTargetBuf -= cchUtf8 - 1;
79 } else {
80 pszFree = pszUtf8 = kmalloc(cchUtf8 + 1, GFP_KERNEL);
81 if (RT_UNLIKELY(!pszUtf8)) {
82 LogRelMax(50, ("vbsf_symlink_nls_convert_slow: failed to allocate %u bytes\n", cchUtf8 + 1));
83 return -ENOMEM;
84 }
85 }
86 memcpy(pszUtf8, pszTarget, cchUtf8);
87 pszUtf8[cchUtf8] = '\0';
88
89 rc = vbsf_nlscpy(pSuperInfo, pszTarget, cbTargetBuf, pszUtf8, cchUtf8);
90 if (pszFree)
91 kfree(pszFree);
92 } else {
93 SFLOGFLOW(("vbsf_symlink_nls_convert_slow: Impossible! Unterminated target!\n"));
94 rc = -ENAMETOOLONG;
95 }
96 return rc;
97}
98
99
100/**
101 * Does NLS conversion if needed.
102 */
103DECLINLINE(int) vbsf_symlink_nls_convert(struct vbsf_super_info *pSuperInfo, char *pszTarget, size_t cbTargetBuf)
104{
105 if (pSuperInfo->fNlsIsUtf8)
106 return 0;
107 return vbsf_symlink_nls_convert_slow(pSuperInfo, pszTarget, cbTargetBuf);
108}
109
[85698]110#if RTLNX_VER_MIN(4,5,0)
[77858]111
112/**
113 * Get symbolic link.
114 */
115static const char *vbsf_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done)
116{
117 char *pszTarget;
118 if (dentry) {
119 pszTarget = (char *)kzalloc(PAGE_SIZE, GFP_KERNEL);
120 if (pszTarget) {
[77951]121 struct vbsf_super_info *pSuperInfo = VBSF_GET_SUPER_INFO(inode->i_sb);
122 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(inode);
123 int rc = VbglR0SfHostReqReadLinkContigSimple(pSuperInfo->map.root, sf_i->path->String.ach, sf_i->path->u16Length,
[77858]124 pszTarget, virt_to_phys(pszTarget), RT_MIN(PATH_MAX, PAGE_SIZE - 1));
125 if (RT_SUCCESS(rc)) {
126 pszTarget[PAGE_SIZE - 1] = '\0';
127 SFLOGFLOW(("vbsf_get_link: %s -> %s\n", sf_i->path->String.ach, pszTarget));
[77951]128 rc = vbsf_symlink_nls_convert(pSuperInfo, pszTarget, PAGE_SIZE);
[77858]129 if (rc == 0) {
[77873]130 vbsf_dentry_chain_increase_ttl(dentry);
[77858]131 set_delayed_call(done, kfree_link, pszTarget);
132 return pszTarget;
133 }
134 } else {
135 SFLOGFLOW(("vbsf_get_link: VbglR0SfHostReqReadLinkContigSimple failed on '%s': %Rrc\n",
136 sf_i->path->String.ach, rc));
137 }
138 kfree(pszTarget);
139 pszTarget = ERR_PTR(vbsf_convert_symlink_error(rc));
140 } else
141 pszTarget = ERR_PTR(-ENOMEM);
142 } else
143 pszTarget = ERR_PTR(-ECHILD);
144 return pszTarget;
145}
146
147#else /* < 4.5 */
148
[85698]149# if RTLNX_VER_MAX(2,6,8)
[77858]150/**
151 * Reads the link into the given buffer.
152 */
153static int vbsf_readlink(struct dentry *dentry, char *buffer, int len)
154{
155 int rc;
156 char *pszTarget = (char *)get_zeroed_page(GFP_KERNEL);
157 if (pszTarget) {
158 struct inode *inode = dentry->d_inode;
[77951]159 struct vbsf_super_info *pSuperInfo = VBSF_GET_SUPER_INFO(inode->i_sb);
160 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(inode);
161 rc = VbglR0SfHostReqReadLinkContigSimple(pSuperInfo->map.root, sf_i->path->String.ach, sf_i->path->u16Length,
[77858]162 pszTarget, virt_to_phys(pszTarget), RT_MIN(PATH_MAX, PAGE_SIZE - 1));
163 if (RT_SUCCESS(rc)) {
164 pszTarget[PAGE_SIZE - 1] = '\0';
165 SFLOGFLOW(("vbsf_readlink: %s -> %*s\n", sf_i->path->String.ach, pszTarget));
[77951]166 rc = vbsf_symlink_nls_convert(pSuperInfo, pszTarget, PAGE_SIZE);
[77873]167 if (rc == 0) {
168 vbsf_dentry_chain_increase_ttl(dentry);
[77858]169 rc = vfs_readlink(dentry, buffer, len, pszTarget);
[77873]170 }
[77858]171 } else {
172 SFLOGFLOW(("vbsf_readlink: VbglR0SfHostReqReadLinkContigSimple failed on '%s': %Rrc\n", sf_i->path->String.ach, rc));
173 rc = vbsf_convert_symlink_error(rc);
174 }
175 free_page((unsigned long)pszTarget);
176 } else
177 rc = -ENOMEM;
178 return rc;
179}
180# endif /* < 2.6.8 */
181
182/**
183 * Follow link in dentry.
184 */
[85698]185# if RTLNX_VER_MIN(4,2,0)
[77529]186static const char *vbsf_follow_link(struct dentry *dentry, void **cookie)
[85698]187# elif RTLNX_VER_MIN(2,6,13)
[77529]188static void *vbsf_follow_link(struct dentry *dentry, struct nameidata *nd)
[77858]189# else
[77529]190static int vbsf_follow_link(struct dentry *dentry, struct nameidata *nd)
[77858]191# endif
[33439]192{
[77526]193 int rc;
[77858]194 char *pszTarget = (char *)get_zeroed_page(GFP_KERNEL);
195 if (pszTarget) {
196 struct inode *inode = dentry->d_inode;
[77951]197 struct vbsf_super_info *pSuperInfo = VBSF_GET_SUPER_INFO(inode->i_sb);
198 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(inode);
[33439]199
[77951]200 rc = VbglR0SfHostReqReadLinkContigSimple(pSuperInfo->map.root, sf_i->path->String.ach, sf_i->path->u16Length,
[77858]201 pszTarget, virt_to_phys(pszTarget), RT_MIN(PATH_MAX, PAGE_SIZE - 1));
202 if (RT_SUCCESS(rc)) {
203 pszTarget[PAGE_SIZE - 1] = '\0';
204 SFLOGFLOW(("vbsf_follow_link: %s -> %s\n", sf_i->path->String.ach, pszTarget));
[77951]205 rc = vbsf_symlink_nls_convert(pSuperInfo, pszTarget, PAGE_SIZE);
[77858]206 if (rc == 0) {
207 /*
208 * Succeeded. For 2.6.8 and later the page gets associated
209 * with the caller-cookie or nameidata structure and freed
210 * later by vbsf_put_link(). On earlier kernels we have to
211 * call vfs_follow_link() which will try continue the walking
212 * using the buffer we pass it here.
213 */
[77873]214 vbsf_dentry_chain_increase_ttl(dentry);
[85698]215# if RTLNX_VER_MIN(4,2,0)
[77858]216 *cookie = pszTarget;
217 return pszTarget;
[85698]218# elif RTLNX_VER_MIN(2,6,8)
[77858]219 nd_set_link(nd, pszTarget);
[85698]220# if RTLNX_VER_MIN(2,6,13)
[77858]221 return NULL;
222# else
223 return 0;
224# endif
225# else /* < 2.6.8 */
226 rc = vfs_follow_link(nd, pszTarget);
227 free_page((unsigned long)pszTarget);
228 return rc;
229# endif
230 }
231
232 /*
233 * Failed.
234 */
235 } else {
[77526]236 LogFunc(("VbglR0SfReadLink failed, caller=%s, rc=%Rrc\n", __func__, rc));
[77858]237 rc = vbsf_convert_symlink_error(rc);
[77526]238 }
[77858]239 free_page((unsigned long)pszTarget);
240 } else {
241 rc = -ENOMEM;
[77526]242 }
[85698]243# if RTLNX_VER_MIN(4,2,0)
[77858]244 *cookie = ERR_PTR(rc);
245 return (const char *)ERR_PTR(rc);
[85698]246# elif RTLNX_VER_MIN(2,6,8)
[77858]247 nd_set_link(nd, (char *)ERR_PTR(rc));
[85698]248# if RTLNX_VER_MIN(2,6,13)
[77858]249 return NULL;
[76744]250# else
[77526]251 return 0;
[77529]252# endif
[77858]253# else /* < 2.6.8 */
254 return rc;
255# endif /* < 2.6.8 */
[33439]256}
257
[85698]258# if RTLNX_VER_MIN(2,6,8)
[77858]259/**
260 * For freeing target link buffer allocated by vbsf_follow_link.
261 *
[77973]262 * For kernels before 2.6.8 memory isn't being kept around.
[77858]263 */
[85698]264# if RTLNX_VER_MIN(4,2,0)
[77974]265static void vbsf_put_link(struct inode *inode, void *cookie)
[85698]266# elif RTLNX_VER_MIN(2,6,13)
[77529]267static void vbsf_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
[77858]268# else
[77529]269static void vbsf_put_link(struct dentry *dentry, struct nameidata *nd)
[77858]270# endif
[33439]271{
[85698]272# if RTLNX_VER_MIN(2,6,13)
[77858]273 char *page = cookie;
274# else
[77526]275 char *page = nd_get_link(nd);
[77858]276# endif
277 SFLOGFLOW(("vbsf_put_link: page=%p\n", page));
[77526]278 if (!IS_ERR(page))
279 free_page((unsigned long)page);
[33439]280}
[77858]281# endif /* >= 2.6.8 */
[33439]282
[77858]283#endif /* < 4.5.0 */
[77529]284
[77858]285/**
286 * Symlink inode operations.
287 */
[77529]288struct inode_operations vbsf_lnk_iops = {
[85698]289#if RTLNX_VER_MAX(4,10,0)
290# if RTLNX_VER_MIN(2,6,8)
[77858]291 .readlink = generic_readlink,
292# else
293 .readlink = vbsf_readlink,
[76744]294# endif
[77858]295#endif
[85698]296#if RTLNX_VER_MIN(4,5,0)
[77858]297 .get_link = vbsf_get_link
298#else
[77529]299 .follow_link = vbsf_follow_link,
[85698]300# if RTLNX_VER_MIN(2,6,8)
[77858]301 .put_link = vbsf_put_link,
[76744]302# endif
[77858]303#endif
[33439]304};
[33440]305
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use