/* print file list */ void dir_print_file_list(FILE *out, const parray *files, const char *root, const char *prefix) { int i; int root_len = 0; /* calculate length of root directory portion */ if (root) { root_len = strlen(root); if (root[root_len - 1] != '/') root_len++; } /* print each file in the list */ for (i = 0; i < parray_num(files); i++) { pgFile *file = (pgFile *)parray_get(files, i); char path[MAXPGPATH]; char *ptr = file->path; char type; /* omit root directory portion */ if (root && strstr(ptr, root) == ptr) ptr = JoinPathEnd(ptr, root); /* append prefix if not NULL */ if (prefix) join_path_components(path, prefix, ptr); else strcpy(path, ptr); if (S_ISREG(file->mode) && file->is_datafile) type = 'F'; else if (S_ISREG(file->mode) && !file->is_datafile) type = 'f'; else if (S_ISDIR(file->mode)) type = 'd'; else if (S_ISLNK(file->mode)) type = 'l'; else type = '?'; fprintf(out, "%s %c %lu %u 0%o", path, type, (unsigned long) file->write_size, file->crc, file->mode & (S_IRWXU | S_IRWXG | S_IRWXO)); if (S_ISLNK(file->mode)) fprintf(out, " %s\n", file->linked); else { char timestamp[20]; time2iso(timestamp, 20, file->mtime); fprintf(out, " %s\n", timestamp); } } }
void pgFileDump(pgFile *file, FILE *out) { char mtime_str[100]; fprintf(out, "=================\n"); if (file) { time2iso(mtime_str, 100, file->mtime); fprintf(out, "mtime=%lu(%s)\n", file->mtime, mtime_str); fprintf(out, "size=" UINT64_FORMAT "\n", (uint64)file->size); fprintf(out, "read_size=" UINT64_FORMAT "\n", (uint64)file->read_size); fprintf(out, "write_size=" UINT64_FORMAT "\n", (uint64)file->write_size); fprintf(out, "mode=0%o\n", file->mode); fprintf(out, "crc=%u\n", file->crc); fprintf(out, "is_datafile=%s\n", file->is_datafile ? "true" : "false"); fprintf(out, "linked=\"%s\"\n", file->linked ? file->linked : "nil"); fprintf(out, "path=\"%s\"\n", file->path); } fprintf(out, "=================\n"); }
/* * Delete backup files of the backup and update the status of the backup to * BACKUP_STATUS_DELETED. */ static int pgBackupDeleteFiles(pgBackup *backup) { int i; char path[MAXPGPATH]; char timestamp[20]; parray *files; /* * If the backup was deleted already, there is nothing to do. */ if (backup->status == BACKUP_STATUS_DELETED) return 0; time2iso(timestamp, lengthof(timestamp), backup->start_time); elog(INFO, "delete: %s", timestamp); /* * Update STATUS to BACKUP_STATUS_DELETING in preparation for the case which * the error occurs before deleting all backup files. */ if (!check) { backup->status = BACKUP_STATUS_DELETING; pgBackupWriteIni(backup); } /* list files to be deleted */ files = parray_new(); pgBackupGetPath(backup, path, lengthof(path), DATABASE_DIR); dir_list_file(files, path, NULL, true, true); /* delete leaf node first */ parray_qsort(files, pgFileComparePathDesc); for (i = 0; i < parray_num(files); i++) { pgFile *file = (pgFile *) parray_get(files, i); /* print progress */ elog(LOG, "delete file(%d/%lu) \"%s\"", i + 1, (unsigned long) parray_num(files), file->path); /* skip actual deletion in check mode */ if (!check) { if (remove(file->path)) { elog(WARNING, "can't remove \"%s\": %s", file->path, strerror(errno)); parray_walk(files, pgFileFree); parray_free(files); return 1; } } } /* * After deleting all of the backup files, update STATUS to * BACKUP_STATUS_DELETED. */ if (!check) { backup->status = BACKUP_STATUS_DELETED; pgBackupWriteIni(backup); } parray_walk(files, pgFileFree); parray_free(files); return 0; }
/* * Validate each files in the backup with its size. */ void pgBackupValidate(pgBackup *backup, bool size_only, bool for_get_timeline, bool with_database) { char timestamp[100]; char base_path[MAXPGPATH]; char path[MAXPGPATH]; parray *files; bool corrupted = false; time2iso(timestamp, lengthof(timestamp), backup->start_time); if(!for_get_timeline) { if (with_database) elog(INFO, "validate: %s backup and archive log files by %s", timestamp, (size_only ? "SIZE" : "CRC")); else { if (backup->backup_mode == BACKUP_MODE_ARCHIVE) elog(INFO, "validate: %s archive log files by %s", timestamp, (size_only ? "SIZE" : "CRC")); else if (backup->with_serverlog) elog(INFO, "validate: %s server log files by %s", timestamp, (size_only ? "SIZE" : "CRC")); } } if(!check) { if (HAVE_DATABASE(backup)) { elog(LOG, "database files..."); pgBackupGetPath(backup, base_path, lengthof(base_path), DATABASE_DIR); pgBackupGetPath(backup, path, lengthof(path), DATABASE_FILE_LIST); files = dir_read_file_list(base_path, path); if (!pgBackupValidateFiles(files, base_path, size_only)) corrupted = true; parray_walk(files, pgFileFree); parray_free(files); } if (HAVE_ARCLOG(backup)) { elog(LOG, "archive WAL files..."); pgBackupGetPath(backup, base_path, lengthof(base_path), ARCLOG_DIR); pgBackupGetPath(backup, path, lengthof(path), ARCLOG_FILE_LIST); files = dir_read_file_list(base_path, path); if (!pgBackupValidateFiles(files, base_path, size_only)) corrupted = true; parray_walk(files, pgFileFree); parray_free(files); } if (backup->with_serverlog) { elog(LOG, "server log files..."); pgBackupGetPath(backup, base_path, lengthof(base_path), SRVLOG_DIR); pgBackupGetPath(backup, path, lengthof(path), SRVLOG_FILE_LIST); files = dir_read_file_list(base_path, path); if (!pgBackupValidateFiles(files, base_path, size_only)) corrupted = true; parray_walk(files, pgFileFree); parray_free(files); } /* update status to OK */ if (corrupted) backup->status = BACKUP_STATUS_CORRUPT; else backup->status = BACKUP_STATUS_OK; pgBackupWriteIni(backup); if (corrupted) elog(WARNING, "backup %s is corrupted", timestamp); else elog(LOG, "backup %s is valid", timestamp); } }