xref: /reactos/base/services/nfsd/getattr.c (revision 1734f297)
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