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
);
110 if (stat(pvfs
->base_directory
, &st
) != 0) {
111 return NT_STATUS_DISK_CORRUPT_ERROR
;
114 /* now fill in the out fields */
115 switch (fs
->generic
.level
) {
116 case RAW_QFS_GENERIC
:
117 return NT_STATUS_INVALID_LEVEL
;
119 case RAW_QFS_DSKATTR
:
120 /* we need to scale the sizes to fit */
121 for (bpunit
=64; bpunit
<0x10000; bpunit
*= 2) {
122 if (blocks_total
* (double)block_size
< bpunit
* 512 * 65535.0) {
126 fs
->dskattr
.out
.blocks_per_unit
= bpunit
;
127 fs
->dskattr
.out
.block_size
= block_size
;
128 fs
->dskattr
.out
.units_total
= (blocks_total
* (double)block_size
) / (bpunit
* 512);
129 fs
->dskattr
.out
.units_free
= (blocks_free
* (double)block_size
) / (bpunit
* 512);
131 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
132 if (bpunit
> 64 && req
->ctx
->protocol
<= PROTOCOL_LANMAN2
) {
133 fs
->dskattr
.out
.blocks_per_unit
= 64;
134 fs
->dskattr
.out
.units_total
= 0xFFFF;
135 fs
->dskattr
.out
.units_free
= 0xFFFF;
139 case RAW_QFS_ALLOCATION
:
140 fs
->allocation
.out
.fs_id
= st
.st_dev
;
141 fs
->allocation
.out
.total_alloc_units
= blocks_total
;
142 fs
->allocation
.out
.avail_alloc_units
= blocks_free
;
143 fs
->allocation
.out
.sectors_per_unit
= 1;
144 fs
->allocation
.out
.bytes_per_sector
= block_size
;
148 fs
->volume
.out
.serial_number
= st
.st_ino
;
149 fs
->volume
.out
.volume_name
.s
= pvfs
->share_name
;
152 case RAW_QFS_VOLUME_INFO
:
153 case RAW_QFS_VOLUME_INFORMATION
:
154 unix_to_nt_time(&fs
->volume_info
.out
.create_time
, st
.st_ctime
);
155 fs
->volume_info
.out
.serial_number
= st
.st_ino
;
156 fs
->volume_info
.out
.volume_name
.s
= pvfs
->share_name
;
159 case RAW_QFS_SIZE_INFO
:
160 case RAW_QFS_SIZE_INFORMATION
:
161 fs
->size_info
.out
.total_alloc_units
= blocks_total
;
162 fs
->size_info
.out
.avail_alloc_units
= blocks_free
;
163 fs
->size_info
.out
.sectors_per_unit
= 1;
164 fs
->size_info
.out
.bytes_per_sector
= block_size
;
167 case RAW_QFS_DEVICE_INFO
:
168 case RAW_QFS_DEVICE_INFORMATION
:
169 fs
->device_info
.out
.device_type
= 0;
170 fs
->device_info
.out
.characteristics
= 0;
173 case RAW_QFS_ATTRIBUTE_INFO
:
174 case RAW_QFS_ATTRIBUTE_INFORMATION
:
175 fs
->attribute_info
.out
.fs_attr
= pvfs
->fs_attribs
;
176 fs
->attribute_info
.out
.max_file_component_length
= 255;
177 fs
->attribute_info
.out
.fs_type
.s
= ntvfs
->ctx
->fs_type
;
180 case RAW_QFS_QUOTA_INFORMATION
:
181 ZERO_STRUCT(fs
->quota_information
.out
.unknown
);
182 fs
->quota_information
.out
.quota_soft
= 0;
183 fs
->quota_information
.out
.quota_hard
= 0;
184 fs
->quota_information
.out
.quota_flags
= 0;
187 case RAW_QFS_FULL_SIZE_INFORMATION
:
188 fs
->full_size_information
.out
.total_alloc_units
= blocks_total
;
189 fs
->full_size_information
.out
.call_avail_alloc_units
= blocks_free
;
190 fs
->full_size_information
.out
.actual_avail_alloc_units
= blocks_free
;
191 fs
->full_size_information
.out
.sectors_per_unit
= 1;
192 fs
->full_size_information
.out
.bytes_per_sector
= block_size
;
195 case RAW_QFS_OBJECTID_INFORMATION
:
196 ZERO_STRUCT(fs
->objectid_information
.out
.guid
);
197 ZERO_STRUCT(fs
->objectid_information
.out
.unknown
);
199 status
= pvfs_cache_base_fs_uuid(pvfs
, &st
);
200 NT_STATUS_NOT_OK_RETURN(status
);
202 fs
->objectid_information
.out
.guid
= *pvfs
->base_fs_uuid
;
205 case RAW_QFS_SECTOR_SIZE_INFORMATION
:
206 fs
->sector_size_info
.out
.logical_bytes_per_sector
= block_size
;
207 fs
->sector_size_info
.out
.phys_bytes_per_sector_atomic
209 fs
->sector_size_info
.out
.phys_bytes_per_sector_perf
211 fs
->sector_size_info
.out
.fs_effective_phys_bytes_per_sector_atomic
213 fs
->sector_size_info
.out
.flags
214 = QFS_SSINFO_FLAGS_ALIGNED_DEVICE
215 | QFS_SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE
;
216 fs
->sector_size_info
.out
.byte_off_sector_align
= 0;
217 fs
->sector_size_info
.out
.byte_off_partition_align
= 0;
223 return NT_STATUS_INVALID_LEVEL
;