-
Notifications
You must be signed in to change notification settings - Fork 158
Description
Describe the bug
With STORAGE_USERS_POSIX_WATCH_FS=true, when a user changes a file on-disk while a file with the same name is upload via WebDAV and still being stuck in post-processing the attributes of the file can get corrupted.
The easiest way to reproduce this is to run the features/collaborativePosix/collaborativePosixFS.feature:55 with a prolonged POSTPROCESSING_DELAY.
Steps to reproduce
- Start the server with ocwrapper and an increase postprocessing delay:
POSTPROCESSING_DELAY=10s tests/ocwrapper/bin/ocwrapper serve --bin=/work/opencloud/opencloud/bin/opencloud - run the above mentioned test:
TEST_SERVER_URL="https://localhost:9200" BEHAT_FEATURE=tests/acceptance/features/collaborativePosix/collaborativePosixFS.feature:55 make test-acceptance-api - Test fails
The test upload a test file with the content contentnew via webdav, then tries to append the string new via normal via system filesystem operations. And finally tries to verify the updated content again via webdav. The content returned via webdav is now con (❗).
Looking into the file on disk shows that the content is actually content (the original uploaded content), but the metadata of the file has the wrong size:
xattr -l .....
...
user.oc.blobid: f524fa38-1c8a-4eab-800f-a7e62bc7ffd3
user.oc.mtime: 2025-11-03T11:30:43.300589087Z
user.oc.parentid: 9d8f3ec4-a587-41c9-a179-8e09fdf44f89
user.oc.blobsize: 3
user.oc.id: 784bca5f-6d9a-4bb8-92ce-5dda1c2cee0c
user.oc.type: 1
user.oc.name: test.txt
The problem is also reproducible when running the above steps manually. (The manual update on disk needs to happen before the POSTPROCESSING finished)
Expected behavior
The file metadata should match the file content, whether the expected content is content or contentnew depends on whether we change happens before or during postprocessing. I'd argue that if the change happens while the file is still being processed it is ok to have the content reverted to content as long as the metadata stays consistent.
Actual behavior
Metadata and actually file disagree about the length.
test output:
Feature: create a resources using collaborative posixfs
Background: # /work/opencloud/tests/acceptance/features/collaborativePosix/collaborativePosixFS.feature:4
Given the config "STORAGE_USERS_POSIX_WATCH_FS" has been set to "true" # OcConfigContext::theConfigHasBeenSetTo()
And user "Alice" has been created with default attributes # FeatureContext::userHasBeenCreatedWithDefaultAttributes()
And user "Alice" has created folder "/firstFolder" # FeatureContext::userHasCreatedFolder()
Scenario: edit file # /work/opencloud/tests/acceptance/features/collaborativePosix/collaborativePosixFS.feature:55
Given user "Alice" has uploaded file with content "content" to "test.txt" # FeatureContext::userHasUploadedAFileWithContentTo()
When the administrator puts the content "new" into the file "test.txt" in the POSIX storage folder of user "Alice" # CliContext::theAdministratorChangesFileContent()
Then the content of file "/test.txt" for user "Alice" should be "contentnew" # FeatureContext::contentOfFileForUserShouldBe()
│ ### RESPONSE
│ Status: 425
│ Headers:
│ Content-Length: 0
│ Content-Security-Policy: child-src 'self'; connect-src 'self' blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; default-src 'none'; font-src 'self'; frame-ancestors 'self'; frame-src 'self' blob: https://embed.diagrams.net/; img-src 'self' data: blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; manifest-src 'self'; media-src 'self'; object-src 'self' blob:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
│ Date: Mon, 03 Nov 2025 12:39:10 GMT
│ Referrer-Policy: strict-origin-when-cross-origin
│ Strict-Transport-Security: max-age=315360000; preload
│ Vary: Origin
│ X-Content-Type-Options: nosniff
│ X-Frame-Options: SAMEORIGIN
│ X-Permitted-Cross-Domain-Policies: none
│ X-Request-Id: aaa0fe5e9d2a/MRPx71Ttfw-000032
│ X-Robots-Tag: none
│ X-Xss-Protection: 1; mode=block
│ Body:
│ string(0) ""
│
│ ### END RESPONSE
│ ### RESPONSE
│ Status: 425
│ Headers:
│ Content-Length: 0
│ Content-Security-Policy: child-src 'self'; connect-src 'self' blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; default-src 'none'; font-src 'self'; frame-ancestors 'self'; frame-src 'self' blob: https://embed.diagrams.net/; img-src 'self' data: blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; manifest-src 'self'; media-src 'self'; object-src 'self' blob:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
│ Date: Mon, 03 Nov 2025 12:39:11 GMT
│ Referrer-Policy: strict-origin-when-cross-origin
│ Strict-Transport-Security: max-age=315360000; preload
│ Vary: Origin
│ X-Content-Type-Options: nosniff
│ X-Frame-Options: SAMEORIGIN
│ X-Permitted-Cross-Domain-Policies: none
│ X-Request-Id: aaa0fe5e9d2a/MRPx71Ttfw-000034
│ X-Robots-Tag: none
│ X-Xss-Protection: 1; mode=block
│ Body:
│ string(0) ""
│
│ ### END RESPONSE
│ ### RESPONSE
│ Status: 425
│ Headers:
│ Content-Length: 0
│ Content-Security-Policy: child-src 'self'; connect-src 'self' blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; default-src 'none'; font-src 'self'; frame-ancestors 'self'; frame-src 'self' blob: https://embed.diagrams.net/; img-src 'self' data: blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; manifest-src 'self'; media-src 'self'; object-src 'self' blob:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
│ Date: Mon, 03 Nov 2025 12:39:12 GMT
│ Referrer-Policy: strict-origin-when-cross-origin
│ Strict-Transport-Security: max-age=315360000; preload
│ Vary: Origin
│ X-Content-Type-Options: nosniff
│ X-Frame-Options: SAMEORIGIN
│ X-Permitted-Cross-Domain-Policies: none
│ X-Request-Id: aaa0fe5e9d2a/MRPx71Ttfw-000036
│ X-Robots-Tag: none
│ X-Xss-Protection: 1; mode=block
│ Body:
│ string(0) ""
│
│ ### END RESPONSE
│ ### RESPONSE
│ Status: 425
│ Headers:
│ Content-Length: 0
│ Content-Security-Policy: child-src 'self'; connect-src 'self' blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; default-src 'none'; font-src 'self'; frame-ancestors 'self'; frame-src 'self' blob: https://embed.diagrams.net/; img-src 'self' data: blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; manifest-src 'self'; media-src 'self'; object-src 'self' blob:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
│ Date: Mon, 03 Nov 2025 12:39:13 GMT
│ Referrer-Policy: strict-origin-when-cross-origin
│ Strict-Transport-Security: max-age=315360000; preload
│ Vary: Origin
│ X-Content-Type-Options: nosniff
│ X-Frame-Options: SAMEORIGIN
│ X-Permitted-Cross-Domain-Policies: none
│ X-Request-Id: aaa0fe5e9d2a/MRPx71Ttfw-000038
│ X-Robots-Tag: none
│ X-Xss-Protection: 1; mode=block
│ Body:
│ string(0) ""
│
│ ### END RESPONSE
│ ### RESPONSE
│ Status: 425
│ Headers:
│ Content-Length: 0
│ Content-Security-Policy: child-src 'self'; connect-src 'self' blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; default-src 'none'; font-src 'self'; frame-ancestors 'self'; frame-src 'self' blob: https://embed.diagrams.net/; img-src 'self' data: blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; manifest-src 'self'; media-src 'self'; object-src 'self' blob:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
│ Date: Mon, 03 Nov 2025 12:39:14 GMT
│ Referrer-Policy: strict-origin-when-cross-origin
│ Strict-Transport-Security: max-age=315360000; preload
│ Vary: Origin
│ X-Content-Type-Options: nosniff
│ X-Frame-Options: SAMEORIGIN
│ X-Permitted-Cross-Domain-Policies: none
│ X-Request-Id: aaa0fe5e9d2a/MRPx71Ttfw-000040
│ X-Robots-Tag: none
│ X-Xss-Protection: 1; mode=block
│ Body:
│ string(0) ""
│
│ ### END RESPONSE
│ ### RESPONSE
│ Status: 425
│ Headers:
│ Content-Length: 0
│ Content-Security-Policy: child-src 'self'; connect-src 'self' blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; default-src 'none'; font-src 'self'; frame-ancestors 'self'; frame-src 'self' blob: https://embed.diagrams.net/; img-src 'self' data: blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; manifest-src 'self'; media-src 'self'; object-src 'self' blob:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
│ Date: Mon, 03 Nov 2025 12:39:15 GMT
│ Referrer-Policy: strict-origin-when-cross-origin
│ Strict-Transport-Security: max-age=315360000; preload
│ Vary: Origin
│ X-Content-Type-Options: nosniff
│ X-Frame-Options: SAMEORIGIN
│ X-Permitted-Cross-Domain-Policies: none
│ X-Request-Id: aaa0fe5e9d2a/MRPx71Ttfw-000042
│ X-Robots-Tag: none
│ X-Xss-Protection: 1; mode=block
│ Body:
│ string(0) ""
│
│ ### END RESPONSE
│ ### RESPONSE
│ Status: 425
│ Headers:
│ Content-Length: 0
│ Content-Security-Policy: child-src 'self'; connect-src 'self' blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; default-src 'none'; font-src 'self'; frame-ancestors 'self'; frame-src 'self' blob: https://embed.diagrams.net/; img-src 'self' data: blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; manifest-src 'self'; media-src 'self'; object-src 'self' blob:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
│ Date: Mon, 03 Nov 2025 12:39:16 GMT
│ Referrer-Policy: strict-origin-when-cross-origin
│ Strict-Transport-Security: max-age=315360000; preload
│ Vary: Origin
│ X-Content-Type-Options: nosniff
│ X-Frame-Options: SAMEORIGIN
│ X-Permitted-Cross-Domain-Policies: none
│ X-Request-Id: aaa0fe5e9d2a/MRPx71Ttfw-000044
│ X-Robots-Tag: none
│ X-Xss-Protection: 1; mode=block
│ Body:
│ string(0) ""
│
│ ### END RESPONSE
│ ### RESPONSE
│ Status: 425
│ Headers:
│ Content-Length: 0
│ Content-Security-Policy: child-src 'self'; connect-src 'self' blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; default-src 'none'; font-src 'self'; frame-ancestors 'self'; frame-src 'self' blob: https://embed.diagrams.net/; img-src 'self' data: blob: https://raw.githubusercontent.com/opencloud-eu/awesome-apps/; manifest-src 'self'; media-src 'self'; object-src 'self' blob:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
│ Date: Mon, 03 Nov 2025 12:39:17 GMT
│ Referrer-Policy: strict-origin-when-cross-origin
│ Strict-Transport-Security: max-age=315360000; preload
│ Vary: Origin
│ X-Content-Type-Options: nosniff
│ X-Frame-Options: SAMEORIGIN
│ X-Permitted-Cross-Domain-Policies: none
│ X-Request-Id: aaa0fe5e9d2a/MRPx71Ttfw-000046
│ X-Robots-Tag: none
│ X-Xss-Protection: 1; mode=block
│ Body:
│ string(0) ""
│
│ ### END RESPONSE
│
The content was expected to be 'contentnew', but actually is 'con'. HTTP status was 200
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'contentnew'
+'con'Metadata
Metadata
Assignees
Labels
Type
Projects
Status