Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

kbuild: use git-archive for source package creation

Commit 5c3d1d0abb12 ("kbuild: add a tool to list files ignored by git")
added a new tool, scripts/list-gitignored. My intention was to create
source packages without cleaning the source tree, without relying on git.

Linus strongly objected to it, and suggested using 'git archive' instead.
[1] [2] [3]

This commit goes in that direction - Remove scripts/list-gitignored.c
and rewrites Makefiles and scripts to use 'git archive' for building
Debian and RPM source packages. It also makes 'make perf-tar*-src-pkg'
use 'git archive' again.

Going forward, building source packages is only possible in a git-managed
tree. Building binary packages does not require git.

[1]: https://lore.kernel.org/lkml/CAHk-=wi49sMaC7vY1yMagk7eqLK=1jHeHQ=yZ_k45P=xBccnmA@mail.gmail.com/
[2]: https://lore.kernel.org/lkml/CAHk-=wh5AixGsLeT0qH2oZHKq0FLUTbyTw4qY921L=PwYgoGVw@mail.gmail.com/
[3]: https://lore.kernel.org/lkml/CAHk-=wgM-W6Fu==EoAVCabxyX8eYBz9kNC88-tm9ExRQwA79UQ@mail.gmail.com/

Fixes: 5c3d1d0abb12 ("kbuild: add a tool to list files ignored by git")
Fixes: e0ca16749ac3 ("kbuild: make perf-tar*-src-pkg work without relying on git")
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>

+181 -1155
+1 -6
Makefile
··· 274 274 cscope gtags TAGS tags help% %docs check% coccicheck \ 275 275 $(version_h) headers headers_% archheaders archscripts \ 276 276 %asm-generic kernelversion %src-pkg dt_binding_check \ 277 - outputmakefile rustavailable rustfmt rustfmtcheck \ 278 - scripts_package 277 + outputmakefile rustavailable rustfmt rustfmtcheck 279 278 # Installation targets should not require compiler. Unfortunately, vdso_install 280 279 # is an exception where build artifacts may be updated. This must be fixed. 281 280 no-compiler-targets := $(no-dot-config-targets) install dtbs_install \ ··· 1654 1655 $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.package $@ 1655 1656 %pkg: include/config/kernel.release FORCE 1656 1657 $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.package $@ 1657 - 1658 - PHONY += scripts_package 1659 - scripts_package: scripts_basic 1660 - $(Q)$(MAKE) $(build)=scripts scripts/list-gitignored 1661 1658 1662 1659 # Brief documentation of the typical targets used 1663 1660 # ---------------------------------------------------------------------------
-1
scripts/.gitignore
··· 3 3 /generate_rust_target 4 4 /insert-sys-cert 5 5 /kallsyms 6 - /list-gitignored 7 6 /module.lds 8 7 /recordmcount 9 8 /sign-file
+1 -1
scripts/Makefile
··· 38 38 endif 39 39 40 40 # The following programs are only built on demand 41 - hostprogs += list-gitignored unifdef 41 + hostprogs += unifdef 42 42 43 43 # The module linker script is preprocessed on demand 44 44 targets += module.lds
+68 -78
scripts/Makefile.package
··· 2 2 # Makefile for the different targets used to generate full packages of a kernel 3 3 4 4 include $(srctree)/scripts/Kbuild.include 5 + include $(srctree)/scripts/Makefile.lib 5 6 6 7 KERNELPATH := kernel-$(subst -,_,$(KERNELRELEASE)) 7 8 KBUILD_PKG_ROOTCMD ?="fakeroot -u" ··· 27 26 tar -I $(KGZIP) -c $(RCS_TAR_IGNORE) -f $(2).tar.gz \ 28 27 --transform 's:^:$(2)/:S' $(TAR_CONTENT) $(3) 29 28 30 - # .tmp_filelist .tmp_filelist_exclude 29 + # tarball compression 31 30 # --------------------------------------------------------------------------- 32 31 33 - scripts/list-gitignored: FORCE 34 - $(Q)$(MAKE) -f $(srctree)/Makefile scripts_package 32 + %.tar.gz: %.tar 33 + $(call cmd,gzip) 35 34 36 - # 1f5d3a6b6532e25a5cdf1f311956b2b03d343a48 removed '*.rej' from .gitignore, 37 - # but it is definitely a generated file. 38 - filechk_filelist = \ 39 - $< --exclude='*.rej' --output=$@_exclude --prefix=./ --rootdir=$(srctree) --stat=- 35 + %.tar.bz2: %.tar 36 + $(call cmd,bzip2) 40 37 41 - .tmp_filelist: scripts/list-gitignored FORCE 42 - $(call filechk,filelist) 38 + %.tar.xz: %.tar 39 + $(call cmd,xzmisc) 43 40 44 - # tarball 41 + %.tar.zst: %.tar 42 + $(call cmd,zstd) 43 + 44 + # Git 45 45 # --------------------------------------------------------------------------- 46 46 47 - quiet_cmd_tar = TAR $@ 48 - cmd_tar = tar -c -f $@ $(tar-compress-opt) $(tar-exclude-opt) \ 49 - --owner=0 --group=0 --sort=name \ 50 - --transform 's:^\.:$*:S' -C $(tar-rootdir) . 47 + filechk_HEAD = git -C $(srctree) rev-parse --verify HEAD 2>/dev/null 51 48 52 - tar-rootdir := $(srctree) 49 + .tmp_HEAD: check-git FORCE 50 + $(call filechk,HEAD) 53 51 54 - %.tar: 55 - $(call cmd,tar) 56 - 57 - %.tar.gz: private tar-compress-opt := -I $(KGZIP) 58 - %.tar.gz: 59 - $(call cmd,tar) 60 - 61 - %.tar.bz2: private tar-compress-opt := -I $(KBZIP2) 62 - %.tar.bz2: 63 - $(call cmd,tar) 64 - 65 - %.tar.xz: private tar-compress-opt := -I $(XZ) 66 - %.tar.xz: 67 - $(call cmd,tar) 68 - 69 - %.tar.zst: private tar-compress-opt := -I $(ZSTD) 70 - %.tar.zst: 71 - $(call cmd,tar) 52 + PHONY += check-git 53 + check-git: 54 + @if ! $(srctree)/scripts/check-git; then \ 55 + echo >&2 "error: creating source package requires git repository"; \ 56 + false; \ 57 + fi 72 58 73 59 # Linux source tarball 74 60 # --------------------------------------------------------------------------- 75 61 76 - linux.tar.gz: tar-exclude-opt = --exclude=./$@ --exclude-from=$<_exclude 77 - linux.tar.gz: .tmp_filelist 62 + quiet_cmd_archive_linux = ARCHIVE $@ 63 + cmd_archive_linux = \ 64 + git -C $(srctree) archive --output=$$(realpath $@) --prefix=$(basename $@)/ $$(cat $<) 65 + 66 + targets += linux.tar 67 + linux.tar: .tmp_HEAD FORCE 68 + $(call if_changed,archive_linux) 78 69 79 70 # rpm-pkg 80 71 # --------------------------------------------------------------------------- ··· 141 148 # dir-pkg tar*-pkg - tarball targets 142 149 # --------------------------------------------------------------------------- 143 150 144 - tar-pkg-tarball = linux-$(KERNELRELEASE)-$(ARCH).$(1) 145 - tar-pkg-phony = $(subst .,,$(1))-pkg 146 - 147 151 tar-install: FORCE 148 152 $(Q)$(MAKE) -f $(srctree)/Makefile 149 153 +$(Q)$(srctree)/scripts/package/buildtar $@ 154 + 155 + quiet_cmd_tar = TAR $@ 156 + cmd_tar = cd $<; tar cf ../$@ --owner=root --group=root --sort=name * 157 + 158 + linux-$(KERNELRELEASE)-$(ARCH).tar: tar-install 159 + $(call cmd,tar) 150 160 151 161 PHONY += dir-pkg 152 162 dir-pkg: tar-install 153 163 @echo "Kernel tree successfully created in $<" 154 164 155 - define tar-pkg-rule 156 - PHONY += $(tar-pkg-phony) 157 - $(tar-pkg-phony): $(tar-pkg-tarball) 165 + PHONY += tar-pkg 166 + tar-pkg: linux-$(KERNELRELEASE)-$(ARCH).tar 158 167 @: 159 168 160 - $(tar-pkg-tarball): private tar-rootdir := tar-install 161 - $(tar-pkg-tarball): tar-install 162 - endef 163 - 164 - $(foreach x, tar tar.gz tar.bz2 tar.xz tar.zst, $(eval $(call tar-pkg-rule,$(x)))) 169 + tar%-pkg: linux-$(KERNELRELEASE)-$(ARCH).tar.% FORCE 170 + @: 165 171 166 172 # perf-tar*-src-pkg - generate a source tarball with perf source 167 173 # --------------------------------------------------------------------------- 168 174 169 - perf-tar-src-pkg-tarball = perf-$(KERNELVERSION).$(1) 170 - perf-tar-src-pkg-phony = perf-$(subst .,,$(1))-src-pkg 175 + .tmp_perf: 176 + $(Q)mkdir .tmp_perf 171 177 172 - quiet_cmd_stage_perf_src = STAGE $@ 173 - cmd_stage_perf_src = \ 174 - rm -rf $@; \ 175 - mkdir -p $@; \ 176 - tar -c -f - --exclude-from=$<_exclude -C $(srctree) --files-from=$(srctree)/tools/perf/MANIFEST | \ 177 - tar -x -f - -C $@ 178 - 179 - .tmp_perf: .tmp_filelist 180 - $(call cmd,stage_perf_src) 181 - 182 - filechk_perf_head = \ 183 - if test -z "$(git -C $(srctree) rev-parse --show-cdup 2>/dev/null)" && \ 184 - head=$$(git -C $(srctree) rev-parse --verify HEAD 2>/dev/null); then \ 185 - echo $$head; \ 186 - else \ 187 - echo "not a git tree"; \ 188 - fi 189 - 190 - .tmp_perf/HEAD: .tmp_perf FORCE 191 - $(call filechk,perf_head) 178 + .tmp_perf/HEAD: .tmp_HEAD | .tmp_perf 179 + $(call cmd,copy) 192 180 193 181 quiet_cmd_perf_version_file = GEN $@ 194 182 cmd_perf_version_file = cd $(srctree)/tools/perf; util/PERF-VERSION-GEN $(dir $(abspath $@)) 195 183 196 - # PERF-VERSION-FILE and HEAD are independent, but this avoids updating the 184 + # PERF-VERSION-FILE and .tmp_HEAD are independent, but this avoids updating the 197 185 # timestamp of PERF-VERSION-FILE. 198 186 # The best is to fix tools/perf/util/PERF-VERSION-GEN. 199 - .tmp_perf/PERF-VERSION-FILE: .tmp_perf/HEAD $(srctree)/tools/perf/util/PERF-VERSION-GEN 187 + .tmp_perf/PERF-VERSION-FILE: .tmp_HEAD $(srctree)/tools/perf/util/PERF-VERSION-GEN | .tmp_perf 200 188 $(call cmd,perf_version_file) 201 189 202 - define perf-tar-src-pkg-rule 203 - PHONY += $(perf-tar-src-pkg-phony) 204 - $(perf-tar-src-pkg-phony): $(perf-tar-src-pkg-tarball) 190 + quiet_cmd_archive_perf = ARCHIVE $@ 191 + cmd_archive_perf = \ 192 + git -C $(srctree) archive --output=$$(realpath $@) --prefix=$(basename $@)/ \ 193 + --add-file=$$(realpath $(word 2, $^)) \ 194 + --add-file=$$(realpath $(word 3, $^)) \ 195 + $$(cat $(word 2, $^))^{tree} $$(cat $<) 196 + 197 + targets += perf-$(KERNELVERSION).tar 198 + perf-$(KERNELVERSION).tar: tools/perf/MANIFEST .tmp_perf/HEAD .tmp_perf/PERF-VERSION-FILE FORCE 199 + $(call if_changed,archive_perf) 200 + 201 + PHONY += perf-tar-src-pkg 202 + perf-tar-src-pkg: perf-$(KERNELVERSION).tar 205 203 @: 206 204 207 - $(perf-tar-src-pkg-tarball): private tar-rootdir := .tmp_perf 208 - $(perf-tar-src-pkg-tarball): .tmp_filelist .tmp_perf/HEAD .tmp_perf/PERF-VERSION-FILE 209 - endef 210 - 211 - $(foreach x, tar tar.gz tar.bz2 tar.xz tar.zst, $(eval $(call perf-tar-src-pkg-rule,$(x)))) 205 + perf-tar%-src-pkg: perf-$(KERNELVERSION).tar.% FORCE 206 + @: 212 207 213 208 # Help text displayed when executing 'make help' 214 209 # --------------------------------------------------------------------------- ··· 223 242 224 243 PHONY += FORCE 225 244 FORCE: 245 + 246 + # Read all saved command lines and dependencies for the $(targets) we 247 + # may be building above, using $(if_changed{,_dep}). As an 248 + # optimization, we don't need to read them if the target does not 249 + # exist, we will rebuild anyway in that case. 250 + 251 + existing-targets := $(wildcard $(sort $(targets))) 252 + 253 + -include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd) 226 254 227 255 .PHONY: $(PHONY)
+14
scripts/check-git
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0-only 3 + # 4 + # succeed if we are in a git repository 5 + 6 + srctree="$(dirname $0)/.." 7 + 8 + if ! git -C "${srctree}" rev-parse --verify HEAD >/dev/null 2>/dev/null; then 9 + exit 1 10 + fi 11 + 12 + if ! test -z $(git -C "${srctree}" rev-parse --show-cdup 2>/dev/null); then 13 + exit 1 14 + fi
-1057
scripts/list-gitignored.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-only 2 - // 3 - // Traverse the source tree, parsing all .gitignore files, and print file paths 4 - // that are ignored by git. 5 - // The output is suitable to the --exclude-from option of tar. 6 - // This is useful until the --exclude-vcs-ignores option gets working correctly. 7 - // 8 - // Copyright (C) 2023 Masahiro Yamada <masahiroy@kernel.org> 9 - // (a lot of code imported from GIT) 10 - 11 - #include <assert.h> 12 - #include <dirent.h> 13 - #include <errno.h> 14 - #include <fcntl.h> 15 - #include <getopt.h> 16 - #include <stdarg.h> 17 - #include <stdbool.h> 18 - #include <stdio.h> 19 - #include <stdlib.h> 20 - #include <string.h> 21 - #include <sys/stat.h> 22 - #include <sys/types.h> 23 - #include <unistd.h> 24 - 25 - // Imported from commit 23c56f7bd5f1667f8b793d796bf30e39545920f6 in GIT 26 - // 27 - //---------------------------(IMPORT FROM GIT BEGIN)--------------------------- 28 - 29 - // Copied from environment.c 30 - 31 - static bool ignore_case; 32 - 33 - // Copied from git-compat-util.h 34 - 35 - /* Sane ctype - no locale, and works with signed chars */ 36 - #undef isascii 37 - #undef isspace 38 - #undef isdigit 39 - #undef isalpha 40 - #undef isalnum 41 - #undef isprint 42 - #undef islower 43 - #undef isupper 44 - #undef tolower 45 - #undef toupper 46 - #undef iscntrl 47 - #undef ispunct 48 - #undef isxdigit 49 - 50 - static const unsigned char sane_ctype[256]; 51 - #define GIT_SPACE 0x01 52 - #define GIT_DIGIT 0x02 53 - #define GIT_ALPHA 0x04 54 - #define GIT_GLOB_SPECIAL 0x08 55 - #define GIT_REGEX_SPECIAL 0x10 56 - #define GIT_PATHSPEC_MAGIC 0x20 57 - #define GIT_CNTRL 0x40 58 - #define GIT_PUNCT 0x80 59 - #define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0) 60 - #define isascii(x) (((x) & ~0x7f) == 0) 61 - #define isspace(x) sane_istest(x,GIT_SPACE) 62 - #define isdigit(x) sane_istest(x,GIT_DIGIT) 63 - #define isalpha(x) sane_istest(x,GIT_ALPHA) 64 - #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 65 - #define isprint(x) ((x) >= 0x20 && (x) <= 0x7e) 66 - #define islower(x) sane_iscase(x, 1) 67 - #define isupper(x) sane_iscase(x, 0) 68 - #define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL) 69 - #define iscntrl(x) (sane_istest(x,GIT_CNTRL)) 70 - #define ispunct(x) sane_istest(x, GIT_PUNCT | GIT_REGEX_SPECIAL | \ 71 - GIT_GLOB_SPECIAL | GIT_PATHSPEC_MAGIC) 72 - #define isxdigit(x) (hexval_table[(unsigned char)(x)] != -1) 73 - #define tolower(x) sane_case((unsigned char)(x), 0x20) 74 - #define toupper(x) sane_case((unsigned char)(x), 0) 75 - 76 - static inline int sane_case(int x, int high) 77 - { 78 - if (sane_istest(x, GIT_ALPHA)) 79 - x = (x & ~0x20) | high; 80 - return x; 81 - } 82 - 83 - static inline int sane_iscase(int x, int is_lower) 84 - { 85 - if (!sane_istest(x, GIT_ALPHA)) 86 - return 0; 87 - 88 - if (is_lower) 89 - return (x & 0x20) != 0; 90 - else 91 - return (x & 0x20) == 0; 92 - } 93 - 94 - // Copied from ctype.c 95 - 96 - enum { 97 - S = GIT_SPACE, 98 - A = GIT_ALPHA, 99 - D = GIT_DIGIT, 100 - G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */ 101 - R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | */ 102 - P = GIT_PATHSPEC_MAGIC, /* other non-alnum, except for ] and } */ 103 - X = GIT_CNTRL, 104 - U = GIT_PUNCT, 105 - Z = GIT_CNTRL | GIT_SPACE 106 - }; 107 - 108 - static const unsigned char sane_ctype[256] = { 109 - X, X, X, X, X, X, X, X, X, Z, Z, X, X, Z, X, X, /* 0.. 15 */ 110 - X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 16.. 31 */ 111 - S, P, P, P, R, P, P, P, R, R, G, R, P, P, R, P, /* 32.. 47 */ 112 - D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, G, /* 48.. 63 */ 113 - P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */ 114 - A, A, A, A, A, A, A, A, A, A, A, G, G, U, R, P, /* 80.. 95 */ 115 - P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */ 116 - A, A, A, A, A, A, A, A, A, A, A, R, R, U, P, X, /* 112..127 */ 117 - /* Nothing in the 128.. range */ 118 - }; 119 - 120 - // Copied from hex.c 121 - 122 - static const signed char hexval_table[256] = { 123 - -1, -1, -1, -1, -1, -1, -1, -1, /* 00-07 */ 124 - -1, -1, -1, -1, -1, -1, -1, -1, /* 08-0f */ 125 - -1, -1, -1, -1, -1, -1, -1, -1, /* 10-17 */ 126 - -1, -1, -1, -1, -1, -1, -1, -1, /* 18-1f */ 127 - -1, -1, -1, -1, -1, -1, -1, -1, /* 20-27 */ 128 - -1, -1, -1, -1, -1, -1, -1, -1, /* 28-2f */ 129 - 0, 1, 2, 3, 4, 5, 6, 7, /* 30-37 */ 130 - 8, 9, -1, -1, -1, -1, -1, -1, /* 38-3f */ 131 - -1, 10, 11, 12, 13, 14, 15, -1, /* 40-47 */ 132 - -1, -1, -1, -1, -1, -1, -1, -1, /* 48-4f */ 133 - -1, -1, -1, -1, -1, -1, -1, -1, /* 50-57 */ 134 - -1, -1, -1, -1, -1, -1, -1, -1, /* 58-5f */ 135 - -1, 10, 11, 12, 13, 14, 15, -1, /* 60-67 */ 136 - -1, -1, -1, -1, -1, -1, -1, -1, /* 68-67 */ 137 - -1, -1, -1, -1, -1, -1, -1, -1, /* 70-77 */ 138 - -1, -1, -1, -1, -1, -1, -1, -1, /* 78-7f */ 139 - -1, -1, -1, -1, -1, -1, -1, -1, /* 80-87 */ 140 - -1, -1, -1, -1, -1, -1, -1, -1, /* 88-8f */ 141 - -1, -1, -1, -1, -1, -1, -1, -1, /* 90-97 */ 142 - -1, -1, -1, -1, -1, -1, -1, -1, /* 98-9f */ 143 - -1, -1, -1, -1, -1, -1, -1, -1, /* a0-a7 */ 144 - -1, -1, -1, -1, -1, -1, -1, -1, /* a8-af */ 145 - -1, -1, -1, -1, -1, -1, -1, -1, /* b0-b7 */ 146 - -1, -1, -1, -1, -1, -1, -1, -1, /* b8-bf */ 147 - -1, -1, -1, -1, -1, -1, -1, -1, /* c0-c7 */ 148 - -1, -1, -1, -1, -1, -1, -1, -1, /* c8-cf */ 149 - -1, -1, -1, -1, -1, -1, -1, -1, /* d0-d7 */ 150 - -1, -1, -1, -1, -1, -1, -1, -1, /* d8-df */ 151 - -1, -1, -1, -1, -1, -1, -1, -1, /* e0-e7 */ 152 - -1, -1, -1, -1, -1, -1, -1, -1, /* e8-ef */ 153 - -1, -1, -1, -1, -1, -1, -1, -1, /* f0-f7 */ 154 - -1, -1, -1, -1, -1, -1, -1, -1, /* f8-ff */ 155 - }; 156 - 157 - // Copied from wildmatch.h 158 - 159 - #define WM_CASEFOLD 1 160 - #define WM_PATHNAME 2 161 - 162 - #define WM_NOMATCH 1 163 - #define WM_MATCH 0 164 - #define WM_ABORT_ALL -1 165 - #define WM_ABORT_TO_STARSTAR -2 166 - 167 - // Copied from wildmatch.c 168 - 169 - typedef unsigned char uchar; 170 - 171 - // local modification: remove NEGATE_CLASS(2) 172 - 173 - #define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \ 174 - && *(class) == *(litmatch) \ 175 - && strncmp((char*)class, litmatch, len) == 0) 176 - 177 - // local modification: simpilify macros 178 - #define ISBLANK(c) ((c) == ' ' || (c) == '\t') 179 - #define ISGRAPH(c) (isprint(c) && !isspace(c)) 180 - #define ISPRINT(c) isprint(c) 181 - #define ISDIGIT(c) isdigit(c) 182 - #define ISALNUM(c) isalnum(c) 183 - #define ISALPHA(c) isalpha(c) 184 - #define ISCNTRL(c) iscntrl(c) 185 - #define ISLOWER(c) islower(c) 186 - #define ISPUNCT(c) ispunct(c) 187 - #define ISSPACE(c) isspace(c) 188 - #define ISUPPER(c) isupper(c) 189 - #define ISXDIGIT(c) isxdigit(c) 190 - 191 - /* Match pattern "p" against "text" */ 192 - static int dowild(const uchar *p, const uchar *text, unsigned int flags) 193 - { 194 - uchar p_ch; 195 - const uchar *pattern = p; 196 - 197 - for ( ; (p_ch = *p) != '\0'; text++, p++) { 198 - int matched, match_slash, negated; 199 - uchar t_ch, prev_ch; 200 - if ((t_ch = *text) == '\0' && p_ch != '*') 201 - return WM_ABORT_ALL; 202 - if ((flags & WM_CASEFOLD) && ISUPPER(t_ch)) 203 - t_ch = tolower(t_ch); 204 - if ((flags & WM_CASEFOLD) && ISUPPER(p_ch)) 205 - p_ch = tolower(p_ch); 206 - switch (p_ch) { 207 - case '\\': 208 - /* Literal match with following character. Note that the test 209 - * in "default" handles the p[1] == '\0' failure case. */ 210 - p_ch = *++p; 211 - /* FALLTHROUGH */ 212 - default: 213 - if (t_ch != p_ch) 214 - return WM_NOMATCH; 215 - continue; 216 - case '?': 217 - /* Match anything but '/'. */ 218 - if ((flags & WM_PATHNAME) && t_ch == '/') 219 - return WM_NOMATCH; 220 - continue; 221 - case '*': 222 - if (*++p == '*') { 223 - const uchar *prev_p = p - 2; 224 - while (*++p == '*') {} 225 - if (!(flags & WM_PATHNAME)) 226 - /* without WM_PATHNAME, '*' == '**' */ 227 - match_slash = 1; 228 - else if ((prev_p < pattern || *prev_p == '/') && 229 - (*p == '\0' || *p == '/' || 230 - (p[0] == '\\' && p[1] == '/'))) { 231 - /* 232 - * Assuming we already match 'foo/' and are at 233 - * <star star slash>, just assume it matches 234 - * nothing and go ahead match the rest of the 235 - * pattern with the remaining string. This 236 - * helps make foo/<*><*>/bar (<> because 237 - * otherwise it breaks C comment syntax) match 238 - * both foo/bar and foo/a/bar. 239 - */ 240 - if (p[0] == '/' && 241 - dowild(p + 1, text, flags) == WM_MATCH) 242 - return WM_MATCH; 243 - match_slash = 1; 244 - } else /* WM_PATHNAME is set */ 245 - match_slash = 0; 246 - } else 247 - /* without WM_PATHNAME, '*' == '**' */ 248 - match_slash = flags & WM_PATHNAME ? 0 : 1; 249 - if (*p == '\0') { 250 - /* Trailing "**" matches everything. Trailing "*" matches 251 - * only if there are no more slash characters. */ 252 - if (!match_slash) { 253 - if (strchr((char *)text, '/')) 254 - return WM_NOMATCH; 255 - } 256 - return WM_MATCH; 257 - } else if (!match_slash && *p == '/') { 258 - /* 259 - * _one_ asterisk followed by a slash 260 - * with WM_PATHNAME matches the next 261 - * directory 262 - */ 263 - const char *slash = strchr((char*)text, '/'); 264 - if (!slash) 265 - return WM_NOMATCH; 266 - text = (const uchar*)slash; 267 - /* the slash is consumed by the top-level for loop */ 268 - break; 269 - } 270 - while (1) { 271 - if (t_ch == '\0') 272 - break; 273 - /* 274 - * Try to advance faster when an asterisk is 275 - * followed by a literal. We know in this case 276 - * that the string before the literal 277 - * must belong to "*". 278 - * If match_slash is false, do not look past 279 - * the first slash as it cannot belong to '*'. 280 - */ 281 - if (!is_glob_special(*p)) { 282 - p_ch = *p; 283 - if ((flags & WM_CASEFOLD) && ISUPPER(p_ch)) 284 - p_ch = tolower(p_ch); 285 - while ((t_ch = *text) != '\0' && 286 - (match_slash || t_ch != '/')) { 287 - if ((flags & WM_CASEFOLD) && ISUPPER(t_ch)) 288 - t_ch = tolower(t_ch); 289 - if (t_ch == p_ch) 290 - break; 291 - text++; 292 - } 293 - if (t_ch != p_ch) 294 - return WM_NOMATCH; 295 - } 296 - if ((matched = dowild(p, text, flags)) != WM_NOMATCH) { 297 - if (!match_slash || matched != WM_ABORT_TO_STARSTAR) 298 - return matched; 299 - } else if (!match_slash && t_ch == '/') 300 - return WM_ABORT_TO_STARSTAR; 301 - t_ch = *++text; 302 - } 303 - return WM_ABORT_ALL; 304 - case '[': 305 - p_ch = *++p; 306 - if (p_ch == '^') 307 - p_ch = '!'; 308 - /* Assign literal 1/0 because of "matched" comparison. */ 309 - negated = p_ch == '!' ? 1 : 0; 310 - if (negated) { 311 - /* Inverted character class. */ 312 - p_ch = *++p; 313 - } 314 - prev_ch = 0; 315 - matched = 0; 316 - do { 317 - if (!p_ch) 318 - return WM_ABORT_ALL; 319 - if (p_ch == '\\') { 320 - p_ch = *++p; 321 - if (!p_ch) 322 - return WM_ABORT_ALL; 323 - if (t_ch == p_ch) 324 - matched = 1; 325 - } else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') { 326 - p_ch = *++p; 327 - if (p_ch == '\\') { 328 - p_ch = *++p; 329 - if (!p_ch) 330 - return WM_ABORT_ALL; 331 - } 332 - if (t_ch <= p_ch && t_ch >= prev_ch) 333 - matched = 1; 334 - else if ((flags & WM_CASEFOLD) && ISLOWER(t_ch)) { 335 - uchar t_ch_upper = toupper(t_ch); 336 - if (t_ch_upper <= p_ch && t_ch_upper >= prev_ch) 337 - matched = 1; 338 - } 339 - p_ch = 0; /* This makes "prev_ch" get set to 0. */ 340 - } else if (p_ch == '[' && p[1] == ':') { 341 - const uchar *s; 342 - int i; 343 - for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {} /*SHARED ITERATOR*/ 344 - if (!p_ch) 345 - return WM_ABORT_ALL; 346 - i = p - s - 1; 347 - if (i < 0 || p[-1] != ':') { 348 - /* Didn't find ":]", so treat like a normal set. */ 349 - p = s - 2; 350 - p_ch = '['; 351 - if (t_ch == p_ch) 352 - matched = 1; 353 - continue; 354 - } 355 - if (CC_EQ(s,i, "alnum")) { 356 - if (ISALNUM(t_ch)) 357 - matched = 1; 358 - } else if (CC_EQ(s,i, "alpha")) { 359 - if (ISALPHA(t_ch)) 360 - matched = 1; 361 - } else if (CC_EQ(s,i, "blank")) { 362 - if (ISBLANK(t_ch)) 363 - matched = 1; 364 - } else if (CC_EQ(s,i, "cntrl")) { 365 - if (ISCNTRL(t_ch)) 366 - matched = 1; 367 - } else if (CC_EQ(s,i, "digit")) { 368 - if (ISDIGIT(t_ch)) 369 - matched = 1; 370 - } else if (CC_EQ(s,i, "graph")) { 371 - if (ISGRAPH(t_ch)) 372 - matched = 1; 373 - } else if (CC_EQ(s,i, "lower")) { 374 - if (ISLOWER(t_ch)) 375 - matched = 1; 376 - } else if (CC_EQ(s,i, "print")) { 377 - if (ISPRINT(t_ch)) 378 - matched = 1; 379 - } else if (CC_EQ(s,i, "punct")) { 380 - if (ISPUNCT(t_ch)) 381 - matched = 1; 382 - } else if (CC_EQ(s,i, "space")) { 383 - if (ISSPACE(t_ch)) 384 - matched = 1; 385 - } else if (CC_EQ(s,i, "upper")) { 386 - if (ISUPPER(t_ch)) 387 - matched = 1; 388 - else if ((flags & WM_CASEFOLD) && ISLOWER(t_ch)) 389 - matched = 1; 390 - } else if (CC_EQ(s,i, "xdigit")) { 391 - if (ISXDIGIT(t_ch)) 392 - matched = 1; 393 - } else /* malformed [:class:] string */ 394 - return WM_ABORT_ALL; 395 - p_ch = 0; /* This makes "prev_ch" get set to 0. */ 396 - } else if (t_ch == p_ch) 397 - matched = 1; 398 - } while (prev_ch = p_ch, (p_ch = *++p) != ']'); 399 - if (matched == negated || 400 - ((flags & WM_PATHNAME) && t_ch == '/')) 401 - return WM_NOMATCH; 402 - continue; 403 - } 404 - } 405 - 406 - return *text ? WM_NOMATCH : WM_MATCH; 407 - } 408 - 409 - /* Match the "pattern" against the "text" string. */ 410 - static int wildmatch(const char *pattern, const char *text, unsigned int flags) 411 - { 412 - // local modification: move WM_CASEFOLD here 413 - if (ignore_case) 414 - flags |= WM_CASEFOLD; 415 - 416 - return dowild((const uchar*)pattern, (const uchar*)text, flags); 417 - } 418 - 419 - // Copied from dir.h 420 - 421 - #define PATTERN_FLAG_NODIR 1 422 - #define PATTERN_FLAG_ENDSWITH 4 423 - #define PATTERN_FLAG_MUSTBEDIR 8 424 - #define PATTERN_FLAG_NEGATIVE 16 425 - 426 - // Copied from dir.c 427 - 428 - static int fspathncmp(const char *a, const char *b, size_t count) 429 - { 430 - return ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count); 431 - } 432 - 433 - static int simple_length(const char *match) 434 - { 435 - int len = -1; 436 - 437 - for (;;) { 438 - unsigned char c = *match++; 439 - len++; 440 - if (c == '\0' || is_glob_special(c)) 441 - return len; 442 - } 443 - } 444 - 445 - static int no_wildcard(const char *string) 446 - { 447 - return string[simple_length(string)] == '\0'; 448 - } 449 - 450 - static void parse_path_pattern(const char **pattern, 451 - int *patternlen, 452 - unsigned *flags, 453 - int *nowildcardlen) 454 - { 455 - const char *p = *pattern; 456 - size_t i, len; 457 - 458 - *flags = 0; 459 - if (*p == '!') { 460 - *flags |= PATTERN_FLAG_NEGATIVE; 461 - p++; 462 - } 463 - len = strlen(p); 464 - if (len && p[len - 1] == '/') { 465 - len--; 466 - *flags |= PATTERN_FLAG_MUSTBEDIR; 467 - } 468 - for (i = 0; i < len; i++) { 469 - if (p[i] == '/') 470 - break; 471 - } 472 - if (i == len) 473 - *flags |= PATTERN_FLAG_NODIR; 474 - *nowildcardlen = simple_length(p); 475 - /* 476 - * we should have excluded the trailing slash from 'p' too, 477 - * but that's one more allocation. Instead just make sure 478 - * nowildcardlen does not exceed real patternlen 479 - */ 480 - if (*nowildcardlen > len) 481 - *nowildcardlen = len; 482 - if (*p == '*' && no_wildcard(p + 1)) 483 - *flags |= PATTERN_FLAG_ENDSWITH; 484 - *pattern = p; 485 - *patternlen = len; 486 - } 487 - 488 - static void trim_trailing_spaces(char *buf) 489 - { 490 - char *p, *last_space = NULL; 491 - 492 - for (p = buf; *p; p++) 493 - switch (*p) { 494 - case ' ': 495 - if (!last_space) 496 - last_space = p; 497 - break; 498 - case '\\': 499 - p++; 500 - if (!*p) 501 - return; 502 - /* fallthrough */ 503 - default: 504 - last_space = NULL; 505 - } 506 - 507 - if (last_space) 508 - *last_space = '\0'; 509 - } 510 - 511 - static int match_basename(const char *basename, int basenamelen, 512 - const char *pattern, int prefix, int patternlen, 513 - unsigned flags) 514 - { 515 - if (prefix == patternlen) { 516 - if (patternlen == basenamelen && 517 - !fspathncmp(pattern, basename, basenamelen)) 518 - return 1; 519 - } else if (flags & PATTERN_FLAG_ENDSWITH) { 520 - /* "*literal" matching against "fooliteral" */ 521 - if (patternlen - 1 <= basenamelen && 522 - !fspathncmp(pattern + 1, 523 - basename + basenamelen - (patternlen - 1), 524 - patternlen - 1)) 525 - return 1; 526 - } else { 527 - // local modification: call wildmatch() directly 528 - if (!wildmatch(pattern, basename, flags)) 529 - return 1; 530 - } 531 - return 0; 532 - } 533 - 534 - static int match_pathname(const char *pathname, int pathlen, 535 - const char *base, int baselen, 536 - const char *pattern, int prefix, int patternlen) 537 - { 538 - // local modification: remove local variables 539 - 540 - /* 541 - * match with FNM_PATHNAME; the pattern has base implicitly 542 - * in front of it. 543 - */ 544 - if (*pattern == '/') { 545 - pattern++; 546 - patternlen--; 547 - prefix--; 548 - } 549 - 550 - /* 551 - * baselen does not count the trailing slash. base[] may or 552 - * may not end with a trailing slash though. 553 - */ 554 - if (pathlen < baselen + 1 || 555 - (baselen && pathname[baselen] != '/') || 556 - fspathncmp(pathname, base, baselen)) 557 - return 0; 558 - 559 - // local modification: simplified because always baselen > 0 560 - pathname += baselen + 1; 561 - pathlen -= baselen + 1; 562 - 563 - if (prefix) { 564 - /* 565 - * if the non-wildcard part is longer than the 566 - * remaining pathname, surely it cannot match. 567 - */ 568 - if (prefix > pathlen) 569 - return 0; 570 - 571 - if (fspathncmp(pattern, pathname, prefix)) 572 - return 0; 573 - pattern += prefix; 574 - patternlen -= prefix; 575 - pathname += prefix; 576 - pathlen -= prefix; 577 - 578 - /* 579 - * If the whole pattern did not have a wildcard, 580 - * then our prefix match is all we need; we 581 - * do not need to call fnmatch at all. 582 - */ 583 - if (!patternlen && !pathlen) 584 - return 1; 585 - } 586 - 587 - // local modification: call wildmatch() directly 588 - return !wildmatch(pattern, pathname, WM_PATHNAME); 589 - } 590 - 591 - // Copied from git/utf8.c 592 - 593 - static const char utf8_bom[] = "\357\273\277"; 594 - 595 - //----------------------------(IMPORT FROM GIT END)---------------------------- 596 - 597 - struct pattern { 598 - unsigned int flags; 599 - int nowildcardlen; 600 - int patternlen; 601 - int dirlen; 602 - char pattern[]; 603 - }; 604 - 605 - static struct pattern **pattern_list; 606 - static int nr_patterns, alloced_patterns; 607 - 608 - // Remember the number of patterns at each directory level 609 - static int *nr_patterns_at; 610 - // Track the current/max directory level; 611 - static int depth, max_depth; 612 - static bool debug_on; 613 - static FILE *out_fp, *stat_fp; 614 - static char *prefix = ""; 615 - static char *progname; 616 - 617 - static void __attribute__((noreturn)) perror_exit(const char *s) 618 - { 619 - perror(s); 620 - 621 - exit(EXIT_FAILURE); 622 - } 623 - 624 - static void __attribute__((noreturn)) error_exit(const char *fmt, ...) 625 - { 626 - va_list args; 627 - 628 - fprintf(stderr, "%s: error: ", progname); 629 - 630 - va_start(args, fmt); 631 - vfprintf(stderr, fmt, args); 632 - va_end(args); 633 - 634 - exit(EXIT_FAILURE); 635 - } 636 - 637 - static void debug(const char *fmt, ...) 638 - { 639 - va_list args; 640 - int i; 641 - 642 - if (!debug_on) 643 - return; 644 - 645 - fprintf(stderr, "[DEBUG] "); 646 - 647 - for (i = 0; i < depth * 2; i++) 648 - fputc(' ', stderr); 649 - 650 - va_start(args, fmt); 651 - vfprintf(stderr, fmt, args); 652 - va_end(args); 653 - } 654 - 655 - static void *xrealloc(void *ptr, size_t size) 656 - { 657 - ptr = realloc(ptr, size); 658 - if (!ptr) 659 - perror_exit(progname); 660 - 661 - return ptr; 662 - } 663 - 664 - static void *xmalloc(size_t size) 665 - { 666 - return xrealloc(NULL, size); 667 - } 668 - 669 - // similar to last_matching_pattern_from_list() in GIT 670 - static bool is_ignored(const char *path, int pathlen, int dirlen, bool is_dir) 671 - { 672 - int i; 673 - 674 - // Search in the reverse order because the last matching pattern wins. 675 - for (i = nr_patterns - 1; i >= 0; i--) { 676 - struct pattern *p = pattern_list[i]; 677 - unsigned int flags = p->flags; 678 - const char *gitignore_dir = p->pattern + p->patternlen + 1; 679 - bool ignored; 680 - 681 - if ((flags & PATTERN_FLAG_MUSTBEDIR) && !is_dir) 682 - continue; 683 - 684 - if (flags & PATTERN_FLAG_NODIR) { 685 - if (!match_basename(path + dirlen + 1, 686 - pathlen - dirlen - 1, 687 - p->pattern, 688 - p->nowildcardlen, 689 - p->patternlen, 690 - p->flags)) 691 - continue; 692 - } else { 693 - if (!match_pathname(path, pathlen, 694 - gitignore_dir, p->dirlen, 695 - p->pattern, 696 - p->nowildcardlen, 697 - p->patternlen)) 698 - continue; 699 - } 700 - 701 - debug("%s: matches %s%s%s (%s/.gitignore)\n", path, 702 - flags & PATTERN_FLAG_NEGATIVE ? "!" : "", p->pattern, 703 - flags & PATTERN_FLAG_MUSTBEDIR ? "/" : "", 704 - gitignore_dir); 705 - 706 - ignored = (flags & PATTERN_FLAG_NEGATIVE) == 0; 707 - if (ignored) 708 - debug("Ignore: %s\n", path); 709 - 710 - return ignored; 711 - } 712 - 713 - debug("%s: no match\n", path); 714 - 715 - return false; 716 - } 717 - 718 - static void add_pattern(const char *string, const char *dir, int dirlen) 719 - { 720 - struct pattern *p; 721 - int patternlen, nowildcardlen; 722 - unsigned int flags; 723 - 724 - parse_path_pattern(&string, &patternlen, &flags, &nowildcardlen); 725 - 726 - if (patternlen == 0) 727 - return; 728 - 729 - p = xmalloc(sizeof(*p) + patternlen + dirlen + 2); 730 - 731 - memcpy(p->pattern, string, patternlen); 732 - p->pattern[patternlen] = 0; 733 - memcpy(p->pattern + patternlen + 1, dir, dirlen); 734 - p->pattern[patternlen + 1 + dirlen] = 0; 735 - 736 - p->patternlen = patternlen; 737 - p->nowildcardlen = nowildcardlen; 738 - p->dirlen = dirlen; 739 - p->flags = flags; 740 - 741 - debug("Add pattern: %s%s%s\n", 742 - flags & PATTERN_FLAG_NEGATIVE ? "!" : "", p->pattern, 743 - flags & PATTERN_FLAG_MUSTBEDIR ? "/" : ""); 744 - 745 - if (nr_patterns >= alloced_patterns) { 746 - alloced_patterns += 128; 747 - pattern_list = xrealloc(pattern_list, 748 - sizeof(*pattern_list) * alloced_patterns); 749 - } 750 - 751 - pattern_list[nr_patterns++] = p; 752 - } 753 - 754 - // similar to add_patterns_from_buffer() in GIT 755 - static void add_patterns_from_gitignore(const char *dir, int dirlen) 756 - { 757 - struct stat st; 758 - char path[PATH_MAX], *buf, *entry; 759 - size_t size; 760 - int fd, pathlen, i; 761 - 762 - pathlen = snprintf(path, sizeof(path), "%s/.gitignore", dir); 763 - if (pathlen >= sizeof(path)) 764 - error_exit("%s: too long path was truncated\n", path); 765 - 766 - fd = open(path, O_RDONLY | O_NOFOLLOW); 767 - if (fd < 0) { 768 - if (errno != ENOENT) 769 - return perror_exit(path); 770 - return; 771 - } 772 - 773 - if (fstat(fd, &st) < 0) 774 - perror_exit(path); 775 - 776 - size = st.st_size; 777 - 778 - buf = xmalloc(size + 1); 779 - if (read(fd, buf, st.st_size) != st.st_size) 780 - perror_exit(path); 781 - 782 - buf[st.st_size] = '\n'; 783 - if (close(fd)) 784 - perror_exit(path); 785 - 786 - debug("Parse %s\n", path); 787 - 788 - entry = buf; 789 - 790 - // skip utf8 bom 791 - if (!strncmp(entry, utf8_bom, strlen(utf8_bom))) 792 - entry += strlen(utf8_bom); 793 - 794 - for (i = entry - buf; i < size; i++) { 795 - if (buf[i] == '\n') { 796 - if (entry != buf + i && entry[0] != '#') { 797 - buf[i - (i && buf[i-1] == '\r')] = 0; 798 - trim_trailing_spaces(entry); 799 - add_pattern(entry, dir, dirlen); 800 - } 801 - entry = buf + i + 1; 802 - } 803 - } 804 - 805 - free(buf); 806 - } 807 - 808 - // Save the current number of patterns and increment the depth 809 - static void increment_depth(void) 810 - { 811 - if (depth >= max_depth) { 812 - max_depth += 1; 813 - nr_patterns_at = xrealloc(nr_patterns_at, 814 - sizeof(*nr_patterns_at) * max_depth); 815 - } 816 - 817 - nr_patterns_at[depth] = nr_patterns; 818 - depth++; 819 - } 820 - 821 - // Decrement the depth, and free up the patterns of this directory level. 822 - static void decrement_depth(void) 823 - { 824 - depth--; 825 - assert(depth >= 0); 826 - 827 - while (nr_patterns > nr_patterns_at[depth]) 828 - free(pattern_list[--nr_patterns]); 829 - } 830 - 831 - static void print_path(const char *path) 832 - { 833 - // The path always starts with "./" 834 - assert(strlen(path) >= 2); 835 - 836 - // Replace the root directory with a preferred prefix. 837 - // This is useful for the tar command. 838 - fprintf(out_fp, "%s%s\n", prefix, path + 2); 839 - } 840 - 841 - static void print_stat(const char *path, struct stat *st) 842 - { 843 - if (!stat_fp) 844 - return; 845 - 846 - if (!S_ISREG(st->st_mode) && !S_ISLNK(st->st_mode)) 847 - return; 848 - 849 - assert(strlen(path) >= 2); 850 - 851 - fprintf(stat_fp, "%c %9ld %10ld %s\n", 852 - S_ISLNK(st->st_mode) ? 'l' : '-', 853 - st->st_size, st->st_mtim.tv_sec, path + 2); 854 - } 855 - 856 - // Traverse the entire directory tree, parsing .gitignore files. 857 - // Print file paths that are not tracked by git. 858 - // 859 - // Return true if all files under the directory are ignored, false otherwise. 860 - static bool traverse_directory(const char *dir, int dirlen) 861 - { 862 - bool all_ignored = true; 863 - DIR *dirp; 864 - 865 - debug("Enter[%d]: %s\n", depth, dir); 866 - increment_depth(); 867 - 868 - add_patterns_from_gitignore(dir, dirlen); 869 - 870 - dirp = opendir(dir); 871 - if (!dirp) 872 - perror_exit(dir); 873 - 874 - while (1) { 875 - struct dirent *d; 876 - struct stat st; 877 - char path[PATH_MAX]; 878 - int pathlen; 879 - bool ignored; 880 - 881 - errno = 0; 882 - d = readdir(dirp); 883 - if (!d) { 884 - if (errno) 885 - perror_exit(dir); 886 - break; 887 - } 888 - 889 - if (!strcmp(d->d_name, "..") || !strcmp(d->d_name, ".")) 890 - continue; 891 - 892 - pathlen = snprintf(path, sizeof(path), "%s/%s", dir, d->d_name); 893 - if (pathlen >= sizeof(path)) 894 - error_exit("%s: too long path was truncated\n", path); 895 - 896 - if (lstat(path, &st) < 0) 897 - perror_exit(path); 898 - 899 - if ((!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode)) || 900 - is_ignored(path, pathlen, dirlen, S_ISDIR(st.st_mode))) { 901 - ignored = true; 902 - } else { 903 - if (S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode)) 904 - // If all the files in a directory are ignored, 905 - // let's ignore that directory as well. This 906 - // will avoid empty directories in the tarball. 907 - ignored = traverse_directory(path, pathlen); 908 - else 909 - ignored = false; 910 - } 911 - 912 - if (ignored) { 913 - print_path(path); 914 - } else { 915 - print_stat(path, &st); 916 - all_ignored = false; 917 - } 918 - } 919 - 920 - if (closedir(dirp)) 921 - perror_exit(dir); 922 - 923 - decrement_depth(); 924 - debug("Leave[%d]: %s\n", depth, dir); 925 - 926 - return all_ignored; 927 - } 928 - 929 - static void usage(void) 930 - { 931 - fprintf(stderr, 932 - "usage: %s [options]\n" 933 - "\n" 934 - "Show files that are ignored by git\n" 935 - "\n" 936 - "options:\n" 937 - " -d, --debug print debug messages to stderr\n" 938 - " -e, --exclude PATTERN add the given exclude pattern\n" 939 - " -h, --help show this help message and exit\n" 940 - " -i, --ignore-case Ignore case differences between the patterns and the files\n" 941 - " -o, --output FILE output the ignored files to a file (default: '-', i.e. stdout)\n" 942 - " -p, --prefix PREFIX prefix added to each path (default: empty string)\n" 943 - " -r, --rootdir DIR root of the source tree (default: current working directory)\n" 944 - " -s, --stat FILE output the file stat of non-ignored files to a file\n", 945 - progname); 946 - } 947 - 948 - static void open_output(const char *pathname, FILE **fp) 949 - { 950 - if (strcmp(pathname, "-")) { 951 - *fp = fopen(pathname, "w"); 952 - if (!*fp) 953 - perror_exit(pathname); 954 - } else { 955 - *fp = stdout; 956 - } 957 - } 958 - 959 - static void close_output(const char *pathname, FILE *fp) 960 - { 961 - fflush(fp); 962 - 963 - if (ferror(fp)) 964 - error_exit("not all data was written to the output\n"); 965 - 966 - if (fclose(fp)) 967 - perror_exit(pathname); 968 - } 969 - 970 - int main(int argc, char *argv[]) 971 - { 972 - const char *output = "-"; 973 - const char *rootdir = "."; 974 - const char *stat = NULL; 975 - 976 - progname = strrchr(argv[0], '/'); 977 - if (progname) 978 - progname++; 979 - else 980 - progname = argv[0]; 981 - 982 - while (1) { 983 - static struct option long_options[] = { 984 - {"debug", no_argument, NULL, 'd'}, 985 - {"help", no_argument, NULL, 'h'}, 986 - {"ignore-case", no_argument, NULL, 'i'}, 987 - {"output", required_argument, NULL, 'o'}, 988 - {"prefix", required_argument, NULL, 'p'}, 989 - {"rootdir", required_argument, NULL, 'r'}, 990 - {"stat", required_argument, NULL, 's'}, 991 - {"exclude", required_argument, NULL, 'x'}, 992 - {}, 993 - }; 994 - 995 - int c = getopt_long(argc, argv, "dhino:p:r:s:x:", long_options, NULL); 996 - 997 - if (c == -1) 998 - break; 999 - 1000 - switch (c) { 1001 - case 'd': 1002 - debug_on = true; 1003 - break; 1004 - case 'h': 1005 - usage(); 1006 - exit(0); 1007 - case 'i': 1008 - ignore_case = true; 1009 - break; 1010 - case 'o': 1011 - output = optarg; 1012 - break; 1013 - case 'p': 1014 - prefix = optarg; 1015 - break; 1016 - case 'r': 1017 - rootdir = optarg; 1018 - break; 1019 - case 's': 1020 - stat = optarg; 1021 - break; 1022 - case 'x': 1023 - add_pattern(optarg, ".", strlen(".")); 1024 - break; 1025 - case '?': 1026 - usage(); 1027 - /* fallthrough */ 1028 - default: 1029 - exit(EXIT_FAILURE); 1030 - } 1031 - } 1032 - 1033 - open_output(output, &out_fp); 1034 - if (stat && stat[0]) 1035 - open_output(stat, &stat_fp); 1036 - 1037 - if (chdir(rootdir)) 1038 - perror_exit(rootdir); 1039 - 1040 - add_pattern(".git/", ".", strlen(".")); 1041 - 1042 - if (traverse_directory(".", strlen("."))) 1043 - print_path("./"); 1044 - 1045 - assert(depth == 0); 1046 - 1047 - while (nr_patterns > 0) 1048 - free(pattern_list[--nr_patterns]); 1049 - free(pattern_list); 1050 - free(nr_patterns_at); 1051 - 1052 - close_output(output, out_fp); 1053 - if (stat_fp) 1054 - close_output(stat, stat_fp); 1055 - 1056 - return 0; 1057 - }
+44
scripts/package/gen-diff-patch
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0-only 3 + 4 + diff_patch="${1}" 5 + untracked_patch="${2}" 6 + srctree=$(dirname $0)/../.. 7 + 8 + rm -f ${diff_patch} ${untracked_patch} 9 + 10 + if ! ${srctree}/scripts/check-git; then 11 + exit 12 + fi 13 + 14 + mkdir -p "$(dirname ${diff_patch})" "$(dirname ${untracked_patch})" 15 + 16 + git -C "${srctree}" diff HEAD > "${diff_patch}" 17 + 18 + if [ ! -s "${diff_patch}" ]; then 19 + rm -f "${diff_patch}" 20 + exit 21 + fi 22 + 23 + git -C ${srctree} status --porcelain --untracked-files=all | 24 + while read stat path 25 + do 26 + if [ "${stat}" = '??' ]; then 27 + 28 + if ! diff -u /dev/null "${srctree}/${path}" > .tmp_diff && 29 + ! head -n1 .tmp_diff | grep -q "Binary files"; then 30 + { 31 + echo "--- /dev/null" 32 + echo "+++ linux/$path" 33 + cat .tmp_diff | tail -n +3 34 + } >> ${untracked_patch} 35 + fi 36 + fi 37 + done 38 + 39 + rm -f .tmp_diff 40 + 41 + if [ ! -s "${diff_patch}" ]; then 42 + rm -f "${diff_patch}" 43 + exit 44 + fi
+9 -1
scripts/package/mkdebian
··· 91 91 if [ -n "$KDEB_PKGVERSION" ]; then 92 92 packageversion=$KDEB_PKGVERSION 93 93 else 94 - packageversion=$version-$($srctree/init/build-version) 94 + packageversion=$(${srctree}/scripts/setlocalversion --no-local ${srctree})-$($srctree/init/build-version) 95 95 fi 96 96 sourcename=${KDEB_SOURCENAME:-linux-upstream} 97 97 ··· 151 151 diff -u /dev/null "${KCONFIG_CONFIG}" | tail -n +3 152 152 } > debian/patches/config 153 153 echo config > debian/patches/series 154 + 155 + $(dirname $0)/gen-diff-patch debian/patches/diff.patch debian/patches/untracked.patch 156 + if [ -f debian/patches/diff.patch ]; then 157 + echo diff.patch >> debian/patches/series 158 + fi 159 + if [ -f debian/patches/untracked.patch ]; then 160 + echo untracked.patch >> debian/patches/series 161 + fi 154 162 155 163 echo $debarch > debian/arch 156 164 extra_build_depends=", $(if_enabled_echo CONFIG_UNWINDER_ORC libelf-dev:native)"
+10
scripts/package/mkspec
··· 19 19 mkdir -p rpmbuild/SOURCES 20 20 cp linux.tar.gz rpmbuild/SOURCES 21 21 cp "${KCONFIG_CONFIG}" rpmbuild/SOURCES/config 22 + $(dirname $0)/gen-diff-patch rpmbuild/SOURCES/diff.patch rpmbuild/SOURCES/untracked.patch 23 + touch rpmbuild/SOURCES/diff.patch rpmbuild/SOURCES/untracked.patch 22 24 fi 23 25 24 26 if grep -q CONFIG_MODULES=y include/config/auto.conf; then ··· 55 53 URL: https://www.kernel.org 56 54 $S Source0: linux.tar.gz 57 55 $S Source1: config 56 + $S Source2: diff.patch 57 + $S Source3: untracked.patch 58 58 Provides: $PROVIDES 59 59 $S BuildRequires: bc binutils bison dwarves 60 60 $S BuildRequires: (elfutils-libelf-devel or libelf-devel) flex ··· 94 90 $S %prep 95 91 $S %setup -q -n linux 96 92 $S cp %{SOURCE1} .config 93 + $S if [ -s %{SOURCE2} ]; then 94 + $S patch -p1 < %{SOURCE2} 95 + $S fi 96 + $S if [ -s %{SOURCE3} ]; then 97 + $S patch -p1 < %{SOURCE3} 98 + $S fi 97 99 $S 98 100 $S %build 99 101 $S $MAKE %{?_smp_mflags} KERNELRELEASE=$KERNELRELEASE KBUILD_BUILD_VERSION=%{release}
+34 -11
scripts/setlocalversion
··· 11 11 # 12 12 13 13 usage() { 14 - echo "Usage: $0 [srctree]" >&2 14 + echo "Usage: $0 [--no-local] [srctree]" >&2 15 15 exit 1 16 16 } 17 + 18 + no_local=false 19 + if test "$1" = "--no-local"; then 20 + no_local=true 21 + shift 22 + fi 17 23 18 24 srctree=. 19 25 if test $# -gt 0; then ··· 32 26 33 27 scm_version() 34 28 { 35 - local short 29 + local short=false 30 + local no_dirty=false 36 31 local tag 37 - short=false 32 + 33 + while [ $# -gt 0 ]; 34 + do 35 + case "$1" in 36 + --short) 37 + short=true;; 38 + --no-dirty) 39 + no_dirty=true;; 40 + esac 41 + shift 42 + done 38 43 39 44 cd "$srctree" 40 - if test "$1" = "--short"; then 41 - short=true 42 - fi 43 45 44 46 if test -n "$(git rev-parse --show-cdup 2>/dev/null)"; then 45 47 return ··· 89 75 printf '%s%s' -g "$(echo $head | cut -c1-12)" 90 76 fi 91 77 78 + if ${no_dirty}; then 79 + return 80 + fi 81 + 92 82 # Check for uncommitted changes. 93 83 # This script must avoid any write attempt to the source tree, which 94 84 # might be read-only. ··· 128 110 echo "$res" 129 111 } 130 112 131 - if ! test -e include/config/auto.conf; then 132 - echo "Error: kernelrelease not valid - run 'make prepare' to update it" >&2 133 - exit 1 134 - fi 135 - 136 113 if [ -z "${KERNELVERSION}" ]; then 137 114 echo "KERNELVERSION is not set" >&2 138 115 exit 1 ··· 137 124 file_localversion="$(collect_files localversion*)" 138 125 if test ! "$srctree" -ef .; then 139 126 file_localversion="${file_localversion}$(collect_files "$srctree"/localversion*)" 127 + fi 128 + 129 + if ${no_local}; then 130 + echo "${KERNELVERSION}$(scm_version --no-dirty)" 131 + exit 0 132 + fi 133 + 134 + if ! test -e include/config/auto.conf; then 135 + echo "Error: kernelrelease not valid - run 'make prepare' to update it" >&2 136 + exit 1 140 137 fi 141 138 142 139 # version string from CONFIG_LOCALVERSION