From patchwork Thu Apr 4 16:31:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Filipe Manana X-Patchwork-Id: 10885935 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8146017E0 for ; Thu, 4 Apr 2019 16:31:16 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6BB7328AC2 for ; Thu, 4 Apr 2019 16:31:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6053528AC8; Thu, 4 Apr 2019 16:31:16 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D21EB28AC2 for ; Thu, 4 Apr 2019 16:31:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728811AbfDDQbP (ORCPT ); Thu, 4 Apr 2019 12:31:15 -0400 Received: from mail.kernel.org ([198.145.29.99]:38264 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727039AbfDDQbP (ORCPT ); Thu, 4 Apr 2019 12:31:15 -0400 Received: from localhost.localdomain (bl8-197-74.dsl.telepac.pt [85.241.197.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 24AF7206BA; Thu, 4 Apr 2019 16:31:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1554395474; bh=AGA07ANO0FIkcVyU8JUBPzKluABHYo70Xsvl7FjzsEE=; h=From:To:Cc:Subject:Date:From; b=zq5QXuNLgDbgi5cNmZtbR7qSDaBnQwSA2KNE6VPxhf9SBap0BIZJGRUppnje+Lu4u 4EjR4f1nJtFG/Y5u47+vkbiEfUDqIN6l4JKHFk2B34puecbNqCitQ20WI8CLBCVZhF vJIZ5S5hwokFWCCZY2K6wY3ivsdwAzcEPUtjRE6k= From: fdmanana@kernel.org To: fstests@vger.kernel.org Cc: linux-btrfs@vger.kernel.org, Filipe Manana Subject: [PATCH v3 7/7] fssum: add support for checking xattrs Date: Thu, 4 Apr 2019 17:31:09 +0100 Message-Id: <20190404163109.19339-1-fdmanana@kernel.org> X-Mailer: git-send-email 2.11.0 Sender: fstests-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Filipe Manana Currently fssum, mostly used for btrfs test cases that test the btrfs send feature, ignores completely the existence of xattrs. This change teaches fssum to find xattrs and make them contribute to the checksum of a filesystem, so that we can catch filesystem bugs regarding missing, corrupt or not supposed to exist xattrs (i.e. that an incremental btrfs send does not forget to create, update or remove xattrs). Signed-off-by: Filipe Manana --- V2: No changes from v1. V3: No changes from v2 and v1. src/fssum.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 129 insertions(+), 14 deletions(-) diff --git a/src/fssum.c b/src/fssum.c index f1da72fb..6ba0a95c 100644 --- a/src/fssum.c +++ b/src/fssum.c @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef __SOLARIS__ #include #endif @@ -40,7 +41,6 @@ #endif /* TODO: add hardlink recognition */ -/* TODO: add xattr/acl */ struct excludes { char *path; @@ -71,15 +71,16 @@ enum _flags { FLAG_MTIME, FLAG_CTIME, FLAG_DATA, + FLAG_XATTRS, FLAG_OPEN_ERROR, FLAG_STRUCTURE, NUM_FLAGS }; -const char flchar[] = "ugoamcdes"; +const char flchar[] = "ugoamcdxes"; char line[65536]; -int flags[NUM_FLAGS] = {1, 1, 1, 1, 1, 0, 1, 0, 0}; +int flags[NUM_FLAGS] = {1, 1, 1, 1, 1, 0, 1, 1, 0, 0}; char * getln(char *buf, int size, FILE *fp) @@ -135,7 +136,7 @@ usage(void) fprintf(stderr, " -v : verbose mode (debugging only)\n"); fprintf(stderr, " -r : read checksum or manifest from file\n"); - fprintf(stderr, " -[ugoamcde] : specify which fields to include in checksum calculation.\n"); + fprintf(stderr, " -[ugoamcdxe]: specify which fields to include in checksum calculation.\n"); fprintf(stderr, " u : include uid\n"); fprintf(stderr, " g : include gid\n"); fprintf(stderr, " o : include mode\n"); @@ -143,9 +144,10 @@ usage(void) fprintf(stderr, " a : include atime\n"); fprintf(stderr, " c : include ctime\n"); fprintf(stderr, " d : include file data\n"); + fprintf(stderr, " x : include xattrs\n"); fprintf(stderr, " e : include open errors (aborts otherwise)\n"); fprintf(stderr, " s : include block structure (holes)\n"); - fprintf(stderr, " -[UGOAMCDES]: exclude respective field from calculation\n"); + fprintf(stderr, " -[UGOAMCDXES]: exclude respective field from calculation\n"); fprintf(stderr, " -n : reset all flags\n"); fprintf(stderr, " -N : set all flags\n"); fprintf(stderr, " -x path : exclude path when building checksum (multiple ok)\n"); @@ -221,6 +223,106 @@ sum_to_string(sum_t *dst) } int +namecmp(const void *aa, const void *bb) +{ + char * const *a = aa; + char * const *b = bb; + + return strcmp(*a, *b); +} + +int +sum_xattrs(int fd, sum_t *dst) +{ + ssize_t buflen; + ssize_t len; + char *buf; + char *p; + char **names = NULL; + int num_xattrs = 0; + int ret = 0; + int i; + + buflen = flistxattr(fd, NULL, 0); + if (buflen < 0) + return -errno; + /* no xattrs exist */ + if (buflen == 0) + return 0; + + buf = malloc(buflen); + if (!buf) + return -ENOMEM; + + buflen = flistxattr(fd, buf, buflen); + if (buflen < 0) { + ret = -errno; + goto out; + } + + /* + * Keep the list of xattrs sorted, because the order in which they are + * listed is filesystem dependent, so we want to get the same checksum + * on different filesystems. + */ + + p = buf; + len = buflen; + while (len > 0) { + int keylen; + + keylen = strlen(p) + 1; /* +1 for NULL terminator */ + len -= keylen; + p += keylen; + num_xattrs++; + } + + names = malloc(sizeof(char *) * num_xattrs); + if (!names) { + ret = -ENOMEM; + goto out; + } + + p = buf; + for (i = 0; i < num_xattrs; i++) { + names[i] = p; + p += strlen(p) + 1; /* +1 for NULL terminator */ + } + + qsort(names, num_xattrs, sizeof(char *), namecmp); + + for (i = 0; i < num_xattrs; i++) { + len = fgetxattr(fd, names[i], NULL, 0); + if (len < 0) { + ret = -errno; + goto out; + } + sum_add(dst, names[i], strlen(names[i])); + /* no value */ + if (len == 0) + continue; + p = malloc(len); + if (!p) { + ret = -ENOMEM; + goto out; + } + len = fgetxattr(fd, names[i], p, len); + if (len < 0) { + ret = -errno; + free(p); + goto out; + } + sum_add(dst, p, len); + free(p); + } +out: + free(buf); + free(names); + + return ret; +} + +int sum_file_data_permissive(int fd, sum_t *dst) { int ret; @@ -401,15 +503,6 @@ malformed: excess_file(fn); } -int -namecmp(const void *aa, const void *bb) -{ - char * const *a = aa; - char * const *b = bb; - - return strcmp(*a, *b); -} - void sum(int dirfd, int level, sum_t *dircs, char *path_prefix, char *path_in) { @@ -493,6 +586,28 @@ sum(int dirfd, int level, sum_t *dircs, char *path_prefix, char *path_in) sum_add_time(&meta, st.st_mtime); if (flags[FLAG_CTIME]) sum_add_time(&meta, st.st_ctime); + if (flags[FLAG_XATTRS] && + (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))) { + fd = openat(dirfd, namelist[i], 0); + if (fd == -1 && flags[FLAG_OPEN_ERROR]) { + sum_add_u64(&meta, errno); + } else if (fd == -1) { + fprintf(stderr, "open failed for %s/%s: %s\n", + path_prefix, path, strerror(errno)); + exit(-1); + } else { + ret = sum_xattrs(fd, &meta); + close(fd); + if (ret < 0) { + fprintf(stderr, + "failed to read xattrs from " + "%s/%s: %s\n", + path_prefix, path, + strerror(-ret)); + exit(-1); + } + } + } if (S_ISDIR(st.st_mode)) { fd = openat(dirfd, namelist[i], 0); if (fd == -1 && flags[FLAG_OPEN_ERROR]) {