1 /* NFSv4.1 client for Windows
2 * Copyright © 2012 The Regents of the University of Michigan
4 * Olga Kornievskaia <aglo@umich.edu>
5 * Casey Bodley <cbodley@umich.edu>
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.
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.
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
27 #include "nfs41_ops.h"
28 #include "from_kernel.h"
31 #include "daemon_debug.h"
34 /* windows volume queries want size in 'units', so we have to
35 * convert the nfs space_* attributes from bytes to units */
36 #define SECTORS_PER_UNIT 8
37 #define BYTES_PER_SECTOR 512
38 #define BYTES_PER_UNIT (SECTORS_PER_UNIT * BYTES_PER_SECTOR)
40 #define TO_UNITS(bytes) (bytes / BYTES_PER_UNIT)
42 #define VOLUME_CACHE_EXPIRATION 20
45 /* NFS41_VOLUME_QUERY */
46 static int parse_volume(unsigned char *buffer
, uint32_t length
, nfs41_upcall
*upcall
)
49 volume_upcall_args
*args
= &upcall
->args
.volume
;
51 status
= safe_read(&buffer
, &length
, &args
->query
, sizeof(FS_INFORMATION_CLASS
));
54 dprintf(1, "parsing NFS41_VOLUME_QUERY: query=%d\n", args
->query
);
59 static int get_volume_size_info(
60 IN nfs41_open_state
*state
,
62 OUT OPTIONAL PLONGLONG total_out
,
63 OUT OPTIONAL PLONGLONG user_out
,
64 OUT OPTIONAL PLONGLONG avail_out
)
66 nfs41_file_info info
= { 0 };
67 nfs41_superblock
*superblock
= state
->file
.fh
.superblock
;
68 int status
= ERROR_NOT_FOUND
;
70 AcquireSRWLockShared(&superblock
->lock
);
71 /* check superblock for cached attributes */
72 if (time(NULL
) <= superblock
->cache_expiration
) {
73 info
.space_total
= superblock
->space_total
;
74 info
.space_avail
= superblock
->space_avail
;
75 info
.space_free
= superblock
->space_free
;
78 dprintf(2, "%s cached: %llu user, %llu free of %llu total\n",
79 query
, info
.space_avail
, info
.space_free
, info
.space_total
);
81 ReleaseSRWLockShared(&superblock
->lock
);
84 bitmap4 attr_request
= { 2, { 0, FATTR4_WORD1_SPACE_AVAIL
|
85 FATTR4_WORD1_SPACE_FREE
| FATTR4_WORD1_SPACE_TOTAL
} };
87 /* query the space_ attributes of the filesystem */
88 status
= nfs41_getattr(state
->session
, &state
->file
,
89 &attr_request
, &info
);
91 eprintf("nfs41_getattr() failed with %s\n",
92 nfs_error_string(status
));
93 status
= nfs_to_windows_error(status
, ERROR_BAD_NET_RESP
);
97 AcquireSRWLockExclusive(&superblock
->lock
);
98 superblock
->space_total
= info
.space_total
;
99 superblock
->space_avail
= info
.space_avail
;
100 superblock
->space_free
= info
.space_free
;
101 superblock
->cache_expiration
= time(NULL
) + VOLUME_CACHE_EXPIRATION
;
102 ReleaseSRWLockExclusive(&superblock
->lock
);
104 dprintf(2, "%s: %llu user, %llu free of %llu total\n",
105 query
, info
.space_avail
, info
.space_free
, info
.space_total
);
108 if (total_out
) *total_out
= TO_UNITS(info
.space_total
);
109 if (user_out
) *user_out
= TO_UNITS(info
.space_avail
);
110 if (avail_out
) *avail_out
= TO_UNITS(info
.space_free
);
115 static int handle_volume(nfs41_upcall
*upcall
)
117 volume_upcall_args
*args
= &upcall
->args
.volume
;
118 int status
= NO_ERROR
;
120 switch (args
->query
) {
121 case FileFsSizeInformation
:
122 args
->len
= sizeof(args
->info
.size
);
123 args
->info
.size
.SectorsPerAllocationUnit
= SECTORS_PER_UNIT
;
124 args
->info
.size
.BytesPerSector
= BYTES_PER_SECTOR
;
126 status
= get_volume_size_info(upcall
->state_ref
,
127 "FileFsSizeInformation",
128 &args
->info
.size
.TotalAllocationUnits
.QuadPart
,
129 &args
->info
.size
.AvailableAllocationUnits
.QuadPart
,
133 case FileFsFullSizeInformation
:
134 args
->len
= sizeof(args
->info
.fullsize
);
135 args
->info
.fullsize
.SectorsPerAllocationUnit
= SECTORS_PER_UNIT
;
136 args
->info
.fullsize
.BytesPerSector
= BYTES_PER_SECTOR
;
138 status
= get_volume_size_info(upcall
->state_ref
,
139 "FileFsFullSizeInformation",
140 &args
->info
.fullsize
.TotalAllocationUnits
.QuadPart
,
141 &args
->info
.fullsize
.CallerAvailableAllocationUnits
.QuadPart
,
142 &args
->info
.fullsize
.ActualAvailableAllocationUnits
.QuadPart
);
145 case FileFsAttributeInformation
:
146 args
->len
= sizeof(args
->info
.attribute
);
147 nfs41_superblock_fs_attributes(upcall
->state_ref
->file
.fh
.superblock
,
148 &args
->info
.attribute
);
152 eprintf("unhandled fs query class %d\n", args
->query
);
153 status
= ERROR_INVALID_PARAMETER
;
159 static int marshall_volume(unsigned char *buffer
, uint32_t *length
, nfs41_upcall
*upcall
)
162 volume_upcall_args
*args
= &upcall
->args
.volume
;
164 status
= safe_write(&buffer
, length
, &args
->len
, sizeof(args
->len
));
165 if (status
) goto out
;
166 status
= safe_write(&buffer
, length
, &args
->info
, args
->len
);
172 const nfs41_upcall_op nfs41_op_volume
= {