2011-06-20 11:52:21 +04:00
/*
* Third attempt at a shadow copy module
2008-01-16 12:21:38 +03:00
*
2011-06-20 11:52:21 +04:00
* Copyright ( C ) Andrew Tridgell 2007 ( portions taken from shadow_copy2 )
* Copyright ( C ) Ed Plese 2009
* Copyright ( C ) Volker Lendecke 2011
* Copyright ( C ) Christian Ambach 2011
2008-01-16 12:21:38 +03:00
*
* 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 .
2011-06-20 11:52:21 +04:00
*
2008-01-16 12:21:38 +03:00
* 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 .
2011-06-20 11:52:21 +04:00
*
2008-01-16 12:21:38 +03:00
* 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 .
*/
/*
2011-06-20 11:52:21 +04:00
This is a 3 rd implemetation of a shadow copy module for exposing
2008-01-16 12:21:38 +03:00
snapshots to windows clients as shadow copies . This version has the
following features :
1 ) you don ' t need to populate your shares with symlinks to the
snapshots . This can be very important when you have thousands of
shares , or use [ homes ]
2 ) the inode number of the files is altered so it is different
from the original . This allows the ' restore ' button to work
without a sharing violation
2009-12-07 06:00:00 +03:00
3 ) shadow copy results can be sorted before being sent to the
client . This is beneficial for filesystems that don ' t read
directories alphabetically ( the default unix ) .
2010-01-21 10:30:01 +03:00
4 ) vanity naming for snapshots . Snapshots can be named in any
format compatible with str [ fp ] time conversions .
2009-12-07 06:03:06 +03:00
5 ) time stamps in snapshot names can be represented in localtime
rather than UTC .
2008-01-16 12:21:38 +03:00
Module options :
shadow : snapdir = < directory where snapshots are kept >
This is the directory containing the @ GMT - * snapshot directories . If it is an absolute
path it is used as - is . If it is a relative path , then it is taken relative to the mount
point of the filesystem that the root of this share is on
shadow : basedir = < base directory that snapshots are from >
This is an optional parameter that specifies the directory that
the snapshots are relative to . It defaults to the filesystem
mount point
shadow : fixinodes = yes / no
If you enable shadow : fixinodes then this module will modify the
apparent inode number of files in the snapshot directories using
a hash of the files path . This is needed for snapshot systems
where the snapshots have the same device : inode number as the
original files ( such as happens with GPFS snapshots ) . If you
don ' t set this option then the ' restore ' button in the shadow
copy UI will fail with a sharing violation .
2009-12-07 06:00:00 +03:00
shadow : sort = asc / desc , or not specified for unsorted ( default )
This is an optional parameter that specifies that the shadow
copy directories should be sorted before sending them to the
client . This can be beneficial as unix filesystems are usually
not listed alphabetically sorted . If enabled , you typically
want to specify descending order .
2010-01-21 10:30:01 +03:00
shadow : format = < format specification for snapshot names >
This is an optional parameter that specifies the format
specification for the naming of snapshots . The format must
be compatible with the conversion specifications recognized
by str [ fp ] time . The default value is " @GMT-%Y.%m.%d-%H.%M.%S " .
2012-07-02 13:31:58 +04:00
shadow : sscanf = yes / no ( default is no )
The time is the unsigned long integer ( % lu ) in the format string
rather than a time strptime ( ) can parse . The result must be a unix time_t
time .
2009-12-07 06:03:06 +03:00
shadow : localtime = yes / no ( default is no )
This is an optional parameter that indicates whether the
snapshot names are in UTC / GMT or the local time .
2010-01-21 10:30:01 +03:00
The following command would generate a correctly formatted directory name
for use with the default parameters :
2008-01-16 12:21:38 +03:00
date - u + @ GMT - % Y . % m . % d - % H . % M . % S
*/
2011-06-20 11:52:21 +04:00
# include "includes.h"
# include "system/filesys.h"
# include "include/ntioctl.h"
2011-08-31 08:26:40 +04:00
# include <ccan/hash/hash.h>
2011-06-20 11:52:21 +04:00
# include "util_tdb.h"
2008-01-16 12:21:38 +03:00
# define GMT_NAME_LEN 24 /* length of a @GMT- name */
2011-06-20 11:52:21 +04:00
# define GMT_FORMAT "@GMT-%Y.%m.%d-%H.%M.%S"
2009-12-07 06:00:00 +03:00
2011-06-20 11:52:21 +04:00
static bool shadow_copy2_find_slashes ( TALLOC_CTX * mem_ctx , const char * str ,
size_t * * poffsets ,
unsigned * pnum_offsets )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
unsigned num_offsets ;
size_t * offsets ;
2009-09-16 05:22:56 +04:00
const char * p ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
num_offsets = 0 ;
2010-01-21 10:30:01 +03:00
2011-06-20 11:52:21 +04:00
p = str ;
while ( ( p = strchr ( p , ' / ' ) ) ! = NULL ) {
num_offsets + = 1 ;
p + = 1 ;
}
2010-01-21 10:30:01 +03:00
2011-06-20 11:52:21 +04:00
offsets = talloc_array ( mem_ctx , size_t , num_offsets ) ;
if ( offsets = = NULL ) {
return false ;
2010-01-21 10:30:01 +03:00
}
2011-06-20 11:52:21 +04:00
p = str ;
num_offsets = 0 ;
while ( ( p = strchr ( p , ' / ' ) ) ! = NULL ) {
offsets [ num_offsets ] = p - str ;
num_offsets + = 1 ;
p + = 1 ;
2009-12-07 06:03:06 +03:00
}
2010-01-21 10:30:01 +03:00
2011-06-20 11:52:21 +04:00
* poffsets = offsets ;
* pnum_offsets = num_offsets ;
return true ;
2010-01-21 10:30:01 +03:00
}
2011-06-20 11:52:21 +04:00
static char * shadow_copy2_insert_string ( TALLOC_CTX * mem_ctx ,
struct vfs_handle_struct * handle ,
time_t snapshot )
2009-09-16 05:22:56 +04:00
{
2012-07-02 13:31:58 +04:00
const char * fmt ;
2011-06-20 11:52:21 +04:00
struct tm snap_tm ;
2012-07-02 16:31:49 +04:00
fstring snaptime_string ;
size_t snaptime_len ;
2009-09-16 05:22:56 +04:00
2012-07-02 13:31:58 +04:00
fmt = lp_parm_const_string ( SNUM ( handle - > conn ) , " shadow " ,
" format " , GMT_FORMAT ) ;
if ( lp_parm_bool ( SNUM ( handle - > conn ) , " shadow " , " sscanf " , false ) ) {
2012-07-02 16:31:49 +04:00
snaptime_len = snprintf ( snaptime_string , sizeof ( snaptime_string ) , fmt ,
2012-07-02 13:31:58 +04:00
( unsigned long ) snapshot ) ;
2012-07-02 16:31:49 +04:00
if ( snaptime_len < = 0 ) {
2012-07-02 13:31:58 +04:00
DEBUG ( 10 , ( " snprintf failed \n " ) ) ;
return NULL ;
}
} else {
2012-07-02 16:31:49 +04:00
if ( lp_parm_bool ( SNUM ( handle - > conn ) , " shadow " , " localtime " , false ) ) {
if ( localtime_r ( & snapshot , & snap_tm ) = = 0 ) {
DEBUG ( 10 , ( " gmtime_r failed \n " ) ) ;
return NULL ;
}
} else {
if ( gmtime_r ( & snapshot , & snap_tm ) = = 0 ) {
DEBUG ( 10 , ( " gmtime_r failed \n " ) ) ;
return NULL ;
}
}
snaptime_len = strftime ( snaptime_string , sizeof ( snaptime_string ) , fmt ,
2012-07-02 13:31:58 +04:00
& snap_tm ) ;
2012-07-02 16:31:49 +04:00
if ( snaptime_len = = 0 ) {
2012-07-02 13:31:58 +04:00
DEBUG ( 10 , ( " strftime failed \n " ) ) ;
return NULL ;
}
2009-09-16 05:22:56 +04:00
}
2012-05-08 11:15:12 +04:00
return talloc_asprintf ( mem_ctx , " /%s/%s " ,
2011-06-20 11:52:21 +04:00
lp_parm_const_string (
SNUM ( handle - > conn ) , " shadow " , " snapdir " ,
" .snapshots " ) ,
2012-07-02 16:31:49 +04:00
snaptime_string ) ;
2009-09-16 05:22:56 +04:00
}
2011-06-20 11:52:21 +04:00
static bool shadow_copy2_strip_snapshot ( TALLOC_CTX * mem_ctx ,
struct vfs_handle_struct * handle ,
const char * name ,
time_t * ptimestamp ,
char * * pstripped )
{
struct tm tm ;
time_t timestamp ;
const char * p ;
char * q ;
char * stripped ;
size_t rest_len , dst_len ;
2009-06-16 23:01:13 +04:00
2011-06-20 11:52:21 +04:00
p = strstr_m ( name , " @GMT- " ) ;
if ( p = = NULL ) {
goto no_snapshot ;
}
if ( ( p > name ) & & ( p [ - 1 ] ! = ' / ' ) ) {
goto no_snapshot ;
}
q = strptime ( p , GMT_FORMAT , & tm ) ;
if ( q = = NULL ) {
goto no_snapshot ;
}
tm . tm_isdst = - 1 ;
2012-07-02 16:31:49 +04:00
timestamp = timegm ( & tm ) ;
2011-06-20 11:52:21 +04:00
if ( timestamp = = ( time_t ) - 1 ) {
goto no_snapshot ;
}
if ( ( p = = name ) & & ( q [ 0 ] = = ' \0 ' ) ) {
if ( pstripped ! = NULL ) {
stripped = talloc_strdup ( mem_ctx , " " ) ;
if ( stripped = = NULL ) {
return false ;
}
* pstripped = stripped ;
}
* ptimestamp = timestamp ;
return true ;
}
if ( q [ 0 ] ! = ' / ' ) {
goto no_snapshot ;
}
q + = 1 ;
rest_len = strlen ( q ) ;
dst_len = ( p - name ) + rest_len ;
if ( lp_parm_bool ( SNUM ( handle - > conn ) , " shadow " , " snapdirseverywhere " ,
false ) ) {
char * insert ;
bool have_insert ;
insert = shadow_copy2_insert_string ( talloc_tos ( ) , handle ,
timestamp ) ;
if ( insert = = NULL ) {
errno = ENOMEM ;
return false ;
}
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
have_insert = ( strstr ( name , insert + 1 ) ! = NULL ) ;
TALLOC_FREE ( insert ) ;
if ( have_insert ) {
goto no_snapshot ;
}
}
2009-07-01 04:04:38 +04:00
2011-06-20 11:52:21 +04:00
if ( pstripped ! = NULL ) {
stripped = talloc_array ( mem_ctx , char , dst_len + 1 ) ;
if ( stripped = = NULL ) {
errno = ENOMEM ;
return false ;
}
if ( p > name ) {
memcpy ( stripped , name , p - name ) ;
}
if ( rest_len > 0 ) {
memcpy ( stripped + ( p - name ) , q , rest_len ) ;
}
stripped [ dst_len ] = ' \0 ' ;
* pstripped = stripped ;
}
* ptimestamp = timestamp ;
return true ;
no_snapshot :
* ptimestamp = 0 ;
return true ;
}
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
static char * shadow_copy2_find_mount_point ( TALLOC_CTX * mem_ctx ,
vfs_handle_struct * handle )
2008-01-16 12:21:38 +03:00
{
char * path = talloc_strdup ( mem_ctx , handle - > conn - > connectpath ) ;
dev_t dev ;
struct stat st ;
char * p ;
if ( stat ( path , & st ) ! = 0 ) {
talloc_free ( path ) ;
return NULL ;
}
dev = st . st_dev ;
while ( ( p = strrchr ( path , ' / ' ) ) & & p > path ) {
* p = 0 ;
if ( stat ( path , & st ) ! = 0 ) {
talloc_free ( path ) ;
return NULL ;
}
if ( st . st_dev ! = dev ) {
* p = ' / ' ;
break ;
}
}
2011-06-20 11:52:21 +04:00
return path ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static char * shadow_copy2_convert ( TALLOC_CTX * mem_ctx ,
struct vfs_handle_struct * handle ,
const char * name , time_t timestamp )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
struct smb_filename converted_fname ;
char * result = NULL ;
size_t * slashes = NULL ;
unsigned num_slashes ;
char * path = NULL ;
size_t pathlen ;
char * insert = NULL ;
char * converted = NULL ;
size_t insertlen ;
int i , saved_errno ;
size_t min_offset ;
path = talloc_asprintf ( mem_ctx , " %s/%s " , handle - > conn - > connectpath ,
name ) ;
if ( path = = NULL ) {
errno = ENOMEM ;
goto fail ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
pathlen = talloc_get_size ( path ) - 1 ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
DEBUG ( 10 , ( " converting %s \n " , path ) ) ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
if ( ! shadow_copy2_find_slashes ( talloc_tos ( ) , path ,
& slashes , & num_slashes ) ) {
goto fail ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
insert = shadow_copy2_insert_string ( talloc_tos ( ) , handle , timestamp ) ;
if ( insert = = NULL ) {
goto fail ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
insertlen = talloc_get_size ( insert ) - 1 ;
converted = talloc_array ( mem_ctx , char , pathlen + insertlen + 1 ) ;
if ( converted = = NULL ) {
goto fail ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
if ( path [ pathlen - 1 ] ! = ' / ' ) {
/*
* Append a fake slash to find the snapshot root
*/
size_t * tmp ;
tmp = talloc_realloc ( talloc_tos ( ) , slashes ,
size_t , num_slashes + 1 ) ;
if ( tmp = = NULL ) {
goto fail ;
}
slashes = tmp ;
slashes [ num_slashes ] = pathlen ;
num_slashes + = 1 ;
2010-04-14 12:05:56 +04:00
}
2011-06-20 11:52:21 +04:00
min_offset = 0 ;
if ( ! lp_parm_bool ( SNUM ( handle - > conn ) , " shadow " , " crossmountpoints " ,
false ) ) {
char * mount_point ;
mount_point = shadow_copy2_find_mount_point ( talloc_tos ( ) ,
handle ) ;
if ( mount_point = = NULL ) {
goto fail ;
2009-09-16 05:22:56 +04:00
}
2011-06-20 11:52:21 +04:00
min_offset = strlen ( mount_point ) ;
TALLOC_FREE ( mount_point ) ;
2009-09-16 05:22:56 +04:00
}
2011-06-20 11:52:21 +04:00
memcpy ( converted , path , pathlen + 1 ) ;
converted [ pathlen + insertlen ] = ' \0 ' ;
2010-01-21 10:30:01 +03:00
2011-06-20 11:52:21 +04:00
ZERO_STRUCT ( converted_fname ) ;
converted_fname . base_name = converted ;
2010-01-21 10:30:01 +03:00
2011-06-20 11:52:21 +04:00
for ( i = num_slashes - 1 ; i > = 0 ; i - - ) {
int ret ;
size_t offset ;
2009-12-07 06:03:06 +03:00
2011-06-20 11:52:21 +04:00
offset = slashes [ i ] ;
2010-01-21 10:30:01 +03:00
2011-06-20 11:52:21 +04:00
if ( offset < min_offset ) {
errno = ENOENT ;
goto fail ;
}
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
memcpy ( converted + offset , insert , insertlen ) ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
offset + = insertlen ;
memcpy ( converted + offset , path + slashes [ i ] ,
pathlen - slashes [ i ] ) ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
ret = SMB_VFS_NEXT_LSTAT ( handle , & converted_fname ) ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
DEBUG ( 10 , ( " Trying %s: %d (%s) \n " , converted ,
ret , ret = = 0 ? " ok " : strerror ( errno ) ) ) ;
if ( ret = = 0 ) {
/* success */
break ;
}
if ( errno = = ENOTDIR ) {
/*
* This is a valid condition : We appended the
* . snaphots / @ GMT . . to a file name . Just try
* with the upper levels .
*/
continue ;
}
if ( errno ! = ENOENT ) {
/* Other problem than "not found" */
goto fail ;
}
}
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
if ( i > = 0 ) {
/*
* Found something
*/
DEBUG ( 10 , ( " Found %s \n " , converted ) ) ;
result = converted ;
converted = NULL ;
} else {
errno = ENOENT ;
}
fail :
saved_errno = errno ;
TALLOC_FREE ( converted ) ;
TALLOC_FREE ( insert ) ;
TALLOC_FREE ( slashes ) ;
TALLOC_FREE ( path ) ;
errno = saved_errno ;
return result ;
2008-01-16 12:21:38 +03:00
}
/*
modify a sbuf return to ensure that inodes in the shadow directory
are different from those in the main directory
*/
2011-06-20 11:52:21 +04:00
static void convert_sbuf ( vfs_handle_struct * handle , const char * fname ,
SMB_STRUCT_STAT * sbuf )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
if ( lp_parm_bool ( SNUM ( handle - > conn ) , " shadow " , " fixinodes " , False ) ) {
2008-01-16 12:21:38 +03:00
/* some snapshot systems, like GPFS, return the name
device : inode for the snapshot files as the current
files . That breaks the ' restore ' button in the shadow copy
GUI , as the client gets a sharing violation .
This is a crude way of allowing both files to be
open at once . It has a slight chance of inode
number collision , but I can ' t see a better approach
without significant VFS changes
*/
2011-06-20 11:52:21 +04:00
uint32_t shash ;
2011-08-31 08:26:40 +04:00
shash = hash ( fname , strlen ( fname ) , 0 ) & 0xFF000000 ;
2008-01-16 12:21:38 +03:00
if ( shash = = 0 ) {
shash = 1 ;
}
2009-05-14 17:34:42 +04:00
sbuf - > st_ex_ino ^ = shash ;
2008-01-16 12:21:38 +03:00
}
}
2012-03-28 06:22:03 +04:00
static DIR * shadow_copy2_opendir ( vfs_handle_struct * handle ,
2011-06-20 11:52:21 +04:00
const char * fname ,
const char * mask ,
uint32 attr )
{
time_t timestamp ;
char * stripped ;
2012-03-28 06:22:03 +04:00
DIR * ret ;
2011-06-20 11:52:21 +04:00
int saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return NULL ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_OPENDIR ( handle , fname , mask , attr ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return NULL ;
}
ret = SMB_VFS_NEXT_OPENDIR ( handle , conv , mask , attr ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
}
2008-01-16 12:21:38 +03:00
static int shadow_copy2_rename ( vfs_handle_struct * handle ,
2009-07-01 04:04:38 +04:00
const struct smb_filename * smb_fname_src ,
const struct smb_filename * smb_fname_dst )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp_src , timestamp_dst ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle ,
smb_fname_src - > base_name ,
& timestamp_src , NULL ) ) {
return - 1 ;
}
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle ,
smb_fname_dst - > base_name ,
& timestamp_dst , NULL ) ) {
return - 1 ;
}
if ( timestamp_src ! = 0 ) {
2010-12-16 14:26:02 +03:00
errno = EXDEV ;
return - 1 ;
}
2011-06-20 11:52:21 +04:00
if ( timestamp_dst ! = 0 ) {
errno = EROFS ;
return - 1 ;
}
return SMB_VFS_NEXT_RENAME ( handle , smb_fname_src , smb_fname_dst ) ;
2008-01-16 12:21:38 +03:00
}
static int shadow_copy2_symlink ( vfs_handle_struct * handle ,
const char * oldname , const char * newname )
{
2011-06-20 11:52:21 +04:00
time_t timestamp_old , timestamp_new ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , oldname ,
& timestamp_old , NULL ) ) {
return - 1 ;
}
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , newname ,
& timestamp_new , NULL ) ) {
return - 1 ;
}
if ( ( timestamp_old ! = 0 ) | | ( timestamp_new ! = 0 ) ) {
errno = EROFS ;
return - 1 ;
}
return SMB_VFS_NEXT_SYMLINK ( handle , oldname , newname ) ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_link ( vfs_handle_struct * handle ,
const char * oldname , const char * newname )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp_old , timestamp_new ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , oldname ,
& timestamp_old , NULL ) ) {
return - 1 ;
}
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , newname ,
& timestamp_new , NULL ) ) {
return - 1 ;
}
if ( ( timestamp_old ! = 0 ) | | ( timestamp_new ! = 0 ) ) {
errno = EROFS ;
return - 1 ;
}
return SMB_VFS_NEXT_LINK ( handle , oldname , newname ) ;
2008-01-16 12:21:38 +03:00
}
static int shadow_copy2_stat ( vfs_handle_struct * handle ,
2009-06-23 02:26:56 +04:00
struct smb_filename * smb_fname )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
char * stripped , * tmp ;
int ret , saved_errno ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle ,
smb_fname - > base_name ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_STAT ( handle , smb_fname ) ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
tmp = smb_fname - > base_name ;
smb_fname - > base_name = shadow_copy2_convert (
talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
2009-07-02 20:27:44 +04:00
2011-06-20 11:52:21 +04:00
if ( smb_fname - > base_name = = NULL ) {
smb_fname - > base_name = tmp ;
2009-07-02 20:27:44 +04:00
return - 1 ;
}
2011-06-20 11:52:21 +04:00
ret = SMB_VFS_NEXT_STAT ( handle , smb_fname ) ;
saved_errno = errno ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
TALLOC_FREE ( smb_fname - > base_name ) ;
smb_fname - > base_name = tmp ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
if ( ret = = 0 ) {
convert_sbuf ( handle , smb_fname - > base_name , & smb_fname - > st ) ;
}
errno = saved_errno ;
return ret ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_lstat ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
char * stripped , * tmp ;
int ret , saved_errno ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle ,
smb_fname - > base_name ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_LSTAT ( handle , smb_fname ) ;
}
2009-07-03 00:39:20 +04:00
2011-06-20 11:52:21 +04:00
tmp = smb_fname - > base_name ;
smb_fname - > base_name = shadow_copy2_convert (
talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( smb_fname - > base_name = = NULL ) {
smb_fname - > base_name = tmp ;
2009-07-03 00:39:20 +04:00
return - 1 ;
}
2011-06-20 11:52:21 +04:00
ret = SMB_VFS_NEXT_LSTAT ( handle , smb_fname ) ;
saved_errno = errno ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
TALLOC_FREE ( smb_fname - > base_name ) ;
smb_fname - > base_name = tmp ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
if ( ret = = 0 ) {
convert_sbuf ( handle , smb_fname - > base_name , & smb_fname - > st ) ;
}
errno = saved_errno ;
return ret ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_fstat ( vfs_handle_struct * handle , files_struct * fsp ,
SMB_STRUCT_STAT * sbuf )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
int ret ;
2009-09-16 05:22:56 +04:00
2011-06-20 11:52:21 +04:00
ret = SMB_VFS_NEXT_FSTAT ( handle , fsp , sbuf ) ;
if ( ret = = - 1 ) {
return ret ;
}
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle ,
fsp - > fsp_name - > base_name ,
& timestamp , NULL ) ) {
return 0 ;
2009-06-30 16:26:32 +04:00
}
2011-06-20 11:52:21 +04:00
if ( timestamp ! = 0 ) {
convert_sbuf ( handle , fsp - > fsp_name - > base_name , sbuf ) ;
}
return 0 ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_open ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname , files_struct * fsp ,
int flags , mode_t mode )
2009-02-02 13:52:08 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
char * stripped , * tmp ;
int ret , saved_errno ;
2009-02-02 13:52:08 +03:00
2011-06-20 11:52:21 +04:00
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle ,
smb_fname - > base_name ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_OPEN ( handle , smb_fname , fsp , flags , mode ) ;
2009-02-02 13:52:08 +03:00
}
2011-06-20 11:52:21 +04:00
tmp = smb_fname - > base_name ;
smb_fname - > base_name = shadow_copy2_convert (
talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
2011-03-14 20:35:36 +03:00
2011-06-20 11:52:21 +04:00
if ( smb_fname - > base_name = = NULL ) {
smb_fname - > base_name = tmp ;
return - 1 ;
2009-09-16 05:22:56 +04:00
}
2011-06-20 11:52:21 +04:00
ret = SMB_VFS_NEXT_OPEN ( handle , smb_fname , fsp , flags , mode ) ;
saved_errno = errno ;
2009-02-02 13:52:08 +03:00
2011-06-20 11:52:21 +04:00
TALLOC_FREE ( smb_fname - > base_name ) ;
smb_fname - > base_name = tmp ;
2009-02-02 13:52:08 +03:00
2011-06-20 11:52:21 +04:00
errno = saved_errno ;
2009-02-02 13:52:08 +03:00
return ret ;
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_unlink ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
char * stripped ;
int ret , saved_errno ;
struct smb_filename * conv ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle ,
smb_fname - > base_name ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
}
2013-04-11 17:32:39 +04:00
conv = cp_smb_filename ( talloc_tos ( ) , smb_fname ) ;
if ( conv = = NULL ) {
2011-06-20 11:52:21 +04:00
errno = ENOMEM ;
return - 1 ;
}
conv - > base_name = shadow_copy2_convert (
conv , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv - > base_name = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_UNLINK ( handle , conv ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_chmod ( vfs_handle_struct * handle , const char * fname ,
mode_t mode )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
char * stripped ;
int ret , saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_CHMOD ( handle , fname , mode ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_CHMOD ( handle , conv , mode ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_chown ( vfs_handle_struct * handle , const char * fname ,
uid_t uid , gid_t gid )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
char * stripped ;
int ret , saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_CHOWN ( handle , fname , uid , gid ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_CHOWN ( handle , conv , uid , gid ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_chdir ( vfs_handle_struct * handle ,
const char * fname )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
char * stripped ;
int ret , saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_CHDIR ( handle , fname ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_CHDIR ( handle , conv ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_ntimes ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname ,
struct smb_file_time * ft )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
char * stripped ;
int ret , saved_errno ;
struct smb_filename * conv ;
NTSTATUS status ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle ,
smb_fname - > base_name ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_NTIMES ( handle , smb_fname , ft ) ;
}
status = copy_smb_filename ( talloc_tos ( ) , smb_fname , & conv ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = ENOMEM ;
return - 1 ;
}
conv - > base_name = shadow_copy2_convert (
conv , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv - > base_name = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_NTIMES ( handle , conv , ft ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_readlink ( vfs_handle_struct * handle ,
const char * fname , char * buf , size_t bufsiz )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
char * stripped ;
int ret , saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_READLINK ( handle , fname , buf , bufsiz ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_READLINK ( handle , conv , buf , bufsiz ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_mknod ( vfs_handle_struct * handle ,
const char * fname , mode_t mode , SMB_DEV_T dev )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
char * stripped ;
int ret , saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_MKNOD ( handle , fname , mode , dev ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_MKNOD ( handle , conv , mode , dev ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static char * shadow_copy2_realpath ( vfs_handle_struct * handle ,
const char * fname )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
char * stripped = NULL ;
char * tmp = NULL ;
char * result = NULL ;
char * inserted = NULL ;
char * inserted_to , * inserted_end ;
int saved_errno ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
goto done ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_REALPATH ( handle , fname ) ;
}
tmp = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
if ( tmp = = NULL ) {
goto done ;
}
result = SMB_VFS_NEXT_REALPATH ( handle , tmp ) ;
if ( result = = NULL ) {
goto done ;
}
/*
* Take away what we ' ve inserted . This removes the @ GMT - thingy
* completely , but will give a path under the share root .
*/
inserted = shadow_copy2_insert_string ( talloc_tos ( ) , handle , timestamp ) ;
if ( inserted = = NULL ) {
goto done ;
}
inserted_to = strstr_m ( result , inserted ) ;
if ( inserted_to = = NULL ) {
DEBUG ( 2 , ( " SMB_VFS_NEXT_REALPATH removed %s \n " , inserted ) ) ;
goto done ;
}
inserted_end = inserted_to + talloc_get_size ( inserted ) - 1 ;
memmove ( inserted_to , inserted_end , strlen ( inserted_end ) + 1 ) ;
done :
saved_errno = errno ;
TALLOC_FREE ( inserted ) ;
TALLOC_FREE ( tmp ) ;
TALLOC_FREE ( stripped ) ;
errno = saved_errno ;
return result ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static char * have_snapdir ( struct vfs_handle_struct * handle ,
const char * path )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
struct smb_filename smb_fname ;
int ret ;
ZERO_STRUCT ( smb_fname ) ;
smb_fname . base_name = talloc_asprintf (
talloc_tos ( ) , " %s/%s " , path ,
lp_parm_const_string ( SNUM ( handle - > conn ) , " shadow " , " snapdir " ,
" .snapshots " ) ) ;
if ( smb_fname . base_name = = NULL ) {
return NULL ;
}
ret = SMB_VFS_NEXT_STAT ( handle , & smb_fname ) ;
if ( ( ret = = 0 ) & & ( S_ISDIR ( smb_fname . st . st_ex_mode ) ) ) {
return smb_fname . base_name ;
}
TALLOC_FREE ( smb_fname . base_name ) ;
return NULL ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
static char * shadow_copy2_find_snapdir ( TALLOC_CTX * mem_ctx ,
struct vfs_handle_struct * handle ,
struct smb_filename * smb_fname )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
char * path , * p ;
char * snapdir ;
path = talloc_asprintf ( mem_ctx , " %s/%s " ,
handle - > conn - > connectpath ,
smb_fname - > base_name ) ;
if ( path = = NULL ) {
return NULL ;
}
snapdir = have_snapdir ( handle , path ) ;
if ( snapdir ! = NULL ) {
TALLOC_FREE ( path ) ;
return snapdir ;
}
while ( ( p = strrchr ( path , ' / ' ) ) & & ( p > path ) ) {
p [ 0 ] = ' \0 ' ;
snapdir = have_snapdir ( handle , path ) ;
if ( snapdir ! = NULL ) {
TALLOC_FREE ( path ) ;
return snapdir ;
}
}
TALLOC_FREE ( path ) ;
return NULL ;
2008-01-16 12:21:38 +03:00
}
2012-05-08 11:15:12 +04:00
static bool shadow_copy2_snapshot_to_gmt ( vfs_handle_struct * handle ,
2011-06-20 11:52:21 +04:00
const char * name ,
char * gmt , size_t gmt_len )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
struct tm timestamp ;
time_t timestamp_t ;
2012-07-02 13:31:58 +04:00
unsigned long int timestamp_long ;
2011-06-20 11:52:21 +04:00
const char * fmt ;
fmt = lp_parm_const_string ( SNUM ( handle - > conn ) , " shadow " ,
" format " , GMT_FORMAT ) ;
ZERO_STRUCT ( timestamp ) ;
2012-07-02 13:31:58 +04:00
if ( lp_parm_bool ( SNUM ( handle - > conn ) , " shadow " , " sscanf " , false ) ) {
if ( sscanf ( name , fmt , & timestamp_long ) ! = 1 ) {
DEBUG ( 10 , ( " shadow_copy2_snapshot_to_gmt: no sscanf match %s: %s \n " ,
fmt , name ) ) ;
return false ;
}
timestamp_t = timestamp_long ;
2011-06-20 11:52:21 +04:00
gmtime_r ( & timestamp_t , & timestamp ) ;
2012-07-02 13:31:58 +04:00
} else {
if ( strptime ( name , fmt , & timestamp ) = = NULL ) {
DEBUG ( 10 , ( " shadow_copy2_snapshot_to_gmt: no match %s: %s \n " ,
fmt , name ) ) ;
return false ;
}
DEBUG ( 10 , ( " shadow_copy2_snapshot_to_gmt: match %s: %s \n " , fmt , name ) ) ;
if ( lp_parm_bool ( SNUM ( handle - > conn ) , " shadow " , " localtime " , false ) ) {
timestamp . tm_isdst = - 1 ;
timestamp_t = mktime ( & timestamp ) ;
gmtime_r ( & timestamp_t , & timestamp ) ;
}
2011-06-20 11:52:21 +04:00
}
2012-07-02 13:31:58 +04:00
2011-06-20 11:52:21 +04:00
strftime ( gmt , gmt_len , GMT_FORMAT , & timestamp ) ;
return true ;
2008-01-16 12:21:38 +03:00
}
2009-12-07 06:00:00 +03:00
static int shadow_copy2_label_cmp_asc ( const void * x , const void * y )
{
2011-05-06 03:19:49 +04:00
return strncmp ( ( const char * ) x , ( const char * ) y , sizeof ( SHADOW_COPY_LABEL ) ) ;
2009-12-07 06:00:00 +03:00
}
static int shadow_copy2_label_cmp_desc ( const void * x , const void * y )
{
2011-05-06 03:19:49 +04:00
return - strncmp ( ( const char * ) x , ( const char * ) y , sizeof ( SHADOW_COPY_LABEL ) ) ;
2009-12-07 06:00:00 +03:00
}
/*
sort the shadow copy data in ascending or descending order
*/
static void shadow_copy2_sort_data ( vfs_handle_struct * handle ,
2011-05-30 14:06:31 +04:00
struct shadow_copy_data * shadow_copy2_data )
2009-12-07 06:00:00 +03:00
{
int ( * cmpfunc ) ( const void * , const void * ) ;
const char * sort ;
sort = lp_parm_const_string ( SNUM ( handle - > conn ) , " shadow " ,
2012-05-08 11:11:36 +04:00
" sort " , " desc " ) ;
2009-12-07 06:00:00 +03:00
if ( sort = = NULL ) {
return ;
}
if ( strcmp ( sort , " asc " ) = = 0 ) {
cmpfunc = shadow_copy2_label_cmp_asc ;
} else if ( strcmp ( sort , " desc " ) = = 0 ) {
cmpfunc = shadow_copy2_label_cmp_desc ;
} else {
return ;
}
if ( shadow_copy2_data & & shadow_copy2_data - > num_volumes > 0 & &
shadow_copy2_data - > labels )
{
2010-02-14 02:01:17 +03:00
TYPESAFE_QSORT ( shadow_copy2_data - > labels ,
shadow_copy2_data - > num_volumes ,
cmpfunc ) ;
2009-12-07 06:00:00 +03:00
}
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_get_shadow_copy_data (
vfs_handle_struct * handle , files_struct * fsp ,
struct shadow_copy_data * shadow_copy2_data ,
bool labels )
2008-01-16 12:21:38 +03:00
{
2012-03-28 06:22:03 +04:00
DIR * p ;
2008-01-16 12:21:38 +03:00
const char * snapdir ;
2012-03-28 06:18:14 +04:00
struct dirent * d ;
2011-06-20 11:52:21 +04:00
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
snapdir = shadow_copy2_find_snapdir ( tmp_ctx , handle , fsp - > fsp_name ) ;
2008-01-16 12:21:38 +03:00
if ( snapdir = = NULL ) {
DEBUG ( 0 , ( " shadow:snapdir not found for %s in get_shadow_copy_data \n " ,
handle - > conn - > connectpath ) ) ;
errno = EINVAL ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
p = SMB_VFS_NEXT_OPENDIR ( handle , snapdir , NULL , 0 ) ;
if ( ! p ) {
2009-04-28 13:16:19 +04:00
DEBUG ( 2 , ( " shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s' "
" - %s \n " , snapdir , strerror ( errno ) ) ) ;
2008-01-16 12:21:38 +03:00
talloc_free ( tmp_ctx ) ;
2009-04-28 13:16:19 +04:00
errno = ENOSYS ;
2008-01-16 12:21:38 +03:00
return - 1 ;
}
shadow_copy2_data - > num_volumes = 0 ;
shadow_copy2_data - > labels = NULL ;
2009-01-23 07:14:38 +03:00
while ( ( d = SMB_VFS_NEXT_READDIR ( handle , p , NULL ) ) ) {
2011-06-20 11:52:21 +04:00
char snapshot [ GMT_NAME_LEN + 1 ] ;
2008-01-16 12:21:38 +03:00
SHADOW_COPY_LABEL * tlabels ;
2011-06-20 11:52:21 +04:00
/*
* ignore names not of the right form in the snapshot
* directory
*/
if ( ! shadow_copy2_snapshot_to_gmt (
2012-05-08 11:15:12 +04:00
handle , d - > d_name ,
2011-06-20 11:52:21 +04:00
snapshot , sizeof ( snapshot ) ) ) {
DEBUG ( 6 , ( " shadow_copy2_get_shadow_copy_data: "
" ignoring %s \n " , d - > d_name ) ) ;
2008-01-16 12:21:38 +03:00
continue ;
}
2011-06-20 11:52:21 +04:00
DEBUG ( 6 , ( " shadow_copy2_get_shadow_copy_data: %s -> %s \n " ,
d - > d_name , snapshot ) ) ;
2008-01-16 12:21:38 +03:00
if ( ! labels ) {
/* the caller doesn't want the labels */
shadow_copy2_data - > num_volumes + + ;
continue ;
}
2011-05-30 14:11:53 +04:00
tlabels = talloc_realloc ( shadow_copy2_data ,
2008-01-16 12:21:38 +03:00
shadow_copy2_data - > labels ,
2011-06-20 11:52:21 +04:00
SHADOW_COPY_LABEL ,
shadow_copy2_data - > num_volumes + 1 ) ;
2008-01-16 12:21:38 +03:00
if ( tlabels = = NULL ) {
DEBUG ( 0 , ( " shadow_copy2: out of memory \n " ) ) ;
SMB_VFS_NEXT_CLOSEDIR ( handle , p ) ;
2010-01-21 10:30:01 +03:00
talloc_free ( tmp_ctx ) ;
2008-01-16 12:21:38 +03:00
return - 1 ;
}
2010-01-21 10:30:01 +03:00
strlcpy ( tlabels [ shadow_copy2_data - > num_volumes ] , snapshot ,
sizeof ( * tlabels ) ) ;
2008-01-16 12:21:38 +03:00
shadow_copy2_data - > num_volumes + + ;
shadow_copy2_data - > labels = tlabels ;
}
SMB_VFS_NEXT_CLOSEDIR ( handle , p ) ;
2009-12-07 06:00:00 +03:00
shadow_copy2_sort_data ( handle , shadow_copy2_data ) ;
2010-01-21 10:30:01 +03:00
talloc_free ( tmp_ctx ) ;
2008-01-16 12:21:38 +03:00
return 0 ;
}
2011-06-20 11:52:21 +04:00
static NTSTATUS shadow_copy2_fget_nt_acl ( vfs_handle_struct * handle ,
struct files_struct * fsp ,
uint32 security_info ,
2012-10-10 04:50:27 +04:00
TALLOC_CTX * mem_ctx ,
2011-06-20 11:52:21 +04:00
struct security_descriptor * * ppdesc )
{
time_t timestamp ;
char * stripped ;
NTSTATUS status ;
char * conv ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle ,
fsp - > fsp_name - > base_name ,
& timestamp , & stripped ) ) {
return map_nt_error_from_unix ( errno ) ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_FGET_NT_ACL ( handle , fsp , security_info ,
2012-10-10 04:50:27 +04:00
mem_ctx ,
2011-06-20 11:52:21 +04:00
ppdesc ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return map_nt_error_from_unix ( errno ) ;
}
2012-10-10 04:50:27 +04:00
status = SMB_VFS_NEXT_GET_NT_ACL ( handle , conv , security_info ,
mem_ctx , ppdesc ) ;
2011-06-20 11:52:21 +04:00
TALLOC_FREE ( conv ) ;
return status ;
}
static NTSTATUS shadow_copy2_get_nt_acl ( vfs_handle_struct * handle ,
const char * fname ,
uint32 security_info ,
2012-10-10 04:50:27 +04:00
TALLOC_CTX * mem_ctx ,
2011-06-20 11:52:21 +04:00
struct security_descriptor * * ppdesc )
2008-01-16 12:21:38 +03:00
{
2011-06-20 11:52:21 +04:00
time_t timestamp ;
char * stripped ;
NTSTATUS status ;
char * conv ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return map_nt_error_from_unix ( errno ) ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_GET_NT_ACL ( handle , fname , security_info ,
2012-10-10 04:50:27 +04:00
mem_ctx , ppdesc ) ;
2011-06-20 11:52:21 +04:00
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return map_nt_error_from_unix ( errno ) ;
}
2012-10-10 04:50:27 +04:00
status = SMB_VFS_NEXT_GET_NT_ACL ( handle , conv , security_info ,
mem_ctx , ppdesc ) ;
2011-06-20 11:52:21 +04:00
TALLOC_FREE ( conv ) ;
return status ;
}
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
static int shadow_copy2_mkdir ( vfs_handle_struct * handle ,
const char * fname , mode_t mode )
{
time_t timestamp ;
char * stripped ;
int ret , saved_errno ;
char * conv ;
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_MKDIR ( handle , fname , mode ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_MKDIR ( handle , conv , mode ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
}
static int shadow_copy2_rmdir ( vfs_handle_struct * handle , const char * fname )
{
time_t timestamp ;
char * stripped ;
int ret , saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_RMDIR ( handle , fname ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_RMDIR ( handle , conv ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
}
static int shadow_copy2_chflags ( vfs_handle_struct * handle , const char * fname ,
unsigned int flags )
{
time_t timestamp ;
char * stripped ;
int ret , saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_CHFLAGS ( handle , fname , flags ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_CHFLAGS ( handle , conv , flags ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
}
static ssize_t shadow_copy2_getxattr ( vfs_handle_struct * handle ,
const char * fname , const char * aname ,
void * value , size_t size )
{
time_t timestamp ;
char * stripped ;
ssize_t ret ;
int saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_GETXATTR ( handle , fname , aname , value ,
size ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_GETXATTR ( handle , conv , aname , value , size ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
}
static ssize_t shadow_copy2_listxattr ( struct vfs_handle_struct * handle ,
const char * fname ,
char * list , size_t size )
{
time_t timestamp ;
char * stripped ;
ssize_t ret ;
int saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_LISTXATTR ( handle , fname , list , size ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
2008-01-16 12:21:38 +03:00
}
2011-06-20 11:52:21 +04:00
ret = SMB_VFS_NEXT_LISTXATTR ( handle , conv , list , size ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
}
2008-01-16 12:21:38 +03:00
2011-06-20 11:52:21 +04:00
static int shadow_copy2_removexattr ( vfs_handle_struct * handle ,
const char * fname , const char * aname )
{
time_t timestamp ;
char * stripped ;
int ret , saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_REMOVEXATTR ( handle , fname , aname ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_REMOVEXATTR ( handle , conv , aname ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
2008-01-16 12:21:38 +03:00
return ret ;
}
2011-06-20 11:52:21 +04:00
static int shadow_copy2_setxattr ( struct vfs_handle_struct * handle ,
const char * fname ,
const char * aname , const void * value ,
size_t size , int flags )
{
time_t timestamp ;
char * stripped ;
ssize_t ret ;
int saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_SETXATTR ( handle , fname , aname , value , size ,
flags ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_SETXATTR ( handle , conv , aname , value , size , flags ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
}
static int shadow_copy2_chmod_acl ( vfs_handle_struct * handle ,
const char * fname , mode_t mode )
{
time_t timestamp ;
char * stripped ;
ssize_t ret ;
int saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , fname ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_CHMOD_ACL ( handle , fname , mode ) ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_CHMOD_ACL ( handle , conv , mode ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
}
static int shadow_copy2_get_real_filename ( struct vfs_handle_struct * handle ,
const char * path ,
const char * name ,
TALLOC_CTX * mem_ctx ,
char * * found_name )
{
time_t timestamp ;
char * stripped ;
ssize_t ret ;
int saved_errno ;
char * conv ;
if ( ! shadow_copy2_strip_snapshot ( talloc_tos ( ) , handle , path ,
& timestamp , & stripped ) ) {
return - 1 ;
}
if ( timestamp = = 0 ) {
return SMB_VFS_NEXT_GET_REAL_FILENAME ( handle , path , name ,
mem_ctx , found_name ) ;
}
if ( stripped [ 0 ] = = ' \0 ' ) {
* found_name = talloc_strdup ( mem_ctx , name ) ;
if ( * found_name = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
return 0 ;
}
conv = shadow_copy2_convert ( talloc_tos ( ) , handle , stripped , timestamp ) ;
TALLOC_FREE ( stripped ) ;
if ( conv = = NULL ) {
return - 1 ;
}
ret = SMB_VFS_NEXT_GET_REAL_FILENAME ( handle , conv , name ,
mem_ctx , found_name ) ;
saved_errno = errno ;
TALLOC_FREE ( conv ) ;
errno = saved_errno ;
return ret ;
}
static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
2011-12-04 08:45:04 +04:00
. opendir_fn = shadow_copy2_opendir ,
. rename_fn = shadow_copy2_rename ,
. link_fn = shadow_copy2_link ,
. symlink_fn = shadow_copy2_symlink ,
. stat_fn = shadow_copy2_stat ,
. lstat_fn = shadow_copy2_lstat ,
. fstat_fn = shadow_copy2_fstat ,
2011-06-20 11:52:21 +04:00
. open_fn = shadow_copy2_open ,
2011-12-04 08:45:04 +04:00
. unlink_fn = shadow_copy2_unlink ,
. chmod_fn = shadow_copy2_chmod ,
. chown_fn = shadow_copy2_chown ,
. chdir_fn = shadow_copy2_chdir ,
. ntimes_fn = shadow_copy2_ntimes ,
. readlink_fn = shadow_copy2_readlink ,
. mknod_fn = shadow_copy2_mknod ,
. realpath_fn = shadow_copy2_realpath ,
. get_nt_acl_fn = shadow_copy2_get_nt_acl ,
. fget_nt_acl_fn = shadow_copy2_fget_nt_acl ,
. get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data ,
. mkdir_fn = shadow_copy2_mkdir ,
. rmdir_fn = shadow_copy2_rmdir ,
. getxattr_fn = shadow_copy2_getxattr ,
. listxattr_fn = shadow_copy2_listxattr ,
. removexattr_fn = shadow_copy2_removexattr ,
. setxattr_fn = shadow_copy2_setxattr ,
. chmod_acl_fn = shadow_copy2_chmod_acl ,
. chflags_fn = shadow_copy2_chflags ,
. get_real_filename_fn = shadow_copy2_get_real_filename ,
2011-06-20 11:52:21 +04:00
} ;
NTSTATUS vfs_shadow_copy2_init ( void ) ;
NTSTATUS vfs_shadow_copy2_init ( void )
{
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION ,
" shadow_copy2 " , & vfs_shadow_copy2_fns ) ;
}