void process_file(const char* path) { struct stat stat; if (::lstat(path, &stat) != 0) { fprintf(stderr, "Could not stat file \"%s\": %s\n", path, strerror(errno)); return; } if (S_ISDIR(stat.st_mode)) { process_directory(path); return; } if (S_ISLNK(stat.st_mode)) return; int file = open(path, O_RDONLY); if (file < 0) { fprintf(stderr, "Could not open file \"%s\": %s\n", path, strerror(errno)); return; } status_t status = gSHA.Process(file); if (status != B_OK) { fprintf(stderr, "Computing SHA failed \"%s\": %s\n", path, strerror(status)); return; } file_entry entry; memcpy(entry.hash, gSHA.Digest(), SHA_DIGEST_LENGTH); entry.node = stat.st_ino; entry.path = path; //printf("%s %s\n", entry.HashString().c_str(), path); gFiles.push_back(entry); static bigtime_t sLastUpdate = -1; if (system_time() - sLastUpdate > 500000) { printf("%ld files scanned\33[1A\n", gFiles.size()); sLastUpdate = system_time(); } }
void process_file(const file_entry& entry, int number) { struct stat stat; if (::stat(entry.path.c_str(), &stat) != 0) { fprintf(stderr, "Could not stat file \"%s\": %s\n", entry.path.c_str(), strerror(errno)); return; } if (stat.st_ino != entry.node) { fprintf(stderr, "\"%s\": inode changed from %Ld to %Ld\n", entry.path.c_str(), entry.node, stat.st_ino); } int file = open(entry.path.c_str(), O_RDONLY); if (file < 0) { fprintf(stderr, "Could not open file \"%s\": %s\n", entry.path.c_str(), strerror(errno)); return; } status_t status = gSHA.Process(file); if (status != B_OK) { fprintf(stderr, "Computing SHA failed \"%s\": %s\n", entry.path.c_str(), strerror(status)); return; } if (memcmp(entry.hash, gSHA.Digest(), SHA_DIGEST_LENGTH)) fprintf(stderr, "\"%s\": Contents differ!\n", entry.path.c_str()); static bigtime_t sLastUpdate = -1; if (system_time() - sLastUpdate > 500000) { printf("%ld files scanned\33[1A\n", number); sLastUpdate = system_time(); } }
int main(int argc, char** argv) { if (argc < 2) { fprintf(stderr, "usage: %s <hash-file> [<files> ...]\n" "\tWhen invoked without files, the hash-file is updated only.\n", kProgramName); return 1; } const char* hashFileName = argv[1]; status_t status = gSHA.Init(); if (status != B_OK) { fprintf(stderr, "%s: Could not initialize SHA processor: %s\n", kProgramName, strerror(status)); return 1; } int fileCount = argc - 2; char** files = argv + 2; if (argc == 2) { // read files from hash file int file = open(hashFileName, O_RDONLY); if (file < 0) { fprintf(stderr, "%s: Could not open hash file \"%s\": %s\n", kProgramName, hashFileName, strerror(status)); return 1; } char buffer[2048]; read(file, buffer, 4); if (memcmp(buffer, "HASH", 4)) { fprintf(stderr, "%s: \"%s\" is not a hash file\n", kProgramName, hashFileName); close(file); return 1; } read(file, &fileCount, sizeof(int)); TRACE("Found %d path(s):\n", fileCount); files = (char**)malloc(fileCount * sizeof(char*)); if (files == NULL) { fprintf(stderr, "%s: Could not allocate %ld bytes\n", kProgramName, fileCount * sizeof(char*)); close(file); return 1; } for (int i = 0; i < fileCount; i++) { int length; read(file, &length, sizeof(int)); files[i] = (char*)malloc(length + 1); if (files[i] == NULL) { fprintf(stderr, "%s: Could not allocate %d bytes\n", kProgramName, length + 1); close(file); // TODO: we actually leak memory here, but it's not important in this context return 1; } read(file, files[i], length + 1); TRACE("\t%s\n", files[i]); } close(file); } else { // Normalize paths char** normalizedFiles = (char**)malloc(fileCount * sizeof(char*)); if (normalizedFiles == NULL) { fprintf(stderr, "%s: Could not allocate %ld bytes\n", kProgramName, fileCount * sizeof(char*)); return 1; } for (int i = 0; i < fileCount; i++) { BPath path(files[i], NULL, true); normalizedFiles[i] = strdup(path.Path()); if (normalizedFiles[i] == NULL) { fprintf(stderr, "%s: Could not allocate %ld bytes\n", kProgramName, strlen(path.Path()) + 1); return 1; } } files = normalizedFiles; } bigtime_t start = system_time(); for (int i = 0; i < fileCount; i++) { process_file(files[i]); } sort(gFiles.begin(), gFiles.end()); bigtime_t runtime = system_time() - start; write_hash_file(hashFileName, fileCount, files); if (gFiles.size() > 0) { printf("Generated hashes for %ld files in %g seconds, %g msec per " "file.\n", gFiles.size(), runtime / 1000000.0, runtime / 1000.0 / gFiles.size()); } for (int i = 0; i < fileCount; i++) { free(files[i]); } free(files); return 0; }
int main(int argc, char** argv) { if (argc != 2) { fprintf(stderr, "usage: %s <hash-file>\n", kProgramName); return 1; } const char* hashFileName = argv[1]; status_t status = gSHA.Init(); if (status != B_OK) { fprintf(stderr, "%s: Could not initialize SHA processor: %s\n", kProgramName, strerror(status)); return 1; } // read files from hash file int file = open(hashFileName, O_RDONLY); if (file < 0) { fprintf(stderr, "%s: Could not open hash file \"%s\": %s\n", kProgramName, hashFileName, strerror(status)); return 1; } char buffer[2048]; read(file, buffer, 4); if (memcmp(buffer, "HASH", 4)) { fprintf(stderr, "%s: \"%s\" is not a hash file\n", kProgramName, hashFileName); close(file); return 1; } int fileCount; read(file, &fileCount, sizeof(int)); TRACE("Skip %d path(s)\n", fileCount); // Skip paths, we don't need it for the consistency check for (int i = 0; i < fileCount; i++) { int length; read(file, &length, sizeof(int)); lseek(file, length + 1, SEEK_CUR); } // Read file names and their hash read(file, &fileCount, sizeof(int)); TRACE("Found %d file(s)\n", fileCount); for (int i = 0; i < fileCount; i++) { file_entry entry; read(file, entry.hash, SHA_DIGEST_LENGTH); read(file, &entry.node, sizeof(ino_t)); int length; read(file, &length, sizeof(int)); read(file, buffer, length + 1); entry.path = buffer; gFiles.push_back(entry); } close(file); bigtime_t start = system_time(); for (int i = 0; i < fileCount; i++) { process_file(gFiles[i], i); } bigtime_t runtime = system_time() - start; if (gFiles.size() > 0) { printf("Consistency check for %ld files in %g seconds, %g msec per " "file.\n", gFiles.size(), runtime / 1000000.0, runtime / 1000.0 / gFiles.size()); } return 0; }