2004-09-20 11:28:43 +04:00
/*
Unix SMB / CIFS implementation .
POSIX NTVFS backend - fsinfo
Copyright ( C ) Andrew Tridgell 2004
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2004-11-05 10:24:25 +03:00
# include "includes.h"
2004-09-20 11:28:43 +04:00
# include "vfs_posix.h"
2006-03-16 03:23:11 +03:00
# include "librpc/gen_ndr/xattr.h"
2006-03-19 00:13:07 +03:00
# include "librpc/ndr/libndr.h"
2004-09-20 11:28:43 +04:00
2005-05-03 13:57:34 +04:00
/* We use libblkid out of e2fsprogs to identify UUID of a volume */
# ifdef HAVE_LIBBLKID
2005-12-02 17:53:56 +03:00
# include <blkid/blkid.h>
# endif
static NTSTATUS pvfs_blkid_fs_uuid ( struct pvfs_state * pvfs , struct stat * st , struct GUID * uuid )
{
# ifdef HAVE_LIBBLKID
NTSTATUS status ;
char * uuid_value = NULL ;
char * devname = NULL ;
devname = blkid_devno_to_devname ( st - > st_dev ) ;
if ( ! devname ) {
2006-08-13 15:55:13 +04:00
ZERO_STRUCTP ( uuid ) ;
return NT_STATUS_OK ;
2005-12-02 17:53:56 +03:00
}
uuid_value = blkid_get_tag_value ( NULL , " UUID " , devname ) ;
free ( devname ) ;
if ( ! uuid_value ) {
2006-08-13 15:55:13 +04:00
ZERO_STRUCTP ( uuid ) ;
return NT_STATUS_OK ;
2005-12-02 17:53:56 +03:00
}
status = GUID_from_string ( uuid_value , uuid ) ;
free ( uuid_value ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2006-08-13 15:55:13 +04:00
ZERO_STRUCTP ( uuid ) ;
return NT_STATUS_OK ;
2005-12-02 17:53:56 +03:00
}
return NT_STATUS_OK ;
# else
ZERO_STRUCTP ( uuid ) ;
return NT_STATUS_OK ;
2005-05-03 13:57:34 +04:00
# endif
2005-12-02 17:53:56 +03:00
}
static NTSTATUS pvfs_cache_base_fs_uuid ( struct pvfs_state * pvfs , struct stat * st )
{
NTSTATUS status ;
struct GUID uuid ;
if ( pvfs - > base_fs_uuid ) return NT_STATUS_OK ;
status = pvfs_blkid_fs_uuid ( pvfs , st , & uuid ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
pvfs - > base_fs_uuid = talloc ( pvfs , struct GUID ) ;
NT_STATUS_HAVE_NO_MEMORY ( pvfs - > base_fs_uuid ) ;
* pvfs - > base_fs_uuid = uuid ;
return NT_STATUS_OK ;
}
2004-09-20 11:28:43 +04:00
/*
return filesystem space info
*/
2004-09-29 17:17:09 +04:00
NTSTATUS pvfs_fsinfo ( struct ntvfs_module_context * ntvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req , union smb_fsinfo * fs )
2004-09-20 11:28:43 +04:00
{
2005-12-02 17:53:56 +03:00
NTSTATUS status ;
2004-09-29 17:17:09 +04:00
struct pvfs_state * pvfs = ntvfs - > private_data ;
2004-10-25 09:44:00 +04:00
uint64_t blocks_free , blocks_total ;
uint_t bpunit ;
2004-09-20 11:28:43 +04:00
struct stat st ;
2004-10-25 09:44:00 +04:00
const uint16_t block_size = 512 ;
2004-09-20 11:28:43 +04:00
2004-10-25 09:44:00 +04:00
/* only some levels need the expensive sys_fsusage() call */
switch ( fs - > generic . level ) {
case RAW_QFS_DSKATTR :
case RAW_QFS_ALLOCATION :
case RAW_QFS_SIZE_INFO :
case RAW_QFS_SIZE_INFORMATION :
case RAW_QFS_FULL_SIZE_INFORMATION :
if ( sys_fsusage ( pvfs - > base_directory , & blocks_free , & blocks_total ) = = - 1 ) {
return pvfs_map_errno ( pvfs , errno ) ;
}
default :
break ;
2004-09-20 11:28:43 +04:00
}
2004-10-25 09:44:00 +04:00
if ( stat ( pvfs - > base_directory , & st ) ! = 0 ) {
return NT_STATUS_DISK_CORRUPT_ERROR ;
2004-09-20 11:28:43 +04:00
}
2004-10-25 09:44:00 +04:00
/* now fill in the out fields */
switch ( fs - > generic . level ) {
case RAW_QFS_GENERIC :
return NT_STATUS_INVALID_LEVEL ;
2004-09-20 11:28:43 +04:00
2004-10-25 09:44:00 +04:00
case RAW_QFS_DSKATTR :
/* we need to scale the sizes to fit */
for ( bpunit = 64 ; bpunit < 0x10000 ; bpunit * = 2 ) {
if ( blocks_total * ( double ) block_size < bpunit * 512 * 65535.0 ) {
break ;
}
}
fs - > dskattr . out . blocks_per_unit = bpunit ;
fs - > dskattr . out . block_size = block_size ;
fs - > dskattr . out . units_total = ( blocks_total * ( double ) block_size ) / ( bpunit * 512 ) ;
fs - > dskattr . out . units_free = ( blocks_free * ( double ) block_size ) / ( bpunit * 512 ) ;
/* we must return a maximum of 2G to old DOS systems, or they get very confused */
2006-03-16 21:54:19 +03:00
if ( bpunit > 64 & & req - > ctx - > protocol < = PROTOCOL_LANMAN2 ) {
2004-10-25 09:44:00 +04:00
fs - > dskattr . out . blocks_per_unit = 64 ;
fs - > dskattr . out . units_total = 0xFFFF ;
fs - > dskattr . out . units_free = 0xFFFF ;
}
return NT_STATUS_OK ;
case RAW_QFS_ALLOCATION :
fs - > allocation . out . fs_id = st . st_dev ;
fs - > allocation . out . total_alloc_units = blocks_total ;
fs - > allocation . out . avail_alloc_units = blocks_free ;
fs - > allocation . out . sectors_per_unit = 1 ;
fs - > allocation . out . bytes_per_sector = block_size ;
return NT_STATUS_OK ;
case RAW_QFS_VOLUME :
fs - > volume . out . serial_number = st . st_ino ;
fs - > volume . out . volume_name . s = pvfs - > share_name ;
return NT_STATUS_OK ;
case RAW_QFS_VOLUME_INFO :
case RAW_QFS_VOLUME_INFORMATION :
unix_to_nt_time ( & fs - > volume_info . out . create_time , st . st_ctime ) ;
fs - > volume_info . out . serial_number = st . st_ino ;
fs - > volume_info . out . volume_name . s = pvfs - > share_name ;
return NT_STATUS_OK ;
case RAW_QFS_SIZE_INFO :
case RAW_QFS_SIZE_INFORMATION :
fs - > size_info . out . total_alloc_units = blocks_total ;
fs - > size_info . out . avail_alloc_units = blocks_free ;
fs - > size_info . out . sectors_per_unit = 1 ;
fs - > size_info . out . bytes_per_sector = block_size ;
return NT_STATUS_OK ;
case RAW_QFS_DEVICE_INFO :
case RAW_QFS_DEVICE_INFORMATION :
fs - > device_info . out . device_type = 0 ;
fs - > device_info . out . characteristics = 0 ;
return NT_STATUS_OK ;
case RAW_QFS_ATTRIBUTE_INFO :
case RAW_QFS_ATTRIBUTE_INFORMATION :
2004-11-17 09:30:06 +03:00
fs - > attribute_info . out . fs_attr = pvfs - > fs_attribs ;
2004-10-25 09:44:00 +04:00
fs - > attribute_info . out . max_file_component_length = 255 ;
2006-03-15 20:28:46 +03:00
fs - > attribute_info . out . fs_type . s = ntvfs - > ctx - > fs_type ;
2004-10-25 09:44:00 +04:00
return NT_STATUS_OK ;
case RAW_QFS_QUOTA_INFORMATION :
ZERO_STRUCT ( fs - > quota_information . out . unknown ) ;
fs - > quota_information . out . quota_soft = 0 ;
fs - > quota_information . out . quota_hard = 0 ;
fs - > quota_information . out . quota_flags = 0 ;
return NT_STATUS_OK ;
case RAW_QFS_FULL_SIZE_INFORMATION :
fs - > full_size_information . out . total_alloc_units = blocks_total ;
fs - > full_size_information . out . call_avail_alloc_units = blocks_free ;
fs - > full_size_information . out . actual_avail_alloc_units = blocks_free ;
fs - > full_size_information . out . sectors_per_unit = 1 ;
fs - > full_size_information . out . bytes_per_sector = block_size ;
return NT_STATUS_OK ;
case RAW_QFS_OBJECTID_INFORMATION :
2005-12-02 17:53:56 +03:00
ZERO_STRUCT ( fs - > objectid_information . out . guid ) ;
ZERO_STRUCT ( fs - > objectid_information . out . unknown ) ;
status = pvfs_cache_base_fs_uuid ( pvfs , & st ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
fs - > objectid_information . out . guid = * pvfs - > base_fs_uuid ;
2005-05-03 17:02:14 +04:00
return NT_STATUS_OK ;
2005-12-02 17:53:56 +03:00
2005-05-03 17:02:14 +04:00
default :
break ;
2004-09-20 11:28:43 +04:00
}
2004-10-25 09:44:00 +04:00
return NT_STATUS_INVALID_LEVEL ;
2004-09-20 11:28:43 +04:00
}