2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - fsinfo
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "vfs_posix.h"
24 #include "librpc/gen_ndr/xattr.h"
25 #include "librpc/ndr/libndr.h"
27 /* We use libblkid out of e2fsprogs to identify UUID of a volume */
29 #include <blkid/blkid.h>
32 static NTSTATUS
pvfs_blkid_fs_uuid(struct pvfs_state
*pvfs
, struct stat
*st
, struct GUID
*uuid
)
36 char *uuid_value
= NULL
;
39 devname
= blkid_devno_to_devname(st
->st_dev
);
45 uuid_value
= blkid_get_tag_value(NULL
, "UUID", devname
);
52 status
= GUID_from_string(uuid_value
, uuid
);
54 if (!NT_STATUS_IS_OK(status
)) {
65 static NTSTATUS
pvfs_cache_base_fs_uuid(struct pvfs_state
*pvfs
, struct stat
*st
)
70 if (pvfs
->base_fs_uuid
) return NT_STATUS_OK
;
72 status
= pvfs_blkid_fs_uuid(pvfs
, st
, &uuid
);
73 NT_STATUS_NOT_OK_RETURN(status
);
75 pvfs
->base_fs_uuid
= talloc(pvfs
, struct GUID
);
76 NT_STATUS_HAVE_NO_MEMORY(pvfs
->base_fs_uuid
);
77 *pvfs
->base_fs_uuid
= uuid
;
82 return filesystem space info
84 NTSTATUS
pvfs_fsinfo(struct ntvfs_module_context
*ntvfs
,
85 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
88 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
90 uint64_t blocks_free
, blocks_total
;
93 const uint16_t block_size
= 512;
95 /* only some levels need the expensive sys_fsusage() call */
96 switch (fs
->generic
.level
) {
98 case RAW_QFS_ALLOCATION
:
99 case RAW_QFS_SIZE_INFO
:
100 case RAW_QFS_SIZE_INFORMATION
:
101 case RAW_QFS_FULL_SIZE_INFORMATION
:
102 if (sys_fsusage(pvfs
->base_directory
, &blocks_free
, &blocks_total
) == -1) {
103 return pvfs_map_errno(pvfs
, errno
);
109 if (stat(pvfs
->base_directory
, &st
) != 0) {
110 return NT_STATUS_DISK_CORRUPT_ERROR
;
113 /* now fill in the out fields */
114 switch (fs
->generic
.level
) {
115 case RAW_QFS_GENERIC
:
116 return NT_STATUS_INVALID_LEVEL
;
118 case RAW_QFS_DSKATTR
:
119 /* we need to scale the sizes to fit */
120 for (bpunit
=64; bpunit
<0x10000; bpunit
*= 2) {
121 if (blocks_total
* (double)block_size
< bpunit
* 512 * 65535.0) {
125 fs
->dskattr
.out
.blocks_per_unit
= bpunit
;
126 fs
->dskattr
.out
.block_size
= block_size
;
127 fs
->dskattr
.out
.units_total
= (blocks_total
* (double)block_size
) / (bpunit
* 512);
128 fs
->dskattr
.out
.units_free
= (blocks_free
* (double)block_size
) / (bpunit
* 512);
130 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
131 if (bpunit
> 64 && req
->ctx
->protocol
<= PROTOCOL_LANMAN2
) {
132 fs
->dskattr
.out
.blocks_per_unit
= 64;
133 fs
->dskattr
.out
.units_total
= 0xFFFF;
134 fs
->dskattr
.out
.units_free
= 0xFFFF;
138 case RAW_QFS_ALLOCATION
:
139 fs
->allocation
.out
.fs_id
= st
.st_dev
;
140 fs
->allocation
.out
.total_alloc_units
= blocks_total
;
141 fs
->allocation
.out
.avail_alloc_units
= blocks_free
;
142 fs
->allocation
.out
.sectors_per_unit
= 1;
143 fs
->allocation
.out
.bytes_per_sector
= block_size
;
147 fs
->volume
.out
.serial_number
= st
.st_ino
;
148 fs
->volume
.out
.volume_name
.s
= pvfs
->share_name
;
151 case RAW_QFS_VOLUME_INFO
:
152 case RAW_QFS_VOLUME_INFORMATION
:
153 unix_to_nt_time(&fs
->volume_info
.out
.create_time
, st
.st_ctime
);
154 fs
->volume_info
.out
.serial_number
= st
.st_ino
;
155 fs
->volume_info
.out
.volume_name
.s
= pvfs
->share_name
;
158 case RAW_QFS_SIZE_INFO
:
159 case RAW_QFS_SIZE_INFORMATION
:
160 fs
->size_info
.out
.total_alloc_units
= blocks_total
;
161 fs
->size_info
.out
.avail_alloc_units
= blocks_free
;
162 fs
->size_info
.out
.sectors_per_unit
= 1;
163 fs
->size_info
.out
.bytes_per_sector
= block_size
;
166 case RAW_QFS_DEVICE_INFO
:
167 case RAW_QFS_DEVICE_INFORMATION
:
168 fs
->device_info
.out
.device_type
= 0;
169 fs
->device_info
.out
.characteristics
= 0;
172 case RAW_QFS_ATTRIBUTE_INFO
:
173 case RAW_QFS_ATTRIBUTE_INFORMATION
:
174 fs
->attribute_info
.out
.fs_attr
= pvfs
->fs_attribs
;
175 fs
->attribute_info
.out
.max_file_component_length
= 255;
176 fs
->attribute_info
.out
.fs_type
.s
= ntvfs
->ctx
->fs_type
;
179 case RAW_QFS_QUOTA_INFORMATION
:
180 ZERO_STRUCT(fs
->quota_information
.out
.unknown
);
181 fs
->quota_information
.out
.quota_soft
= 0;
182 fs
->quota_information
.out
.quota_hard
= 0;
183 fs
->quota_information
.out
.quota_flags
= 0;
186 case RAW_QFS_FULL_SIZE_INFORMATION
:
187 fs
->full_size_information
.out
.total_alloc_units
= blocks_total
;
188 fs
->full_size_information
.out
.call_avail_alloc_units
= blocks_free
;
189 fs
->full_size_information
.out
.actual_avail_alloc_units
= blocks_free
;
190 fs
->full_size_information
.out
.sectors_per_unit
= 1;
191 fs
->full_size_information
.out
.bytes_per_sector
= block_size
;
194 case RAW_QFS_OBJECTID_INFORMATION
:
195 ZERO_STRUCT(fs
->objectid_information
.out
.guid
);
196 ZERO_STRUCT(fs
->objectid_information
.out
.unknown
);
198 status
= pvfs_cache_base_fs_uuid(pvfs
, &st
);
199 NT_STATUS_NOT_OK_RETURN(status
);
201 fs
->objectid_information
.out
.guid
= *pvfs
->base_fs_uuid
;
207 return NT_STATUS_INVALID_LEVEL
;