ReactOS 0.4.15-dev-6669-g8227c5d
open.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 <stdio.h>
24#include <strsafe.h>
25
26#include "nfs41_ops.h"
27#include "delegation.h"
28#include "from_kernel.h"
29#include "daemon_debug.h"
30#include "upcall.h"
31#include "util.h"
32
33
35 IN const char *path,
37 OUT nfs41_open_state **state_out)
38{
39 int status;
41
42 state = calloc(1, sizeof(nfs41_open_state));
43 if (state == NULL) {
45 goto out;
46 }
47
48 InitializeSRWLock(&state->path.lock);
51 goto out_free;
52 }
53 state->path.len = (unsigned short)strlen(state->path.path);
54 path_fh_init(&state->file, &state->path);
55 path_fh_init(&state->parent, &state->path);
56 last_component(state->path.path, state->file.name.name, &state->parent.name);
57
58 StringCchPrintfA((LPSTR)state->owner.owner, NFS4_OPAQUE_LIMIT, "%u",
60 state->owner.owner_len = (uint32_t)strlen((const char*)state->owner.owner);
61 state->ref_count = 1;
62 list_init(&state->locks.list);
63 list_init(&state->client_entry);
64 InitializeCriticalSection(&state->locks.lock);
65
66 state->ea.list = INVALID_HANDLE_VALUE;
68
69 *state_out = state;
71out:
72 return status;
73
74out_free:
75 free(state);
76 goto out;
77}
78
79static void open_state_free(
81{
82 struct list_entry *entry, *tmp;
83
84 /* free associated lock state */
85 list_for_each_tmp(entry, tmp, &state->locks.list)
87 if (state->delegation.state)
88 nfs41_delegation_deref(state->delegation.state);
89 if (state->ea.list != INVALID_HANDLE_VALUE)
90 free(state->ea.list);
91 free(state);
92}
93
94
95/* open state reference counting */
98{
99 const LONG count = InterlockedIncrement(&state->ref_count);
100
101 dprintf(2, "nfs41_open_state_ref(%s) count %d\n", state->path.path, count);
102}
103
106{
107 const LONG count = InterlockedDecrement(&state->ref_count);
108
109 dprintf(2, "nfs41_open_state_deref(%s) count %d\n", state->path.path, count);
110 if (count == 0)
112}
113
114/* 8.2.5. Stateid Use for I/O Operations
115 * o If the client holds a delegation for the file in question, the
116 * delegation stateid SHOULD be used.
117 * o Otherwise, if the entity corresponding to the lock-owner (e.g., a
118 * process) sending the I/O has a byte-range lock stateid for the
119 * associated open file, then the byte-range lock stateid for that
120 * lock-owner and open file SHOULD be used.
121 * o If there is no byte-range lock stateid, then the OPEN stateid for
122 * the open file in question SHOULD be used.
123 * o Finally, if none of the above apply, then a special stateid SHOULD
124 * be used. */
128{
129 arg->open = state;
130 arg->delegation = NULL;
131
133
134 if (state->delegation.state) {
135 nfs41_delegation_state *deleg = state->delegation.state;
136 AcquireSRWLockShared(&deleg->lock);
137 if (deleg->status == DELEGATION_GRANTED) {
138 arg->type = STATEID_DELEG_FILE;
139 memcpy(&arg->stateid, &deleg->state.stateid, sizeof(stateid4));
140 }
141 ReleaseSRWLockShared(&deleg->lock);
142
143 if (arg->type == STATEID_DELEG_FILE)
144 goto out;
145
146 dprintf(2, "delegation recalled, waiting for open stateid..\n");
147
148 /* wait for nfs41_delegation_to_open() to recover open stateid */
149 while (!state->do_close)
150 SleepConditionVariableSRW(&state->delegation.cond, &state->lock,
151 INFINITE, CONDITION_VARIABLE_LOCKMODE_SHARED);
152 }
153
154 if (state->locks.stateid.seqid) {
155 memcpy(&arg->stateid, &state->locks.stateid, sizeof(stateid4));
156 arg->type = STATEID_LOCK;
157 } else if (state->do_close) {
158 memcpy(&arg->stateid, &state->stateid, sizeof(stateid4));
159 arg->type = STATEID_OPEN;
160 } else {
161 memset(&arg->stateid, 0, sizeof(stateid4));
162 arg->type = STATEID_SPECIAL;
163 }
164out:
166}
167
168/* client list of associated open state */
171{
172 nfs41_client *client = state->session->client;
173
174 EnterCriticalSection(&client->state.lock);
175 list_add_tail(&client->state.opens, &state->client_entry);
176 LeaveCriticalSection(&client->state.lock);
177}
178
181{
182 nfs41_client *client = state->session->client;
183
184 EnterCriticalSection(&client->state.lock);
185 list_remove(&state->client_entry);
186 LeaveCriticalSection(&client->state.lock);
187}
188
189static int do_open(
192 IN uint32_t createhow,
193 IN nfs41_file_info *createattrs,
194 IN bool_t try_recovery,
196{
197 open_claim4 claim;
198 stateid4 open_stateid;
199 open_delegation4 delegation = { 0 };
200 nfs41_delegation_state *deleg_state = NULL;
201 int status;
202
203 claim.claim = CLAIM_NULL;
204 claim.u.null.filename = &state->file.name;
205
206 status = nfs41_open(state->session, &state->parent, &state->file,
207 &state->owner, &claim, state->share_access, state->share_deny,
208 create, createhow, createattrs, TRUE, &open_stateid,
209 &delegation, info);
210 if (status)
211 goto out;
212
213 /* allocate delegation state and register it with the client */
214 nfs41_delegation_granted(state->session, &state->parent,
215 &state->file, &delegation, TRUE, &deleg_state);
216 if (deleg_state) {
217 deleg_state->srv_open = state->srv_open;
218 dprintf(1, "do_open: received delegation: saving srv_open = %x\n",
219 state->srv_open);
220 }
221
223 /* update the stateid */
224 memcpy(&state->stateid, &open_stateid, sizeof(open_stateid));
225 state->do_close = 1;
226 state->delegation.state = deleg_state;
228out:
229 return status;
230}
231
235 IN uint32_t createhow,
236 IN nfs41_file_info *createattrs,
237 IN bool_t try_recovery,
239{
240 int status;
241
242 /* check for existing delegation */
243 status = nfs41_delegate_open(state, create, createattrs, info);
244
245 /* get an open stateid if we have no delegation stateid */
246 if (status)
247 status = do_open(state, create, createhow,
248 createattrs, try_recovery, info);
249
250 state->pnfs_last_offset = info->size ? info->size - 1 : 0;
251
252 /* register the client's open state on success */
253 if (status == NFS4_OK)
255 return status;
256}
257
258
260{
261 int status = safe_read(buffer, length, &path->len, sizeof(USHORT));
262 if (status) goto out;
263 if (path->len == 0)
264 goto out;
265 if (path->len >= NFS41_MAX_PATH_LEN) {
267 goto out;
268 }
269 status = safe_read(buffer, length, path->path, path->len);
270 if (status) goto out;
271 path->len--; /* subtract 1 for null */
272out:
273 return status;
274}
275
276/* NFS41_OPEN */
277static int parse_open(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
278{
279 int status;
280 open_upcall_args *args = &upcall->args.open;
281
282 status = get_name(&buffer, &length, &args->path);
283 if (status) goto out;
284 status = safe_read(&buffer, &length, &args->access_mask, sizeof(ULONG));
285 if (status) goto out;
286 status = safe_read(&buffer, &length, &args->access_mode, sizeof(ULONG));
287 if (status) goto out;
288 status = safe_read(&buffer, &length, &args->file_attrs, sizeof(ULONG));
289 if (status) goto out;
290 status = safe_read(&buffer, &length, &args->create_opts, sizeof(ULONG));
291 if (status) goto out;
292 status = safe_read(&buffer, &length, &args->disposition, sizeof(ULONG));
293 if (status) goto out;
294 status = safe_read(&buffer, &length, &args->open_owner_id, sizeof(LONG));
295 if (status) goto out;
296 status = safe_read(&buffer, &length, &args->mode, sizeof(DWORD));
297 if (status) goto out;
298 status = safe_read(&buffer, &length, &args->srv_open, sizeof(HANDLE));
299 if (status) goto out;
300 status = parse_abs_path(&buffer, &length, &args->symlink);
301 if (status) goto out;
302 status = safe_read(&buffer, &length, &args->ea, sizeof(HANDLE));
303 if (status) goto out;
304
305 dprintf(1, "parsing NFS41_OPEN: filename='%s' access mask=%d "
306 "access mode=%d\n\tfile attrs=0x%x create attrs=0x%x "
307 "(kernel) disposition=%d\n\topen_owner_id=%d mode=%o "
308 "srv_open=%p symlink=%s ea=%p\n", args->path, args->access_mask,
309 args->access_mode, args->file_attrs, args->create_opts,
310 args->disposition, args->open_owner_id, args->mode, args->srv_open,
311 args->symlink.path, args->ea);
312 print_disposition(2, args->disposition);
313 print_access_mask(2, args->access_mask);
314 print_share_mode(2, args->access_mode);
315 print_create_attributes(2, args->create_opts);
316out:
317 return status;
318}
319
321 ULONG disposition, int status)
322{
323 if (type == NF4DIR) {
324 if (disposition == FILE_OPEN || disposition == FILE_OVERWRITE ||
325 (!status && (disposition == FILE_OPEN_IF ||
326 disposition == FILE_OVERWRITE_IF ||
327 disposition == FILE_SUPERSEDE))) {
328 dprintf(1, "Opening a directory\n");
329 return TRUE;
330 } else {
331 dprintf(1, "Creating a directory\n");
332 return FALSE;
333 }
334 }
335
336 if ((access_mask & FILE_READ_DATA) ||
337 (access_mask & FILE_WRITE_DATA) ||
338 (access_mask & FILE_APPEND_DATA) ||
339 (access_mask & FILE_EXECUTE) ||
340 disposition == FILE_CREATE ||
341 disposition == FILE_OVERWRITE_IF ||
342 disposition == FILE_SUPERSEDE ||
343 disposition == FILE_OPEN_IF ||
344 disposition == FILE_OVERWRITE)
345 return FALSE;
346 else {
347 dprintf(1, "Open call that wants to manage attributes\n");
348 return TRUE;
349 }
350}
351
352static int map_disposition_2_nfsopen(ULONG disposition, int in_status, bool_t persistent,
353 uint32_t *create, uint32_t *createhowmode,
355{
356 int status = NO_ERROR;
357 if (disposition == FILE_SUPERSEDE) {
358 if (in_status == NFS4ERR_NOENT)
360 //remove and recreate the file
362 if (persistent) *createhowmode = GUARDED4;
363 else *createhowmode = EXCLUSIVE4_1;
364 } else if (disposition == FILE_CREATE) {
365 // if lookup succeeded which means the file exist, return an error
366 if (!in_status)
368 else {
370 if (persistent) *createhowmode = GUARDED4;
371 else *createhowmode = EXCLUSIVE4_1;
372 }
373 } else if (disposition == FILE_OPEN) {
374 if (in_status == NFS4ERR_NOENT)
376 else
378 } else if (disposition == FILE_OPEN_IF) {
379 if (in_status == NFS4ERR_NOENT) {
380 dprintf(1, "creating new file\n");
383 } else {
384 dprintf(1, "opening existing file\n");
386 }
387 } else if (disposition == FILE_OVERWRITE) {
388 if (in_status == NFS4ERR_NOENT)
390 //truncate file
392 } else if (disposition == FILE_OVERWRITE_IF) {
393 if (in_status == NFS4ERR_NOENT)
395 //truncate file
397 }
398 return status;
399}
400
401static void map_access_2_allowdeny(ULONG access_mask, ULONG access_mode,
402 ULONG disposition, uint32_t *allow, uint32_t *deny)
403{
404 if ((access_mask &
406 (access_mask & (FILE_READ_DATA | FILE_EXECUTE)))
408 else if (access_mask & (FILE_READ_DATA | FILE_EXECUTE))
410 else if (access_mask &
413 /* if we are creating a file and no data access is specified, then
414 * do an open and request no delegations. example open with share access 0
415 * and share deny 0 (ie deny_both).
416 */
417 if ((disposition == FILE_CREATE || disposition == FILE_OPEN_IF ||
418 disposition == FILE_OVERWRITE_IF || disposition == FILE_SUPERSEDE ||
419 disposition == FILE_OVERWRITE) &&
420 !(access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA |
423
424#define FIX_ALLOW_DENY_WIN2NFS_CONVERSION
425#ifdef FIX_ALLOW_DENY_WIN2NFS_CONVERSION
426 if ((access_mode & FILE_SHARE_READ) &&
427 (access_mode & FILE_SHARE_WRITE))
428 *deny = OPEN4_SHARE_DENY_NONE;
429 else if (access_mode & FILE_SHARE_READ)
431 else if (access_mode & FILE_SHARE_WRITE)
432 *deny = OPEN4_SHARE_DENY_READ;
433 else
434 *deny = OPEN4_SHARE_DENY_BOTH;
435#else
436 // AGLO: 11/13/2009.
437 // readonly file that is being opened for reading with a
438 // share read mode given above logic translates into deny
439 // write and linux server does not allow it.
440 *deny = OPEN4_SHARE_DENY_NONE;
441#endif
442}
443
445{
446 uint32_t supported, access;
447 int status = nfs41_access(state->session, &state->file,
448 ACCESS4_EXECUTE | ACCESS4_READ, &supported, &access);
449 if (status) {
450 eprintf("nfs41_access() failed with %s for %s\n",
451 nfs_error_string(status), state->path.path);
453 } else if ((supported & ACCESS4_EXECUTE) == 0) {
454 /* server can't verify execute access;
455 * for now, assume that read access is good enough */
456 if ((supported & ACCESS4_READ) == 0 || (access & ACCESS4_READ) == 0) {
457 eprintf("server can't verify execute access, and user does "
458 "not have read access to file %s\n", state->path.path);
460 }
461 } else if ((access & ACCESS4_EXECUTE) == 0) {
462 dprintf(1, "user does not have execute access to file %s\n",
463 state->path.path);
465 } else
466 dprintf(2, "user has execute access to file\n");
467 return status;
468}
469
470static int create_with_ea(
471 IN uint32_t disposition,
472 IN uint32_t lookup_status)
473{
474 /* only set EAs on file creation */
475 return disposition == FILE_SUPERSEDE || disposition == FILE_CREATE
476 || disposition == FILE_OVERWRITE || disposition == FILE_OVERWRITE_IF
477 || (disposition == FILE_OPEN_IF && lookup_status == NFS4ERR_NOENT);
478}
479
481{
482 int status = 0;
483 open_upcall_args *args = &upcall->args.open;
485 nfs41_file_info info = { 0 };
486
487 status = create_open_state(args->path, args->open_owner_id, &state);
488 if (status) {
489 eprintf("create_open_state(%d) failed with %d\n",
490 args->open_owner_id, status);
491 goto out;
492 }
493 state->srv_open = args->srv_open;
494
495 // first check if windows told us it's a directory
496 if (args->create_opts & FILE_DIRECTORY_FILE)
497 state->type = NF4DIR;
498 else
499 state->type = NF4REG;
500
501 // always do a lookup
502 status = nfs41_lookup(upcall->root_ref, nfs41_root_session(upcall->root_ref),
503 &state->path, &state->parent, &state->file, &info, &state->session);
504
505 if (status == ERROR_REPARSE) {
506 uint32_t depth = 0;
507 /* one of the parent components was a symlink */
508 do {
511 goto out_free_state;
512 }
513
514 /* replace the path with the symlink target's */
516 &state->parent, &state->path);
517 if (status) {
518 /* can't do the reparse if we can't get the target */
519 eprintf("nfs41_symlink_target() failed with %d\n", status);
520 goto out_free_state;
521 }
522
523 /* redo the lookup until it doesn't return REPARSE */
524 status = nfs41_lookup(upcall->root_ref, state->session,
525 &state->path, &state->parent, NULL, NULL, &state->session);
526 } while (status == ERROR_REPARSE);
527
529 abs_path_copy(&args->symlink, &state->path);
531 upcall->last_error = ERROR_REPARSE;
532 args->symlink_embedded = TRUE;
533 }
534 goto out_free_state;
535 }
536
537 // now if file/dir exists, use type returned by lookup
538 if (status == NO_ERROR) {
539 if (info.type == NF4DIR) {
540 dprintf(2, "handle_nfs41_open: DIRECTORY\n");
541 if (args->create_opts & FILE_NON_DIRECTORY_FILE) {
542 eprintf("trying to open directory %s as a file\n",
543 state->path.path);
545 goto out_free_state;
546 }
547 } else if (info.type == NF4REG) {
548 dprintf(2, "handle nfs41_open: FILE\n");
549 if (args->create_opts & FILE_DIRECTORY_FILE) {
550 eprintf("trying to open file %s as a directory\n",
551 state->path.path);
553 goto out_free_state;
554 }
555 } else if (info.type == NF4LNK) {
556 dprintf(2, "handle nfs41_open: SYMLINK\n");
557 if (args->create_opts & FILE_OPEN_REPARSE_POINT) {
558 /* continue and open the symlink itself, but we need to
559 * know if the target is a regular file or directory */
561 int target_status = nfs41_symlink_follow(upcall->root_ref,
562 state->session, &state->file, &target_info);
563 if (target_status == NO_ERROR && target_info.type == NF4DIR)
564 info.symlink_dir = TRUE;
565 } else {
566 /* replace the path with the symlink target */
568 &state->file, &args->symlink);
569 if (status) {
570 eprintf("nfs41_symlink_target() for %s failed with %d\n",
571 args->path, status);
572 } else {
573 /* tell the driver to call RxPrepareToReparseSymbolicLink() */
574 upcall->last_error = ERROR_REPARSE;
575 args->symlink_embedded = FALSE;
576 }
577 goto out_free_state;
578 }
579 } else
580 dprintf(2, "handle_open(): unsupported type=%d\n", info.type);
581 state->type = info.type;
582 } else if (status != ERROR_FILE_NOT_FOUND)
583 goto out_free_state;
584
585 /* XXX: this is a hard-coded check for the open arguments we see from
586 * the CreateSymbolicLink() system call. we respond to this by deferring
587 * the CREATE until we get the upcall to set the symlink. this approach
588 * is troublesome for two reasons:
589 * -an application might use these exact arguments to create a normal
590 * file, and we would return success without actually creating it
591 * -an application could create a symlink by sending the FSCTL to set
592 * the reparse point manually, and their open might be different. in
593 * this case we'd create the file on open, and need to remove it
594 * before creating the symlink */
595 if (args->disposition == FILE_CREATE &&
596 args->access_mask == (FILE_WRITE_ATTRIBUTES | SYNCHRONIZE | DELETE) &&
597 args->access_mode == 0 &&
598 args->create_opts & FILE_OPEN_REPARSE_POINT) {
599 /* fail if the file already exists */
600 if (status == NO_ERROR) {
602 goto out_free_state;
603 }
604
605 /* defer the call to CREATE until we get the symlink set upcall */
606 dprintf(1, "trying to create a symlink, deferring create\n");
607
608 /* because of WRITE_ATTR access, be prepared for a setattr upcall;
609 * will crash if the superblock is null, so use the parent's */
610 state->file.fh.superblock = state->parent.fh.superblock;
611
613 } else if (args->symlink.len) {
614 /* handle cygwin symlinks */
615 nfs41_file_info createattrs;
616 createattrs.attrmask.count = 2;
617 createattrs.attrmask.arr[0] = 0;
618 createattrs.attrmask.arr[1] = FATTR4_WORD1_MODE;
619 createattrs.mode = 0777;
620
621 dprintf(1, "creating cygwin symlink %s -> %s\n",
622 state->file.name.name, args->symlink.path);
623
624 status = nfs41_create(state->session, NF4LNK, &createattrs,
625 args->symlink.path, &state->parent, &state->file, &info);
626 if (status) {
627 eprintf("nfs41_create() for symlink=%s failed with %s\n",
628 args->symlink.path, nfs_error_string(status));
630 goto out_free_state;
631 }
632 nfs_to_basic_info(&info, &args->basic_info);
633 nfs_to_standard_info(&info, &args->std_info);
634 args->mode = info.mode;
635 args->changeattr = info.change;
636 } else if (open_for_attributes(state->type, args->access_mask,
637 args->disposition, status)) {
638 if (status) {
639 dprintf(1, "nfs41_lookup failed with %d\n", status);
640 goto out_free_state;
641 }
642
643 nfs_to_basic_info(&info, &args->basic_info);
644 nfs_to_standard_info(&info, &args->std_info);
645 args->mode = info.mode;
646 args->changeattr = info.change;
647 } else {
648 nfs41_file_info createattrs = { 0 };
649 uint32_t create = 0, createhowmode = 0, lookup_status = status;
650
651 if (!lookup_status && (args->disposition == FILE_OVERWRITE ||
652 args->disposition == FILE_OVERWRITE_IF ||
653 args->disposition == FILE_SUPERSEDE)) {
654 if ((info.hidden && !(args->file_attrs & FILE_ATTRIBUTE_HIDDEN)) ||
655 (info.system && !(args->file_attrs & FILE_ATTRIBUTE_SYSTEM))) {
657 goto out_free_state;
658 }
659 if (args->disposition != FILE_SUPERSEDE)
660 args->mode = info.mode;
661 }
662 createattrs.attrmask.count = 2;
665 createattrs.mode = args->mode;
666 createattrs.hidden = args->file_attrs & FILE_ATTRIBUTE_HIDDEN ? 1 : 0;
667 createattrs.system = args->file_attrs & FILE_ATTRIBUTE_SYSTEM ? 1 : 0;
668 createattrs.archive = args->file_attrs & FILE_ATTRIBUTE_ARCHIVE ? 1 : 0;
669
670 map_access_2_allowdeny(args->access_mask, args->access_mode,
671 args->disposition, &state->share_access, &state->share_deny);
673 state->session->flags & CREATE_SESSION4_FLAG_PERSIST,
674 &create, &createhowmode, &upcall->last_error);
675 if (status)
676 goto out_free_state;
677
678 if (args->access_mask & FILE_EXECUTE && state->file.fh.len) {
680 if (status)
681 goto out_free_state;
682 }
683
684supersede_retry:
685 // XXX file exists and we have to remove it first
686 if (args->disposition == FILE_SUPERSEDE && lookup_status == NO_ERROR) {
687 nfs41_component *name = &state->file.name;
688 if (!(args->create_opts & FILE_DIRECTORY_FILE))
689 nfs41_delegation_return(state->session, &state->file,
691
692 dprintf(1, "open for FILE_SUPERSEDE removing %s first\n", name->name);
693 status = nfs41_remove(state->session, &state->parent,
694 name, state->file.fh.fileid);
695 if (status)
696 goto out_free_state;
697 }
698
699 if (create == OPEN4_CREATE && (args->create_opts & FILE_DIRECTORY_FILE)) {
700 status = nfs41_create(state->session, NF4DIR, &createattrs, NULL,
701 &state->parent, &state->file, &info);
702 args->created = status == NFS4_OK ? TRUE : FALSE;
703 } else {
704 createattrs.attrmask.arr[0] |= FATTR4_WORD0_SIZE;
705 createattrs.size = 0;
706 dprintf(1, "creating with mod %o\n", args->mode);
707 status = open_or_delegate(state, create, createhowmode, &createattrs,
708 TRUE, &info);
709 if (status == NFS4_OK && state->delegation.state)
710 args->deleg_type = state->delegation.state->state.type;
711 }
712 if (status) {
713 dprintf(1, "%s failed with %s\n", (create == OPEN4_CREATE &&
714 (args->create_opts & FILE_DIRECTORY_FILE))?"nfs41_create":"nfs41_open",
716 if (args->disposition == FILE_SUPERSEDE && status == NFS4ERR_EXIST)
717 goto supersede_retry;
719 goto out_free_state;
720 } else {
721 nfs_to_basic_info(&info, &args->basic_info);
722 nfs_to_standard_info(&info, &args->std_info);
723 args->mode = info.mode;
724 args->changeattr = info.change;
725 }
726
727 /* set extended attributes on file creation */
728 if (args->ea && create_with_ea(args->disposition, lookup_status)) {
731 }
732 }
733
734 upcall->state_ref = state;
735 nfs41_open_state_ref(upcall->state_ref);
736out:
737 return status;
738out_free_state:
740 goto out;
741}
742
744{
745 int status;
746 open_upcall_args *args = &upcall->args.open;
747
748 status = safe_write(&buffer, length, &args->basic_info, sizeof(args->basic_info));
749 if (status) goto out;
750 status = safe_write(&buffer, length, &args->std_info, sizeof(args->std_info));
751 if (status) goto out;
752 status = safe_write(&buffer, length, &upcall->state_ref, sizeof(HANDLE));
753 if (status) goto out;
754 status = safe_write(&buffer, length, &args->mode, sizeof(args->mode));
755 if (status) goto out;
756 status = safe_write(&buffer, length, &args->changeattr, sizeof(args->changeattr));
757 if (status) goto out;
758 status = safe_write(&buffer, length, &args->deleg_type, sizeof(args->deleg_type));
759 if (status) goto out;
760 if (upcall->last_error == ERROR_REPARSE) {
761 unsigned short len = (args->symlink.len + 1) * sizeof(WCHAR);
762 status = safe_write(&buffer, length, &args->symlink_embedded, sizeof(BOOLEAN));
763 if (status) goto out;
764 status = safe_write(&buffer, length, &len, sizeof(len));
765 if (status) goto out;
766 /* convert args->symlink to wchar */
767 if (*length <= len || !MultiByteToWideChar(CP_UTF8, 0,
768 args->symlink.path, args->symlink.len,
769 (LPWSTR)buffer, len / sizeof(WCHAR))) {
771 goto out;
772 }
773 }
774 dprintf(2, "NFS41_OPEN: downcall open_state=0x%p mode %o changeattr 0x%llu\n",
775 upcall->state_ref, args->mode, args->changeattr);
776out:
777 return status;
778}
779
781{
782 int status = NFS4_OK;
783 open_upcall_args *args = &upcall->args.open;
784 nfs41_open_state *state = upcall->state_ref;
785
786 dprintf(1, "--> cancel_open('%s')\n", args->path);
787
788 if (upcall->state_ref == NULL ||
789 upcall->state_ref == INVALID_HANDLE_VALUE)
790 goto out; /* if handle_open() failed, the state was already freed */
791
792 if (state->do_close) {
793 stateid_arg stateid;
794 stateid.open = state;
795 stateid.delegation = NULL;
796 stateid.type = STATEID_OPEN;
797 memcpy(&stateid.stateid, &state->stateid, sizeof(stateid4));
798
799 status = nfs41_close(state->session, &state->file, &stateid);
800 if (status)
801 dprintf(1, "cancel_open: nfs41_close() failed with %s\n",
803
804 } else if (args->created) {
805 const nfs41_component *name = &state->file.name;
806 /* break any delegations and truncate before REMOVE */
807 nfs41_delegation_return(state->session, &state->file,
809 status = nfs41_remove(state->session, &state->parent,
810 name, state->file.fh.fileid);
811 if (status)
812 dprintf(1, "cancel_open: nfs41_remove() failed with %s\n",
814 }
815
816 /* remove from the client's list of state for recovery */
819out:
821 dprintf(1, "<-- cancel_open() returning %d\n", status);
822}
823
824
825/* NFS41_CLOSE */
827{
828 int status;
829 close_upcall_args *args = &upcall->args.close;
830
831 status = safe_read(&buffer, &length, &args->remove, sizeof(BOOLEAN));
832 if (status) goto out;
833 status = safe_read(&buffer, &length, &args->srv_open, sizeof(HANDLE));
834 if (status) goto out;
835 if (args->remove) {
836 status = get_name(&buffer, &length, &args->path);
837 if (status) goto out;
838 status = safe_read(&buffer, &length, &args->renamed, sizeof(BOOLEAN));
839 if (status) goto out;
840 }
841
842 dprintf(1, "parsing NFS41_CLOSE: remove=%d srv_open=%x renamed=%d "
843 "filename='%s'\n", args->remove, args->srv_open, args->renamed,
844 args->remove ? args->path : "");
845out:
846 return status;
847}
848
850{
851 int status;
852 stateid_arg stateid;
853 stateid.open = state;
854 stateid.delegation = NULL;
855 stateid.type = STATEID_OPEN;
856 memcpy(&stateid.stateid, &state->stateid, sizeof(stateid4));
857
858 status = nfs41_close(state->session, &state->file, &stateid);
859 if (status) {
860 dprintf(1, "nfs41_close() failed with error %s.\n",
863 }
864
865 return status;
866}
867
869{
870 int status = NFS4_OK, rm_status = NFS4_OK;
871 close_upcall_args *args = &upcall->args.close;
872 nfs41_open_state *state = upcall->state_ref;
873
874 /* return associated file layouts if necessary */
875 if (state->type == NF4REG)
876 pnfs_layout_state_close(state->session, state, args->remove);
877
878 if (state->srv_open == args->srv_open)
880
881 if (args->remove) {
882 nfs41_component *name = &state->file.name;
883
884 if (args->renamed) {
885 dprintf(1, "removing a renamed file %s\n", name->name);
886 create_silly_rename(&state->path, &state->file.fh, name);
888 if (status)
889 goto out;
890 else
891 state->do_close = 0;
892 }
893
894 /* break any delegations and truncate before REMOVE */
895 nfs41_delegation_return(state->session, &state->file,
897
898 dprintf(1, "calling nfs41_remove for %s\n", name->name);
899retry_delete:
900 rm_status = nfs41_remove(state->session, &state->parent,
901 name, state->file.fh.fileid);
902 if (rm_status) {
903 if (rm_status == NFS4ERR_FILE_OPEN) {
905 if (!status) {
906 state->do_close = 0;
907 goto retry_delete;
908 } else goto out;
909 }
910 dprintf(1, "nfs41_remove() failed with error %s.\n",
911 nfs_error_string(rm_status));
912 rm_status = nfs_to_windows_error(rm_status, ERROR_INTERNAL_ERROR);
913 }
914 }
915
916 if (state->do_close) {
918 }
919out:
920 /* remove from the client's list of state for recovery */
922
923 if (status || !rm_status)
924 return status;
925 else
926 return rm_status;
927}
928
930{
931 /* release the initial reference from create_open_state() */
932 nfs41_open_state_deref(upcall->state_ref);
933}
934
935
941};
945 NULL,
946 NULL,
948};
unsigned char BOOLEAN
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
static int state
Definition: maze.c:121
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
#define FILE_DIRECTORY_FILE
Definition: constants.h:491
#define FILE_NON_DIRECTORY_FILE
Definition: constants.h:492
int nfs41_ea_set(IN nfs41_open_state *state, IN PFILE_FULL_EA_INFORMATION ea)
Definition: ea.c:116
static void list_remove(struct list_entry *entry)
Definition: list.h:90
#define list_container(entry, type, field)
Definition: list.h:33
#define list_for_each_tmp(entry, tmp, head)
Definition: list.h:39
static void list_add_tail(struct list_entry *head, struct list_entry *entry)
Definition: list.h:83
static void list_init(struct list_entry *head)
Definition: list.h:51
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
const nfs41_upcall_op nfs41_op_close
Definition: open.c:942
static int map_disposition_2_nfsopen(ULONG disposition, int in_status, bool_t persistent, uint32_t *create, uint32_t *createhowmode, uint32_t *last_error)
Definition: open.c:352
static int do_nfs41_close(nfs41_open_state *state)
Definition: open.c:849
static int handle_open(nfs41_upcall *upcall)
Definition: open.c:480
static int parse_open(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
Definition: open.c:277
void nfs41_open_state_deref(IN nfs41_open_state *state)
Definition: open.c:104
const nfs41_upcall_op nfs41_op_open
Definition: open.c:936
static void client_state_add(IN nfs41_open_state *state)
Definition: open.c:169
void nfs41_open_state_ref(IN nfs41_open_state *state)
Definition: open.c:96
static int create_open_state(IN const char *path, IN uint32_t open_owner_id, OUT nfs41_open_state **state_out)
Definition: open.c:34
static void cancel_open(IN nfs41_upcall *upcall)
Definition: open.c:780
static BOOLEAN open_for_attributes(uint32_t type, ULONG access_mask, ULONG disposition, int status)
Definition: open.c:320
static int handle_close(nfs41_upcall *upcall)
Definition: open.c:868
static void open_state_free(IN nfs41_open_state *state)
Definition: open.c:79
static void cleanup_close(nfs41_upcall *upcall)
Definition: open.c:929
static int create_with_ea(IN uint32_t disposition, IN uint32_t lookup_status)
Definition: open.c:470
static int check_execute_access(nfs41_open_state *state)
Definition: open.c:444
static int open_or_delegate(IN OUT nfs41_open_state *state, IN uint32_t create, IN uint32_t createhow, IN nfs41_file_info *createattrs, IN bool_t try_recovery, OUT nfs41_file_info *info)
Definition: open.c:232
void nfs41_open_stateid_arg(IN nfs41_open_state *state, OUT stateid_arg *arg)
Definition: open.c:125
static int parse_abs_path(unsigned char **buffer, uint32_t *length, nfs41_abs_path *path)
Definition: open.c:259
static void map_access_2_allowdeny(ULONG access_mask, ULONG access_mode, ULONG disposition, uint32_t *allow, uint32_t *deny)
Definition: open.c:401
static void client_state_remove(IN nfs41_open_state *state)
Definition: open.c:179
static int parse_close(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
Definition: open.c:826
static int do_open(IN OUT nfs41_open_state *state, IN uint32_t create, IN uint32_t createhow, IN nfs41_file_info *createattrs, IN bool_t try_recovery, OUT nfs41_file_info *info)
Definition: open.c:189
static int marshall_open(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall)
Definition: open.c:743
void path_fh_init(OUT nfs41_path_fh *file, IN nfs41_abs_path *path)
Definition: util.c:346
void nfs_to_standard_info(IN const nfs41_file_info *info, OUT PFILE_STANDARD_INFO std_out)
Definition: util.c:175
bool_t last_component(IN const char *path, IN const char *path_end, OUT nfs41_component *component)
Definition: util.c:317
void nfs_to_basic_info(IN const nfs41_file_info *info, OUT PFILE_BASIC_INFO basic_out)
Definition: util.c:163
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
void abs_path_copy(OUT nfs41_abs_path *dst, IN const nfs41_abs_path *src)
Definition: util.c:338
int safe_read(unsigned char **pos, uint32_t *remaining, void *dest, uint32_t dest_len)
Definition: util.c:33
int nfs_to_windows_error(int status, int default_error)
Definition: util.c:235
int get_name(unsigned char **pos, uint32_t *remaining, const char **out_name)
Definition: util.c:55
int create_silly_rename(IN nfs41_abs_path *path, IN const nfs41_fh *fh, OUT nfs41_component *silly)
Definition: util.c:380
void eprintf(LPCSTR format,...)
Definition: daemon_debug.c:86
void print_disposition(int level, DWORD disposition)
Definition: daemon_debug.c:164
const char * nfs_error_string(int status)
Definition: daemon_debug.c:370
void print_share_mode(int level, DWORD mode)
Definition: daemon_debug.c:215
void print_create_attributes(int level, DWORD create_opts)
Definition: daemon_debug.c:126
void print_access_mask(int level, DWORD access_mask)
Definition: daemon_debug.c:181
#define NO_ERROR
Definition: dderror.h:5
#define free
Definition: debug_ros.c:5
void nfs41_delegation_deref(IN nfs41_delegation_state *state)
Definition: delegation.c:79
int nfs41_delegate_open(IN nfs41_open_state *state, IN uint32_t create, IN OPTIONAL nfs41_file_info *createattrs, OUT nfs41_file_info *info)
Definition: delegation.c:462
int nfs41_delegation_return(IN nfs41_session *session, IN nfs41_path_fh *file, IN enum open_delegation_type4 access, IN bool_t truncate)
Definition: delegation.c:629
int nfs41_delegation_granted(IN nfs41_session *session, IN nfs41_path_fh *parent, IN nfs41_path_fh *file, IN open_delegation4 *delegation, IN bool_t try_recovery, OUT nfs41_delegation_state **deleg_out)
Definition: delegation.c:330
#define open_entry(pos)
Definition: delegation.c:89
void nfs41_delegation_remove_srvopen(IN nfs41_session *session, IN nfs41_path_fh *file)
Definition: delegation.c:610
#define NULL
Definition: types.h:112
int32_t bool_t
Definition: types.h:101
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
UINT32 uint32_t
Definition: types.h:75
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define MultiByteToWideChar
Definition: compat.h:110
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
#define FILE_SHARE_READ
Definition: compat.h:136
VOID WINAPI ReleaseSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:89
VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:54
VOID WINAPI AcquireSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:61
VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:82
VOID WINAPI InitializeSRWLock(PSRWLOCK Lock)
Definition: sync.c:75
BOOL WINAPI SleepConditionVariableSRW(PCONDITION_VARIABLE ConditionVariable, PSRWLOCK Lock, DWORD Timeout, ULONG Flags)
Definition: sync.c:121
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:94
#define INFINITE
Definition: serial.h:102
unsigned long DWORD
Definition: ntddk_ex.h:95
#define FILE_OPEN
Definition: from_kernel.h:54
#define FILE_CREATE
Definition: from_kernel.h:55
#define FILE_OVERWRITE_IF
Definition: from_kernel.h:58
#define FILE_OPEN_REPARSE_POINT
Definition: from_kernel.h:46
#define FILE_OVERWRITE
Definition: from_kernel.h:57
#define FILE_OPEN_IF
Definition: from_kernel.h:56
#define FILE_SUPERSEDE
Definition: from_kernel.h:53
GLint GLint GLsizei GLsizei GLsizei depth
Definition: gl.h:1546
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint buffer
Definition: glext.h:5915
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLuint GLint GLboolean GLint GLenum access
Definition: glext.h:7866
GLenum GLsizei len
Definition: glext.h:6722
#define FAILED(hr)
Definition: intsafe.h:51
uint32_t entry
Definition: isohybrid.c:63
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
static const struct access_res create[16]
Definition: package.c:7644
@ DELEGATION_GRANTED
Definition: nfs41.h:90
static __inline nfs41_session * nfs41_root_session(IN nfs41_root *root)
Definition: nfs41.h:321
#define NFS41_MAX_PATH_LEN
Definition: nfs41_const.h:46
@ FATTR4_WORD0_HIDDEN
Definition: nfs41_const.h:237
@ FATTR4_WORD1_MODE
Definition: nfs41_const.h:245
@ FATTR4_WORD0_ARCHIVE
Definition: nfs41_const.h:227
@ FATTR4_WORD1_SYSTEM
Definition: nfs41_const.h:258
@ FATTR4_WORD0_SIZE
Definition: nfs41_const.h:211
@ NF4REG
Definition: nfs41_const.h:294
@ NF4DIR
Definition: nfs41_const.h:295
@ NF4LNK
Definition: nfs41_const.h:298
#define NFS41_MAX_SYMLINK_DEPTH
Definition: nfs41_const.h:60
#define CREATE_SESSION4_FLAG_PERSIST
Definition: nfs41_const.h:307
@ NFS4ERR_EXIST
Definition: nfs41_const.h:93
@ NFS4ERR_NOENT
Definition: nfs41_const.h:89
@ NFS4ERR_FILE_OPEN
Definition: nfs41_const.h:153
@ NFS4_OK
Definition: nfs41_const.h:87
#define NFS4_OPAQUE_LIMIT
Definition: nfs41_const.h:31
LONG open_owner_id
Definition: nfs41_driver.c:107
nfs41_updowncall_list upcall
Definition: nfs41_driver.c:273
int nfs41_open(IN nfs41_session *session, IN nfs41_path_fh *parent, IN nfs41_path_fh *file, IN state_owner4 *owner, IN open_claim4 *claim, IN uint32_t allow, IN uint32_t deny, IN uint32_t create, IN uint32_t how_mode, IN OPTIONAL nfs41_file_info *createattrs, IN bool_t try_recovery, OUT stateid4 *stateid, OUT open_delegation4 *delegation, OUT OPTIONAL nfs41_file_info *info)
Definition: nfs41_ops.c:366
int nfs41_access(IN nfs41_session *session, IN nfs41_path_fh *file, IN uint32_t requested, OUT uint32_t *supported OPTIONAL, OUT uint32_t *access OPTIONAL)
Definition: nfs41_ops.c:1554
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_close(IN nfs41_session *session, IN nfs41_path_fh *file, IN stateid_arg *stateid)
Definition: nfs41_ops.c:627
@ OPEN_DELEGATE_WRITE
Definition: nfs41_ops.h:588
@ OPEN4_CREATE
Definition: nfs41_ops.h:554
@ OPEN4_NOCREATE
Definition: nfs41_ops.h:553
int nfs41_symlink_follow(IN nfs41_root *root, IN nfs41_session *session, IN nfs41_path_fh *symlink, OUT nfs41_file_info *info)
Definition: symlink.c:146
@ GUARDED4
Definition: nfs41_ops.h:541
@ EXCLUSIVE4_1
Definition: nfs41_ops.h:543
@ ACCESS4_EXECUTE
Definition: nfs41_ops.h:298
@ ACCESS4_READ
Definition: nfs41_ops.h:293
@ STATEID_LOCK
Definition: nfs41_ops.h:277
@ STATEID_DELEG_FILE
Definition: nfs41_ops.h:278
@ STATEID_SPECIAL
Definition: nfs41_ops.h:281
@ STATEID_OPEN
Definition: nfs41_ops.h:276
@ OPEN4_SHARE_ACCESS_WRITE
Definition: nfs41_ops.h:565
@ OPEN4_SHARE_DENY_READ
Definition: nfs41_ops.h:569
@ OPEN4_SHARE_ACCESS_WANT_NO_DELEG
Definition: nfs41_ops.h:578
@ OPEN4_SHARE_ACCESS_BOTH
Definition: nfs41_ops.h:566
@ OPEN4_SHARE_DENY_WRITE
Definition: nfs41_ops.h:570
@ OPEN4_SHARE_DENY_NONE
Definition: nfs41_ops.h:568
@ OPEN4_SHARE_ACCESS_READ
Definition: nfs41_ops.h:564
@ OPEN4_SHARE_DENY_BOTH
Definition: nfs41_ops.h:571
int nfs41_symlink_target(IN nfs41_session *session, IN nfs41_path_fh *file, OUT nfs41_abs_path *target)
Definition: symlink.c:92
@ CLAIM_NULL
Definition: nfs41_ops.h:593
#define uint32_t
Definition: nsiface.idl:61
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define SYNCHRONIZE
Definition: nt_native.h:61
#define FILE_WRITE_DATA
Definition: nt_native.h:631
#define FILE_READ_DATA
Definition: nt_native.h:628
#define FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
#define FILE_EXECUTE
Definition: nt_native.h:642
#define FILE_WRITE_ATTRIBUTES
Definition: nt_native.h:649
#define FILE_APPEND_DATA
Definition: nt_native.h:634
#define FILE_ATTRIBUTE_ARCHIVE
Definition: nt_native.h:706
#define DELETE
Definition: nt_native.h:57
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
void pnfs_layout_state_close(IN struct __nfs41_session *session, IN struct __nfs41_open_state *state, IN bool_t remove)
#define dprintf
Definition: regdump.c:33
static FILE * out
Definition: regtests2xml.c:44
#define calloc
Definition: rosglue.h:14
#define CP_UTF8
Definition: nls.h:20
#define memset(x, y, z)
Definition: compat.h:39
static FILE * client
Definition: client.c:41
STRSAFEAPI StringCchCopyA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc)
Definition: strsafe.h:145
STRSAFEAPI StringCchPrintfA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszFormat,...)
Definition: strsafe.h:520
uint32_t count
Definition: nfs41_types.h:96
uint32_t arr[3]
Definition: nfs41_types.h:97
enum delegation_status status
Definition: nfs41.h:103
open_delegation4 state
Definition: nfs41.h:96
struct __open_claim4::@41::__open_claim_null null
uint32_t claim
Definition: nfs41_ops.h:615
union __open_claim4::@41 u
enum stateid_type type
Definition: nfs41_ops.h:285
nfs41_open_state * open
Definition: nfs41_ops.h:286
stateid4 stateid
Definition: nfs41_ops.h:284
nfs41_delegation_state * delegation
Definition: nfs41_ops.h:287
Definition: match.c:390
Definition: list.h:27
Definition: name.c:39
WCHAR * name
Definition: name.c:42
Definition: ps.c:97
enum shader_type type
Definition: compiler.c:659
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
#define ERROR_BUFFER_OVERFLOW
Definition: winerror.h:185
#define ERROR_REPARSE
Definition: winerror.h:522
#define ERROR_DIRECTORY
Definition: winerror.h:295
#define ERROR_TOO_MANY_LINKS
Definition: winerror.h:671
#define ERROR_FILE_EXISTS
Definition: winerror.h:165
#define ERROR_BAD_FILE_TYPE
Definition: winerror.h:277
#define ERROR_FILENAME_EXCED_RANGE
Definition: winerror.h:263
#define ERROR_INTERNAL_ERROR
Definition: winerror.h:840
char * LPSTR
Definition: xmlstorage.h:182
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184