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 "name_cache.h" 28 #include "upcall.h" 29 #include "daemon_debug.h" 30 31 32 int nfs41_cached_getattr( 33 IN nfs41_session *session, 34 IN nfs41_path_fh *file, 35 OUT nfs41_file_info *info) 36 { 37 int status; 38 39 /* first look for cached attributes */ 40 status = nfs41_attr_cache_lookup(session_name_cache(session), 41 file->fh.fileid, info); 42 43 if (status) { 44 /* fetch attributes from the server */ 45 bitmap4 attr_request; 46 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request); 47 48 status = nfs41_getattr(session, file, &attr_request, info); 49 if (status) { 50 eprintf("nfs41_getattr() failed with %s\n", 51 nfs_error_string(status)); 52 status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP); 53 } 54 } 55 return status; 56 } 57 58 /* NFS41_FILE_QUERY */ 59 static int parse_getattr(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) 60 { 61 int status; 62 getattr_upcall_args *args = &upcall->args.getattr; 63 64 status = safe_read(&buffer, &length, &args->query_class, sizeof(args->query_class)); 65 if (status) goto out; 66 status = safe_read(&buffer, &length, &args->buf_len, sizeof(args->buf_len)); 67 if (status) goto out; 68 69 dprintf(1, "parsing NFS41_FILE_QUERY: info_class=%d buf_len=%d file=%.*s\n", 70 args->query_class, args->buf_len, upcall->state_ref->path.len, 71 upcall->state_ref->path.path); 72 out: 73 return status; 74 } 75 76 static int handle_getattr(nfs41_upcall *upcall) 77 { 78 int status; 79 getattr_upcall_args *args = &upcall->args.getattr; 80 nfs41_open_state *state = upcall->state_ref; 81 nfs41_file_info info = { 0 }; 82 83 status = nfs41_cached_getattr(state->session, &state->file, &info); 84 if (status) { 85 eprintf("nfs41_cached_getattr() failed with %d\n", status); 86 goto out; 87 } 88 89 if (info.type == NF4LNK) { 90 nfs41_file_info target_info; 91 int target_status = nfs41_symlink_follow(upcall->root_ref, 92 state->session, &state->file, &target_info); 93 if (target_status == NO_ERROR && target_info.type == NF4DIR) 94 info.symlink_dir = TRUE; 95 } 96 97 switch (args->query_class) { 98 case FileBasicInformation: 99 nfs_to_basic_info(&info, &args->basic_info); 100 args->ctime = info.change; 101 break; 102 case FileStandardInformation: 103 nfs_to_standard_info(&info, &args->std_info); 104 break; 105 case FileAttributeTagInformation: 106 args->tag_info.FileAttributes = nfs_file_info_to_attributes(&info); 107 args->tag_info.ReparseTag = info.type == NF4LNK ? 108 IO_REPARSE_TAG_SYMLINK : 0; 109 break; 110 case FileInternalInformation: 111 args->intr_info.IndexNumber.QuadPart = info.fileid; 112 break; 113 case FileNetworkOpenInformation: 114 nfs_to_network_openinfo(&info, &args->network_info); 115 break; 116 default: 117 eprintf("unhandled file query class %d\n", args->query_class); 118 status = ERROR_INVALID_PARAMETER; 119 break; 120 } 121 out: 122 return status; 123 } 124 125 static int marshall_getattr(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) 126 { 127 int status; 128 getattr_upcall_args *args = &upcall->args.getattr; 129 uint32_t info_len; 130 131 switch (args->query_class) { 132 case FileBasicInformation: 133 info_len = sizeof(args->basic_info); 134 status = safe_write(&buffer, length, &info_len, sizeof(info_len)); 135 if (status) goto out; 136 status = safe_write(&buffer, length, &args->basic_info, info_len); 137 if (status) goto out; 138 break; 139 case FileStandardInformation: 140 info_len = sizeof(args->std_info); 141 status = safe_write(&buffer, length, &info_len, sizeof(info_len)); 142 if (status) goto out; 143 status = safe_write(&buffer, length, &args->std_info, info_len); 144 if (status) goto out; 145 break; 146 case FileAttributeTagInformation: 147 info_len = sizeof(args->tag_info); 148 status = safe_write(&buffer, length, &info_len, sizeof(info_len)); 149 if (status) goto out; 150 status = safe_write(&buffer, length, &args->tag_info, info_len); 151 if (status) goto out; 152 break; 153 case FileInternalInformation: 154 info_len = sizeof(args->intr_info); 155 status = safe_write(&buffer, length, &info_len, sizeof(info_len)); 156 if (status) goto out; 157 status = safe_write(&buffer, length, &args->intr_info, info_len); 158 if (status) goto out; 159 break; 160 case FileNetworkOpenInformation: 161 info_len = sizeof(args->network_info); 162 status = safe_write(&buffer, length, &info_len, sizeof(info_len)); 163 if (status) goto out; 164 status = safe_write(&buffer, length, &args->network_info, info_len); 165 if (status) goto out; 166 break; 167 default: 168 eprintf("unknown file query class %d\n", args->query_class); 169 status = 103; 170 goto out; 171 } 172 status = safe_write(&buffer, length, &args->ctime, sizeof(args->ctime)); 173 if (status) goto out; 174 dprintf(1, "NFS41_FILE_QUERY: downcall changattr=%llu\n", args->ctime); 175 out: 176 return status; 177 } 178 179 180 const nfs41_upcall_op nfs41_op_getattr = { 181 parse_getattr, 182 handle_getattr, 183 marshall_getattr 184 }; 185