[CRYPTEX] Add French translation
[reactos.git] / base / services / nfsd / nfs41_superblock.c
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
25 #include "daemon_debug.h"
26 #include "nfs41.h"
27 #include "nfs41_ops.h"
28 #include "from_kernel.h"
29 #include "util.h"
30
31
32 #define SBLVL 3 /* dprintf level for superblock logging */
33
34
35 static __inline int compare_fsid(
36 IN const nfs41_fsid *lhs,
37 IN const nfs41_fsid *rhs)
38 {
39 if (lhs->major > rhs->major) return 1;
40 if (lhs->major < rhs->major) return -1;
41 if (lhs->minor > rhs->minor) return 1;
42 if (lhs->minor < rhs->minor) return -1;
43 return 0;
44 }
45
46
47 /* nfs41_superblock */
48 static int superblock_create(
49 IN const nfs41_fsid *fsid,
50 OUT nfs41_superblock **superblock_out)
51 {
52 int status = NO_ERROR;
53 nfs41_superblock *superblock;
54
55 dprintf(SBLVL, "creating superblock for fsid(%llu,%llu)\n",
56 fsid->major, fsid->minor);
57
58 superblock = calloc(1, sizeof(nfs41_superblock));
59 if (superblock == NULL) {
60 status = GetLastError();
61 eprintf("failed to allocate superblock "
62 "for fsid(%llu,%llu)\n", fsid->major, fsid->minor);
63 goto out;
64 }
65
66 memcpy(&superblock->fsid, fsid, sizeof(nfs41_fsid));
67 InitializeSRWLock(&superblock->lock);
68
69 *superblock_out = superblock;
70 out:
71 return status;
72 }
73
74 static int get_superblock_attrs(
75 IN nfs41_session *session,
76 IN nfs41_superblock *superblock,
77 IN nfs41_path_fh *file)
78 {
79 bool_t supports_named_attrs;
80 int status;
81 bitmap4 attr_request;
82 nfs41_file_info info = { 0 };
83
84 attr_request.arr[0] = FATTR4_WORD0_SUPPORTED_ATTRS |
85 FATTR4_WORD0_LINK_SUPPORT | FATTR4_WORD0_SYMLINK_SUPPORT |
86 FATTR4_WORD0_ACLSUPPORT | FATTR4_WORD0_CANSETTIME |
87 FATTR4_WORD0_CASE_INSENSITIVE | FATTR4_WORD0_CASE_PRESERVING |
88 FATTR4_WORD0_MAXREAD | (uint32_t)(FATTR4_WORD0_MAXWRITE);
89 attr_request.arr[1] = FATTR4_WORD1_FS_LAYOUT_TYPE |
90 FATTR4_WORD1_TIME_DELTA;
91 attr_request.arr[2] = FATTR4_WORD2_SUPPATTR_EXCLCREAT;
92 attr_request.count = 3;
93
94 info.supported_attrs = &superblock->supported_attrs;
95 info.suppattr_exclcreat = &superblock->suppattr_exclcreat;
96 info.time_delta = &superblock->time_delta;
97
98 status = nfs41_superblock_getattr(session, file,
99 &attr_request, &info, &supports_named_attrs);
100 if (status) {
101 eprintf("nfs41_superblock_getattr() failed with %s when fetching "
102 "attributes for fsid(%llu,%llu)\n", nfs_error_string(status),
103 superblock->fsid.major, superblock->fsid.minor);
104 goto out;
105 }
106
107 if (info.maxread)
108 superblock->maxread = info.maxread;
109 else
110 superblock->maxread = session->fore_chan_attrs.ca_maxresponsesize;
111
112 if (info.maxwrite)
113 superblock->maxwrite = info.maxwrite;
114 else
115 superblock->maxwrite = session->fore_chan_attrs.ca_maxrequestsize;
116
117 superblock->layout_types = info.fs_layout_types;
118 superblock->aclsupport = info.aclsupport;
119 superblock->link_support = info.link_support;
120 superblock->symlink_support = info.symlink_support;
121 superblock->ea_support = supports_named_attrs;
122 superblock->case_preserving = info.case_preserving;
123 superblock->case_insensitive = info.case_insensitive;
124
125 if (bitmap_isset(&info.attrmask, 0, FATTR4_WORD0_CANSETTIME))
126 superblock->cansettime = info.cansettime;
127 else /* cansettime is not supported, try setting them anyway */
128 superblock->cansettime = 1;
129
130 /* if time_delta is not supported, default to 1s */
131 if (!bitmap_isset(&info.attrmask, 1, FATTR4_WORD1_TIME_DELTA))
132 superblock->time_delta.seconds = 1;
133
134 /* initialize the default getattr mask */
135 superblock->default_getattr.count = 2;
136 superblock->default_getattr.arr[0] = FATTR4_WORD0_TYPE
137 | FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE
138 | FATTR4_WORD0_FILEID | FATTR4_WORD0_HIDDEN
139 | FATTR4_WORD0_ARCHIVE;
140 superblock->default_getattr.arr[1] = FATTR4_WORD1_MODE
141 | FATTR4_WORD1_NUMLINKS | FATTR4_WORD1_SYSTEM
142 | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_CREATE
143 | FATTR4_WORD1_TIME_MODIFY;
144 superblock->default_getattr.arr[2] = 0;
145
146 nfs41_superblock_supported_attrs(superblock, &superblock->default_getattr);
147
148 dprintf(SBLVL, "attributes for fsid(%llu,%llu): "
149 "maxread=%llu, maxwrite=%llu, layout_types: 0x%X, "
150 "cansettime=%u, time_delta={%llu,%u}, aclsupport=%u, "
151 "link_support=%u, symlink_support=%u, case_preserving=%u, "
152 "case_insensitive=%u\n",
153 superblock->fsid.major, superblock->fsid.minor,
154 superblock->maxread, superblock->maxwrite,
155 superblock->layout_types, superblock->cansettime,
156 superblock->time_delta.seconds, superblock->time_delta.nseconds,
157 superblock->aclsupport, superblock->link_support,
158 superblock->symlink_support, superblock->case_preserving,
159 superblock->case_insensitive);
160 out:
161 return status;
162 }
163
164 void nfs41_superblock_fs_attributes(
165 IN const nfs41_superblock *superblock,
166 OUT PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs)
167 {
168 FsAttrs->FileSystemAttributes = FILE_SUPPORTS_REMOTE_STORAGE;
169 if (superblock->link_support)
170 FsAttrs->FileSystemAttributes |= FILE_SUPPORTS_HARD_LINKS;
171 if (superblock->symlink_support)
172 FsAttrs->FileSystemAttributes |= FILE_SUPPORTS_REPARSE_POINTS;
173 if (superblock->ea_support)
174 FsAttrs->FileSystemAttributes |= FILE_SUPPORTS_EXTENDED_ATTRIBUTES;
175 if (superblock->case_preserving)
176 FsAttrs->FileSystemAttributes |= FILE_CASE_PRESERVED_NAMES;
177 if (!superblock->case_insensitive)
178 FsAttrs->FileSystemAttributes |= FILE_CASE_SENSITIVE_SEARCH;
179 if (superblock->aclsupport)
180 FsAttrs->FileSystemAttributes |= FILE_PERSISTENT_ACLS;
181
182 FsAttrs->MaximumComponentNameLength = NFS41_MAX_COMPONENT_LEN;
183
184 /* let the driver fill in FileSystemName */
185 FsAttrs->FileSystemNameLength = 0;
186
187 dprintf(SBLVL, "FileFsAttributeInformation: case_preserving %u, "
188 "case_insensitive %u, max component %u\n",
189 superblock->case_preserving, superblock->case_insensitive,
190 FsAttrs->MaximumComponentNameLength);
191 }
192
193
194 /* nfs41_superblock_list */
195 #define superblock_entry(pos) list_container(pos, nfs41_superblock, entry)
196
197 static int superblock_compare(
198 const struct list_entry *entry,
199 const void *value)
200 {
201 const nfs41_superblock *superblock = superblock_entry(entry);
202 return compare_fsid(&superblock->fsid, (const nfs41_fsid*)value);
203 }
204
205 static nfs41_superblock* find_superblock(
206 IN nfs41_superblock_list *superblocks,
207 IN const nfs41_fsid *fsid)
208 {
209 struct list_entry *entry;
210 entry = list_search(&superblocks->head, fsid, superblock_compare);
211 return entry ? superblock_entry(entry) : NULL;
212 }
213
214 void nfs41_superblock_list_init(
215 IN nfs41_superblock_list *superblocks)
216 {
217 list_init(&superblocks->head);
218 InitializeSRWLock(&superblocks->lock);
219 }
220
221 void nfs41_superblock_list_free(
222 IN nfs41_superblock_list *superblocks)
223 {
224 struct list_entry *entry, *tmp;
225
226 dprintf(SBLVL, "nfs41_superblock_list_free()\n");
227
228 list_for_each_tmp(entry, tmp, &superblocks->head)
229 free(superblock_entry(entry));
230 }
231
232
233 int nfs41_superblock_for_fh(
234 IN nfs41_session *session,
235 IN const nfs41_fsid *fsid,
236 IN const nfs41_fh *parent OPTIONAL,
237 OUT nfs41_path_fh *file)
238 {
239 int status = NFS4_OK;
240 nfs41_server *server = client_server(session->client);
241 nfs41_superblock_list *superblocks = &server->superblocks;
242 nfs41_superblock *superblock;
243
244 dprintf(SBLVL, "--> nfs41_superblock_for_fh(fsid(%llu,%llu))\n",
245 fsid->major, fsid->minor);
246
247 /* compare with the parent's fsid, and use that if it matches */
248 if (parent && parent->superblock &&
249 compare_fsid(fsid, &parent->superblock->fsid) == 0) {
250 file->fh.superblock = parent->superblock;
251 dprintf(SBLVL, "using superblock from parent\n");
252 goto out;
253 }
254
255 /* using a shared lock, search for an existing superblock */
256 AcquireSRWLockShared(&superblocks->lock);
257 superblock = find_superblock(superblocks, fsid);
258 ReleaseSRWLockShared(&superblocks->lock);
259
260 if (superblock) {
261 dprintf(SBLVL, "found existing superblock in server list "
262 "[shared lock]\n");
263 } else {
264 AcquireSRWLockExclusive(&superblocks->lock);
265 /* must search again under an exclusive lock, in case another thread
266 * created it after our first search */
267 superblock = find_superblock(superblocks, fsid);
268 if (superblock) {
269 dprintf(SBLVL, "found newly created superblock in server list "
270 "[exclusive lock]\n");
271 } else {
272 /* create the superblock */
273 status = superblock_create(fsid, &superblock);
274 if (status == NO_ERROR) /* add it to the list */
275 list_add_tail(&superblocks->head, &superblock->entry);
276 }
277 ReleaseSRWLockExclusive(&superblocks->lock);
278 }
279
280 if (status == NO_ERROR && superblock->supported_attrs.count == 0) {
281 /* exclusive lock on the superblock while fetching attributes */
282 AcquireSRWLockExclusive(&superblock->lock);
283 if (superblock->supported_attrs.count == 0)
284 status = get_superblock_attrs(session, superblock, file);
285 ReleaseSRWLockExclusive(&superblock->lock);
286 }
287
288 file->fh.superblock = superblock;
289 out:
290 dprintf(SBLVL, "<-- nfs41_superblock_for_fh() returning %p, status %d\n",
291 file->fh.superblock, status);
292 return status;
293 }
294
295 void nfs41_superblock_space_changed(
296 IN nfs41_superblock *superblock)
297 {
298 /* invalidate cached volume size attributes */
299 AcquireSRWLockExclusive(&superblock->lock);
300 superblock->cache_expiration = 0;
301 ReleaseSRWLockExclusive(&superblock->lock);
302 }