9 #define _FILE_OFFSET_BITS 64
11 #include "cvmfs_config.h"
69 "CernVM File System consistency checker, version %s\n\n"
70 "This tool checks a cvmfs cache directory for consistency.\n"
71 "If necessary, the managed cache db is removed so that\n"
72 "it will be rebuilt on next mount.\n\n"
73 "Usage: cvmfs_fsck [-v] [-p] [-f] [-j #threads] <cache directory>\n"
75 " -v verbose output\n"
76 " -p try to fix automatically\n"
77 " -f force rebuild of managed cache db on next mount\n"
78 " -j number of concurrent integrity check worker threads\n",
83 static bool GetNextFile(
string *relative_path,
string *hash_name) {
89 const string name = d->d_name;
90 if ((name ==
".") || (name ==
".."))
continue;
95 const string path = *
g_cache_dir +
"/" + *relative_path;
102 if (!S_ISREG(info.st_mode)) {
119 snprintf(hex,
sizeof(hex),
"%02x",
g_num_dirs);
127 "Invalid cache directory, %s/%s does not exist",
131 goto get_next_file_again;
140 string relative_path;
144 const string path = *
g_cache_dir +
"/" + relative_path;
152 if (relative_path[relative_path.length()-1] ==
'T') {
154 "Warning: temporary file catalog %s found", path.c_str());
157 if (unlink(relative_path.c_str()) == 0) {
169 int fd_src = open(relative_path.c_str() , O_RDONLY);
186 if (hash != expected_hash) {
193 if (hash != expected_hash) {
195 const string quarantaine_path =
"./quarantaine/" + hash_name;
197 if (rename(relative_path.c_str(), quarantaine_path.c_str()) == 0) {
199 "Fix: %s is corrupted, moved to quarantaine folder",
204 "Warning: failed to move %s into quarantaine folder",
206 if (unlink(relative_path.c_str()) == 0) {
208 "Fix: %s is corrupted, file unlinked", path.c_str());
212 "Error: %s is corrupted, could not unlink",
228 "Error: %s has compressed checksum %s, "
229 "delete this file from cache directory!",
230 path.c_str(), hash.
ToString().c_str());
243 int main(
int argc,
char **argv) {
249 while ((c = getopt(argc, argv,
"hvpfj:")) != -1) {
267 "There is at least one worker thread required");
279 if (optind >= argc) {
292 if ((dirp_txn = opendir(
"txn")) == NULL) {
294 "Invalid cache directory, %s/txn does not exist",
300 const string name = d->d_name;
301 if ((name ==
".") || (name ==
".."))
continue;
304 "Warning: temporary directory %s/txn is not empty\n"
305 "If this repository is currently _not_ mounted, "
306 "you can remove its contents",
g_cache_dir->c_str());
317 pthread_t *workers =
reinterpret_cast<pthread_t *
>(
324 if (pthread_create(&workers[i], NULL,
MainCheck, NULL) != 0) {
329 for (
int i = g_num_threads-1; i >= 0; --i) {
330 pthread_join(workers[i], NULL);
344 if (unlink(
"cachedb") == 0) {
346 "Fix: managed cache db unlinked, will be rebuilt on next mount");
349 if (errno != ENOENT) {
351 "Error: could not unlink managed cache database (%d)", errno);
359 "WARNING: There might by corrupted files in the kernel buffers.\n"
360 "Remount CernVM-FS or run 'echo 3 > /proc/sys/vm/drop_caches'"
bool HashFile(const std::string &filename, Any *any_digest)
static void Usage(const char *progname)
std::string ToString(const bool with_suffix=false) const
struct cvmcache_object_info __attribute__
atomic_int32 g_num_err_fixed
atomic_int32 g_num_tmp_catalog
bool CompressFd2Null(int fd_src, shash::Any *compressed_hash, uint64_t *processed_bytes)
static bool GetNextFile(string *relative_path, string *hash_name)
static void * MainCheck(void *data __attribute__((unused)))
pthread_mutex_t g_lock_traverse
atomic_int32 g_force_rebuild
atomic_int32 g_modified_cache
Any MkFromHexPtr(const HexPtr hex, const char suffix)
std::string MakeCanonicalPath(const std::string &path)
atomic_int32 g_num_err_operational
atomic_int32 g_num_err_unfixed
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)