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

Guard uses of lutimes, for portability #7048

Merged
merged 2 commits into from
Jun 25, 2024
Merged

Conversation

puffnfresh
Copy link
Contributor

Fixes #7045

struct timeval times[2];
times[0].tv_sec = touch_time;
times[0].tv_usec = 0;
times[1].tv_sec = touch_time;
times[1].tv_usec = 0;

return lutimes(path.c_str(), times) == 0;
#else
return false;
Copy link
Contributor Author

@puffnfresh puffnfresh Sep 15, 2022

Choose a reason for hiding this comment

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

Nix emits a warning when this returns false but I have assumed that's acceptable.

Copy link
Member

@thufschmitt thufschmitt left a comment

Choose a reason for hiding this comment

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

Mh, that's sad (and apologies, at least some of these are my doing).

Dropping these is annoying because it can make things non-reproducible (and in a way that Nix might very much not like). Not sure whether there's a good way around this

@@ -76,6 +77,7 @@ void createSymlink(const Path & target, const Path & link,
if (lutimes(link.c_str(), times))
throw SysError("setting time of symlink '%s'", link);
}
#endif
Copy link
Member

Choose a reason for hiding this comment

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

That guard (and the one below which acts on essentially duplicated code :/ ) is a bit annoying because it changes the semantics and affects reproducibility. Do you know whether there's a way to emulate lutimes if it's absent?

Or maybe we can just ignore setting the time for the symlinks if lutimes isn't available and pray that it doesn't matter in practice

Copy link
Contributor

Choose a reason for hiding this comment

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

futimes() is available since glibc 2.3. lutimes() is available since glibc 2.6, and is implemented using the utimensat(2) system call, which is supported since kernel 2.6.22.

Copy link
Contributor

Choose a reason for hiding this comment

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

@jugendhacker Does termux has the mentioned function ?

@Ericson2314
Copy link
Member

Ericson2314 commented Mar 3, 2023

Triaged in the Nix team meeting:

  • @thufschmitt: lutimes is a syscall that's not available everywhere
    • its for getting file timestamps while observing symlinks
    • this is relevant for termux
  • @edolstra: don't really believe in autoconf checks and its philosophy
    • should just have conditionals
  • no decision
  • assigned to @Ericson2314 to try a different approach and make the autoconf checks mandatory for now

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2023-03-03-nix-team-meeting-minutes-37/25998/1

@fricklerhandwerk
Copy link
Contributor

@Ericson2314 and me checked the code, and found #8495 (which you are welcome to implement, it's an almost trivial change).

Other than that, we agree with @thufschmitt. For any remaining occurrences of lutime we should do the following:

  • Factor out a utility function such that all uses of lutime go through it
  • Use lutime if possible, fall back to utime if the file in question is not a symlink, fail with an error message otherwise

Making this PR a draft until these changes are implemented.

@fricklerhandwerk fricklerhandwerk marked this pull request as draft June 12, 2023 12:17
@fricklerhandwerk fricklerhandwerk added the build-problem Nix fails to compile or test; also improvements to build process label Jun 12, 2023
@salpelter salpelter mentioned this pull request Jun 12, 2023
8 tasks
@Ericson2314
Copy link
Member

#8504 removed the dead code, now there are just two lutimes to deduplicate left.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2023-06-12-nix-team-meeting-minutes-62/29315/1

@github-actions github-actions bot added the fetching Networking with the outside (non-Nix) world, input locking label Nov 30, 2023
@fricklerhandwerk fricklerhandwerk marked this pull request as ready for review January 21, 2024 20:02
@fricklerhandwerk
Copy link
Contributor

This should be good to go, @thufschmitt @Ericson2314 do you want to take another look?

Comment on lines 173 to 174
* Whether or not the path is a symlink is taken from the mode of `st`
* in fallback code.
Copy link
Member

Choose a reason for hiding this comment

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

I don't think that precision really makes sense without the context of that PR (what's “fallback mode”?)

Besides that, I don't think we should trust st to tell us whether the file is a symlink or not. Barring possible race conditions (which I think we can't avoid any way), there's no guaranty that st refers to the path at path (might have been a totally made up struct just to set the time, or taken from another file). We should rather re-check within the function (std::filesystem::is_symlink being our friend here I guess)

Copy link
Member

Choose a reason for hiding this comment

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

fallback mode is without lutimes, with just utimes (yes, this should be reworded)

Besides that, I don't think we should trust st to tell us whether the file is a symlink or not.

Note that this is not a new thing. I agree in principle, but how would you update canonicaliseTimestampAndPermissions in practice? It is, already, very geared about working from a prior stat (in a context that we don't think things would change without them looking.

Unless we want to scope creep and overhaul canonicaliseTimestampAndPermissions, I think it would be good to just document the race condition on this function and say callers must be confident st is up to date.

Copy link
Member

Choose a reason for hiding this comment

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

Note that this is not a new thing. I agree in principle, but how would you update canonicaliseTimestampAndPermissions in practice? It is, already, very geared about working from a prior stat (in a context that we don't think things would change without them looking.

That's indeed already the case for canonicaliseTimestampAndPermissions, but I'd rather not also make it the case here when we can just replace the S_ISLNK(st.st_mode) calls by std::filesystem::is_symlink(path)

Copy link
Member

@Ericson2314 Ericson2314 Jun 24, 2024

Choose a reason for hiding this comment

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

OK this is done now. the struct stat way still exists, but is not forced upon everyone else.

@Ericson2314 Ericson2314 force-pushed the lutimes branch 2 times, most recently from fa1ca2e to 9642d2d Compare June 24, 2024 21:28
Copy link
Member

@Ericson2314 Ericson2314 left a comment

Choose a reason for hiding this comment

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

@thufschmitt's request is addressed. All the compat is a bit gnarly, but future improvements are possible.

@Ericson2314 Ericson2314 merged commit d02d38f into NixOS:master Jun 25, 2024
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug build-problem Nix fails to compile or test; also improvements to build process fetching Networking with the outside (non-Nix) world, input locking
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

lutimes not optional
6 participants