Skip to content

Switch to FileMetadata to use statx instead of stat on Linux and Apple platforms#1772

Merged
swankjesse merged 7 commits intomasterfrom
jwilson.0205.birthtime
Mar 11, 2026
Merged

Switch to FileMetadata to use statx instead of stat on Linux and Apple platforms#1772
swankjesse merged 7 commits intomasterfrom
jwilson.0205.birthtime

Conversation

@swankjesse
Copy link
Copy Markdown
Collaborator

@MohammedKHC
Copy link
Copy Markdown
Contributor

This is good!
But also I think that we may use statx call on Linux.
It's only downside is that we need to use custom cinterop. and check if it's available at runtime..

Please refer to this code
https://github.com/MohammadKHC/mokio/blob/main/mokio/src/linuxMain/kotlin/metadata/FileMetadata.linux.kt#L40
and
https://github.com/MohammadKHC/mokio/blob/main/mokio/src/nativeInterop/linux/statx.def

And if we couldn't use statx then we should really let the creation time be mtime.. as in some cases (ex, modifying the file permissions) will make ctime newer than mtime!

* createdAt: 2026-01-01T01:01:01Z
* lastModifiedAt: 2026-02-02T02:02:02Z
*
* It would be nicer to do this in the test itself with exec(), but we don't yet have a handy
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What if okio provided an api to set file attributes?
Maybe something like this
https://github.com/MohammadKHC/mokio/blob/main/mokio/src/commonMain/kotlin/metadata/FileAttribute.kt

Although iam sure that you can even do better than it.
Iam really bad at writing documentation for things. I usually just leave the code as is..

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I don’t believe that it’s an API many people want?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Some background here, where I argue that files are less frequently UI and therefore setting metadata is not as useful as it once was.

There is definitely a use for it, but it’s difficult to do well. For example, I don’t believe cloud file systems do a particularly good job of preserving metadata!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I read your article, and I mostly agree with it.

It’s not just cloud file systems that don’t preserve file metadata—Git doesn’t either. Aside from whether a file is executable, Git ignores file metadata entirely.

https://softwareengineering.stackexchange.com/questions/350403/why-doesnt-git-set-the-file-time
https://superuser.com/a/1422661

That said, I think that we do need to support at least one piece of metadata: whether a file is executable.
This is very common on Unix systems.

Setting file creation or last-modified times only really makes sense for things like restoring family photo dates in the gallery 😄

And other attributes don’t seem necessary unless you’re building something very specialized.

However they are kinda nice to have in a filesystem API!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, they are nice to have in a FileSystem API. I certainly prefer metadata over access control!

@swankjesse
Copy link
Copy Markdown
Collaborator Author

@MohammadKHC your mokio project is rad!

I hope you don’t mind I’d like to copy your Process class (and the code that supports it) into okio-testing-support. I want to do processes in our tests! I would like to later promote that code into the main production artifact, but I want to start small by running it in our tests. There’s a lot of little design decisions in these things and I don’t yet have an intuition on how it should work. Forking processes is forbidden on iOS!

@MohammedKHC
Copy link
Copy Markdown
Contributor

@swankjesse

I absolutely don’t mind — and I’m glad you liked Mokio.

I actually built it hoping some parts might eventually be useful for Okio, so feel free to copy the Process class and any supporting code.

There may be some imperfect design decisions, but it works for my use case.

Mokio doesn’t support iOS for the same reason you mentioned: forking processes isn’t supported there. I considered a custom source set or stubs, but I decided it wasn’t worth the extra complexity for my use case.

Happy to see where this goes if it’s promoted later.

Thanks!

@OptIn(UnsafeNumber::class)
internal val timespec.epochMillis: Long
get() = tv_sec * 1000L + tv_sec / 1_000_000L
get() = tv_sec * 1000L + tv_nsec / 1_000_000L
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Longstanding severe bug!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I assume we got away with it cause it's usually zero? Otherwise we wouldn't have passed our tests.

@swankjesse swankjesse changed the title Switch to FileMetadata to use st_birthtimespec on Apple platforms Switch to FileMetadata to use statx instead of stat on Linux and Apple platforms Feb 8, 2026
Comment thread okio/src/linuxMain/kotlin/okio/LinuxPosixVariant.kt Outdated
Comment thread okio/src/linuxMain/headers/okio_statx.h Outdated
Comment thread okio/src/linuxMain/kotlin/okio/LinuxPosixVariant.kt Outdated
Comment thread okio/src/linuxMain/headers/okio_statx.h
@swankjesse swankjesse force-pushed the jwilson.0205.birthtime branch from 43630e5 to ddd7c3f Compare February 9, 2026 04:31
isDirectory = stat.st_mode.toInt() and S_IFMT == S_IFDIR,
symlinkTarget = symlinkTarget(stat.st_mode.toInt(), path),
size = stat.st_size,
createdAtMillis = stat.st_mtim.epochMillis,
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

behavior change from st_ctim

@swankjesse swankjesse marked this pull request as ready for review February 9, 2026 12:38
}

fun fromIso8601String(iso8601String: String): Instant =
Instant.fromEpochMilliseconds(Instant.parse(iso8601String).toEpochMilliseconds())
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why the round trip through millis after parsing?

Copy link
Copy Markdown
Contributor

@MohammedKHC MohammedKHC Feb 10, 2026

Choose a reason for hiding this comment

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

It's probably to ignore some nanosecond precision..
Although I am not sure if it's intentional or not..

Edit: after checking the assertInRange code I think that this is redundant.
Sorry for replying before checking the code 😶‍🌫️

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yep. Just a bug. Fixed!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

(introduced by deleting our commonMain Instant for Wasm)

Comment on lines +45 to +52
/**
* Returns true if the host file system probably exposes metadata like file creation time.
*
* The file system that GitHub actions gives us doesn't do anything when we `touch` a file.
*/
val fileSystemHasGoodMetadata: Boolean
get() = getEnv("GITHUB_WORKSPACE") == null

Copy link
Copy Markdown
Contributor

@MohammedKHC MohammedKHC Feb 10, 2026

Choose a reason for hiding this comment

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

After reviewing the code again, I don’t think this is a GitHub issue.

GNU touch itself does not modify the creation time (and on Linux there’s no way to do that anyway).

Relevant code:
https://github.com/coreutils/coreutils/blob/3d35e82b9b0460769c1966b1ef8acc0b5e5c8348/src/touch.c#L138-L160
https://github.com/coreutils/coreutils/blob/3d35e82b9b0460769c1966b1ef8acc0b5e5c8348/src/touch.c#L218

I’m not sure about macOS and Windows, though.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Ahh, it’s a Linux issue, not a GitHub issue. That makes sense.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I was able to do validate our code worked successfully running Linux in Docker on my Mac, but that would have relied on my Mac’s touch command.

@swankjesse swankjesse force-pushed the jwilson.0205.birthtime branch from ddd7c3f to 069930f Compare March 11, 2026 20:54
@swankjesse swankjesse merged commit 65c0c26 into master Mar 11, 2026
26 of 27 checks passed
@swankjesse swankjesse deleted the jwilson.0205.birthtime branch March 11, 2026 21:44
MohammedKHC added a commit to MohammedKHC/mokio that referenced this pull request Mar 14, 2026
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.

3 participants