mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-09-08 11:53:07 -04:00
Compare commits
33
Commits
v4.0.5
..
stable-4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abad26e657 | ||
|
|
9ba009f069 | ||
|
|
9e10e420d7 | ||
|
|
60c51aa1dd | ||
|
|
87f86f8c35 | ||
|
|
4eb0591829 | ||
|
|
c5fc3e075f | ||
|
|
38c783f890 | ||
|
|
392e8965d0 | ||
|
|
5caa34d51a | ||
|
|
8f743fe9f3 | ||
|
|
08eb7321ee | ||
|
|
66ba9504a2 | ||
|
|
07859d9ac4 | ||
|
|
2aa6943eaf | ||
|
|
a7bb32bf64 | ||
|
|
df4bc7c1d8 | ||
|
|
2ef5d1289d | ||
|
|
8ec82331cc | ||
|
|
15fc59626b | ||
|
|
813f42f825 | ||
|
|
f0e9e10fa7 | ||
|
|
32549ae0e1 | ||
|
|
f70ce6d8a8 | ||
|
|
e9ce946fe0 | ||
|
|
c0b0910000 | ||
|
|
4af5add77d | ||
|
|
01686db6d9 | ||
|
|
3434f55c78 | ||
|
|
7374ae61a9 | ||
|
|
62674c71cf | ||
|
|
193431b875 | ||
|
|
5e889612d6 |
No files matched your search
+1
-1
@@ -1,4 +1,4 @@
|
||||
# The test runner source for UI tests
|
||||
WEB_COMMITID=50e3fff6a518361d59cba864a927470f313b6f91
|
||||
WEB_COMMITID=c247f854a95b7bcaf10f27577458d2f566b2f939
|
||||
WEB_BRANCH=stable-4.2
|
||||
|
||||
@@ -1919,7 +1919,6 @@ def dockerRelease(ctx, repo, build_type):
|
||||
],
|
||||
},
|
||||
"when": [
|
||||
event["cron"],
|
||||
event["tag"],
|
||||
],
|
||||
},
|
||||
@@ -1948,8 +1947,6 @@ def dockerRelease(ctx, repo, build_type):
|
||||
],
|
||||
},
|
||||
"when": [
|
||||
event["cron"],
|
||||
event["base"],
|
||||
event["tag"],
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,5 +1,37 @@
|
||||
# Changelog
|
||||
|
||||
## [4.0.8](https://github.com/opencloud-eu/opencloud/releases/tag/v4.0.8) - 2026-06-25
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@ScharfViktor, @rhafer
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- bump reva 2.40.5 [[#3018](https://github.com/opencloud-eu/opencloud/pull/3018)]
|
||||
- [stable-4.0] Revert "fix: disallow thumbnails for tiff and jpeg2000 images" [[#3009](https://github.com/opencloud-eu/opencloud/pull/3009)]
|
||||
- [stable-4.0] Bump alpine base image [[#2965](https://github.com/opencloud-eu/opencloud/pull/2965)]
|
||||
|
||||
## [4.0.7](https://github.com/opencloud-eu/opencloud/releases/tag/v4.0.7) - 2026-05-18
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@ScharfViktor, @rhafer
|
||||
|
||||
### 🔒 Security
|
||||
|
||||
- [stable/4.0] Backports [[#2761](https://github.com/opencloud-eu/opencloud/pull/2761)]
|
||||
|
||||
## [4.0.6](https://github.com/opencloud-eu/opencloud/releases/tag/v4.0.6) - 2026-04-29
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@ScharfViktor, @dragonchaser, @kulmann, @rhafer
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- [stable-4.0] More graceful shutdown fixes [[#2692](https://github.com/opencloud-eu/opencloud/pull/2692)]
|
||||
|
||||
## [4.0.5](https://github.com/opencloud-eu/opencloud/releases/tag/v4.0.5) - 2026-04-02
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
+2
-3
@@ -21,15 +21,14 @@ COPY ./ /opencloud/
|
||||
WORKDIR /opencloud/opencloud
|
||||
RUN make node-generate-prod
|
||||
|
||||
FROM golang:1.24-alpine AS build
|
||||
RUN apk add bash make git curl gcc musl-dev libc-dev binutils-gold inotify-tools vips-dev
|
||||
FROM quay.io/opencloudeu/golang-ci:1.25 AS build
|
||||
|
||||
COPY --from=generate /opencloud /opencloud
|
||||
|
||||
WORKDIR /opencloud/opencloud
|
||||
RUN make go-generate build ENABLE_VIPS=true
|
||||
|
||||
FROM alpine:3.20
|
||||
FROM alpine:3.24
|
||||
|
||||
RUN apk add --no-cache attr ca-certificates curl mailcap tree vips && \
|
||||
echo 'hosts: files dns' >| /etc/nsswitch.conf
|
||||
|
||||
@@ -64,7 +64,7 @@ require (
|
||||
github.com/open-policy-agent/opa v1.10.1
|
||||
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76
|
||||
github.com/opencloud-eu/reva/v2 v2.40.4
|
||||
github.com/opencloud-eu/reva/v2 v2.40.5
|
||||
github.com/opensearch-project/opensearch-go/v4 v4.5.0
|
||||
github.com/orcaman/concurrent-map v1.0.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
|
||||
@@ -965,8 +965,8 @@ github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9 h1:dIft
|
||||
github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9/go.mod h1:JWyDC6H+5oZRdUJUgKuaye+8Ph5hEs6HVzVoPKzWSGI=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76 h1:vD/EdfDUrv4omSFjrinT8Mvf+8D7f9g4vgQ2oiDrVUI=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
|
||||
github.com/opencloud-eu/reva/v2 v2.40.4 h1:KTeFLHSwRp2bnK9J1dtaAGwPCreEiijYIXSyQ1A5tbo=
|
||||
github.com/opencloud-eu/reva/v2 v2.40.4/go.mod h1:NN88hQAbjCVq011D2zhr0IOZ9Xclz3HS+Wf961YHwbg=
|
||||
github.com/opencloud-eu/reva/v2 v2.40.5 h1:EfLoiwv0EouKMSYzSXd+1gAgZTgFdD4Q0d5r6yIVZVU=
|
||||
github.com/opencloud-eu/reva/v2 v2.40.5/go.mod h1:NN88hQAbjCVq011D2zhr0IOZ9Xclz3HS+Wf961YHwbg=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
FROM golang:alpine3.22 AS build
|
||||
FROM quay.io/opencloudeu/golang-ci:1.25 AS build
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG VERSION
|
||||
ARG STRING
|
||||
ARG EDITION
|
||||
|
||||
RUN apk add bash make git curl gcc musl-dev libc-dev binutils-gold inotify-tools vips-dev
|
||||
|
||||
WORKDIR /build
|
||||
RUN --mount=type=bind,target=/build,rw \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
@@ -14,7 +12,7 @@ RUN --mount=type=bind,target=/build,rw \
|
||||
GOOS="${TARGETOS:-linux}" GOARCH="${TARGETARCH:-amd64}" ; \
|
||||
make -C opencloud/opencloud release-linux-docker-${TARGETARCH} ENABLE_VIPS=true DIST=/dist
|
||||
|
||||
FROM alpine:3.22
|
||||
FROM alpine:3.24
|
||||
ARG VERSION
|
||||
ARG REVISION
|
||||
ARG TARGETOS
|
||||
|
||||
@@ -434,12 +434,9 @@ func Start(ctx context.Context, o ...Option) error {
|
||||
// prepare the set of services to run
|
||||
s.generateRunSet(s.cfg)
|
||||
|
||||
// There are reasons not to do this, but we have race conditions ourselves. Until we resolve them, mind the following disclaimer:
|
||||
// Calling ServeBackground will CORRECTLY start the supervisor running in a new goroutine. It is risky to directly run
|
||||
// go supervisor.Serve()
|
||||
// because that will briefly create a race condition as it starts up, if you try to .Add() services immediately afterward.
|
||||
// https://pkg.go.dev/github.com/thejerf/suture/v4@v4.0.0#Supervisor
|
||||
go s.Supervisor.ServeBackground(ctx)
|
||||
// We need to control the order in which services are started and shut down,
|
||||
// so we need a backgroud context that will outlive the service execution.
|
||||
go s.Supervisor.ServeBackground(context.Background())
|
||||
|
||||
for i, service := range s.Services {
|
||||
scheduleServiceTokens(s, service)
|
||||
|
||||
@@ -34,7 +34,7 @@ var (
|
||||
// LatestTag is the latest released version plus the dev meta version.
|
||||
// Will be overwritten by the release pipeline
|
||||
// Needs a manual change for every tagged release
|
||||
LatestTag = "4.0.5+dev"
|
||||
LatestTag = "4.0.8+dev"
|
||||
|
||||
// Date indicates the build date.
|
||||
// This has been removed, it looks like you can only replace static strings with recent go versions
|
||||
|
||||
@@ -91,7 +91,9 @@ func Server(cfg *config.Config) *cli.Command {
|
||||
gr.Add(runner.New(cfg.Service.Name+".svc", func() error {
|
||||
return natsServer.ListenAndServe()
|
||||
}, func() {
|
||||
logger.Info().Msg("Gracefully shutting down the NATS server...")
|
||||
natsServer.Shutdown()
|
||||
logger.Info().Msg("NATS server shutdown")
|
||||
}))
|
||||
|
||||
grResults := gr.Run(ctx)
|
||||
|
||||
@@ -88,7 +88,7 @@ func NewPostprocessingService(ctx context.Context, logger log.Logger, sto store.
|
||||
|
||||
m := metrics.New()
|
||||
m.BuildInfo.WithLabelValues(version.GetString()).Set(1)
|
||||
monitorMetrics(raw, "postprocessing-pull", m, logger)
|
||||
monitorMetrics(ctx, raw, "postprocessing-pull", m, logger)
|
||||
|
||||
return &PostprocessingService{
|
||||
ctx: ctx,
|
||||
@@ -425,25 +425,30 @@ func (pps *PostprocessingService) findUploadsByStep(step events.Postprocessingst
|
||||
return ids
|
||||
}
|
||||
|
||||
func monitorMetrics(stream raw.Stream, name string, m *metrics.Metrics, logger log.Logger) {
|
||||
ctx := context.Background()
|
||||
func monitorMetrics(ctx context.Context, stream raw.Stream, name string, m *metrics.Metrics, logger log.Logger) {
|
||||
consumer, err := stream.JetStream().Consumer(ctx, name)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to get consumer")
|
||||
}
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
go func() {
|
||||
for range ticker.C {
|
||||
info, err := consumer.Info(ctx)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to get consumer")
|
||||
continue
|
||||
}
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
info, err := consumer.Info(ctx)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to get consumer")
|
||||
continue
|
||||
}
|
||||
|
||||
m.EventsOutstandingAcks.Set(float64(info.NumAckPending))
|
||||
m.EventsUnprocessed.Set(float64(info.NumPending))
|
||||
m.EventsRedelivered.Set(float64(info.NumRedelivered))
|
||||
logger.Trace().Msg("updated postprocessing event metrics")
|
||||
m.EventsOutstandingAcks.Set(float64(info.NumAckPending))
|
||||
m.EventsUnprocessed.Set(float64(info.NumPending))
|
||||
m.EventsRedelivered.Set(float64(info.NumRedelivered))
|
||||
logger.Trace().Msg("updated postprocessing event metrics")
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -88,7 +88,7 @@ func (s Service) Run() error {
|
||||
}
|
||||
|
||||
if s.m != nil {
|
||||
monitorMetrics(s.stream, "search-pull", s.m, s.log)
|
||||
monitorMetrics(s.ctx, s.stream, "search-pull", s.m, s.log)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
@@ -202,25 +202,30 @@ func (s Service) processEvent(e raw.Event) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func monitorMetrics(stream raw.Stream, name string, m *metrics.Metrics, logger log.Logger) {
|
||||
ctx := context.Background()
|
||||
func monitorMetrics(ctx context.Context, stream raw.Stream, name string, m *metrics.Metrics, logger log.Logger) {
|
||||
consumer, err := stream.JetStream().Consumer(ctx, name)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to get consumer")
|
||||
}
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
go func() {
|
||||
for range ticker.C {
|
||||
info, err := consumer.Info(ctx)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to get consumer")
|
||||
continue
|
||||
}
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
info, err := consumer.Info(ctx)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to get consumer")
|
||||
continue
|
||||
}
|
||||
|
||||
m.EventsOutstandingAcks.Set(float64(info.NumAckPending))
|
||||
m.EventsUnprocessed.Set(float64(info.NumPending))
|
||||
m.EventsRedelivered.Set(float64(info.NumRedelivered))
|
||||
logger.Trace().Msg("updated search event metrics")
|
||||
m.EventsOutstandingAcks.Set(float64(info.NumAckPending))
|
||||
m.EventsUnprocessed.Set(float64(info.NumPending))
|
||||
m.EventsRedelivered.Set(float64(info.NumRedelivered))
|
||||
logger.Trace().Msg("updated search event metrics")
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
SHELL := bash
|
||||
NAME := web
|
||||
WEB_ASSETS_VERSION = v4.2.1
|
||||
WEB_ASSETS_VERSION = v4.2.2
|
||||
WEB_ASSETS_BRANCH = main
|
||||
|
||||
ifneq (, $(shell command -v go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
package ignore
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/blobstore"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/lookup"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/tree/propagator"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/utils/templates"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
const (
|
||||
// The needles include the separator at the beginning to avoid matching internal dir names in substrings
|
||||
// The end segment boundary is checked in isInternalDir
|
||||
trashNeedle = needle(string(filepath.Separator) + lookup.TrashDir)
|
||||
metadataNeedle = needle(string(filepath.Separator) + lookup.MetadataDir)
|
||||
tmpNeedle = needle(string(filepath.Separator) + blobstore.TMPDir)
|
||||
)
|
||||
|
||||
type needle string
|
||||
|
||||
// Ignorer handles checking if paths should be ignored in posix operations
|
||||
type Ignorer struct {
|
||||
options *options.Options
|
||||
log *zerolog.Logger
|
||||
personalSpacesRoot string
|
||||
projectSpacesRoot string
|
||||
}
|
||||
|
||||
// NewIgnorer creates a new Ignorer given the posix options and logger
|
||||
func NewIgnorer(options *options.Options, log *zerolog.Logger) *Ignorer {
|
||||
return &Ignorer{
|
||||
options: options,
|
||||
log: log,
|
||||
personalSpacesRoot: filepath.Clean(filepath.Join(options.Root, templates.Base(options.PersonalSpacePathTemplate))),
|
||||
projectSpacesRoot: filepath.Clean(filepath.Join(options.Root, templates.Base(options.GeneralSpacePathTemplate))),
|
||||
}
|
||||
}
|
||||
|
||||
// IsIgnored checking if paths should be ignored in posix operations
|
||||
func (i *Ignorer) IsIgnored(path string) bool {
|
||||
return i.IsChanges(path) ||
|
||||
i.IsIndex(path) ||
|
||||
IsLockFile(path) ||
|
||||
i.IsTrash(path) ||
|
||||
i.IsMetadata(path) ||
|
||||
i.IsTemporary(path) ||
|
||||
i.IsUpload(path) ||
|
||||
i.IsRootPath(path) ||
|
||||
i.IsSpaceRoot(path)
|
||||
}
|
||||
|
||||
func (i *Ignorer) IsChanges(path string) bool {
|
||||
return strings.HasPrefix(path, filepath.Join(i.options.Root, propagator.ChangesDir))
|
||||
}
|
||||
|
||||
func (i *Ignorer) IsIndex(path string) bool {
|
||||
return strings.HasPrefix(path, filepath.Join(i.options.Root, lookup.IndexesDir))
|
||||
}
|
||||
|
||||
func (i *Ignorer) IsUpload(path string) bool {
|
||||
return strings.HasPrefix(path, i.options.UploadDirectory)
|
||||
}
|
||||
|
||||
func (i *Ignorer) IsRootPath(path string) bool {
|
||||
return path == i.options.Root ||
|
||||
path == i.personalSpacesRoot ||
|
||||
path == i.projectSpacesRoot
|
||||
}
|
||||
|
||||
func (i *Ignorer) IsSpaceRoot(path string) bool {
|
||||
parent := filepath.Dir(path)
|
||||
return parent == i.personalSpacesRoot || parent == i.projectSpacesRoot
|
||||
}
|
||||
|
||||
func IsLockFile(path string) bool {
|
||||
return strings.HasSuffix(path, ".flock") || strings.HasSuffix(path, ".mlock")
|
||||
}
|
||||
|
||||
func (i *Ignorer) IsMetadata(path string) bool {
|
||||
return i.isInternalDir(path, metadataNeedle)
|
||||
}
|
||||
|
||||
func (i *Ignorer) IsTemporary(path string) bool {
|
||||
return i.isInternalDir(path, tmpNeedle)
|
||||
}
|
||||
|
||||
func (i *Ignorer) IsTrash(path string) bool {
|
||||
return i.isInternalDir(path, trashNeedle)
|
||||
}
|
||||
|
||||
// isInternalDir checks if the path contains the match dir and that the match lives
|
||||
// in the space root, e.g. "/storage/users/user1/.metadata/file" -> match is ".metadata",
|
||||
// parent dir is "/storage/users/user1" which is a space root, so this would return true
|
||||
func (i *Ignorer) isInternalDir(path string, match needle) bool {
|
||||
idx := strings.Index(path, string(match))
|
||||
if idx <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// must end at a segment boundary (end of path or separator)
|
||||
if length := idx + len(match); length != len(path) && path[length] != filepath.Separator {
|
||||
return false
|
||||
}
|
||||
|
||||
// get the path of the parent dir, e.g. "/a/match" -> index of "match" is 3
|
||||
// so parentPath is path[:2] -> "/a"
|
||||
parentPath := path[:idx-1]
|
||||
|
||||
return len(parentPath) > 0 && i.IsSpaceRoot(parentPath)
|
||||
}
|
||||
+6
-1
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/appctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/errtypes"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options"
|
||||
dfslookup "github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/lookup"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata/prefixes"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/node"
|
||||
@@ -47,7 +48,11 @@ import (
|
||||
|
||||
var tracer trace.Tracer
|
||||
|
||||
const MetadataDir = ".oc-nodes"
|
||||
const (
|
||||
IndexesDir = dfslookup.IndexesDir
|
||||
MetadataDir = ".oc-nodes"
|
||||
TrashDir = ".Trash"
|
||||
)
|
||||
|
||||
var _spaceTypePersonal = "personal"
|
||||
var _spaceTypeProject = "project"
|
||||
|
||||
+6
-6
@@ -144,7 +144,7 @@ func (tb *Trashbin) Setup(fs storage.FS) error {
|
||||
}
|
||||
|
||||
func trashRootForNode(n *node.Node) string {
|
||||
return filepath.Join(n.SpaceRoot.InternalPath(), ".Trash")
|
||||
return filepath.Join(n.SpaceRoot.InternalPath(), lookup.TrashDir)
|
||||
}
|
||||
|
||||
func (tb *Trashbin) MoveToTrash(ctx context.Context, n *node.Node, path string) error {
|
||||
@@ -191,7 +191,7 @@ func (tb *Trashbin) ListRecycle(ctx context.Context, spaceID string, key, relati
|
||||
_, span := tracer.Start(ctx, "ListRecycle")
|
||||
defer span.End()
|
||||
|
||||
trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), ".Trash")
|
||||
trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), lookup.TrashDir)
|
||||
base := filepath.Join(trashRoot, "files")
|
||||
|
||||
var originalPath string
|
||||
@@ -303,7 +303,7 @@ func (tb *Trashbin) RestoreRecycleItem(ctx context.Context, spaceID string, key,
|
||||
_, span := tracer.Start(ctx, "RestoreRecycleItem")
|
||||
defer span.End()
|
||||
|
||||
trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), ".Trash")
|
||||
trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), lookup.TrashDir)
|
||||
trashPath := filepath.Clean(filepath.Join(trashRoot, "files", key+".trashitem", relativePath))
|
||||
|
||||
restorePath := ""
|
||||
@@ -376,7 +376,7 @@ func (tb *Trashbin) PurgeRecycleItem(ctx context.Context, spaceID, key, relative
|
||||
_, span := tracer.Start(ctx, "PurgeRecycleItem")
|
||||
defer span.End()
|
||||
|
||||
trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), ".Trash")
|
||||
trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), lookup.TrashDir)
|
||||
trashPath := filepath.Clean(filepath.Join(trashRoot, "files", key+".trashitem", relativePath))
|
||||
|
||||
type item struct {
|
||||
@@ -521,7 +521,7 @@ func (tb *Trashbin) EmptyRecycle(ctx context.Context, spaceID string) error {
|
||||
_, span := tracer.Start(ctx, "EmptyRecycle")
|
||||
defer span.End()
|
||||
|
||||
trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), ".Trash")
|
||||
trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), lookup.TrashDir)
|
||||
filesRoot := filepath.Join(trashRoot, "files")
|
||||
|
||||
entries, err := os.ReadDir(filesRoot)
|
||||
@@ -581,7 +581,7 @@ func (tb *Trashbin) EmptyRecycle(ctx context.Context, spaceID string) error {
|
||||
func (tb *Trashbin) IsEmpty(ctx context.Context, spaceID string) bool {
|
||||
_, span := tracer.Start(ctx, "HasTrashedItems")
|
||||
defer span.End()
|
||||
trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), ".Trash", "info")
|
||||
trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), lookup.TrashDir, "info")
|
||||
trash, err := os.Open(filepath.Clean(trashRoot))
|
||||
if err != nil {
|
||||
// there is no trash for this space, so no trashed items
|
||||
|
||||
+7
-8
@@ -679,7 +679,7 @@ assimilate:
|
||||
// The Space's name attribute might not match the directory name. Use the name as
|
||||
// it was set before. Also the space root doesn't have a 'type' attribute
|
||||
// currently so only set it for normal directories.
|
||||
if t.isSpaceRoot(path) {
|
||||
if t.Ignorer.IsSpaceRoot(path) {
|
||||
if previousAttribs != nil && previousAttribs[prefixes.NameAttr] != nil {
|
||||
attributes[prefixes.NameAttr] = previousAttribs[prefixes.NameAttr]
|
||||
}
|
||||
@@ -830,14 +830,13 @@ func (t *Tree) WarmupIDCache(root string, assimilate, onlyDirty bool) error {
|
||||
}
|
||||
|
||||
// skip irrelevant files
|
||||
if t.isInternal(path) ||
|
||||
isLockFile(path) ||
|
||||
isTrash(path) ||
|
||||
t.isUpload(path) ||
|
||||
t.isIndex(path) {
|
||||
if !t.Ignorer.IsSpaceRoot(path) && t.Ignorer.IsIgnored(path) {
|
||||
if info.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if t.isRootPath(path) {
|
||||
if t.Ignorer.IsRootPath(path) {
|
||||
return nil // ignore the root paths
|
||||
}
|
||||
|
||||
@@ -935,7 +934,7 @@ func (t *Tree) WarmupIDCache(root string, assimilate, onlyDirty bool) error {
|
||||
})
|
||||
|
||||
for dir, size := range sizes {
|
||||
if t.isRootPath(dir) {
|
||||
if t.Ignorer.IsRootPath(dir) {
|
||||
continue
|
||||
}
|
||||
spaceID, id, err := t.lookup.IDsForPath(context.Background(), dir)
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -83,7 +83,7 @@ func (w *CephFSWatcher) Watch(topic string) {
|
||||
continue
|
||||
}
|
||||
|
||||
if w.tree.isIgnored(ev.Path) {
|
||||
if w.tree.Ignorer.IsIgnored(ev.Path) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -82,7 +82,7 @@ start:
|
||||
w.log.Error().Err(err).Str("line", line).Msg("error unmarshalling line")
|
||||
continue
|
||||
}
|
||||
if w.tree.isIgnored(ev.Path) {
|
||||
if w.tree.Ignorer.IsIgnored(ev.Path) {
|
||||
continue
|
||||
}
|
||||
go func() {
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -65,7 +65,7 @@ func (w *GpfsWatchFolderWatcher) Watch(topic string) {
|
||||
continue
|
||||
}
|
||||
|
||||
if w.tree.isIgnored(lwev.Path) {
|
||||
if w.tree.Ignorer.IsIgnored(lwev.Path) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -88,7 +88,7 @@ func (iw *InotifyWatcher) Watch(path string) {
|
||||
for {
|
||||
select {
|
||||
case event := <-events:
|
||||
if iw.tree.isIgnored(event.Filename) {
|
||||
if iw.tree.Ignorer.IsIgnored(event.Filename) {
|
||||
continue
|
||||
}
|
||||
for _, e := range event.Events {
|
||||
|
||||
+16
-55
@@ -43,7 +43,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/appctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/errtypes"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/blobstore"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/ignore"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/lookup"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/trashbin"
|
||||
@@ -84,6 +84,7 @@ type Tree struct {
|
||||
options *options.Options
|
||||
personalSpacesRoot string
|
||||
projectSpacesRoot string
|
||||
Ignorer *ignore.Ignorer
|
||||
|
||||
userMapper usermapper.Mapper
|
||||
idCache store.Store
|
||||
@@ -119,6 +120,7 @@ func New(lu node.PathLookup, bs node.Blobstore, um usermapper.Mapper, trashbin *
|
||||
log: log,
|
||||
personalSpacesRoot: filepath.Clean(filepath.Join(o.Root, templates.Base(o.PersonalSpacePathTemplate))),
|
||||
projectSpacesRoot: filepath.Clean(filepath.Join(o.Root, templates.Base(o.GeneralSpacePathTemplate))),
|
||||
Ignorer: ignore.NewIgnorer(o, log),
|
||||
}
|
||||
if err := t.checkStorage(); err != nil {
|
||||
return nil, errors.Wrap(err, "tree: unfit storage '"+o.Root+"'")
|
||||
@@ -252,6 +254,10 @@ func (t *Tree) GetMD(ctx context.Context, n *node.Node) (os.FileInfo, error) {
|
||||
|
||||
// TouchFile creates a new empty file
|
||||
func (t *Tree) TouchFile(ctx context.Context, n *node.Node, markprocessing bool, mtime string) error {
|
||||
if t.Ignorer.IsIgnored(filepath.Join(n.ParentPath(), n.Name)) {
|
||||
return errtypes.PermissionDenied(n.ID)
|
||||
}
|
||||
|
||||
if n.Exists {
|
||||
if markprocessing {
|
||||
return n.SetXattr(ctx, prefixes.StatusPrefix, []byte(node.ProcessingStatus))
|
||||
@@ -468,7 +474,7 @@ func (t *Tree) ListFolder(ctx context.Context, n *node.Node) ([]*node.Node, erro
|
||||
g.Go(func() error {
|
||||
defer close(work)
|
||||
for _, name := range names {
|
||||
if t.isInternal(name) || isLockFile(name) || isTrash(name) {
|
||||
if t.Ignorer.IsIgnored(filepath.Join(dir, name)) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -648,6 +654,10 @@ func (t *Tree) ResolveSpaceIDIndexEntry(spaceID string) (string, error) {
|
||||
|
||||
// InitNewNode initializes a new node
|
||||
func (t *Tree) InitNewNode(ctx context.Context, n *node.Node, fsize uint64) (metadata.UnlockFunc, error) {
|
||||
if t.Ignorer.IsIgnored(filepath.Join(n.ParentPath(), n.Name)) {
|
||||
return nil, errtypes.PermissionDenied(n.ID)
|
||||
}
|
||||
|
||||
_, span := tracer.Start(ctx, "InitNewNode")
|
||||
defer span.End()
|
||||
// create folder structure (if needed)
|
||||
@@ -680,6 +690,10 @@ func (t *Tree) InitNewNode(ctx context.Context, n *node.Node, fsize uint64) (met
|
||||
|
||||
// TODO check if node exists?
|
||||
func (t *Tree) createDirNode(ctx context.Context, n *node.Node) (err error) {
|
||||
if t.Ignorer.IsIgnored(filepath.Join(n.ParentPath(), n.Name)) {
|
||||
return errtypes.PermissionDenied(n.ID)
|
||||
}
|
||||
|
||||
ctx, span := tracer.Start(ctx, "createDirNode")
|
||||
defer span.End()
|
||||
|
||||
@@ -730,56 +744,3 @@ func (t *Tree) createDirNode(ctx context.Context, n *node.Node) (err error) {
|
||||
}
|
||||
return n.SetXattrsWithContext(ctx, attributes, false)
|
||||
}
|
||||
|
||||
func (t *Tree) isIgnored(path string) bool {
|
||||
return isLockFile(path) || isTrash(path) || t.isUpload(path) || t.isInternal(path) || t.isRootPath(path) || t.isSpaceRoot(path)
|
||||
}
|
||||
|
||||
func (t *Tree) isUpload(path string) bool {
|
||||
return strings.HasPrefix(path, t.options.UploadDirectory)
|
||||
}
|
||||
|
||||
func (t *Tree) isIndex(path string) bool {
|
||||
return strings.HasPrefix(path, filepath.Join(t.options.Root, "indexes"))
|
||||
}
|
||||
|
||||
func (t *Tree) isTemporary(path string) bool {
|
||||
if filepath.IsAbs(path) {
|
||||
tmpDirPattern := filepath.Join(t.options.Root, "*", "*", blobstore.TMPDir)
|
||||
isTempDir, err := filepath.Match(tmpDirPattern, path)
|
||||
if err != nil {
|
||||
t.log.Error().Err(err).Str("pattern", tmpDirPattern).Str("path", path).Msg("error matching temporary path")
|
||||
return false
|
||||
}
|
||||
isTempParentDir, err := filepath.Match(tmpDirPattern, filepath.Dir(path))
|
||||
if err != nil {
|
||||
t.log.Error().Err(err).Str("pattern", tmpDirPattern).Str("path", filepath.Dir(path)).Msg("error matching temporary path")
|
||||
return false
|
||||
}
|
||||
return isTempDir || isTempParentDir
|
||||
}
|
||||
return path == blobstore.TMPDir || filepath.Dir(path) == blobstore.TMPDir
|
||||
}
|
||||
|
||||
func (t *Tree) isRootPath(path string) bool {
|
||||
return path == t.options.Root ||
|
||||
path == t.personalSpacesRoot ||
|
||||
path == t.projectSpacesRoot
|
||||
}
|
||||
|
||||
func (t *Tree) isSpaceRoot(path string) bool {
|
||||
parent := filepath.Dir(path)
|
||||
return parent == t.personalSpacesRoot || parent == t.projectSpacesRoot
|
||||
}
|
||||
|
||||
func (t *Tree) isInternal(path string) bool {
|
||||
return t.isIndex(path) || strings.Contains(path, lookup.MetadataDir) || t.isTemporary(path)
|
||||
}
|
||||
|
||||
func isLockFile(path string) bool {
|
||||
return strings.HasSuffix(path, ".flock") || strings.HasSuffix(path, ".mlock")
|
||||
}
|
||||
|
||||
func isTrash(path string) bool {
|
||||
return strings.HasSuffix(path, ".trashinfo") || strings.HasSuffix(path, ".trashitem") || strings.Contains(path, ".Trash")
|
||||
}
|
||||
Generated
Vendored
+3
-3
@@ -203,17 +203,17 @@ func New(o *options.Options, aspects aspects.Aspects, log *zerolog.Logger) (stor
|
||||
if o.LockCycleDurationFactor != 0 {
|
||||
filelocks.SetLockCycleDurationFactor(o.LockCycleDurationFactor)
|
||||
}
|
||||
userSpaceIndex := spaceidindex.New(filepath.Join(o.Root, "indexes"), "by-user-id")
|
||||
userSpaceIndex := spaceidindex.New(filepath.Join(o.Root, lookup.IndexesDir), "by-user-id")
|
||||
err = userSpaceIndex.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groupSpaceIndex := spaceidindex.New(filepath.Join(o.Root, "indexes"), "by-group-id")
|
||||
groupSpaceIndex := spaceidindex.New(filepath.Join(o.Root, lookup.IndexesDir), "by-group-id")
|
||||
err = groupSpaceIndex.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spaceTypeIndex := spaceidindex.New(filepath.Join(o.Root, "indexes"), "by-type")
|
||||
spaceTypeIndex := spaceidindex.New(filepath.Join(o.Root, lookup.IndexesDir), "by-type")
|
||||
err = spaceTypeIndex.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Generated
Vendored
+2
@@ -45,6 +45,8 @@ var tracer trace.Tracer
|
||||
|
||||
const (
|
||||
_spaceTypePersonal = "personal"
|
||||
|
||||
IndexesDir = "indexes"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
Generated
Vendored
+6
-2
@@ -37,6 +37,10 @@ import (
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
const (
|
||||
ChangesDir = "changes"
|
||||
)
|
||||
|
||||
var _propagationGracePeriod = 3 * time.Minute
|
||||
|
||||
type PropagationNode interface {
|
||||
@@ -80,7 +84,7 @@ func NewAsyncPropagator(treeSizeAccounting, treeTimeAccounting bool, o options.A
|
||||
return
|
||||
}
|
||||
|
||||
changesDirPath := filepath.Join(p.lookup.InternalRoot(), "changes")
|
||||
changesDirPath := filepath.Join(p.lookup.InternalRoot(), ChangesDir)
|
||||
doSleep := false // switch to not sleep on the first iteration
|
||||
for {
|
||||
if doSleep {
|
||||
@@ -426,5 +430,5 @@ func (p AsyncPropagator) propagate(ctx context.Context, pn PropagationNode, reca
|
||||
}
|
||||
|
||||
func (p AsyncPropagator) changesPath(spaceID, nodeID, filename string) string {
|
||||
return filepath.Join(p.lookup.InternalRoot(), "changes", spaceID[0:2], spaceID+":"+nodeID, filename)
|
||||
return filepath.Join(p.lookup.InternalRoot(), ChangesDir, spaceID[0:2], spaceID+":"+nodeID, filename)
|
||||
}
|
||||
Vendored
+2
-1
@@ -1375,7 +1375,7 @@ github.com/opencloud-eu/icap-client
|
||||
# github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76
|
||||
## explicit; go 1.18
|
||||
github.com/opencloud-eu/libre-graph-api-go
|
||||
# github.com/opencloud-eu/reva/v2 v2.40.4
|
||||
# github.com/opencloud-eu/reva/v2 v2.40.5
|
||||
## explicit; go 1.24.1
|
||||
github.com/opencloud-eu/reva/v2/cmd/revad/internal/grace
|
||||
github.com/opencloud-eu/reva/v2/cmd/revad/runtime
|
||||
@@ -1684,6 +1684,7 @@ github.com/opencloud-eu/reva/v2/pkg/storage/fs/owncloudsql
|
||||
github.com/opencloud-eu/reva/v2/pkg/storage/fs/owncloudsql/filecache
|
||||
github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix
|
||||
github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/blobstore
|
||||
github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/ignore
|
||||
github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/lookup
|
||||
github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options
|
||||
github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/timemanager
|
||||
|
||||
Reference in new issue
Block a user