mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-05-10 18:15:18 -04:00

. - corrected a bug that caused file copy error: a closeFile() was missing when the file is complete. Because of delays in fwrite, the file would not be always co mplete, nor exist at all for small files (e.g. cache files), which in the later case caused the copy error. Warning: needs a make clean in libretroshare to recompile. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3261 b45a01b8-16f6-495d-af2f-9b41ad6348cc
1010 lines
22 KiB
C++
1010 lines
22 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 <unistd.h>
|
|
|
|
#include "util/rsdir.h"
|
|
#include "pqi/pqinotify.h"
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include <stdio.h>
|
|
#include <dirent.h>
|
|
#include <openssl/sha.h>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
|
|
#include <fstream>
|
|
|
|
#if defined(WIN32) || defined(__CYGWIN__)
|
|
#include "util/rswin.h"
|
|
#include "wtypes.h"
|
|
#include <winioctl.h>
|
|
#else
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
/****
|
|
* #define RSDIR_DEBUG 1
|
|
****/
|
|
#define RSDIR_DEBUG 1
|
|
|
|
std::string RsDirUtil::getTopDir(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;
|
|
}
|
|
|
|
class CRC32Table
|
|
{
|
|
public:
|
|
inline uint32_t operator[](unsigned char i) const { return _data[i] ; }
|
|
|
|
CRC32Table()
|
|
{
|
|
_data = new uint32_t[256] ;
|
|
uint32_t polynmial = 0x04c11db7 ;
|
|
|
|
for(uint32_t i=0;i<256;++i)
|
|
{
|
|
uint32_t a = reflect(i,8)<<24 ;
|
|
|
|
for(uint32_t j=0;j<8;++j)
|
|
a = (a << 1)^ ( (a&(1<<31))?polynmial:0) ;
|
|
|
|
_data[i] = reflect(a,32) ;
|
|
}
|
|
}
|
|
// Swap bits 0-7, 1-6, etc.
|
|
//
|
|
uint32_t reflect(uint32_t ref,unsigned char ch)
|
|
{
|
|
uint32_t val = 0 ;
|
|
for(int i=1;i<ch+1;i++,ref>>=1)
|
|
if(ref & 1)
|
|
val |= (1 << (ch-i)) ;
|
|
return val ;
|
|
}
|
|
~CRC32Table() { delete[] _data ; }
|
|
|
|
private:
|
|
uint32_t *_data ;
|
|
};
|
|
|
|
uint32_t rs_CRC32(const unsigned char *data,uint32_t len)
|
|
{
|
|
static const CRC32Table crc32_table ;
|
|
uint32_t a = 0xffffffff ;
|
|
|
|
for(const unsigned char *buf=data;len>=0;len--)
|
|
a = (a >> 8) ^ crc32_table[ (a & 0xff) ^ *buf++] ;
|
|
|
|
return a ^ 0xffffffff ;
|
|
}
|
|
|
|
bool RsDirUtil::hashFile(const std::string& f_hash, std::string& hash)
|
|
{
|
|
FILE *fd;
|
|
int len;
|
|
SHA_CTX *sha_ctx = new SHA_CTX;
|
|
unsigned char sha_buf[SHA_DIGEST_LENGTH];
|
|
unsigned char *gblBuf = new unsigned char[1024*1024*10]; // 10MB buffer.
|
|
|
|
#ifdef FIM_DEBUG
|
|
std::cerr << "File to hash = " << f_hash << std::endl;
|
|
#endif
|
|
|
|
#ifdef WINDOWS_SYS
|
|
std::wstring wf_hash;
|
|
librs::util::ConvertUtf8ToUtf16(f_hash, wf_hash);
|
|
if (NULL == (fd = _wfopen(wf_hash.c_str(), L"rb")))
|
|
goto hashing_failed ;
|
|
#else
|
|
if (NULL == (fd = fopen64(f_hash.c_str(), "rb")))
|
|
goto hashing_failed ;
|
|
#endif
|
|
|
|
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))
|
|
{
|
|
#ifdef FIM_DEBUG
|
|
std::cerr << "read error !!" << std::endl;
|
|
#endif
|
|
goto hashing_failed ;
|
|
}
|
|
|
|
SHA1_Final(&sha_buf[0], sha_ctx);
|
|
|
|
/* TODO: Actually we should store the hash data as binary ...
|
|
* but then it shouldn't be put in a string.
|
|
*/
|
|
|
|
{
|
|
std::ostringstream tmpout;
|
|
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;
|
|
delete[] gblBuf ;
|
|
fclose(fd);
|
|
return true;
|
|
|
|
hashing_failed:
|
|
|
|
delete sha_ctx;
|
|
delete[] gblBuf ;
|
|
|
|
if(fd != NULL)
|
|
fclose(fd) ;
|
|
|
|
return false ;
|
|
}
|
|
|
|
std::string RsDirUtil::removeTopDir(std::string dir)
|
|
{
|
|
std::string 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::string RsDirUtil::getRootDir(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(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(std::string path, 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(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;
|
|
}
|
|
|
|
|
|
|
|
bool RsDirUtil::checkDirectory(std::string dir)
|
|
{
|
|
struct stat buf;
|
|
int val = stat(dir.c_str(), &buf);
|
|
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(buf.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(std::string dir)
|
|
{
|
|
#ifdef RSDIR_DEBUG
|
|
std::cerr << "RsDirUtil::checkCreateDirectory() dir: " << dir << std::endl;
|
|
#endif
|
|
DIR *direc = opendir(dir.c_str());
|
|
if (!direc)
|
|
{
|
|
// directory don't exist. create.
|
|
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
|
#ifndef WINDOWS_SYS // UNIX
|
|
if (-1 == mkdir(dir.c_str(), 0777))
|
|
#else // WIN
|
|
if (-1 == mkdir(dir.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
|
|
}
|
|
|
|
#ifdef RSDIR_DEBUG
|
|
std::cerr << "check_create_directory()";
|
|
std::cerr <<std::endl<< "\tDir Exists:" <<dir<<std::endl;
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
//#include <sys/types.h>
|
|
//#include <sys/stat.h>
|
|
//#include <fcntl.h>
|
|
//#include <unistd.h>
|
|
|
|
bool RsDirUtil::cleanupDirectory(std::string cleandir, std::list<std::string> keepFiles)
|
|
{
|
|
|
|
/* check for the dir existance */
|
|
DIR *dir = opendir(cleandir.c_str());
|
|
std::list<std::string>::const_iterator it;
|
|
|
|
if (!dir)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
struct dirent *dent;
|
|
struct stat buf;
|
|
|
|
while(NULL != (dent = readdir(dir)))
|
|
{
|
|
/* check entry type */
|
|
std::string fname = dent -> d_name;
|
|
std::string fullname = cleandir + "/" + fname;
|
|
|
|
if (-1 != stat(fullname.c_str(), &buf))
|
|
{
|
|
/* 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(), fname)))
|
|
{
|
|
/* can remove */
|
|
remove(fullname.c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* close directory */
|
|
closedir(dir);
|
|
|
|
return true;
|
|
}
|
|
|
|
/* slightly nicer helper function */
|
|
bool RsDirUtil::hashFile(std::string filepath,
|
|
std::string &name, std::string &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 <sstream>
|
|
#include <iomanip>
|
|
|
|
/* Function to hash, and get details of a file */
|
|
bool RsDirUtil::getFileHash(std::string 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];
|
|
|
|
#ifdef WINDOWS_SYS
|
|
std::wstring filepathW;
|
|
librs::util::ConvertUtf8ToUtf16(filepath, filepathW);
|
|
if (NULL == (fd = _wfopen(filepathW.c_str(), L"rb")))
|
|
return false;
|
|
#else
|
|
if (NULL == (fd = fopen(filepath.c_str(), "rb")))
|
|
return false;
|
|
#endif
|
|
|
|
/* determine size */
|
|
fseek(fd, 0, SEEK_END);
|
|
size = ftell(fd);
|
|
fseek(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;
|
|
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::renameFile(const std::string& from, const std::string& 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::string f(from),t(to) ;
|
|
#endif
|
|
while (!MoveFileExA(f.c_str(), t.c_str(), MOVEFILE_REPLACE_EXISTING))
|
|
#else
|
|
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 ;
|
|
#ifdef WIN32
|
|
Sleep(100000); /* us */
|
|
#else
|
|
usleep(100000); /* us */
|
|
#endif
|
|
|
|
if (loops >= 30)
|
|
return false ;
|
|
|
|
loops++;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
bool RsDirUtil::createBackup (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;
|
|
sStream << sFilename << nLast << ".bak";
|
|
|
|
if (GetFileAttributesA (sStream.str ().c_str ()) != -1) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// delete max backup
|
|
if (nLast == nCount) {
|
|
std::ostringstream sStream;
|
|
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;
|
|
sStream << sFilename << nIndex << ".bak";
|
|
std::ostringstream sStream1;
|
|
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;
|
|
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;
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
#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 = fopen(fp.c_str(), "rb")))
|
|
return false;
|
|
|
|
/***** XXX TO MAKE WIDE SYSTEM CALL ******************************************************/
|
|
|
|
/* determine size */
|
|
fseek(fd, 0, SEEK_END);
|
|
size = ftell(fd);
|
|
fseek(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;
|
|
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))
|
|
#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 ;
|
|
#ifdef WIN32
|
|
Sleep(100000); /* us */
|
|
#else
|
|
usleep(100000); /* us */
|
|
#endif
|
|
|
|
if (loops >= 30)
|
|
return false ;
|
|
|
|
loops++;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
|
|
#endif // WIDE STUFF NOT ENABLED YET!
|