static int verify_object(struct conf *conf, struct manifest *mf, struct object *obj, struct hashtable *stated_files, struct hashtable *hashed_files) { for (uint32_t i = 0; i < obj->n_file_info_indexes; i++) { struct file_info *fi = &mf->file_infos[obj->file_info_indexes[i]]; char *path = mf->files[fi->index]; struct file_stats *st = hashtable_search(stated_files, path); if (!st) { struct stat file_stat; if (x_stat(path, &file_stat) != 0) { return 0; } st = x_malloc(sizeof(*st)); st->size = file_stat.st_size; st->mtime = file_stat.st_mtime; st->ctime = file_stat.st_ctime; hashtable_insert(stated_files, x_strdup(path), st); } if (fi->size != st->size) { return 0; } if (conf->sloppiness & SLOPPY_FILE_STAT_MATCHES) { if (fi->mtime == st->mtime && fi->ctime == st->ctime) { cc_log("mtime/ctime hit for %s", path); continue; } else { cc_log("mtime/ctime miss for %s", path); } } struct file_hash *actual = hashtable_search(hashed_files, path); if (!actual) { struct mdfour hash; hash_start(&hash); int result = hash_source_code_file(conf, &hash, path); if (result & HASH_SOURCE_CODE_ERROR) { cc_log("Failed hashing %s", path); return 0; } if (result & HASH_SOURCE_CODE_FOUND_TIME) { return 0; } actual = x_malloc(sizeof(*actual)); hash_result_as_bytes(&hash, actual->hash); actual->size = hash.totalN; hashtable_insert(hashed_files, x_strdup(path), actual); } if (memcmp(fi->hash, actual->hash, mf->hash_size) != 0 || fi->size != actual->size) { return 0; } } return 1; }
/**************************************************************************** Create a directory given an absolute path, perms based upon another directory path ****************************************************************************/ int make_bak_dir(const char *fullpath) { char fbuf[MAXPATHLEN], *rel, *end, *p; struct file_struct *file; int len = backup_dir_len; stat_x sx; while (*fullpath == '.' && fullpath[1] == '/') { fullpath += 2; len -= 2; } if (strlcpy(fbuf, fullpath, sizeof fbuf) >= sizeof fbuf) return -1; rel = fbuf + len; end = p = rel + strlen(rel); /* Try to find an existing dir, starting from the deepest dir. */ while (1) { if (--p == fbuf) return -1; if (*p == '/') { *p = '\0'; if (mkdir_defmode(fbuf) == 0) break; if (errno != ENOENT) { rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed", full_fname(fbuf)); return -1; } } } /* Make all the dirs that we didn't find on the way here. */ while (1) { if (p >= rel) { /* Try to transfer the directory settings of the * actual dir that the files are coming from. */ if (x_stat(rel, &sx.st, NULL) < 0) { rsyserr(FERROR, errno, "make_bak_dir stat %s failed", full_fname(rel)); } else { #ifdef SUPPORT_ACLS sx.acc_acl = sx.def_acl = NULL; #endif #ifdef SUPPORT_XATTRS sx.xattr = NULL; #endif if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS))) continue; #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { get_acl(rel, &sx); cache_tmp_acl(file, &sx); free_acl(&sx); } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { get_xattr(rel, &sx); cache_tmp_xattr(file, &sx); free_xattr(&sx); } #endif set_file_attrs(fbuf, file, NULL, NULL, 0); unmake_file(file); #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif } } *p = '/'; p += strlen(p); if (p == end) break; if (mkdir_defmode(fbuf) < 0) { rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed", full_fname(fbuf)); return -1; } } return 0; }
static int verify_object(struct conf *conf, struct manifest *mf, struct object *obj, struct hashtable *stated_files, struct hashtable *hashed_files) { for (uint32_t i = 0; i < obj->n_file_info_indexes; i++) { struct file_info *fi = &mf->file_infos[obj->file_info_indexes[i]]; char *path = mf->files[fi->index]; struct file_stats *st = hashtable_search(stated_files, path); if (!st) { struct stat file_stat; if (x_stat(path, &file_stat) != 0) { return 0; } st = x_malloc(sizeof(*st)); st->size = file_stat.st_size; st->mtime = file_stat.st_mtime; st->ctime = file_stat.st_ctime; hashtable_insert(stated_files, x_strdup(path), st); } if (fi->size != st->size) { return 0; } // Clang stores the mtime of the included files in the precompiled header, // and will error out if that header is later used without rebuilding. if ((guessed_compiler == GUESSED_CLANG || guessed_compiler == GUESSED_UNKNOWN) && output_is_precompiled_header && fi->mtime != st->mtime) { cc_log("Precompiled header includes %s, which has a new mtime", path); return 0; } if (conf->sloppiness & SLOPPY_FILE_STAT_MATCHES) { if (!(conf->sloppiness & SLOPPY_FILE_STAT_MATCHES_CTIME)) { if (fi->mtime == st->mtime && fi->ctime == st->ctime) { cc_log("mtime/ctime hit for %s", path); continue; } else { cc_log("mtime/ctime miss for %s", path); } } else { if (fi->mtime == st->mtime) { cc_log("mtime hit for %s", path); continue; } else { cc_log("mtime miss for %s", path); } } } struct file_hash *actual = hashtable_search(hashed_files, path); if (!actual) { struct hash *hash = hash_init(); int result = hash_source_code_file(conf, hash, path); if (result & HASH_SOURCE_CODE_ERROR) { cc_log("Failed hashing %s", path); hash_free(hash); return 0; } if (result & HASH_SOURCE_CODE_FOUND_TIME) { hash_free(hash); return 0; } actual = x_malloc(sizeof(*actual)); hash_result_as_bytes(hash, actual->hash); actual->size = hash_input_size(hash); hashtable_insert(hashed_files, x_strdup(path), actual); hash_free(hash); } if (memcmp(fi->hash, actual->hash, mf->hash_size) != 0 || fi->size != actual->size) { return 0; } } return 1; }
/* Create a backup path from the given fname, putting the result into * backup_dir_buf. Any new directories (compared to the prior backup * path) are ensured to exist as directories, replacing anything else * that may be in the way (e.g. a symlink). */ static BOOL copy_valid_path(const char *fname) { const char *f; int val; BOOL ret = True; stat_x sx; char *b, *rel = backup_dir_buf + backup_dir_len, *name = rel; for (f = fname, b = rel; *f && *f == *b; f++, b++) { if (*b == '/') name = b + 1; } if (stringjoin(rel, backup_dir_remainder, fname, backup_suffix, NULL) >= backup_dir_remainder) { rprintf(FERROR, "backup filename too long\n"); *name = '\0'; return False; } for ( ; ; name = b + 1) { if ((b = strchr(name, '/')) == NULL) return True; *b = '\0'; val = validate_backup_dir(); if (val == 0) break; if (val < 0) { *name = '\0'; return False; } *b = '/'; } init_stat_x(&sx); for ( ; b; name = b + 1, b = strchr(name, '/')) { *b = '\0'; while (do_mkdir(backup_dir_buf, ACCESSPERMS) < 0) { if (errno == EEXIST) { val = validate_backup_dir(); if (val > 0) break; if (val == 0) continue; } else rsyserr(FERROR, errno, "backup mkdir %s failed", backup_dir_buf); *name = '\0'; ret = False; goto cleanup; } /* Try to transfer the directory settings of the actual dir * that the files are coming from. */ if (x_stat(rel, &sx.st, NULL) < 0) rsyserr(FERROR, errno, "backup stat %s failed", full_fname(rel)); else { struct file_struct *file; if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS))) continue; #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { get_acl(rel, &sx); cache_tmp_acl(file, &sx); free_acl(&sx); } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { get_xattr(rel, &sx); cache_tmp_xattr(file, &sx); free_xattr(&sx); } #endif set_file_attrs(backup_dir_buf, file, NULL, NULL, 0); unmake_file(file); } *b = '/'; } cleanup: #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif return ret; }