Compare commits

..

1 Commits

Author SHA1 Message Date
Viktor Scharf
243af451e5 bump-version-v2.0.3 2025-07-10 15:56:05 +02:00
20 changed files with 80 additions and 275 deletions

View File

@@ -1,3 +1,3 @@
# The test runner source for UI tests
WEB_COMMITID=3cc779ddb45b52134fa986d21587f18316e2135a
WEB_COMMITID=59e329cc5fe288cf247cc5272547a77ac59cc000
WEB_BRANCH=stable-2.1

View File

@@ -1559,10 +1559,10 @@ def dockerReleases(ctx):
return pipelines
def dockerRelease(ctx, repo, build_type):
build_args = {
"REVISION": "%s" % (ctx.build.commit),
"VERSION": "%s" % (ctx.build.ref.replace("refs/tags/", "") if ctx.build.event == "tag" else "daily"),
}
build_args = [
"REVISION=%s" % (ctx.build.commit),
"VERSION=%s" % (ctx.build.ref.replace("refs/tags/", "") if ctx.build.event == "tag" else "daily"),
]
depends_on = getPipelineNames(getGoBinForTesting(ctx))

View File

@@ -1,36 +1,5 @@
# Changelog
## [2.0.5](https://github.com/opencloud-eu/opencloud/releases/tag/v2.0.5) - 2025-10-29
### ❤️ Thanks to all contributors! ❤️
@ScharfViktor
### ✅ Tests
- [full-ci] Bump reva 2.29.5 [[#1738](https://github.com/opencloud-eu/opencloud/pull/1738)]
- Fix tests in the stable branch [[#1731](https://github.com/opencloud-eu/opencloud/pull/1731)]
## [2.0.4](https://github.com/opencloud-eu/opencloud/releases/tag/v2.0.4) - 2025-07-11
### ❤️ Thanks to all contributors! ❤️
@micbar
### 🐛 Bug Fixes
- [Backport] fix: build_args is now an object [[#1213](https://github.com/opencloud-eu/opencloud/pull/1213)]
## [2.0.3](https://github.com/opencloud-eu/opencloud/releases/tag/v2.0.3) - 2025-07-10
### ❤️ Thanks to all contributors! ❤️
@ScharfViktor
### 📦️ Dependencies
- [full-ci] Reva bump 2.29.4 [[#1202](https://github.com/opencloud-eu/opencloud/pull/1202)]
## [2.0.2](https://github.com/opencloud-eu/opencloud/releases/tag/v2.0.2) - 2025-05-02
### ❤️ Thanks to all contributors! ❤️

View File

@@ -39,10 +39,10 @@ OPENCLOUD=:opencloud.yml
# For production releases: "opencloudeu/opencloud"
# For rolling releases: "opencloudeu/opencloud-rolling"
# Defaults to production if not set otherwise
OC_DOCKER_IMAGE=opencloudeu/opencloud-rolling
OC_DOCKER_IMAGE=opencloudeu/opencloud
# The openCloud container version.
# Defaults to "latest" and points to the latest stable tag.
OC_DOCKER_TAG=
OC_DOCKER_TAG=2.0.3
# Domain of openCloud, where you can find the frontend.
# Defaults to "cloud.opencloud.test"
OC_DOMAIN=

2
go.mod
View File

@@ -63,7 +63,7 @@ require (
github.com/onsi/ginkgo/v2 v2.23.3
github.com/onsi/gomega v1.36.3
github.com/open-policy-agent/opa v1.2.0
github.com/opencloud-eu/reva/v2 v2.29.5
github.com/opencloud-eu/reva/v2 v2.29.4
github.com/orcaman/concurrent-map v1.0.0
github.com/owncloud/libre-graph-api-go v1.0.5-0.20240829135935-80dc00d6f5ea
github.com/pkg/errors v0.9.1

4
go.sum
View File

@@ -865,8 +865,8 @@ github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU=
github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/open-policy-agent/opa v1.2.0 h1:88NDVCM0of1eO6Z4AFeL3utTEtMuwloFmWWU7dRV1z0=
github.com/open-policy-agent/opa v1.2.0/go.mod h1:30euUmOvuBoebRCcJ7DMF42bRBOPznvt0ACUMYDUGVY=
github.com/opencloud-eu/reva/v2 v2.29.5 h1:T4RjTSDk650PVn0hAL8HpF+61ChqQ/UwNoWMYYAMOGU=
github.com/opencloud-eu/reva/v2 v2.29.5/go.mod h1:+nkCU7w6E6cyNSsKRYj1rb0cCI7QswEQ7KOPljctebM=
github.com/opencloud-eu/reva/v2 v2.29.4 h1:UaykCqG3FNEpaeZzixsJBGi+j/Ihl3qASQ1WgcYTDb0=
github.com/opencloud-eu/reva/v2 v2.29.4/go.mod h1:+nkCU7w6E6cyNSsKRYj1rb0cCI7QswEQ7KOPljctebM=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=

View File

@@ -16,7 +16,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 = "2.0.5+dev"
LatestTag = "2.0.3+dev"
// Date indicates the build date.
// This has been removed, it looks like you can only replace static strings with recent go versions

View File

@@ -472,10 +472,7 @@ module.exports = function(webpackEnv) {
// its runtime that would otherwise be processed through "file" loader.
// Also exclude `html` and `json` extensions so they get processed
// by webpacks internal loaders.
//
// html-webpack-plugin has a known bug,
// fixed by /^$/ https://github.com/jantimon/html-webpack-plugin/issues/1589
exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
options: {
name: 'static/media/[name].[hash:8].[ext]',
},

View File

@@ -120,26 +120,3 @@ Feature: Propfind test
| Manager | RDNVWZP |
| Space Editor | DNVW |
| Space Viewer | |
@issue-1523
Scenario: propfind response contains a restored folder with correct name
Given user "Alice" has created a folder "folderMain" in space "Personal"
And user "Alice" has deleted folder "folderMain"
And user "Alice" has created a folder "folderMain" in space "Personal"
When user "Alice" restores the folder with original path "/folderMain" to "/folderMain (1)" using the trashbin API
And user "Alice" sends PROPFIND request to space "Personal" using the WebDAV API
Then the HTTP status code should be "207"
And as user "Alice" the PROPFIND response should contain a resource "folderMain" with these key and value pairs:
| key | value |
| oc:fileid | %file_id_pattern% |
| oc:file-parent | %file_id_pattern% |
| oc:name | folderMain |
| oc:permissions | RDNVCKZP |
| oc:size | 0 |
And as user "Alice" the PROPFIND response should contain a resource "folderMain (1)" with these key and value pairs:
| key | value |
| oc:fileid | %file_id_pattern% |
| oc:file-parent | %file_id_pattern% |
| oc:name | folderMain (1) |
| oc:permissions | RDNVCKZP |
| oc:size | 0 |

View File

@@ -23,7 +23,6 @@ Feature: Send a sharing invitations
| shareType | user |
| permissionsRole | <permissions-role> |
Then the HTTP status code should be "200"
And user "Brian" has a share "<resource>" synced
And user "Brian" should have a share "<resource>" shared by user "Alice" from space "Personal"
And the JSON data of the response should match
"""
@@ -114,9 +113,7 @@ Feature: Send a sharing invitations
| shareType | group |
| permissionsRole | <permissions-role> |
Then the HTTP status code should be "200"
And user "Brian" has a share "<resource>" synced
And user "Brian" should have a share "<resource>" shared by user "Alice" from space "Personal"
And user "Carol" has a share "<resource>" synced
And user "Carol" should have a share "<resource>" shared by user "Alice" from space "Personal"
And the JSON data of the response should match
"""
@@ -2001,7 +1998,6 @@ Feature: Send a sharing invitations
| shareType | user |
| permissionsRole | <permissions-role> |
Then the HTTP status code should be "200"
And user "Brian" has a share "<resource>" synced
And user "Brian" should have a share "<resource>" shared by user "Alice" from space "NewSpace"
And the JSON data of the response should match
"""
@@ -2090,9 +2086,7 @@ Feature: Send a sharing invitations
| shareType | group |
| permissionsRole | <permissions-role> |
Then the HTTP status code should be "200"
And user "Brian" has a share "<resource>" synced
And user "Brian" should have a share "<resource>" shared by user "Alice" from space "NewSpace"
And user "Carol" has a share "<resource>" synced
And user "Carol" should have a share "<resource>" shared by user "Alice" from space "NewSpace"
And the JSON data of the response should match
"""
@@ -3172,7 +3166,6 @@ Feature: Send a sharing invitations
| shareType | user |
| permissionsRole | Viewer |
Then the HTTP status code should be "200"
And user "Brian" has a share "textfile.txt" synced
And user "Brian" should have a share "textfile.txt" shared by user "Alice" from space "NewSpace"
When user "Alice" sends the following resource share invitation using the Graph API:
| resource | textfile.txt |
@@ -3181,7 +3174,6 @@ Feature: Send a sharing invitations
| shareType | group |
| permissionsRole | Viewer |
Then the HTTP status code should be "200"
And user "Carol" has a share "textfile.txt" synced
And user "Carol" should have a share "textfile.txt" shared by user "Alice" from space "NewSpace"
@@ -3201,5 +3193,4 @@ Feature: Send a sharing invitations
| shareType | group |
| permissionsRole | Viewer |
Then the HTTP status code should be "200"
And user "Brian" has a share "textfile.txt" synced
And user "Brian" should have a share "textfile.txt" shared by user "Alice" from space "NewSpace"

View File

@@ -19,7 +19,7 @@ Feature: Update permission of a share
| sharee | Brian |
| shareType | user |
| permissionsRole | Viewer |
| expirationDateTime | 2027-07-15T14:00:00Z |
| expirationDateTime | 2025-07-15T14:00:00Z |
When user "Alice" updates the last resource share with the following properties using the Graph API:
| space | Personal |
| resource | testfile.txt |
@@ -91,7 +91,7 @@ Feature: Update permission of a share
| sharee | Brian |
| shareType | user |
| permissionsRole | Viewer |
| expirationDateTime | 2027-07-15T14:00:00Z |
| expirationDateTime | 2025-07-15T14:00:00Z |
When user "Alice" updates the last resource share with the following properties using the Graph API:
| space | Personal |
| resource | <resource> |
@@ -394,7 +394,7 @@ Feature: Update permission of a share
| sharee | grp1 |
| shareType | group |
| permissionsRole | <permissions-role> |
| expirationDateTime | 2027-07-15T14:00:00Z |
| expirationDateTime | 2025-07-15T14:00:00Z |
When user "Alice" updates the last drive share with the following using root endpoint of the Graph API:
| permissionsRole | <new-permissions-role> |
| space | NewSpace |
@@ -474,7 +474,7 @@ Feature: Update permission of a share
| sharee | grp1 |
| shareType | group |
| permissionsRole | <permissions-role> |
| expirationDateTime | 2027-07-15T14:00:00Z |
| expirationDateTime | 2025-07-15T14:00:00Z |
When user "Alice" updates the last drive share with the following using root endpoint of the Graph API:
| expirationDateTime | |
| space | NewSpace |
@@ -554,7 +554,7 @@ Feature: Update permission of a share
| sharee | grp1 |
| shareType | group |
| permissionsRole | <permissions-role> |
| expirationDateTime | 2027-07-15T14:00:00Z |
| expirationDateTime | 2025-07-15T14:00:00Z |
When user "Alice" updates the last drive share with the following using root endpoint of the Graph API:
| expirationDateTime | 2200-07-15T14:00:00Z |
| space | NewSpace |
@@ -636,7 +636,7 @@ Feature: Update permission of a share
| sharee | grp1 |
| shareType | group |
| permissionsRole | <permissions-role> |
| expirationDateTime | 2027-07-15T14:00:00Z |
| expirationDateTime | 2025-07-15T14:00:00Z |
When user "Alice" updates the last drive share with the following using root endpoint of the Graph API:
| expirationDateTime | |
| permissionsRole | <new-permissions-role> |
@@ -717,7 +717,7 @@ Feature: Update permission of a share
| sharee | grp1 |
| shareType | group |
| permissionsRole | <permissions-role> |
| expirationDateTime | 2027-07-15T14:00:00Z |
| expirationDateTime | 2025-07-15T14:00:00Z |
When user "Alice" updates the last drive share with the following using root endpoint of the Graph API:
| expirationDateTime | 2200-07-15T14:00:00Z |
| permissionsRole | <new-permissions-role> |
@@ -799,7 +799,7 @@ Feature: Update permission of a share
| sharee | Brian |
| shareType | user |
| permissionsRole | <permissions-role> |
| expirationDateTime | 2027-07-15T14:00:00Z |
| expirationDateTime | 2025-07-15T14:00:00Z |
When user "Alice" updates the last drive share with the following using root endpoint of the Graph API:
| permissionsRole | <new-permissions-role> |
| space | NewSpace |
@@ -875,7 +875,7 @@ Feature: Update permission of a share
| sharee | Brian |
| shareType | user |
| permissionsRole | <permissions-role> |
| expirationDateTime | 2027-07-15T14:00:00Z |
| expirationDateTime | 2025-07-15T14:00:00Z |
When user "Alice" updates the last drive share with the following using root endpoint of the Graph API:
| expirationDateTime | |
| space | NewSpace |
@@ -951,7 +951,7 @@ Feature: Update permission of a share
| sharee | Brian |
| shareType | user |
| permissionsRole | <permissions-role> |
| expirationDateTime | 2027-07-15T14:00:00Z |
| expirationDateTime | 2025-07-15T14:00:00Z |
When user "Alice" updates the last drive share with the following using root endpoint of the Graph API:
| expirationDateTime | 2200-07-15T14:00:00Z |
| permissionsRole | <new-permissions-role> |
@@ -1033,7 +1033,7 @@ Feature: Update permission of a share
| sharee | Brian |
| shareType | user |
| permissionsRole | <permissions-role> |
| expirationDateTime | 2027-07-15T14:00:00Z |
| expirationDateTime | 2025-07-15T14:00:00Z |
When user "Alice" updates the last drive share with the following using root endpoint of the Graph API:
| expirationDateTime | |
| permissionsRole | <new-permissions-role> |
@@ -1110,7 +1110,7 @@ Feature: Update permission of a share
| sharee | Brian |
| shareType | user |
| permissionsRole | <permissions-role> |
| expirationDateTime | 2027-07-15T14:00:00Z |
| expirationDateTime | 2025-07-15T14:00:00Z |
When user "Alice" updates the last drive share with the following using root endpoint of the Graph API:
| expirationDateTime | 2200-07-15T14:00:00Z |
| permissionsRole | <new-permissions-role> |

View File

@@ -21,7 +21,6 @@ Feature: sharing
| shareType | user |
| permissionsRole | Viewer |
And using SharingNG
And user "Brian" has a share "textfile0.txt" synced
When user "Brian" gets all the shares shared with him using the sharing API
Then the OCS status code should be "<ocs-status-code>"
And the HTTP status code should be "200"
@@ -48,8 +47,6 @@ Feature: sharing
| shareType | user |
| permissionsRole | Viewer |
And using SharingNG
And user "Brian" has a share "textfile0.txt" synced
And user "Brian" has a share "textfile1.txt" synced
When user "Brian" gets all the shares shared with him that are received as file "/Shares/textfile1.txt" using the provisioning API
Then the OCS status code should be "<ocs-status-code>"
And the HTTP status code should be "200"
@@ -76,8 +73,6 @@ Feature: sharing
| shareType | user |
| permissionsRole | Viewer |
And using SharingNG
And user "Brian" has a share "textfile0.txt" synced
And user "Brian" has a share "textfile1.txt" synced
When user "Brian" gets all the shares shared with him that are received as file "/Shares/textfile0.txt" using the provisioning API
Then the OCS status code should be "<ocs-status-code>"
And the HTTP status code should be "200"
@@ -99,7 +94,6 @@ Feature: sharing
| shareType | group |
| permissionsRole | Viewer |
And using SharingNG
And user "Brian" has a share "textfile0.txt" synced
When user "Brian" gets all the shares shared with him using the sharing API
Then the OCS status code should be "<ocs-status-code>"
And the HTTP status code should be "200"

View File

@@ -567,52 +567,3 @@ Feature: restore deleted files/folders
| dav-path-version |
| spaces |
| new |
@issue-1523
Scenario Outline: restore deleted folder when folder with same name exists
Given using <dav-path-version> DAV path
And user "Alice" has created folder "new"
And user "Alice" has uploaded file with content "content" to "new/test.txt"
And user "Alice" has deleted folder "new"
And user "Alice" has created folder "new"
And user "Alice" has uploaded file with content "new content" to "new/new-file.txt"
When user "Alice" restores the folder with original path "/new" to "/new (1)" using the trashbin API
Then the HTTP status code should be "201"
And as "Alice" the following folders should exist
| path |
| /new |
| /new (1) |
And as "Alice" the following files should exist
| path |
| /new/new-file.txt |
| /new (1)/test.txt |
Examples:
| dav-path-version |
| spaces |
| new |
@issue-1523
Scenario Outline: restore deleted folder with files when folder with same name exists
Given using <dav-path-version> DAV path
And user "Alice" has created folder "folder-a"
And user "Alice" has uploaded file with content "content b" to "folder-a/b.txt"
And user "Alice" has uploaded file with content "content c" to "folder-a/c.txt"
And user "Alice" has deleted file "folder-a/b.txt"
And user "Alice" has deleted folder "folder-a"
And user "Alice" has created folder "folder-a"
When user "Alice" restores the file with original path "folder-a/b.txt" using the trashbin API
Then the HTTP status code should be "201"
When user "Alice" restores the folder with original path "/folder-a" to "/folder-a (1)" using the trashbin API
Then the HTTP status code should be "201"
And as "Alice" the following folders should exist
| path |
| /folder-a |
| /folder-a (1) |
And as "Alice" the following files should exist
| path |
| /folder-a/b.txt |
| /folder-a (1)/c.txt |
Examples:
| dav-path-version |
| spaces |
| new |

View File

@@ -261,11 +261,10 @@ function run_behat_tests() {
FAILED_SCENARIO_PATHS_COLORED=`awk '/Failed scenarios:/',0 ${TEST_LOG_FILE} | grep -a feature`
# There will be some ANSI escape codes for color in the FEATURE_COLORED var.
# Strip them out so we can pass just the ordinary feature details to Behat.
# Also strip everything after ".feature:XX", including text such as "(on line xx)" added by Behat indicating the failing step's line number.
# Thanks to https://en.wikipedia.org/wiki/Tee_(command) and
# https://stackoverflow.com/questions/23416278/how-to-strip-ansi-escape-sequences-from-a-variable
# for ideas.
FAILED_SCENARIO_PATHS=$(echo "${FAILED_SCENARIO_PATHS_COLORED}" | sed "s/\x1b[^m]*m//g" | sed 's/\(\.feature:[0-9]\+\).*/\1/')
FAILED_SCENARIO_PATHS=$(echo "${FAILED_SCENARIO_PATHS_COLORED}" | sed "s/\x1b[^m]*m//g")
# If something else went wrong, and there were no failed scenarios,
# then the awk, grep, sed command sequence above ends up with an empty string.

View File

@@ -8,7 +8,7 @@
}
},
"require": {
"behat/behat": "^3.24",
"behat/behat": "^3.13",
"behat/gherkin": "^4.9",
"behat/mink": "1.7.1",
"friends-of-behat/mink-extension": "^2.7",

View File

@@ -20,21 +20,13 @@
package blobstore
import (
"context"
"fmt"
"bufio"
"io"
"os"
"path/filepath"
"time"
"github.com/pkg/errors"
"github.com/pkg/xattr"
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/node"
)
const (
TMPDir = ".oc-tmp"
"github.com/pkg/errors"
)
// Blobstore provides an interface to an filesystem based blobstore
@@ -49,106 +41,61 @@ func New(root string) (*Blobstore, error) {
}, nil
}
// Upload is responsible for transferring data from a source file (upload) to its final location;
// the file operation is done atomically using a temporary file followed by a rename
func (bs *Blobstore) Upload(n *node.Node, source, copyTarget string) error {
tempName := filepath.Join(n.SpaceRoot.InternalPath(), TMPDir, filepath.Base(source))
// Upload stores some data in the blobstore under the given key
func (bs *Blobstore) Upload(node *node.Node, source, copyTarget string) error {
path := node.InternalPath()
// there is no guarantee that the space root TMPDir exists at this point, so we create the directory if needed
if err := os.MkdirAll(filepath.Dir(tempName), 0700); err != nil {
// preserve the mtime of the file
fi, _ := os.Stat(path)
file, err := os.Open(source)
if err != nil {
return errors.Wrap(err, "Decomposedfs: posix blobstore: Can not open source file to upload")
}
defer file.Close()
f, err := os.OpenFile(node.InternalPath(), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0700)
if err != nil {
return errors.Wrapf(err, "could not open blob '%s' for writing", node.InternalPath())
}
defer f.Close()
w := bufio.NewWriter(f)
_, err = w.ReadFrom(file)
if err != nil {
return errors.Wrapf(err, "could not write blob '%s'", node.InternalPath())
}
err = w.Flush()
if err != nil {
return err
}
err = os.Chtimes(path, fi.ModTime(), fi.ModTime())
if err != nil {
return err
}
sourceFile, err := os.Open(source)
if err != nil {
return fmt.Errorf("failed to open source file '%s': %v", source, err)
}
defer func() {
_ = sourceFile.Close()
}()
tempFile, err := os.OpenFile(tempName, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0700)
if err != nil {
return fmt.Errorf("unable to create temp file '%s': %v", tempName, err)
}
if _, err := tempFile.ReadFrom(sourceFile); err != nil {
return fmt.Errorf("failed to write data from source file '%s' to temp file '%s' - %v", source, tempName, err)
}
if err := tempFile.Sync(); err != nil {
return fmt.Errorf("failed to sync temp file '%s' - %v", tempName, err)
}
if err := tempFile.Close(); err != nil {
return fmt.Errorf("failed to close temp file '%s' - %v", tempName, err)
}
nodeAttributes, err := n.Xattrs(context.Background())
if err != nil {
return fmt.Errorf("failed to get xattrs for node '%s': %v", n.InternalPath(), err)
}
var mtime *time.Time
for k, v := range nodeAttributes {
if err := xattr.Set(tempName, k, v); err != nil {
return fmt.Errorf("failed to set xattr '%s' on temp file '%s' - %v", k, tempName, err)
if copyTarget != "" {
// also "upload" the file to a local path, e.g. for keeping the "current" version of the file
err := os.MkdirAll(filepath.Dir(copyTarget), 0700)
if err != nil {
return err
}
if k == "user.oc.mtime" {
tv, err := time.Parse(time.RFC3339Nano, string(v))
if err == nil {
mtime = &tv
}
}
}
// the extended attributes should always contain a mtime, but in case they don't, we fetch it from the node
if mtime == nil {
switch nodeMtime, err := n.GetMTime(context.Background()); {
case err != nil:
return fmt.Errorf("failed to get mtime for node '%s' - %v", n.InternalPath(), err)
default:
mtime = &nodeMtime
_, err = file.Seek(0, 0)
if err != nil {
return err
}
}
copyFile, err := os.OpenFile(copyTarget, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
if err != nil {
return errors.Wrapf(err, "could not open copy target '%s' for writing", copyTarget)
}
defer copyFile.Close()
// etags rely on the id and the mtime, so we need to ensure the mtime is set correctly
if err := os.Chtimes(tempName, *mtime, *mtime); err != nil {
return fmt.Errorf("failed to set mtime on temp file '%s' - %v", tempName, err)
}
// atomically move the file to its final location,
// on Windows systems (unsupported oc os) os.Rename is not atomic
if err := os.Rename(tempName, n.InternalPath()); err != nil {
return fmt.Errorf("failed to move temp file '%s' to node '%s' - %v", tempName, n.InternalPath(), err)
}
// upload successfully, now handle the copy target if set
if copyTarget == "" {
return nil
}
// also "upload" the file to a local path, e.g., for keeping the "current" version of the file
if err := os.MkdirAll(filepath.Dir(copyTarget), 0700); err != nil {
return err
}
if _, err := sourceFile.Seek(0, 0); err != nil {
return err
}
copyFile, err := os.OpenFile(copyTarget, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
if err != nil {
return errors.Wrapf(err, "could not open copy target '%s' for writing", copyTarget)
}
defer func() {
_ = copyFile.Close()
}()
if _, err := copyFile.ReadFrom(sourceFile); err != nil {
return errors.Wrapf(err, "could not write blob copy of '%s' to '%s'", n.InternalPath(), copyTarget)
_, err = copyFile.ReadFrom(file)
if err != nil {
return errors.Wrapf(err, "could not write blob copy of '%s' to '%s'", node.InternalPath(), copyTarget)
}
}
return nil

View File

@@ -32,7 +32,6 @@ import (
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/opencloud-eu/reva/v2/pkg/errtypes"
"github.com/opencloud-eu/reva/v2/pkg/storage"
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/lookup"
@@ -334,12 +333,10 @@ func (tb *Trashbin) RestoreRecycleItem(ctx context.Context, spaceID string, key,
return nil, fmt.Errorf("trashbin: parent id not found for %s", restorePath)
}
trashedNode := &trashNode{spaceID: spaceID, id: id, path: trashPath}
if err = tb.lu.MetadataBackend().SetMultiple(ctx, trashedNode, map[string][]byte{
prefixes.NameAttr: []byte(filepath.Base(restorePath)),
prefixes.ParentidAttr: []byte(parentID),
}, true); err != nil {
return nil, fmt.Errorf("posixfs: failed to update trashed node metadata: %w", err)
trashNode := &trashNode{spaceID: spaceID, id: id, path: trashPath}
err = tb.lu.MetadataBackend().Set(ctx, trashNode, prefixes.ParentidAttr, []byte(parentID))
if err != nil {
return nil, err
}
// restore the item

View File

@@ -38,11 +38,9 @@ import (
"golang.org/x/sync/errgroup"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"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/lookup"
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options"
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/trashbin"
@@ -651,10 +649,6 @@ func (t *Tree) createDirNode(ctx context.Context, n *node.Node) (err error) {
return n.SetXattrsWithContext(ctx, attributes, false)
}
func (t *Tree) isTemporary(path string) bool {
return path == blobstore.TMPDir
}
func (t *Tree) isIgnored(path string) bool {
return isLockFile(path) || isTrash(path) || t.isUpload(path) || t.isInternal(path)
}
@@ -670,7 +664,7 @@ func (t *Tree) isIndex(path string) bool {
func (t *Tree) isInternal(path string) bool {
return path == t.options.Root ||
path == filepath.Join(t.options.Root, "users") ||
t.isIndex(path) || strings.Contains(path, lookup.MetadataDir) || t.isTemporary(path)
t.isIndex(path) || strings.Contains(path, lookup.MetadataDir)
}
func isLockFile(path string) bool {

View File

@@ -286,17 +286,6 @@ func (session *DecomposedFsSession) Finalize(ctx context.Context) (err error) {
revisionNode := node.New(session.SpaceID(), session.NodeID(), "", "", session.Size(), session.ID(),
provider.ResourceType_RESOURCE_TYPE_FILE, session.SpaceOwner(), session.store.lu)
switch spaceRoot, err := session.store.lu.NodeFromSpaceID(ctx, session.SpaceID()); {
case err != nil:
return fmt.Errorf("failed to get space root for space id %s: %v", session.SpaceID(), err)
case spaceRoot == nil:
return fmt.Errorf("space root for space id %s not found", session.SpaceID())
case spaceRoot.InternalPath() == "":
return fmt.Errorf("space root for space id %s has no valid internal path", session.SpaceID())
default:
revisionNode.SpaceRoot = spaceRoot
}
// upload the data to the blobstore
_, subspan := tracer.Start(ctx, "WriteBlob")
err = session.store.tp.WriteBlob(revisionNode, session.binPath())

2
vendor/modules.txt vendored
View File

@@ -1198,7 +1198,7 @@ github.com/open-policy-agent/opa/v1/types
github.com/open-policy-agent/opa/v1/util
github.com/open-policy-agent/opa/v1/util/decoding
github.com/open-policy-agent/opa/v1/version
# github.com/opencloud-eu/reva/v2 v2.29.5
# github.com/opencloud-eu/reva/v2 v2.29.4
## explicit; go 1.24.1
github.com/opencloud-eu/reva/v2/cmd/revad/internal/grace
github.com/opencloud-eu/reva/v2/cmd/revad/runtime