Line data Source code
1 : /* 2 : Unix SMB/CIFS implementation. 3 : 4 : POSIX NTVFS backend - fsinfo 5 : 6 : Copyright (C) Andrew Tridgell 2004 7 : 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. 12 : 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. 17 : 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/>. 20 : */ 21 : 22 : #include "includes.h" 23 : #include "vfs_posix.h" 24 : #include "librpc/gen_ndr/xattr.h" 25 : #include "librpc/ndr/libndr.h" 26 : 27 : /* We use libblkid out of e2fsprogs to identify UUID of a volume */ 28 : #ifdef HAVE_LIBBLKID 29 : #include <blkid/blkid.h> 30 : #endif 31 : 32 15 : static NTSTATUS pvfs_blkid_fs_uuid(struct pvfs_state *pvfs, struct stat *st, struct GUID *uuid) 33 : { 34 : #ifdef HAVE_LIBBLKID 35 : NTSTATUS status; 36 : char *uuid_value = NULL; 37 : char *devname = NULL; 38 : 39 : devname = blkid_devno_to_devname(st->st_dev); 40 : if (!devname) { 41 : ZERO_STRUCTP(uuid); 42 : return NT_STATUS_OK; 43 : } 44 : 45 : uuid_value = blkid_get_tag_value(NULL, "UUID", devname); 46 : free(devname); 47 : if (!uuid_value) { 48 : ZERO_STRUCTP(uuid); 49 : return NT_STATUS_OK; 50 : } 51 : 52 : status = GUID_from_string(uuid_value, uuid); 53 : free(uuid_value); 54 : if (!NT_STATUS_IS_OK(status)) { 55 : ZERO_STRUCTP(uuid); 56 : return NT_STATUS_OK; 57 : } 58 : return NT_STATUS_OK; 59 : #else 60 15 : ZERO_STRUCTP(uuid); 61 15 : return NT_STATUS_OK; 62 : #endif 63 : } 64 : 65 15 : static NTSTATUS pvfs_cache_base_fs_uuid(struct pvfs_state *pvfs, struct stat *st) 66 : { 67 0 : NTSTATUS status; 68 0 : struct GUID uuid; 69 : 70 15 : if (pvfs->base_fs_uuid) return NT_STATUS_OK; 71 : 72 15 : status = pvfs_blkid_fs_uuid(pvfs, st, &uuid); 73 15 : NT_STATUS_NOT_OK_RETURN(status); 74 : 75 15 : pvfs->base_fs_uuid = talloc(pvfs, struct GUID); 76 15 : NT_STATUS_HAVE_NO_MEMORY(pvfs->base_fs_uuid); 77 15 : *pvfs->base_fs_uuid = uuid; 78 : 79 15 : return NT_STATUS_OK; 80 : } 81 : /* 82 : return filesystem space info 83 : */ 84 4195 : NTSTATUS pvfs_fsinfo(struct ntvfs_module_context *ntvfs, 85 : struct ntvfs_request *req, union smb_fsinfo *fs) 86 : { 87 0 : NTSTATUS status; 88 4195 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data, 89 : struct pvfs_state); 90 0 : uint64_t blocks_free, blocks_total; 91 0 : unsigned int bpunit; 92 0 : struct stat st; 93 4195 : const uint16_t block_size = 512; 94 : 95 : /* only some levels need the expensive sys_fsusage() call */ 96 4195 : switch (fs->generic.level) { 97 59 : case RAW_QFS_DSKATTR: 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 59 : if (sys_fsusage(pvfs->base_directory, &blocks_free, &blocks_total) == -1) { 103 0 : return pvfs_map_errno(pvfs, errno); 104 : } 105 59 : break; 106 4136 : default: 107 4136 : break; 108 : } 109 : 110 4195 : if (stat(pvfs->base_directory, &st) != 0) { 111 0 : return NT_STATUS_DISK_CORRUPT_ERROR; 112 : } 113 : 114 : /* now fill in the out fields */ 115 4195 : switch (fs->generic.level) { 116 0 : case RAW_QFS_GENERIC: 117 222 : return NT_STATUS_INVALID_LEVEL; 118 : 119 1 : case RAW_QFS_DSKATTR: 120 : /* we need to scale the sizes to fit */ 121 6 : for (bpunit=64; bpunit<0x10000; bpunit *= 2) { 122 6 : if (blocks_total * (double)block_size < bpunit * 512 * 65535.0) { 123 1 : break; 124 : } 125 : } 126 1 : fs->dskattr.out.blocks_per_unit = bpunit; 127 1 : fs->dskattr.out.block_size = block_size; 128 1 : fs->dskattr.out.units_total = (blocks_total * (double)block_size) / (bpunit * 512); 129 1 : fs->dskattr.out.units_free = (blocks_free * (double)block_size) / (bpunit * 512); 130 : 131 : /* we must return a maximum of 2G to old DOS systems, or they get very confused */ 132 1 : if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) { 133 0 : fs->dskattr.out.blocks_per_unit = 64; 134 0 : fs->dskattr.out.units_total = 0xFFFF; 135 0 : fs->dskattr.out.units_free = 0xFFFF; 136 : } 137 1 : return NT_STATUS_OK; 138 : 139 5 : case RAW_QFS_ALLOCATION: 140 5 : fs->allocation.out.fs_id = st.st_dev; 141 5 : fs->allocation.out.total_alloc_units = blocks_total; 142 5 : fs->allocation.out.avail_alloc_units = blocks_free; 143 5 : fs->allocation.out.sectors_per_unit = 1; 144 5 : fs->allocation.out.bytes_per_sector = block_size; 145 5 : return NT_STATUS_OK; 146 : 147 5 : case RAW_QFS_VOLUME: 148 5 : fs->volume.out.serial_number = st.st_ino; 149 5 : fs->volume.out.volume_name.s = pvfs->share_name; 150 5 : return NT_STATUS_OK; 151 : 152 37 : case RAW_QFS_VOLUME_INFO: 153 : case RAW_QFS_VOLUME_INFORMATION: 154 37 : unix_to_nt_time(&fs->volume_info.out.create_time, st.st_ctime); 155 37 : fs->volume_info.out.serial_number = st.st_ino; 156 37 : fs->volume_info.out.volume_name.s = pvfs->share_name; 157 37 : return NT_STATUS_OK; 158 : 159 47 : case RAW_QFS_SIZE_INFO: 160 : case RAW_QFS_SIZE_INFORMATION: 161 47 : fs->size_info.out.total_alloc_units = blocks_total; 162 47 : fs->size_info.out.avail_alloc_units = blocks_free; 163 47 : fs->size_info.out.sectors_per_unit = 1; 164 47 : fs->size_info.out.bytes_per_sector = block_size; 165 47 : return NT_STATUS_OK; 166 : 167 21 : case RAW_QFS_DEVICE_INFO: 168 : case RAW_QFS_DEVICE_INFORMATION: 169 21 : fs->device_info.out.device_type = 0; 170 21 : fs->device_info.out.characteristics = 0; 171 21 : return NT_STATUS_OK; 172 : 173 75 : case RAW_QFS_ATTRIBUTE_INFO: 174 : case RAW_QFS_ATTRIBUTE_INFORMATION: 175 75 : fs->attribute_info.out.fs_attr = pvfs->fs_attribs; 176 75 : fs->attribute_info.out.max_file_component_length = 255; 177 75 : fs->attribute_info.out.fs_type.s = ntvfs->ctx->fs_type; 178 75 : return NT_STATUS_OK; 179 : 180 6 : case RAW_QFS_QUOTA_INFORMATION: 181 6 : ZERO_STRUCT(fs->quota_information.out.unknown); 182 6 : fs->quota_information.out.quota_soft = 0; 183 6 : fs->quota_information.out.quota_hard = 0; 184 6 : fs->quota_information.out.quota_flags = 0; 185 6 : return NT_STATUS_OK; 186 : 187 6 : case RAW_QFS_FULL_SIZE_INFORMATION: 188 6 : fs->full_size_information.out.total_alloc_units = blocks_total; 189 6 : fs->full_size_information.out.call_avail_alloc_units = blocks_free; 190 6 : fs->full_size_information.out.actual_avail_alloc_units = blocks_free; 191 6 : fs->full_size_information.out.sectors_per_unit = 1; 192 6 : fs->full_size_information.out.bytes_per_sector = block_size; 193 6 : return NT_STATUS_OK; 194 : 195 15 : case RAW_QFS_OBJECTID_INFORMATION: 196 15 : ZERO_STRUCT(fs->objectid_information.out.guid); 197 15 : ZERO_STRUCT(fs->objectid_information.out.unknown); 198 : 199 15 : status = pvfs_cache_base_fs_uuid(pvfs, &st); 200 15 : NT_STATUS_NOT_OK_RETURN(status); 201 : 202 15 : fs->objectid_information.out.guid = *pvfs->base_fs_uuid; 203 15 : return NT_STATUS_OK; 204 : 205 4 : case RAW_QFS_SECTOR_SIZE_INFORMATION: 206 4 : fs->sector_size_info.out.logical_bytes_per_sector = block_size; 207 0 : fs->sector_size_info.out.phys_bytes_per_sector_atomic 208 4 : = block_size; 209 0 : fs->sector_size_info.out.phys_bytes_per_sector_perf 210 4 : = block_size; 211 0 : fs->sector_size_info.out.fs_effective_phys_bytes_per_sector_atomic 212 4 : = block_size; 213 0 : fs->sector_size_info.out.flags 214 4 : = QFS_SSINFO_FLAGS_ALIGNED_DEVICE 215 : | QFS_SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE; 216 4 : fs->sector_size_info.out.byte_off_sector_align = 0; 217 4 : fs->sector_size_info.out.byte_off_partition_align = 0; 218 4 : return NT_STATUS_OK; 219 : 220 3973 : default: 221 3973 : break; 222 : } 223 3973 : return NT_STATUS_INVALID_LEVEL; 224 : }