2002-01-10 15:22:17 +03:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 Red Hat , Inc . All rights reserved .
2002-01-10 15:22:17 +03:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2002-01-10 15:22:17 +03:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2002-01-10 15:22:17 +03:00
# include "lvm-file.h"
# include "lvm-string.h"
# include <unistd.h>
# include <sys/stat.h>
# include <sys/file.h>
# include <fcntl.h>
2002-03-12 01:23:24 +03:00
# include <dirent.h>
2002-01-10 15:22:17 +03:00
/*
* Creates a temporary filename , and opens a descriptor to the
* file . Both the filename and descriptor are needed so we can
* rename the file after successfully writing it . Grab
* NFS - supported exclusive fcntl discretionary lock .
*/
2002-03-12 01:23:24 +03:00
int create_temp_name ( const char * dir , char * buffer , size_t len , int * fd )
2002-01-10 15:22:17 +03:00
{
int i , num ;
pid_t pid ;
char hostname [ 255 ] ;
struct flock lock = {
2002-03-12 01:23:24 +03:00
l_type : F_WRLCK ,
l_whence : 0 ,
l_start : 0 ,
l_len : 0
2002-01-10 15:22:17 +03:00
} ;
num = rand ( ) ;
pid = getpid ( ) ;
if ( gethostname ( hostname , sizeof ( hostname ) ) < 0 ) {
log_sys_error ( " gethostname " , " " ) ;
strcpy ( hostname , " nohostname " ) ;
}
for ( i = 0 ; i < 20 ; i + + , num + + ) {
if ( lvm_snprintf ( buffer , len , " %s/.lvm_%s_%d_%d " ,
dir , hostname , pid , num ) = = - 1 ) {
log_err ( " Not enough space to build temporary file "
" string. " ) ;
return 0 ;
}
* fd = open ( buffer , O_CREAT | O_EXCL | O_WRONLY | O_APPEND ,
S_IRUSR | S_IRGRP | S_IROTH |
S_IWUSR | S_IWGRP | S_IWOTH ) ;
if ( * fd < 0 )
continue ;
if ( ! fcntl ( * fd , F_SETLK , & lock ) )
return 1 ;
close ( * fd ) ;
}
return 0 ;
}
/*
* NFS - safe rename of a temporary file to a common name , designed
* to avoid race conditions and not overwrite the destination if
* it exists .
*
* Try to create the new filename as a hard link to the original .
* Check the link count of the original file to see if it worked .
* ( Assumes nothing else touches our temporary file ! ) If it
* worked , unlink the old filename .
*/
int lvm_rename ( const char * old , const char * new )
{
struct stat buf ;
link ( old , new ) ;
if ( stat ( old , & buf ) ) {
log_sys_error ( " stat " , old ) ;
return 0 ;
}
if ( buf . st_nlink ! = 2 ) {
log_error ( " %s: rename to %s failed " , old , new ) ;
return 0 ;
}
if ( unlink ( old ) ) {
log_sys_error ( " unlink " , old ) ;
return 0 ;
}
return 1 ;
}
2002-02-11 18:42:34 +03:00
int path_exists ( const char * path )
{
struct stat info ;
if ( ! * path )
return 0 ;
if ( stat ( path , & info ) < 0 )
return 0 ;
return 1 ;
}
int dir_exists ( const char * path )
{
struct stat info ;
if ( ! * path )
return 0 ;
if ( stat ( path , & info ) < 0 )
return 0 ;
if ( ! S_ISDIR ( info . st_mode ) )
return 0 ;
return 1 ;
}
2002-05-19 07:46:34 +04:00
static int _create_dir_recursive ( const char * dir )
{
char * orig , * s ;
int rc ;
2002-05-31 23:28:37 +04:00
log_verbose ( " Creating directory \" %s \" " , dir ) ;
/* Create parent directories */
2002-05-19 07:46:34 +04:00
orig = s = dbg_strdup ( dir ) ;
while ( ( s = strchr ( s , ' / ' ) ) ! = NULL ) {
* s = ' \0 ' ;
if ( * orig ) {
rc = mkdir ( orig , 0777 ) ;
if ( rc < 0 & & errno ! = EEXIST ) {
log_sys_error ( " mkdir " , orig ) ;
dbg_free ( orig ) ;
return 0 ;
}
}
* s + + = ' / ' ;
}
dbg_free ( orig ) ;
2002-05-31 23:28:37 +04:00
/* Create final directory */
2002-05-19 07:46:34 +04:00
rc = mkdir ( dir , 0777 ) ;
if ( rc < 0 & & errno ! = EEXIST ) {
log_sys_error ( " mkdir " , dir ) ;
return 0 ;
}
return 1 ;
}
2002-02-11 18:42:34 +03:00
int create_dir ( const char * dir )
{
struct stat info ;
if ( ! * dir )
return 1 ;
2002-05-19 07:46:34 +04:00
if ( stat ( dir , & info ) < 0 )
return _create_dir_recursive ( dir ) ;
2002-02-11 18:42:34 +03:00
if ( S_ISDIR ( info . st_mode ) )
return 1 ;
log_error ( " Directory \" %s \" not found " , dir ) ;
return 0 ;
}
2002-03-12 01:23:24 +03:00
int is_empty_dir ( const char * dir )
{
struct dirent * dirent ;
DIR * d ;
if ( ! ( d = opendir ( dir ) ) ) {
log_sys_error ( " opendir " , dir ) ;
return 0 ;
}
while ( ( dirent = readdir ( d ) ) )
if ( strcmp ( dirent - > d_name , " . " ) & & strcmp ( dirent - > d_name , " .. " ) )
break ;
if ( closedir ( d ) ) {
log_sys_error ( " closedir " , dir ) ;
}
return dirent ? 0 : 1 ;
}
2002-12-06 01:51:15 +03:00
void sync_dir ( const char * file )
{
int fd ;
char * dir , * c ;
if ( ! ( dir = dbg_strdup ( file ) ) ) {
log_error ( " sync_dir failed in strdup " ) ;
return ;
}
if ( ! dir_exists ( dir ) ) {
c = dir + strlen ( dir ) ;
while ( * c ! = ' / ' & & c > dir )
c - - ;
* c = ' \0 ' ;
}
if ( ( fd = open ( dir , O_RDONLY ) ) = = - 1 ) {
log_sys_error ( " open " , dir ) ;
goto out ;
}
if ( fsync ( fd ) = = - 1 )
log_sys_error ( " fsync " , dir ) ;
close ( fd ) ;
out :
dbg_free ( dir ) ;
}