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 34 static int create_open_state( 35 IN const char *path, 36 IN uint32_t open_owner_id, 37 OUT nfs41_open_state **state_out) 38 { 39 int status; 40 nfs41_open_state *state; 41 42 state = calloc(1, sizeof(nfs41_open_state)); 43 if (state == NULL) { 44 status = GetLastError(); 45 goto out; 46 } 47 48 InitializeSRWLock(&state->path.lock); 49 if (FAILED(StringCchCopyA(state->path.path, NFS41_MAX_PATH_LEN, path))) { 50 status = ERROR_FILENAME_EXCED_RANGE; 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", 59 open_owner_id); 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; 67 InitializeCriticalSection(&state->ea.lock); 68 69 *state_out = state; 70 status = NO_ERROR; 71 out: 72 return status; 73 74 out_free: 75 free(state); 76 goto out; 77 } 78 79 static void open_state_free( 80 IN nfs41_open_state *state) 81 { 82 struct list_entry *entry, *tmp; 83 84 /* free associated lock state */ 85 list_for_each_tmp(entry, tmp, &state->locks.list) 86 free(list_container(entry, nfs41_lock_state, open_entry)); 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 */ 96 void nfs41_open_state_ref( 97 IN nfs41_open_state *state) 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 104 void nfs41_open_state_deref( 105 IN nfs41_open_state *state) 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) 111 open_state_free(state); 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. */ 125 void nfs41_open_stateid_arg( 126 IN nfs41_open_state *state, 127 OUT stateid_arg *arg) 128 { 129 arg->open = state; 130 arg->delegation = NULL; 131 132 AcquireSRWLockShared(&state->lock); 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 } 164 out: 165 ReleaseSRWLockShared(&state->lock); 166 } 167 168 /* client list of associated open state */ 169 static void client_state_add( 170 IN nfs41_open_state *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 179 static void client_state_remove( 180 IN nfs41_open_state *state) 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 189 static int do_open( 190 IN OUT nfs41_open_state *state, 191 IN uint32_t create, 192 IN uint32_t createhow, 193 IN nfs41_file_info *createattrs, 194 IN bool_t try_recovery, 195 OUT nfs41_file_info *info) 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 222 AcquireSRWLockExclusive(&state->lock); 223 /* update the stateid */ 224 memcpy(&state->stateid, &open_stateid, sizeof(open_stateid)); 225 state->do_close = 1; 226 state->delegation.state = deleg_state; 227 ReleaseSRWLockExclusive(&state->lock); 228 out: 229 return status; 230 } 231 232 static int open_or_delegate( 233 IN OUT nfs41_open_state *state, 234 IN uint32_t create, 235 IN uint32_t createhow, 236 IN nfs41_file_info *createattrs, 237 IN bool_t try_recovery, 238 OUT nfs41_file_info *info) 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) 254 client_state_add(state); 255 return status; 256 } 257 258 259 static int parse_abs_path(unsigned char **buffer, uint32_t *length, nfs41_abs_path *path) 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) { 266 status = ERROR_BUFFER_OVERFLOW; 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 */ 272 out: 273 return status; 274 } 275 276 /* NFS41_OPEN */ 277 static 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); 316 out: 317 return status; 318 } 319 320 static BOOLEAN open_for_attributes(uint32_t type, ULONG access_mask, 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 352 static int map_disposition_2_nfsopen(ULONG disposition, int in_status, bool_t persistent, 353 uint32_t *create, uint32_t *createhowmode, 354 uint32_t *last_error) 355 { 356 int status = NO_ERROR; 357 if (disposition == FILE_SUPERSEDE) { 358 if (in_status == NFS4ERR_NOENT) 359 *last_error = ERROR_FILE_NOT_FOUND; 360 //remove and recreate the file 361 *create = OPEN4_CREATE; 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) 367 status = ERROR_FILE_EXISTS; 368 else { 369 *create = OPEN4_CREATE; 370 if (persistent) *createhowmode = GUARDED4; 371 else *createhowmode = EXCLUSIVE4_1; 372 } 373 } else if (disposition == FILE_OPEN) { 374 if (in_status == NFS4ERR_NOENT) 375 status = ERROR_FILE_NOT_FOUND; 376 else 377 *create = OPEN4_NOCREATE; 378 } else if (disposition == FILE_OPEN_IF) { 379 if (in_status == NFS4ERR_NOENT) { 380 dprintf(1, "creating new file\n"); 381 *create = OPEN4_CREATE; 382 *last_error = ERROR_FILE_NOT_FOUND; 383 } else { 384 dprintf(1, "opening existing file\n"); 385 *create = OPEN4_NOCREATE; 386 } 387 } else if (disposition == FILE_OVERWRITE) { 388 if (in_status == NFS4ERR_NOENT) 389 status = ERROR_FILE_NOT_FOUND; 390 //truncate file 391 *create = OPEN4_CREATE; 392 } else if (disposition == FILE_OVERWRITE_IF) { 393 if (in_status == NFS4ERR_NOENT) 394 *last_error = ERROR_FILE_NOT_FOUND; 395 //truncate file 396 *create = OPEN4_CREATE; 397 } 398 return status; 399 } 400 401 static 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 & 405 (FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES)) && 406 (access_mask & (FILE_READ_DATA | FILE_EXECUTE))) 407 *allow = OPEN4_SHARE_ACCESS_BOTH; 408 else if (access_mask & (FILE_READ_DATA | FILE_EXECUTE)) 409 *allow = OPEN4_SHARE_ACCESS_READ; 410 else if (access_mask & 411 (FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES)) 412 *allow = OPEN4_SHARE_ACCESS_WRITE; 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 | 421 FILE_WRITE_ATTRIBUTES | FILE_READ_DATA | FILE_EXECUTE))) 422 *allow = OPEN4_SHARE_ACCESS_READ | OPEN4_SHARE_ACCESS_WANT_NO_DELEG; 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) 430 *deny = OPEN4_SHARE_DENY_WRITE; 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 444 static int check_execute_access(nfs41_open_state *state) 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); 452 status = ERROR_ACCESS_DENIED; 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); 459 status = ERROR_ACCESS_DENIED; 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); 464 status = ERROR_ACCESS_DENIED; 465 } else 466 dprintf(2, "user has execute access to file\n"); 467 return status; 468 } 469 470 static 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 480 static int handle_open(nfs41_upcall *upcall) 481 { 482 int status = 0; 483 open_upcall_args *args = &upcall->args.open; 484 nfs41_open_state *state; 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 { 509 if (++depth > NFS41_MAX_SYMLINK_DEPTH) { 510 status = ERROR_TOO_MANY_LINKS; 511 goto out_free_state; 512 } 513 514 /* replace the path with the symlink target's */ 515 status = nfs41_symlink_target(state->session, 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 528 if (status == NO_ERROR || status == ERROR_FILE_NOT_FOUND) { 529 abs_path_copy(&args->symlink, &state->path); 530 status = NO_ERROR; 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); 544 status = ERROR_DIRECTORY; 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); 552 status = ERROR_BAD_FILE_TYPE; 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 */ 560 nfs41_file_info target_info; 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 */ 567 status = nfs41_symlink_target(state->session, 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) { 601 status = ERROR_FILE_EXISTS; 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 612 status = NO_ERROR; 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)); 629 status = map_symlink_errors(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))) { 656 status = ERROR_ACCESS_DENIED; 657 goto out_free_state; 658 } 659 if (args->disposition != FILE_SUPERSEDE) 660 args->mode = info.mode; 661 } 662 createattrs.attrmask.count = 2; 663 createattrs.attrmask.arr[0] = FATTR4_WORD0_HIDDEN | FATTR4_WORD0_ARCHIVE; 664 createattrs.attrmask.arr[1] = FATTR4_WORD1_MODE | FATTR4_WORD1_SYSTEM; 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); 672 status = map_disposition_2_nfsopen(args->disposition, status, 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) { 679 status = check_execute_access(state); 680 if (status) 681 goto out_free_state; 682 } 683 684 supersede_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, 690 OPEN_DELEGATE_WRITE, TRUE); 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", 715 nfs_error_string(status)); 716 if (args->disposition == FILE_SUPERSEDE && status == NFS4ERR_EXIST) 717 goto supersede_retry; 718 status = nfs_to_windows_error(status, ERROR_FILE_NOT_FOUND); 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)) { 729 status = nfs41_ea_set(state, args->ea); 730 status = nfs_to_windows_error(status, ERROR_FILE_NOT_FOUND); 731 } 732 } 733 734 upcall->state_ref = state; 735 nfs41_open_state_ref(upcall->state_ref); 736 out: 737 return status; 738 out_free_state: 739 nfs41_open_state_deref(state); 740 goto out; 741 } 742 743 static int marshall_open(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) 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))) { 770 status = ERROR_BUFFER_OVERFLOW; 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); 776 out: 777 return status; 778 } 779 780 static void cancel_open(IN nfs41_upcall *upcall) 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", 802 nfs_error_string(status)); 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, 808 OPEN_DELEGATE_WRITE, TRUE); 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", 813 nfs_error_string(status)); 814 } 815 816 /* remove from the client's list of state for recovery */ 817 client_state_remove(state); 818 nfs41_open_state_deref(state); 819 out: 820 status = nfs_to_windows_error(status, ERROR_INTERNAL_ERROR); 821 dprintf(1, "<-- cancel_open() returning %d\n", status); 822 } 823 824 825 /* NFS41_CLOSE */ 826 static int parse_close(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) 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 : ""); 845 out: 846 return status; 847 } 848 849 static int do_nfs41_close(nfs41_open_state *state) 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", 861 nfs_error_string(status)); 862 status = nfs_to_windows_error(status, ERROR_INTERNAL_ERROR); 863 } 864 865 return status; 866 } 867 868 static int handle_close(nfs41_upcall *upcall) 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) 879 nfs41_delegation_remove_srvopen(state->session, &state->file); 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); 887 status = do_nfs41_close(state); 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, 896 OPEN_DELEGATE_WRITE, TRUE); 897 898 dprintf(1, "calling nfs41_remove for %s\n", name->name); 899 retry_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) { 904 status = do_nfs41_close(state); 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) { 917 status = do_nfs41_close(state); 918 } 919 out: 920 /* remove from the client's list of state for recovery */ 921 client_state_remove(state); 922 923 if (status || !rm_status) 924 return status; 925 else 926 return rm_status; 927 } 928 929 static void cleanup_close(nfs41_upcall *upcall) 930 { 931 /* release the initial reference from create_open_state() */ 932 nfs41_open_state_deref(upcall->state_ref); 933 } 934 935 936 const nfs41_upcall_op nfs41_op_open = { 937 parse_open, 938 handle_open, 939 marshall_open, 940 cancel_open 941 }; 942 const nfs41_upcall_op nfs41_op_close = { 943 parse_close, 944 handle_close, 945 NULL, 946 NULL, 947 cleanup_close 948 }; 949