Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: First close file channel, then persist lastModified #228

Merged
merged 9 commits into from
Aug 2, 2024

Conversation

infeo
Copy link
Member

@infeo infeo commented Jun 20, 2024

This PR changes the logic of persisting the lastModfied date from before closing the ciphertext channel to afterwards. Additionally, the cryptofs internal lastModifiedDate is always updated, even when persisting to storage fails.

This impl change is motivated by the behaviour of some fs/storage implemenations, which set the lastModified time to "now" when closing a channel, regardless of changes made.

Before merging, we should test the implementation with different scenarios:

OneDrive pCloud GoogleDrive iCloud Dropbox LocalFS
Windows ❓1
macOS
Linux ➖ 2 ➖ 2 ➖ 2 ➖ 2 ➖ 2

The test was to edit and save an spreadsheet/document file and copying files of different sizes into the vault.

1: iCloud on Windows is... strange. First of all, everything copied into the iCloud dir gets as mTime the current time. Inside a Cryptomator vault, this becomes even stranger. Sometimes, the files are set to the current time, but especially bigger files (<30MB) get ... "some" time. "Some" can be the current, the former file mTime or something in between.

2: On Linux there are no offical filesystem integrations. GNOME offers "online account", but these are not accessible from the filesystem.

@infeo infeo self-assigned this Jun 20, 2024
Copy link

coderabbitai bot commented Jun 20, 2024

Walkthrough

Overall, the changes improve the handling of file attributes and channel closures in the Cryptomator project. Key modifications include the restructuring of methods for better readability, the removal of unnecessary exception declarations, and enhanced testability. These adjustments ensure a more robust, maintainable, and test-friendly codebase.

Changes

File Path Change Summary
src/.../CryptoBasicFileAttributeView.java Modified setTimes method to set ciphertext attributes before checking and setting last modified time.
src/.../ChannelCloseListener.java Updated closed method signature to remove throws IOException.
src/.../CleartextFileChannel.java Annotated flush with @VisibleForTesting, refactored implCloseChannel, and added new helper methods.
src/.../OpenCryptoFile.java Refined channelClosed method to ensure correct file closure logic.
src/test/.../CleartextFileChannelTest.java Removed unused imports and adjusted tests for new method signatures and order verification.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CryptoBasicFileAttributeView
    participant Filesystem
    participant CleartextFileChannel
    participant OpenCryptoFile

    User ->> CryptoBasicFileAttributeView: setTimes(lastModifiedTime, lastAccessTime, createTime)
    CryptoBasicFileAttributeView ->> Filesystem: Set ciphertext attributes
    CryptoBasicFileAttributeView ->> OpenCryptoFile: Check and set last modified time
    
    User ->> CleartextFileChannel: Close Channel
    CleartextFileChannel ->> OpenCryptoFile: channelClosed(cleartextFileChannel)
    OpenCryptoFile ->> CleartextFileChannel: Close if no open channels
    CleartextFileChannel ->> Filesystem: Flush and close
Loading

Poem

In Cryptomator's code we delve,
Refactoring methods, oh so swell.
Channels close with graceful ease,
Testing's simpler, bugs appease.
Attributes set, secure and right,
In the codebase, shines the light.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 0682c2a and ecca2a6.

Files selected for processing (5)
  • src/main/java/org/cryptomator/cryptofs/attr/CryptoBasicFileAttributeView.java (1 hunks)
  • src/main/java/org/cryptomator/cryptofs/ch/ChannelCloseListener.java (1 hunks)
  • src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java (2 hunks)
  • src/main/java/org/cryptomator/cryptofs/fh/OpenCryptoFile.java (1 hunks)
  • src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java (5 hunks)
Additional comments not posted (4)
src/main/java/org/cryptomator/cryptofs/ch/ChannelCloseListener.java (1)

7-7: Simplified method signature enhances interface usability.

#!/bin/bash
# Description: Verify that all implementations of `closed` method handle IOException internally if necessary.
rg --type java $'void closed(CleartextFileChannel channel)' -A 10
src/main/java/org/cryptomator/cryptofs/fh/OpenCryptoFile.java (1)

186-192: Improved resource management by ensuring proper channel and file closure.

