/************************************************************************* * UrBackup - Client/Server backup system * Copyright (C) 2011-2016 Martin Raiber * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * **************************************************************************/ #include "action_header.h" #include "../../urbackupcommon/os_functions.h" #include "../../Interface/File.h" #include "backups.h" #include #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES #include "../../common/miniz/miniz.h" #include "../../common/miniz/miniz_zip.h" #ifndef _WIN32 #define _fdopen fdopen #else #include #include #endif namespace { struct MiniZFileInfo { uint64 file_offset; THREAD_ID tid; }; size_t my_mz_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { MiniZFileInfo* fileInfo = reinterpret_cast(pOpaque); if(fileInfo->file_offset!=file_ofs) { return 0; } fileInfo->file_offset=file_ofs+n; bool b=Server->WriteRaw(fileInfo->tid, reinterpret_cast(pBuf), n, false); return b?n:0; } bool my_miniz_init(mz_zip_archive *pZip, MiniZFileInfo* fileInfo) { pZip->m_pWrite = my_mz_write_func; pZip->m_pIO_opaque = fileInfo; if (!mz_zip_writer_init(pZip, 0, MZ_ZIP_FLAG_CASE_SENSITIVE)) return false; return true; } bool add_dir(mz_zip_archive& zip_archive, const std::string& archivefoldername, const std::string& folderbase, const std::string& foldername, const std::string& hashfolderbase, const std::string& hashfoldername, const std::string& filter, bool token_authentication, const std::vector &backup_tokens, const std::vector &tokens, bool skip_special) { bool has_error=false; const std::vector files = getFiles(os_file_prefix(foldername), &has_error); if (has_error) { Server->Log("Error while adding files to ZIP file. Error listing files in folder \"" + foldername+"\". " + os_last_error_str(), LL_ERROR); return false; } for(size_t i=0;iLog("Error opening symlink target \""+filename+"\" of symlink at \"" + filename_old + "\"", LL_INFO); continue; } if (is_dir_link) { metadataname = hashfolderbase + os_file_sep() + symlink_target + os_file_sep() + metadata_dir_fn; next_hashfoldername = hashfolderbase + os_file_sep() + symlink_target; } else { metadataname = hashfolderbase + os_file_sep() + symlink_target; } } else { Server->Log("Error getting symlink target of \"" + filename + "\". "+os_last_error_str(), LL_ERROR); continue; } } bool has_metadata = false; FileMetadata metadata; if(token_authentication && ( !read_metadata(metadataname, metadata) || !backupaccess::checkFileToken(backup_tokens, tokens, metadata) ) ) { continue; } else if(!token_authentication) { has_metadata = read_metadata(metadataname, metadata); } else { has_metadata = true; } time_t* last_modified=NULL; time_t last_modified_wt; if(has_metadata) { #ifdef _WIN32 last_modified_wt=static_cast(metadata.last_modified); #else last_modified_wt=static_cast(metadata.last_modified); #endif last_modified=&last_modified_wt; } mz_bool rc; if(file.isdir) { rc = mz_zip_writer_add_mem_ex(&zip_archive, (archivename + "/").c_str(), NULL, 0, NULL, 0, MZ_DEFAULT_LEVEL, 0, 0, 1<<11, last_modified); } else { std::auto_ptr add_file(Server->openFile(os_file_prefix(filename))); if (add_file.get() == NULL) { Server->Log("Error opening file \"" + filename + "\" for ZIP file download." + os_last_error_str(), LL_ERROR); return false; } #ifndef _WIN32 int fd = reinterpret_cast(add_file->getOsHandle()); #else int fd =_open_osfhandle(reinterpret_cast(add_file->getOsHandle()), _O_RDONLY); if (fd == -1) { Server->Log("Error opening file fd for \"" + filename + "\" for ZIP file download." + os_last_error_str(), LL_ERROR); return false; } #endif FILE* file = _fdopen(fd, "r"); if (file != NULL) { rc = mz_zip_writer_add_cfile(&zip_archive, archivename.c_str(), file, add_file->Size(), last_modified, NULL, 0, MZ_DEFAULT_LEVEL); fclose(file); } else { Server->Log("Error opening FILE handle for \"" + filename + "\" for ZIP file download." + os_last_error_str(), LL_ERROR); return false; } } if(rc==MZ_FALSE) { Server->Log("Error while adding file \""+filename+"\" to ZIP file. RC="+convert((int)rc), LL_ERROR); return false; } if(file.isdir) { add_dir(zip_archive, archivename, folderbase, filename, hashfolderbase, next_hashfoldername, filter, token_authentication, backup_tokens, tokens, false); } } return true; } } bool create_zip_to_output(const std::string& folderbase, const std::string& foldername, const std::string& hashfolderbase, const std::string& hashfoldername, const std::string& filter, bool token_authentication, const std::vector &backup_tokens, const std::vector &tokens, bool skip_hashes) { mz_zip_archive zip_archive; memset(&zip_archive, 0, sizeof(zip_archive)); MiniZFileInfo file_info = {}; file_info.tid=Server->getThreadID(); if(!my_miniz_init(&zip_archive, &file_info)) { Server->Log("Error while initializing ZIP archive", LL_ERROR); return false; } if(!add_dir(zip_archive, "", folderbase, foldername, hashfolderbase, hashfoldername, filter, token_authentication, backup_tokens, tokens, skip_hashes)) { Server->Log("Error while adding files and folders to ZIP archive", LL_ERROR); return false; } if(!mz_zip_writer_finalize_archive(&zip_archive)) { Server->Log("Error while finalizing ZIP archive", LL_ERROR); return false; } if(!mz_zip_writer_end(&zip_archive)) { Server->Log("Error while ending ZIP archive writer", LL_ERROR); return false; } return true; }