2004-09-20 07:28:43 +00:00
/*
Unix SMB / CIFS implementation .
POSIX NTVFS backend - read
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
2007-07-10 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2004-09-20 07:28:43 +00:00
( 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
2007-07-10 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-09-20 07:28:43 +00:00
*/
2004-11-05 07:24:25 +00:00
# include "includes.h"
2004-09-20 07:28:43 +00:00
# include "vfs_posix.h"
2006-03-16 00:23:11 +00:00
# include "librpc/gen_ndr/xattr.h"
2004-09-20 07:28:43 +00:00
2004-12-30 05:50:23 +00:00
/*
determine what access bits are needed for a call
*/
2006-04-12 16:27:53 +00:00
static uint32_t pvfs_fileinfo_access ( union smb_fileinfo * info )
2004-12-30 05:50:23 +00:00
{
uint32_t needed ;
2006-04-12 16:27:53 +00:00
switch ( info - > generic . level ) {
2004-12-30 05:50:23 +00:00
case RAW_FILEINFO_EA_LIST :
case RAW_FILEINFO_ALL_EAS :
needed = SEC_FILE_READ_EA ;
break ;
case RAW_FILEINFO_IS_NAME_VALID :
needed = 0 ;
break ;
2004-12-31 08:56:32 +00:00
case RAW_FILEINFO_SEC_DESC :
2006-04-12 16:27:53 +00:00
needed = 0 ;
if ( info - > query_secdesc . in . secinfo_flags & ( SECINFO_OWNER | SECINFO_GROUP ) ) {
needed | = SEC_STD_READ_CONTROL ;
}
if ( info - > query_secdesc . in . secinfo_flags & SECINFO_DACL ) {
needed | = SEC_STD_READ_CONTROL ;
}
if ( info - > query_secdesc . in . secinfo_flags & SECINFO_SACL ) {
needed | = SEC_FLAG_SYSTEM_SECURITY ;
}
2004-12-31 08:56:32 +00:00
break ;
2004-12-30 05:50:23 +00:00
default :
needed = SEC_FILE_READ_ATTRIBUTE ;
break ;
}
2006-04-12 16:27:53 +00:00
return needed ;
2004-12-30 05:50:23 +00:00
}
2004-12-17 22:47:49 +00:00
/*
reply to a RAW_FILEINFO_EA_LIST call
*/
2004-12-18 04:38:43 +00:00
NTSTATUS pvfs_query_ea_list ( struct pvfs_state * pvfs , TALLOC_CTX * mem_ctx ,
struct pvfs_filename * name , int fd ,
uint_t num_names ,
struct ea_name * names ,
struct smb_ea_list * eas )
2004-12-17 22:47:49 +00:00
{
NTSTATUS status ;
int i ;
2005-01-27 07:08:20 +00:00
struct xattr_DosEAs * ealist = talloc ( mem_ctx , struct xattr_DosEAs ) ;
2004-12-17 22:47:49 +00:00
ZERO_STRUCTP ( eas ) ;
status = pvfs_doseas_load ( pvfs , name , fd , ealist ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2005-01-27 07:08:20 +00:00
eas - > eas = talloc_array ( mem_ctx , struct ea_struct , num_names ) ;
2004-12-17 22:47:49 +00:00
if ( eas - > eas = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
eas - > num_eas = num_names ;
for ( i = 0 ; i < num_names ; i + + ) {
int j ;
eas - > eas [ i ] . flags = 0 ;
eas - > eas [ i ] . name . s = names [ i ] . name . s ;
eas - > eas [ i ] . value = data_blob ( NULL , 0 ) ;
for ( j = 0 ; j < ealist - > num_eas ; j + + ) {
2005-08-30 11:55:05 +00:00
if ( strcasecmp_m ( eas - > eas [ i ] . name . s ,
2004-12-17 22:47:49 +00:00
ealist - > eas [ j ] . name ) = = 0 ) {
eas - > eas [ i ] . value = ealist - > eas [ j ] . value ;
break ;
}
}
}
return NT_STATUS_OK ;
}
2004-11-05 11:31:35 +00:00
/*
reply to a RAW_FILEINFO_ALL_EAS call
*/
static NTSTATUS pvfs_query_all_eas ( struct pvfs_state * pvfs , TALLOC_CTX * mem_ctx ,
2004-11-17 12:36:14 +00:00
struct pvfs_filename * name , int fd ,
struct smb_ea_list * eas )
2004-11-05 11:31:35 +00:00
{
NTSTATUS status ;
int i ;
2005-01-27 07:08:20 +00:00
struct xattr_DosEAs * ealist = talloc ( mem_ctx , struct xattr_DosEAs ) ;
2004-11-05 11:31:35 +00:00
ZERO_STRUCTP ( eas ) ;
status = pvfs_doseas_load ( pvfs , name , fd , ealist ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2005-01-27 07:08:20 +00:00
eas - > eas = talloc_array ( mem_ctx , struct ea_struct , ealist - > num_eas ) ;
2004-11-05 11:31:35 +00:00
if ( eas - > eas = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2004-12-17 22:47:49 +00:00
eas - > num_eas = 0 ;
for ( i = 0 ; i < ealist - > num_eas ; i + + ) {
eas - > eas [ eas - > num_eas ] . flags = 0 ;
eas - > eas [ eas - > num_eas ] . name . s = ealist - > eas [ i ] . name ;
eas - > eas [ eas - > num_eas ] . value = ealist - > eas [ i ] . value ;
eas - > num_eas + + ;
2004-11-05 11:31:35 +00:00
}
return NT_STATUS_OK ;
}
2004-09-20 07:28:43 +00:00
/*
approximately map a struct pvfs_filename to a generic fileinfo struct
*/
2004-11-18 03:31:35 +00:00
static NTSTATUS pvfs_map_fileinfo ( struct pvfs_state * pvfs ,
2006-03-10 14:31:17 +00:00
struct ntvfs_request * req ,
2004-11-05 11:31:35 +00:00
struct pvfs_filename * name , union smb_fileinfo * info ,
int fd )
2004-09-20 07:28:43 +00:00
{
2004-10-25 01:16:04 +00:00
switch ( info - > generic . level ) {
2004-10-28 13:19:39 +00:00
case RAW_FILEINFO_GENERIC :
return NT_STATUS_INVALID_LEVEL ;
2004-10-25 01:16:04 +00:00
case RAW_FILEINFO_GETATTR :
info - > getattr . out . attrib = name - > dos . attrib ;
info - > getattr . out . size = name - > st . st_size ;
info - > getattr . out . write_time = nt_time_to_unix ( name - > dos . write_time ) ;
return NT_STATUS_OK ;
case RAW_FILEINFO_GETATTRE :
case RAW_FILEINFO_STANDARD :
info - > standard . out . create_time = nt_time_to_unix ( name - > dos . create_time ) ;
info - > standard . out . access_time = nt_time_to_unix ( name - > dos . access_time ) ;
info - > standard . out . write_time = nt_time_to_unix ( name - > dos . write_time ) ;
info - > standard . out . size = name - > st . st_size ;
info - > standard . out . alloc_size = name - > dos . alloc_size ;
info - > standard . out . attrib = name - > dos . attrib ;
return NT_STATUS_OK ;
case RAW_FILEINFO_EA_SIZE :
info - > ea_size . out . create_time = nt_time_to_unix ( name - > dos . create_time ) ;
info - > ea_size . out . access_time = nt_time_to_unix ( name - > dos . access_time ) ;
info - > ea_size . out . write_time = nt_time_to_unix ( name - > dos . write_time ) ;
info - > ea_size . out . size = name - > st . st_size ;
info - > ea_size . out . alloc_size = name - > dos . alloc_size ;
info - > ea_size . out . attrib = name - > dos . attrib ;
info - > ea_size . out . ea_size = name - > dos . ea_size ;
return NT_STATUS_OK ;
2004-12-17 22:47:49 +00:00
case RAW_FILEINFO_EA_LIST :
return pvfs_query_ea_list ( pvfs , req , name , fd ,
info - > ea_list . in . num_names ,
info - > ea_list . in . ea_names ,
& info - > ea_list . out ) ;
2004-10-25 01:16:04 +00:00
case RAW_FILEINFO_ALL_EAS :
2004-11-18 03:31:35 +00:00
return pvfs_query_all_eas ( pvfs , req , name , fd , & info - > all_eas . out ) ;
2004-10-25 01:16:04 +00:00
case RAW_FILEINFO_IS_NAME_VALID :
return NT_STATUS_OK ;
case RAW_FILEINFO_BASIC_INFO :
case RAW_FILEINFO_BASIC_INFORMATION :
info - > basic_info . out . create_time = name - > dos . create_time ;
info - > basic_info . out . access_time = name - > dos . access_time ;
info - > basic_info . out . write_time = name - > dos . write_time ;
info - > basic_info . out . change_time = name - > dos . change_time ;
info - > basic_info . out . attrib = name - > dos . attrib ;
return NT_STATUS_OK ;
case RAW_FILEINFO_STANDARD_INFO :
case RAW_FILEINFO_STANDARD_INFORMATION :
info - > standard_info . out . alloc_size = name - > dos . alloc_size ;
info - > standard_info . out . size = name - > st . st_size ;
2006-02-28 03:47:02 +00:00
info - > standard_info . out . nlink = name - > dos . nlink ;
2006-06-22 17:36:06 +00:00
info - > standard_info . out . delete_pending = 0 ; /* only for qfileinfo */
2004-10-25 01:16:04 +00:00
info - > standard_info . out . directory =
( name - > dos . attrib & FILE_ATTRIBUTE_DIRECTORY ) ? 1 : 0 ;
return NT_STATUS_OK ;
case RAW_FILEINFO_EA_INFO :
case RAW_FILEINFO_EA_INFORMATION :
info - > ea_info . out . ea_size = name - > dos . ea_size ;
return NT_STATUS_OK ;
case RAW_FILEINFO_NAME_INFO :
case RAW_FILEINFO_NAME_INFORMATION :
info - > name_info . out . fname . s = name - > original_name ;
return NT_STATUS_OK ;
case RAW_FILEINFO_ALL_INFO :
case RAW_FILEINFO_ALL_INFORMATION :
info - > all_info . out . create_time = name - > dos . create_time ;
info - > all_info . out . access_time = name - > dos . access_time ;
info - > all_info . out . write_time = name - > dos . write_time ;
info - > all_info . out . change_time = name - > dos . change_time ;
info - > all_info . out . attrib = name - > dos . attrib ;
info - > all_info . out . alloc_size = name - > dos . alloc_size ;
info - > all_info . out . size = name - > st . st_size ;
2006-02-28 03:47:02 +00:00
info - > all_info . out . nlink = name - > dos . nlink ;
2006-06-22 17:36:06 +00:00
info - > all_info . out . delete_pending = 0 ; /* only set by qfileinfo */
2004-10-25 01:16:04 +00:00
info - > all_info . out . directory =
( name - > dos . attrib & FILE_ATTRIBUTE_DIRECTORY ) ? 1 : 0 ;
info - > all_info . out . ea_size = name - > dos . ea_size ;
info - > all_info . out . fname . s = name - > original_name ;
return NT_STATUS_OK ;
case RAW_FILEINFO_ALT_NAME_INFO :
case RAW_FILEINFO_ALT_NAME_INFORMATION :
info - > name_info . out . fname . s = pvfs_short_name ( pvfs , name , name ) ;
return NT_STATUS_OK ;
case RAW_FILEINFO_STREAM_INFO :
case RAW_FILEINFO_STREAM_INFORMATION :
2004-11-18 03:31:35 +00:00
return pvfs_stream_information ( pvfs , req , name , fd , & info - > stream_info . out ) ;
2004-10-25 01:16:04 +00:00
case RAW_FILEINFO_COMPRESSION_INFO :
case RAW_FILEINFO_COMPRESSION_INFORMATION :
info - > compression_info . out . compressed_size = name - > st . st_size ;
info - > compression_info . out . format = 0 ;
info - > compression_info . out . unit_shift = 0 ;
info - > compression_info . out . chunk_shift = 0 ;
info - > compression_info . out . cluster_shift = 0 ;
return NT_STATUS_OK ;
case RAW_FILEINFO_INTERNAL_INFORMATION :
info - > internal_information . out . file_id = name - > dos . file_id ;
return NT_STATUS_OK ;
case RAW_FILEINFO_ACCESS_INFORMATION :
2006-06-22 17:36:06 +00:00
info - > access_information . out . access_flags = 0 ; /* only set by qfileinfo */
2004-10-25 01:16:04 +00:00
return NT_STATUS_OK ;
case RAW_FILEINFO_POSITION_INFORMATION :
2006-06-22 17:36:06 +00:00
info - > position_information . out . position = 0 ; /* only set by qfileinfo */
2004-10-25 01:16:04 +00:00
return NT_STATUS_OK ;
case RAW_FILEINFO_MODE_INFORMATION :
2006-06-22 17:36:06 +00:00
info - > mode_information . out . mode = 0 ; /* only set by qfileinfo */
2004-10-25 01:16:04 +00:00
return NT_STATUS_OK ;
case RAW_FILEINFO_ALIGNMENT_INFORMATION :
info - > alignment_information . out . alignment_requirement = 0 ;
return NT_STATUS_OK ;
case RAW_FILEINFO_NETWORK_OPEN_INFORMATION :
info - > network_open_information . out . create_time = name - > dos . create_time ;
info - > network_open_information . out . access_time = name - > dos . access_time ;
info - > network_open_information . out . write_time = name - > dos . write_time ;
info - > network_open_information . out . change_time = name - > dos . change_time ;
info - > network_open_information . out . alloc_size = name - > dos . alloc_size ;
info - > network_open_information . out . size = name - > st . st_size ;
info - > network_open_information . out . attrib = name - > dos . attrib ;
return NT_STATUS_OK ;
case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION :
info - > attribute_tag_information . out . attrib = name - > dos . attrib ;
info - > attribute_tag_information . out . reparse_tag = 0 ;
return NT_STATUS_OK ;
2004-11-18 03:31:35 +00:00
case RAW_FILEINFO_SEC_DESC :
return pvfs_acl_query ( pvfs , req , name , fd , info ) ;
2006-06-22 17:36:06 +00:00
case RAW_FILEINFO_SMB2_ALL_INFORMATION :
info - > all_info2 . out . create_time = name - > dos . create_time ;
info - > all_info2 . out . access_time = name - > dos . access_time ;
info - > all_info2 . out . write_time = name - > dos . write_time ;
info - > all_info2 . out . change_time = name - > dos . change_time ;
info - > all_info2 . out . attrib = name - > dos . attrib ;
info - > all_info2 . out . unknown1 = 0 ;
info - > all_info2 . out . alloc_size = name - > dos . alloc_size ;
info - > all_info2 . out . size = name - > st . st_size ;
info - > all_info2 . out . nlink = name - > dos . nlink ;
info - > all_info2 . out . delete_pending = 0 ; /* only set by qfileinfo */
info - > all_info2 . out . directory =
( name - > dos . attrib & FILE_ATTRIBUTE_DIRECTORY ) ? 1 : 0 ;
info - > all_info2 . out . file_id = name - > dos . file_id ;
info - > all_info2 . out . ea_size = name - > dos . ea_size ;
info - > all_info2 . out . access_mask = 0 ; /* only set by qfileinfo */
info - > all_info2 . out . position = 0 ; /* only set by qfileinfo */
info - > all_info2 . out . mode = 0 ; /* only set by qfileinfo */
info - > all_info2 . out . fname . s = name - > original_name ;
return NT_STATUS_OK ;
2004-09-20 07:28:43 +00:00
}
2004-10-25 01:16:04 +00:00
return NT_STATUS_INVALID_LEVEL ;
2004-09-20 07:28:43 +00:00
}
/*
return info on a pathname
*/
2004-09-29 13:17:09 +00:00
NTSTATUS pvfs_qpathinfo ( struct ntvfs_module_context * ntvfs ,
2006-03-10 14:31:17 +00:00
struct ntvfs_request * req , union smb_fileinfo * info )
2004-09-20 07:28:43 +00:00
{
2004-09-29 13:17:09 +00:00
struct pvfs_state * pvfs = ntvfs - > private_data ;
2004-09-20 07:28:43 +00:00
struct pvfs_filename * name ;
NTSTATUS status ;
/* resolve the cifs name to a posix name */
2006-03-12 22:48:25 +00:00
status = pvfs_resolve_name ( pvfs , req , info - > generic . in . file . path , PVFS_RESOLVE_STREAMS , & name ) ;
2004-09-20 07:28:43 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-11-17 05:58:04 +00:00
if ( ! name - > stream_exists ) {
2004-09-20 07:28:43 +00:00
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2006-02-28 03:47:02 +00:00
status = pvfs_can_stat ( pvfs , req , name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-26 10:29:07 +01:00
return status ;
2006-02-28 03:47:02 +00:00
}
2004-12-30 05:50:23 +00:00
status = pvfs_access_check_simple ( pvfs , req , name ,
2006-04-12 16:27:53 +00:00
pvfs_fileinfo_access ( info ) ) ;
2004-12-30 05:50:23 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-11-05 11:31:35 +00:00
status = pvfs_map_fileinfo ( pvfs , req , name , info , - 1 ) ;
2004-10-25 01:16:04 +00:00
return status ;
2004-09-20 07:28:43 +00:00
}
/*
query info on a open file
*/
2004-09-29 13:17:09 +00:00
NTSTATUS pvfs_qfileinfo ( struct ntvfs_module_context * ntvfs ,
2006-03-10 14:31:17 +00:00
struct ntvfs_request * req , union smb_fileinfo * info )
2004-09-20 07:28:43 +00:00
{
2004-09-29 13:17:09 +00:00
struct pvfs_state * pvfs = ntvfs - > private_data ;
2004-09-20 07:28:43 +00:00
struct pvfs_file * f ;
2004-11-08 03:54:12 +00:00
struct pvfs_file_handle * h ;
2004-09-20 07:28:43 +00:00
NTSTATUS status ;
2004-12-30 05:50:23 +00:00
uint32_t access_needed ;
2004-09-20 07:28:43 +00:00
2006-05-20 08:15:22 +00:00
f = pvfs_find_fd ( pvfs , req , info - > generic . in . file . ntvfs ) ;
2004-09-20 07:28:43 +00:00
if ( ! f ) {
return NT_STATUS_INVALID_HANDLE ;
}
2004-11-08 03:54:12 +00:00
h = f - > handle ;
2004-09-20 07:28:43 +00:00
2006-04-12 16:27:53 +00:00
access_needed = pvfs_fileinfo_access ( info ) ;
2004-12-30 06:02:54 +00:00
if ( ( f - > access_mask & access_needed ) ! = access_needed ) {
2004-12-30 05:50:23 +00:00
return NT_STATUS_ACCESS_DENIED ;
}
2004-09-20 07:28:43 +00:00
/* update the file information */
2004-11-08 03:54:12 +00:00
status = pvfs_resolve_name_fd ( pvfs , h - > fd , h - > name ) ;
2004-09-20 07:28:43 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-11-08 03:54:12 +00:00
status = pvfs_map_fileinfo ( pvfs , req , h - > name , info , h - > fd ) ;
2004-10-24 14:18:03 +00:00
2004-10-25 01:16:04 +00:00
/* a qfileinfo can fill in a bit more info than a qpathinfo -
now modify the levels that need to be fixed up */
switch ( info - > generic . level ) {
case RAW_FILEINFO_STANDARD_INFO :
case RAW_FILEINFO_STANDARD_INFORMATION :
2006-02-28 03:47:02 +00:00
if ( pvfs_delete_on_close_set ( pvfs , h , NULL , NULL ) ) {
2004-10-25 01:16:04 +00:00
info - > standard_info . out . delete_pending = 1 ;
info - > standard_info . out . nlink - - ;
}
break ;
case RAW_FILEINFO_ALL_INFO :
case RAW_FILEINFO_ALL_INFORMATION :
2006-02-28 03:47:02 +00:00
if ( pvfs_delete_on_close_set ( pvfs , h , NULL , NULL ) ) {
2004-10-25 01:16:04 +00:00
info - > all_info . out . delete_pending = 1 ;
info - > all_info . out . nlink - - ;
}
break ;
case RAW_FILEINFO_POSITION_INFORMATION :
2004-11-08 03:54:12 +00:00
info - > position_information . out . position = h - > position ;
2004-10-25 01:16:04 +00:00
break ;
case RAW_FILEINFO_ACCESS_INFORMATION :
2004-11-08 11:35:49 +00:00
info - > access_information . out . access_flags = f - > access_mask ;
2004-10-25 01:16:04 +00:00
break ;
2004-11-07 10:09:50 +00:00
case RAW_FILEINFO_MODE_INFORMATION :
2004-11-08 03:54:12 +00:00
info - > mode_information . out . mode = h - > mode ;
2004-11-07 10:09:50 +00:00
break ;
2006-06-22 17:36:06 +00:00
case RAW_FILEINFO_SMB2_ALL_INFORMATION :
if ( pvfs_delete_on_close_set ( pvfs , h , NULL , NULL ) ) {
2006-07-01 07:47:49 +00:00
info - > all_info2 . out . delete_pending = 1 ;
info - > all_info2 . out . nlink - - ;
2006-06-22 17:36:06 +00:00
}
info - > all_info2 . out . position = h - > position ;
info - > all_info2 . out . access_mask = f - > access_mask ;
info - > all_info2 . out . mode = h - > mode ;
break ;
2004-10-25 01:16:04 +00:00
default :
break ;
}
2004-10-24 14:18:03 +00:00
return status ;
2004-09-20 07:28:43 +00:00
}