RetroShare/libretroshare/src/util/rsdir.cc
Gio c3aca0cf26 Implement a working Distant Chat prototype in Qml
Deprecate id field in JSON API as it may cause problems in Qml
Offer gxs_id field in JSON API as an id alternative
LibresapiLocalClient support callbacks now an instance may be shared for
  different tasks
Expose an instance of LibresapiLocalClient to Qml, type exposure is kept
  for retrocompatibility but deprecated
Qml app now has a tab that permit to exchange some message with selected
  distant peer
2016-12-08 15:56:23 +01:00

1279 lines
29 KiB
C++

/*
* "$Id: rsdir.cc,v 1.1 2007-02-19 20:08:30 rmf24 Exp $"
*
* RetroShare C++ Interface.
*
* Copyright 2004-2007 by Robert Fernie.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* Please report all bugs and problems to "retroshare@lunamutt.com".
*
*/
// Includes for directory creation.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "util/rsdir.h"
#include "util/rsstring.h"
#include "util/rsrandom.h"
#include "util/rsmemory.h"
#include "util/folderiterator.h"
#include "retroshare/rstypes.h"
#include "retroshare/rsnotify.h"
#include "rsthreads.h"
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <dirent.h>
#include <openssl/sha.h>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <stdexcept>
#if defined(WIN32) || defined(__CYGWIN__)
#include "util/rsstring.h"
#include "wtypes.h"
#include <winioctl.h>
#else
#include <errno.h>
#endif
/****
* #define RSDIR_DEBUG 1
****/
std::string RsDirUtil::getTopDir(const std::string& dir)
{
std::string top;
/* find the subdir: [/][dir1.../]<top>[/]
*/
int i,j;
int len = dir.length();
for(j = len - 1; (j > 0) && (dir[j] == '/'); j--) ;
for(i = j; (i > 0) && (dir[i] != '/'); i--) ;
if (dir[i] == '/')
i++;
for(; i <= j; i++)
{
top += dir[i];
}
return top;
}
const char *RsDirUtil::scanf_string_for_uint(int bytes)
{
const char *strgs[3] = { "%u","%lu","%llu" } ;
//std::cerr << "RsDirUtil::scanf_string_for_uint(): returning for bytes=" << bytes << std::endl;
if(sizeof(unsigned int) == bytes)
return strgs[0] ;
if(sizeof(long unsigned int) == bytes)
return strgs[1] ;
if(sizeof(long long unsigned int) == bytes)
return strgs[2] ;
std::cerr << "RsDirUtil::scanf_string_for_uint(): no corresponding scan string for "<< bytes << " bytes. This will probably cause inconsistencies." << std::endl;
return strgs[0] ;
}
void RsDirUtil::removeTopDir(const std::string& dir, std::string& path)
{
path.clear();
/* remove the subdir: [/][dir1.../]<top>[/]
*/
int j = dir.find_last_not_of('/');
int i = dir.rfind('/', j);
/* remove any more slashes */
if (i > 0)
{
i = dir.find_last_not_of('/', i);
}
if (i > 0)
{
path.assign(dir, 0, i + 1);
}
}
std::string RsDirUtil::getRootDir(const std::string& dir)
{
std::string root;
/* find the subdir: [/]root[/...]
*/
int i,j;
int len = dir.length();
for(i = 0; (i < len) && (dir[i] == '/'); i++) ;
for(j = i; (j < len) && (dir[j] != '/'); j++) ;
if (i == j)
return root; /* empty */
for(; i < j; i++)
{
root += dir[i];
}
return root;
}
std::string RsDirUtil::removeRootDir(const std::string& path)
{
unsigned int i, j;
unsigned int len = path.length();
std::string output;
/* chew leading '/'s */
for(i = 0; (i < len) && (path[i] == '/'); i++) ;
if (i == len)
return output; /* empty string */
for(j = i; (j < len) && (path[j] != '/'); j++) ; /* run to next '/' */
for(; (j < len) && (path[j] == '/'); j++) ; /* chew leading '/'s */
for(; j < len; j++)
{
output += path[j];
}
return output;
}
std::string RsDirUtil::removeRootDirs(const std::string& path, const std::string& root)
{
/* too tired */
std::string notroot;
unsigned int i = 0, j = 0;
/* catch empty data */
if ((root.length() < 1) || (path.length() < 1))
return notroot;
if ((path[0] == '/') && (root[0] != '/'))
{
i++;
}
for(; (i < path.length()) && (j < root.length()) && (path[i] == root[j]); i++, j++) ;
/* should have consumed root. */
if (j == root.length())
{
//std::cerr << "matched root!" << std::endl;
}
else
{
//std::cerr << "failed i: " << i << ", j: " << j << std::endl;
//std::cerr << "root: " << root << " path: " << path << std::endl;
return notroot;
}
if (path[i] == '/')
{
i++;
}
for(; i < path.length(); i++)
{
notroot += path[i];
}
//std::cerr << "Found NotRoot: " << notroot << std::endl;
return notroot;
}
int RsDirUtil::breakupDirList(const std::string& path,
std::list<std::string> &subdirs)
{
int start = 0;
unsigned int i;
for(i = 0; i < path.length(); i++)
{
if (path[i] == '/')
{
if (i - start > 0)
{
subdirs.push_back(path.substr(start, i-start));
}
start = i+1;
}
}
// get the final one.
if (i - start > 0)
{
subdirs.push_back(path.substr(start, i-start));
}
return 1;
}
/**** Copied and Tweaked from ftcontroller ***/
bool RsDirUtil::fileExists(const std::string& filename)
{
return ( access( filename.c_str(), F_OK ) != -1 );
}
bool RsDirUtil::moveFile(const std::string& source,const std::string& dest)
{
// First try a rename
//
if(renameFile(source,dest))
return true ;
// If not, try to copy. The src and dest probably belong to different file systems
if(!copyFile(source,dest))
return false ;
// copy was successful, let's delete the original
if(!removeFile(source))
return false ;
return true ;
}
bool RsDirUtil::removeFile(const std::string& filename)
{
#ifdef CONTROL_DEBUG
std::cerr << "deleting original file " << source << std::endl ;
#endif
#ifdef WINDOWS_SYS
std::wstring filenameW;
librs::util::ConvertUtf8ToUtf16(filename,filenameW);
if(0 != DeleteFileW(filenameW.c_str()))
#else
if(0 == remove(filename.c_str()))
#endif
return true ;
else
{
std::cerr << "(EE) File erase error while removing file " << filename << ". Read-only file system ?" << std::endl;
return false ;
}
}
/**** Copied and Tweaked from ftcontroller ***/
bool RsDirUtil::copyFile(const std::string& source,const std::string& dest)
{
#ifdef WINDOWS_SYS
std::wstring sourceW;
std::wstring destW;
librs::util::ConvertUtf8ToUtf16(source,sourceW);
librs::util::ConvertUtf8ToUtf16(dest,destW);
return (CopyFileW(sourceW.c_str(), destW.c_str(), FALSE) != 0);
#else
FILE *in = fopen64(source.c_str(),"rb") ;
if(in == NULL)
{
return false ;
}
FILE *out = fopen64(dest.c_str(),"wb") ;
if(out == NULL)
{
fclose (in);
return false ;
}
size_t s=0;
size_t T=0;
static const int BUFF_SIZE = 10485760 ; // 10 MB buffer to speed things up.
RsTemporaryMemory buffer(BUFF_SIZE) ;
if(!buffer)
{
fclose(in) ;
fclose(out) ;
return false ;
}
bool bRet = true;
while( (s = fread(buffer,1,BUFF_SIZE,in)) > 0)
{
size_t t = fwrite(buffer,1,s,out) ;
T += t ;
if(t != s)
{
bRet = false ;
break;
}
}
fclose(in) ;
fclose(out) ;
return bRet ;
#endif
}
bool RsDirUtil::checkFile(const std::string& filename,uint64_t& file_size,bool disallow_empty_file)
{
int val;
mode_t st_mode;
#ifdef WINDOWS_SYS
std::wstring wfilename;
librs::util::ConvertUtf8ToUtf16(filename, wfilename);
struct _stat buf;
val = _wstat(wfilename.c_str(), &buf);
st_mode = buf.st_mode;
#else
struct stat64 buf;
val = stat64(filename.c_str(), &buf);
st_mode = buf.st_mode;
#endif
if (val == -1)
{
#ifdef RSDIR_DEBUG
std::cerr << "RsDirUtil::checkFile() ";
std::cerr << filename << " doesn't exist" << std::endl;
#endif
return false;
}
else if (!S_ISREG(st_mode))
{
// Some other type - error.
#ifdef RSDIR_DEBUG
std::cerr << "RsDirUtil::checkFile() ";
std::cerr << filename << " is not a Regular File" << std::endl;
#endif
return false;
}
file_size = buf.st_size ;
if(disallow_empty_file && buf.st_size == 0)
return false ;
return true;
}
bool RsDirUtil::checkDirectory(const std::string& dir)
{
int val;
mode_t st_mode;
#ifdef WINDOWS_SYS
std::wstring wdir;
librs::util::ConvertUtf8ToUtf16(dir, wdir);
struct _stat buf;
val = _wstat(wdir.c_str(), &buf);
st_mode = buf.st_mode;
#else
struct stat buf;
val = stat(dir.c_str(), &buf);
st_mode = buf.st_mode;
#endif
if (val == -1)
{
#ifdef RSDIR_DEBUG
std::cerr << "RsDirUtil::checkDirectory() ";
std::cerr << dir << " doesn't exist" << std::endl;
#endif
return false;
}
else if (!S_ISDIR(st_mode))
{
// Some other type - error.
#ifdef RSDIR_DEBUG
std::cerr << "RsDirUtil::checkDirectory() ";
std::cerr << dir << " is not Directory" << std::endl;
#endif
return false;
}
return true;
}
bool RsDirUtil::checkCreateDirectory(const std::string& dir)
{
#ifdef RSDIR_DEBUG
std::cerr << "RsDirUtil::checkCreateDirectory() dir: " << dir << std::endl;
#endif
#ifdef WINDOWS_SYS
std::wstring wdir;
librs::util::ConvertUtf8ToUtf16(dir, wdir);
_WDIR *direc = _wopendir(wdir.c_str());
if (!direc)
#else
DIR *direc = opendir(dir.c_str());
if (!direc)
#endif
{
// directory don't exist. create.
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
#ifndef WINDOWS_SYS // UNIX
if (-1 == mkdir(dir.c_str(), 0777))
#else // WIN
if (-1 == _wmkdir(wdir.c_str()))
#endif
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
{
#ifdef RSDIR_DEBUG
std::cerr << "check_create_directory() Fatal Error et oui--";
std::cerr <<std::endl<< "\tcannot create:" <<dir<<std::endl;
#endif
return 0;
}
#ifdef RSDIR_DEBUG
std::cerr << "check_create_directory()";
std::cerr <<std::endl<< "\tcreated:" <<dir<<std::endl;
#endif
return 1;
}
#ifdef RSDIR_DEBUG
std::cerr << "check_create_directory()";
std::cerr <<std::endl<< "\tDir Exists:" <<dir<<std::endl;
#endif
#ifdef WINDOWS_SYS
_wclosedir(direc);
#else
closedir(direc) ;
#endif
return 1;
}
std::string RsDirUtil::removeSymLinks(const std::string& path)
{
#if defined(WINDOWS_SYS) || defined(__APPLE__) || defined(__ANDROID__)
#warning (Mr.Alice): I don't know how to do this on windows/MacOS/Android. See https://msdn.microsoft.com/en-us/library/windows/desktop/hh707084(v=vs.85).aspx'
//if(!S_OK == PathCchCanonicalizeEx(tmp,...) ;
return path ;
#else
char *tmp = canonicalize_file_name(path.c_str()) ;
std::string result(tmp) ;
free(tmp);
return result ;
#endif
}
bool RsDirUtil::cleanupDirectory(const std::string& cleandir, const std::set<std::string> &keepFiles)
{
for(librs::util::FolderIterator it(cleandir,false);it.isValid();it.next())
if(it.file_type() == librs::util::FolderIterator::TYPE_FILE && (keepFiles.end() == std::find(keepFiles.begin(), keepFiles.end(), it.file_name())))
remove( (cleandir + "/" + it.file_name()).c_str() ) ;
return true;
}
/* slightly nicer helper function */
bool RsDirUtil::hashFile(const std::string& filepath,
std::string &name, RsFileHash &hash, uint64_t &size)
{
if (getFileHash(filepath, hash, size))
{
/* extract file name */
name = RsDirUtil::getTopDir(filepath);
return true;
}
return false;
}
#include <openssl/sha.h>
#include <iomanip>
/* Function to hash, and get details of a file */
bool RsDirUtil::getFileHash(const std::string& filepath, RsFileHash &hash, uint64_t &size, RsThread *thread /*= NULL*/)
{
FILE *fd;
if (NULL == (fd = RsDirUtil::rs_fopen(filepath.c_str(), "rb")))
return false;
int len;
SHA_CTX *sha_ctx = new SHA_CTX;
unsigned char sha_buf[SHA_DIGEST_LENGTH];
unsigned char gblBuf[512];
/* determine size */
fseeko64(fd, 0, SEEK_END);
size = ftello64(fd);
fseeko64(fd, 0, SEEK_SET);
/* check if thread is running */
bool isRunning = thread ? thread->isRunning() : true;
int runningCheckCount = 0;
SHA1_Init(sha_ctx);
while(isRunning && (len = fread(gblBuf,1, 512, fd)) > 0)
{
SHA1_Update(sha_ctx, gblBuf, len);
if (thread && ++runningCheckCount > (10 * 1024)) {
/* check all 50MB if thread is running */
isRunning = thread->isRunning();
runningCheckCount = 0;
}
}
/* Thread has ended */
if (isRunning == false)
{
delete sha_ctx;
fclose(fd);
return false;
}
/* reading failed for some reason */
if (ferror(fd))
{
delete sha_ctx;
fclose(fd);
return false;
}
SHA1_Final(&sha_buf[0], sha_ctx);
hash = Sha1CheckSum(sha_buf);
delete sha_ctx;
fclose(fd);
return true;
}
/* Function to hash, and get details of a file */
Sha1CheckSum RsDirUtil::sha1sum(const unsigned char *data, uint32_t size)
{
SHA_CTX sha_ctx ;
if(SHA_DIGEST_LENGTH != 20)
throw std::runtime_error("Warning: can't compute Sha1Sum with sum size != 20") ;
SHA1_Init(&sha_ctx);
while(size > 512)
{
SHA1_Update(&sha_ctx, data, 512);
data = &data[512] ;
size -= 512 ;
}
SHA1_Update(&sha_ctx, data, size);
unsigned char sha_buf[SHA_DIGEST_LENGTH];
SHA1_Final(&sha_buf[0], &sha_ctx);
return Sha1CheckSum(sha_buf) ;
}
bool RsDirUtil::saveStringToFile(const std::string &file, const std::string &str)
{
std::ofstream out(file.c_str(), std::ios_base::out | std::ios_base::binary);
if(!out.is_open())
{
std::cerr << "RsDirUtil::saveStringToFile() ERROR: can't open file " << file << std::endl;
return false;
}
out << str;
return true;
}
bool RsDirUtil::loadStringFromFile(const std::string &file, std::string &str)
{
std::ifstream in(file.c_str(), std::ios_base::in | std::ios_base::binary);
if(!in.is_open())
{
std::cerr << "RsDirUtil::loadStringFromFile() ERROR: can't open file " << file << std::endl;
return false;
}
std::stringstream buffer;
buffer << in.rdbuf();
str = buffer.str();
return true;
}
bool RsDirUtil::renameFile(const std::string& from, const std::string& to)
{
int loops = 0;
#ifdef WINDOWS_SYS
std::wstring f;
librs::util::ConvertUtf8ToUtf16(from, f);
std::wstring t;
librs::util::ConvertUtf8ToUtf16(to, t);
while (!MoveFileEx(f.c_str(), t.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH))
#else
std::string f(from),t(to) ;
while (rename(from.c_str(), to.c_str()) < 0)
#endif
{
#ifdef WIN32
if (GetLastError() != ERROR_ACCESS_DENIED)
#else
if (errno != EACCES)
#endif
/* set errno? */
return false ;
usleep(100 * 1000); // 100 msec
if (loops >= 30)
return false ;
loops++;
}
return true ;
}
#ifdef UNUSED_CODE
// not used
bool RsDirUtil::createBackup (const std::string& sFilename, unsigned int nCount)
{
#ifdef WINDOWS_SYS
if (GetFileAttributesA (sFilename.c_str ()) == -1) {
// file doesn't exist
return true;
}
// search last backup
int nLast;
for (nLast = nCount; nLast >= 1; nLast--) {
std::ostringstream sStream; // please do not use std::ostringstream
sStream << sFilename << nLast << ".bak";
if (GetFileAttributesA (sStream.str ().c_str ()) != -1) {
break;
}
}
// delete max backup
if (nLast == nCount) {
std::ostringstream sStream; // please do not use std::ostringstream
sStream << sFilename << nCount << ".bak";
if (DeleteFileA (sStream.str ().c_str ()) == FALSE) {
getPqiNotify()->AddSysMessage (0, RS_SYS_WARNING, "File delete error", "Error while deleting file " + sStream.str ());
return false;
}
nLast--;
}
// rename backups
for (int nIndex = nLast; nIndex >= 1; nIndex--) {
std::ostringstream sStream; // please do not use std::ostringstream
sStream << sFilename << nIndex << ".bak";
std::ostringstream sStream1; // please do not use std::ostringstream
sStream1 << sFilename << nIndex + 1 << ".bak";
if (renameFile (sStream.str (), sStream1.str ()) == false) {
getPqiNotify()->AddSysMessage (0, RS_SYS_WARNING, "File rename error", "Error while renaming file " + sStream.str () + " to " + sStream1.str ());
return false;
}
}
// copy backup
std::ostringstream sStream; // please do not use std::ostringstream
sStream << sFilename << 1 << ".bak";
if (CopyFileA (sFilename.c_str (), sStream.str ().c_str (), FALSE) == FALSE) {
getPqiNotify()->AddSysMessage (0, RS_SYS_WARNING, "File rename error", "Error while renaming file " + sFilename + " to " + sStream.str ());
return false;
}
#else
/* remove unused parameter warnings */
(void) sFilename;
(void) nCount;
#endif
return true;
}
#endif
FILE *RsDirUtil::rs_fopen(const char* filename, const char* mode)
{
#ifdef WINDOWS_SYS
std::wstring wfilename;
librs::util::ConvertUtf8ToUtf16(filename, wfilename);
std::wstring wmode;
librs::util::ConvertUtf8ToUtf16(mode, wmode);
return _wfopen(wfilename.c_str(), wmode.c_str());
#else
return fopen64(filename, mode);
#endif
}
std::string RsDirUtil::convertPathToUnix(std::string path)
{
for (unsigned int i = 0; i < path.length(); i++)
{
if (path[i] == '\\')
path[i] = '/';
}
return path;
}
std::string RsDirUtil::makePath(const std::string &path1, const std::string &path2)
{
std::string path = path1;
if (path.empty() == false && *path.rbegin() != '/') {
path += "/";
}
path += path2;
return path;
}
int RsDirUtil::createLockFile(const std::string& lock_file_path, rs_lock_handle_t &lock_handle)
{
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
#ifndef WINDOWS_SYS
// Suspended. The user should make sure he's not already using the file descriptor.
// if(lock_handle != -1)
// close(lock_handle);
// open the file in write mode, create it if necessary, truncate it (it should be empty)
lock_handle = open(lock_file_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if(lock_handle == -1)
{
std::cerr << "Could not open lock file " << lock_file_path.c_str() << std::flush;
perror(NULL);
return 2;
}
// see "man fcntl" for the details, in short: non blocking lock creation on the whole file contents
struct flock lockDetails;
lockDetails.l_type = F_WRLCK;
lockDetails.l_whence = SEEK_SET;
lockDetails.l_start = 0;
lockDetails.l_len = 0;
if(fcntl(lock_handle, F_SETLK, &lockDetails) == -1)
{
int fcntlErr = errno;
std::cerr << "Could not request lock on file " << lock_file_path.c_str() << std::flush;
perror(NULL);
// there's no lock so let's release the file handle immediately
close(lock_handle);
lock_handle = -1;
if(fcntlErr == EACCES || fcntlErr == EAGAIN)
return 1;
else
return 2;
}
return 0;
#else
// Suspended. The user should make sure he's not already using the file descriptor.
//
// if (lock_handle) {
// CloseHandle(lock_handle);
// }
std::wstring wlockFile;
librs::util::ConvertUtf8ToUtf16(lock_file_path, wlockFile);
// open the file in write mode, create it if necessary
lock_handle = CreateFile(wlockFile.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (lock_handle == INVALID_HANDLE_VALUE)
{
DWORD lasterror = GetLastError();
std::cerr << "Could not open lock file " << lock_file_path.c_str() << std::endl;
std::cerr << "Last error: " << lasterror << std::endl << std::flush;
perror(NULL);
if (lasterror == ERROR_SHARING_VIOLATION || lasterror == ERROR_ACCESS_DENIED)
return 1;
return 2;
}
return 0;
#endif
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
}
void RsDirUtil::releaseLockFile(rs_lock_handle_t lockHandle)
{
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
#ifndef WINDOWS_SYS
if(lockHandle != -1)
{
close(lockHandle);
lockHandle = -1;
}
#else
if(lockHandle)
{
CloseHandle(lockHandle);
lockHandle = 0;
}
#endif
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
}
RsStackFileLock::RsStackFileLock(const std::string& file_path)
{
while(RsDirUtil::createLockFile(file_path,_file_handle))
{
std::cerr << "Cannot acquire file lock " << file_path << ", waiting 1 sec." << std::endl;
usleep(1 * 1000 * 1000) ; // 1 sec
}
#ifdef RSDIR_DEBUG
std::cerr << "Acquired file handle " << _file_handle << ", lock file:" << file_path << std::endl;
#endif
}
RsStackFileLock::~RsStackFileLock()
{
RsDirUtil::releaseLockFile(_file_handle) ;
#ifdef RSDIR_DEBUG
std::cerr << "Released file lock with handle " << _file_handle << std::endl;
#endif
}
#if 0 // NOT ENABLED YET!
/************************* WIDE STRING ***************************/
/************************* WIDE STRING ***************************/
/************************* WIDE STRING ***************************/
std::wstring RsDirUtil::getWideTopDir(std::wstring dir)
{
std::wstring top;
/* find the subdir: [/][dir1.../]<top>[/]
*/
int i,j;
int len = dir.length();
for(j = len - 1; (j > 0) && (dir[j] == '/'); j--);
for(i = j; (i > 0) && (dir[i] != '/'); i--);
if (dir[i] == '/')
i++;
for(; i <= j; i++)
{
top += dir[i];
}
return top;
}
std::wstring RsDirUtil::removeWideTopDir(std::wstring dir)
{
std::wstring rest;
/* remove the subdir: [/][dir1.../]<top>[/]
*/
int i,j;
int len = dir.length();
for(j = len - 1; (j > 0) && (dir[j] == '/'); j--);
for(i = j; (i >= 0) && (dir[i] != '/'); i--);
/* remove any more slashes */
for(; (i >= 0) && (dir[i] == '/'); i--);
for(j = 0; j <= i; j++)
{
rest += dir[j];
}
return rest;
}
std::wstring RsDirUtil::getWideRootDir(std::wstring dir)
{
std::wstring root;
/* find the subdir: [/]root[/...]
*/
int i,j;
int len = dir.length();
for(i = 0; (i < len) && (dir[i] == '/'); i++);
for(j = i; (j < len) && (dir[j] != '/'); j++);
if (i == j)
return root; /* empty */
for(; i < j; i++)
{
root += dir[i];
}
return root;
}
std::wstring RsDirUtil::removeWideRootDir(std::wstring path)
{
unsigned int i, j;
unsigned int len = path.length();
std::wstring output;
/* chew leading '/'s */
for(i = 0; (i < len) && (path[i] == '/'); i++);
if (i == len)
return output; /* empty string */
for(j = i; (j < len) && (path[j] != '/'); j++); /* run to next '/' */
for(; (j < len) && (path[j] == '/'); j++); /* chew leading '/'s */
for(; j < len; j++)
{
output += path[j];
}
return output;
}
std::wstring RsDirUtil::removeWideRootDirs(std::wstring path, std::wstring root)
{
/* too tired */
std::wstring notroot;
unsigned int i = 0, j = 0;
/* catch empty data */
if ((root.length() < 1) || (path.length() < 1))
return notroot;
if ((path[0] == '/') && (root[0] != '/'))
{
i++;
}
for(; (i < path.length()) && (j < root.length()) && (path[i] == root[j]); i++, j++);
/* should have consumed root. */
if (j == root.length())
{
//std::cerr << "matched root!" << std::endl;
}
else
{
//std::cerr << "failed i: " << i << ", j: " << j << std::endl;
//std::cerr << "root: " << root << " path: " << path << std::endl;
return notroot;
}
if (path[i] == '/')
{
i++;
}
for(; i < path.length(); i++)
{
notroot += path[i];
}
//std::cerr << "Found NotRoot: " << notroot << std::endl;
return notroot;
}
int RsDirUtil::breakupWideDirList(std::wstring path,
std::list<std::wstring> &subdirs)
{
int start = 0;
unsigned int i;
for(i = 0; i < path.length(); i++)
{
if (path[i] == '/')
{
if (i - start > 0)
{
subdirs.push_back(path.substr(start, i-start));
}
start = i+1;
}
}
// get the final one.
if (i - start > 0)
{
subdirs.push_back(path.substr(start, i-start));
}
return 1;
}
bool RsDirUtil::checkWideDirectory(std::wstring dir)
{
struct stat buf;
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
std::string d(dir.begin(), dir.end());
int val = stat(d.c_str(), &buf);
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
if (val == -1)
{
#ifdef RSDIR_DEBUG
std::cerr << "RsDirUtil::checkDirectory() ";
std::cerr << d << " doesn't exist" << std::endl;
#endif
return false;
}
else if (!S_ISDIR(buf.st_mode))
{
// Some other type - error.
#ifdef RSDIR_DEBUG
std::cerr << "RsDirUtil::checkDirectory() ";
std::cerr << d << " is not Directory" << std::endl;
#endif
return false;
}
return true;
}
bool RsDirUtil::checkWideCreateDirectory(std::wstring dir)
{
struct stat buf;
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
std::string d(dir.begin(), dir.end());
int val = stat(d.c_str(), &buf);
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
if (val == -1)
{
// directory don't exist. create.
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
#ifndef WINDOWS_SYS // UNIX
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
if (-1 == mkdir(d.c_str(), 0777))
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
#else // WIN
if (-1 == mkdir(d.c_str()))
#endif
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
{
#ifdef RSDIR_DEBUG
std::cerr << "check_create_directory() Fatal Error --";
std::cerr <<std::endl<< "\tcannot create:" <<d<<std::endl;
#endif
return 0;
}
#ifdef RSDIR_DEBUG
std::cerr << "check_create_directory()";
std::cerr <<std::endl<< "\tcreated:" <<d<<std::endl;
#endif
}
else if (!S_ISDIR(buf.st_mode))
{
// Some other type - error.
#ifdef RSDIR_DEBUG
std::cerr<<"check_create_directory() Fatal Error --";
std::cerr<<std::endl<<"\t"<<d<<" is nor Directory"<<std::endl;
#endif
return 0;
}
#ifdef RSDIR_DEBUG
std::cerr << "check_create_directory()";
std::cerr <<std::endl<< "\tDir Exists:" <<d<<std::endl;
#endif
return 1;
}
#include <dirent.h>
bool RsDirUtil::cleanupWideDirectory(std::wstring cleandir, std::list<std::wstring> keepFiles)
{
/* check for the dir existance */
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
std::string cd(cleandir.begin(), cleandir.end());
DIR *dir = opendir(cd.c_str());
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
std::list<std::wstring>::const_iterator it;
if (!dir)
{
return false;
}
struct dirent *dent;
struct stat buf;
while(NULL != (dent = readdir(dir)))
{
/* check entry type */
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
std::string fname(dent -> d_name);
std::wstring wfname(fname.begin(), fname.end());
std::string fullname = cd + "/" + fname;
if (-1 != stat(fullname.c_str(), &buf))
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
{
/* only worry about files */
if (S_ISREG(buf.st_mode))
{
/* check if we should keep it */
if (keepFiles.end() == (it = std::find(keepFiles.begin(), keepFiles.end(), wfname)))
{
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
/* can remove */
remove(fullname.c_str());
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
}
}
}
}
/* close directory */
closedir(dir);
return true;
}
/* slightly nicer helper function */
bool RsDirUtil::hashWideFile(std::wstring filepath,
std::wstring &name, std::string &hash, uint64_t &size)
{
if (getWideFileHash(filepath, hash, size))
{
/* extract file name */
name = RsDirUtil::getWideTopDir(filepath);
return true;
}
return false;
}
#include <openssl/sha.h>
#include <sstream>
#include <iomanip>
/* Function to hash, and get details of a file */
bool RsDirUtil::getWideFileHash(std::wstring filepath,
std::string &hash, uint64_t &size)
{
FILE *fd;
int len;
SHA_CTX *sha_ctx = new SHA_CTX;
unsigned char sha_buf[SHA_DIGEST_LENGTH];
unsigned char gblBuf[512];
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
std::string fp(filepath.begin(), filepath.end());
if (NULL == (fd = fopen64(fp.c_str(), "rb")))
return false;
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
/* determine size */
fseeko64(fd, 0, SEEK_END);
size = ftello64(fd);
fseeko64(fd, 0, SEEK_SET);
SHA1_Init(sha_ctx);
while((len = fread(gblBuf,1, 512, fd)) > 0)
{
SHA1_Update(sha_ctx, gblBuf, len);
}
/* reading failed for some reason */
if (ferror(fd))
{
delete sha_ctx;
fclose(fd);
return false;
}
SHA1_Final(&sha_buf[0], sha_ctx);
std::ostringstream tmpout; // please do not use std::ostringstream
for(int i = 0; i < SHA_DIGEST_LENGTH; i++)
{
tmpout << std::setw(2) << std::setfill('0') << std::hex << (unsigned int) (sha_buf[i]);
}
hash = tmpout.str();
delete sha_ctx;
fclose(fd);
return true;
}
bool RsDirUtil::renameWideFile(const std::wstring& from, const std::wstring& to)
{
int loops = 0;
#if defined(WIN32) || defined(MINGW) || defined(__CYGWIN__)
#ifdef WIN_CROSS_UBUNTU
std::wstring f,t ;
for(int i=0;i<from.size();++i) f.push_back(from[i]) ;
for(int i=0;i<to.size();++i) t.push_back(to[i]) ;
#else
std::wstring f(from),t(to) ;
#endif
while (!MoveFileEx(f.c_str(), t.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH))
#else
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
std::string f(from.begin(), from.end());
std::string t(to.begin(), to.end());
while (rename(f.c_str(), t.c_str()) < 0)
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
#endif
{
#ifdef WIN32
if (GetLastError() != ERROR_ACCESS_DENIED)
#else
if (errno != EACCES)
#endif
/* set errno? */
return false ;
usleep(100 * 1000); //100 msec
if (loops >= 30)
return false ;
loops++;
}
return true ;
}
#endif // WIDE STUFF NOT ENABLED YET!