From 4418ba8b697516b84f3f699ee60896a260554e85 Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Fri, 16 Mar 2012 16:34:15 -0400 Subject: [PATCH] fixing open for FILE_SUPERSEDE http://www.osronline.com/showThread.cfm?link=27213 clarifies that unless open for overwrite_if the old file should be deleted and then created again. --- daemon/open.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/daemon/open.c b/daemon/open.c index f3e2e7c..7ae9825 100644 --- a/daemon/open.c +++ b/daemon/open.c @@ -324,22 +324,20 @@ static int map_disposition_2_nfsopen(ULONG disposition, int in_status, bool_t pe { int status = NO_ERROR; if (disposition == FILE_SUPERSEDE) { - if (in_status == NFS4ERR_NOENT) { - *create = OPEN4_CREATE; + if (in_status == NFS4ERR_NOENT) *last_error = ERROR_FILE_NOT_FOUND; - } - else // we need to truncate the file file then open it - *create = OPEN4_NOCREATE; + //remove and recreate the file + *create = OPEN4_CREATE; + if (persistent) *createhowmode = GUARDED4; + else *createhowmode = EXCLUSIVE4_1; } else if (disposition == FILE_CREATE) { // if lookup succeeded which means the file exist, return an error if (!in_status) status = ERROR_FILE_EXISTS; else { *create = OPEN4_CREATE; - if (persistent) - *createhowmode = GUARDED4; - else - *createhowmode = EXCLUSIVE4_1; + if (persistent) *createhowmode = GUARDED4; + else *createhowmode = EXCLUSIVE4_1; } } else if (disposition == FILE_OPEN) { if (in_status == NFS4ERR_NOENT) @@ -584,7 +582,7 @@ static int handle_open(nfs41_upcall *upcall) args->mode = info.mode; args->changeattr = info.change; } else { - uint32_t create = 0, createhowmode = 0; + uint32_t create = 0, createhowmode = 0, lookup_status = status; map_access_2_allowdeny(args->access_mask, args->access_mode, args->disposition, &state->share_access, &state->share_deny); @@ -600,6 +598,21 @@ static int handle_open(nfs41_upcall *upcall) goto out_free_state; } +supersede_retry: + // XXX file exists and we have to remove it first + if (args->disposition == FILE_SUPERSEDE && lookup_status == NO_ERROR) { + nfs41_component *name = &state->file.name; + if (!(args->create_opts & FILE_DIRECTORY_FILE)) + nfs41_delegation_return(state->session, &state->file, + OPEN_DELEGATE_WRITE, TRUE); + + dprintf(1, "open for FILE_SUPERSEDE removing %s first\n", name->name); + status = nfs41_remove(state->session, &state->parent, + name, state->file.fh.fileid); + if (status) + goto out_free_state; + } + if (create == OPEN4_CREATE && (args->create_opts & FILE_DIRECTORY_FILE)) { status = nfs41_create(state->session, NF4DIR, args->mode, NULL, &state->parent, &state->file); @@ -621,6 +634,8 @@ static int handle_open(nfs41_upcall *upcall) dprintf(1, "%s failed with %s\n", (create == OPEN4_CREATE && (args->create_opts & FILE_DIRECTORY_FILE))?"nfs41_create":"nfs41_open", nfs_error_string(status)); + if (args->disposition == FILE_SUPERSEDE && status == NFS4ERR_EXIST) + goto supersede_retry; status = nfs_to_windows_error(status, ERROR_FILE_NOT_FOUND); goto out_free_state; }