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
nfs41_cached_getattr(IN nfs41_session * session,IN nfs41_path_fh * file,OUT nfs41_file_info * info)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 */
parse_getattr(unsigned char * buffer,uint32_t length,nfs41_upcall * upcall)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
handle_getattr(nfs41_upcall * upcall)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
marshall_getattr(unsigned char * buffer,uint32_t * length,nfs41_upcall * upcall)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