ReactOS 0.4.15-dev-5865-g640e228
symlink.c
Go to the documentation of this file.
1/* NFSv4.1 client for Windows
2 * Copyright 2012 The Regents of the University of Michigan
3 *
4 * Olga Kornievskaia <aglo@umich.edu>
5 * Casey Bodley <cbodley@umich.edu>
6 *
7 * This library is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or (at
10 * your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful, but
13 * without any warranty; without even the implied warranty of merchantability
14 * or fitness for a particular purpose. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 */
21
22#include <windows.h>
23#include <strsafe.h>
24
25#include "nfs41_ops.h"
26#include "upcall.h"
27#include "util.h"
28#include "daemon_debug.h"
29
30
31static int abs_path_link(
33 IN char *path_pos,
34 IN const char *link,
35 IN uint32_t link_len)
36{
38 const char *path_max = path->path + NFS41_MAX_PATH_LEN;
39 const char *link_pos = link;
40 const char *link_end = link + link_len;
41 int status = NO_ERROR;
42
43 /* if link is an absolute path, start path_pos at the beginning */
44 if (is_delimiter(*link))
45 path_pos = path->path;
46
47 /* copy each component of link into the path */
48 while (next_component(link_pos, link_end, &name)) {
49 link_pos = name.name + name.len;
50
51 if (is_delimiter(*path_pos))
52 path_pos++;
53
54 /* handle special components . and .. */
55 if (name.len == 1 && name.name[0] == '.')
56 continue;
57 if (name.len == 2 && name.name[0] == '.' && name.name[1] == '.') {
58 /* back path_pos up by one component */
59 if (!last_component(path->path, path_pos, &name)) {
60 eprintf("symlink with .. that points below server root!\n");
62 goto out;
63 }
64 path_pos = (char*)prev_delimiter(name.name, path->path);
65 continue;
66 }
67
68 /* copy the component and add a \ */
69 if (FAILED(StringCchCopyNA(path_pos, path_max-path_pos, name.name,
70 name.len))) {
72 goto out;
73 }
74 path_pos += name.len;
75 if (FAILED(StringCchCopyNA(path_pos, path_max-path_pos, "\\", 1))) {
77 goto out;
78 }
79 }
80
81 /* make sure the path is null terminated */
82 if (path_pos == path_max) {
84 goto out;
85 }
86 *path_pos = '\0';
87out:
88 path->len = (unsigned short)(path_pos - path->path);
89 return status;
90}
91
96{
98 const nfs41_abs_path *path = file->path;
99 ptrdiff_t path_offset;
100 uint32_t link_len;
101 int status;
102
103 /* read the link */
105 if (status) {
106 eprintf("nfs41_readlink() for %s failed with %s\n", file->path->path,
109 goto out;
110 }
111
112 dprintf(2, "--> nfs41_symlink_target('%s', '%s')\n", path->path, link);
113
114 /* append any components after the symlink */
116 file->name.name + file->name.len))) {
118 goto out;
119 }
120 link_len = (uint32_t)strlen(link);
121
122 /* overwrite the last component of the path; get the starting offset */
123 path_offset = file->name.name - path->path;
124
125 /* copy the path and update it with the results from link */
126 if (target != path) {
127 target->len = path->len;
129 path->path, path->len))) {
131 goto out;
132 }
133 }
134 status = abs_path_link(target, target->path + path_offset, link, link_len);
135 if (status) {
136 eprintf("abs_path_link() for path %s with link %s failed with %d\n",
137 target->path, link, status);
138 goto out;
139 }
140out:
141 dprintf(2, "<-- nfs41_symlink_target('%s') returning %d\n",
142 target->path, status);
143 return status;
144}
145
149 IN nfs41_path_fh *symlink,
151{
154 uint32_t depth = 0;
155 int status = NO_ERROR;
156
157 file.path = &path;
158 InitializeSRWLock(&path.lock);
159
160 dprintf(2, "--> nfs41_symlink_follow('%s')\n", symlink->path->path);
161
162 do {
165 goto out;
166 }
167
168 /* construct the target path */
170 if (status) goto out;
171
172 dprintf(2, "looking up '%s'\n", path.path);
173
174 last_component(path.path, path.path + path.len, &file.name);
175
176 /* get attributes for the target */
178 NULL, &file, info, &session);
179 if (status) goto out;
180
181 symlink = &file;
182 } while (info->type == NF4LNK);
183out:
184 dprintf(2, "<-- nfs41_symlink_follow() returning %d\n", status);
185 return status;
186}
187
188
189/* NFS41_SYMLINK */
191{
192 symlink_upcall_args *args = &upcall->args.symlink;
193 int status;
194
195 status = get_name(&buffer, &length, &args->path);
196 if (status) goto out;
197 status = safe_read(&buffer, &length, &args->set, sizeof(BOOLEAN));
198 if (status) goto out;
199
200 if (args->set)
201 status = get_name(&buffer, &length, &args->target_set);
202 else
203 args->target_set = NULL;
204
205 dprintf(1, "parsing NFS41_SYMLINK: path='%s' set=%u target='%s'\n",
206 args->path, args->set, args->target_set);
207out:
208 return status;
209}
210
212{
213 symlink_upcall_args *args = &upcall->args.symlink;
214 nfs41_open_state *state = upcall->state_ref;
215 int status = NO_ERROR;
216
217 if (args->set) {
218 nfs41_file_info info, createattrs;
219
220 /* don't send windows slashes to the server */
221 char *p;
222 for (p = args->target_set; *p; p++) if (*p == '\\') *p = '/';
223
224 if (state->file.fh.len) {
225 /* the check in handle_open() didn't catch that we're creating
226 * a symlink, so we have to remove the file it already created */
227 eprintf("handle_symlink: attempting to create a symlink when "
228 "the file=%s was already created on open; sending REMOVE "
229 "first\n", state->file.path->path);
230 status = nfs41_remove(state->session, &state->parent,
231 &state->file.name, state->file.fh.fileid);
232 if (status) {
233 eprintf("nfs41_remove() for symlink=%s failed with %s\n",
234 args->target_set, nfs_error_string(status));
236 goto out;
237 }
238 }
239
240 /* create the symlink */
241 createattrs.attrmask.count = 2;
242 createattrs.attrmask.arr[0] = 0;
243 createattrs.attrmask.arr[1] = FATTR4_WORD1_MODE;
244 createattrs.mode = 0777;
245 status = nfs41_create(state->session, NF4LNK, &createattrs,
246 args->target_set, &state->parent, &state->file, &info);
247 if (status) {
248 eprintf("nfs41_create() for symlink=%s failed with %s\n",
249 args->target_set, nfs_error_string(status));
251 goto out;
252 }
253 } else {
255
256 /* read the link */
257 status = nfs41_readlink(state->session, &state->file,
258 NFS41_MAX_PATH_LEN, args->target_get.path, &len);
259 if (status) {
260 eprintf("nfs41_readlink() for filename=%s failed with %s\n",
261 state->file.path->path, nfs_error_string(status));
263 goto out;
264 }
265 args->target_get.len = (unsigned short)len;
266 dprintf(2, "returning symlink target '%s'\n", args->target_get.path);
267 }
268out:
269 return status;
270}
271
273{
274 symlink_upcall_args *args = &upcall->args.symlink;
275 unsigned short len = (args->target_get.len + 1) * sizeof(WCHAR);
276 int status = NO_ERROR;
277
278 if (args->set)
279 goto out;
280
281 status = safe_write(&buffer, length, &len, sizeof(len));
282 if (status) goto out;
283
284 if (*length <= len || !MultiByteToWideChar(CP_UTF8, 0,
285 args->target_get.path, args->target_get.len,
286 (LPWSTR)buffer, len / sizeof(WCHAR))) {
288 goto out;
289 }
290out:
291 return status;
292}
293
294
299};
unsigned char BOOLEAN
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
static int state
Definition: maze.c:121
int nfs41_lookup(IN nfs41_root *root, IN nfs41_session *session, IN OUT nfs41_abs_path *path_inout, OUT OPTIONAL nfs41_path_fh *parent_out, OUT OPTIONAL nfs41_path_fh *target_out, OUT OPTIONAL nfs41_file_info *info_out, OUT nfs41_session **session_out)
Definition: lookup.c:424
bool_t last_component(IN const char *path, IN const char *path_end, OUT nfs41_component *component)
Definition: util.c:317
int safe_write(unsigned char **pos, uint32_t *remaining, void *src, uint32_t src_len)
Definition: util.c:44
int map_symlink_errors(int status)
Definition: util.c:293
int safe_read(unsigned char **pos, uint32_t *remaining, void *dest, uint32_t dest_len)
Definition: util.c:33
int get_name(unsigned char **pos, uint32_t *remaining, const char **out_name)
Definition: util.c:55
bool_t next_component(IN const char *path, IN const char *path_end, OUT nfs41_component *component)
Definition: util.c:305
__inline int is_delimiter(char c)
Definition: util.h:207
__inline const char * prev_delimiter(const char *pos, const char *start)
Definition: util.h:223
void eprintf(LPCSTR format,...)
Definition: daemon_debug.c:86
const char * nfs_error_string(int status)
Definition: daemon_debug.c:370
const WCHAR * link
Definition: db.cpp:997
#define NO_ERROR
Definition: dderror.h:5
#define NULL
Definition: types.h:112
UINT32 uint32_t
Definition: types.h:75
#define MultiByteToWideChar
Definition: compat.h:110
VOID WINAPI InitializeSRWLock(PSRWLOCK Lock)
Definition: sync.c:75
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:94
__kernel_ptrdiff_t ptrdiff_t
Definition: linux.h:247
GLint GLint GLsizei GLsizei GLsizei depth
Definition: gl.h:1546
GLuint buffer
Definition: glext.h:5915
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLenum target
Definition: glext.h:7315
#define FAILED(hr)
Definition: intsafe.h:51
#define NFS41_MAX_PATH_LEN
Definition: nfs41_const.h:46
@ FATTR4_WORD1_MODE
Definition: nfs41_const.h:245
@ NF4LNK
Definition: nfs41_const.h:298
#define NFS41_MAX_SYMLINK_DEPTH
Definition: nfs41_const.h:60
nfs41_updowncall_list upcall
Definition: nfs41_driver.c:273
int nfs41_create(IN nfs41_session *session, IN uint32_t type, IN nfs41_file_info *createattrs, IN OPTIONAL const char *symlink, IN nfs41_path_fh *parent, OUT nfs41_path_fh *file, OUT nfs41_file_info *info)
Definition: nfs41_ops.c:530
int nfs41_remove(IN nfs41_session *session, IN nfs41_path_fh *parent, IN const nfs41_component *target, IN uint64_t fileid)
Definition: nfs41_ops.c:1180
int nfs41_readlink(IN nfs41_session *session, IN nfs41_path_fh *file, IN uint32_t max_len, OUT char *link_out, OUT uint32_t *len_out)
Definition: nfs41_ops.c:1511
#define uint32_t
Definition: nsiface.idl:61
#define dprintf
Definition: regdump.c:33
static FILE * out
Definition: regtests2xml.c:44
#define CP_UTF8
Definition: nls.h:20
STRSAFEAPI StringCchCatA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc)
Definition: strsafe.h:320
STRSAFEAPI StringCchCopyNA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc, size_t cchToCopy)
Definition: strsafe.h:230
uint32_t count
Definition: nfs41_types.h:96
uint32_t arr[3]
Definition: nfs41_types.h:97
Definition: match.c:390
Definition: fci.c:127
WCHAR * path
Definition: filesystem.c:122
char name[1]
Definition: fci.c:135
Definition: name.c:39
WCHAR * name
Definition: name.c:42
Definition: ps.c:97
#define IN
Definition: typedefs.h:39
#define OUT
Definition: typedefs.h:40
#define ERROR_BAD_NETPATH
Definition: winerror.h:145
#define ERROR_BUFFER_OVERFLOW
Definition: winerror.h:185
#define ERROR_PATH_NOT_FOUND
Definition: winerror.h:106
#define ERROR_TOO_MANY_LINKS
Definition: winerror.h:671
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184