#!/bin/bash
# Description: Verify that all error scenarios during channel closure are adequately handled.
rg --type java $'channelClosed' -A 20 -B 10
src/test/java/org/cryptomator/cryptofs/ch/CleartextFileChannelTest.java (2)

251-257: Ensure correct order of operations in testCloseCipherChannelCloseBeforePersist.

This test correctly checks the sequence of closing the channel before persisting lastModified, aligning with the PR's intent.


73-73: Ensure the mock path setup is correct and consistent with the expected test environment.

#!/bin/bash
# Description: Check if the mock setup for `filePath` is consistently used across the test suite.
rg --type java --multiline $'Mockito.mock(Path.class, "/foo/bar")' src/test/java/org/cryptomator/cryptofs/ch/

Comment on lines +236 to +237
@VisibleForTesting
void flush() throws IOException {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified testing intent and enhanced data integrity during channel closure.

Would you like me to help in adding or enhancing the unit tests to cover these new scenarios?

Also applies to: 331-342

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between ecca2a6 and e247a2e.

Files selected for processing (1)
  • src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java (2 hunks)
Additional comments not posted (4)
src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java (4)

236-237: LGTM! The @VisibleForTesting annotation is appropriate.

The flush method is now accessible for testing, which is beneficial for verifying the flush logic.


328-331: LGTM! The refactoring improves reliability.

The implCloseChannel method now ensures that implCloseChannelFinally1 is always called, even if an exception occurs during the flush method.


333-340: LGTM! The refactoring improves reliability and readability.

The implCloseChannelFinally1 method ensures that closeListener.closed(this) is always called, even if an exception occurs during the super.implCloseChannel() method. It also ensures that implCloseChannelFinally2 is always called.


342-345: LGTM! The refactoring improves reliability and error handling.

The implCloseChannelFinally2 method ensures that ciphertextFileChannel.close() is always called, even if an exception occurs during the persistLastModified method. The handling of NoSuchFileException and logging of other IOException cases is appropriate.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between e247a2e and 6757801.

Files selected for processing (1)
  • src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java (3 hunks)
Additional comments not posted (1)
src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java (1)

238-239: Visibility change of flush method for testing purposes.

The visibility of the flush method has been changed to package-private and annotated with @VisibleForTesting. This is a good practice as it allows for unit testing of methods that would otherwise be private, enhancing testability without exposing them as part of the public API.

Comment on lines +336 to +343
private void tryPersistLastModified() {
try {
flush();
ciphertextFileChannel.force(true);
persistLastModified();
} catch (NoSuchFileException nsfe) {
//no-op, see https://github.com/cryptomator/cryptofs/issues/169
} catch (IOException e) {
LOG.warn("Failed to persist last modified timestamp for encrypted file: {}", e.getMessage());
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handling of exceptions in tryPersistLastModified.

The method tryPersistLastModified appropriately handles NoSuchFileException by performing no operation, which is a valid approach given the context provided in the linked issue. However, the catch block for IOException logs a warning, which is good, but it might also be beneficial to rethrow the exception to ensure that callers are aware that not all operations completed successfully.

Consider rethrowing the exception after logging to ensure that error handling is consistent and robust across the application.

- LOG.warn("Failed to persist last modified timestamp for encrypted file: {}", e.getMessage());
+ LOG.warn("Failed to persist last modified timestamp for encrypted file: {}", e.getMessage());
+ throw e;
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private void tryPersistLastModified() {
try {
flush();
ciphertextFileChannel.force(true);
persistLastModified();
} catch (NoSuchFileException nsfe) {
//no-op, see https://github.com/cryptomator/cryptofs/issues/169
} catch (IOException e) {
LOG.warn("Failed to persist last modified timestamp for encrypted file: {}", e.getMessage());
}
private void tryPersistLastModified() {
try {
persistLastModified();
} catch (NoSuchFileException nsfe) {
//no-op, see https://github.com/cryptomator/cryptofs/issues/169
} catch (IOException e) {
LOG.warn("Failed to persist last modified timestamp for encrypted file: {}", e.getMessage());
throw e;
}

@infeo infeo merged commit 8d7251a into develop Aug 2, 2024
6 checks passed
@infeo infeo deleted the feature/205-close-before-lastModifiedPersist branch August 2, 2024 11:45
@infeo infeo added this to the next milestone Aug 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants