ReactOS  0.4.12-dev-51-ge94618b
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 
31 static 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");
61  status = ERROR_BAD_NETPATH;
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))) {
71  status = ERROR_BUFFER_OVERFLOW;
72  goto out;
73  }
74  path_pos += name.len;
75  if (FAILED(StringCchCopyNA(path_pos, path_max-path_pos, "\\", 1))) {
76  status = ERROR_BUFFER_OVERFLOW;
77  goto out;
78  }
79  }
80 
81  /* make sure the path is null terminated */
82  if (path_pos == path_max) {
83  status = ERROR_BUFFER_OVERFLOW;
84  goto out;
85  }
86  *path_pos = '\0';
87 out:
88  path->len = (unsigned short)(path_pos - path->path);
89  return status;
90 }
91 
93  IN nfs41_session *session,
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 */
104  status = nfs41_readlink(session, file, NFS41_MAX_PATH_LEN, link, &link_len);
105  if (status) {
106  eprintf("nfs41_readlink() for %s failed with %s\n", file->path->path,
107  nfs_error_string(status));
108  status = ERROR_PATH_NOT_FOUND;
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))) {
117  status = ERROR_BUFFER_OVERFLOW;
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;
128  if (FAILED(StringCchCopyNA(target->path, NFS41_MAX_PATH_LEN,
129  path->path, path->len))) {
130  status = ERROR_BUFFER_OVERFLOW;
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  }
140 out:
141  dprintf(2, "<-- nfs41_symlink_target('%s') returning %d\n",
142  target->path, status);
143  return status;
144 }
145 
147  IN nfs41_root *root,
148  IN nfs41_session *session,
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 {
163  if (++depth > NFS41_MAX_SYMLINK_DEPTH) {
164  status = ERROR_TOO_MANY_LINKS;
165  goto out;
166  }
167 
168  /* construct the target path */
169  status = nfs41_symlink_target(session, symlink, &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 */
177  status = nfs41_lookup(root, session, &path,
178  NULL, &file, info, &session);
179  if (status) goto out;
180 
181  symlink = &file;
182  } while (info->type == NF4LNK);
183 out:
184  dprintf(2, "<-- nfs41_symlink_follow() returning %d\n", status);
185  return status;
186 }
187 
188 
189 /* NFS41_SYMLINK */
190 static int parse_symlink(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
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);
207 out:
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));
235  status = map_symlink_errors(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));
250  status = map_symlink_errors(status);
251  goto out;
252  }
253  } else {
254  uint32_t len;
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));
262  status = map_symlink_errors(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  }
268 out:
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))) {
287  status = ERROR_BUFFER_OVERFLOW;
288  goto out;
289  }
290 out:
291  return status;
292 }
293 
294 
299 };
char * name
Definition: wpp.c:36
#define IN
Definition: typedefs.h:38
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
uint64_t fileid
Definition: nfs41_types.h:55
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define ERROR_BUFFER_OVERFLOW
Definition: winerror.h:185
GLsizei const GLchar ** path
Definition: glext.h:7234
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
GLuint buffer
Definition: glext.h:5915
void eprintf(LPCSTR format,...)
Definition: daemon_debug.c:86
#define NO_ERROR
Definition: dderror.h:5
uint32_t arr[3]
Definition: nfs41_types.h:97
Definition: match.c:390
int map_symlink_errors(int status)
Definition: util.c:293
#define ERROR_BAD_NETPATH
Definition: winerror.h:145
struct __nfs41_session * session
Definition: nfs41.h:132
bool_t last_component(IN const char *path, IN const char *path_end, OUT nfs41_component *component)
Definition: util.c:317
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
struct _test_info info[]
Definition: SetCursorPos.c:19
#define NFS41_MAX_PATH_LEN
Definition: nfs41_const.h:46
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:91
STRSAFEAPI StringCchCopyNA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc, size_t cchToCopy)
Definition: strsafe.h:230
#define CP_UTF8
Definition: nls.h:20
nfs41_open_state * state_ref
Definition: upcall.h:207
STRSAFEAPI StringCchCatA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc)
Definition: strsafe.h:320
#define dprintf
Definition: regdump.c:33
symlink_upcall_args symlink
Definition: upcall.h:187
uint32_t count
Definition: nfs41_types.h:96
int get_name(unsigned char **pos, uint32_t *remaining, const char **out_name)
Definition: util.c:55
__inline const char * prev_delimiter(const char *pos, const char *start)
Definition: util.h:223
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
bool_t next_component(IN const char *path, IN const char *path_end, OUT nfs41_component *component)
Definition: util.c:305
uint32_t len
Definition: nfs41_types.h:54
nfs41_abs_path * path
Definition: nfs41_types.h:60
upcall_args args
Definition: upcall.h:198
const char * name
Definition: nfs41_types.h:48
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
unsigned short len
Definition: nfs41_types.h:43
const char file[]
Definition: icontest.c:11
static FILE * out
Definition: regtests2xml.c:44
int safe_write(unsigned char **pos, uint32_t *remaining, void *src, uint32_t src_len)
Definition: util.c:44
const char * nfs_error_string(int status)
Definition: daemon_debug.c:370
GLint GLint GLsizei GLsizei GLsizei depth
Definition: gl.h:1546
#define ERROR_TOO_MANY_LINKS
Definition: winerror.h:671
static int state
Definition: maze.c:121
nfs41_path_fh parent
Definition: nfs41.h:129
GLenum GLsizei len
Definition: glext.h:6722
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
VOID WINAPI InitializeSRWLock(PSRWLOCK Lock)
Definition: sync.c:75
nfs41_path_fh file
Definition: nfs41.h:130
nfs41_component name
Definition: nfs41_types.h:61
Definition: services.c:325
__kernel_ptrdiff_t ptrdiff_t
Definition: linux.h:247
UINT32 uint32_t
Definition: types.h:75
#define MultiByteToWideChar
Definition: compat.h:100
#define NFS41_MAX_SYMLINK_DEPTH
Definition: nfs41_const.h:60
nfs41_updowncall_list upcall
Definition: nfs41_driver.c:273
#define OUT
Definition: typedefs.h:39
int safe_read(unsigned char **pos, uint32_t *remaining, void *dest, uint32_t dest_len)
Definition: util.c:33
const WCHAR * link
Definition: db.cpp:926
#define ERROR_PATH_NOT_FOUND
Definition: winerror.h:106
char path[NFS41_MAX_PATH_LEN]
Definition: nfs41_types.h:42
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define uint32_t
Definition: nsiface.idl:61
unsigned short len
Definition: nfs41_types.h:49
static SERVICE_STATUS status
Definition: service.c:31
__inline int is_delimiter(char c)
Definition: util.h:207
Definition: fci.c:126
Definition: ps.c:97
GLuint const GLchar * name
Definition: glext.h:6031