1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
|
/*
a class to hold information about a file.
cvs info:
$Revision: 822 $
$Id: Fileinfo.cc 822 2013-06-03 09:25:13Z paul $
Author Paul Sundvall 2006
See LICENSE for details.
*/
#include "config.h"
#include "Fileinfo.hh"
#include <fstream>//for file reading
#include <iostream>//for cout etc
#include <sys/stat.h>//for file info
#include <errno.h>//for errno
#include <unistd.h>//for unlink etc.
#include "Checksum.hh" //checksum calculation
using std::cerr;
using std::endl;
int Fileinfo::fillwithbytes(enum readtobuffermode filltype,
enum readtobuffermode lasttype)
{
//Decide if we are going to read from file or not.
//If file is short, first bytes might be ALL bytes!
if(lasttype!=-1) {
if(this->size()<= (Fileinfo::filesizetype)m_nbytes) {
//pointless to read - all bytes in the file are in the field
//m_somebytes, or checksum is calculated!
// cout<<"Skipped reading from file because lasttype="<<lasttype
// <<" and size="<<size()<<endl;
return 0;
}
}
//set memory to zero
//(this command is equivalent to memset(m_somebytes,0,sizeeof(m_somebytes))
//but this is easier to understand.)
memset(m_somebytes,0,m_nbytes*sizeof(m_somebytes[0]));
std::fstream f1;
f1.open(m_filename.c_str(),std::ios_base::in);
if(!f1.is_open()){
std::cerr<<"fillwithbytes.cc: Could not open file \""<<m_filename<<"\""<<std::endl;
return -1;
}
int checksumtype=Checksum::NOTSET;
//read some bytes
switch(filltype) {
case READ_FIRST_BYTES:
//read at start of file
f1.read(m_somebytes,m_nbytes);
break;
case READ_LAST_BYTES:
//read at end of file
f1.seekg(-m_nbytes,std::ios_base::end);
f1.read(m_somebytes,m_nbytes);
break;
case CREATE_MD5_CHECKSUM://note: fall through is on purpose
checksumtype=Checksum::MD5;
case CREATE_SHA1_CHECKSUM:
checksumtype=Checksum::SHA1;
{//checksum calculation
Checksum chk;
if(chk.init(checksumtype))
std::cerr<<"error in checksum init"<<std::endl;
char buffer[1024];
int len=1;
while(len){
f1.read(buffer,1024);
len=f1.gcount();
if(len)
if(chk.update((unsigned int)len,(unsigned char*)buffer))
std::cerr<<"error in update"<<std::endl;
}
//store the result of the checksum calculation in somebytes
int digestlength=chk.getDigestLength();
if (digestlength<=0 || digestlength>=m_nbytes)
std::cerr<<"wrong answer from getDigestLength! FIXME"<<std::endl;
if(chk.printToBuffer(m_somebytes))
std::cerr<<"failed writing digest to buffer!!"<<std::endl;
}
break;
default:
std::cerr<<"does not know how to do that filltype:"<<filltype<<std::endl;
}
f1.close();
return 0;
}
bool Fileinfo::readfileinfo(){
struct stat info;
m_info.is_file=false;
m_info.is_directory=false;
int res;
do {
res=stat(m_filename.c_str(), &info);
} while(res<0 && errno==EINTR);
if (res<0){
m_info.stat_size=0;
m_info.stat_ino=0;
m_info.stat_dev=0;
std::cerr<<"readfileinfo.cc:Something went wrong when reading file info from \""<<
m_filename<<"\" :"<<strerror(errno)<<std::endl;
return false;
}
//only keep the relevant information
m_info.stat_size=(Fileinfo::filesizetype) info.st_size;
m_info.stat_ino= info.st_ino;
m_info.stat_dev= info.st_dev;
m_info.is_file=S_ISREG(info.st_mode)?true:false;
m_info.is_directory=S_ISDIR(info.st_mode)?true:false;
return true;
}
const std::string Fileinfo::getduptypestring(const Fileinfo &A) {
switch (A.getduptype()) {
case DUPTYPE_UNKNOWN:
return "DUPTYPE_UNKNOWN";
case DUPTYPE_FIRST_OCCURRENCE:
return "DUPTYPE_FIRST_OCCURRENCE";
case DUPTYPE_WITHIN_SAME_TREE:
return "DUPTYPE_WITHIN_SAME_TREE";
case DUPTYPE_OUTSIDE_TREE:
return "DUPTYPE_OUTSIDE_TREE";
default:
std::cerr<<"error. does not know that one"<<std::endl;
}
return "error-error";
}
//constructor
Fileinfo::Fileinfostat::Fileinfostat() {
stat_size=99999;
stat_ino =99999;
stat_dev =99999;
is_file =false;
is_directory=false;
}
int Fileinfo::deletefile()
{
return unlink(name().c_str());
}
int simplifyPath(std::string &path){
//replace a/./b to a/b
std::string::size_type pos=std::string::npos;
do {
pos=path.find("/./");
if(pos!=std::string::npos) {
path.replace(pos,3,"/");
}
} while(pos!=std::string::npos);
//we should get rid of /../ also, but that is more difficult.
//future work...
return 0;
}
//prepares target, so that location can point to target in
//the best way possible
int makeReadyForLink(std::string &target, const std::string &location_)
{
std::string location(location_);
//simplify target and location
simplifyPath(location);
simplifyPath(target);
//if target is not absolute, let us make it absolute
if(target.length()>0 && target.at(0)=='/') {
//absolute. do nothing.
// std::cout<<"absolute"<<std::endl;
} else {
//not absolute. make it absolute.
// std::cout<<"not absolute"<<std::endl;
//yes, this is possible to do with dynamically allocated memory,
//but it is not portable then (and more work).
const size_t buflength=256;
char buf[buflength];
if(buf!=getcwd(buf,buflength)) {
std::cerr<<"failed to get current working directory"<<std::endl;
return -1;
}
target=std::string(buf)+std::string("/")+target;
// std::cout<<"target is now "<<target<<std::endl;
}
return 0;
}
//makes a symlink that points to A
int Fileinfo::makesymlink(const Fileinfo &A) {
int retval=0;
//step 1: remove the file
retval=unlink(name().c_str());
if(retval) {
cerr<<"failed to unlink file "<<name()<<endl;
return retval;
}
//step 2: make a symlink.
//the tricky thing is that the path must be correct, as seen from
//the directory where *this is.
//simplifiy A and *this, so that asdf/../asdfdf are removed
std::string target=A.name();
makeReadyForLink(target,name());
// std::cout<<"will call symlink("<<target<<","<<name()<<")"<<std::endl;
retval=symlink(target.c_str(),name().c_str());
if(retval) {
cerr<<"failed to make symlink "<<name()<<" to "<<A.name()<<endl;
return retval;
}
return retval;
}
//makes a hard link that points to A
int Fileinfo::makehardlink(const Fileinfo &A) {
int retval=0;
//step 1: remove the file
retval=unlink(name().c_str());
if(retval) {
cerr<<"failed to unlink file "<<name()<<endl;
return retval;
}
//step 2: make a hardlink.
retval=link(A.name().c_str(),name().c_str());
if(retval) {
cerr<<"failed to make hardlink "<<name()<<" to "<<A.name()<<endl;
return retval;
}
return retval;
}
int Fileinfo::static_deletefile(Fileinfo &A, const Fileinfo &B) {
//delete A.
// cout<<"wants to delete file "<<A.name()<<endl;
// return 0;
return A.deletefile();
}
int Fileinfo::static_makesymlink(Fileinfo &A, const Fileinfo &B) {
// cout<<"wants to make symlink from file "<<A.name()<<" to "<<B.name()<<endl;
// return 0;
return A.makesymlink(B);
}
int Fileinfo::static_makehardlink(Fileinfo &A, const Fileinfo &B) {
// cout<<"wants to make hardlink from file "<<A.name()<<" to "<<B.name()<<endl;
// return 0;
return A.makehardlink(B);
}
bool Fileinfo::compareonbytes(const Fileinfo &a, const Fileinfo &b)
{
int retval=memcmp(a.getbyteptr(),b.getbyteptr(),m_nbytes);
return (retval<0);
/*
for(int i=0;i<m_nbytes;i++)
if(a.getreadbyte(i)<b.getreadbyte(i))
return true;
return false;
*/
}
bool Fileinfo::equalbytes(const Fileinfo &a, const Fileinfo &b)
{
int retval=memcmp(a.getbyteptr(),b.getbyteptr(),m_nbytes);
return (retval==0);
}
bool Fileinfo::compareonsizeandfirstbytes(const Fileinfo &a, const Fileinfo &b)
{
if (a.size()>b.size())
return true;
if (a.size()<b.size())
return false;
//must be equal. compare on bytes.
return compareonbytes(a,b);
}
bool Fileinfo::equalsize(const Fileinfo &a, const Fileinfo &b)
{
if (a.size()==b.size())
return true;
else
return false;
}
|