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

Add API for setting last accessed and last modified file times #2735

Merged
merged 5 commits into from
Jun 10, 2024

Conversation

gjcairo
Copy link
Contributor

@gjcairo gjcairo commented Jun 5, 2024

This PR adds API to set a file's last accessed and last modified times, as well as a touch() shorthand that updates both to the current time.

Motivation:

Feature request: #2712

Modifications:

This PR adds API to set a file's last accessed and last modified times, as well as a touch() shorthand that updates both to the current time.

Result:

Files' last accessed and last modified times can be updated.

@gjcairo gjcairo requested a review from glbrntt June 5, 2024 16:12
Copy link
Contributor

@glbrntt glbrntt left a comment

Choose a reason for hiding this comment

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

Great start, I think we need to change a couple of minor things though to fit in with how syscalls are done in the rest of the module.

Sources/NIOFileSystem/FileHandleProtocol.swift Outdated Show resolved Hide resolved
Sources/NIOFileSystem/FileHandleProtocol.swift Outdated Show resolved Hide resolved
Sources/NIOFileSystem/FileHandleProtocol.swift Outdated Show resolved Hide resolved
switch errno {
case .permissionDenied, .notPermitted:
code = .permissionDenied
message = "Not permited to change last access or last data modification times for \(path)."
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
message = "Not permited to change last access or last data modification times for \(path)."
message = "Not permitted to change last access or last data modification times for \(path)."

Copy link
Contributor

Choose a reason for hiding this comment

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

^ this one didn't get fixed

Sources/NIOFileSystem/Internal/SystemFileHandle.swift Outdated Show resolved Hide resolved
Sources/NIOFileSystem/Internal/SystemFileHandle.swift Outdated Show resolved Hide resolved
Sources/NIOFileSystem/Internal/SystemFileHandle.swift Outdated Show resolved Hide resolved
Sources/NIOFileSystem/FileHandleProtocol.swift Outdated Show resolved Hide resolved
@glbrntt glbrntt added the semver/minor Adds new public API. label Jun 6, 2024
@gjcairo gjcairo requested a review from glbrntt June 7, 2024 13:03
Copy link
Contributor

@glbrntt glbrntt left a comment

Choose a reason for hiding this comment

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

A few small things need fixing otherwise this looks great!

/// > Important: Times are only considered valid if their nanoseconds components are one of the following:
/// > - `UTIME_NOW` (you can use ``FileInfo/Timespec/now`` to get a Timespec set to this value),
/// > - `UTIME_OMIT` (you can use ``FileInfo/Timespec/omit`` to get a Timespec set to this value),,
/// > - Greater than zero and no larger than 1000 million
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we remove this line as we clamp the value?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought it was better to explain that we will clamp/update the value to the closest valid value instead. Otherwise if people are willingly using an invalid value they could be confused as to why the times are being set to the "wrong" thing. Let me know if you don't agree.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh yeah I'm happy with that.


/// A timespec where the seconds are set to zero and the nanoseconds set to `UTIME_OMIT`.
/// In syscalls such as `futimens`, this means the time component set to this value will be ignored.
public static var omit = Self.init(
Copy link
Contributor

Choose a reason for hiding this comment

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

🚨 public static var alert! 🚨

This should either be a let or a computed property. Same goes for now.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also let's avoid Self.init(...) and just use Self(...)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh god, why did I use var. Good catch.

Copy link
Contributor

Choose a reason for hiding this comment

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

Easily done 🙂

Sources/NIOFileSystem/FileInfo.swift Outdated Show resolved Hide resolved
switch errno {
case .permissionDenied, .notPermitted:
code = .permissionDenied
message = "Not permited to change last access or last data modification times for \(path)."
Copy link
Contributor

Choose a reason for hiding this comment

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

^ this one didn't get fixed

Sources/NIOFileSystem/Internal/SystemFileHandle.swift Outdated Show resolved Hide resolved
Tests/NIOFileSystemTests/FileSystemErrorTests.swift Outdated Show resolved Hide resolved
Copy link
Contributor

@glbrntt glbrntt left a comment

Choose a reason for hiding this comment

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

Looks great, thanks Gus!

@glbrntt
Copy link
Contributor

glbrntt commented Jun 7, 2024

API breakage is expected, we're adding requirements to a protocol, but that's okay NIOFileSystem isn't stable API yet.

Comment on lines +149 to +150
/// If **either** time is `nil`, the current value will not be changed.
/// If **both** times are `nil`, then both times will be set to the current time.
Copy link
Contributor

@MahdiBM MahdiBM Jun 8, 2024

Choose a reason for hiding this comment

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

IMO "clamp/update the value to the closest valid value" is good/fine, but the API design still bothers me.

I would have preferred these 2 lines to have been obvious in the API design.
Perhaps using an (structified) enum as the single parameter that the function accepts. Or anything better. Maybe splitting up the responsibility into 2/3 different functions.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's clear from setTimes(lastAccess: t) that lastDataModification isn't modified.

It's fair to say though that setting both to nil isn't an obvious API: setTimes(lastAccess: nil, lastDataModification: nil) but that's why we also have the touch() wrapper which many developers are familiar with.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we had separate methods for each, we'd unavoidably have to make two separate sys calls, which is expensive. We'd also not be setting the times to the exact same value, as the current time will have changed if we use the UTIME_NOW timespec.

However, I've added two new convenience methods that default one of the parameters to nil to have nicer API: setLastAccessTime(to:) and setLastDataModificationTime(to:).

@glbrntt
Copy link
Contributor

glbrntt commented Jun 10, 2024

@swift-server-bot test this please

@glbrntt glbrntt merged commit bc16180 into apple:main Jun 10, 2024
7 of 9 checks passed
@gjcairo gjcairo deleted the touch-api branch June 10, 2024 16:11
chkp-aviads added a commit to chkp-aviads/swift-nio that referenced this pull request Jul 21, 2024
* commit 'fc79798d5a150d61361a27ce0c51169b889e23de':
  NIOSendableBox: allow off-loop initialisation iff Value is Sendable (apple#2753)
  Throw an appropriate error from the writer when the channel closed (apple#2744)
  put snippet code inside @available function (apple#2750)
  fix link to NIOFileSystem from NIO index page (apple#2747)
  convert the NIOFileSystem example code to a Snippet (apple#2746)
  Silence warning about missing include in macOS builds (apple#2741)
  Correctly mark 304 as not having a response body (apple#2737)
  Update availability guard (apple#2739)
  Add API for setting last accessed and last modified file times (apple#2735)
  Add a fallback path if renameat2 fails (apple#2733)
  Release file handles back to caller on failure to take ownership (apple#2715)
  Add a version of 'write' for 'ByteBuffer' (apple#2730)
  Imrprove rename error (apple#2731)
  Remove storage indirection for FileSystemError (apple#2726)
  testSimpleMPTCP should not fail for ENOPROTOOPT (apple#2725)
  Fix race in TCPThroughputBenchmark (apple#2724)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver/minor Adds new public API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants