Compare commits
53
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8cfc8acfb | ||
|
|
7c07610ab2 | ||
|
|
ff88430efb | ||
|
|
06dd8ee6d7 | ||
|
|
c0aa7b436c | ||
|
|
b80fa9dcd2 | ||
|
|
95187bcc64 | ||
|
|
f2a5b62733 | ||
|
|
385ca6772c | ||
|
|
88c307b65b | ||
|
|
9d425b0588 | ||
|
|
cf84a260ca | ||
|
|
c4e024c7e3 | ||
|
|
c5a29b5b26 | ||
|
|
4c64843d60 | ||
|
|
b4ff96d754 | ||
|
|
21c5ac2161 | ||
|
|
6fc0b41f97 | ||
|
|
0b0b2143ed | ||
|
|
af64140c61 | ||
|
|
1c68062231 | ||
|
|
4d92855d76 | ||
|
|
1c6f542cb7 | ||
|
|
b28066c85d | ||
|
|
71c8a2c36f | ||
|
|
e4ab7b4ff3 | ||
|
|
8b978d4712 | ||
|
|
7b319111d3 | ||
|
|
cb7cea93a2 | ||
|
|
20257faf54 | ||
|
|
c14abebd68 | ||
|
|
b1a1a90045 | ||
|
|
8afc9855f2 | ||
|
|
4215058911 | ||
|
|
9fb1a18dbf | ||
|
|
064213ceb8 | ||
|
|
0211251b34 | ||
|
|
1903da569b | ||
|
|
b6a7beca1f | ||
|
|
7b83e7403e | ||
|
|
1915a470e9 | ||
|
|
0b100296e1 | ||
|
|
e6ed3acf5f | ||
|
|
9f95bf3573 | ||
|
|
b05ece0681 | ||
|
|
5381178c46 | ||
|
|
e7f4f8306c | ||
|
|
9922a3abd9 | ||
|
|
40ab668a73 | ||
|
|
10d20c4800 | ||
|
|
700bb75016 | ||
|
|
e25de22705 | ||
|
|
ef6d561c66 |
@@ -37,6 +37,51 @@ env:
|
||||
|
||||
jobs:
|
||||
|
||||
#
|
||||
# Source
|
||||
#
|
||||
|
||||
facts:
|
||||
name: Gather common facts
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.get-version.outputs.version }}
|
||||
release-kind: ${{ steps.get-version.outputs.release-kind }}
|
||||
go-version: ${{ steps.get-go.outputs.go-version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Get Syncthing version
|
||||
id: get-version
|
||||
run: |
|
||||
version=$(go run build.go version)
|
||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||
echo "Version: $version"
|
||||
|
||||
kind=stable
|
||||
if [[ $version == *-rc.[0-9] || $version == *-rc.[0-9][0-9] ]] ; then
|
||||
kind=candidate
|
||||
elif [[ $version == *-* ]] ; then
|
||||
kind=nightly
|
||||
fi
|
||||
echo "release-kind=$kind" >> "$GITHUB_OUTPUT"
|
||||
echo "Release kind: $kind"
|
||||
|
||||
- name: Get Go version
|
||||
id: get-go
|
||||
run: |
|
||||
go version
|
||||
echo "go-version=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_OUTPUT
|
||||
|
||||
#
|
||||
# Tests for all platforms. Runs a matrix build on Windows, Linux and Mac,
|
||||
# with the list of expected supported Go versions (current, previous).
|
||||
@@ -123,17 +168,18 @@ jobs:
|
||||
package-windows:
|
||||
name: Package for Windows
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- uses: mlugg/setup-zig@v2
|
||||
|
||||
@@ -142,7 +188,7 @@ jobs:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-package-windows-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-package-windows-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -231,22 +277,18 @@ jobs:
|
||||
package-linux:
|
||||
name: Package for Linux
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Get actual Go version
|
||||
run: |
|
||||
go version
|
||||
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
|
||||
|
||||
- uses: mlugg/setup-zig@v2
|
||||
|
||||
@@ -255,7 +297,7 @@ jobs:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-package-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-package-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
- name: Create packages
|
||||
run: |
|
||||
@@ -297,32 +339,27 @@ jobs:
|
||||
name: Package for macOS
|
||||
if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release-nightly' || startsWith(github.ref, 'refs/tags/v'))
|
||||
environment: release
|
||||
runs-on: macos-latest
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
CODESIGN_IDENTITY: ${{ secrets.CODESIGN_IDENTITY }}
|
||||
runs-on: macos-latest
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Get actual Go version
|
||||
run: |
|
||||
go version
|
||||
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-package-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-package-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
- name: Import signing certificate
|
||||
if: env.CODESIGN_IDENTITY != ''
|
||||
@@ -432,29 +469,25 @@ jobs:
|
||||
package-cross:
|
||||
name: Package cross compiled
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Get actual Go version
|
||||
run: |
|
||||
go version
|
||||
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-cross-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-cross-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
- name: Create packages
|
||||
run: |
|
||||
@@ -502,33 +535,33 @@ jobs:
|
||||
package-source:
|
||||
name: Package source code
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Package source
|
||||
run: |
|
||||
version=$(go run build.go version)
|
||||
echo "$version" > RELEASE
|
||||
echo "$VERSION" > RELEASE
|
||||
|
||||
go mod vendor
|
||||
go run build.go assets
|
||||
|
||||
cd ..
|
||||
|
||||
tar c -z -f "syncthing-source-$version.tar.gz" \
|
||||
tar c -z -f "syncthing-source-$VERSION.tar.gz" \
|
||||
--exclude .git \
|
||||
syncthing
|
||||
|
||||
mv "syncthing-source-$version.tar.gz" syncthing
|
||||
mv "syncthing-source-$VERSION.tar.gz" syncthing
|
||||
|
||||
- name: Archive artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -550,27 +583,26 @@ jobs:
|
||||
- package-macos
|
||||
- package-cross
|
||||
- package-source
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: syncthing/release-tools
|
||||
path: tools
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Install signing tool
|
||||
run: |
|
||||
@@ -597,9 +629,6 @@ jobs:
|
||||
sha256sum "${files[@]}" > sha256sum.txt
|
||||
popd
|
||||
|
||||
version=$(go run build.go version)
|
||||
echo "VERSION=$version" >> $GITHUB_ENV
|
||||
|
||||
- name: Sign shasum files
|
||||
uses: docker://ghcr.io/kastelo/ezapt:latest
|
||||
with:
|
||||
@@ -635,22 +664,18 @@ jobs:
|
||||
package-debian:
|
||||
name: Package for Debian
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Get actual Go version
|
||||
run: |
|
||||
go version
|
||||
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
|
||||
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
@@ -667,13 +692,14 @@ jobs:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-debian-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-debian-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
- name: Package for Debian (CGO)
|
||||
run: |
|
||||
for tgt in syncthing stdiscosrv strelaysrv ; do
|
||||
go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch amd64 -cc "zig cc -target x86_64-linux-musl" deb "$tgt"
|
||||
go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch arm -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" deb "$tgt"
|
||||
go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch armel -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" deb "$tgt"
|
||||
go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch armhf -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" deb "$tgt"
|
||||
go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch arm64 -cc "zig cc -target aarch64-linux-musl" deb "$tgt"
|
||||
done
|
||||
env:
|
||||
@@ -697,13 +723,13 @@ jobs:
|
||||
environment: release
|
||||
needs:
|
||||
- sign-for-upgrade
|
||||
- facts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: syncthing/release-tools
|
||||
path: tools
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -713,9 +739,8 @@ jobs:
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Create release json
|
||||
run: |
|
||||
@@ -735,7 +760,7 @@ jobs:
|
||||
RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACL: public-read
|
||||
with:
|
||||
args: sync -v packages objstore:nightly
|
||||
args: sync -v --no-update-modtime packages objstore:nightly
|
||||
|
||||
#
|
||||
# Push release artifacts to Spaces
|
||||
@@ -750,6 +775,10 @@ jobs:
|
||||
needs:
|
||||
- sign-for-upgrade
|
||||
- package-debian
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -771,14 +800,8 @@ jobs:
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Set version
|
||||
run: |
|
||||
version=$(go run build.go version)
|
||||
echo "VERSION=$version" >> $GITHUB_ENV
|
||||
|
||||
- name: Push to object store (${{ env.VERSION }})
|
||||
uses: docker://docker.io/rclone/rclone:latest
|
||||
@@ -791,7 +814,7 @@ jobs:
|
||||
RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACL: public-read
|
||||
with:
|
||||
args: sync -v packages objstore:release/${{ env.VERSION }}
|
||||
args: sync -v --no-update-modtime packages objstore:release/${{ env.VERSION }}
|
||||
|
||||
- name: Push to object store (latest)
|
||||
uses: docker://docker.io/rclone/rclone:latest
|
||||
@@ -804,7 +827,7 @@ jobs:
|
||||
RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACL: public-read
|
||||
with:
|
||||
args: sync -v objstore:release/${{ env.VERSION }} objstore:release/latest
|
||||
args: sync -v --no-update-modtime objstore:release/${{ env.VERSION }} objstore:release/latest
|
||||
|
||||
- name: Create GitHub releases and push binaries
|
||||
run: |
|
||||
@@ -819,7 +842,7 @@ jobs:
|
||||
--title "$VERSION" \
|
||||
--notes-from-tag
|
||||
fi
|
||||
gh release upload "$VERSION" \
|
||||
gh release upload --clobber "$VERSION" \
|
||||
packages/*.asc packages/*.json \
|
||||
packages/syncthing-*.tar.gz \
|
||||
packages/syncthing-*.zip \
|
||||
@@ -835,7 +858,7 @@ jobs:
|
||||
--title "$VERSION" \
|
||||
--notes "https://github.com/syncthing/syncthing/releases/tag/$VERSION"
|
||||
fi
|
||||
gh release upload "$VERSION" \
|
||||
gh release upload --clobber "$VERSION" \
|
||||
$PKGS/*.asc \
|
||||
$PKGS/*${repo}*
|
||||
done
|
||||
@@ -852,12 +875,13 @@ jobs:
|
||||
environment: release
|
||||
needs:
|
||||
- package-debian
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- name: Download packages
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -865,24 +889,11 @@ jobs:
|
||||
name: debian-packages
|
||||
path: packages
|
||||
|
||||
- name: Set version
|
||||
run: |
|
||||
version=$(go run build.go version)
|
||||
echo "Version: $version"
|
||||
echo "VERSION=$version" >> $GITHUB_ENV
|
||||
|
||||
# Decide whether packages should go to stable, candidate or nightly
|
||||
- name: Prepare packages
|
||||
run: |
|
||||
kind=stable
|
||||
if [[ $VERSION == *-rc.[0-9] || $VERSION == *-rc.[0-9][0-9] ]] ; then
|
||||
kind=candidate
|
||||
elif [[ $VERSION == *-* ]] ; then
|
||||
kind=nightly
|
||||
fi
|
||||
echo "Kind: $kind"
|
||||
mkdir -p packages/syncthing/$kind
|
||||
mv packages/*.deb packages/syncthing/$kind
|
||||
mkdir -p packages/syncthing/$RELEASE_KIND
|
||||
mv packages/*.deb packages/syncthing/$RELEASE_KIND
|
||||
|
||||
- name: Pull archive
|
||||
uses: docker://docker.io/rclone/rclone:latest
|
||||
@@ -918,7 +929,7 @@ jobs:
|
||||
RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACL: public-read
|
||||
with:
|
||||
args: sync -v dists objstore:apt/dists
|
||||
args: sync -v --no-update-modtime dists objstore:apt/dists
|
||||
|
||||
#
|
||||
# Build and push (except for PRs) to GHCR.
|
||||
@@ -930,6 +941,11 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
strategy:
|
||||
matrix:
|
||||
pkg:
|
||||
@@ -948,20 +964,11 @@ jobs:
|
||||
image: discosrv
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Get actual Go version
|
||||
run: |
|
||||
go version
|
||||
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
|
||||
|
||||
- uses: mlugg/setup-zig@v2
|
||||
|
||||
@@ -970,7 +977,7 @@ jobs:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-docker-${{ matrix.pkg }}-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-docker-${{ matrix.pkg }}-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
- name: Build binaries (CGO)
|
||||
run: |
|
||||
@@ -1002,8 +1009,7 @@ jobs:
|
||||
|
||||
- name: Set version tags
|
||||
run: |
|
||||
version=$(go run build.go version)
|
||||
version=${version#v}
|
||||
version=${VERSION#v}
|
||||
repo=ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}
|
||||
ref="${{github.ref_name}}"
|
||||
ref=${ref//\//-} # slashes to dashes
|
||||
@@ -1022,9 +1028,7 @@ jobs:
|
||||
fi
|
||||
|
||||
echo Pushing to $tags
|
||||
|
||||
echo "DOCKER_TAGS=$tags" >> $GITHUB_ENV
|
||||
echo "VERSION=$version" >> $GITHUB_ENV
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
@@ -1069,14 +1073,15 @@ jobs:
|
||||
govulncheck:
|
||||
runs-on: ubuntu-latest
|
||||
name: Run govulncheck
|
||||
needs:
|
||||
- facts
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: run govulncheck
|
||||
run: |
|
||||
@@ -1091,6 +1096,7 @@ jobs:
|
||||
golangci:
|
||||
runs-on: ubuntu-latest
|
||||
name: Run golangci-lint
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
|
||||
@@ -51,3 +51,10 @@ jobs:
|
||||
git config --global user.email 'release@syncthing.net'
|
||||
git tag -a -F notes.md --cleanup=whitespace "$NEXT"
|
||||
git push origin "$NEXT"
|
||||
|
||||
- name: Trigger the build
|
||||
uses: benc-uk/workflow-dispatch@v1
|
||||
with:
|
||||
workflow: build-syncthing.yaml
|
||||
ref: refs/tags/${{ env.NEXT }}
|
||||
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
|
||||
|
||||
@@ -8,12 +8,14 @@ linters:
|
||||
- exhaustive
|
||||
- exhaustruct
|
||||
- forbidigo
|
||||
- funcorder
|
||||
- funlen
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gocognit
|
||||
- goconst
|
||||
- gocyclo
|
||||
- godot
|
||||
- godox
|
||||
- gomoddirectives
|
||||
- inamedparam
|
||||
@@ -25,6 +27,7 @@ linters:
|
||||
- musttag
|
||||
- nestif
|
||||
- nlreturn
|
||||
- noinlineerr
|
||||
- nonamedreturns
|
||||
- paralleltest
|
||||
- prealloc
|
||||
@@ -40,6 +43,7 @@ linters:
|
||||
- whitespace
|
||||
- wrapcheck
|
||||
- wsl
|
||||
- wsl_v5
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
@@ -49,6 +53,7 @@ linters:
|
||||
- std-error-handling
|
||||
paths:
|
||||
- internal/gen
|
||||
- internal/db/olddb
|
||||
- cmd/dev
|
||||
- repos
|
||||
- third_party$
|
||||
|
||||
@@ -56,10 +56,12 @@ Anthony Goeckner <agoeckner@users.noreply.github.com>
|
||||
Antoine Lamielle (0x010C) <antoine.lamielle@0x010c.fr> <gh@0x010c.fr>
|
||||
Anur <anurnomeru@163.com>
|
||||
Aranjedeath <Aranjedeath@users.noreply.github.com>
|
||||
ardevd <ardevd@users.noreply.github.com>
|
||||
Arkadiusz Tymiński <gevleeog@gmail.com>
|
||||
Aroun <login@b-vo.fr>
|
||||
Arthur Axel fREW Schmidt (frioux) <frew@afoolishmanifesto.com> <frioux@gmail.com>
|
||||
Artur Zubilewicz <AkaZecik@users.noreply.github.com>
|
||||
Ashish Bhate <bhate.ashish@gmail.com>
|
||||
Aurélien Rainone <476650+arl@users.noreply.github.com>
|
||||
BAHADIR YILMAZ <bahadiryilmaz32@gmail.com>
|
||||
Bart De Vries (mogwa1) <devriesb@gmail.com>
|
||||
@@ -192,6 +194,7 @@ Luke Hamburg <1992842+luckman212@users.noreply.github.com>
|
||||
luzpaz <luzpaz@users.noreply.github.com>
|
||||
Majed Abdulaziz (majedev) <majed.alhajry@gmail.com>
|
||||
Marc Laporte (marclaporte) <marc@marclaporte.com> <marc@laporte.name>
|
||||
Marcel Meyer <mm.marcelmeyer@gmail.com>
|
||||
Marcin Dziadus (marcindziadus) <dziadus.marcin@gmail.com>
|
||||
Marcus B Spencer <marcus@marcusspencer.xyz> <marcus@marcusspencer.us>
|
||||
Marcus Legendre <marcus.legendre@gmail.com>
|
||||
@@ -252,6 +255,7 @@ Philippe Schommers (filoozoom) <philippe@schommers.be>
|
||||
Phill Luby (pluby) <phill.luby@newredo.com>
|
||||
Piotr Bejda (piobpl) <piotrb10@gmail.com>
|
||||
polyfloyd <polyfloyd@users.noreply.github.com>
|
||||
pullmerge <166967364+pullmerge@users.noreply.github.com>
|
||||
Quentin Hibon <qh.public@yahoo.com>
|
||||
Rahmi Pruitt <rjpruitt16@gmail.com>
|
||||
red_led <red-led@users.noreply.github.com>
|
||||
@@ -312,5 +316,6 @@ xarx00 <xarx00@users.noreply.github.com>
|
||||
Xavier O. (damajor) <damajor@gmail.com>
|
||||
xjtdy888 (xjtdy888) <xjtdy888@163.com> <xjtdy888@gmail.com>
|
||||
Yannic A. (eipiminus1) <eipiminusone+github@gmail.com> <eipiminus1@users.noreply.github.com>
|
||||
yparitcher <y@paritcher.com>
|
||||
佛跳墙 <daoquan@qq.com>
|
||||
落心 <luoxin.ttt@gmail.com>
|
||||
|
||||
@@ -901,6 +901,7 @@ func weblate() {
|
||||
func ldflags(tags []string) string {
|
||||
b := new(strings.Builder)
|
||||
b.WriteString("-w")
|
||||
b.WriteString(" -buildid=")
|
||||
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Version=%s", version)
|
||||
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Stamp=%d", buildStamp())
|
||||
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.User=%s", buildUser())
|
||||
@@ -922,6 +923,9 @@ func rmr(paths ...string) {
|
||||
}
|
||||
|
||||
func getReleaseVersion() (string, error) {
|
||||
if ver := os.Getenv("VERSION"); ver != "" {
|
||||
return strings.TrimSpace(ver), nil
|
||||
}
|
||||
bs, err := os.ReadFile("RELEASE")
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -966,7 +970,7 @@ func getGitVersion() (string, error) {
|
||||
}
|
||||
|
||||
func getVersion() string {
|
||||
// First try for a RELEASE file,
|
||||
// First try for a RELEASE file or $VERSION env var,
|
||||
if ver, err := getReleaseVersion(); err == nil {
|
||||
return ver
|
||||
}
|
||||
|
||||
@@ -620,7 +620,7 @@ func createTestCertificate() tls.Certificate {
|
||||
}
|
||||
|
||||
certFile, keyFile := filepath.Join(tmpDir, "cert.pem"), filepath.Join(tmpDir, "key.pem")
|
||||
cert, err := tlsutil.NewCertificate(certFile, keyFile, "relaypoolsrv", 20*365)
|
||||
cert, err := tlsutil.NewCertificate(certFile, keyFile, "relaypoolsrv", 20*365, false)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to create test X509 key pair:", err)
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ func fetchStats(relay *relay) *stats {
|
||||
|
||||
var stats stats
|
||||
|
||||
if json.NewDecoder(response.Body).Decode(&stats); err != nil {
|
||||
if err := json.NewDecoder(response.Body).Decode(&stats); err != nil {
|
||||
return nil
|
||||
}
|
||||
return &stats
|
||||
|
||||
@@ -115,7 +115,7 @@ func BenchmarkAPIRequests(b *testing.B) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(api.handler))
|
||||
|
||||
kf := b.TempDir() + "/cert"
|
||||
crt, err := tlsutil.NewCertificate(kf+".crt", kf+".key", "localhost", 7)
|
||||
crt, err := tlsutil.NewCertificate(kf+".crt", kf+".key", "localhost", 7, true)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func main() {
|
||||
cert, err = tls.LoadX509KeyPair(cli.Cert, cli.Key)
|
||||
if os.IsNotExist(err) {
|
||||
log.Println("Failed to load keypair. Generating one, this might take a while...")
|
||||
cert, err = tlsutil.NewCertificate(cli.Cert, cli.Key, "stdiscosrv", 20*365)
|
||||
cert, err = tlsutil.NewCertificate(cli.Cert, cli.Key, "stdiscosrv", 20*365, false)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to generate X509 key pair:", err)
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ func main() {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
log.Println("Failed to load keypair. Generating one, this might take a while...")
|
||||
cert, err = tlsutil.NewCertificate(certFile, keyFile, "strelaysrv", 20*365)
|
||||
cert, err = tlsutil.NewCertificate(certFile, keyFile, "strelaysrv", 20*365, false)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to generate X509 key pair:", err)
|
||||
}
|
||||
|
||||
+35
-5
@@ -403,9 +403,11 @@ func upgradeViaRest() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
bs, err := io.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -611,8 +613,7 @@ func setupSignalHandling(app *syncthing.App) {
|
||||
// Exit cleanly with "restarting" code on SIGHUP.
|
||||
|
||||
restartSign := make(chan os.Signal, 1)
|
||||
sigHup := syscall.Signal(1)
|
||||
signal.Notify(restartSign, sigHup)
|
||||
signal.Notify(restartSign, syscall.SIGHUP)
|
||||
go func() {
|
||||
<-restartSign
|
||||
app.Stop(svcutil.ExitRestart)
|
||||
@@ -919,8 +920,10 @@ func (browserCmd) Run() error {
|
||||
}
|
||||
|
||||
type debugCmd struct {
|
||||
ResetDatabase resetDatabaseCmd `cmd:"" help:"Reset the database, forcing a full rescan and resync"`
|
||||
DatabaseStatistics databaseStatsCmd `cmd:"" help:"Display database size statistics"`
|
||||
ResetDatabase resetDatabaseCmd `cmd:"" help:"Reset the database, forcing a full rescan and resync"`
|
||||
DatabaseStatistics databaseStatsCmd `cmd:"" help:"Display database size statistics"`
|
||||
DatabaseCounts databaseCountsCmd `cmd:"" help:"Display database folder counts"`
|
||||
DatabaseFile databaseFileCmd `cmd:"" help:"Display database file metadata"`
|
||||
}
|
||||
|
||||
type resetDatabaseCmd struct{}
|
||||
@@ -955,6 +958,33 @@ func (c databaseStatsCmd) Run() error {
|
||||
return tw.Flush()
|
||||
}
|
||||
|
||||
type databaseCountsCmd struct {
|
||||
Folder string `arg:"" required:""`
|
||||
}
|
||||
|
||||
func (c databaseCountsCmd) Run() error {
|
||||
db, err := sqlite.Open(locations.Get(locations.Database))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.DebugCounts(os.Stdout, c.Folder)
|
||||
}
|
||||
|
||||
type databaseFileCmd struct {
|
||||
Folder string `arg:"" required:""`
|
||||
File string `arg:"" required:""`
|
||||
}
|
||||
|
||||
func (c databaseFileCmd) Run() error {
|
||||
db, err := sqlite.Open(locations.Get(locations.Database))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.DebugFilePattern(os.Stdout, c.Folder, c.File)
|
||||
}
|
||||
|
||||
func (c databaseStatsCmd) printStat(w io.Writer, s *sqlite.DatabaseStatistics) {
|
||||
for _, table := range s.Tables {
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%8d KiB\t%5.01f %%\n", s.Name, cmp.Or(s.FolderID, "-"), table.Name, table.Size/1024, float64(table.Size-table.Unused)*100/float64(table.Size))
|
||||
|
||||
@@ -32,3 +32,10 @@
|
||||
darwin: "20"
|
||||
linux: "3.2"
|
||||
windows: "10.0"
|
||||
|
||||
- runtime: go1.25
|
||||
requirements:
|
||||
# macOS 12 (Monterey) per https://tip.golang.org/doc/go1.25#darwin
|
||||
darwin: "21"
|
||||
linux: "3.2"
|
||||
windows: "10.0"
|
||||
|
||||
@@ -18,4 +18,4 @@ env STNORESTART=yes
|
||||
respawn
|
||||
|
||||
# the syncthing command Upstart is to execute when it is started up
|
||||
exec $SYNCTHING_EXE -no-browser
|
||||
exec $SYNCTHING_EXE --no-browser
|
||||
|
||||
@@ -10,6 +10,7 @@ require (
|
||||
github.com/calmh/incontainer v1.0.0
|
||||
github.com/calmh/xdr v1.2.0
|
||||
github.com/ccding/go-stun v0.1.5
|
||||
github.com/coreos/go-semver v0.3.1
|
||||
github.com/d4l3k/messagediff v1.2.1
|
||||
github.com/getsentry/raven-go v0.2.0
|
||||
github.com/go-ldap/ldap/v3 v3.4.11
|
||||
@@ -40,6 +41,7 @@ require (
|
||||
github.com/urfave/cli v1.22.16
|
||||
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
|
||||
github.com/willabides/kongplete v0.4.0
|
||||
github.com/wlynxg/anet v0.0.5
|
||||
go.uber.org/automaxprocs v1.6.0
|
||||
golang.org/x/crypto v0.38.0
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
|
||||
@@ -61,7 +63,6 @@ require (
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
|
||||
@@ -274,6 +274,8 @@ github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0 h1:okhMind4q9H1OxF44gN
|
||||
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0/go.mod h1:TTbGUfE+cXXceWtbTHq6lqcTvYPBKLNejBEbnUsQJtU=
|
||||
github.com/willabides/kongplete v0.4.0 h1:eivXxkp5ud5+4+NVN9e4goxC5mSh3n1RHov+gsblM2g=
|
||||
github.com/willabides/kongplete v0.4.0/go.mod h1:0P0jtWD9aTsqPSUAl4de35DLghrr57XcayPyvqSi2X8=
|
||||
github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
|
||||
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Научете повече",
|
||||
"Learn more at {%url%}": "Научете повече на {{url}}",
|
||||
"Limit": "Ограничение",
|
||||
"Limit Bandwidth in LAN": "Огранич. на скоростта в местната мрежа",
|
||||
"Listener Failures": "Грешки при очакване на връзка",
|
||||
"Listener Status": "Очакване на връзка",
|
||||
"Listeners": "Очакване на връзка",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"Allowed Networks": "Xarxes permeses",
|
||||
"Alphabetic": "Alfabètic",
|
||||
"Altered by ignoring deletes.": "S'ha alterat ignorant les supressions.",
|
||||
"Always turned on when the folder type is \"{%foldertype%}\".": "Sempre activat quan el tipus de carpeta és \"{{foldertype}}\".",
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Una ordre externa gestiona la versió. Ha d'eliminar el fitxer de la carpeta compartida. Si el camí a l'aplicació conté espais, s'ha de citar.",
|
||||
"Anonymous Usage Reporting": "Informe anònim d'ús",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "El format de l'informe d'ús anònim ha canviat. Voleu canviar a aquest nou format?",
|
||||
@@ -52,6 +53,7 @@
|
||||
"Body:": "Cos de text:",
|
||||
"Bugs": "Errors (Bugs)",
|
||||
"Cancel": "Cancel·la",
|
||||
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "No es pot habilitar quan el tipus de carpeta és \"{{foldertype}}\".",
|
||||
"Changelog": "Historial de canvis",
|
||||
"Clean out after": "Netejar després",
|
||||
"Cleaning Versions": "Netejant versions",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Mehr erfahren",
|
||||
"Learn more at {%url%}": "Erfahren Sie mehr unter {{url}}",
|
||||
"Limit": "Limit",
|
||||
"Limit Bandwidth in LAN": "Bandbreite im LAN begrenzen",
|
||||
"Listener Failures": "Fehler bei Listener",
|
||||
"Listener Status": "Status der Listener",
|
||||
"Listeners": "Zuhörer",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Learn more",
|
||||
"Learn more at {%url%}": "Learn more at {{url}}",
|
||||
"Limit": "Limit",
|
||||
"Limit Bandwidth in LAN": "Limit Bandwidth in LAN",
|
||||
"Listener Failures": "Listener Failures",
|
||||
"Listener Status": "Listener Status",
|
||||
"Listeners": "Listeners",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Learn more",
|
||||
"Learn more at {%url%}": "Learn more at {{url}}",
|
||||
"Limit": "Limit",
|
||||
"Limit Bandwidth in LAN": "Limit Bandwidth in LAN",
|
||||
"Listener Failures": "Listener Failures",
|
||||
"Listener Status": "Listener Status",
|
||||
"Listeners": "Listeners",
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
"New Folder": "Uus Kaust",
|
||||
"Newest First": "Uusimad Ennem",
|
||||
"No": "Ei",
|
||||
"OK": "OK",
|
||||
"OK": "Sobib",
|
||||
"Oldest First": "Vanimad Ennem",
|
||||
"Options": "Valikud",
|
||||
"Outgoing Rate Limit (KiB/s)": "Väljuva Kiiruse Piirang (KiB/s)",
|
||||
@@ -116,7 +116,7 @@
|
||||
"The device ID cannot be blank.": "Seadme ID ei tohi olla tühi.",
|
||||
"The folder ID cannot be blank.": "Kausta ID ei tohi olla tühi.",
|
||||
"The folder ID must be unique.": "Kausta ID peab olema unikaalne.",
|
||||
"The folder path cannot be blank.": "Kausta asukoht ei tohi olla tühi!",
|
||||
"The folder path cannot be blank.": "Kausta asukoht ei tohi olla tühi.",
|
||||
"The following items could not be synchronized.": "Järgnevaid üksusi ei õnnestunud sünkroniseerida.",
|
||||
"The maximum age must be a number and cannot be blank.": "Maksimaalne vanus peab olema arv ning ei tohi olla tühi.",
|
||||
"Unknown": "Teadmata",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "En savoir plus",
|
||||
"Learn more at {%url%}": "Si vous souhaitez en savoir plus, c'est ici (en anglais) : {{url}}",
|
||||
"Limit": "Limite",
|
||||
"Limit Bandwidth in LAN": "Limiter la bande passante locale (LAN)",
|
||||
"Listener Failures": "Échecs de l'écouteur",
|
||||
"Listener Status": "État de l'écouteur",
|
||||
"Listeners": "Écoute",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Faigh tuilleadh eolais",
|
||||
"Learn more at {%url%}": "Tuilleadh eolais ag {{url}}",
|
||||
"Limit": "Teorainn",
|
||||
"Limit Bandwidth in LAN": "Teorainn a chur ar an bandaleithead i LAN",
|
||||
"Listener Failures": "Teipeanna an Éisteora",
|
||||
"Listener Status": "Stádas an éisteora",
|
||||
"Listeners": "Éisteoirí",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"Allowed Networks": "רשתות מורשות",
|
||||
"Alphabetic": "אלפביתי",
|
||||
"Altered by ignoring deletes.": "השתנה על ידי התעלמות ממחיקות.",
|
||||
"Always turned on when the folder type is \"{%foldertype%}\".": "תמיד מופעל כאשר סוג התיקייה הוא \"{{foldertype}}\".",
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "פקודה חיצונית מטפלת בניהול הגרסאות. היא חייבת להסיר את הקובץ מהתיקייה המשותפת. אם הנתיב ליישום מכיל רווחים, יש לצטט אותו.",
|
||||
"Anonymous Usage Reporting": "דיווח שימוש אנונימי",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "פורמט דוח שימוש אנונימי השתנה. האם ברצונך לעבור לפורמט החדש?",
|
||||
@@ -52,6 +53,7 @@
|
||||
"Body:": "גוף:",
|
||||
"Bugs": "באגים",
|
||||
"Cancel": "ביטול",
|
||||
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "לא ניתן לאפשור כאשר סוג התיקייה הוא \"{{foldertype}}\".",
|
||||
"Changelog": "יומן שינויים",
|
||||
"Clean out after": "נקה לאחר",
|
||||
"Cleaning Versions": "מנקה גרסאות",
|
||||
@@ -225,6 +227,7 @@
|
||||
"Learn more": "למד עוד",
|
||||
"Learn more at {%url%}": "למד עוד באתר {{url}}",
|
||||
"Limit": "מגבלה",
|
||||
"Limit Bandwidth in LAN": "הגבלת רוחב פס ברשת תקשורת מקומית (LAN)",
|
||||
"Listener Failures": "כשלי מאזין",
|
||||
"Listener Status": "מצב מאזין",
|
||||
"Listeners": "מאזינים",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "더 알아보기",
|
||||
"Learn more at {%url%}": "자세한 내용은 {{url}}을 참조하십시오.",
|
||||
"Limit": "제한",
|
||||
"Limit Bandwidth in LAN": "근거리 통신망(LAN)에 속도 제한 적용",
|
||||
"Listener Failures": "대기자 실패",
|
||||
"Listener Status": "대기자 현황",
|
||||
"Listeners": "대기자",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"Allowed Networks": "Toegestane netwerken",
|
||||
"Alphabetic": "Alfabetisch",
|
||||
"Altered by ignoring deletes.": "Veranderd door het negeren van verwijderingen.",
|
||||
"Always turned on when the folder type is \"{%foldertype%}\".": "Altijd aanzetten als het map-type \"{{foldertype}}\" is.",
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Een externe opdracht regelt het versiebeheer. Hij moet het bestand verwijderen uit de gedeelde map. Als het pad naar de toepassing spaties bevat, moet dit tussen aanhalingstekens geplaatst worden.",
|
||||
"Anonymous Usage Reporting": "Anonieme gebruikersstatistieken",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Het formaat voor anonieme gebruikersrapporten is gewijzigd. Wil je naar het nieuwe formaat overschakelen?",
|
||||
@@ -52,6 +53,7 @@
|
||||
"Body:": "Inhoud:",
|
||||
"Bugs": "Bugs",
|
||||
"Cancel": "Annuleren",
|
||||
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Kan niet aangezet worden als het map-type \"{{foldertype}}\" is.",
|
||||
"Changelog": "Wijzigingenlogboek",
|
||||
"Clean out after": "Opruimen na",
|
||||
"Cleaning Versions": "Versies opruimen",
|
||||
@@ -225,8 +227,9 @@
|
||||
"Learn more": "Lees meer",
|
||||
"Learn more at {%url%}": "Meer informatie op {{url}}",
|
||||
"Limit": "Begrenzing",
|
||||
"Listener Failures": "Luisteraarfouten",
|
||||
"Listener Status": "Luisteraarstatus",
|
||||
"Limit Bandwidth in LAN": "Beperk de bandbreedte op het lokale netwerk",
|
||||
"Listener Failures": "Luisteraarsfouten",
|
||||
"Listener Status": "Luisteraarsstatus",
|
||||
"Listeners": "Luisteraars",
|
||||
"Loading data...": "Gegevens laden...",
|
||||
"Loading...": "Laden...",
|
||||
@@ -386,6 +389,7 @@
|
||||
"Staggered File Versioning": "Gespreid versiebeheer",
|
||||
"Start Browser": "Browser starten",
|
||||
"Statistics": "Statistieken",
|
||||
"Stay logged in": "Blijf aangemeld",
|
||||
"Stopped": "Gestopt",
|
||||
"Stores and syncs only encrypted data. Folders on all connected devices need to be set up with the same password or be of type \"{%receiveEncrypted%}\" too.": "Bewaart en synchroniseert alleen versleutelde gegevens. Mappen op alle verbonden apparaten moeten met hetzelfde wachtwoord ingesteld worden of ook van het type \"{{receiveEncrypted}}\" zijn.",
|
||||
"Subject:": "Onderwerp:",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Dowiedz się więcej",
|
||||
"Learn more at {%url%}": "Dowiedz się więcej na {{url}}",
|
||||
"Limit": "Ograniczenie",
|
||||
"Limit Bandwidth in LAN": "Ogranicz przepustowość w sieci lokalnej LAN",
|
||||
"Listener Failures": "Błędy nasłuchujących",
|
||||
"Listener Status": "Stan nasłuchujących",
|
||||
"Listeners": "Nasłuchujący",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Узнать больше",
|
||||
"Learn more at {%url%}": "Узнать больше на сайте {{url}}",
|
||||
"Limit": "Ограничение",
|
||||
"Limit Bandwidth in LAN": "Ограничить пропускную способность в локальной сети",
|
||||
"Listener Failures": "Ошибки прослушивателя",
|
||||
"Listener Status": "Статус прослушивателя",
|
||||
"Listeners": "Прослушиватель",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Läs mer",
|
||||
"Learn more at {%url%}": "Läs mer på {{url}}",
|
||||
"Limit": "Gräns",
|
||||
"Limit Bandwidth in LAN": "Begränsa bandbredd i LAN",
|
||||
"Listener Failures": "Lyssnarfel",
|
||||
"Listener Status": "Lyssnarstatus",
|
||||
"Listeners": "Lyssnare",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Daha fazla bilgi edinin",
|
||||
"Learn more at {%url%}": "{{url}} adresinde daha fazla bilgi edinin",
|
||||
"Limit": "Sınır",
|
||||
"Limit Bandwidth in LAN": "LAN'da Bant Genişliğini Sınırla",
|
||||
"Listener Failures": "Dinleyici Hataları",
|
||||
"Listener Status": "Dinleyici Durumu",
|
||||
"Listeners": "Dinleyiciler",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "了解更多",
|
||||
"Learn more at {%url%}": "了解更多请访问 {{url}}",
|
||||
"Limit": "限制",
|
||||
"Limit Bandwidth in LAN": "在局域网内限制带宽",
|
||||
"Listener Failures": "监听程序失败",
|
||||
"Listener Status": "监听程序状态",
|
||||
"Listeners": "监听程序",
|
||||
|
||||
@@ -333,7 +333,7 @@
|
||||
</p>
|
||||
<table>
|
||||
<tr ng-repeat="(id, err) in fsWatcherErrorMap()">
|
||||
<td>{{folderLabel(id)}}</td><td>{{err}}</td>
|
||||
<td>{{folderLabel(id)}}: </td><td>{{err}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -874,11 +874,11 @@
|
||||
<td ng-if="!connections[deviceCfg.deviceID].connected" class="text-right">
|
||||
<span ng-repeat="addr in deviceCfg.addresses">
|
||||
<span tooltip data-original-title="{{'Configured' | translate}}">{{addr}}</span><br>
|
||||
<small ng-if="system.lastDialStatus[addr].error" tooltip data-original-title="{{system.lastDialStatus[addr].error}}" class="text-danger">{{abbreviatedError(addr)}}<br></small>
|
||||
<small ng-if="system.lastDialStatus[addr].error && !deviceCfg.paused" tooltip data-original-title="{{system.lastDialStatus[addr].error}}" class="text-danger">{{abbreviatedError(addr)}}<br></small>
|
||||
</span>
|
||||
<span ng-repeat="addr in discoveryCache[deviceCfg.deviceID].addresses">
|
||||
<span tooltip data-original-title="{{'Discovered' | translate}}">{{addr}}</span><br>
|
||||
<small ng-if="system.lastDialStatus[addr].error" tooltip data-original-title="{{system.lastDialStatus[addr].error}}" class="text-danger">{{abbreviatedError(addr)}}<br></small>
|
||||
<small ng-if="system.lastDialStatus[addr].error && !deviceCfg.paused" tooltip data-original-title="{{system.lastDialStatus[addr].error}}" class="text-danger">{{abbreviatedError(addr)}}<br></small>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<h4 class="text-center" translate>The Syncthing Authors</h4>
|
||||
<div class="row">
|
||||
<div class="col-md-12" id="contributor-list">
|
||||
Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, bt90, Caleb Callaway, Daniel Harte, Emil Lundberg, Eric P, Evgeny Kuznetsov, greatroar, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Ross Smith II, Stefan Tatschner, Wulf Weich, Adam Piggott, Adel Qalieh, Aleksey Vasenev, Alessandro G., Alex Ionescu, Alex Lindeman, Alex Xu, Alexander Seiler, Alexandre Alves, Aman Gupta, Andreas Sommer, andresvia, Andrew Rabert, Andrey D, andyleap, Anjan Momi, Anthony Goeckner, Antoine Lamielle, Anur, Aranjedeath, Arkadiusz Tymiński, Aroun, Arthur Axel fREW Schmidt, Artur Zubilewicz, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Beat Reichenbach, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benno Fünfstück, Benny Ng, boomsquared, Boqin Qin, Boris Rybalkin, Brendan Long, Catfriend1, Cathryne Linenweaver, Cedric Staniewski, Chih-Hsuan Yen, Choongkyu, Chris Howie, Chris Joel, Christian Kujau, Christian Prescott, chucic, cjc7373, Colin Kennedy, Cromefire_, Cyprien Devillez, d-volution, Dan, Daniel Barczyk, Daniel Bergmann, Daniel Martí, Daniel Padrta, Darshil Chanpura, dashangcun, David Rimmer, DeflateAwning, Denis A., Dennis Wilson, derekriemer, DerRockWolf, desbma, Devon G. Redekopp, digital, Dimitri Papadopoulos Orfanos, Dmitry Saveliev, domain, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eng Zer Jun, entity0xfe, Eric Lesiuta, Erik Meitner, Evan Spensley, Federico Castagnini, Felix, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, georgespatton, ghjklw, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Greg, guangwu, gudvinr, Gusted, Han Boetes, HansK-p, Harrison Jones, Hazem Krimi, Heiko Zuerker, Hireworks, Hugo Locurcio, Iain Barnett, Ian Johnson, ignacy123, Iskander Sharipov, Jaakko Hannikainen, Jack Croft, Jacob, Jake Peterson, James O'Beirne, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaspitta, Jaya Chithra, Jaya Kumar, Jeffery To, jelle van der Waa, Jens Diemer, Jochen Voss, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jose Manuel Delicado, jtagcat, Julian Lehrhuber, Jörg Thalheim, Jędrzej Kula, Kapil Sareen, Karol Różycki, Kebin Liu, Keith Harrison, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., klemens, Kurt Fitzner, kylosus, Lars Lehtonen, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, LSmithx2, Lukas Lihotzki, Luke Hamburg, luzpaz, Majed Abdulaziz, Marc Laporte, Marcin Dziadus, Marcus B Spencer, Marcus Legendre, Mario Majila, Mark Pulford, Martchus, Mateusz Naściszewski, Mateusz Ż, mathias4833, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max, Max Schulze, MaximAL, Maximilian, Michael Jephcote, Michael Rienstra, MichaIng, Migelo, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, mv1005, Nate Morrison, nf, Nicholas Rishel, Nick Busey, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, orangekame3, otbutz, overkill, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Paul Donald, Pawel Palenica, perewa, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Philippe Schommers, Phill Luby, Piotr Bejda, polyfloyd, Quentin Hibon, Rahmi Pruitt, red_led, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, rubenbe, Ruslan Yevdokymov, Ryan Qian, Ryan Sullivan, Sacheendra Talluri, Scott Klupfel, sec65, Sergey Mishin, Sertonix, Severin von Wnuck-Lipinski, Shaarad Dalvi, Simon Mwepu, Simon Pickup, Sly_tom_cat, Sonu Kumar Saw, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Sven Bachmann, Sébastien WENSKE, Taylor Khan, Terrance, TheCreeper, Thomas, Thomas Hipp, Tim Abell, Tim Howes, Tobias Frölich, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tommy van der Vorst, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, vapatel2, Veeti Paananen, Victor Buinsky, Vik, Vil Brekin, villekalliomaki, Vladimir Rusinov, wangguoliang, WangXi, Will Rouesnel, William A. Kennington III, wouter bolsterlee, xarx00, Xavier O., xjtdy888, Yannic A., 佛跳墙, 落心
|
||||
Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, bt90, Caleb Callaway, Daniel Harte, Emil Lundberg, Eric P, Evgeny Kuznetsov, greatroar, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Ross Smith II, Stefan Tatschner, Wulf Weich, Adam Piggott, Adel Qalieh, Aleksey Vasenev, Alessandro G., Alex Ionescu, Alex Lindeman, Alex Xu, Alexander Seiler, Alexandre Alves, Aman Gupta, Andreas Sommer, andresvia, Andrew Rabert, Andrey D, andyleap, Anjan Momi, Anthony Goeckner, Antoine Lamielle, Anur, Aranjedeath, ardevd, Arkadiusz Tymiński, Aroun, Arthur Axel fREW Schmidt, Artur Zubilewicz, Ashish Bhate, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Beat Reichenbach, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benno Fünfstück, Benny Ng, boomsquared, Boqin Qin, Boris Rybalkin, Brendan Long, Catfriend1, Cathryne Linenweaver, Cedric Staniewski, Chih-Hsuan Yen, Choongkyu, Chris Howie, Chris Joel, Christian Kujau, Christian Prescott, chucic, cjc7373, Colin Kennedy, Cromefire_, Cyprien Devillez, d-volution, Dan, Daniel Barczyk, Daniel Bergmann, Daniel Martí, Daniel Padrta, Darshil Chanpura, dashangcun, David Rimmer, DeflateAwning, Denis A., Dennis Wilson, derekriemer, DerRockWolf, desbma, Devon G. Redekopp, digital, Dimitri Papadopoulos Orfanos, Dmitry Saveliev, domain, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eng Zer Jun, entity0xfe, Eric Lesiuta, Erik Meitner, Evan Spensley, Federico Castagnini, Felix, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, georgespatton, ghjklw, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Greg, guangwu, gudvinr, Gusted, Han Boetes, HansK-p, Harrison Jones, Hazem Krimi, Heiko Zuerker, Hireworks, Hugo Locurcio, Iain Barnett, Ian Johnson, ignacy123, Iskander Sharipov, Jaakko Hannikainen, Jack Croft, Jacob, Jake Peterson, James O'Beirne, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaspitta, Jaya Chithra, Jaya Kumar, Jeffery To, jelle van der Waa, Jens Diemer, Jochen Voss, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jose Manuel Delicado, jtagcat, Julian Lehrhuber, Jörg Thalheim, Jędrzej Kula, Kapil Sareen, Karol Różycki, Kebin Liu, Keith Harrison, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., klemens, Kurt Fitzner, kylosus, Lars Lehtonen, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, LSmithx2, Lukas Lihotzki, Luke Hamburg, luzpaz, Majed Abdulaziz, Marc Laporte, Marcel Meyer, Marcin Dziadus, Marcus B Spencer, Marcus Legendre, Mario Majila, Mark Pulford, Martchus, Mateusz Naściszewski, Mateusz Ż, mathias4833, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max, Max Schulze, MaximAL, Maximilian, Michael Jephcote, Michael Rienstra, MichaIng, Migelo, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, mv1005, Nate Morrison, nf, Nicholas Rishel, Nick Busey, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, orangekame3, otbutz, overkill, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Paul Donald, Pawel Palenica, perewa, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Philippe Schommers, Phill Luby, Piotr Bejda, polyfloyd, pullmerge, Quentin Hibon, Rahmi Pruitt, red_led, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, rubenbe, Ruslan Yevdokymov, Ryan Qian, Ryan Sullivan, Sacheendra Talluri, Scott Klupfel, sec65, Sergey Mishin, Sertonix, Severin von Wnuck-Lipinski, Shaarad Dalvi, Simon Mwepu, Simon Pickup, Sly_tom_cat, Sonu Kumar Saw, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Sven Bachmann, Sébastien WENSKE, Taylor Khan, Terrance, TheCreeper, Thomas, Thomas Hipp, Tim Abell, Tim Howes, Tobias Frölich, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tommy van der Vorst, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, vapatel2, Veeti Paananen, Victor Buinsky, Vik, Vil Brekin, villekalliomaki, Vladimir Rusinov, wangguoliang, WangXi, Will Rouesnel, William A. Kennington III, wouter bolsterlee, xarx00, Xavier O., xjtdy888, Yannic A., yparitcher, 佛跳墙, 落心
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -58,7 +58,6 @@ Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf,
|
||||
<li><a href="https://github.com/calmh/xdr">calmh/xdr</a>, Copyright © 2014 Jakob Borg.</li>
|
||||
<li><a href="https://github.com/ccding/go-stun">ccding/go-stun</a>, Copyright © 2016 Cong Ding.</li>
|
||||
<li><a href="https://github.com/cespare/xxhash/v2">cespare/xxhash/v2</a>, Copyright © 2016 Caleb Spare.</li>
|
||||
<li><a href="https://github.com/chmduquesne/rollinghash">chmduquesne/rollinghash</a>, Copyright © 2015 Christophe-Marie Duquesne.</li>
|
||||
<li><a href="https://github.com/cpuguy83/go-md2man/v2">cpuguy83/go-md2man/v2</a>, Copyright © 2014 Brian Goff.</li>
|
||||
<li><a href="https://github.com/davecgh/go-spew">davecgh/go-spew</a>, Copyright © 2012-2016 Dave Collins.</li>
|
||||
<li><a href="https://github.com/go-asn1-ber/asn1-ber">go-asn1-ber/asn1-ber</a>, Copyright © 2011-2015 Michael Mitton (mmitton@gmail.com).</li>
|
||||
@@ -70,14 +69,15 @@ Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf,
|
||||
<li><a href="https://github.com/protocolbuffers/protobuf-go">google.golang.org/protobuf</a>, Copyright © 2018 The Go Authors.</li>
|
||||
<li><a href="https://github.com/google/uuid">google/uuid</a>, Copyright © 2009,2014 Google Inc.</li>
|
||||
<li><a href="https://gopkg.in/yaml.v3">gopkg.in/yaml.v3</a>, Copyright © 2025, the gopkg.in/yaml.v3 authors.</li>
|
||||
<li><a href="https://github.com/greatroar/blobloom">greatroar/blobloom</a>, Copyright © 2020-2024 the Blobloom authors.</li>
|
||||
<li><a href="https://github.com/hashicorp/errwrap">hashicorp/errwrap</a>, Copyright © 2014 HashiCorp, Inc.</li>
|
||||
<li><a href="https://github.com/hashicorp/go-multierror">hashicorp/go-multierror</a>, Copyright © 2014 HashiCorp, Inc.</li>
|
||||
<li><a href="https://github.com/hashicorp/golang-lru">hashicorp/golang-lru</a>, Copyright © 2014 HashiCorp, Inc.</li>
|
||||
<li><a href="https://github.com/jackpal/gateway">jackpal/gateway</a>, Copyright © 2010 Jack Palevich.</li>
|
||||
<li><a href="https://github.com/jackpal/go-nat-pmp">jackpal/go-nat-pmp</a>, Copyright 2013 John Howard Palevich.</li>
|
||||
<li><a href="https://github.com/jmoiron/sqlx">jmoiron/sqlx</a>, Copyright © 2013, Jason Moiron.</li>
|
||||
<li><a href="https://github.com/julienschmidt/httprouter">julienschmidt/httprouter</a>, Copyright © 2013, Julien Schmidt.</li>
|
||||
<li><a href="https://github.com/kballard/go-shellquote">kballard/go-shellquote</a>, Copyright © 2014 Kevin Ballard.</li>
|
||||
<li><a href="https://github.com/mattn/go-sqlite3">mattn/go-sqlite3</a>, Copyright © 2014 Yasuhiro Matsumoto.</li>
|
||||
<li><a href="https://github.com/miscreant/miscreant.go">miscreant/miscreant.go</a>, Copyright © 2017-2019 The Miscreant Developers.</li>
|
||||
<li><a href="https://github.com/munnerz/goautoneg">munnerz/goautoneg</a>, Copyright © 2011, Open Knowledge Foundation Ltd.</li>
|
||||
<li><a href="https://github.com/pierrec/lz4">pierrec/lz4</a>, Copyright © 2015 Pierre Curto.</li>
|
||||
@@ -102,6 +102,7 @@ Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf,
|
||||
<li><a href="https://github.com/urfave/cli">urfave/cli</a>, Copyright © 2016 Jeremy Saenz & Contributors.</li>
|
||||
<li><a href="https://github.com/vitrun/qart">vitrun/qart</a>, Copyright © 2010-2011 The Go Authors.</li>
|
||||
<li><a href="https://github.com/willabides/kongplete">willabides/kongplete</a>, Copyright © 2020 WillAbides.</li>
|
||||
<li><a href="https://github.com/wlynxg/anet">wlynxg/anet</a>, Copyright © 2023, wlynxg.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -210,6 +210,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input id="LimitBandwidthInLan" type="checkbox" ng-model="tmpOptions.limitBandwidthInLan" /> <span translate>Limit Bandwidth in LAN</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
|
||||
@@ -19,9 +19,9 @@ type Counts struct {
|
||||
Symlinks int
|
||||
Deleted int
|
||||
Bytes int64
|
||||
Sequence int64 // zero for the global state
|
||||
DeviceID protocol.DeviceID // device ID for remote devices, or special values for local/global
|
||||
LocalFlags uint32 // the local flag for this count bucket
|
||||
Sequence int64 // zero for the global state
|
||||
DeviceID protocol.DeviceID // device ID for remote devices, or special values for local/global
|
||||
LocalFlags protocol.FlagLocal // the local flag for this count bucket
|
||||
}
|
||||
|
||||
func (c Counts) Add(other Counts) Counts {
|
||||
|
||||
@@ -100,10 +100,9 @@ type FileMetadata struct {
|
||||
Sequence int64
|
||||
ModNanos int64
|
||||
Size int64
|
||||
LocalFlags int64
|
||||
LocalFlags protocol.FlagLocal
|
||||
Type protocol.FileInfoType
|
||||
Deleted bool
|
||||
Invalid bool
|
||||
}
|
||||
|
||||
func (f *FileMetadata) ModTime() time.Time {
|
||||
@@ -121,3 +120,7 @@ func (f *FileMetadata) IsDirectory() bool {
|
||||
func (f *FileMetadata) ShouldConflict() bool {
|
||||
return f.LocalFlags&protocol.LocalConflictFlags != 0
|
||||
}
|
||||
|
||||
func (f *FileMetadata) IsInvalid() bool {
|
||||
return f.LocalFlags.IsInvalid()
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ var (
|
||||
Namespace: "syncthing",
|
||||
Subsystem: "db",
|
||||
Name: "operations_current",
|
||||
Help: "Number of database operations currently ongoing, per folder and operation",
|
||||
}, []string{"folder", "operation"})
|
||||
metricTotalOperationSeconds = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: "syncthing",
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
|
||||
const currentSchemaVersion = 1
|
||||
const currentSchemaVersion = 3
|
||||
|
||||
//go:embed sql/**
|
||||
var embedded embed.FS
|
||||
@@ -62,6 +62,17 @@ func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScript
|
||||
baseName: filepath.Base(path),
|
||||
sql: sqlDB,
|
||||
statements: make(map[string]*sqlx.Stmt),
|
||||
tplInput: map[string]any{
|
||||
"FlagLocalUnsupported": protocol.FlagLocalUnsupported,
|
||||
"FlagLocalIgnored": protocol.FlagLocalIgnored,
|
||||
"FlagLocalMustRescan": protocol.FlagLocalMustRescan,
|
||||
"FlagLocalReceiveOnly": protocol.FlagLocalReceiveOnly,
|
||||
"FlagLocalGlobal": protocol.FlagLocalGlobal,
|
||||
"FlagLocalNeeded": protocol.FlagLocalNeeded,
|
||||
"FlagLocalRemoteInvalid": protocol.FlagLocalRemoteInvalid,
|
||||
"LocalInvalidFlags": protocol.LocalInvalidFlags,
|
||||
"SyncthingVersion": build.LongVersion,
|
||||
},
|
||||
}
|
||||
|
||||
for _, script := range schemaScripts {
|
||||
@@ -96,16 +107,6 @@ func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScript
|
||||
return nil, wrap(err)
|
||||
}
|
||||
|
||||
db.tplInput = map[string]any{
|
||||
"FlagLocalUnsupported": protocol.FlagLocalUnsupported,
|
||||
"FlagLocalIgnored": protocol.FlagLocalIgnored,
|
||||
"FlagLocalMustRescan": protocol.FlagLocalMustRescan,
|
||||
"FlagLocalReceiveOnly": protocol.FlagLocalReceiveOnly,
|
||||
"FlagLocalGlobal": protocol.FlagLocalGlobal,
|
||||
"FlagLocalNeeded": protocol.FlagLocalNeeded,
|
||||
"SyncthingVersion": build.LongVersion,
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
@@ -151,15 +152,8 @@ func (s *baseDB) stmt(tpl string) stmt {
|
||||
return stmt
|
||||
}
|
||||
|
||||
// Apply template expansions
|
||||
var sb strings.Builder
|
||||
compTpl := template.Must(template.New("tpl").Funcs(tplFuncs).Parse(tpl))
|
||||
if err := compTpl.Execute(&sb, s.tplInput); err != nil {
|
||||
panic("bug: bad template: " + err.Error())
|
||||
}
|
||||
|
||||
// Prepare and cache
|
||||
stmt, err := s.sql.Preparex(sb.String())
|
||||
stmt, err := s.sql.Preparex(s.expandTemplateVars(tpl))
|
||||
if err != nil {
|
||||
return failedStmt{err}
|
||||
}
|
||||
@@ -167,6 +161,17 @@ func (s *baseDB) stmt(tpl string) stmt {
|
||||
return stmt
|
||||
}
|
||||
|
||||
// expandTemplateVars just applies template expansions to the template
|
||||
// string, or dies trying
|
||||
func (s *baseDB) expandTemplateVars(tpl string) string {
|
||||
var sb strings.Builder
|
||||
compTpl := template.Must(template.New("tpl").Funcs(tplFuncs).Parse(tpl))
|
||||
if err := compTpl.Execute(&sb, s.tplInput); err != nil {
|
||||
panic("bug: bad template: " + err.Error())
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
type stmt interface {
|
||||
Exec(args ...any) (sql.Result, error)
|
||||
Get(dest any, args ...any) error
|
||||
@@ -211,7 +216,7 @@ nextScript:
|
||||
// separately. We require it on a separate line because there are
|
||||
// also statement-internal semicolons in the triggers.
|
||||
for _, stmt := range strings.Split(string(bs), "\n;") {
|
||||
if _, err := tx.Exec(stmt); err != nil {
|
||||
if _, err := tx.Exec(s.expandTemplateVars(stmt)); err != nil {
|
||||
return wrap(err, stmt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"iter"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -255,7 +256,7 @@ func (s *DB) ListDevicesForFolder(folder string) ([]protocol.DeviceID, error) {
|
||||
func (s *DB) RemoteSequences(folder string) (map[protocol.DeviceID]int64, error) {
|
||||
fdb, err := s.getFolderDB(folder, false)
|
||||
if errors.Is(err, errNoSuchFolder) {
|
||||
return nil, nil
|
||||
return nil, nil //nolint:nilnil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -376,6 +377,22 @@ func (s *DB) DropDevice(device protocol.DeviceID) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DB) DebugCounts(out io.Writer, folder string) error {
|
||||
fdb, err := s.getFolderDB(folder, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fdb.DebugCounts(out)
|
||||
}
|
||||
|
||||
func (s *DB) DebugFilePattern(out io.Writer, folder, name string) error {
|
||||
fdb, err := s.getFolderDB(folder, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fdb.DebugFilePattern(out, name)
|
||||
}
|
||||
|
||||
// forEachFolder runs the function for each currently open folderDB,
|
||||
// returning the first error that was encountered.
|
||||
func (s *DB) forEachFolder(fn func(fdb *folderDB) error) error {
|
||||
|
||||
@@ -268,6 +268,57 @@ func TestDontNeedIgnored(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDontNeedRemoteInvalid(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, err := OpenTemp()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
if err := db.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
// A remote file with the invalid bit set
|
||||
files := []protocol.FileInfo{
|
||||
genFile("test1", 1, 103),
|
||||
}
|
||||
files[0].LocalFlags = protocol.FlagLocalRemoteInvalid
|
||||
err = db.Update(folderID, protocol.DeviceID{42}, files)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// It's not part of the global size
|
||||
s, err := db.CountGlobal(folderID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if s.Bytes != 0 || s.Files != 0 {
|
||||
t.Log(s)
|
||||
t.Error("bad global")
|
||||
}
|
||||
|
||||
// We don't need it
|
||||
s, err = db.CountNeed(folderID, protocol.LocalDeviceID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if s.Bytes != 0 || s.Files != 0 {
|
||||
t.Log(s)
|
||||
t.Error("bad need")
|
||||
}
|
||||
|
||||
// It shouldn't show up in the need list
|
||||
names := mustCollect[protocol.FileInfo](t)(db.AllNeededGlobalFiles(folderID, protocol.LocalDeviceID, config.PullOrderAlphabetic, 0, 0))
|
||||
if len(names) != 0 {
|
||||
t.Log(names)
|
||||
t.Error("need no files")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteDontNeedLocalIgnored(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -517,3 +568,59 @@ func TestNeedPagination(t *testing.T) {
|
||||
t.Error("bad need")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeletedAfterConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// A delete that comes after a conflict should be applied, not lose the
|
||||
// conflict and suddenly cause an old conflict version to become
|
||||
// promoted.
|
||||
|
||||
// D:\syncthing-windows-amd64-v2.0.0-rc.22.dev.11.gff88430e>syncthing --home=c:\PortableApp\SyncTrayzorPortable-x64\data\syncthing debug database-file tnhbr-gxtuf TreeSizeFreeSetup.exe
|
||||
// DEVICE TYPE NAME SEQUENCE DELETED MODIFIED SIZE FLAGS VERSION BLOCKLIST
|
||||
// -local- FILE TreeSizeFreeSetup.exe 499 del 2025-07-04T11:52:36.2804841Z 0 ------- HZJYWFM:1751507473,OMKHRPB:1751629956 -nil-
|
||||
// J5WNYJ6 FILE TreeSizeFreeSetup.exe 500 del 2025-07-04T11:52:36.2804841Z 0 ------- HZJYWFM:1751507473,OMKHRPB:1751629956 -nil-
|
||||
// 23NHXGS FILE TreeSizeFreeSetup.exe 445 --- 2025-06-23T03:16:10.2804841Z 13832808 -nG---- HZJYWFM:1751507473 7B4kLitF
|
||||
// JKX6ZDN FILE TreeSizeFreeSetup.exe 320 --- 2025-06-23T03:16:10.2804841Z 13832808 ------- JKX6ZDN:1750992570 7B4kLitF
|
||||
|
||||
db, err := OpenTemp()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
if err := db.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
// A file, updated by some remote device. This file is an old, conflicted copy.
|
||||
file := genFile("test1", 1, 101)
|
||||
file.ModifiedS = 1750992570
|
||||
file.Version = protocol.Vector{Counters: []protocol.Counter{{ID: 5 << 60, Value: 1750992570}}}
|
||||
if err := db.Update(folderID, protocol.DeviceID{5}, []protocol.FileInfo{file}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The file, updated by a newer remote device. This file is the newer, conflict-winning copy.
|
||||
file.ModifiedS = 1751507473
|
||||
file.Version = protocol.Vector{Counters: []protocol.Counter{{ID: 2 << 60, Value: 1751507473}}}
|
||||
if err := db.Update(folderID, protocol.DeviceID{2}, []protocol.FileInfo{file}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The file, deleted locally after syncing the file from the remote above..
|
||||
file.SetDeleted(4)
|
||||
if err := db.Update(folderID, protocol.LocalDeviceID, []protocol.FileInfo{file}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The delete should be the global version
|
||||
f, _, err := db.GetGlobalFile(folderID, "test1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !f.IsDeleted() {
|
||||
t.Log(f)
|
||||
t.Error("should be deleted")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,10 +50,14 @@ func Open(path string, opts ...Option) (*DB, error) {
|
||||
"sql/schema/common/*",
|
||||
"sql/schema/main/*",
|
||||
}
|
||||
migrations := []string{
|
||||
"sql/migrations/common/*",
|
||||
"sql/migrations/main/*",
|
||||
}
|
||||
|
||||
os.MkdirAll(path, 0o700)
|
||||
_ = os.MkdirAll(path, 0o700)
|
||||
mainPath := filepath.Join(path, "main.db")
|
||||
mainBase, err := openBase(mainPath, maxDBConns, pragmas, schemas, nil)
|
||||
mainBase, err := openBase(mainPath, maxDBConns, pragmas, schemas, migrations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -88,10 +92,14 @@ func OpenForMigration(path string) (*DB, error) {
|
||||
"sql/schema/common/*",
|
||||
"sql/schema/main/*",
|
||||
}
|
||||
migrations := []string{
|
||||
"sql/migrations/common/*",
|
||||
"sql/migrations/main/*",
|
||||
}
|
||||
|
||||
os.MkdirAll(path, 0o700)
|
||||
_ = os.MkdirAll(path, 0o700)
|
||||
mainPath := filepath.Join(path, "main.db")
|
||||
mainBase, err := openBase(mainPath, 1, pragmas, schemas, nil)
|
||||
mainBase, err := openBase(mainPath, 1, pragmas, schemas, migrations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -84,8 +84,11 @@ func (s *Service) periodic(ctx context.Context) error {
|
||||
defer func() { l.Debugln("Periodic done in", time.Since(t1), "+", t1.Sub(t0)) }()
|
||||
|
||||
s.sdb.updateLock.Lock()
|
||||
tidy(ctx, s.sdb.sql)
|
||||
err := tidy(ctx, s.sdb.sql)
|
||||
s.sdb.updateLock.Unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return wrap(s.sdb.forEachFolder(func(fdb *folderDB) error {
|
||||
fdb.updateLock.Lock()
|
||||
@@ -97,8 +100,7 @@ func (s *Service) periodic(ctx context.Context) error {
|
||||
if err := garbageCollectBlocklistsAndBlocksLocked(ctx, fdb); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
tidy(ctx, fdb.sql)
|
||||
return nil
|
||||
return tidy(ctx, fdb.sql)
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ type countsRow struct {
|
||||
Count int
|
||||
Size int64
|
||||
Deleted bool
|
||||
LocalFlags int64 `db:"local_flags"`
|
||||
LocalFlags protocol.FlagLocal `db:"local_flags"`
|
||||
}
|
||||
|
||||
func (s *folderDB) CountLocal(device protocol.DeviceID) (db.Counts, error) {
|
||||
@@ -39,13 +39,10 @@ func (s *folderDB) CountNeed(device protocol.DeviceID) (db.Counts, error) {
|
||||
}
|
||||
|
||||
func (s *folderDB) CountGlobal() (db.Counts, error) {
|
||||
// Exclude ignored and receive-only changed files from the global count
|
||||
// (legacy expectation? it's a bit weird since those files can in fact
|
||||
// be global and you can get them with GetGlobal etc.)
|
||||
var res []countsRow
|
||||
err := s.stmt(`
|
||||
SELECT s.type, s.count, s.size, s.local_flags, s.deleted FROM counts s
|
||||
WHERE s.local_flags & {{.FlagLocalGlobal}} != 0 AND s.local_flags & {{or .FlagLocalReceiveOnly .FlagLocalIgnored}} = 0
|
||||
WHERE s.local_flags & {{.FlagLocalGlobal}} != 0 AND s.local_flags & {{.LocalInvalidFlags}} = 0
|
||||
`).Select(&res)
|
||||
if err != nil {
|
||||
return db.Counts{}, wrap(err)
|
||||
@@ -84,7 +81,7 @@ func (s *folderDB) needSizeRemote(device protocol.DeviceID) (db.Counts, error) {
|
||||
// See neededGlobalFilesRemote for commentary as that is the same query without summing
|
||||
if err := s.stmt(`
|
||||
SELECT g.type, count(*) as count, sum(g.size) as size, g.local_flags, g.deleted FROM files g
|
||||
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND NOT g.deleted AND NOT g.invalid AND NOT EXISTS (
|
||||
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND NOT g.deleted AND g.local_flags & {{.LocalInvalidFlags}} = 0 AND NOT EXISTS (
|
||||
SELECT 1 FROM FILES f
|
||||
INNER JOIN devices d ON d.idx = f.device_idx
|
||||
WHERE f.name = g.name AND f.version = g.version AND d.device_id = ?
|
||||
@@ -94,10 +91,10 @@ func (s *folderDB) needSizeRemote(device protocol.DeviceID) (db.Counts, error) {
|
||||
UNION ALL
|
||||
|
||||
SELECT g.type, count(*) as count, sum(g.size) as size, g.local_flags, g.deleted FROM files g
|
||||
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND g.deleted AND NOT g.invalid AND EXISTS (
|
||||
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND g.deleted AND g.local_flags & {{.LocalInvalidFlags}} = 0 AND EXISTS (
|
||||
SELECT 1 FROM FILES f
|
||||
INNER JOIN devices d ON d.idx = f.device_idx
|
||||
WHERE f.name = g.name AND d.device_id = ? AND NOT f.deleted AND NOT f.invalid
|
||||
WHERE f.name = g.name AND d.device_id = ? AND NOT f.deleted AND f.local_flags & {{.LocalInvalidFlags}} = 0
|
||||
)
|
||||
GROUP BY g.type, g.local_flags, g.deleted
|
||||
`).Select(&res, device.String(),
|
||||
|
||||
@@ -74,7 +74,7 @@ func (s *folderDB) GetGlobalAvailability(file string) ([]protocol.DeviceID, erro
|
||||
|
||||
func (s *folderDB) AllGlobalFiles() (iter.Seq[db.FileMetadata], func() error) {
|
||||
it, errFn := iterStructs[db.FileMetadata](s.stmt(`
|
||||
SELECT f.sequence, f.name, f.type, f.modified as modnanos, f.size, f.deleted, f.invalid, f.local_flags as localflags FROM files f
|
||||
SELECT f.sequence, f.name, f.type, f.modified as modnanos, f.size, f.deleted, f.local_flags as localflags FROM files f
|
||||
WHERE f.local_flags & {{.FlagLocalGlobal}} != 0
|
||||
ORDER BY f.name
|
||||
`).Queryx())
|
||||
@@ -93,7 +93,7 @@ func (s *folderDB) AllGlobalFilesPrefix(prefix string) (iter.Seq[db.FileMetadata
|
||||
end := prefixEnd(prefix)
|
||||
|
||||
it, errFn := iterStructs[db.FileMetadata](s.stmt(`
|
||||
SELECT f.sequence, f.name, f.type, f.modified as modnanos, f.size, f.deleted, f.invalid, f.local_flags as localflags FROM files f
|
||||
SELECT f.sequence, f.name, f.type, f.modified as modnanos, f.size, f.deleted, f.local_flags as localflags FROM files f
|
||||
WHERE f.name >= ? AND f.name < ? AND f.local_flags & {{.FlagLocalGlobal}} != 0
|
||||
ORDER BY f.name
|
||||
`).Queryx(prefix, end))
|
||||
@@ -158,7 +158,7 @@ func (s *folderDB) neededGlobalFilesRemote(device protocol.DeviceID, selectOpts
|
||||
SELECT fi.fiprotobuf, bl.blprotobuf, g.name, g.size, g.modified FROM fileinfos fi
|
||||
INNER JOIN files g on fi.sequence = g.sequence
|
||||
LEFT JOIN blocklists bl ON bl.blocklist_hash = g.blocklist_hash
|
||||
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND NOT g.deleted AND NOT g.invalid AND NOT EXISTS (
|
||||
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND NOT g.deleted AND g.local_flags & {{.LocalInvalidFlags}} = 0 AND NOT EXISTS (
|
||||
SELECT 1 FROM FILES f
|
||||
INNER JOIN devices d ON d.idx = f.device_idx
|
||||
WHERE f.name = g.name AND f.version = g.version AND d.device_id = ?
|
||||
@@ -169,10 +169,10 @@ func (s *folderDB) neededGlobalFilesRemote(device protocol.DeviceID, selectOpts
|
||||
SELECT fi.fiprotobuf, bl.blprotobuf, g.name, g.size, g.modified FROM fileinfos fi
|
||||
INNER JOIN files g on fi.sequence = g.sequence
|
||||
LEFT JOIN blocklists bl ON bl.blocklist_hash = g.blocklist_hash
|
||||
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND g.deleted AND NOT g.invalid AND EXISTS (
|
||||
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND g.deleted AND g.local_flags & {{.LocalInvalidFlags}} = 0 AND EXISTS (
|
||||
SELECT 1 FROM FILES f
|
||||
INNER JOIN devices d ON d.idx = f.device_idx
|
||||
WHERE f.name = g.name AND d.device_id = ? AND NOT f.deleted AND NOT f.invalid
|
||||
WHERE f.name = g.name AND d.device_id = ? AND NOT f.deleted AND f.local_flags & {{.LocalInvalidFlags}} = 0
|
||||
)
|
||||
`+selectOpts).Queryx(
|
||||
device.String(),
|
||||
|
||||
@@ -8,9 +8,14 @@ package sqlite
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"iter"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/internal/db"
|
||||
"github.com/syncthing/syncthing/internal/itererr"
|
||||
@@ -89,7 +94,7 @@ func (s *folderDB) AllLocalFilesWithPrefix(device protocol.DeviceID, prefix stri
|
||||
|
||||
func (s *folderDB) AllLocalFilesWithBlocksHash(h []byte) (iter.Seq[db.FileMetadata], func() error) {
|
||||
return iterStructs[db.FileMetadata](s.stmt(`
|
||||
SELECT f.sequence, f.name, f.type, f.modified as modnanos, f.size, f.deleted, f.invalid, f.local_flags as localflags FROM files f
|
||||
SELECT f.sequence, f.name, f.type, f.modified as modnanos, f.size, f.deleted, f.local_flags as localflags FROM files f
|
||||
WHERE f.device_idx = {{.LocalDeviceIdx}} AND f.blocklist_hash = ?
|
||||
`).Queryx(h))
|
||||
}
|
||||
@@ -126,3 +131,82 @@ func (s *folderDB) ListDevicesForFolder() ([]protocol.DeviceID, error) {
|
||||
}
|
||||
return devs, nil
|
||||
}
|
||||
|
||||
func (s *folderDB) DebugCounts(out io.Writer) error {
|
||||
type deviceCountsRow struct {
|
||||
countsRow
|
||||
|
||||
DeviceID string
|
||||
}
|
||||
|
||||
delMap := map[bool]string{
|
||||
true: "del",
|
||||
false: "---",
|
||||
}
|
||||
|
||||
var res []deviceCountsRow
|
||||
if err := s.stmt(`
|
||||
SELECT d.device_id as deviceid, s.type, s.count, s.size, s.local_flags, s.deleted FROM counts s
|
||||
INNER JOIN devices d ON d.idx = s.device_idx
|
||||
`).Select(&res); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
|
||||
tw := tabwriter.NewWriter(out, 2, 2, 2, ' ', 0)
|
||||
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\t%s\n", "DEVICE", "TYPE", "FLAGS", "DELETED", "COUNT", "SIZE")
|
||||
for _, row := range res {
|
||||
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%d\t%d\n", shortDevice(row.DeviceID), shortType(row.Type), row.LocalFlags.HumanString(), delMap[row.Deleted], row.Count, row.Size)
|
||||
}
|
||||
return tw.Flush()
|
||||
}
|
||||
|
||||
func (s *folderDB) DebugFilePattern(out io.Writer, name string) error {
|
||||
type hashFileMetadata struct {
|
||||
db.FileMetadata
|
||||
|
||||
Version dbVector
|
||||
BlocklistHash []byte
|
||||
DeviceID string
|
||||
}
|
||||
name = "%" + name + "%"
|
||||
res := itererr.Zip(iterStructs[hashFileMetadata](s.stmt(`
|
||||
SELECT f.sequence, f.name, f.type, f.modified as modnanos, f.size, f.deleted, f.local_flags as localflags, f.version, f.blocklist_hash as blocklisthash, d.device_id as deviceid FROM files f
|
||||
INNER JOIN devices d ON d.idx = f.device_idx
|
||||
WHERE f.name LIKE ?
|
||||
ORDER BY f.name, f.device_idx
|
||||
`).Queryx(name)))
|
||||
|
||||
delMap := map[bool]string{
|
||||
true: "del",
|
||||
false: "---",
|
||||
}
|
||||
|
||||
tw := tabwriter.NewWriter(out, 2, 2, 2, ' ', 0)
|
||||
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", "DEVICE", "TYPE", "NAME", "SEQUENCE", "DELETED", "MODIFIED", "SIZE", "FLAGS", "VERSION", "BLOCKLIST")
|
||||
for row, err := range res {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(tw, "%s\t%s\t%s\t%d\t%s\t%s\t%d\t%s\t%s\t%s\n", shortDevice(row.DeviceID), shortType(row.Type), row.Name, row.Sequence, delMap[row.Deleted], row.ModTime().UTC().Format(time.RFC3339Nano), row.Size, row.LocalFlags.HumanString(), row.Version.HumanString(), shortHash(row.BlocklistHash))
|
||||
}
|
||||
return tw.Flush()
|
||||
}
|
||||
|
||||
func shortDevice(s string) string {
|
||||
if dev, err := protocol.DeviceIDFromString(s); err == nil && dev == protocol.LocalDeviceID {
|
||||
return "-local-"
|
||||
}
|
||||
short, _, _ := strings.Cut(s, "-")
|
||||
return short
|
||||
}
|
||||
|
||||
func shortType(t protocol.FileInfoType) string {
|
||||
return strings.TrimPrefix(t.String(), "FILE_INFO_TYPE_")
|
||||
}
|
||||
|
||||
func shortHash(bs []byte) string {
|
||||
if len(bs) == 0 {
|
||||
return "-nil-"
|
||||
}
|
||||
return base64.RawStdEncoding.EncodeToString(bs)[:8]
|
||||
}
|
||||
|
||||
@@ -32,8 +32,12 @@ func openFolderDB(folder, path string, deleteRetention time.Duration) (*folderDB
|
||||
"sql/schema/common/*",
|
||||
"sql/schema/folder/*",
|
||||
}
|
||||
migrations := []string{
|
||||
"sql/migrations/common/*",
|
||||
"sql/migrations/folder/*",
|
||||
}
|
||||
|
||||
base, err := openBase(path, maxDBConns, pragmas, schemas, nil)
|
||||
base, err := openBase(path, maxDBConns, pragmas, schemas, migrations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ func (s *folderDB) Update(device protocol.DeviceID, fs []protocol.FileInfo) erro
|
||||
|
||||
//nolint:sqlclosecheck
|
||||
insertFileStmt, err := txp.Preparex(`
|
||||
INSERT OR REPLACE INTO files (device_idx, remote_sequence, name, type, modified, size, version, deleted, invalid, local_flags, blocklist_hash)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
INSERT OR REPLACE INTO files (device_idx, remote_sequence, name, type, modified, size, version, deleted, local_flags, blocklist_hash)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
RETURNING sequence
|
||||
`)
|
||||
if err != nil {
|
||||
@@ -101,7 +101,7 @@ func (s *folderDB) Update(device protocol.DeviceID, fs []protocol.FileInfo) erro
|
||||
remoteSeq = &f.Sequence
|
||||
}
|
||||
var localSeq int64
|
||||
if err := insertFileStmt.Get(&localSeq, deviceIdx, remoteSeq, f.Name, f.Type, f.ModTime().UnixNano(), f.Size, f.Version.String(), f.IsDeleted(), f.IsInvalid(), f.LocalFlags, blockshash); err != nil {
|
||||
if err := insertFileStmt.Get(&localSeq, deviceIdx, remoteSeq, f.Name, f.Type, f.ModTime().UnixNano(), f.Size, f.Version.String(), f.IsDeleted(), f.LocalFlags, blockshash); err != nil {
|
||||
return wrap(err, "insert file")
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ func (s *folderDB) recalcGlobalForFolder(txp *txPreparedStmts) error {
|
||||
func (s *folderDB) recalcGlobalForFile(txp *txPreparedStmts, file string) error {
|
||||
//nolint:sqlclosecheck
|
||||
selStmt, err := txp.Preparex(`
|
||||
SELECT name, device_idx, sequence, modified, version, deleted, invalid, local_flags FROM files
|
||||
SELECT name, device_idx, sequence, modified, version, deleted, local_flags FROM files
|
||||
WHERE name = ?
|
||||
`)
|
||||
if err != nil {
|
||||
@@ -350,7 +350,7 @@ func (s *folderDB) recalcGlobalForFile(txp *txPreparedStmts, file string) error
|
||||
// The global version is the first one in the list that is not invalid,
|
||||
// or just the first one in the list if all are invalid.
|
||||
var global fileRow
|
||||
globIdx := slices.IndexFunc(es, func(e fileRow) bool { return !e.Invalid })
|
||||
globIdx := slices.IndexFunc(es, func(e fileRow) bool { return !e.IsInvalid() })
|
||||
if globIdx < 0 {
|
||||
globIdx = 0
|
||||
}
|
||||
@@ -368,7 +368,7 @@ func (s *folderDB) recalcGlobalForFile(txp *txPreparedStmts, file string) error
|
||||
// Set the global flag on the global entry. Set the need flag if the
|
||||
// local device needs this file, unless it's invalid.
|
||||
global.LocalFlags |= protocol.FlagLocalGlobal
|
||||
if hasLocal || global.Invalid {
|
||||
if hasLocal || global.IsInvalid() {
|
||||
global.LocalFlags &= ^protocol.FlagLocalNeeded
|
||||
} else {
|
||||
global.LocalFlags |= protocol.FlagLocalNeeded
|
||||
@@ -426,18 +426,17 @@ type fileRow struct {
|
||||
Sequence int64
|
||||
Modified int64
|
||||
Size int64
|
||||
LocalFlags int64 `db:"local_flags"`
|
||||
LocalFlags protocol.FlagLocal `db:"local_flags"`
|
||||
Deleted bool
|
||||
Invalid bool
|
||||
}
|
||||
|
||||
func (e fileRow) Compare(other fileRow) int {
|
||||
// From FileInfo.WinsConflict
|
||||
vc := e.Version.Vector.Compare(other.Version.Vector)
|
||||
vc := e.Version.Compare(other.Version.Vector)
|
||||
switch vc {
|
||||
case protocol.Equal:
|
||||
if e.Invalid != other.Invalid {
|
||||
if e.Invalid {
|
||||
if e.IsInvalid() != other.IsInvalid() {
|
||||
if e.IsInvalid() {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
@@ -453,18 +452,12 @@ func (e fileRow) Compare(other fileRow) int {
|
||||
case protocol.Lesser: // we are older
|
||||
return 1
|
||||
case protocol.ConcurrentGreater, protocol.ConcurrentLesser: // there is a conflict
|
||||
if e.Invalid != other.Invalid {
|
||||
if e.Invalid { // we are invalid, we lose
|
||||
if e.IsInvalid() != other.IsInvalid() {
|
||||
if e.IsInvalid() { // we are invalid, we lose
|
||||
return 1
|
||||
}
|
||||
return -1 // they are invalid, we win
|
||||
}
|
||||
if e.Deleted != other.Deleted {
|
||||
if e.Deleted { // we are deleted, we lose
|
||||
return 1
|
||||
}
|
||||
return -1 // they are deleted, we win
|
||||
}
|
||||
if d := cmp.Compare(e.Modified, other.Modified); d != 0 {
|
||||
return -d // positive d means we were newer, so we win (negative return)
|
||||
}
|
||||
@@ -477,6 +470,10 @@ func (e fileRow) Compare(other fileRow) int {
|
||||
}
|
||||
}
|
||||
|
||||
func (e fileRow) IsInvalid() bool {
|
||||
return e.LocalFlags.IsInvalid()
|
||||
}
|
||||
|
||||
func (s *folderDB) periodicCheckpointLocked(fs []protocol.FileInfo) {
|
||||
// Induce periodic checkpoints. We add points for each file and block,
|
||||
// and checkpoint when we've written more than a threshold of points.
|
||||
@@ -519,11 +516,12 @@ func (s *folderDB) periodicCheckpointLocked(fs []protocol.FileInfo) {
|
||||
// failed, we'll keep trying it until we succeed. Increase it faster
|
||||
// when we fail to checkpoint, as it's more likely the WAL is
|
||||
// growing and will need truncation when we get out of this state.
|
||||
if res == 1 {
|
||||
switch {
|
||||
case res == 1:
|
||||
s.checkpointsCount += 10
|
||||
} else if res == 0 && checkpointType == "TRUNCATE" {
|
||||
case res == 0 && checkpointType == "TRUNCATE":
|
||||
s.checkpointsCount = 0
|
||||
} else {
|
||||
default:
|
||||
s.checkpointsCount++
|
||||
}
|
||||
s.updatePoints = 0
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
-- Copyright (C) 2025 The Syncthing Authors.
|
||||
--
|
||||
-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
-- You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
-- The next migration should be number two.
|
||||
@@ -0,0 +1,20 @@
|
||||
-- Copyright (C) 2025 The Syncthing Authors.
|
||||
--
|
||||
-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
-- You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
-- Remote files with the invalid bit instead gain the RemoteInvalid local
|
||||
-- flag.
|
||||
UPDATE files
|
||||
SET local_flags = local_flags | {{.FlagLocalRemoteInvalid}}
|
||||
FROM (
|
||||
SELECT idx FROM devices
|
||||
WHERE device_id = '7777777-777777N-7777777-777777N-7777777-777777N-7777777-77777Q4'
|
||||
) AS local_device
|
||||
WHERE invalid AND device_idx != local_device.idx
|
||||
;
|
||||
|
||||
-- The invalid column goes away.
|
||||
ALTER TABLE files DROP COLUMN invalid
|
||||
;
|
||||
@@ -0,0 +1,17 @@
|
||||
-- Copyright (C) 2025 The Syncthing Authors.
|
||||
--
|
||||
-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
-- You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
-- Remove broken file entries in the database.
|
||||
DELETE FROM files
|
||||
WHERE type == 0 -- files
|
||||
AND NOT deleted -- that are not deleted
|
||||
AND blocklist_hash IS null -- with no blocks
|
||||
AND local_flags & {{.LocalInvalidFlags}} == 0 -- and not invalid
|
||||
;
|
||||
|
||||
-- Force a new index transmission.
|
||||
DELETE FROM indexids
|
||||
;
|
||||
@@ -31,7 +31,6 @@ CREATE TABLE IF NOT EXISTS files (
|
||||
size INTEGER NOT NULL,
|
||||
version TEXT NOT NULL COLLATE BINARY,
|
||||
deleted INTEGER NOT NULL, -- boolean
|
||||
invalid INTEGER NOT NULL, -- boolean
|
||||
local_flags INTEGER NOT NULL,
|
||||
blocklist_hash BLOB, -- null when there are no blocks
|
||||
FOREIGN KEY(device_idx) REFERENCES devices(idx) ON DELETE CASCADE
|
||||
|
||||
@@ -37,7 +37,7 @@ func NewTyped(db KV, prefix string) *Typed {
|
||||
// is overwritten.
|
||||
func (n *Typed) PutInt64(key string, val int64) error {
|
||||
var valBs [8]byte
|
||||
binary.BigEndian.PutUint64(valBs[:], uint64(val))
|
||||
binary.BigEndian.PutUint64(valBs[:], uint64(val)) //nolint:gosec
|
||||
return n.db.PutKV(n.prefixedKey(key), valBs[:])
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ func (n *Typed) Int64(key string) (int64, bool, error) {
|
||||
return 0, false, filterNotFound(err)
|
||||
}
|
||||
val := binary.BigEndian.Uint64(valBs)
|
||||
return int64(val), true, nil
|
||||
return int64(val), true, nil //nolint:gosec
|
||||
}
|
||||
|
||||
// PutTime stores a new time.Time. Any existing value (even if of another
|
||||
|
||||
+432
-346
@@ -179,6 +179,104 @@ func (Compression) EnumDescriptor() ([]byte, []int) {
|
||||
return file_bep_bep_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
type FolderType int32
|
||||
|
||||
const (
|
||||
FolderType_FOLDER_TYPE_SEND_RECEIVE FolderType = 0
|
||||
FolderType_FOLDER_TYPE_SEND_ONLY FolderType = 1
|
||||
FolderType_FOLDER_TYPE_RECEIVE_ONLY FolderType = 2
|
||||
FolderType_FOLDER_TYPE_RECEIVE_ENCRYPTED FolderType = 3
|
||||
)
|
||||
|
||||
// Enum value maps for FolderType.
|
||||
var (
|
||||
FolderType_name = map[int32]string{
|
||||
0: "FOLDER_TYPE_SEND_RECEIVE",
|
||||
1: "FOLDER_TYPE_SEND_ONLY",
|
||||
2: "FOLDER_TYPE_RECEIVE_ONLY",
|
||||
3: "FOLDER_TYPE_RECEIVE_ENCRYPTED",
|
||||
}
|
||||
FolderType_value = map[string]int32{
|
||||
"FOLDER_TYPE_SEND_RECEIVE": 0,
|
||||
"FOLDER_TYPE_SEND_ONLY": 1,
|
||||
"FOLDER_TYPE_RECEIVE_ONLY": 2,
|
||||
"FOLDER_TYPE_RECEIVE_ENCRYPTED": 3,
|
||||
}
|
||||
)
|
||||
|
||||
func (x FolderType) Enum() *FolderType {
|
||||
p := new(FolderType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x FolderType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (FolderType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_bep_bep_proto_enumTypes[3].Descriptor()
|
||||
}
|
||||
|
||||
func (FolderType) Type() protoreflect.EnumType {
|
||||
return &file_bep_bep_proto_enumTypes[3]
|
||||
}
|
||||
|
||||
func (x FolderType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use FolderType.Descriptor instead.
|
||||
func (FolderType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_bep_bep_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
type FolderStopReason int32
|
||||
|
||||
const (
|
||||
FolderStopReason_FOLDER_STOP_REASON_RUNNING FolderStopReason = 0 // i.e., not stopped
|
||||
FolderStopReason_FOLDER_STOP_REASON_PAUSED FolderStopReason = 1
|
||||
)
|
||||
|
||||
// Enum value maps for FolderStopReason.
|
||||
var (
|
||||
FolderStopReason_name = map[int32]string{
|
||||
0: "FOLDER_STOP_REASON_RUNNING",
|
||||
1: "FOLDER_STOP_REASON_PAUSED",
|
||||
}
|
||||
FolderStopReason_value = map[string]int32{
|
||||
"FOLDER_STOP_REASON_RUNNING": 0,
|
||||
"FOLDER_STOP_REASON_PAUSED": 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (x FolderStopReason) Enum() *FolderStopReason {
|
||||
p := new(FolderStopReason)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x FolderStopReason) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (FolderStopReason) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_bep_bep_proto_enumTypes[4].Descriptor()
|
||||
}
|
||||
|
||||
func (FolderStopReason) Type() protoreflect.EnumType {
|
||||
return &file_bep_bep_proto_enumTypes[4]
|
||||
}
|
||||
|
||||
func (x FolderStopReason) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use FolderStopReason.Descriptor instead.
|
||||
func (FolderStopReason) EnumDescriptor() ([]byte, []int) {
|
||||
return file_bep_bep_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
type FileInfoType int32
|
||||
|
||||
const (
|
||||
@@ -220,11 +318,11 @@ func (x FileInfoType) String() string {
|
||||
}
|
||||
|
||||
func (FileInfoType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_bep_bep_proto_enumTypes[3].Descriptor()
|
||||
return file_bep_bep_proto_enumTypes[5].Descriptor()
|
||||
}
|
||||
|
||||
func (FileInfoType) Type() protoreflect.EnumType {
|
||||
return &file_bep_bep_proto_enumTypes[3]
|
||||
return &file_bep_bep_proto_enumTypes[5]
|
||||
}
|
||||
|
||||
func (x FileInfoType) Number() protoreflect.EnumNumber {
|
||||
@@ -233,7 +331,7 @@ func (x FileInfoType) Number() protoreflect.EnumNumber {
|
||||
|
||||
// Deprecated: Use FileInfoType.Descriptor instead.
|
||||
func (FileInfoType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_bep_bep_proto_rawDescGZIP(), []int{3}
|
||||
return file_bep_bep_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
type ErrorCode int32
|
||||
@@ -272,11 +370,11 @@ func (x ErrorCode) String() string {
|
||||
}
|
||||
|
||||
func (ErrorCode) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_bep_bep_proto_enumTypes[4].Descriptor()
|
||||
return file_bep_bep_proto_enumTypes[6].Descriptor()
|
||||
}
|
||||
|
||||
func (ErrorCode) Type() protoreflect.EnumType {
|
||||
return &file_bep_bep_proto_enumTypes[4]
|
||||
return &file_bep_bep_proto_enumTypes[6]
|
||||
}
|
||||
|
||||
func (x ErrorCode) Number() protoreflect.EnumNumber {
|
||||
@@ -285,7 +383,7 @@ func (x ErrorCode) Number() protoreflect.EnumNumber {
|
||||
|
||||
// Deprecated: Use ErrorCode.Descriptor instead.
|
||||
func (ErrorCode) EnumDescriptor() ([]byte, []int) {
|
||||
return file_bep_bep_proto_rawDescGZIP(), []int{4}
|
||||
return file_bep_bep_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
type FileDownloadProgressUpdateType int32
|
||||
@@ -318,11 +416,11 @@ func (x FileDownloadProgressUpdateType) String() string {
|
||||
}
|
||||
|
||||
func (FileDownloadProgressUpdateType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_bep_bep_proto_enumTypes[5].Descriptor()
|
||||
return file_bep_bep_proto_enumTypes[7].Descriptor()
|
||||
}
|
||||
|
||||
func (FileDownloadProgressUpdateType) Type() protoreflect.EnumType {
|
||||
return &file_bep_bep_proto_enumTypes[5]
|
||||
return &file_bep_bep_proto_enumTypes[7]
|
||||
}
|
||||
|
||||
func (x FileDownloadProgressUpdateType) Number() protoreflect.EnumNumber {
|
||||
@@ -331,7 +429,7 @@ func (x FileDownloadProgressUpdateType) Number() protoreflect.EnumNumber {
|
||||
|
||||
// Deprecated: Use FileDownloadProgressUpdateType.Descriptor instead.
|
||||
func (FileDownloadProgressUpdateType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_bep_bep_proto_rawDescGZIP(), []int{5}
|
||||
return file_bep_bep_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
type Hello struct {
|
||||
@@ -522,14 +620,11 @@ type Folder struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"`
|
||||
ReadOnly bool `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"`
|
||||
IgnorePermissions bool `protobuf:"varint,4,opt,name=ignore_permissions,json=ignorePermissions,proto3" json:"ignore_permissions,omitempty"`
|
||||
IgnoreDelete bool `protobuf:"varint,5,opt,name=ignore_delete,json=ignoreDelete,proto3" json:"ignore_delete,omitempty"`
|
||||
DisableTempIndexes bool `protobuf:"varint,6,opt,name=disable_temp_indexes,json=disableTempIndexes,proto3" json:"disable_temp_indexes,omitempty"`
|
||||
Paused bool `protobuf:"varint,7,opt,name=paused,proto3" json:"paused,omitempty"`
|
||||
Devices []*Device `protobuf:"bytes,16,rep,name=devices,proto3" json:"devices,omitempty"`
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"`
|
||||
Type FolderType `protobuf:"varint,3,opt,name=type,proto3,enum=bep.FolderType" json:"type,omitempty"`
|
||||
StopReason FolderStopReason `protobuf:"varint,7,opt,name=stop_reason,json=stopReason,proto3,enum=bep.FolderStopReason" json:"stop_reason,omitempty"`
|
||||
Devices []*Device `protobuf:"bytes,16,rep,name=devices,proto3" json:"devices,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Folder) Reset() {
|
||||
@@ -576,39 +671,18 @@ func (x *Folder) GetLabel() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Folder) GetReadOnly() bool {
|
||||
func (x *Folder) GetType() FolderType {
|
||||
if x != nil {
|
||||
return x.ReadOnly
|
||||
return x.Type
|
||||
}
|
||||
return false
|
||||
return FolderType_FOLDER_TYPE_SEND_RECEIVE
|
||||
}
|
||||
|
||||
func (x *Folder) GetIgnorePermissions() bool {
|
||||
func (x *Folder) GetStopReason() FolderStopReason {
|
||||
if x != nil {
|
||||
return x.IgnorePermissions
|
||||
return x.StopReason
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Folder) GetIgnoreDelete() bool {
|
||||
if x != nil {
|
||||
return x.IgnoreDelete
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Folder) GetDisableTempIndexes() bool {
|
||||
if x != nil {
|
||||
return x.DisableTempIndexes
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Folder) GetPaused() bool {
|
||||
if x != nil {
|
||||
return x.Paused
|
||||
}
|
||||
return false
|
||||
return FolderStopReason_FOLDER_STOP_REASON_RUNNING
|
||||
}
|
||||
|
||||
func (x *Folder) GetDevices() []*Device {
|
||||
@@ -1959,259 +2033,267 @@ var file_bep_bep_proto_rawDesc = []byte{
|
||||
0x70, 0x2e, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x52, 0x07, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72,
|
||||
0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x22,
|
||||
0x90, 0x02, 0x0a, 0x06, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
|
||||
0xb8, 0x01, 0x0a, 0x06, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61,
|
||||
0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c,
|
||||
0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x2d, 0x0a,
|
||||
0x12, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x69, 0x67, 0x6e, 0x6f, 0x72,
|
||||
0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d,
|
||||
0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74,
|
||||
0x65, 0x12, 0x30, 0x0a, 0x14, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x74, 0x65, 0x6d,
|
||||
0x70, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x12, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x49, 0x6e, 0x64, 0x65,
|
||||
0x78, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x75, 0x73, 0x65, 0x64, 0x18, 0x07, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x61, 0x75, 0x73, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x07, 0x64,
|
||||
0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x62,
|
||||
0x65, 0x70, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x07, 0x64, 0x65, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x22, 0xf3, 0x02, 0x0a, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x0a,
|
||||
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03,
|
||||
0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12,
|
||||
0x32, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x72,
|
||||
0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x65, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65,
|
||||
0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65,
|
||||
0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x65, 0x71, 0x75, 0x65,
|
||||
0x6e, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65,
|
||||
0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75,
|
||||
0x63, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x49, 0x64, 0x12, 0x3c,
|
||||
0x0a, 0x1a, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x61, 0x6c, 0x73, 0x18, 0x09, 0x20, 0x01,
|
||||
0x28, 0x08, 0x52, 0x18, 0x73, 0x6b, 0x69, 0x70, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x61, 0x6c, 0x73, 0x12, 0x3a, 0x0a, 0x19,
|
||||
0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77,
|
||||
0x6f, 0x72, 0x64, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||
0x17, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77,
|
||||
0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x69, 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65,
|
||||
0x78, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x05, 0x66, 0x69, 0x6c,
|
||||
0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46,
|
||||
0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x23,
|
||||
0x0a, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x71, 0x75, 0x65,
|
||||
0x6e, 0x63, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x0b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x55, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x05, 0x66,
|
||||
0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x62, 0x65, 0x70,
|
||||
0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73,
|
||||
0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63,
|
||||
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x71,
|
||||
0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x73, 0x65,
|
||||
0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x70, 0x72,
|
||||
0x65, 0x76, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0xfe, 0x05, 0x0a, 0x08, 0x46,
|
||||
0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73,
|
||||
0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12,
|
||||
0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x73, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x03, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x53, 0x12, 0x1f,
|
||||
0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x0c, 0x20,
|
||||
0x01, 0x28, 0x04, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x42, 0x79, 0x12,
|
||||
0x25, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x0b, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x76,
|
||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e,
|
||||
0x63, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e,
|
||||
0x63, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x10, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e,
|
||||
0x66, 0x6f, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x79,
|
||||
0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x11, 0x20, 0x01,
|
||||
0x28, 0x0c, 0x52, 0x0d, 0x73, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x54, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68,
|
||||
0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x48, 0x61,
|
||||
0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x18,
|
||||
0x13, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64,
|
||||
0x12, 0x25, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11,
|
||||
0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x54, 0x79, 0x70,
|
||||
0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x65,
|
||||
0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64,
|
||||
0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a,
|
||||
0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x4e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09,
|
||||
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x2d, 0x0a, 0x08, 0x70, 0x6c, 0x61,
|
||||
0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x65,
|
||||
0x70, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x52, 0x08,
|
||||
0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x20, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61,
|
||||
0x6c, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a,
|
||||
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x76, 0x65,
|
||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x27,
|
||||
0x0a, 0x0f, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6e,
|
||||
0x73, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x43,
|
||||
0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x73, 0x12, 0x37, 0x0a, 0x17, 0x65, 0x6e, 0x63, 0x72, 0x79,
|
||||
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x5f, 0x73, 0x69,
|
||||
0x7a, 0x65, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x65, 0x6e, 0x63, 0x72, 0x79,
|
||||
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6e,
|
||||
0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x6e, 0x76,
|
||||
0x61, 0x6c, 0x69, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x6f, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e, 0x6f,
|
||||
0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x51, 0x0a, 0x09, 0x42,
|
||||
0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66,
|
||||
0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x05, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x32,
|
||||
0x0a, 0x06, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x28, 0x0a, 0x08, 0x63, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x62, 0x65, 0x70,
|
||||
0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x08, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65,
|
||||
0x72, 0x73, 0x22, 0x2f, 0x0a, 0x07, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x0e, 0x0a,
|
||||
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a,
|
||||
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x22, 0xfd, 0x01, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x44, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x55, 0x6e, 0x69, 0x78, 0x44, 0x61, 0x74,
|
||||
0x61, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x78, 0x12, 0x2a, 0x0a, 0x07, 0x77, 0x69, 0x6e, 0x64, 0x6f,
|
||||
0x77, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x57,
|
||||
0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x61, 0x74, 0x61, 0x52, 0x07, 0x77, 0x69, 0x6e, 0x64,
|
||||
0x6f, 0x77, 0x73, 0x12, 0x24, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61,
|
||||
0x74, 0x61, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x12, 0x26, 0x0a, 0x06, 0x64, 0x61, 0x72,
|
||||
0x77, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e,
|
||||
0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x06, 0x64, 0x61, 0x72, 0x77, 0x69,
|
||||
0x6e, 0x12, 0x28, 0x0a, 0x07, 0x66, 0x72, 0x65, 0x65, 0x62, 0x73, 0x64, 0x18, 0x05, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61,
|
||||
0x74, 0x61, 0x52, 0x07, 0x66, 0x72, 0x65, 0x65, 0x62, 0x73, 0x64, 0x12, 0x26, 0x0a, 0x06, 0x6e,
|
||||
0x65, 0x74, 0x62, 0x73, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65,
|
||||
0x70, 0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x06, 0x6e, 0x65, 0x74,
|
||||
0x62, 0x73, 0x64, 0x22, 0x6c, 0x0a, 0x08, 0x55, 0x6e, 0x69, 0x78, 0x44, 0x61, 0x74, 0x61, 0x12,
|
||||
0x1d, 0x0a, 0x0a, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d,
|
||||
0x0a, 0x0a, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a,
|
||||
0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12,
|
||||
0x10, 0x0a, 0x03, 0x67, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x67, 0x69,
|
||||
0x64, 0x22, 0x52, 0x0a, 0x0b, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x61, 0x74, 0x61,
|
||||
0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12,
|
||||
0x24, 0x0a, 0x0e, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x75,
|
||||
0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x73,
|
||||
0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x2f, 0x0a, 0x09, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61,
|
||||
0x74, 0x61, 0x12, 0x22, 0x0a, 0x06, 0x78, 0x61, 0x74, 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x52, 0x06,
|
||||
0x78, 0x61, 0x74, 0x74, 0x72, 0x73, 0x22, 0x31, 0x0a, 0x05, 0x58, 0x61, 0x74, 0x74, 0x72, 0x12,
|
||||
0x12, 0x23, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f,
|
||||
0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52,
|
||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x72, 0x65,
|
||||
0x61, 0x73, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x62, 0x65, 0x70,
|
||||
0x2e, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x61, 0x73, 0x6f,
|
||||
0x6e, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x25, 0x0a,
|
||||
0x07, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b,
|
||||
0x2e, 0x62, 0x65, 0x70, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x07, 0x64, 0x65, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x07, 0x22, 0xf3, 0x02, 0x0a, 0x06, 0x44,
|
||||
0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64,
|
||||
0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64,
|
||||
0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x72,
|
||||
0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x62,
|
||||
0x65, 0x70, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b,
|
||||
0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x63,
|
||||
0x65, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x63, 0x65, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f,
|
||||
0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b,
|
||||
0x6d, 0x61, 0x78, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x0a, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x69,
|
||||
0x6e, 0x64, 0x65, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x69,
|
||||
0x6e, 0x64, 0x65, 0x78, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x1a, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x69,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x6d, 0x6f,
|
||||
0x76, 0x61, 0x6c, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x73, 0x6b, 0x69, 0x70,
|
||||
0x49, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6d, 0x6f,
|
||||
0x76, 0x61, 0x6c, 0x73, 0x12, 0x3a, 0x0a, 0x19, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x74, 0x6f, 0x6b, 0x65,
|
||||
0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
|
||||
0x22, 0x69, 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c,
|
||||
0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65,
|
||||
0x72, 0x12, 0x23, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x0d, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52,
|
||||
0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73,
|
||||
0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c,
|
||||
0x61, 0x73, 0x74, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x0b,
|
||||
0x49, 0x6e, 0x64, 0x65, 0x78, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66,
|
||||
0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c,
|
||||
0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66,
|
||||
0x6f, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x61, 0x73, 0x74,
|
||||
0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x23, 0x0a,
|
||||
0x0d, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x76, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e,
|
||||
0x63, 0x65, 0x22, 0xfe, 0x05, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12,
|
||||
0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xcd, 0x01, 0x0a, 0x07, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a,
|
||||
0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73,
|
||||
0x68, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72,
|
||||
0x61, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x66, 0x72, 0x6f, 0x6d, 0x54,
|
||||
0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x6c, 0x6f, 0x63,
|
||||
0x6b, 0x5f, 0x6e, 0x6f, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63,
|
||||
0x6b, 0x4e, 0x6f, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0x52, 0x0a, 0x08, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x04, 0x63, 0x6f, 0x64,
|
||||
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x45, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x65, 0x0a,
|
||||
0x10, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,
|
||||
0x73, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x07, 0x75, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x62, 0x65, 0x70,
|
||||
0x2e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f,
|
||||
0x67, 0x72, 0x65, 0x73, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x07, 0x75, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x1a, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x69, 0x66,
|
||||
0x69, 0x65, 0x64, 0x5f, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6d, 0x6f, 0x64,
|
||||
0x69, 0x66, 0x69, 0x65, 0x64, 0x53, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,
|
||||
0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6d, 0x6f, 0x64,
|
||||
0x69, 0x66, 0x69, 0x65, 0x64, 0x42, 0x79, 0x12, 0x25, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x56,
|
||||
0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a,
|
||||
0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x62, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70,
|
||||
0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x63,
|
||||
0x6b, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x79, 0x6d, 0x6c,
|
||||
0x69, 0x6e, 0x6b, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f,
|
||||
0x63, 0x6b, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a,
|
||||
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e,
|
||||
0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x65,
|
||||
0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69, 0x6c,
|
||||
0x65, 0x49, 0x6e, 0x66, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12,
|
||||
0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x6e, 0x73,
|
||||
0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64,
|
||||
0x4e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x69, 0x7a, 0x65,
|
||||
0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x69, 0x7a,
|
||||
0x65, 0x12, 0x2d, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x0e, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f,
|
||||
0x72, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x12, 0x20, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18,
|
||||
0xe8, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x46, 0x6c, 0x61,
|
||||
0x67, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x61,
|
||||
0x73, 0x68, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x5f,
|
||||
0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6e, 0x73, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x0d, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4e, 0x73, 0x12,
|
||||
0x37, 0x0a, 0x17, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x72,
|
||||
0x61, 0x69, 0x6c, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28,
|
||||
0x05, 0x52, 0x15, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x61,
|
||||
0x69, 0x6c, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65,
|
||||
0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74,
|
||||
0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x07, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x25, 0x0a, 0x0e,
|
||||
0x6e, 0x6f, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e, 0x6f, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x22, 0x51, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04,
|
||||
0x68, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04,
|
||||
0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65,
|
||||
0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x32, 0x0a, 0x06, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72,
|
||||
0x12, 0x28, 0x0a, 0x08, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
|
||||
0x52, 0x08, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0x2f, 0x0a, 0x07, 0x43, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xfd, 0x01, 0x0a, 0x0c,
|
||||
0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x04,
|
||||
0x75, 0x6e, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x62, 0x65, 0x70,
|
||||
0x2e, 0x55, 0x6e, 0x69, 0x78, 0x44, 0x61, 0x74, 0x61, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x78, 0x12,
|
||||
0x2a, 0x0a, 0x07, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x10, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x61,
|
||||
0x74, 0x61, 0x52, 0x07, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x12, 0x24, 0x0a, 0x05, 0x6c,
|
||||
0x69, 0x6e, 0x75, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70,
|
||||
0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x75,
|
||||
0x78, 0x12, 0x26, 0x0a, 0x06, 0x64, 0x61, 0x72, 0x77, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74,
|
||||
0x61, 0x52, 0x06, 0x64, 0x61, 0x72, 0x77, 0x69, 0x6e, 0x12, 0x28, 0x0a, 0x07, 0x66, 0x72, 0x65,
|
||||
0x65, 0x62, 0x73, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70,
|
||||
0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x07, 0x66, 0x72, 0x65, 0x65,
|
||||
0x62, 0x73, 0x64, 0x12, 0x26, 0x0a, 0x06, 0x6e, 0x65, 0x74, 0x62, 0x73, 0x64, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44,
|
||||
0x61, 0x74, 0x61, 0x52, 0x06, 0x6e, 0x65, 0x74, 0x62, 0x73, 0x64, 0x22, 0x6c, 0x0a, 0x08, 0x55,
|
||||
0x6e, 0x69, 0x78, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x77, 0x6e, 0x65, 0x72,
|
||||
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x77, 0x6e,
|
||||
0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x72, 0x6f, 0x75,
|
||||
0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x05, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x69, 0x64, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x67, 0x69, 0x64, 0x22, 0x52, 0x0a, 0x0b, 0x57, 0x69, 0x6e,
|
||||
0x64, 0x6f, 0x77, 0x73, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x77, 0x6e, 0x65,
|
||||
0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x77,
|
||||
0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6f, 0x77, 0x6e, 0x65, 0x72,
|
||||
0x5f, 0x69, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x0c, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x2f, 0x0a,
|
||||
0x09, 0x58, 0x61, 0x74, 0x74, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x06, 0x78, 0x61,
|
||||
0x74, 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x62, 0x65, 0x70,
|
||||
0x2e, 0x58, 0x61, 0x74, 0x74, 0x72, 0x52, 0x06, 0x78, 0x61, 0x74, 0x74, 0x72, 0x73, 0x22, 0x31,
|
||||
0x0a, 0x05, 0x58, 0x61, 0x74, 0x74, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x22, 0xcd, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a,
|
||||
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a,
|
||||
0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66,
|
||||
0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66,
|
||||
0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65,
|
||||
0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||
0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x72, 0x6f,
|
||||
0x6d, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x0d, 0x66, 0x72, 0x6f, 0x6d, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79,
|
||||
0x12, 0x19, 0x0a, 0x08, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x6f, 0x18, 0x09, 0x20, 0x01,
|
||||
0x28, 0x05, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x6f, 0x4a, 0x04, 0x08, 0x08, 0x10,
|
||||
0x09, 0x22, 0x52, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a,
|
||||
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74,
|
||||
0x61, 0x12, 0x22, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x0e, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x52,
|
||||
0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x65, 0x0a, 0x10, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61,
|
||||
0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c,
|
||||
0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65,
|
||||
0x72, 0x12, 0x39, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77,
|
||||
0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x55, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x79,
|
||||
0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46,
|
||||
0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72,
|
||||
0x65, 0x73, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x75,
|
||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a,
|
||||
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b,
|
||||
0x2e, 0x62, 0x65, 0x70, 0x2e, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x76, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x69, 0x6e,
|
||||
0x64, 0x65, 0x78, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x05, 0x42, 0x02, 0x10, 0x00, 0x52,
|
||||
0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x12, 0x1d, 0x0a,
|
||||
0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28,
|
||||
0x05, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x06, 0x0a, 0x04,
|
||||
0x50, 0x69, 0x6e, 0x67, 0x22, 0x1f, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x16, 0x0a,
|
||||
0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72,
|
||||
0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, 0xed, 0x01, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45,
|
||||
0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c, 0x55, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x43, 0x4f,
|
||||
0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47,
|
||||
0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x10, 0x01, 0x12, 0x1d,
|
||||
0x0a, 0x19, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49,
|
||||
0x4e, 0x44, 0x45, 0x58, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a,
|
||||
0x14, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45,
|
||||
0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x45, 0x53, 0x53, 0x41,
|
||||
0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45,
|
||||
0x10, 0x04, 0x12, 0x22, 0x0a, 0x1e, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59,
|
||||
0x50, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x5f, 0x50, 0x52, 0x4f, 0x47,
|
||||
0x52, 0x45, 0x53, 0x53, 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47,
|
||||
0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x06, 0x12, 0x16, 0x0a,
|
||||
0x12, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c,
|
||||
0x4f, 0x53, 0x45, 0x10, 0x07, 0x2a, 0x4f, 0x0a, 0x12, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x18, 0x4d,
|
||||
0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49,
|
||||
0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x45, 0x53,
|
||||
0x53, 0x41, 0x47, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e,
|
||||
0x5f, 0x4c, 0x5a, 0x34, 0x10, 0x01, 0x2a, 0x56, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53,
|
||||
0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x10, 0x00, 0x12,
|
||||
0x15, 0x0a, 0x11, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4e,
|
||||
0x45, 0x56, 0x45, 0x52, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45,
|
||||
0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x41, 0x4c, 0x57, 0x41, 0x59, 0x53, 0x10, 0x02, 0x2a, 0xb0,
|
||||
0x01, 0x0a, 0x0c, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x12,
|
||||
0x17, 0x0a, 0x13, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50,
|
||||
0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x46, 0x49, 0x4c, 0x45,
|
||||
0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43,
|
||||
0x54, 0x4f, 0x52, 0x59, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1b, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49,
|
||||
0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4d, 0x4c, 0x49, 0x4e, 0x4b,
|
||||
0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x02, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x28, 0x0a, 0x20, 0x46,
|
||||
0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59,
|
||||
0x4d, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x59, 0x10,
|
||||
0x03, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e,
|
||||
0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4d, 0x4c, 0x49, 0x4e, 0x4b, 0x10,
|
||||
0x04, 0x2a, 0x76, 0x0a, 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17,
|
||||
0x0a, 0x13, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x4e, 0x4f, 0x5f,
|
||||
0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x45, 0x52, 0x52, 0x4f, 0x52,
|
||||
0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x49, 0x43, 0x10, 0x01, 0x12,
|
||||
0x1b, 0x0a, 0x17, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x4e, 0x4f,
|
||||
0x5f, 0x53, 0x55, 0x43, 0x48, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17,
|
||||
0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c,
|
||||
0x49, 0x44, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x2a, 0x7e, 0x0a, 0x1e, 0x46, 0x69, 0x6c,
|
||||
0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,
|
||||
0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x29, 0x46,
|
||||
0x49, 0x4c, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x5f, 0x50, 0x52, 0x4f,
|
||||
0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x59, 0x50,
|
||||
0x45, 0x5f, 0x41, 0x50, 0x50, 0x45, 0x4e, 0x44, 0x10, 0x00, 0x12, 0x2d, 0x0a, 0x29, 0x46, 0x49,
|
||||
0x4c, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x5f, 0x50, 0x52, 0x4f, 0x47,
|
||||
0x52, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45,
|
||||
0x5f, 0x46, 0x4f, 0x52, 0x47, 0x45, 0x54, 0x10, 0x01, 0x42, 0x70, 0x0a, 0x07, 0x63, 0x6f, 0x6d,
|
||||
0x2e, 0x62, 0x65, 0x70, 0x42, 0x08, 0x42, 0x65, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01,
|
||||
0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x79, 0x6e,
|
||||
0x63, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x74, 0x68, 0x69, 0x6e, 0x67,
|
||||
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x62, 0x65,
|
||||
0x70, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x03, 0x42, 0x65, 0x70, 0xca, 0x02, 0x03,
|
||||
0x42, 0x65, 0x70, 0xe2, 0x02, 0x0f, 0x42, 0x65, 0x70, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74,
|
||||
0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x03, 0x42, 0x65, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
0x61, 0x74, 0x65, 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a,
|
||||
0x1a, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f,
|
||||
0x67, 0x72, 0x65, 0x73, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x44, 0x0a, 0x0b, 0x75,
|
||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
|
||||
0x32, 0x23, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c,
|
||||
0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74,
|
||||
0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70,
|
||||
0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x62, 0x65, 0x70, 0x2e, 0x56, 0x65, 0x63,
|
||||
0x74, 0x6f, 0x72, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0d,
|
||||
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x18, 0x04, 0x20,
|
||||
0x03, 0x28, 0x05, 0x42, 0x02, 0x10, 0x00, 0x52, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e,
|
||||
0x64, 0x65, 0x78, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73,
|
||||
0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x53, 0x69, 0x7a, 0x65, 0x22, 0x06, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x22, 0x1f, 0x0a, 0x05,
|
||||
0x43, 0x6c, 0x6f, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, 0xed, 0x01,
|
||||
0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a,
|
||||
0x1b, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c,
|
||||
0x55, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x16,
|
||||
0x0a, 0x12, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49,
|
||||
0x4e, 0x44, 0x45, 0x58, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47,
|
||||
0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x5f, 0x55, 0x50, 0x44,
|
||||
0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45,
|
||||
0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x03, 0x12,
|
||||
0x19, 0x0a, 0x15, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f,
|
||||
0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x04, 0x12, 0x22, 0x0a, 0x1e, 0x4d, 0x45,
|
||||
0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c,
|
||||
0x4f, 0x41, 0x44, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x05, 0x12, 0x15,
|
||||
0x0a, 0x11, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50,
|
||||
0x49, 0x4e, 0x47, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45,
|
||||
0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x07, 0x2a, 0x4f, 0x0a,
|
||||
0x12, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x18, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x43,
|
||||
0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10,
|
||||
0x00, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x43, 0x4f, 0x4d,
|
||||
0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4c, 0x5a, 0x34, 0x10, 0x01, 0x2a, 0x56,
|
||||
0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a,
|
||||
0x14, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x54,
|
||||
0x41, 0x44, 0x41, 0x54, 0x41, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x4f, 0x4d, 0x50, 0x52,
|
||||
0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4e, 0x45, 0x56, 0x45, 0x52, 0x10, 0x01, 0x12, 0x16,
|
||||
0x0a, 0x12, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x41, 0x4c,
|
||||
0x57, 0x41, 0x59, 0x53, 0x10, 0x02, 0x2a, 0x86, 0x01, 0x0a, 0x0a, 0x46, 0x6f, 0x6c, 0x64, 0x65,
|
||||
0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f,
|
||||
0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x52, 0x45, 0x43, 0x45, 0x49, 0x56,
|
||||
0x45, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x54, 0x59,
|
||||
0x50, 0x45, 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x01, 0x12, 0x1c,
|
||||
0x0a, 0x18, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45,
|
||||
0x43, 0x45, 0x49, 0x56, 0x45, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d,
|
||||
0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x43, 0x45,
|
||||
0x49, 0x56, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x45, 0x44, 0x10, 0x03, 0x2a,
|
||||
0x51, 0x0a, 0x10, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x61,
|
||||
0x73, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x1a, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x53, 0x54,
|
||||
0x4f, 0x50, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e,
|
||||
0x47, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x46, 0x4f, 0x4c, 0x44, 0x45, 0x52, 0x5f, 0x53, 0x54,
|
||||
0x4f, 0x50, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x50, 0x41, 0x55, 0x53, 0x45, 0x44,
|
||||
0x10, 0x01, 0x2a, 0xb0, 0x01, 0x0a, 0x0c, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x54,
|
||||
0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f,
|
||||
0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18,
|
||||
0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44,
|
||||
0x49, 0x52, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x59, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1b, 0x46, 0x49,
|
||||
0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4d,
|
||||
0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x02, 0x1a, 0x02, 0x08, 0x01, 0x12,
|
||||
0x28, 0x0a, 0x20, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50,
|
||||
0x45, 0x5f, 0x53, 0x59, 0x4d, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54,
|
||||
0x4f, 0x52, 0x59, 0x10, 0x03, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x49, 0x4c,
|
||||
0x45, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x4d, 0x4c,
|
||||
0x49, 0x4e, 0x4b, 0x10, 0x04, 0x2a, 0x76, 0x0a, 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f,
|
||||
0x64, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45,
|
||||
0x5f, 0x4e, 0x4f, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x45,
|
||||
0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x49,
|
||||
0x43, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44,
|
||||
0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x53, 0x55, 0x43, 0x48, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x02,
|
||||
0x12, 0x1b, 0x0a, 0x17, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49,
|
||||
0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x2a, 0x7e, 0x0a,
|
||||
0x1e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x72, 0x6f,
|
||||
0x67, 0x72, 0x65, 0x73, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12,
|
||||
0x2d, 0x0a, 0x29, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44,
|
||||
0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45,
|
||||
0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x50, 0x50, 0x45, 0x4e, 0x44, 0x10, 0x00, 0x12, 0x2d,
|
||||
0x0a, 0x29, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x5f,
|
||||
0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f,
|
||||
0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x47, 0x45, 0x54, 0x10, 0x01, 0x42, 0x70, 0x0a,
|
||||
0x07, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x65, 0x70, 0x42, 0x08, 0x42, 0x65, 0x70, 0x50, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x2f, 0x73, 0x79, 0x6e, 0x63, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x74,
|
||||
0x68, 0x69, 0x6e, 0x67, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65,
|
||||
0x6e, 0x2f, 0x62, 0x65, 0x70, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x03, 0x42, 0x65,
|
||||
0x70, 0xca, 0x02, 0x03, 0x42, 0x65, 0x70, 0xe2, 0x02, 0x0f, 0x42, 0x65, 0x70, 0x5c, 0x47, 0x50,
|
||||
0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x03, 0x42, 0x65, 0x70, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -2226,67 +2308,71 @@ func file_bep_bep_proto_rawDescGZIP() []byte {
|
||||
return file_bep_bep_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_bep_bep_proto_enumTypes = make([]protoimpl.EnumInfo, 6)
|
||||
var file_bep_bep_proto_enumTypes = make([]protoimpl.EnumInfo, 8)
|
||||
var file_bep_bep_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
|
||||
var file_bep_bep_proto_goTypes = []any{
|
||||
(MessageType)(0), // 0: bep.MessageType
|
||||
(MessageCompression)(0), // 1: bep.MessageCompression
|
||||
(Compression)(0), // 2: bep.Compression
|
||||
(FileInfoType)(0), // 3: bep.FileInfoType
|
||||
(ErrorCode)(0), // 4: bep.ErrorCode
|
||||
(FileDownloadProgressUpdateType)(0), // 5: bep.FileDownloadProgressUpdateType
|
||||
(*Hello)(nil), // 6: bep.Hello
|
||||
(*Header)(nil), // 7: bep.Header
|
||||
(*ClusterConfig)(nil), // 8: bep.ClusterConfig
|
||||
(*Folder)(nil), // 9: bep.Folder
|
||||
(*Device)(nil), // 10: bep.Device
|
||||
(*Index)(nil), // 11: bep.Index
|
||||
(*IndexUpdate)(nil), // 12: bep.IndexUpdate
|
||||
(*FileInfo)(nil), // 13: bep.FileInfo
|
||||
(*BlockInfo)(nil), // 14: bep.BlockInfo
|
||||
(*Vector)(nil), // 15: bep.Vector
|
||||
(*Counter)(nil), // 16: bep.Counter
|
||||
(*PlatformData)(nil), // 17: bep.PlatformData
|
||||
(*UnixData)(nil), // 18: bep.UnixData
|
||||
(*WindowsData)(nil), // 19: bep.WindowsData
|
||||
(*XattrData)(nil), // 20: bep.XattrData
|
||||
(*Xattr)(nil), // 21: bep.Xattr
|
||||
(*Request)(nil), // 22: bep.Request
|
||||
(*Response)(nil), // 23: bep.Response
|
||||
(*DownloadProgress)(nil), // 24: bep.DownloadProgress
|
||||
(*FileDownloadProgressUpdate)(nil), // 25: bep.FileDownloadProgressUpdate
|
||||
(*Ping)(nil), // 26: bep.Ping
|
||||
(*Close)(nil), // 27: bep.Close
|
||||
(FolderType)(0), // 3: bep.FolderType
|
||||
(FolderStopReason)(0), // 4: bep.FolderStopReason
|
||||
(FileInfoType)(0), // 5: bep.FileInfoType
|
||||
(ErrorCode)(0), // 6: bep.ErrorCode
|
||||
(FileDownloadProgressUpdateType)(0), // 7: bep.FileDownloadProgressUpdateType
|
||||
(*Hello)(nil), // 8: bep.Hello
|
||||
(*Header)(nil), // 9: bep.Header
|
||||
(*ClusterConfig)(nil), // 10: bep.ClusterConfig
|
||||
(*Folder)(nil), // 11: bep.Folder
|
||||
(*Device)(nil), // 12: bep.Device
|
||||
(*Index)(nil), // 13: bep.Index
|
||||
(*IndexUpdate)(nil), // 14: bep.IndexUpdate
|
||||
(*FileInfo)(nil), // 15: bep.FileInfo
|
||||
(*BlockInfo)(nil), // 16: bep.BlockInfo
|
||||
(*Vector)(nil), // 17: bep.Vector
|
||||
(*Counter)(nil), // 18: bep.Counter
|
||||
(*PlatformData)(nil), // 19: bep.PlatformData
|
||||
(*UnixData)(nil), // 20: bep.UnixData
|
||||
(*WindowsData)(nil), // 21: bep.WindowsData
|
||||
(*XattrData)(nil), // 22: bep.XattrData
|
||||
(*Xattr)(nil), // 23: bep.Xattr
|
||||
(*Request)(nil), // 24: bep.Request
|
||||
(*Response)(nil), // 25: bep.Response
|
||||
(*DownloadProgress)(nil), // 26: bep.DownloadProgress
|
||||
(*FileDownloadProgressUpdate)(nil), // 27: bep.FileDownloadProgressUpdate
|
||||
(*Ping)(nil), // 28: bep.Ping
|
||||
(*Close)(nil), // 29: bep.Close
|
||||
}
|
||||
var file_bep_bep_proto_depIdxs = []int32{
|
||||
0, // 0: bep.Header.type:type_name -> bep.MessageType
|
||||
1, // 1: bep.Header.compression:type_name -> bep.MessageCompression
|
||||
9, // 2: bep.ClusterConfig.folders:type_name -> bep.Folder
|
||||
10, // 3: bep.Folder.devices:type_name -> bep.Device
|
||||
2, // 4: bep.Device.compression:type_name -> bep.Compression
|
||||
13, // 5: bep.Index.files:type_name -> bep.FileInfo
|
||||
13, // 6: bep.IndexUpdate.files:type_name -> bep.FileInfo
|
||||
15, // 7: bep.FileInfo.version:type_name -> bep.Vector
|
||||
14, // 8: bep.FileInfo.blocks:type_name -> bep.BlockInfo
|
||||
3, // 9: bep.FileInfo.type:type_name -> bep.FileInfoType
|
||||
17, // 10: bep.FileInfo.platform:type_name -> bep.PlatformData
|
||||
16, // 11: bep.Vector.counters:type_name -> bep.Counter
|
||||
18, // 12: bep.PlatformData.unix:type_name -> bep.UnixData
|
||||
19, // 13: bep.PlatformData.windows:type_name -> bep.WindowsData
|
||||
20, // 14: bep.PlatformData.linux:type_name -> bep.XattrData
|
||||
20, // 15: bep.PlatformData.darwin:type_name -> bep.XattrData
|
||||
20, // 16: bep.PlatformData.freebsd:type_name -> bep.XattrData
|
||||
20, // 17: bep.PlatformData.netbsd:type_name -> bep.XattrData
|
||||
21, // 18: bep.XattrData.xattrs:type_name -> bep.Xattr
|
||||
4, // 19: bep.Response.code:type_name -> bep.ErrorCode
|
||||
25, // 20: bep.DownloadProgress.updates:type_name -> bep.FileDownloadProgressUpdate
|
||||
5, // 21: bep.FileDownloadProgressUpdate.update_type:type_name -> bep.FileDownloadProgressUpdateType
|
||||
15, // 22: bep.FileDownloadProgressUpdate.version:type_name -> bep.Vector
|
||||
23, // [23:23] is the sub-list for method output_type
|
||||
23, // [23:23] is the sub-list for method input_type
|
||||
23, // [23:23] is the sub-list for extension type_name
|
||||
23, // [23:23] is the sub-list for extension extendee
|
||||
0, // [0:23] is the sub-list for field type_name
|
||||
11, // 2: bep.ClusterConfig.folders:type_name -> bep.Folder
|
||||
3, // 3: bep.Folder.type:type_name -> bep.FolderType
|
||||
4, // 4: bep.Folder.stop_reason:type_name -> bep.FolderStopReason
|
||||
12, // 5: bep.Folder.devices:type_name -> bep.Device
|
||||
2, // 6: bep.Device.compression:type_name -> bep.Compression
|
||||
15, // 7: bep.Index.files:type_name -> bep.FileInfo
|
||||
15, // 8: bep.IndexUpdate.files:type_name -> bep.FileInfo
|
||||
17, // 9: bep.FileInfo.version:type_name -> bep.Vector
|
||||
16, // 10: bep.FileInfo.blocks:type_name -> bep.BlockInfo
|
||||
5, // 11: bep.FileInfo.type:type_name -> bep.FileInfoType
|
||||
19, // 12: bep.FileInfo.platform:type_name -> bep.PlatformData
|
||||
18, // 13: bep.Vector.counters:type_name -> bep.Counter
|
||||
20, // 14: bep.PlatformData.unix:type_name -> bep.UnixData
|
||||
21, // 15: bep.PlatformData.windows:type_name -> bep.WindowsData
|
||||
22, // 16: bep.PlatformData.linux:type_name -> bep.XattrData
|
||||
22, // 17: bep.PlatformData.darwin:type_name -> bep.XattrData
|
||||
22, // 18: bep.PlatformData.freebsd:type_name -> bep.XattrData
|
||||
22, // 19: bep.PlatformData.netbsd:type_name -> bep.XattrData
|
||||
23, // 20: bep.XattrData.xattrs:type_name -> bep.Xattr
|
||||
6, // 21: bep.Response.code:type_name -> bep.ErrorCode
|
||||
27, // 22: bep.DownloadProgress.updates:type_name -> bep.FileDownloadProgressUpdate
|
||||
7, // 23: bep.FileDownloadProgressUpdate.update_type:type_name -> bep.FileDownloadProgressUpdateType
|
||||
17, // 24: bep.FileDownloadProgressUpdate.version:type_name -> bep.Vector
|
||||
25, // [25:25] is the sub-list for method output_type
|
||||
25, // [25:25] is the sub-list for method input_type
|
||||
25, // [25:25] is the sub-list for extension type_name
|
||||
25, // [25:25] is the sub-list for extension extendee
|
||||
0, // [0:25] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_bep_bep_proto_init() }
|
||||
@@ -2299,7 +2385,7 @@ func file_bep_bep_proto_init() {
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_bep_bep_proto_rawDesc,
|
||||
NumEnums: 6,
|
||||
NumEnums: 8,
|
||||
NumMessages: 22,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
|
||||
@@ -7,14 +7,16 @@
|
||||
package protoutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var errBufferTooSmall = errors.New("buffer too small")
|
||||
|
||||
func MarshalTo(buf []byte, pb proto.Message) (int, error) {
|
||||
if sz := proto.Size(pb); len(buf) < sz {
|
||||
return 0, fmt.Errorf("buffer too small")
|
||||
return 0, errBufferTooSmall
|
||||
} else if sz == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
+1
-1
@@ -166,7 +166,7 @@ func (s *service) getListener(guiCfg config.GUIConfiguration) (net.Listener, err
|
||||
name = s.tlsDefaultCommonName
|
||||
}
|
||||
|
||||
cert, err = tlsutil.NewCertificate(httpsCertFile, httpsKeyFile, name, httpsCertLifetimeDays)
|
||||
cert, err = tlsutil.NewCertificate(httpsCertFile, httpsKeyFile, name, httpsCertLifetimeDays, true)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/wlynxg/anet"
|
||||
)
|
||||
|
||||
func NewBroadcast(port int) Interface {
|
||||
@@ -44,7 +46,7 @@ func writeBroadcasts(ctx context.Context, inbox <-chan []byte, port int) error {
|
||||
return doneCtx.Err()
|
||||
}
|
||||
|
||||
intfs, err := net.Interfaces()
|
||||
intfs, err := anet.Interfaces()
|
||||
if err != nil {
|
||||
l.Debugln("Failed to list interfaces:", err)
|
||||
// net.Interfaces() is broken on Android. see https://github.com/golang/go/issues/40569
|
||||
@@ -52,12 +54,14 @@ func writeBroadcasts(ctx context.Context, inbox <-chan []byte, port int) error {
|
||||
}
|
||||
|
||||
var dsts []net.IP
|
||||
for _, intf := range intfs {
|
||||
for i := range intfs {
|
||||
intf := intfs[i]
|
||||
|
||||
if intf.Flags&net.FlagRunning == 0 || intf.Flags&net.FlagBroadcast == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
addrs, err := intf.Addrs()
|
||||
addrs, err := anet.InterfaceAddrsByInterface(&intf)
|
||||
if err != nil {
|
||||
l.Debugln("Failed to list interface addresses:", err)
|
||||
// Interface discovery might work while retrieving the addresses doesn't. So log the error and carry on.
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/wlynxg/anet"
|
||||
|
||||
"golang.org/x/net/ipv6"
|
||||
)
|
||||
|
||||
@@ -59,7 +61,7 @@ func writeMulticasts(ctx context.Context, inbox <-chan []byte, addr string) erro
|
||||
return doneCtx.Err()
|
||||
}
|
||||
|
||||
intfs, err := net.Interfaces()
|
||||
intfs, err := anet.Interfaces()
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
return err
|
||||
@@ -117,7 +119,7 @@ func readMulticasts(ctx context.Context, outbox chan<- recv, addr string) error
|
||||
conn.Close()
|
||||
}()
|
||||
|
||||
intfs, err := net.Interfaces()
|
||||
intfs, err := anet.Interfaces()
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
return err
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
|
||||
const (
|
||||
OldestHandledVersion = 10
|
||||
CurrentVersion = 50
|
||||
CurrentVersion = 51
|
||||
MaxRescanIntervalS = 365 * 24 * 60 * 60
|
||||
)
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ func TestDefaultValues(t *testing.T) {
|
||||
},
|
||||
MaxConflicts: 10,
|
||||
MarkerName: ".stfolder",
|
||||
MaxConcurrentWrites: 2,
|
||||
MaxConcurrentWrites: maxConcurrentWritesDefault,
|
||||
XattrFilter: XattrFilter{
|
||||
Entries: []XattrFilterEntry{},
|
||||
MaxSingleEntrySize: 1024,
|
||||
@@ -1453,11 +1453,10 @@ func TestReceiveEncryptedFolderFixed(t *testing.T) {
|
||||
cfg := Configuration{
|
||||
Folders: []FolderConfiguration{
|
||||
{
|
||||
ID: "foo",
|
||||
Path: "testdata",
|
||||
Type: FolderTypeReceiveEncrypted,
|
||||
DisableTempIndexes: false,
|
||||
IgnorePerms: false,
|
||||
ID: "foo",
|
||||
Path: "testdata",
|
||||
Type: FolderTypeReceiveEncrypted,
|
||||
IgnorePerms: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1468,9 +1467,6 @@ func TestReceiveEncryptedFolderFixed(t *testing.T) {
|
||||
t.Fatal("Expected one folder")
|
||||
}
|
||||
f := cfg.Folders[0]
|
||||
if !f.DisableTempIndexes {
|
||||
t.Error("DisableTempIndexes should be true")
|
||||
}
|
||||
if !f.IgnorePerms {
|
||||
t.Error("IgnorePerms should be true")
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ var (
|
||||
const (
|
||||
DefaultMarkerName = ".stfolder"
|
||||
EncryptionTokenName = "syncthing-encryption_password_token" //nolint: gosec
|
||||
maxConcurrentWritesDefault = 2
|
||||
maxConcurrentWritesLimit = 64
|
||||
maxConcurrentWritesDefault = 16
|
||||
maxConcurrentWritesLimit = 256
|
||||
)
|
||||
|
||||
type FolderDeviceConfiguration struct {
|
||||
@@ -71,12 +71,11 @@ type FolderConfiguration struct {
|
||||
PullerDelayS float64 `json:"pullerDelayS" xml:"pullerDelayS" default:"1"`
|
||||
MaxConflicts int `json:"maxConflicts" xml:"maxConflicts" default:"10"`
|
||||
DisableSparseFiles bool `json:"disableSparseFiles" xml:"disableSparseFiles"`
|
||||
DisableTempIndexes bool `json:"disableTempIndexes" xml:"disableTempIndexes"`
|
||||
Paused bool `json:"paused" xml:"paused"`
|
||||
MarkerName string `json:"markerName" xml:"markerName"`
|
||||
CopyOwnershipFromParent bool `json:"copyOwnershipFromParent" xml:"copyOwnershipFromParent"`
|
||||
RawModTimeWindowS int `json:"modTimeWindowS" xml:"modTimeWindowS"`
|
||||
MaxConcurrentWrites int `json:"maxConcurrentWrites" xml:"maxConcurrentWrites" default:"2"`
|
||||
MaxConcurrentWrites int `json:"maxConcurrentWrites" xml:"maxConcurrentWrites" default:"0"`
|
||||
DisableFsync bool `json:"disableFsync" xml:"disableFsync"`
|
||||
BlockPullOrder BlockPullOrder `json:"blockPullOrder" xml:"blockPullOrder"`
|
||||
CopyRangeMethod CopyRangeMethod `json:"copyRangeMethod" xml:"copyRangeMethod" default:"standard"`
|
||||
@@ -322,7 +321,6 @@ func (f *FolderConfiguration) prepare(myID protocol.DeviceID, existingDevices ma
|
||||
}
|
||||
|
||||
if f.Type == FolderTypeReceiveEncrypted {
|
||||
f.DisableTempIndexes = true
|
||||
f.IgnorePerms = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,15 @@
|
||||
|
||||
package config
|
||||
|
||||
type FolderType int32
|
||||
import "github.com/syncthing/syncthing/lib/protocol"
|
||||
|
||||
type FolderType protocol.FolderType
|
||||
|
||||
const (
|
||||
FolderTypeSendReceive FolderType = 0
|
||||
FolderTypeSendOnly FolderType = 1
|
||||
FolderTypeReceiveOnly FolderType = 2
|
||||
FolderTypeReceiveEncrypted FolderType = 3
|
||||
FolderTypeSendReceive = FolderType(protocol.FolderTypeSendReceive)
|
||||
FolderTypeSendOnly = FolderType(protocol.FolderTypeSendOnly)
|
||||
FolderTypeReceiveOnly = FolderType(protocol.FolderTypeReceiveOnly)
|
||||
FolderTypeReceiveEncrypted = FolderType(protocol.FolderTypeReceiveEncrypted)
|
||||
)
|
||||
|
||||
func (t FolderType) String() string {
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
// put the newest on top for readability.
|
||||
var (
|
||||
migrations = migrationSet{
|
||||
{51, migrateToConfigV51},
|
||||
{50, migrateToConfigV50},
|
||||
{37, migrateToConfigV37},
|
||||
{36, migrateToConfigV36},
|
||||
@@ -98,6 +99,18 @@ func (m migration) apply(cfg *Configuration) {
|
||||
cfg.Version = m.targetVersion
|
||||
}
|
||||
|
||||
func migrateToConfigV51(cfg *Configuration) {
|
||||
oldDefault := 2
|
||||
for i, fcfg := range cfg.Folders {
|
||||
if fcfg.MaxConcurrentWrites == oldDefault {
|
||||
cfg.Folders[i].MaxConcurrentWrites = maxConcurrentWritesDefault
|
||||
}
|
||||
}
|
||||
if cfg.Defaults.Folder.MaxConcurrentWrites == oldDefault {
|
||||
cfg.Defaults.Folder.MaxConcurrentWrites = maxConcurrentWritesDefault
|
||||
}
|
||||
}
|
||||
|
||||
func migrateToConfigV50(cfg *Configuration) {
|
||||
// v50 is Syncthing 2.0
|
||||
}
|
||||
|
||||
@@ -49,9 +49,11 @@ type quicListener struct {
|
||||
registry *registry.Registry
|
||||
lanChecker *lanChecker
|
||||
|
||||
address *url.URL
|
||||
laddr net.Addr
|
||||
mut sync.Mutex
|
||||
address *url.URL
|
||||
natService *nat.Service
|
||||
mapping *nat.Mapping
|
||||
laddr net.Addr
|
||||
mut sync.Mutex
|
||||
}
|
||||
|
||||
func (t *quicListener) OnNATTypeChanged(natType stun.NATType) {
|
||||
@@ -126,7 +128,24 @@ func (t *quicListener) serve(ctx context.Context) error {
|
||||
l.Infof("QUIC listener (%v) starting", udpConn.LocalAddr())
|
||||
defer l.Infof("QUIC listener (%v) shutting down", udpConn.LocalAddr())
|
||||
|
||||
var ipVersion nat.IPVersion
|
||||
switch t.uri.Scheme {
|
||||
case "quic4":
|
||||
ipVersion = nat.IPv4Only
|
||||
case "quic6":
|
||||
ipVersion = nat.IPv6Only
|
||||
default:
|
||||
ipVersion = nat.IPvAny
|
||||
}
|
||||
mapping := t.natService.NewMapping(nat.UDP, ipVersion, udpAddr.IP, udpAddr.Port)
|
||||
mapping.OnChanged(func() {
|
||||
t.notifyAddressesChanged(t)
|
||||
})
|
||||
// Should be called after t.mapping is nil'ed out.
|
||||
defer t.natService.RemoveMapping(mapping)
|
||||
|
||||
t.mut.Lock()
|
||||
t.mapping = mapping
|
||||
t.laddr = udpConn.LocalAddr()
|
||||
t.mut.Unlock()
|
||||
defer func() {
|
||||
@@ -196,6 +215,9 @@ func (t *quicListener) WANAddresses() []*url.URL {
|
||||
if t.address != nil {
|
||||
uris = append(uris, t.address)
|
||||
}
|
||||
|
||||
uris = append(uris, portMappingURIs(t.mapping, *t.uri)...)
|
||||
|
||||
t.mut.Unlock()
|
||||
return uris
|
||||
}
|
||||
@@ -232,12 +254,13 @@ func (*quicListenerFactory) Valid(config.Configuration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *quicListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, _ *nat.Service, registry *registry.Registry, lanChecker *lanChecker) genericListener {
|
||||
func (f *quicListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service, registry *registry.Registry, lanChecker *lanChecker) genericListener {
|
||||
l := &quicListener{
|
||||
uri: fixupPort(uri, config.DefaultQUICPort),
|
||||
cfg: cfg,
|
||||
tlsCfg: tlsCfg,
|
||||
conns: conns,
|
||||
natService: natService,
|
||||
factory: f,
|
||||
registry: registry,
|
||||
lanChecker: lanChecker,
|
||||
|
||||
@@ -175,24 +175,9 @@ func (t *tcpListener) WANAddresses() []*url.URL {
|
||||
uris := []*url.URL{
|
||||
maybeReplacePort(t.uri, t.laddr),
|
||||
}
|
||||
if t.mapping != nil {
|
||||
addrs := t.mapping.ExternalAddresses()
|
||||
for _, addr := range addrs {
|
||||
uri := *t.uri
|
||||
// Does net.JoinHostPort internally
|
||||
uri.Host = addr.String()
|
||||
uris = append(uris, &uri)
|
||||
|
||||
// For every address with a specified IP, add one without an IP,
|
||||
// just in case the specified IP is still internal (router behind DMZ).
|
||||
if len(addr.IP) != 0 && !addr.IP.IsUnspecified() {
|
||||
zeroUri := *t.uri
|
||||
addr.IP = nil
|
||||
zeroUri.Host = addr.String()
|
||||
uris = append(uris, &zeroUri)
|
||||
}
|
||||
}
|
||||
}
|
||||
uris = append(uris, portMappingURIs(t.mapping, *t.uri)...)
|
||||
|
||||
t.mut.RUnlock()
|
||||
|
||||
// If we support ReusePort, add an unspecified zero port address, which will be resolved by the discovery server
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/nat"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
)
|
||||
|
||||
@@ -130,3 +131,27 @@ func maybeReplacePort(uri *url.URL, laddr net.Addr) *url.URL {
|
||||
uriCopy.Host = net.JoinHostPort(host, lportStr)
|
||||
return &uriCopy
|
||||
}
|
||||
|
||||
func portMappingURIs(mapping *nat.Mapping, listener_uri url.URL) []*url.URL {
|
||||
var uris []*url.URL
|
||||
if mapping != nil {
|
||||
addrs := mapping.ExternalAddresses()
|
||||
for _, addr := range addrs {
|
||||
uri := listener_uri
|
||||
// Does net.JoinHostPort internally
|
||||
uri.Host = addr.String()
|
||||
uris = append(uris, &uri)
|
||||
|
||||
// For every address with a specified IP, add one without an IP,
|
||||
// just in case the specified IP is still internal (router behind DMZ).
|
||||
if len(addr.IP) != 0 && !addr.IP.IsUnspecified() {
|
||||
zeroUri := listener_uri
|
||||
addr.IP = nil
|
||||
zeroUri.Host = addr.String()
|
||||
uris = append(uris, &zeroUri)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uris
|
||||
}
|
||||
|
||||
+4
-4
@@ -379,12 +379,12 @@ func longFilenameSupport(path string) string {
|
||||
return path
|
||||
}
|
||||
|
||||
type ErrWatchEventOutsideRoot struct{ msg string }
|
||||
type WatchEventOutsideRootError struct{ msg string }
|
||||
|
||||
func (e *ErrWatchEventOutsideRoot) Error() string {
|
||||
func (e *WatchEventOutsideRootError) Error() string {
|
||||
return e.msg
|
||||
}
|
||||
|
||||
func (f *BasicFilesystem) newErrWatchEventOutsideRoot(absPath string, roots []string) *ErrWatchEventOutsideRoot {
|
||||
return &ErrWatchEventOutsideRoot{fmt.Sprintf("Watching for changes encountered an event outside of the filesystem root: f.root==%v, roots==%v, path==%v. This should never happen, please report this message to forum.syncthing.net.", f.root, roots, absPath)}
|
||||
func (f *BasicFilesystem) newErrWatchEventOutsideRoot(absPath string, roots []string) *WatchEventOutsideRootError {
|
||||
return &WatchEventOutsideRootError{fmt.Sprintf("Watching for changes encountered an event outside of the filesystem root: f.root==%v, roots==%v, path==%v. This should never happen, please report this message to forum.syncthing.net.", f.root, roots, absPath)}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
func (fi basicFileInfo) InodeChangeTime() time.Time {
|
||||
if sys, ok := fi.FileInfo.Sys().(*syscall.Stat_t); ok {
|
||||
if sys, ok := fi.Sys().(*syscall.Stat_t); ok {
|
||||
return time.Unix(0, sys.Ctimespec.Nano())
|
||||
}
|
||||
return time.Time{}
|
||||
|
||||
@@ -86,7 +86,7 @@ func (f *BasicFilesystem) Remove(name string) error {
|
||||
// unrooted) or an error if the given path is not a subpath and handles the
|
||||
// special case when the given path is the folder root without a trailing
|
||||
// pathseparator.
|
||||
func (f *BasicFilesystem) unrootedChecked(absPath string, roots []string) (string, *ErrWatchEventOutsideRoot) {
|
||||
func (f *BasicFilesystem) unrootedChecked(absPath string, roots []string) (string, *WatchEventOutsideRootError) {
|
||||
for _, root := range roots {
|
||||
// Make sure the root ends with precisely one path separator, to
|
||||
// ease prefix comparisons.
|
||||
|
||||
@@ -69,7 +69,7 @@ var xattrBufPool = sync.Pool{
|
||||
}
|
||||
|
||||
func getXattr(path, name string) ([]byte, error) {
|
||||
buf := xattrBufPool.Get().([]byte)
|
||||
buf := xattrBufPool.Get().([]byte) //nolint:forcetypeassert
|
||||
defer func() {
|
||||
// Put the buffer back in the pool, or not if we're not supposed to
|
||||
// (we returned it to the caller).
|
||||
|
||||
+5
-5
@@ -24,16 +24,16 @@ const (
|
||||
caseCacheItemLimit = 4 << 10
|
||||
)
|
||||
|
||||
type ErrCaseConflict struct {
|
||||
type CaseConflictError struct {
|
||||
Given, Real string
|
||||
}
|
||||
|
||||
func (e *ErrCaseConflict) Error() string {
|
||||
func (e *CaseConflictError) Error() string {
|
||||
return fmt.Sprintf(`remote "%v" uses different upper or lowercase characters than local "%v"; change the casing on either side to match the other`, e.Given, e.Real)
|
||||
}
|
||||
|
||||
func IsErrCaseConflict(err error) bool {
|
||||
e := &ErrCaseConflict{}
|
||||
e := &CaseConflictError{}
|
||||
return errors.As(err, &e)
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ func (f *caseFilesystem) Rename(oldpath, newpath string) error {
|
||||
}
|
||||
if err := f.checkCase(newpath); err != nil {
|
||||
// Case-only rename is ok
|
||||
e := &ErrCaseConflict{}
|
||||
e := &CaseConflictError{}
|
||||
if !errors.As(err, &e) || e.Real != oldpath {
|
||||
return err
|
||||
}
|
||||
@@ -389,7 +389,7 @@ func (f *caseFilesystem) checkCaseExisting(name string) error {
|
||||
// comparing, as we don't want to treat a normalization difference as a
|
||||
// case conflict.
|
||||
if norm.NFC.String(realName) != norm.NFC.String(name) {
|
||||
return &ErrCaseConflict{name, realName}
|
||||
return &CaseConflictError{name, realName}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+12
-10
@@ -147,29 +147,29 @@ func newFakeFilesystem(rootURI string, _ ...Option) *fakeFS {
|
||||
// *look* like file I/O, but they are not. Do not worry that they
|
||||
// might fail.
|
||||
|
||||
rng := rand.New(rand.NewSource(int64(seed)))
|
||||
rng := rand.New(rand.NewSource(int64(seed))) //nolint:gosec
|
||||
var createdFiles int
|
||||
var writtenData int64
|
||||
for (files == 0 || createdFiles < files) && (maxsize == 0 || writtenData>>20 < int64(maxsize)) {
|
||||
dir := filepath.Join(fmt.Sprintf("%02x", rng.Intn(255)), fmt.Sprintf("%02x", rng.Intn(255)))
|
||||
file := fmt.Sprintf("%016x", rng.Int63())
|
||||
fs.MkdirAll(dir, 0o755)
|
||||
_ = fs.MkdirAll(dir, 0o755)
|
||||
|
||||
fd, _ := fs.Create(filepath.Join(dir, file))
|
||||
createdFiles++
|
||||
|
||||
fsize := int64(sizeavg/2 + rng.Intn(sizeavg))
|
||||
fd.Truncate(fsize)
|
||||
_ = fd.Truncate(fsize)
|
||||
writtenData += fsize
|
||||
|
||||
ftime := time.Unix(1000000000+rng.Int63n(10*365*86400), 0)
|
||||
fs.Chtimes(filepath.Join(dir, file), ftime, ftime)
|
||||
_ = fs.Chtimes(filepath.Join(dir, file), ftime, ftime)
|
||||
}
|
||||
}
|
||||
|
||||
if !nostfolder {
|
||||
// Also create a default folder marker for good measure
|
||||
fs.Mkdir(".stfolder", 0o700)
|
||||
_ = fs.Mkdir(".stfolder", 0o700)
|
||||
}
|
||||
|
||||
// We only set the latency after doing the operations required to create
|
||||
@@ -284,9 +284,10 @@ func (fs *fakeFS) create(name string) (*fakeEntry, error) {
|
||||
time.Sleep(fs.latency)
|
||||
|
||||
if entry := fs.entryForName(name); entry != nil {
|
||||
if entry.entryType == fakeEntryTypeDir {
|
||||
switch entry.entryType {
|
||||
case fakeEntryTypeDir:
|
||||
return nil, os.ErrExist
|
||||
} else if entry.entryType == fakeEntryTypeSymlink {
|
||||
case fakeEntryTypeSymlink:
|
||||
return nil, errors.New("following symlink not supported")
|
||||
}
|
||||
entry.size = 0
|
||||
@@ -731,6 +732,7 @@ func (fs *fakeFS) resetCounters() {
|
||||
}
|
||||
|
||||
func (fs *fakeFS) reportMetricsPerOp(b *testing.B) {
|
||||
b.Helper()
|
||||
fs.reportMetricsPer(b, 1, "op")
|
||||
}
|
||||
|
||||
@@ -829,7 +831,7 @@ func (f *fakeFile) readShortAt(p []byte, offs int64) (int, error) {
|
||||
if f.seed == 0 {
|
||||
hf := fnv.New64()
|
||||
hf.Write([]byte(f.name))
|
||||
f.seed = int64(hf.Sum64())
|
||||
f.seed = int64(hf.Sum64()) //nolint:gosec
|
||||
}
|
||||
|
||||
// Check whether the read is a continuation of an RNG we already have or
|
||||
@@ -839,14 +841,14 @@ func (f *fakeFile) readShortAt(p []byte, offs int64) (int, error) {
|
||||
nextBlockOffs := (seedNo + 1) << randomBlockShift
|
||||
if f.rng == nil || f.offset != offs || seedNo != f.seedOffs {
|
||||
// This is not a straight read continuing from a previous one
|
||||
f.rng = rand.New(rand.NewSource(f.seed + seedNo))
|
||||
f.rng = rand.New(rand.NewSource(f.seed + seedNo)) //nolint:gosec
|
||||
|
||||
// If the read is not at the start of the block, discard data
|
||||
// accordingly.
|
||||
diff := offs - minOffs
|
||||
if diff > 0 {
|
||||
lr := io.LimitReader(f.rng, diff)
|
||||
io.Copy(io.Discard, lr)
|
||||
_, _ = io.Copy(io.Discard, lr)
|
||||
}
|
||||
|
||||
f.offset = offs
|
||||
|
||||
@@ -180,7 +180,7 @@ const (
|
||||
// SkipDir is used as a return value from WalkFuncs to indicate that
|
||||
// the directory named in the call is to be skipped. It is not returned
|
||||
// as an error by any function.
|
||||
var SkipDir = filepath.SkipDir
|
||||
var SkipDir = filepath.SkipDir //nolint:errname
|
||||
|
||||
func IsExist(err error) bool {
|
||||
return errors.Is(err, ErrExist)
|
||||
@@ -259,15 +259,16 @@ func NewFilesystem(fsType FilesystemType, uri string, opts ...Option) Filesystem
|
||||
// attributed to the calling function.
|
||||
layersAboveWalkFilesystem++
|
||||
}
|
||||
if l.ShouldDebug("walkfs") {
|
||||
switch {
|
||||
case l.ShouldDebug("walkfs"):
|
||||
// A walkFilesystem is not a layer to skip, it embeds the underlying
|
||||
// filesystem, passing calls directly trough. Except for calls made
|
||||
// during walking, however those are truly originating in the walk
|
||||
// filesystem.
|
||||
fs = NewWalkFilesystem(newLogFilesystem(fs, layersAboveWalkFilesystem))
|
||||
} else if l.ShouldDebug("fs") {
|
||||
case l.ShouldDebug("fs"):
|
||||
fs = newLogFilesystem(NewWalkFilesystem(fs), layersAboveWalkFilesystem)
|
||||
} else {
|
||||
default:
|
||||
fs = NewWalkFilesystem(fs)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
@@ -28,7 +29,7 @@ func copyRangeStandard(src, dst File, srcOffset, dstOffset, size int64) error {
|
||||
}
|
||||
n, err := src.ReadAt(buf, srcOffset)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return err
|
||||
|
||||
@@ -8,6 +8,7 @@ package fs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
@@ -329,7 +330,7 @@ func TestCopyRange(tttt *testing.T) {
|
||||
t.Fatal("dst file is not a basic file")
|
||||
}
|
||||
if err := impl(srcBasic, dstBasic, testCase.srcOffset, testCase.dstOffset, testCase.copySize); err != nil {
|
||||
if err == syscall.ENOTSUP {
|
||||
if errors.Is(err, errors.ErrUnsupported) {
|
||||
// Test runner can adjust directory in which to run the tests, that allow broader tests.
|
||||
t.Skip("Not supported on the current filesystem, set STFSTESTPATH env var.")
|
||||
}
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ func (*optionMtime) String() string {
|
||||
|
||||
func (f *mtimeFS) Chtimes(name string, atime, mtime time.Time) error {
|
||||
// Do a normal Chtimes call, don't care if it succeeds or not.
|
||||
f.chtimes(name, atime, mtime)
|
||||
_ = f.chtimes(name, atime, mtime)
|
||||
|
||||
// Stat the file to see what happened. Here we *do* return an error,
|
||||
// because it might be "does not exist" or similar.
|
||||
|
||||
+4
-2
@@ -26,8 +26,10 @@ type Option interface {
|
||||
type FilesystemFactory func(string, ...Option) (Filesystem, error)
|
||||
|
||||
// For each registered file system type, a function to construct a file system.
|
||||
var filesystemFactories map[FilesystemType]FilesystemFactory = make(map[FilesystemType]FilesystemFactory)
|
||||
var filesystemFactoriesMutex sync.Mutex = sync.Mutex{}
|
||||
var (
|
||||
filesystemFactories map[FilesystemType]FilesystemFactory = make(map[FilesystemType]FilesystemFactory)
|
||||
filesystemFactoriesMutex sync.Mutex = sync.Mutex{}
|
||||
)
|
||||
|
||||
// Register a function to be called when a filesystem is to be constructed with
|
||||
// the specified fsType. The function will receive the URI for the file system as well
|
||||
|
||||
+1
-1
@@ -192,7 +192,7 @@ func CommonPrefix(first, second string) string {
|
||||
}
|
||||
|
||||
common := make([]string, 0, count)
|
||||
for i := 0; i < count; i++ {
|
||||
for i := range count {
|
||||
if firstParts[i] != secondParts[i] {
|
||||
break
|
||||
}
|
||||
|
||||
+3
-3
@@ -89,7 +89,7 @@ func (f *walkFilesystem) walk(path string, info FileInfo, walkFn WalkFunc, ances
|
||||
|
||||
err = walkFn(path, info, nil)
|
||||
if err != nil {
|
||||
if info.IsDir() && err == SkipDir {
|
||||
if info.IsDir() && errors.Is(err, SkipDir) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -117,13 +117,13 @@ func (f *walkFilesystem) walk(path string, info FileInfo, walkFn WalkFunc, ances
|
||||
filename := filepath.Join(path, name)
|
||||
fileInfo, err := f.Lstat(filename)
|
||||
if err != nil {
|
||||
if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir {
|
||||
if err := walkFn(filename, fileInfo, err); err != nil && !errors.Is(err, SkipDir) {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = f.walk(filename, fileInfo, walkFn, ancestors)
|
||||
if err != nil {
|
||||
if !fileInfo.IsDir() || err != SkipDir {
|
||||
if !fileInfo.IsDir() || !errors.Is(err, SkipDir) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ type standardBlockPullReorderer struct {
|
||||
}
|
||||
|
||||
func newStandardBlockPullReorderer(id protocol.DeviceID, otherDevices []protocol.DeviceID) *standardBlockPullReorderer {
|
||||
allDevices := append(otherDevices, id)
|
||||
allDevices := append(otherDevices, id) //nolint:gocritic
|
||||
slices.SortFunc(allDevices, func(a, b protocol.DeviceID) int {
|
||||
return a.Compare(b)
|
||||
})
|
||||
@@ -92,7 +92,7 @@ func (p *standardBlockPullReorderer) Reorder(blocks []protocol.BlockInfo) []prot
|
||||
// The rest of the chunks we fetch in a random order in whole chunks.
|
||||
// Generate chunk index slice and shuffle it
|
||||
indexes := make([]int, 0, len(chunks)-1)
|
||||
for i := range len(chunks) {
|
||||
for i := range chunks {
|
||||
if i != p.myIndex {
|
||||
indexes = append(indexes, i)
|
||||
}
|
||||
|
||||
@@ -56,17 +56,18 @@ func (p *deviceFolderDownloadState) Update(updates []protocol.FileDownloadProgre
|
||||
if update.UpdateType == protocol.FileDownloadProgressUpdateTypeForget && ok && local.version.Equal(update.Version) {
|
||||
delete(p.files, update.Name)
|
||||
} else if update.UpdateType == protocol.FileDownloadProgressUpdateTypeAppend {
|
||||
if !ok {
|
||||
switch {
|
||||
case !ok:
|
||||
local = deviceFolderFileDownloadState{
|
||||
blockIndexes: update.BlockIndexes,
|
||||
version: update.Version,
|
||||
blockSize: update.BlockSize,
|
||||
}
|
||||
} else if !local.version.Equal(update.Version) {
|
||||
case !local.version.Equal(update.Version):
|
||||
local.blockIndexes = append(local.blockIndexes[:0], update.BlockIndexes...)
|
||||
local.version = update.Version
|
||||
local.blockSize = update.BlockSize
|
||||
} else {
|
||||
default:
|
||||
local.blockIndexes = append(local.blockIndexes, update.BlockIndexes...)
|
||||
}
|
||||
p.files[update.Name] = local
|
||||
|
||||
@@ -74,7 +74,7 @@ func (f *fakeConnection) DownloadProgress(_ context.Context, dp *protocol.Downlo
|
||||
})
|
||||
}
|
||||
|
||||
func (f *fakeConnection) addFileLocked(name string, flags uint32, ftype protocol.FileInfoType, data []byte, version protocol.Vector, localFlags uint32) {
|
||||
func (f *fakeConnection) addFileLocked(name string, flags uint32, ftype protocol.FileInfoType, data []byte, version protocol.Vector, localFlags protocol.FlagLocal) {
|
||||
blockSize := protocol.BlockSize(int64(len(data)))
|
||||
blocks, _ := scanner.Blocks(context.TODO(), bytes.NewReader(data), blockSize, int64(len(data)), nil)
|
||||
|
||||
|
||||
+12
-8
@@ -44,7 +44,7 @@ type folder struct {
|
||||
*stats.FolderStatisticsReference
|
||||
ioLimiter *semaphore.Semaphore
|
||||
|
||||
localFlags uint32
|
||||
localFlags protocol.FlagLocal
|
||||
|
||||
model *model
|
||||
shortID protocol.ShortID
|
||||
@@ -52,7 +52,7 @@ type folder struct {
|
||||
ignores *ignore.Matcher
|
||||
mtimefs fs.Filesystem
|
||||
modTimeWindow time.Duration
|
||||
ctx context.Context // used internally, only accessible on serve lifetime
|
||||
ctx context.Context //nolint:containedctx // used internally, only accessible on serve lifetime
|
||||
done chan struct{} // used externally, accessible regardless of serve
|
||||
|
||||
scanInterval time.Duration
|
||||
@@ -188,8 +188,12 @@ func (f *folder) Serve(ctx context.Context) error {
|
||||
case <-f.pullScheduled:
|
||||
if f.PullerDelayS > 0 {
|
||||
// Wait for incoming updates to settle before doing the
|
||||
// actual pull
|
||||
f.setState(FolderSyncWaiting)
|
||||
// actual pull. Only set the state to SyncWaiting if we have
|
||||
// reason to believe there is something to sync, to avoid
|
||||
// unnecessary flashing in the GUI.
|
||||
if needCount, err := f.db.CountNeed(f.folderID, protocol.LocalDeviceID); err == nil && needCount.TotalItems() > 0 {
|
||||
f.setState(FolderSyncWaiting)
|
||||
}
|
||||
pullTimer.Reset(time.Duration(float64(time.Second) * f.PullerDelayS))
|
||||
} else {
|
||||
_, err = f.pull()
|
||||
@@ -322,7 +326,7 @@ func (f *folder) Reschedule() {
|
||||
return
|
||||
}
|
||||
// Sleep a random time between 3/4 and 5/4 of the configured interval.
|
||||
sleepNanos := (f.scanInterval.Nanoseconds()*3 + rand.Int63n(2*f.scanInterval.Nanoseconds())) / 4
|
||||
sleepNanos := (f.scanInterval.Nanoseconds()*3 + rand.Int63n(2*f.scanInterval.Nanoseconds())) / 4 //nolint:gosec
|
||||
interval := time.Duration(sleepNanos) * time.Nanosecond
|
||||
l.Debugln(f, "next rescan in", interval)
|
||||
f.scanTimer.Reset(interval)
|
||||
@@ -1077,7 +1081,7 @@ func (f *folder) monitorWatch(ctx context.Context) {
|
||||
f.setWatchError(err, next)
|
||||
// This error was previously a panic and should never occur, so generate
|
||||
// a warning, but don't do it repetitively.
|
||||
var errOutside *fs.ErrWatchEventOutsideRoot
|
||||
var errOutside *fs.WatchEventOutsideRootError
|
||||
if errors.As(err, &errOutside) {
|
||||
if !warnedOutside {
|
||||
l.Warnln(err)
|
||||
@@ -1111,7 +1115,7 @@ func (f *folder) setWatchError(err error, nextTryIn time.Duration) {
|
||||
prevErr := f.watchErr
|
||||
f.watchErr = err
|
||||
f.watchMut.Unlock()
|
||||
if err != prevErr {
|
||||
if err != prevErr { //nolint:errorlint
|
||||
data := map[string]interface{}{
|
||||
"folder": f.ID,
|
||||
}
|
||||
@@ -1127,7 +1131,7 @@ func (f *folder) setWatchError(err error, nextTryIn time.Duration) {
|
||||
return
|
||||
}
|
||||
msg := fmt.Sprintf("Error while trying to start filesystem watcher for folder %s, trying again in %v: %v", f.Description(), nextTryIn, err)
|
||||
if prevErr != err {
|
||||
if prevErr != err { //nolint:errorlint
|
||||
l.Infof(msg)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func newSendOnlyFolder(model *model, ignores *ignore.Matcher, cfg config.FolderC
|
||||
f := &sendOnlyFolder{
|
||||
folder: newFolder(model, ignores, cfg, evLogger, ioLimiter, nil),
|
||||
}
|
||||
f.folder.puller = f
|
||||
f.puller = f
|
||||
return f
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ func newSendReceiveFolder(model *model, ignores *ignore.Matcher, cfg config.Fold
|
||||
blockPullReorderer: newBlockPullReorderer(cfg.BlockPullOrder, model.id, cfg.DeviceIDs()),
|
||||
writeLimiter: semaphore.New(cfg.MaxConcurrentWrites),
|
||||
}
|
||||
f.folder.puller = f
|
||||
f.puller = f
|
||||
|
||||
if f.Copiers == 0 {
|
||||
f.Copiers = defaultCopiers
|
||||
@@ -359,13 +359,14 @@ loop:
|
||||
}
|
||||
|
||||
case file.IsDeleted():
|
||||
if file.IsDirectory() {
|
||||
switch {
|
||||
case file.IsDirectory():
|
||||
// Perform directory deletions at the end, as we may have
|
||||
// files to delete inside them before we get to that point.
|
||||
dirDeletions = append(dirDeletions, file)
|
||||
} else if file.IsSymlink() {
|
||||
case file.IsSymlink():
|
||||
f.deleteFile(file, dbUpdateChan, scanChan)
|
||||
} else {
|
||||
default:
|
||||
df, ok, err := f.model.sdb.GetDeviceFile(f.folderID, protocol.LocalDeviceID, file.Name)
|
||||
if err != nil {
|
||||
return changed, nil, nil, err
|
||||
@@ -895,18 +896,20 @@ func (f *sendReceiveFolder) deleteFileWithCurrent(file, cur protocol.FileInfo, h
|
||||
return
|
||||
}
|
||||
|
||||
if f.inConflict(cur.Version, file.Version) {
|
||||
// There is a conflict here, which shouldn't happen as deletions
|
||||
// always lose. Merge the version vector of the file we have
|
||||
// locally and commit it to db to resolve the conflict.
|
||||
cur.Version = cur.Version.Merge(file.Version)
|
||||
dbUpdateChan <- dbUpdateJob{cur, dbUpdateHandleFile}
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case f.inConflict(cur.Version, file.Version) && !cur.IsSymlink():
|
||||
// If the delete constitutes winning a conflict, we move the file to
|
||||
// a conflict copy instead of doing the delete
|
||||
err = f.inWritableDir(func(name string) error {
|
||||
return f.moveForConflict(name, file.ModifiedBy.String(), scanChan)
|
||||
}, cur.Name)
|
||||
|
||||
if f.versioner != nil && !cur.IsSymlink() {
|
||||
case f.versioner != nil && !cur.IsSymlink():
|
||||
// If we have a versioner, use that to move the file away
|
||||
err = f.inWritableDir(f.versioner.Archive, file.Name)
|
||||
} else {
|
||||
|
||||
default:
|
||||
// Delete the file
|
||||
err = f.inWritableDir(f.mtimefs.Remove, file.Name)
|
||||
}
|
||||
|
||||
@@ -976,7 +979,7 @@ func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, db
|
||||
}
|
||||
switch stat, serr := f.mtimefs.Lstat(target.Name); {
|
||||
case serr != nil:
|
||||
var caseErr *fs.ErrCaseConflict
|
||||
var caseErr *fs.CaseConflictError
|
||||
switch {
|
||||
case errors.As(serr, &caseErr):
|
||||
if caseErr.Real != source.Name {
|
||||
@@ -1023,7 +1026,7 @@ func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, db
|
||||
tempName := fs.TempName(target.Name)
|
||||
|
||||
if f.versioner != nil {
|
||||
err = f.CheckAvailableSpace(uint64(source.Size))
|
||||
err = f.CheckAvailableSpace(uint64(source.Size)) //nolint:gosec
|
||||
if err == nil {
|
||||
err = osutil.Copy(f.CopyRangeMethod.ToFS(), f.mtimefs, f.mtimefs, source.Name, tempName)
|
||||
if err == nil {
|
||||
@@ -1148,7 +1151,7 @@ func (f *sendReceiveFolder) reuseBlocks(blocks []protocol.BlockInfo, reused []in
|
||||
// reuse.
|
||||
tempBlocks, err := scanner.HashFile(f.ctx, f.ID, f.mtimefs, tempName, file.BlockSize(), nil)
|
||||
if err != nil {
|
||||
var caseErr *fs.ErrCaseConflict
|
||||
var caseErr *fs.CaseConflictError
|
||||
if errors.As(err, &caseErr) {
|
||||
if rerr := f.mtimefs.Rename(caseErr.Real, tempName); rerr == nil {
|
||||
tempBlocks, err = scanner.HashFile(f.ctx, f.ID, f.mtimefs, tempName, file.BlockSize(), nil)
|
||||
@@ -1295,7 +1298,7 @@ func (f *sendReceiveFolder) copierRoutine(in <-chan copyBlocksState, pullChan ch
|
||||
}
|
||||
|
||||
for state := range in {
|
||||
if err := f.CheckAvailableSpace(uint64(state.file.Size)); err != nil {
|
||||
if err := f.CheckAvailableSpace(uint64(state.file.Size)); err != nil { //nolint:gosec
|
||||
state.fail(err)
|
||||
// Nothing more to do for this failed file, since it would use to much disk space
|
||||
out <- state.sharedPullerState
|
||||
@@ -1461,7 +1464,7 @@ func (f *sendReceiveFolder) copyBlockFromFile(srcName string, srcOffset int64, s
|
||||
}
|
||||
|
||||
func (*sendReceiveFolder) verifyBuffer(buf []byte, block protocol.BlockInfo) error {
|
||||
if len(buf) != int(block.Size) {
|
||||
if len(buf) != block.Size {
|
||||
return fmt.Errorf("length mismatch %d != %d", len(buf), block.Size)
|
||||
}
|
||||
|
||||
@@ -1489,8 +1492,7 @@ func (f *sendReceiveFolder) pullerRoutine(in <-chan pullBlockState, out chan<- *
|
||||
// ongoing at any given time, based on the size of the blocks
|
||||
// themselves.
|
||||
|
||||
state := state
|
||||
bytes := int(state.block.Size)
|
||||
bytes := state.block.Size
|
||||
|
||||
if err := requestLimiter.TakeWithContext(f.ctx, bytes); err != nil {
|
||||
state.fail(err)
|
||||
@@ -1713,7 +1715,7 @@ func (f *sendReceiveFolder) dbUpdaterRoutine(dbUpdateChan <-chan dbUpdateJob) {
|
||||
// sync directories
|
||||
for dir := range changedDirs {
|
||||
delete(changedDirs, dir)
|
||||
if !f.FolderConfiguration.DisableFsync {
|
||||
if !f.DisableFsync {
|
||||
fd, err := f.mtimefs.Open(dir)
|
||||
if err != nil {
|
||||
l.Debugf("fsync %q failed: %v", dir, err)
|
||||
@@ -1996,7 +1998,7 @@ func (f *sendReceiveFolder) deleteDirOnDiskHandleChildren(dir string, scanChan c
|
||||
// Lets just assume the file has changed.
|
||||
scanChan <- path
|
||||
hasToBeScanned = true
|
||||
return nil
|
||||
return nil //nolint:nilerr
|
||||
}
|
||||
if !cf.IsEquivalentOptional(diskFile, protocol.FileInfoComparison{
|
||||
ModTimeWindow: f.modTimeWindow,
|
||||
@@ -2055,7 +2057,7 @@ func (f *sendReceiveFolder) deleteDirOnDiskHandleChildren(dir string, scanChan c
|
||||
// not changed.
|
||||
func (f *sendReceiveFolder) scanIfItemChanged(name string, stat fs.FileInfo, item protocol.FileInfo, hasItem bool, fromDelete bool, scanChan chan<- string) (err error) {
|
||||
defer func() {
|
||||
if err == errModified {
|
||||
if errors.Is(err, errModified) {
|
||||
scanChan <- name
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -1014,7 +1014,7 @@ func TestPullCaseOnlyPerformFinish(t *testing.T) {
|
||||
default:
|
||||
}
|
||||
|
||||
var caseErr *fs.ErrCaseConflict
|
||||
var caseErr *fs.CaseConflictError
|
||||
if !errors.As(err, &caseErr) {
|
||||
t.Error("Expected case conflict error, got", err)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -125,7 +126,7 @@ func (c *folderSummaryService) Summary(folder string) (*FolderSummary, error) {
|
||||
var local, global, need, ro db.Counts
|
||||
var ourSeq int64
|
||||
var remoteSeq map[protocol.DeviceID]int64
|
||||
errors, err := c.model.FolderErrors(folder)
|
||||
errs, err := c.model.FolderErrors(folder)
|
||||
if err == nil {
|
||||
global, _ = c.model.GlobalSize(folder)
|
||||
local, _ = c.model.LocalSize(folder, protocol.LocalDeviceID)
|
||||
@@ -137,12 +138,12 @@ func (c *folderSummaryService) Summary(folder string) (*FolderSummary, error) {
|
||||
// For API backwards compatibility (SyncTrayzor needs it) an empty folder
|
||||
// summary is returned for not running folders, an error might actually be
|
||||
// more appropriate
|
||||
if err != nil && err != ErrFolderPaused && err != ErrFolderNotRunning {
|
||||
if err != nil && !errors.Is(err, ErrFolderPaused) && !errors.Is(err, ErrFolderNotRunning) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res.Errors = len(errors)
|
||||
res.PullErrors = len(errors) // deprecated
|
||||
res.Errors = len(errs)
|
||||
res.PullErrors = len(errs) // deprecated
|
||||
|
||||
res.Invalid = "" // Deprecated, retains external API for now
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ func newIndexHandler(conn protocol.Connection, downloads *deviceDownloadState, f
|
||||
// about us. Lets check to see if we can start sending index
|
||||
// updates directly or need to send the index from start...
|
||||
|
||||
if startInfo.local.IndexID == myIndexID {
|
||||
switch startInfo.local.IndexID {
|
||||
case myIndexID:
|
||||
// They say they've seen our index ID before, so we can
|
||||
// send a delta update only.
|
||||
|
||||
@@ -83,15 +84,17 @@ func newIndexHandler(conn protocol.Connection, downloads *deviceDownloadState, f
|
||||
l.Debugf("Device %v folder %s is delta index compatible (mlv=%d)", conn.DeviceID().Short(), folder.Description(), startInfo.local.MaxSequence)
|
||||
startSequence = startInfo.local.MaxSequence
|
||||
}
|
||||
} else if startInfo.local.IndexID != 0 {
|
||||
|
||||
case 0:
|
||||
l.Debugf("Device %v folder %s has no index ID for us", conn.DeviceID().Short(), folder.Description())
|
||||
|
||||
default:
|
||||
// They say they've seen an index ID from us, but it's
|
||||
// not the right one. Either they are confused or we
|
||||
// must have reset our database since last talking to
|
||||
// them. We'll start with a full index transfer.
|
||||
l.Infof("Device %v folder %s has mismatching index ID for us (%v != %v)", conn.DeviceID().Short(), folder.Description(), startInfo.local.IndexID, myIndexID)
|
||||
startSequence = 0
|
||||
} else {
|
||||
l.Debugf("Device %v folder %s has no index ID for us", conn.DeviceID().Short(), folder.Description())
|
||||
}
|
||||
|
||||
// This is the other side's description of themselves. We
|
||||
@@ -418,11 +421,6 @@ func (s *indexHandler) receive(fs []protocol.FileInfo, update bool, op string, p
|
||||
"precedingSeq": fs[i-1].Sequence,
|
||||
})
|
||||
}
|
||||
|
||||
// The local attributes should never be transmitted over the wire.
|
||||
// Make sure they look like they weren't.
|
||||
fs[i].LocalFlags = 0
|
||||
fs[i].VersionHash = nil
|
||||
}
|
||||
|
||||
// Verify the claimed last sequence number
|
||||
@@ -478,22 +476,14 @@ func (s *indexHandler) logSequenceAnomaly(msg string, extra map[string]any) {
|
||||
}
|
||||
|
||||
func prepareFileInfoForIndex(f protocol.FileInfo) protocol.FileInfo {
|
||||
// Mark the file as invalid if any of the local bad stuff flags are set.
|
||||
f.RawInvalid = f.IsInvalid()
|
||||
// If the file is marked LocalReceive (i.e., changed locally on a
|
||||
// receive only folder) we do not want it to ever become the
|
||||
// globally best version, invalid or not.
|
||||
if f.IsReceiveOnlyChanged() {
|
||||
f.Version = protocol.Vector{}
|
||||
}
|
||||
// The trailer with the encrypted fileinfo is device local, don't send info
|
||||
// about that to remotes
|
||||
// The trailer with the encrypted fileinfo is device local, announce the size without it to remotes.
|
||||
f.Size -= int64(f.EncryptionTrailerSize)
|
||||
f.EncryptionTrailerSize = 0
|
||||
// never sent externally
|
||||
f.LocalFlags = 0
|
||||
f.VersionHash = nil
|
||||
f.InodeChangeNs = 0
|
||||
return f
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ var (
|
||||
Name: "folder_state",
|
||||
Help: "Current folder state",
|
||||
}, []string{"folder"})
|
||||
metricFolderSummary = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
metricFolderSummary = promauto.NewGaugeVec(prometheus.GaugeOpts{ //nolint:promlinter
|
||||
Namespace: "syncthing",
|
||||
Subsystem: "model",
|
||||
Name: "folder_summary",
|
||||
|
||||
+39
-35
@@ -195,7 +195,7 @@ var (
|
||||
ErrFolderMissing = errors.New("no such folder")
|
||||
errNoVersioner = errors.New("folder has no versioner")
|
||||
// errors about why a connection is closed
|
||||
errStopped = errors.New("Syncthing is being stopped")
|
||||
errStopped = errors.New("Syncthing is being stopped") //nolint:staticcheck
|
||||
errEncryptionInvConfigLocal = errors.New("can't encrypt outgoing data because local data is encrypted (folder-type receive-encrypted)")
|
||||
errEncryptionInvConfigRemote = errors.New("remote has encrypted data and encrypts that data for us - this is impossible")
|
||||
errEncryptionNotEncryptedLocal = errors.New("remote expects to exchange encrypted data, but is configured for plain data")
|
||||
@@ -460,6 +460,9 @@ func (m *model) warnAboutOverwritingProtectedFiles(cfg config.FolderConfiguratio
|
||||
}
|
||||
|
||||
func (m *model) removeFolder(cfg config.FolderConfiguration) {
|
||||
l.Infoln("Removing folder", cfg.Description())
|
||||
defer l.Infoln("Removed folder", cfg.Description())
|
||||
|
||||
m.mut.RLock()
|
||||
wait := m.folderRunners.StopAndWaitChan(cfg.ID, 0)
|
||||
m.mut.RUnlock()
|
||||
@@ -622,24 +625,26 @@ func (m *model) UsageReportingStats(report *contract.Report, version int, previe
|
||||
|
||||
for _, line := range lines {
|
||||
// Allow prefixes to be specified in any order, but only once.
|
||||
loop:
|
||||
for {
|
||||
if strings.HasPrefix(line, "!") && !seenPrefix[0] {
|
||||
switch {
|
||||
case strings.HasPrefix(line, "!") && !seenPrefix[0]:
|
||||
seenPrefix[0] = true
|
||||
line = line[1:]
|
||||
report.IgnoreStats.Inverts++
|
||||
} else if strings.HasPrefix(line, "(?i)") && !seenPrefix[1] {
|
||||
case strings.HasPrefix(line, "(?i)") && !seenPrefix[1]:
|
||||
seenPrefix[1] = true
|
||||
line = line[4:]
|
||||
report.IgnoreStats.Folded++
|
||||
} else if strings.HasPrefix(line, "(?d)") && !seenPrefix[2] {
|
||||
case strings.HasPrefix(line, "(?d)") && !seenPrefix[2]:
|
||||
seenPrefix[2] = true
|
||||
line = line[4:]
|
||||
report.IgnoreStats.Deletable++
|
||||
} else {
|
||||
default:
|
||||
seenPrefix[0] = false
|
||||
seenPrefix[1] = false
|
||||
seenPrefix[2] = false
|
||||
break
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1227,9 +1232,10 @@ func (m *model) ClusterConfig(conn protocol.Connection, cm *protocol.ClusterConf
|
||||
for _, folder := range cm.Folders {
|
||||
info := &clusterConfigDeviceInfo{}
|
||||
for _, dev := range folder.Devices {
|
||||
if dev.ID == m.id {
|
||||
switch dev.ID {
|
||||
case m.id:
|
||||
info.local = dev
|
||||
} else if dev.ID == deviceID {
|
||||
case deviceID:
|
||||
info.remote = dev
|
||||
}
|
||||
if info.local.ID != protocol.EmptyDeviceID && info.remote.ID != protocol.EmptyDeviceID {
|
||||
@@ -1416,7 +1422,7 @@ func (m *model) ccHandleFolders(folders []protocol.Folder, deviceCfg config.Devi
|
||||
if err := m.observed.AddOrUpdatePendingFolder(folder.ID, of, deviceID); err != nil {
|
||||
l.Warnf("Failed to persist pending folder entry to database: %v", err)
|
||||
}
|
||||
if !folder.Paused {
|
||||
if folder.IsRunning() {
|
||||
indexHandlers.AddIndexInfo(folder.ID, ccDeviceInfos[folder.ID])
|
||||
}
|
||||
updatedPending = append(updatedPending, updatedPendingFolder{
|
||||
@@ -1436,7 +1442,7 @@ func (m *model) ccHandleFolders(folders []protocol.Folder, deviceCfg config.Devi
|
||||
continue
|
||||
}
|
||||
|
||||
if folder.Paused {
|
||||
if !folder.IsRunning() {
|
||||
indexHandlers.Remove(folder.ID)
|
||||
seenFolders[cfg.ID] = remoteFolderPaused
|
||||
continue
|
||||
@@ -1451,7 +1457,7 @@ func (m *model) ccHandleFolders(folders []protocol.Folder, deviceCfg config.Devi
|
||||
sameError := false
|
||||
m.mut.Lock()
|
||||
if devs, ok := m.folderEncryptionFailures[folder.ID]; ok {
|
||||
sameError = devs[deviceID] == err
|
||||
sameError = devs[deviceID] == err //nolint:errorlint
|
||||
} else {
|
||||
m.folderEncryptionFailures[folder.ID] = make(map[protocol.DeviceID]error)
|
||||
}
|
||||
@@ -1461,7 +1467,8 @@ func (m *model) ccHandleFolders(folders []protocol.Folder, deviceCfg config.Devi
|
||||
if sameError {
|
||||
l.Debugln(msg)
|
||||
} else {
|
||||
if rerr, ok := err.(*redactedError); ok {
|
||||
var rerr *redactedError
|
||||
if errors.As(err, &rerr) {
|
||||
err = rerr.redacted
|
||||
}
|
||||
m.evLogger.Log(events.Failure, err.Error())
|
||||
@@ -1481,10 +1488,9 @@ func (m *model) ccHandleFolders(folders []protocol.Folder, deviceCfg config.Devi
|
||||
|
||||
// Handle indexes
|
||||
|
||||
if !folder.DisableTempIndexes {
|
||||
if folder.Type != protocol.FolderTypeReceiveEncrypted {
|
||||
tempIndexFolders = append(tempIndexFolders, folder.ID)
|
||||
}
|
||||
|
||||
indexHandlers.AddIndexInfo(folder.ID, ccDeviceInfos[folder.ID])
|
||||
}
|
||||
|
||||
@@ -2015,7 +2021,7 @@ func (m *model) Request(conn protocol.Connection, req *protocol.Request) (out pr
|
||||
|
||||
// The requestResponse releases the bytes to the buffer pool and the
|
||||
// limiters when its Close method is called.
|
||||
res := newLimitedRequestResponse(int(req.Size), limiter, m.globalRequestLimiter)
|
||||
res := newLimitedRequestResponse(req.Size, limiter, m.globalRequestLimiter)
|
||||
|
||||
defer func() {
|
||||
// Close it ourselves if it isn't returned due to an error
|
||||
@@ -2036,7 +2042,7 @@ func (m *model) Request(conn protocol.Connection, req *protocol.Request) (out pr
|
||||
|
||||
// Only check temp files if the flag is set, and if we are set to advertise
|
||||
// the temp indexes.
|
||||
if req.FromTemporary && !folderCfg.DisableTempIndexes {
|
||||
if req.FromTemporary {
|
||||
tempFn := fs.TempName(req.Name)
|
||||
|
||||
if info, err := folderFs.Lstat(tempFn); err != nil || !info.IsRegular() {
|
||||
@@ -2061,16 +2067,17 @@ func (m *model) Request(conn protocol.Connection, req *protocol.Request) (out pr
|
||||
}
|
||||
|
||||
n, err := readOffsetIntoBuf(folderFs, req.Name, req.Offset, res.data)
|
||||
if fs.IsNotExist(err) {
|
||||
switch {
|
||||
case fs.IsNotExist(err):
|
||||
l.Debugf("%v REQ(in) file doesn't exist: %s: %q / %q o=%d s=%d", m, deviceID.Short(), req.Folder, req.Name, req.Offset, req.Size)
|
||||
return nil, protocol.ErrNoSuchFile
|
||||
} else if err == io.EOF {
|
||||
case errors.Is(err, io.EOF):
|
||||
// Read beyond end of file. This might indicate a problem, or it
|
||||
// might be a short block that gets padded when read for encrypted
|
||||
// folders. We ignore the error and let the hash validation in the
|
||||
// next step take care of it, by only hashing the part we actually
|
||||
// managed to read.
|
||||
} else if err != nil {
|
||||
case err != nil:
|
||||
l.Debugf("%v REQ(in) failed reading file (%v): %s: %q / %q o=%d s=%d", m, err, deviceID.Short(), req.Folder, req.Name, req.Offset, req.Size)
|
||||
return nil, protocol.ErrGeneric
|
||||
}
|
||||
@@ -2230,13 +2237,13 @@ func (m *model) SetIgnores(folder string, content []string) error {
|
||||
|
||||
func (m *model) setIgnores(cfg config.FolderConfiguration, content []string) error {
|
||||
err := cfg.CheckPath()
|
||||
if err == config.ErrPathMissing {
|
||||
if errors.Is(err, config.ErrPathMissing) {
|
||||
if err = cfg.CreateRoot(); err != nil {
|
||||
return fmt.Errorf("failed to create folder root: %w", err)
|
||||
}
|
||||
err = cfg.CheckPath()
|
||||
}
|
||||
if err != nil && err != config.ErrMarkerMissing {
|
||||
if err != nil && !errors.Is(err, config.ErrMarkerMissing) {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2412,7 +2419,7 @@ func (m *model) DownloadProgress(conn protocol.Connection, p *protocol.DownloadP
|
||||
cfg, ok := m.folderCfgs[p.Folder]
|
||||
m.mut.RUnlock()
|
||||
|
||||
if !ok || cfg.DisableTempIndexes || !cfg.SharedWith(deviceID) {
|
||||
if !ok || !cfg.SharedWith(deviceID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2498,7 +2505,6 @@ func (m *model) ScanFolders() map[string]error {
|
||||
wg := sync.NewWaitGroup()
|
||||
wg.Add(len(folders))
|
||||
for _, folder := range folders {
|
||||
folder := folder
|
||||
go func() {
|
||||
err := m.ScanFolder(folder)
|
||||
if err != nil {
|
||||
@@ -2594,19 +2600,17 @@ func (m *model) generateClusterConfigRLocked(device protocol.DeviceID) (*protoco
|
||||
}
|
||||
|
||||
protocolFolder := protocol.Folder{
|
||||
ID: folderCfg.ID,
|
||||
Label: folderCfg.Label,
|
||||
ReadOnly: folderCfg.Type == config.FolderTypeSendOnly,
|
||||
IgnorePermissions: folderCfg.IgnorePerms,
|
||||
IgnoreDelete: folderCfg.IgnoreDelete,
|
||||
DisableTempIndexes: folderCfg.DisableTempIndexes,
|
||||
ID: folderCfg.ID,
|
||||
Label: folderCfg.Label,
|
||||
}
|
||||
|
||||
// Even if we aren't paused, if we haven't started the folder yet
|
||||
// pretend we are. Otherwise the remote might get confused about
|
||||
// the missing index info (and drop all the info). We will send
|
||||
// another cluster config once the folder is started.
|
||||
protocolFolder.Paused = folderCfg.Paused
|
||||
if folderCfg.Paused {
|
||||
protocolFolder.StopReason = protocol.FolderStopReasonPaused
|
||||
}
|
||||
|
||||
for _, folderDevice := range folderCfg.Devices {
|
||||
deviceCfg, _ := m.cfg.Device(folderDevice.DeviceID)
|
||||
@@ -2677,7 +2681,7 @@ func (m *model) WatchError(folder string) error {
|
||||
runner, _ := m.folderRunners.Get(folder)
|
||||
m.mut.RUnlock()
|
||||
if err != nil {
|
||||
return nil // If the folder isn't running, there's no error to report.
|
||||
return nil //nolint:nilerr // If the folder isn't running, there's no error to report.
|
||||
}
|
||||
return runner.WatchError()
|
||||
}
|
||||
@@ -2744,7 +2748,7 @@ func (m *model) GlobalDirectoryTree(folder, prefix string, levels int, dirsOnly
|
||||
prefix = osutil.NativeFilename(prefix)
|
||||
|
||||
if prefix != "" && !strings.HasSuffix(prefix, sep) {
|
||||
prefix = prefix + sep
|
||||
prefix += sep
|
||||
}
|
||||
|
||||
for f, err := range itererr.Zip(m.sdb.AllGlobalFilesPrefix(folder, prefix)) {
|
||||
@@ -2753,7 +2757,7 @@ func (m *model) GlobalDirectoryTree(folder, prefix string, levels int, dirsOnly
|
||||
}
|
||||
|
||||
// Don't include the prefix itself.
|
||||
if f.Invalid || f.Deleted || strings.HasPrefix(prefix, f.Name) {
|
||||
if f.IsInvalid() || f.Deleted || strings.HasPrefix(prefix, f.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -3456,8 +3460,8 @@ type updatedPendingFolder struct {
|
||||
// redactPathError checks if the error is actually a os.PathError, and if yes
|
||||
// returns a redactedError with the path removed.
|
||||
func redactPathError(err error) (error, bool) {
|
||||
perr, ok := err.(*os.PathError)
|
||||
if !ok {
|
||||
var perr *os.PathError
|
||||
if !errors.As(err, &perr) {
|
||||
return nil, false
|
||||
}
|
||||
return &redactedError{
|
||||
|
||||
@@ -3498,6 +3498,7 @@ func TestScanDeletedROChangedOnSR(t *testing.T) {
|
||||
}
|
||||
// A remote must have the file, otherwise the deletion below is
|
||||
// automatically resolved as not a ro-changed item.
|
||||
file.LocalFlags = 0 // clear as we're skipping the code path where it would otherwise be cleared naturally
|
||||
must(t, m.IndexUpdate(conn, &protocol.IndexUpdate{Folder: fcfg.ID, Files: []protocol.FileInfo{file}}))
|
||||
|
||||
must(t, ffs.Remove(name))
|
||||
@@ -3609,7 +3610,7 @@ func TestIssue6961(t *testing.T) {
|
||||
// Remote, valid and existing file
|
||||
must(t, m.Index(conn1, &protocol.Index{Folder: fcfg.ID, Files: []protocol.FileInfo{{Name: name, Version: version, Sequence: 1}}}))
|
||||
// Remote, invalid (receive-only) and existing file
|
||||
must(t, m.Index(conn2, &protocol.Index{Folder: fcfg.ID, Files: []protocol.FileInfo{{Name: name, RawInvalid: true, Sequence: 1}}}))
|
||||
must(t, m.Index(conn2, &protocol.Index{Folder: fcfg.ID, Files: []protocol.FileInfo{{Name: name, LocalFlags: protocol.FlagLocalRemoteInvalid, Sequence: 1}}}))
|
||||
// Create a local file
|
||||
if fd, err := tfs.OpenFile(name, fs.OptCreate, 0o666); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -3635,7 +3636,7 @@ func TestIssue6961(t *testing.T) {
|
||||
m.ScanFolders()
|
||||
|
||||
// Drop the remote index, add some other file.
|
||||
must(t, m.Index(conn2, &protocol.Index{Folder: fcfg.ID, Files: []protocol.FileInfo{{Name: "bar", RawInvalid: true, Sequence: 1}}}))
|
||||
must(t, m.Index(conn2, &protocol.Index{Folder: fcfg.ID, Files: []protocol.FileInfo{{Name: "bar", LocalFlags: protocol.FlagLocalRemoteInvalid, Sequence: 1}}}))
|
||||
|
||||
// Pause and unpause folder to create new db.FileSet and thus recalculate everything
|
||||
pauseFolder(t, wcfg, fcfg.ID, true)
|
||||
@@ -3870,7 +3871,7 @@ func TestCCFolderNotRunning(t *testing.T) {
|
||||
if local.ID != myID {
|
||||
local = folder.Devices[0]
|
||||
}
|
||||
if !folder.Paused && local.IndexID == 0 {
|
||||
if folder.StopReason != protocol.FolderStopReasonPaused && local.IndexID == 0 {
|
||||
t.Errorf("Folder isn't paused, but index-id is zero")
|
||||
}
|
||||
}
|
||||
|
||||
+21
-10
@@ -903,13 +903,24 @@ func TestRequestDeleteChanged(t *testing.T) {
|
||||
t.Fatal("timed out")
|
||||
}
|
||||
|
||||
// Check outcome
|
||||
if _, err := tfs.Lstat(a); err != nil {
|
||||
if fs.IsNotExist(err) {
|
||||
t.Error(`Modified file "a" was removed`)
|
||||
} else {
|
||||
t.Error(`Error stating file "a":`, err)
|
||||
// Check outcome. The file may have been moved to a conflict copy.
|
||||
remains := false
|
||||
files, err := tfs.Glob("a*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, file := range files {
|
||||
if file == "a" {
|
||||
remains = true
|
||||
break
|
||||
}
|
||||
if strings.HasPrefix(file, "a.sync-conflict-") {
|
||||
remains = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !remains {
|
||||
t.Error(`Modified file "a" was removed`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1118,7 +1129,7 @@ func TestRequestIndexSenderPause(t *testing.T) {
|
||||
// Remote paused
|
||||
|
||||
cc := basicClusterConfig(device1, myID, fcfg.ID)
|
||||
cc.Folders[0].Paused = true
|
||||
cc.Folders[0].StopReason = protocol.FolderStopReasonPaused
|
||||
m.ClusterConfig(fc, cc)
|
||||
|
||||
seq++
|
||||
@@ -1139,7 +1150,7 @@ func TestRequestIndexSenderPause(t *testing.T) {
|
||||
|
||||
// Remote unpaused
|
||||
|
||||
cc.Folders[0].Paused = false
|
||||
cc.Folders[0].StopReason = protocol.FolderStopReasonRunning
|
||||
m.ClusterConfig(fc, cc)
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
@@ -1164,12 +1175,12 @@ func TestRequestIndexSenderPause(t *testing.T) {
|
||||
|
||||
// Local and remote paused, then first resume remote, then local
|
||||
|
||||
cc.Folders[0].Paused = true
|
||||
cc.Folders[0].StopReason = protocol.FolderStopReasonPaused
|
||||
m.ClusterConfig(fc, cc)
|
||||
|
||||
pauseFolder(t, m.cfg, fcfg.ID, true)
|
||||
|
||||
cc.Folders[0].Paused = false
|
||||
cc.Folders[0].StopReason = protocol.FolderStopReasonRunning
|
||||
m.ClusterConfig(fc, cc)
|
||||
|
||||
pauseFolder(t, m.cfg, fcfg.ID, false)
|
||||
|
||||
@@ -384,7 +384,7 @@ func writeEncryptionTrailer(file protocol.FileInfo, writer io.WriterAt) (int64,
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
binary.BigEndian.PutUint32(bs[n:], uint32(n))
|
||||
binary.BigEndian.PutUint32(bs[n:], uint32(n)) //nolint:gosec
|
||||
bs = bs[:n+4]
|
||||
|
||||
if _, err := writer.WriteAt(bs, wireFile.Size); err != nil {
|
||||
|
||||
+6
-6
@@ -257,7 +257,7 @@ func (s *Service) verifyExistingLocked(ctx context.Context, mapping *Mapping, na
|
||||
// extAddrs either contains one IPv4 address, or possibly several
|
||||
// IPv6 addresses all using the same port. Therefore the first
|
||||
// entry always has the external port.
|
||||
responseAddrs, err := s.tryNATDevice(ctx, nat, mapping.address, extAddrs[0].Port, leaseTime)
|
||||
responseAddrs, err := s.tryNATDevice(ctx, nat, mapping.address, extAddrs[0].Port, mapping.protocol, leaseTime)
|
||||
if err != nil {
|
||||
l.Infof("Failed to renew %s -> %v open port on %s: %s", mapping, extAddrs, id, err)
|
||||
mapping.removeAddressLocked(id)
|
||||
@@ -309,7 +309,7 @@ func (s *Service) acquireNewLocked(ctx context.Context, mapping *Mapping, nats m
|
||||
continue
|
||||
}
|
||||
|
||||
addrs, err := s.tryNATDevice(ctx, nat, mapping.address, 0, leaseTime)
|
||||
addrs, err := s.tryNATDevice(ctx, nat, mapping.address, 0, mapping.protocol, leaseTime)
|
||||
if err != nil {
|
||||
l.Infof("Failed to acquire %s open port on %s: %s", mapping, id, err)
|
||||
continue
|
||||
@@ -325,14 +325,14 @@ func (s *Service) acquireNewLocked(ctx context.Context, mapping *Mapping, nats m
|
||||
|
||||
// tryNATDevice tries to acquire a port mapping for the given internal address to
|
||||
// the given external port. If external port is 0, picks a pseudo-random port.
|
||||
func (s *Service) tryNATDevice(ctx context.Context, natd Device, intAddr Address, extPort int, leaseTime time.Duration) ([]Address, error) {
|
||||
func (s *Service) tryNATDevice(ctx context.Context, natd Device, intAddr Address, extPort int, protocol Protocol, leaseTime time.Duration) ([]Address, error) {
|
||||
var err error
|
||||
var port int
|
||||
// For IPv6, we just try to create the pinhole. If it fails, nothing can be done (probably no IGDv2 support).
|
||||
// If it already exists, the relevant UPnP standard requires that the gateway recognizes this and updates the lease time.
|
||||
// Since we usually have a global unicast IPv6 address so no conflicting mappings, we just request the port we're running on
|
||||
if natd.SupportsIPVersion(IPv6Only) {
|
||||
ipaddrs, err := natd.AddPinhole(ctx, TCP, intAddr, leaseTime)
|
||||
ipaddrs, err := natd.AddPinhole(ctx, protocol, intAddr, leaseTime)
|
||||
var addrs []Address
|
||||
for _, ipaddr := range ipaddrs {
|
||||
addrs = append(addrs, Address{
|
||||
@@ -354,7 +354,7 @@ func (s *Service) tryNATDevice(ctx context.Context, natd Device, intAddr Address
|
||||
if extPort != 0 {
|
||||
// First try renewing our existing mapping, if we have one.
|
||||
name := fmt.Sprintf("syncthing-%d", extPort)
|
||||
port, err = natd.AddPortMapping(ctx, TCP, intAddr.Port, extPort, name, leaseTime)
|
||||
port, err = natd.AddPortMapping(ctx, protocol, intAddr.Port, extPort, name, leaseTime)
|
||||
if err == nil {
|
||||
extPort = port
|
||||
goto findIP
|
||||
@@ -372,7 +372,7 @@ func (s *Service) tryNATDevice(ctx context.Context, natd Device, intAddr Address
|
||||
// Then try up to ten random ports.
|
||||
extPort = 1024 + predictableRand.Intn(65535-1024)
|
||||
name := fmt.Sprintf("syncthing-%d", extPort)
|
||||
port, err = natd.AddPortMapping(ctx, TCP, intAddr.Port, extPort, name, leaseTime)
|
||||
port, err = natd.AddPortMapping(ctx, protocol, intAddr.Port, extPort, name, leaseTime)
|
||||
if err == nil {
|
||||
extPort = port
|
||||
goto findIP
|
||||
|
||||
+27
-1
@@ -6,7 +6,14 @@
|
||||
|
||||
package netutil
|
||||
|
||||
import "net/url"
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/jackpal/gateway"
|
||||
)
|
||||
|
||||
// Address constructs a URL from the given network and hostname.
|
||||
func AddressURL(network, host string) string {
|
||||
@@ -16,3 +23,22 @@ func AddressURL(network, host string) string {
|
||||
}
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// Gateway returns the IP address of the default network gateway.
|
||||
func Gateway() (ip net.IP, err error) {
|
||||
ip, err = gateway.DiscoverGateway()
|
||||
if err != nil {
|
||||
// Fails on Android 14+ due to permission denied error when reading
|
||||
// /proc/net/route. The wrapper may give a hint then because it is
|
||||
// able to discover the gateway from java code.
|
||||
if v := os.Getenv("FALLBACK_NET_GATEWAY_IPV4"); v != "" {
|
||||
ip = net.ParseIP(v)
|
||||
if ip == nil {
|
||||
return nil, fmt.Errorf("%q: invalid IP", v)
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
return ip, err
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
+7
-3
@@ -9,18 +9,22 @@ package osutil
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/wlynxg/anet"
|
||||
)
|
||||
|
||||
// GetInterfaceAddrs returns the IP networks of all interfaces that are up.
|
||||
// Point-to-point interfaces are exluded unless includePtP is true.
|
||||
func GetInterfaceAddrs(includePtP bool) ([]*net.IPNet, error) {
|
||||
intfs, err := net.Interfaces()
|
||||
intfs, err := anet.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var addrs []net.Addr
|
||||
|
||||
for _, intf := range intfs {
|
||||
for i := range intfs {
|
||||
intf := intfs[i]
|
||||
|
||||
if intf.Flags&net.FlagRunning == 0 {
|
||||
continue
|
||||
}
|
||||
@@ -29,7 +33,7 @@ func GetInterfaceAddrs(includePtP bool) ([]*net.IPNet, error) {
|
||||
// which, for our purposes, do not qualify as LANs.
|
||||
continue
|
||||
}
|
||||
intfAddrs, err := intf.Addrs()
|
||||
intfAddrs, err := anet.InterfaceAddrsByInterface(&intf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+2
-2
@@ -14,10 +14,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jackpal/gateway"
|
||||
natpmp "github.com/jackpal/go-nat-pmp"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/nat"
|
||||
"github.com/syncthing/syncthing/lib/netutil"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
)
|
||||
@@ -30,7 +30,7 @@ func Discover(ctx context.Context, renewal, timeout time.Duration) []nat.Device
|
||||
var ip net.IP
|
||||
err := svcutil.CallWithContext(ctx, func() error {
|
||||
var err error
|
||||
ip, err = gateway.DiscoverGateway()
|
||||
ip, err = netutil.Gateway()
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -12,12 +12,28 @@ import (
|
||||
"github.com/syncthing/syncthing/internal/gen/bep"
|
||||
)
|
||||
|
||||
type Compression = bep.Compression
|
||||
type Compression bep.Compression
|
||||
|
||||
const (
|
||||
CompressionMetadata = bep.Compression_COMPRESSION_METADATA
|
||||
CompressionNever = bep.Compression_COMPRESSION_NEVER
|
||||
CompressionAlways = bep.Compression_COMPRESSION_ALWAYS
|
||||
CompressionMetadata = Compression(bep.Compression_COMPRESSION_METADATA)
|
||||
CompressionNever = Compression(bep.Compression_COMPRESSION_NEVER)
|
||||
CompressionAlways = Compression(bep.Compression_COMPRESSION_ALWAYS)
|
||||
)
|
||||
|
||||
type FolderType bep.FolderType
|
||||
|
||||
const (
|
||||
FolderTypeSendReceive = FolderType(bep.FolderType_FOLDER_TYPE_SEND_RECEIVE)
|
||||
FolderTypeSendOnly = FolderType(bep.FolderType_FOLDER_TYPE_SEND_ONLY)
|
||||
FolderTypeReceiveOnly = FolderType(bep.FolderType_FOLDER_TYPE_RECEIVE_ONLY)
|
||||
FolderTypeReceiveEncrypted = FolderType(bep.FolderType_FOLDER_TYPE_RECEIVE_ENCRYPTED)
|
||||
)
|
||||
|
||||
type FolderStopReason bep.FolderStopReason
|
||||
|
||||
const (
|
||||
FolderStopReasonRunning = FolderStopReason(bep.FolderStopReason_FOLDER_STOP_REASON_RUNNING)
|
||||
FolderStopReasonPaused = FolderStopReason(bep.FolderStopReason_FOLDER_STOP_REASON_PAUSED)
|
||||
)
|
||||
|
||||
type ClusterConfig struct {
|
||||
@@ -51,14 +67,11 @@ func clusterConfigFromWire(w *bep.ClusterConfig) *ClusterConfig {
|
||||
}
|
||||
|
||||
type Folder struct {
|
||||
ID string
|
||||
Label string
|
||||
ReadOnly bool
|
||||
IgnorePermissions bool
|
||||
IgnoreDelete bool
|
||||
DisableTempIndexes bool
|
||||
Paused bool
|
||||
Devices []Device
|
||||
ID string
|
||||
Label string
|
||||
Type FolderType
|
||||
StopReason FolderStopReason
|
||||
Devices []Device
|
||||
}
|
||||
|
||||
func (f *Folder) toWire() *bep.Folder {
|
||||
@@ -67,14 +80,11 @@ func (f *Folder) toWire() *bep.Folder {
|
||||
devices[i] = d.toWire()
|
||||
}
|
||||
return &bep.Folder{
|
||||
Id: f.ID,
|
||||
Label: f.Label,
|
||||
ReadOnly: f.ReadOnly,
|
||||
IgnorePermissions: f.IgnorePermissions,
|
||||
IgnoreDelete: f.IgnoreDelete,
|
||||
DisableTempIndexes: f.DisableTempIndexes,
|
||||
Paused: f.Paused,
|
||||
Devices: devices,
|
||||
Id: f.ID,
|
||||
Label: f.Label,
|
||||
Type: bep.FolderType(f.Type),
|
||||
StopReason: bep.FolderStopReason(f.StopReason),
|
||||
Devices: devices,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,14 +94,11 @@ func folderFromWire(w *bep.Folder) Folder {
|
||||
devices[i] = deviceFromWire(d)
|
||||
}
|
||||
return Folder{
|
||||
ID: w.Id,
|
||||
Label: w.Label,
|
||||
ReadOnly: w.ReadOnly,
|
||||
IgnorePermissions: w.IgnorePermissions,
|
||||
IgnoreDelete: w.IgnoreDelete,
|
||||
DisableTempIndexes: w.DisableTempIndexes,
|
||||
Paused: w.Paused,
|
||||
Devices: devices,
|
||||
ID: w.Id,
|
||||
Label: w.Label,
|
||||
Type: FolderType(w.Type),
|
||||
StopReason: FolderStopReason(w.StopReason),
|
||||
Devices: devices,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +110,15 @@ func (f Folder) Description() string {
|
||||
return fmt.Sprintf("%q (%s)", f.Label, f.ID)
|
||||
}
|
||||
|
||||
func (f Folder) IsRunning() bool {
|
||||
switch f.StopReason {
|
||||
case FolderStopReasonPaused:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
ID DeviceID
|
||||
Name string
|
||||
@@ -121,7 +137,7 @@ func (d *Device) toWire() *bep.Device {
|
||||
Id: d.ID[:],
|
||||
Name: d.Name,
|
||||
Addresses: d.Addresses,
|
||||
Compression: d.Compression,
|
||||
Compression: bep.Compression(d.Compression),
|
||||
CertName: d.CertName,
|
||||
MaxSequence: d.MaxSequence,
|
||||
Introducer: d.Introducer,
|
||||
@@ -136,7 +152,7 @@ func deviceFromWire(w *bep.Device) Device {
|
||||
ID: DeviceID(w.Id),
|
||||
Name: w.Name,
|
||||
Addresses: w.Addresses,
|
||||
Compression: w.Compression,
|
||||
Compression: Compression(w.Compression),
|
||||
CertName: w.CertName,
|
||||
MaxSequence: w.MaxSequence,
|
||||
Introducer: w.Introducer,
|
||||
|
||||
@@ -11,32 +11,83 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/internal/gen/bep"
|
||||
"github.com/syncthing/syncthing/lib/build"
|
||||
)
|
||||
|
||||
type FlagLocal uint32
|
||||
|
||||
// FileInfo.LocalFlags flags
|
||||
const (
|
||||
FlagLocalUnsupported = 1 << 0 // 1: The kind is unsupported, e.g. symlinks on Windows
|
||||
FlagLocalIgnored = 1 << 1 // 2: Matches local ignore patterns
|
||||
FlagLocalMustRescan = 1 << 2 // 4: Doesn't match content on disk, must be rechecked fully
|
||||
FlagLocalReceiveOnly = 1 << 3 // 8: Change detected on receive only folder
|
||||
FlagLocalGlobal = 1 << 4 // 16: This is the global file version
|
||||
FlagLocalNeeded = 1 << 5 // 32: We need this file
|
||||
FlagLocalUnsupported FlagLocal = 1 << 0 // 1: The kind is unsupported, e.g. symlinks on Windows
|
||||
FlagLocalIgnored FlagLocal = 1 << 1 // 2: Matches local ignore patterns
|
||||
FlagLocalMustRescan FlagLocal = 1 << 2 // 4: Doesn't match content on disk, must be rechecked fully
|
||||
FlagLocalReceiveOnly FlagLocal = 1 << 3 // 8: Change detected on receive only folder
|
||||
FlagLocalGlobal FlagLocal = 1 << 4 // 16: This is the global file version
|
||||
FlagLocalNeeded FlagLocal = 1 << 5 // 32: We need this file
|
||||
FlagLocalRemoteInvalid FlagLocal = 1 << 6 // 64: The remote marked this as invalid
|
||||
|
||||
// Flags that should result in the Invalid bit on outgoing updates
|
||||
LocalInvalidFlags = FlagLocalUnsupported | FlagLocalIgnored | FlagLocalMustRescan | FlagLocalReceiveOnly
|
||||
// Flags that should result in the Invalid bit on outgoing updates (or had it on ingoing ones)
|
||||
LocalInvalidFlags = FlagLocalUnsupported | FlagLocalIgnored | FlagLocalMustRescan | FlagLocalReceiveOnly | FlagLocalRemoteInvalid
|
||||
|
||||
// Flags that should result in a file being in conflict with its
|
||||
// successor, due to us not having an up to date picture of its state on
|
||||
// disk.
|
||||
LocalConflictFlags = FlagLocalUnsupported | FlagLocalIgnored | FlagLocalReceiveOnly
|
||||
|
||||
LocalAllFlags = FlagLocalUnsupported | FlagLocalIgnored | FlagLocalMustRescan | FlagLocalReceiveOnly | FlagLocalGlobal | FlagLocalNeeded
|
||||
LocalAllFlags = FlagLocalUnsupported | FlagLocalIgnored | FlagLocalMustRescan | FlagLocalReceiveOnly | FlagLocalGlobal | FlagLocalNeeded | FlagLocalRemoteInvalid
|
||||
)
|
||||
|
||||
// localFlagBitNames maps flag values to characters which can be used to
|
||||
// build a permission-like bit string for easier reading.
|
||||
var localFlagBitNames = map[FlagLocal]string{
|
||||
FlagLocalUnsupported: "u",
|
||||
FlagLocalIgnored: "i",
|
||||
FlagLocalMustRescan: "r",
|
||||
FlagLocalReceiveOnly: "e",
|
||||
FlagLocalGlobal: "G",
|
||||
FlagLocalNeeded: "n",
|
||||
FlagLocalRemoteInvalid: "v",
|
||||
}
|
||||
|
||||
func (f FlagLocal) IsInvalid() bool {
|
||||
return f&LocalInvalidFlags != 0
|
||||
}
|
||||
|
||||
// HumanString returns a permission-like string representation of the flag bits
|
||||
func (f FlagLocal) HumanString() string {
|
||||
if f == 0 {
|
||||
return strings.Repeat("-", len(localFlagBitNames))
|
||||
}
|
||||
|
||||
bit := FlagLocal(1)
|
||||
var res bytes.Buffer
|
||||
var extra strings.Builder
|
||||
for f != 0 {
|
||||
if f&bit != 0 {
|
||||
if name, ok := localFlagBitNames[bit]; ok {
|
||||
res.WriteString(name)
|
||||
} else {
|
||||
fmt.Fprintf(&extra, "+0x%x", bit)
|
||||
}
|
||||
} else {
|
||||
res.WriteString("-")
|
||||
}
|
||||
f &^= bit
|
||||
bit <<= 1
|
||||
}
|
||||
if res.Len() < len(localFlagBitNames) {
|
||||
res.WriteString(strings.Repeat("-", len(localFlagBitNames)-res.Len()))
|
||||
}
|
||||
base := res.Bytes()
|
||||
slices.Reverse(base)
|
||||
return string(base) + extra.String()
|
||||
}
|
||||
|
||||
// BlockSizes is the list of valid block sizes, from min to max
|
||||
var BlockSizes []int
|
||||
|
||||
@@ -82,7 +133,9 @@ type FileInfo struct {
|
||||
// host only. It is not part of the protocol, doesn't get sent or
|
||||
// received (we make sure to zero it), nonetheless we need it on our
|
||||
// struct and to be able to serialize it to/from the database.
|
||||
LocalFlags uint32
|
||||
// It does carry the info to decide if the file is invalid, which is part of
|
||||
// the protocol.
|
||||
LocalFlags FlagLocal
|
||||
|
||||
// The version_hash is an implementation detail and not part of the wire
|
||||
// format.
|
||||
@@ -97,7 +150,6 @@ type FileInfo struct {
|
||||
EncryptionTrailerSize int
|
||||
|
||||
Deleted bool
|
||||
RawInvalid bool
|
||||
NoPermissions bool
|
||||
|
||||
truncated bool // was created from a truncated file info without blocks
|
||||
@@ -128,11 +180,11 @@ func (f *FileInfo) ToWire(withInternalFields bool) *bep.FileInfo {
|
||||
BlockSize: f.RawBlockSize,
|
||||
Platform: f.Platform.toWire(),
|
||||
Deleted: f.Deleted,
|
||||
Invalid: f.RawInvalid,
|
||||
Invalid: f.IsInvalid(),
|
||||
NoPermissions: f.NoPermissions,
|
||||
}
|
||||
if withInternalFields {
|
||||
w.LocalFlags = f.LocalFlags
|
||||
w.LocalFlags = uint32(f.LocalFlags)
|
||||
w.VersionHash = f.VersionHash
|
||||
w.InodeChangeNs = f.InodeChangeNs
|
||||
w.EncryptionTrailerSize = int32(f.EncryptionTrailerSize)
|
||||
@@ -148,15 +200,6 @@ func (f *FileInfo) WinsConflict(other FileInfo) bool {
|
||||
return !f.IsInvalid()
|
||||
}
|
||||
|
||||
// If a modification is in conflict with a delete, we pick the
|
||||
// modification.
|
||||
if !f.IsDeleted() && other.IsDeleted() {
|
||||
return true
|
||||
}
|
||||
if f.IsDeleted() && !other.IsDeleted() {
|
||||
return false
|
||||
}
|
||||
|
||||
// The one with the newer modification time wins.
|
||||
if f.ModTime().After(other.ModTime()) {
|
||||
return true
|
||||
@@ -207,6 +250,10 @@ type FileInfoWithoutBlocks interface {
|
||||
}
|
||||
|
||||
func fileInfoFromWireWithBlocks(w FileInfoWithoutBlocks, blocks []BlockInfo) FileInfo {
|
||||
var localFlags FlagLocal
|
||||
if w.GetInvalid() {
|
||||
localFlags = FlagLocalRemoteInvalid
|
||||
}
|
||||
return FileInfo{
|
||||
Name: w.GetName(),
|
||||
Size: w.GetSize(),
|
||||
@@ -224,14 +271,14 @@ func fileInfoFromWireWithBlocks(w FileInfoWithoutBlocks, blocks []BlockInfo) Fil
|
||||
RawBlockSize: w.GetBlockSize(),
|
||||
Platform: platformDataFromWire(w.GetPlatform()),
|
||||
Deleted: w.GetDeleted(),
|
||||
RawInvalid: w.GetInvalid(),
|
||||
LocalFlags: localFlags,
|
||||
NoPermissions: w.GetNoPermissions(),
|
||||
}
|
||||
}
|
||||
|
||||
func FileInfoFromDB(w *bep.FileInfo) FileInfo {
|
||||
f := FileInfoFromWire(w)
|
||||
f.LocalFlags = w.LocalFlags
|
||||
f.LocalFlags = FlagLocal(w.LocalFlags)
|
||||
f.VersionHash = w.VersionHash
|
||||
f.InodeChangeNs = w.InodeChangeNs
|
||||
f.EncryptionTrailerSize = int(w.EncryptionTrailerSize)
|
||||
@@ -240,7 +287,7 @@ func FileInfoFromDB(w *bep.FileInfo) FileInfo {
|
||||
|
||||
func FileInfoFromDBTruncated(w FileInfoWithoutBlocks) FileInfo {
|
||||
f := fileInfoFromWireWithBlocks(w, nil)
|
||||
f.LocalFlags = w.GetLocalFlags()
|
||||
f.LocalFlags = FlagLocal(w.GetLocalFlags())
|
||||
f.VersionHash = w.GetVersionHash()
|
||||
f.InodeChangeNs = w.GetInodeChangeNs()
|
||||
f.EncryptionTrailerSize = int(w.GetEncryptionTrailerSize())
|
||||
@@ -252,13 +299,13 @@ func (f FileInfo) String() string {
|
||||
switch f.Type {
|
||||
case FileInfoTypeDirectory:
|
||||
return fmt.Sprintf("Directory{Name:%q, Sequence:%d, Permissions:0%o, ModTime:%v, Version:%v, VersionHash:%x, Deleted:%v, Invalid:%v, LocalFlags:0x%x, NoPermissions:%v, Platform:%v, InodeChangeTime:%v}",
|
||||
f.Name, f.Sequence, f.Permissions, f.ModTime(), f.Version, f.VersionHash, f.Deleted, f.RawInvalid, f.LocalFlags, f.NoPermissions, f.Platform, f.InodeChangeTime())
|
||||
f.Name, f.Sequence, f.Permissions, f.ModTime(), f.Version, f.VersionHash, f.Deleted, f.IsInvalid(), f.LocalFlags, f.NoPermissions, f.Platform, f.InodeChangeTime())
|
||||
case FileInfoTypeFile:
|
||||
return fmt.Sprintf("File{Name:%q, Sequence:%d, Permissions:0%o, ModTime:%v, Version:%v, VersionHash:%x, Length:%d, Deleted:%v, Invalid:%v, LocalFlags:0x%x, NoPermissions:%v, BlockSize:%d, NumBlocks:%d, BlocksHash:%x, Platform:%v, InodeChangeTime:%v}",
|
||||
f.Name, f.Sequence, f.Permissions, f.ModTime(), f.Version, f.VersionHash, f.Size, f.Deleted, f.RawInvalid, f.LocalFlags, f.NoPermissions, f.RawBlockSize, len(f.Blocks), f.BlocksHash, f.Platform, f.InodeChangeTime())
|
||||
f.Name, f.Sequence, f.Permissions, f.ModTime(), f.Version, f.VersionHash, f.Size, f.Deleted, f.IsInvalid(), f.LocalFlags, f.NoPermissions, f.RawBlockSize, len(f.Blocks), f.BlocksHash, f.Platform, f.InodeChangeTime())
|
||||
case FileInfoTypeSymlink, FileInfoTypeSymlinkDirectory, FileInfoTypeSymlinkFile:
|
||||
return fmt.Sprintf("Symlink{Name:%q, Type:%v, Sequence:%d, Version:%v, VersionHash:%x, Deleted:%v, Invalid:%v, LocalFlags:0x%x, NoPermissions:%v, SymlinkTarget:%q, Platform:%v, InodeChangeTime:%v}",
|
||||
f.Name, f.Type, f.Sequence, f.Version, f.VersionHash, f.Deleted, f.RawInvalid, f.LocalFlags, f.NoPermissions, f.SymlinkTarget, f.Platform, f.InodeChangeTime())
|
||||
f.Name, f.Type, f.Sequence, f.Version, f.VersionHash, f.Deleted, f.IsInvalid(), f.LocalFlags, f.NoPermissions, f.SymlinkTarget, f.Platform, f.InodeChangeTime())
|
||||
default:
|
||||
panic("mystery file type detected")
|
||||
}
|
||||
@@ -269,7 +316,7 @@ func (f FileInfo) IsDeleted() bool {
|
||||
}
|
||||
|
||||
func (f FileInfo) IsInvalid() bool {
|
||||
return f.RawInvalid || f.LocalFlags&LocalInvalidFlags != 0
|
||||
return f.LocalFlags.IsInvalid()
|
||||
}
|
||||
|
||||
func (f FileInfo) IsUnsupported() bool {
|
||||
@@ -342,7 +389,7 @@ func (f FileInfo) FileName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
func (f FileInfo) FileLocalFlags() uint32 {
|
||||
func (f FileInfo) FileLocalFlags() FlagLocal {
|
||||
return f.LocalFlags
|
||||
}
|
||||
|
||||
@@ -386,7 +433,7 @@ type FileInfoComparison struct {
|
||||
ModTimeWindow time.Duration
|
||||
IgnorePerms bool
|
||||
IgnoreBlocks bool
|
||||
IgnoreFlags uint32
|
||||
IgnoreFlags FlagLocal
|
||||
IgnoreOwnership bool
|
||||
IgnoreXattrs bool
|
||||
}
|
||||
@@ -533,8 +580,7 @@ func (f *FileInfo) SetDeleted(by ShortID) {
|
||||
f.setNoContent()
|
||||
}
|
||||
|
||||
func (f *FileInfo) setLocalFlags(flags uint32) {
|
||||
f.RawInvalid = false
|
||||
func (f *FileInfo) setLocalFlags(flags FlagLocal) {
|
||||
f.LocalFlags = flags
|
||||
f.setNoContent()
|
||||
}
|
||||
@@ -847,9 +893,13 @@ func unixOwnershipEqual(a, b *UnixData) bool {
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
ownerEqual := a.OwnerName == "" || b.OwnerName == "" || a.OwnerName == b.OwnerName
|
||||
groupEqual := a.GroupName == "" || b.GroupName == "" || a.GroupName == b.GroupName
|
||||
return a.UID == b.UID && a.GID == b.GID && ownerEqual && groupEqual
|
||||
if a.UID == b.UID && a.GID == b.GID {
|
||||
return true
|
||||
}
|
||||
if a.OwnerName == b.OwnerName && a.GroupName == b.GroupName {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func windowsOwnershipEqual(a, b *WindowsData) bool {
|
||||
|
||||
@@ -45,7 +45,7 @@ func TestIsEquivalent(t *testing.T) {
|
||||
b FileInfo
|
||||
ignPerms *bool // nil means should not matter, we'll test both variants
|
||||
ignBlocks *bool
|
||||
ignFlags uint32
|
||||
ignFlags FlagLocal
|
||||
eq bool
|
||||
}
|
||||
cases := []testCase{
|
||||
@@ -75,8 +75,8 @@ func TestIsEquivalent(t *testing.T) {
|
||||
eq: false,
|
||||
},
|
||||
{
|
||||
a: FileInfo{RawInvalid: false},
|
||||
b: FileInfo{RawInvalid: true},
|
||||
a: FileInfo{LocalFlags: 0},
|
||||
b: FileInfo{LocalFlags: FlagLocalRemoteInvalid},
|
||||
eq: false,
|
||||
},
|
||||
{
|
||||
@@ -100,8 +100,8 @@ func TestIsEquivalent(t *testing.T) {
|
||||
eq: false,
|
||||
},
|
||||
{
|
||||
a: FileInfo{RawInvalid: true},
|
||||
b: FileInfo{RawInvalid: true},
|
||||
a: FileInfo{LocalFlags: FlagLocalRemoteInvalid},
|
||||
b: FileInfo{LocalFlags: FlagLocalRemoteInvalid},
|
||||
eq: true,
|
||||
},
|
||||
{
|
||||
@@ -110,7 +110,7 @@ func TestIsEquivalent(t *testing.T) {
|
||||
eq: true,
|
||||
},
|
||||
{
|
||||
a: FileInfo{RawInvalid: true},
|
||||
a: FileInfo{LocalFlags: FlagLocalRemoteInvalid},
|
||||
b: FileInfo{LocalFlags: FlagLocalUnsupported},
|
||||
eq: true,
|
||||
},
|
||||
@@ -196,6 +196,42 @@ func TestIsEquivalent(t *testing.T) {
|
||||
b: FileInfo{Type: FileInfoTypeFile, SymlinkTarget: []byte("b")},
|
||||
eq: true,
|
||||
},
|
||||
// Unix Ownership should be the same
|
||||
{
|
||||
a: FileInfo{Platform: PlatformData{Unix: &UnixData{OwnerName: "A", GroupName: "A", UID: 1000, GID: 1000}}},
|
||||
b: FileInfo{Platform: PlatformData{Unix: &UnixData{OwnerName: "A", GroupName: "A", UID: 1000, GID: 1000}}},
|
||||
eq: true,
|
||||
},
|
||||
// ... but matching ID is enough
|
||||
{
|
||||
a: FileInfo{Platform: PlatformData{Unix: &UnixData{OwnerName: "A", GroupName: "A", UID: 1000, GID: 1000}}},
|
||||
b: FileInfo{Platform: PlatformData{Unix: &UnixData{OwnerName: "B", GroupName: "B", UID: 1000, GID: 1000}}},
|
||||
eq: true,
|
||||
},
|
||||
// ... or matching name
|
||||
{
|
||||
a: FileInfo{Platform: PlatformData{Unix: &UnixData{OwnerName: "A", GroupName: "A", UID: 1000, GID: 1000}}},
|
||||
b: FileInfo{Platform: PlatformData{Unix: &UnixData{OwnerName: "A", GroupName: "A", UID: 1001, GID: 1001}}},
|
||||
eq: true,
|
||||
},
|
||||
// ... or empty name
|
||||
{
|
||||
a: FileInfo{Platform: PlatformData{Unix: &UnixData{OwnerName: "A", GroupName: "A", UID: 1000, GID: 1000}}},
|
||||
b: FileInfo{Platform: PlatformData{Unix: &UnixData{OwnerName: "", GroupName: "", UID: 1000, GID: 1000}}},
|
||||
eq: true,
|
||||
},
|
||||
// ... but not different ownership
|
||||
{
|
||||
a: FileInfo{Platform: PlatformData{Unix: &UnixData{OwnerName: "A", GroupName: "A", UID: 1000, GID: 1000}}},
|
||||
b: FileInfo{Platform: PlatformData{Unix: &UnixData{OwnerName: "B", GroupName: "B", UID: 1001, GID: 1001}}},
|
||||
eq: false,
|
||||
},
|
||||
// or missing ownership
|
||||
{
|
||||
a: FileInfo{Platform: PlatformData{Unix: &UnixData{OwnerName: "A", GroupName: "A", UID: 1000, GID: 1000}}},
|
||||
b: FileInfo{Platform: PlatformData{}},
|
||||
eq: false,
|
||||
},
|
||||
}
|
||||
|
||||
if build.IsWindows {
|
||||
|
||||
@@ -14,8 +14,8 @@ func TestWinsConflict(t *testing.T) {
|
||||
testcases := [][2]FileInfo{
|
||||
// The first should always win over the second
|
||||
{{ModifiedS: 42}, {ModifiedS: 41}},
|
||||
{{ModifiedS: 41}, {ModifiedS: 42, Deleted: true}},
|
||||
{{Deleted: true}, {ModifiedS: 10, RawInvalid: true}},
|
||||
{{ModifiedS: 42, Deleted: true}, {ModifiedS: 41}},
|
||||
{{Deleted: true}, {ModifiedS: 10, LocalFlags: FlagLocalRemoteInvalid}},
|
||||
{{ModifiedS: 41, Version: Vector{Counters: []Counter{{ID: 42, Value: 2}, {ID: 43, Value: 1}}}}, {ModifiedS: 41, Version: Vector{Counters: []Counter{{ID: 42, Value: 1}, {ID: 43, Value: 2}}}}},
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user