std::vector<SShadowCopy> ClientDAO::getShadowcopies(void)
{
	db_results res=q_get_shadowcopies->Read();
	q_get_shadowcopies->Reset();
	std::vector<SShadowCopy> ret;
	for(size_t i=0;i<res.size();++i)
	{
		db_single_result &r=res[i];
		SShadowCopy sc;
		sc.id=watoi(r[L"id"]);
		memcpy(&sc.vssid, r[L"vssid"].c_str(), sizeof(GUID) );
		memcpy(&sc.ssetid, r[L"ssetid"].c_str(), sizeof(GUID) );
		sc.target=r[L"target"];
		sc.path=r[L"path"];
		sc.tname=r[L"tname"];
		sc.orig_target=r[L"orig_target"];
		sc.filesrv=r[L"filesrv"]==L"0"?false:true;
		sc.vol=r[L"vol"];
		sc.passedtime=watoi(r[L"passedtime"]);
		sc.refs=watoi(r[L"refs"]);
		sc.starttoken=r[L"starttoken"];
		ret.push_back(sc);
	}
	return ret;
}
Beispiel #2
0
void updateArchiveSettings(int clientid, str_map &GET, IDatabase *db)
{
	int i=0;
	IQuery *q=db->Prepare("DELETE FROM settings_db.automatic_archival WHERE clientid=?");
	q->Bind(clientid);
	q->Write();
	q=db->Prepare("INSERT INTO settings_db.automatic_archival (next_archival, interval, interval_unit, length, length_unit, backup_types, clientid, archive_window) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
	while(GET.find(L"archive_every_"+convert(i))!=GET.end())
	{
		_i64 archive_next=watoi64(GET[L"archive_next_"+convert(i)]);
		int archive_every=watoi(GET[L"archive_every_"+convert(i)]);
		int archive_for=watoi(GET[L"archive_for_"+convert(i)]);
		std::wstring backup_type_str=GET[L"archive_backup_type_"+convert(i)];
		int backup_types=ServerAutomaticArchive::getBackupTypes(backup_type_str);


		if(archive_next<0)
		{
			if(clientid==0)
			{
				q->Bind(0);
			}
			else
			{
				q->Bind(Server->getTimeSeconds());
			}
		}
		else
		{
			q->Bind(archive_next);
		}
		q->Bind(archive_every);
		q->Bind(GET[L"archive_every_unit_"+convert(i)]);
		q->Bind(archive_for);
		q->Bind(GET[L"archive_for_unit_"+convert(i)]);
		q->Bind(backup_types);
		q->Bind(clientid);
		q->Bind(GET[L"archive_window_"+convert(i)]);
		q->Write();
		q->Reset();

		++i;
	}

	IQuery *q_get=db->Prepare("SELECT value FROM settings_db.settings WHERE clientid="+nconvert(clientid)+" AND key=?");
	if(clientid!=0)
	{		
		IQuery *q_update=db->Prepare("UPDATE settings_db.settings SET value=? WHERE key=? AND clientid="+nconvert(clientid));
		IQuery *q_insert=db->Prepare("INSERT INTO settings_db.settings (key, value, clientid) VALUES (?,?,"+nconvert(clientid)+")");

		updateSetting(L"overwrite_archive_settings", L"true", q_get, q_update, q_insert);
	}
	else
	{
		db->Write("DELETE FROM settings_db.settings WHERE key='archive_settings_copied'");
	}
}
Beispiel #3
0
void getArchiveSettings(JSON::Object &obj, IDatabase *db, int clientid)
{
	IQuery *q_get=db->Prepare("SELECT value FROM settings_db.settings WHERE clientid="+nconvert(clientid)+" AND key=?");
	q_get->Bind("overwrite");
	db_results res=q_get->Read();
	q_get->Reset();
	if(res.empty() || res[0][L"value"]!=L"true")
		clientid=0;

	q_get->Bind("overwrite_archive_settings");
	res=q_get->Read();
	if(res.empty() || res[0][L"value"]!=L"true")
		clientid=0;

	IQuery *q=db->Prepare("SELECT next_archival, interval, interval_unit, length, length_unit, backup_types FROM settings_db.automatic_archival WHERE clientid=?");
	q->Bind(clientid);
	res=q->Read();

	JSON::Array arr;
	for(size_t i=0;i<res.size();++i)
	{
		_i64 archive_next=watoi64(res[i][L"next_archival"]);

		JSON::Object ca;
		ca.set("next_archival", res[i][L"next_archival"]);
		ca.set("archive_every", watoi(res[i][L"interval"]));
		ca.set("archive_every_unit", res[i][L"interval_unit"]);
		ca.set("archive_for", watoi(res[i][L"length"]));
		ca.set("archive_for_unit", res[i][L"length_unit"]);
		ca.set("archive_backup_type", ServerAutomaticArchive::getBackupType(watoi(res[i][L"backup_types"])));
		ca.set("archive_window", res[i][L"archive_window"]);

		if(archive_next>0 && clientid!=0)
		{
			_i64 tl=archive_next-(_i64)Server->getTimeSeconds();
			ca.set("archive_timeleft", tl);
		}
		else
		{
			ca.set("archive_timeleft", "-");
		}

		arr.add(ca);
	}
	obj.set("archive_settings", arr);
}
SDeviceInfo ChangeJournalWatcher::getDeviceInfo(const std::wstring &name)
{
	q_get_dev_id->Bind(name);
	db_results res=q_get_dev_id->Read();
	q_get_dev_id->Reset();
	SDeviceInfo r;
	r.has_info=false;
	if(!res.empty())
	{
		r.has_info=true;
		r.journal_id=os_atoi64(wnarrow(res[0][L"journal_id"]));
		r.last_record=os_atoi64(wnarrow(res[0][L"last_record"]));
		r.index_done=watoi(res[0][L"index_done"])>0;
	}
	return r;
}
int ClientDAO::modShadowcopyRefCount(int id, int m)
{
	q_get_shadowcopy_refcount->Bind(id);
	db_results res=q_get_shadowcopy_refcount->Read();
	q_get_shadowcopy_refcount->Reset();
	if(!res.empty())
	{
		int refs=watoi(res[0][L"refs"]);
		refs+=m;
		q_set_shadowcopy_refcount->Bind(refs);
		q_set_shadowcopy_refcount->Bind(id);
		q_set_shadowcopy_refcount->Write();
		q_set_shadowcopy_refcount->Reset();
		return refs;
	}
	return -1;
}
std::vector<SBackupDir> ClientDAO::getBackupDirs(void)
{
	db_results res=q_get_dirs->Read();
	q_get_dirs->Reset();

	std::vector<SBackupDir> ret;
	for(size_t i=0;i<res.size();++i)
	{
		SBackupDir dir;
		dir.id=watoi(res[i][L"id"]);
		dir.tname=res[i][L"name"];
		dir.path=res[i][L"path"];

		if(dir.tname!=L"*")
			ret.push_back(dir);
	}
	return ret;
}
int ServerAutomaticArchive::getNonArchivedFileBackup(int backup_types, int clientid)
{
	std::string incremental;
	if(backup_types & backup_type_full_file && backup_types & backup_type_incr_file)
		incremental="";
	else if( backup_types & backup_type_full_file )
		incremental=" AND incremental<>0";
	else if( backup_types & backup_type_incr_file)
		incremental=" AND incremental=0";

	IQuery *q_get_backups=db->Prepare("SELECT id FROM backups WHERE complete=1 AND archived=0 AND clientid=?"+incremental+" ORDER BY backuptime DESC LIMIT 1");
	q_get_backups->Bind(clientid);
	db_results res=q_get_backups->Read();
	if(!res.empty())
		return watoi(res[0][L"id"]);
	else
		return 0;
}
SStatus Connector::getStatus(void)
{
    std::string d=getResponse("STATUS","");

    std::vector<std::string> toks;
    Tokenize(d, toks, "#");

    SStatus ret;
    ret.pause=false;
    ret.capa=0;
    if(toks.size()>0)
        ret.lastbackupdate=wxString::FromUTF8(toks[0].c_str() );
    if(toks.size()>1)
        ret.status=wxString::FromUTF8(toks[1].c_str() );
    if(toks.size()>2)
        ret.pcdone=wxString::FromUTF8(toks[2].c_str() );
    if(toks.size()>3)
    {
        if(toks[3]=="P")
            ret.pause=true;
        else if(toks[3]=="NP")
            ret.pause=false;
    }
    if(toks.size()>4)
    {
        std::map<std::wstring,std::wstring> params;
        ParseParamStr(toks[4], &params);
        std::map<std::wstring,std::wstring>::iterator it_capa=params.find(L"capa");
        if(it_capa!=params.end())
        {
            ret.capa=watoi(it_capa->second);
        }
        std::map<std::wstring,std::wstring>::iterator it_new_server=params.find(L"new_ident");
        if(it_new_server!=params.end())
        {
            ret.new_server=wnarrow(it_new_server->second);
        }
    }

    return ret;
}
bool ClientDAO::getFiles(std::wstring path, std::vector<SFile> &data)
{
	q_get_files->Bind(path);
	db_results res=q_get_files->Read();
	q_get_files->Reset();
	if(res.size()==0)
		return false;

	std::wstring &qdata=res[0][L"data"];

	if(qdata.empty())
		return true;

	int num=watoi(res[0][L"num"]);
	char *ptr=(char*)&qdata[0];
	while(ptr-(char*)&qdata[0]<num)
	{
		SFile f;
		unsigned short ss;
		memcpy(&ss, ptr, sizeof(unsigned short));
		ptr+=sizeof(unsigned short);
		std::string tmp;
		tmp.resize(ss);
		memcpy(&tmp[0], ptr, ss);
		f.name=Server->ConvertToUnicode(tmp);
		ptr+=ss;
		memcpy(&f.size, ptr, sizeof(int64));
		ptr+=sizeof(int64);
		memcpy(&f.last_modified, ptr, sizeof(int64));
		ptr+=sizeof(int64);
		char isdir=*ptr;
		++ptr;
		if(isdir==0)
			f.isdir=false;
		else
			f.isdir=true;
		data.push_back(f);
	}
	return true;
}
Beispiel #10
0
DLLEXPORT void LoadActions(IServer* pServer)
{
	Server=pServer;

	std::string compress_file = Server->getServerParameter("compress");
	if(!compress_file.empty())
	{
		IFile* in = Server->openFile(compress_file, MODE_READ_SEQUENTIAL);
		if(in==NULL)
		{
			Server->Log("Cannot open file \""+compress_file+"\" to compress", LL_ERROR);
			exit(1);
		}

		{
			Server->deleteFile(compress_file+".urz");
			CompressedFile compFile(compress_file+".urz", MODE_RW_CREATE);

			if(compFile.hasError())
			{
				Server->Log("Error opening compressed file", LL_ERROR);
				exit(3);
			}

			char buffer[32768];
			_u32 read;
			do 
			{
				read = in->Read(buffer, 32768);
				if(read>0)
				{
					if(compFile.Write(buffer, read)!=read)
					{
						Server->Log("Error writing to compressed file", LL_ERROR);
						exit(2);
					}
				}			
			} while (read>0);

			compFile.finish();
			delete in;
		}	

		exit(0);
	}

	std::string decompress = Server->getServerParameter("decompress");
	if(!decompress.empty())
	{
		bool selected_via_gui=false;
#ifdef _WIN32
		if(decompress=="SelectViaGUI")
		{
			std::string filter;
			filter += "Compressed image files (*.vhdz)";
			filter += '\0';
			filter += "*.vhdz";
			filter += '\0';
			filter += '\0';
			std::vector<std::string> res = file_via_dialog("Please select compressed image file to decompress",
				filter, false, true, "");
			if(!res.empty())
			{
				decompress = res[0];
			}
			else
			{
				decompress.clear();
			}
			

			if(decompress.empty())
			{
				exit(1);
			}
			else
			{
				selected_via_gui=true;
			}
		}
#endif

		std::string targetName = decompress;
		if(findextension(decompress)!="vhdz" && findextension(decompress)!="urz")
		{
			Server->Log("Unknown file extension: "+findextension(decompress), LL_ERROR);
			exit(1);
		}

		if(!Server->getServerParameter("output_fn").empty() && !selected_via_gui)
		{
			targetName = Server->getServerParameter("output_fn");
		}

		bool b = decompress_vhd(decompress, targetName);		

		exit(b?0:3);
	}

	std::string assemble = Server->getServerParameter("assemble");
	if(!assemble.empty())
	{
		bool selected_via_gui=false;
		std::vector<std::string> input_files;
		std::string output_file;
#ifdef _WIN32
		if(assemble=="SelectViaGUI")
		{
			std::string filter;
			filter += "Image files (*.vhdz;*.vhd)";
			filter += '\0';
			filter += "*.vhdz;*.vhd";
			filter += '\0';
			/*filter += L"Image files (*.vhd)";
			filter += '\0';
			filter += L"*.vhd";
			filter += '\0';*/
			filter += '\0';
			std::vector<std::string> new_input_files;
			do
			{
				new_input_files = file_via_dialog("Please select all the images to assemble into one image. Cancel once finished.",
					filter, true, true, "");
				input_files.insert(input_files.end(), new_input_files.begin(), new_input_files.end());
			} while (!new_input_files.empty());

			filter.clear();
			filter += "Image file (*.vhd)";
			filter += '\0';
			filter += "*.vhd";
			filter += '\0';
			filter += '\0';

			std::vector<std::string> output_files = file_via_dialog("Please select where to save the output image",
				filter, false, false, "vhd");

			if(!output_files.empty())
			{
				output_file = output_files[0];
			}			

			selected_via_gui=true;
		}
#endif

		if(!selected_via_gui)
		{
			Tokenize(assemble, input_files, ";");
			output_file = Server->getServerParameter("output_file");
		}

		if(input_files.empty())
		{
			Server->Log("No input files selected", LL_ERROR);
			exit(1);
		}

		if(output_file.empty())
		{
			Server->Log("No output file selected", LL_ERROR);
			exit(1);
		}

		bool b = assemble_vhd(input_files, output_file);		

		exit(b?0:3);
	}


	std::string devinfo=Server->getServerParameter("devinfo");

	if(!devinfo.empty())
	{
		FSNTFS ntfs("\\\\.\\"+devinfo+":", IFSImageFactory::EReadaheadMode_None, false, NULL);
	
		if(!ntfs.hasError())
		{
			Server->Log("Used Space: "+convert(ntfs.calculateUsedSpace())+" of "+convert(ntfs.getSize()));
			Server->Log(convert(((float)ntfs.calculateUsedSpace()/(float)ntfs.getSize())*100.0f)+" %");
		}
	}

	std::string vhdcopy_in=Server->getServerParameter("vhdcopy_in");
	if(!vhdcopy_in.empty())
	{
		Server->Log("VHDCopy.");
		VHDFile in(vhdcopy_in, true,0);
		if(in.isOpen()==false)
		{
			Server->Log("Error opening VHD-File \""+vhdcopy_in+"\"", LL_ERROR);
			exit(4);
		}

		uint64 vhdsize=in.getSize();
		float vhdsize_gb=(vhdsize/1024)/1024.f/1024.f;
		uint64 vhdsize_mb=vhdsize/1024/1024;
		Server->Log("VHD Info: Size: "+convert(vhdsize_gb)+" GB "+convert(vhdsize_mb)+" MB",LL_INFO);
		unsigned int vhd_blocksize=in.getBlocksize();
		
		std::string vhdcopy_out=Server->getServerParameter("vhdcopy_out");
		if(vhdcopy_out.empty())
		{
			Server->Log("'vhdcopy_out' not specified. Not copying.", LL_ERROR);
			exit(5);
		}
		else
		{
			IFile *out=Server->openFile(vhdcopy_out, MODE_RW);
			if(out==NULL)
			{
				Server->Log("Couldn't open output file", LL_ERROR);
				exit(6);
			}
			else
			{
				std::string skip_s=Server->getServerParameter("skip");
				int skip=1024*512;
				if(!skip_s.empty())
				{
					skip=atoi(skip_s.c_str());
				}
				else if (is_disk_mbr(vhdcopy_in + ".mbr"))
				{
					skip = 0;
				}

				Server->Log("Skipping "+convert(skip)+" bytes...", LL_INFO);
				in.Seek(skip);
				char buffer[4096];
				size_t read;
				int last_pc=0;
				int p_skip=0;
				uint64 currpos=skip;
				bool is_ok=true;

				out->Seek(0);
				while(currpos%vhd_blocksize!=0)
				{
					is_ok=in.Read(buffer, 512, read);
					if(read>0)
					{
						_u32 rc=out->Write(buffer, (_u32)read);
						if(rc!=read)
						{
							Server->Log("Writing to output file failed", LL_ERROR);
							exit(7);
						}
					}
					currpos+=read;
				}

				if(currpos!=skip)
				{
					Server->Log("First VHD sector at "+convert(currpos), LL_INFO);
				}

				do
				{
					if(in.has_sector())
					{
						is_ok=in.Read(buffer, 4096, read);
						if(read>0)
						{
							_u32 rc=out->Write(buffer, (_u32)read);
							if(rc!=read)
							{
								Server->Log("Writing to output file failed", LL_ERROR);
								exit(7);
							}
						}
						currpos+=read;
					}
					else
					{
						read=4096;
						currpos+=read;
						in.Seek(currpos);
						out->Seek(currpos-skip);
					}
					
					++p_skip;
					if(p_skip>100)
					{
						p_skip=0;
						int pc=(int)(((float)currpos/(float)vhdsize)*100.f+0.5f);
						if(pc!=last_pc)
						{
							Server->Log(convert(pc)+"%", LL_INFO);
							last_pc=pc;
						}
					}
				}
				while( read==4096 && is_ok );

				Server->destroy(out);
				Server->Log("Copy process finished successfully.", LL_INFO);
				exit(0);
			}
		}
	}
	
	std::string hashfilecomp_1=Server->getServerParameter("hashfilecomp_1");
	if(!hashfilecomp_1.empty())
	{
		IFile *hf1=Server->openFile(hashfilecomp_1, MODE_READ);
		IFile *hf2=Server->openFile(Server->getServerParameter("hashfilecomp_2"), MODE_READ);
		
		if(hf1==NULL || hf2==NULL )
		{
			Server->Log("Error opening hashfile", LL_ERROR);
		}
		else
		{
			size_t h_equal=0;
			size_t h_diff=0;
			_i64 fsize=hf1->Size();
			for(_i64 p=0;p<fsize;p+=32)
			{
				char buf1[32];
				hf1->Read(buf1, 32);
				char buf2[32];
				hf2->Read(buf2, 32);
				if( memcmp(buf1, buf2, 32)==0)
				{
					++h_equal;
				}
				else
				{
					++h_diff;
				}
			}
			
			std::cout << "Hashfile analysis: " << h_equal << " equal hashes; " << h_diff << " differences " << std::endl;
		}
		
		exit(5);
	}
	
	std::string vhdinfo=Server->getServerParameter("vhdinfo");
	if(!vhdinfo.empty())
	{
		std::cout << "--VHDINFO--" << std::endl;
		VHDFile in(vhdinfo, true,0);
		if(in.isOpen()==false)
		{
			Server->Log("Error opening VHD-File \""+vhdinfo+"\"", LL_ERROR);
			exit(4);
		}

		uint64 vhdsize=in.getSize();
		float vhdsize_gb=(vhdsize/1024)/1024.f/1024.f;
		uint64 vhdsize_mb=vhdsize/1024/1024;
		std::cout << ("VHD Info: Size: "+convert(vhdsize_gb)+" GB "+convert(vhdsize_mb)+" MB") << std::endl;
		std::cout << "Blocksize: " << in.getBlocksize() << " Bytes" << std::endl;
		
		uint64 new_blocks=0;
		uint64 total_blocks=0;
		unsigned int bs=in.getBlocksize();
		for(uint64 pos=0;pos<vhdsize;pos+=bs)
		{
			in.Seek(pos);
			if(in.this_has_sector())
			{
				++new_blocks;
			}
			++total_blocks;
		}
		
		std::cout << "Blocks: " << new_blocks << "/" << total_blocks << std::endl;
		exit(3);
	}

	std::string image_verify=Server->getServerParameter("image_verify");
	if(!image_verify.empty())
	{
		std::auto_ptr<IVHDFile> in(open_device_file(image_verify));

		if(in.get()==NULL || in->isOpen()==false)
		{
			Server->Log("Error opening Image-File \""+image_verify+"\"", LL_ERROR);
			exit(4);
		}

		std::string s_hashfile=Server->getServerParameter("hashfile");
		bool has_hashfile=true;
		if(s_hashfile.empty())
		{
			has_hashfile=false;
			s_hashfile=image_verify+".hash";
		}

		IFile *hashfile=Server->openFile(s_hashfile, MODE_READ);
		if(hashfile==NULL)
		{
			Server->Log("Error opening hashfile");
			exit(5);
		}

		bool verify_all = Server->getServerParameter("verify_all")=="true";
		
		if(verify_all)
		{
			Server->Log("Verifying empty blocks");
		}
		
		const int64 vhd_blocksize=(1024*1024)/2;
		int skip=1024*512;
		std::string s_verify_skip = Server->getServerParameter("verify_skip");
		if (!s_verify_skip.empty())
		{
			skip = watoi(s_verify_skip);
		}

		in->Seek(skip);
		uint64 currpos=skip;
		uint64 size=in->getSize();
		sha256_ctx ctx;
		sha256_init(&ctx);
		char buf[512];
		int diff=0;
		int diff_w=0;
		size_t ok_blocks=0;
		int last_pc=0;
		unsigned char dig_z[32];
		bool has_dig_z=false;
		for(;currpos<size;currpos+=vhd_blocksize)
		{
			in->Seek(currpos);
			bool has_sector=verify_all || in->this_has_sector(vhd_blocksize);

			if(!has_sector && !has_dig_z)
			{
				for(unsigned int i=0;i<vhd_blocksize;i+=512)
				{
					size_t read;
					in->Read(buf, 512, read);
					sha256_update(&ctx, (unsigned char*)buf, 512);
				}
				sha256_final(&ctx, dig_z);
				sha256_init(&ctx);
				has_dig_z=true;
			}
			unsigned char dig_r[32];
			unsigned char dig_f[32];

			if(has_sector)
			{
				for(unsigned int i=0;i<vhd_blocksize && currpos+i<size;i+=512)
				{
					size_t read;
					in->Read(buf, 512, read);
					sha256_update(&ctx, (unsigned char*)buf, 512);
				}
				
				_u32 dr=hashfile->Read((char*)dig_f, 32);
				if( dr!=32 )
				{
					Server->Log("Could not read hash from file", LL_ERROR);
				}
				sha256_final(&ctx, dig_r);
				sha256_init(&ctx);
			}
			else
			{
				hashfile->Read((char*)dig_f, 32);
				memcpy(dig_r, dig_z, 32);
			}

			if(memcmp(dig_r, dig_f, 32)!=0)
			{
				++diff;
				Server->Log("Different blocks: "+convert(diff)+" at pos "+convert(currpos)+" has_sector="+convert(has_sector));
			}
			else if(has_sector && has_hashfile)
			{
				++diff_w;
				Server->Log("Wrong difference: "+convert(diff_w)+" at pos "+convert(currpos));
			}
			else
			{
				++ok_blocks;
			}
		
			int pc=(int)((float)((float)currpos/(float)size)*100.f+0.5f);
			if(pc!=last_pc)
			{
				last_pc=pc;
				Server->Log("Checking hashfile: "+convert(pc)+"%");
			}
			
		}
		if(diff==0)
		{
			Server->Log("Hashfile does match");
		}
		Server->Log("Blocks with correct hash: "+convert(ok_blocks));
		Server->Log("Different blocks: "+convert(diff));
		Server->Log("Wrong differences: "+convert(diff_w));
		exit(diff==0?0:7);
	}

	std::string device_verify=Server->getServerParameter("device_verify");
	if(!device_verify.empty())
	{
		std::auto_ptr<IVHDFile> in(open_device_file(device_verify));

		if(in.get()==NULL || in->isOpen()==false)
		{
			Server->Log("Error opening Image-File \""+device_verify+"\"", LL_ERROR);
			exit(4);
		}

		int skip=1024*512;
		FileWrapper wrapper(in.get(), skip);
		FSNTFS fs(&wrapper, IFSImageFactory::EReadaheadMode_None, false, NULL);
		if(fs.hasError())
		{
			Server->Log("Error opening device file", LL_ERROR);
			exit(3);
		}

		PrintInfo(&fs);

		std::string s_hashfile=Server->getServerParameter("hash_file");
		if(s_hashfile.empty())
		{
			s_hashfile = device_verify+".hash";
		}

		IFile *hashfile=Server->openFile(s_hashfile, MODE_READ);
		if(hashfile==NULL)
		{
			Server->Log("Error opening hashfile "+s_hashfile);
			exit(7);
		}

		unsigned int ntfs_blocksize=(unsigned int)fs.getBlocksize();
		unsigned int vhd_sectorsize=(1024*1024)/2;

		uint64 currpos=0;
		uint64 size=fs.getSize();
		sha256_ctx ctx;
		sha256_init(&ctx);
		int diff=0;
		int last_pc=0;
		int mixed=0;
		std::vector<char> zerobuf;
		zerobuf.resize(ntfs_blocksize);
		memset(&zerobuf[0], 0, ntfs_blocksize);

		for(;currpos<size;currpos+=ntfs_blocksize)
		{
			bool has_block=fs.hasBlock(currpos/ntfs_blocksize);

			if(has_block)
			{
				fs_buffer buf(&fs, fs.readBlock(currpos/ntfs_blocksize));

				if(buf.get()==NULL)
				{
					Server->Log("Could not read block "+convert(currpos/ntfs_blocksize), LL_ERROR);
				}
				else
				{
					sha256_update(&ctx, (unsigned char*)buf.get(), ntfs_blocksize);
				}
				mixed = mixed | 1;
			}
			else
			{
				sha256_update(&ctx, (unsigned char*)&zerobuf[0], ntfs_blocksize);

				mixed = mixed | 2;
			}

			if( (currpos+ntfs_blocksize)%vhd_sectorsize==0 )
			{
				unsigned char dig_r[32];
				unsigned char dig_f[32];

				_u32 dr=hashfile->Read((char*)dig_f, 32);
				if( dr!=32 )
				{
					Server->Log("Could not read hash from file", LL_ERROR);
				}

				sha256_final(&ctx, dig_r);
				sha256_init(&ctx);

				if(memcmp(dig_r, dig_f, 32)!=0 && mixed!=2)
				{
					++diff;
					Server->Log("Different blocks: "+convert(diff)+" at pos "+convert(currpos)+" mixed = "+
						(mixed==3? "true":"false")+" ("+convert(mixed)+")" );
				}

				mixed=0;
			}		
		
			int pc=(int)((float)((float)currpos/(float)size)*100.f+0.5f);
			if(pc!=last_pc)
			{
				last_pc=pc;
				Server->Log("Checking device hashsums: "+convert(pc)+"%");
			}
			
		}
		if(diff>0)
		{
			Server->Log("Device does not match hash file");
		}
		Server->Log("Different blocks: "+convert(diff));
		exit(7);
	}

	std::string vhd_cmp=Server->getServerParameter("vhd_cmp");
	if(!vhd_cmp.empty())
	{
		VHDFile in(vhd_cmp, true,0);
		if(in.isOpen()==false)
		{
			Server->Log("Error opening VHD-File \""+vhd_cmp+"\"", LL_ERROR);
			exit(4);
		}

		std::string other=Server->getServerParameter("other");
		VHDFile other_in(other, true,0);
		if(other_in.isOpen()==false)
		{
			Server->Log("Error opening VHD-File \""+other+"\"", LL_ERROR);
			exit(4);
		}

		unsigned int blocksize=in.getBlocksize();
		int skip=1024*512;
		in.Seek(skip);
		other_in.Seek(skip);
		uint64 currpos=skip;
		uint64 size=(std::min)(in.getSize(), other_in.getSize());

		char buf1[512];
		char buf2[512];
		int diff=0;
		int last_pc=0;

		for(;currpos<size;currpos+=blocksize)
		{
			in.Seek(currpos);
			other_in.Seek(currpos);
			bool has_sector=in.this_has_sector() || other_in.this_has_sector();

			if(in.this_has_sector() && !other_in.this_has_sector())
			{
				Server->Log("Sector only in file 1 at pos "+convert(currpos));
			}
			if(!in.this_has_sector() && other_in.this_has_sector())
			{
				Server->Log("Sector only in file 2 at pos "+convert(currpos));
			}

			if(has_sector)
			{
				bool hdiff=false;
				for(unsigned int i=0;i<blocksize;i+=512)
				{
					size_t read;
					in.Read(buf1, 512, read);
					other_in.Read(buf2, 512, read);
					int mr=memcmp(buf1, buf2, 512);
					if(mr!=0)
					{
						int n=0;
						for(size_t i=0;i<512;++i)
						{
							if(buf1[i]!=buf2[i])
							{
								++n;
							}
						}
						if(n==2)
						{
							NTFSFileRecord *fr=(NTFSFileRecord*)buf1;
							if(fr->magic[0]=='F' && fr->magic[1]=='I' && fr->magic[2]=='L' && fr->magic[3]=='E' )
							{
								MFTAttribute attr;
								attr.length=fr->attribute_offset;
								int pos=0;
								do
								{
									pos+=attr.length;
									memcpy((char*)&attr, buf1+pos, sizeof(MFTAttribute) );
									if(attr.type==0x30 && attr.nonresident==0) //FILENAME
									{
										MFTAttributeFilename fn;
										memcpy((char*)&fn, buf1+pos+attr.attribute_offset, sizeof(MFTAttributeFilename) );
										std::string fn_uc;
										fn_uc.resize(fn.filename_length*2);
										memcpy(&fn_uc[0], buf1+pos+attr.attribute_offset+sizeof(MFTAttributeFilename), fn.filename_length*2);
										Server->Log("Filename="+Server->ConvertFromUTF16(fn_uc) , LL_DEBUG);
									}
									Server->Log("Attribute Type: "+convert(attr.type)+" nonresident="+convert(attr.nonresident)+" length="+convert(attr.length), LL_DEBUG);
								}while( attr.type!=0xFFFFFFFF && attr.type!=0x80);
							}

							for(size_t i=0;i<512;++i)
							{
								if(buf1[i]!=buf2[i])
								{
									Server->Log("Position "+convert(i)+": "+convert((int)buf1[i])+"<->"+convert((int)buf2[i]));
								}
							}
						}
						hdiff=true;
						break;
					}
				}
				
				if(hdiff)
				{
					++diff;
					Server->Log("Different blocks: "+convert(diff)+" at pos "+convert(currpos));
				}
			}
		
			int pc=(int)((float)((float)currpos/(float)size)*100.f+0.5f);
			if(pc!=last_pc)
			{
				last_pc=pc;
				Server->Log("Checking hashfile: "+convert(pc)+"%");
			}
			
		}
		Server->Log("Different blocks: "+convert(diff));
		exit(7);
	}

	std::string vhd_fixmftmirr=Server->getServerParameter("vhd_checkmftmirr");
	if(!vhd_fixmftmirr.empty())
	{
		VHDFile vhd(vhd_fixmftmirr, false, 0);
		vhd.addVolumeOffset(1024*512);

		if(vhd.isOpen()==false)
		{
			Server->Log("Could not open VHD file", LL_ERROR);
			exit(7);
		}

		if(Server->getServerParameter("fix")!="true")
		{
			FSNTFS fs(&vhd, IFSImageFactory::EReadaheadMode_None, false, NULL);
			if(fs.hasError())
			{
				Server->Log("NTFS filesystem has errors", LL_ERROR);
			}
			exit(7);
		}
		else
		{
			FSNTFS fs(&vhd, IFSImageFactory::EReadaheadMode_None, false, NULL);
			if(fs.hasError())
			{
				Server->Log("NTFS filesystem has errors", LL_ERROR);
			}
			exit(7);
		}
		exit(0);
	}

#ifdef _DEBUG
	std::string fibmap_test_fn = Server->getServerParameter("fibmap_test");
	if (!fibmap_test_fn.empty())
	{
#ifdef __linux__
		fibmap_test(fibmap_test_fn, Server->getServerParameter("bitmap_source"));
#endif
		exit(0);
	}
#endif

	imagepluginmgr=new CImagePluginMgr;

	Server->RegisterPluginThreadsafeModel( imagepluginmgr, "fsimageplugin");

#ifndef STATIC_PLUGIN
	Server->Log("Loaded -fsimageplugin- plugin", LL_INFO);
#endif
}
void LMDBFileIndex::create(get_data_callback_t get_data_callback, void *userdata)
{
	begin_txn(0);

	IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER_FILES_NEW);

	ServerFilesDao filesdao(db);

	size_t n_done=0;
	size_t n_rows=0;

	SIndexKey last;
	int64 last_prev_entry;
	int64 last_id;
	db_results res;
	do
	{
		res=get_data_callback(n_done, n_rows, userdata);

		++n_rows;

		for(size_t i=0;i<res.size();++i)
		{
			const std::string& shahash=res[i]["shahash"];
			int64 id = watoi64(res[i]["id"]);
			SIndexKey key(reinterpret_cast<const char*>(shahash.c_str()), watoi64(res[i]["filesize"]), watoi(res[i]["clientid"]));

			int64 next_entry = watoi64(res[i]["next_entry"]);
			int64 prev_entry = watoi64(res[i]["prev_entry"]);
			int pointed_to = watoi(res[i]["pointed_to"]);

			assert(memcmp(&last, &key, sizeof(SIndexKey))!=1);

			if(key==last)
			{
				if(last_prev_entry==0)
				{
					filesdao.setPrevEntry(id, last_id);
				}

				if(next_entry==0
					&& (last_prev_entry==0 || last_prev_entry==id) )
				{
					filesdao.setNextEntry(last_id, id);
				}

				if(pointed_to)
				{
					filesdao.setPointedTo(0, id);
				}

				last=key;
				last_id=id;
				last_prev_entry=prev_entry;

				continue;
			}
			else
			{
				if(!pointed_to)
				{
					filesdao.setPointedTo(1, id);
				}
			}
			
			put(key, id, MDB_APPEND);

			if(_has_error)
			{
				Server->Log("LMDB error after putting element. Error state interrupting..", LL_ERROR);
				return;
			}

			if(n_done % 1000 == 0 && n_done>0)
			{
				if ((Server->getFailBits() & IServer::FAIL_DATABASE_CORRUPTED) ||
					(Server->getFailBits() & IServer::FAIL_DATABASE_IOERR) ||
					(Server->getFailBits() & IServer::FAIL_DATABASE_FULL))
				{
					Server->Log("Database error. Stopping.", LL_ERROR);
					return;
				}
				Server->Log("File entry index contains "+convert(n_done)+" entries now.", LL_INFO);
			}

			if(n_done % c_create_commit_n == 0 && n_done>0)
			{
				commit_transaction();
				begin_txn(0);
			}

			++n_done;

			last=key;
			last_id=id;
			last_prev_entry=prev_entry;
		}		
	}
	while(!res.empty());

	commit_transaction();
}
void ServerAutomaticArchive::archiveBackups(void)
{
	db_results res_clients=db->Read("SELECT id FROM clients");
	for(size_t i=0;i<res_clients.size();++i)
	{
		int clientid=watoi(res_clients[i][L"id"]);
		int r_clientid=clientid;
		IQuery *q_get=db->Prepare("SELECT value FROM settings_db.settings WHERE clientid=? AND key=?");
		q_get->Bind(clientid);
		q_get->Bind("overwrite");
		db_results res=q_get->Read();
		q_get->Reset();
		if(res.empty() || res[0][L"value"]!=L"true")
			r_clientid=0;

		q_get->Bind(clientid);
		q_get->Bind("overwrite_archive_settings");
		res=q_get->Read();
		q_get->Reset();
		if(res.empty() || res[0][L"value"]!=L"true")
			r_clientid=0;

		bool archive_settings_copied=false;
		q_get->Bind(clientid);
		q_get->Bind("archive_settings_copied");
		res=q_get->Read();
		if(!res.empty() && res[0][L"value"]==L"true")
			archive_settings_copied=true;

		if(r_clientid==0 && !archive_settings_copied)
		{
			copyArchiveSettings(clientid);
		}

		IQuery *q_get_archived=db->Prepare("SELECT id, next_archival, interval, length, backup_types, archive_window FROM settings_db.automatic_archival WHERE clientid=?");
		q_get_archived->Bind(clientid);
		db_results res_archived=q_get_archived->Read();

		
		for(size_t j=0;j<res_archived.size();++j)
		{
			_i64 next_archival=watoi64(res_archived[j][L"next_archival"]);

			std::wstring &archive_window=res_archived[j][L"archive_window"];
						
			_i64 curr_time=Server->getTimeSeconds();
			if(next_archival<curr_time && (archive_window.empty() || isInArchiveWindow(archive_window)) )
			{
				int backupid=getNonArchivedFileBackup(watoi(res_archived[j][L"backup_types"]), clientid);
				if(backupid!=0)
				{
					int length=watoi(res_archived[j][L"length"]);
					archiveFileBackup(backupid, length);
					Server->Log("Archived file backup with id="+nconvert(backupid)+" for "+nconvert(length)+" seconds", LL_INFO);
					updateInterval(watoi(res_archived[j][L"id"]), watoi(res_archived[j][L"interval"]));
				}
				else
				{
					Server->Log("Did not find file backup suitable for archiving with backup_type="+nconvert(watoi(res_archived[j][L"backup_types"])), LL_INFO);
				}
			}
		}
	}
}
bool ServerAutomaticArchive::isInArchiveWindow(const std::wstring &window_def)
{
	std::vector<std::wstring> toks;
	Tokenize(window_def, toks, L";");
	bool matched_dom=false;
	for(size_t i=0;i<toks.size();++i)
	{
		if(trim(toks[i])==L"*")
			continue;

		std::vector<std::wstring> stoks;
		Tokenize(toks[i], stoks, L",");

		std::vector<int> nums;
		for(size_t j=0;j<stoks.size();++j)
		{
			int n=watoi(stoks[j]);
			if(i==3)//dow
			{
				if(n==7) n=0;
			}
			nums.push_back(n);
		}

		int ref_num=-1;
		if(i==0) // hour
		{
			ref_num=atoi(os_strftime("%H").c_str());
		}
		else if(i==1) // dom
		{
			ref_num=atoi(os_strftime("%d").c_str());
		}
		else if(i==2) // mon
		{
			ref_num=atoi(os_strftime("%m").c_str());
		}
		else if(i==3) // dow
		{
			ref_num=atoi(os_strftime("%w").c_str());
			if(ref_num==7) ref_num=0;
		}

		if( std::find(nums.begin(), nums.end(), ref_num)==nums.end() )
		{
			if(i!=1)
			{
				if(i==3 && matched_dom==true)
					continue;

				return false;
			}
		}
		else
		{
			if(i==1) matched_dom=true;
		}
	}

	return true;
}
void ServerAutomaticArchive::copyArchiveSettings(int clientid)
{
	db_results res_all=db->Read("SELECT id, next_archival, interval, interval_unit, length, length_unit, backup_types, archive_window FROM settings_db.automatic_archival WHERE clientid=0");


	std::vector<std::wstring> next_archivals;
	for(size_t i=0;i<res_all.size();++i)
	{
		std::wstring &interval=res_all[i][L"interval"];
		std::wstring &length=res_all[i][L"length"];
		std::wstring &backup_types=res_all[i][L"backup_types"];
		std::wstring &id=res_all[i][L"id"];
		std::wstring &archive_window=res_all[i][L"archive_window"];
		std::wstring next_archival=res_all[i][L"next_archival"];

		IQuery *q_next=db->Prepare("SELECT next_archival FROM settings_db.automatic_archival WHERE clientid=? AND interval=? AND length=? AND backup_types=? AND archive_window=?");
		IQuery *q_num=db->Prepare("SELECT count(*) AS num FROM settings_db.automatic_archival WHERE clientid=0 AND interval=? AND length=? AND backup_types=? AND archive_window=? AND id<?");

		q_num->Bind(interval);
		q_num->Bind(length);
		q_num->Bind(backup_types);
		q_num->Bind(archive_window);
		q_num->Bind(id);
		db_results res_num=q_num->Read();
		int num=watoi(res_num[0][L"num"]);

		q_next->Bind(clientid);
		q_next->Bind(interval);
		q_next->Bind(length);
		q_next->Bind(backup_types);
		q_next->Bind(archive_window);


		db_results res_next=q_next->Read();
		if((size_t)num<res_next.size())
		{
			next_archival=res_next[num][L"next_archival"];
			_i64 na=watoi64(next_archival);
			if(na==0)
			{
				next_archival=convert(Server->getTimeSeconds());
			}
		}

		next_archivals.push_back(next_archival);
	}


	IQuery *q_del_all=db->Prepare("DELETE FROM settings_db.automatic_archival WHERE clientid=?");
	IQuery *q_insert_all=db->Prepare("INSERT INTO settings_db.automatic_archival (next_archival, interval, interval_unit, length, length_unit, backup_types, clientid, archive_window)"
									"VALUES (?,?,?,?,?,?,?,?)");

	q_del_all->Bind(clientid);
	q_del_all->Write();

	for(size_t i=0;i<res_all.size();++i)
	{
		std::wstring &interval=res_all[i][L"interval"];
		std::wstring &length=res_all[i][L"length"];
		std::wstring &backup_types=res_all[i][L"backup_types"];		
		std::wstring &archive_window=res_all[i][L"archive_window"];

		q_insert_all->Bind(next_archivals[i]);
		q_insert_all->Bind(interval);
		q_insert_all->Bind(res_all[i][L"interval_unit"]);
		q_insert_all->Bind(length);
		q_insert_all->Bind(res_all[i][L"length_unit"]);
		q_insert_all->Bind(backup_types);
		q_insert_all->Bind(clientid);
		q_insert_all->Bind(archive_window);		
		q_insert_all->Write();
		q_insert_all->Reset();
	}	

	IQuery *q_insert_copied=db->Prepare("INSERT INTO settings_db.settings (key, value, clientid) VALUES ('archive_settings_copied','true',?)");
	q_insert_copied->Bind(clientid);
	q_insert_copied->Write();
}