Skip to content

Make file_info record into a native record#648

Open
garazdawi wants to merge 11 commits into
masterfrom
lukas/kernel/native-file_info
Open

Make file_info record into a native record#648
garazdawi wants to merge 11 commits into
masterfrom
lukas/kernel/native-file_info

Conversation

@garazdawi

@garazdawi garazdawi commented Feb 23, 2026

Copy link
Copy Markdown
Owner

In order for this migration to really work the lists:key functions needs to work with native records.

Summary by Sourcery

Convert the file-related records to native records and propagate their usage across the codebase, while fixing distribution handling and build flags to support the new representation.

New Features:

  • Expose file_info and file_descriptor as native records from the file module and make them importable via file.hrl.
  • Add a test to verify that native records are correctly sent and received over distributed Erlang.

Bug Fixes:

  • Ensure distributed term decoding of native record metadata uses the appropriate flags so atoms participate in the atom cache.
  • Handle conversion of low-level file_info tuples to native file_info records before adjusting time fields.
  • Prevent incorrect dependency handling in the preloaded build Makefile by guarding dep.mk inclusion based on make goals.

Enhancements:

  • Standardize inclusion of file.hrl throughout the codebase by replacing include_lib usages with local includes where appropriate.
  • Extend Makefile compile flags across multiple applications to include the kernel/include directory and propagate common ERL_COMPILE_FLAGS to bootstrap compilation.
  • Improve distribution opcode debug output by naming the DOP_ALTACT_SIG_SEND opcode in logging utilities.

CI:

  • Relax the GitHub Actions workflow so the 64-bit pack job no longer depends on the check-beam job.

@garazdawi garazdawi requested a review from Copilot February 23, 2026 14:03
@garazdawi garazdawi self-assigned this Feb 23, 2026
@sourcery-ai

sourcery-ai Bot commented Feb 23, 2026

Copy link
Copy Markdown

Reviewer's Guide

Convert the file_info (and file_descriptor) record from a header-defined record into a native record in file.erl, adapt callers and tooling to use the new native record mechanism (import_record/include paths), ensure distribution and external term format support for native records, and adjust build flags/paths so non-kernel apps can compile against kernel’s native records.

Sequence diagram for prim_file read_handle_info using native file_info

sequenceDiagram
    participant Caller
    participant prim_file
    participant NIF as prim_file_NIF

    Caller->>prim_file: read_handle_info_1(Fd, TimeType)
    prim_file->>prim_file: get_fd_data(Fd)
    prim_file->>NIF: read_handle_info_nif(FRef)
    alt NIF error
        NIF-->>prim_file: {error, Reason}
        prim_file-->>Caller: {error, Reason}
    else NIF returns tuple_file_info
        NIF-->>prim_file: {file_info,S,T,A,AT,MT,CT,M,L,MAD,MID,I,U,G}
        prim_file->>prim_file: adjust_times({file_info,S,T,A,AT,MT,CT,M,L,MAD,MID,I,U,G}, TimeType)
        prim_file->>prim_file: convert to #file_info{...}
        prim_file->>prim_file: adjust_times(#file_info{...}, TimeType)
        prim_file-->>Caller: {ok, #file_info{...}}
    end
Loading

Class diagram for native file_info and file_descriptor records

classDiagram
    class file {
        +#file_info file_info
        +#file_descriptor file_descriptor
    }

    class file_info {
        +non_neg_integer size
        +device|directory|other|regular|symlink|undefined type
        +read|write|read_write|none|undefined access
        +file_date_time_or_epoch atime
        +file_date_time_or_epoch mtime
        +file_date_time_or_epoch ctime
        +non_neg_integer_or_undefined mode
        +non_neg_integer_or_undefined links
        +non_neg_integer_or_undefined major_device
        +non_neg_integer_or_undefined minor_device
        +non_neg_integer_or_undefined inode
        +non_neg_integer_or_undefined uid
        +non_neg_integer_or_undefined gid
    }

    class file_descriptor {
        +module module
        +term data
    }

    class kernel_file_hrl {
        +import_record file[file_info,file_descriptor]
    }

    class bootstrap_kernel_file_hrl {
        +import_record file[file_info,file_descriptor]
    }

    class client_module {
        +include file_hrl
        +use_record file_info
        +use_record file_descriptor
    }

    file <|.. file_info : defines
    file <|.. file_descriptor : defines

    kernel_file_hrl ..> file : import_record
    bootstrap_kernel_file_hrl ..> file : import_record

    client_module ..> kernel_file_hrl : include
    client_module ..> file_info : uses
    client_module ..> file_descriptor : uses

    class file_date_time_or_epoch {
    }
    class non_neg_integer_or_undefined {
    }
Loading

File-Level Changes

Change Details Files
Define file_info and file_descriptor as native records in file.erl and expose them via export_record/import_record instead of header-defined records.
  • Add -export_record and native -record declarations for file_info and file_descriptor in file.erl, replacing the previous internal include
  • Change kernel/lib header files file.hrl to use -import_record(file, [file_info, file_descriptor]) instead of duplicating record definitions
  • Adjust prim_file:read_handle_info_1/2 to convert tuple-form file_info into the native #file_info{} record before time adjustment
lib/kernel/src/file.erl
bootstrap/lib/kernel/include/file.hrl
lib/kernel/include/file.hrl
erts/preloaded/src/prim_file.erl
Update external term decoding and distribution support to handle native records correctly and add a regression test over distribution.
  • Pass decoding flags into dec_atom when decoding native record metadata and field names in external.c so atom cache and native record semantics are respected over distribution
  • Add a new dist/1 test case in native_record_SUITE to verify native records can be sent/received across nodes and behave correctly with atom caching
  • Ensure DOP_ALTACT_SIG_SEND has a debug name in dist.c for completeness of distribution opcode logging
erts/emulator/beam/external.c
erts/emulator/beam/dist.c
erts/emulator/test/native_record_SUITE.erl
Switch modules that use #file_info{} (and related records) to include kernel’s file.hrl via local include paths and adjust Makefiles accordingly.
  • Replace -include_lib("kernel/include/file.hrl") with -include("file.hrl") or add missing includes where required across multiple apps (kernel, stdlib, asn1, common_test, debugger, dialyzer, eunit, ftp, mnesia, observer, public_key, reltool, sasl, ssh, ssl, tftp, tools, xmerl, etc.)
  • Add -I../../kernel/include (or equivalent) to various application Makefiles so that file.hrl can be found via local include
  • Clean up duplicated late -include_lib("kernel/include/file.hrl") occurrences by consolidating includes near the top of modules or test files
erts/preloaded/src/erl_prim_loader.erl
erts/preloaded/src/init.erl
erts/preloaded/src/prim_zip.erl
lib/asn1/src/asn1ct.erl
lib/common_test/src/ct_cover.erl
lib/common_test/src/ct_logs.erl
lib/common_test/src/ct_make.erl
lib/common_test/src/ct_release_test.erl
lib/common_test/src/test_server.erl
lib/common_test/src/test_server_ctrl.erl
lib/debugger/src/dbg_wx_interpret.erl
lib/debugger/src/dbg_wx_mon.erl
lib/debugger/src/dbg_wx_settings.erl
lib/debugger/src/int.erl
lib/dialyzer/src/dialyzer_cl.erl
lib/dialyzer/src/dialyzer_incremental.erl
lib/eunit/src/eunit_data.erl
lib/ftp/src/ftp_progress.erl
lib/kernel/src/auth.erl
lib/kernel/src/code.erl
lib/kernel/src/code_server.erl
lib/kernel/src/inet_db.erl
lib/kernel/src/inet_parse.erl
lib/kernel/src/logger_std_h.erl
lib/mnesia/src/mnesia_backup.erl
lib/mnesia/src/mnesia_dumper.erl
lib/mnesia/src/mnesia_lib.erl
lib/mnesia/src/mnesia_schema.erl
lib/observer/src/cdv_wx.erl
lib/observer/src/crashdump_viewer.erl
lib/observer/src/observer_wx.erl
lib/observer/src/ttb.erl
lib/public_key/src/pubkey_os_cacerts.erl
lib/reltool/src/reltool_target.erl
lib/reltool/src/reltool_utils.erl
lib/sasl/src/release_handler.erl
lib/sasl/src/systools_lib.erl
lib/sasl/src/systools_make.erl
lib/ssh/src/ssh.erl
lib/ssh/src/ssh_file.erl
lib/ssh/src/ssh_options.erl
lib/ssh/src/ssh_sftp.erl
lib/ssh/src/ssh_sftpd.erl
lib/ssl/src/ssl_manager.erl
lib/ssl/src/ssl_pem_cache.erl
lib/ssl/src/ssl_pkix_db.erl
lib/stdlib/src/epp.erl
lib/stdlib/src/erl_tar.erl
lib/stdlib/src/file_sorter.erl
lib/stdlib/src/filelib.erl
lib/stdlib/src/filename.erl
lib/tftp/src/tftp_file.erl
lib/tools/src/make.erl
lib/tools/src/xref_utils.erl
lib/xmerl/src/xmerl_eventp.erl
lib/xmerl/src/xmerl_scan.erl
lib/xmerl/src/xmerl_xsd.erl
lib/stdlib/test/beam_lib_SUITE.erl
lib/xmerl/test/xmerl_std_SUITE.erl
lib/kernel/src/shell.erl
Tweak build system details to support the new include paths and CI behavior.
  • Add -I../../kernel/include (or similar) to several app Makefiles (asn1, dialyzer, mnesia, observer, public_key, reltool, ssh, ssl, tftp, tools, eunit, ftp, sasl, debugger, stdlib) so they can locate file.hrl from kernel/include during compilation, including bootstrap paths
  • Update stdlib’s bootstrap compilation commands to propagate ERL_COMPILE_FLAGS to the bootstrap compiler
  • Guard dep.mk inclusion in erts/preloaded/src/Makefile with an ifneq on APP_TARGET so deps are not included when building only a specific target
  • Remove the dependency of the pack job on check-beam in the GitHub Actions workflow so packaging runs independently
lib/stdlib/src/Makefile
erts/preloaded/src/Makefile
.github/workflows/main.yaml
lib/reltool/src/Makefile
lib/debugger/src/Makefile
lib/eunit/src/Makefile
lib/ftp/src/Makefile
lib/public_key/src/Makefile
lib/sasl/src/Makefile
lib/ssh/src/Makefile
lib/ssl/src/Makefile
lib/tftp/src/Makefile
lib/tools/src/Makefile
lib/asn1/src/Makefile
lib/dialyzer/src/Makefile
lib/mnesia/src/Makefile
lib/observer/src/Makefile
lib/xmerl/src/Makefile

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The switch from -include_lib("kernel/include/file.hrl") to -include("file.hrl") in modules outside kernel (e.g. ssh/ssl/ftp/tftp/tools/etc.) introduces explicit -I ../../kernel/include coupling in multiple Makefiles; consider either keeping include_lib for cross-application users or centralizing this include-path configuration to avoid fragile relative-path dependencies.
  • In prim_file:adjust_times/2, the long tuple pattern for {file_info, ...} hard-codes the field order; it may be safer and easier to maintain to centralize the tuple-to-#file_info{} conversion (or use a small helper) so changes to the record layout only need to be updated in one place.
  • Double-check that all places where -include("file.hrl") is now used (notably under erts/preloaded/src/) have the appropriate include paths configured at build time, as these were previously resolved via include_lib and may fail if file.hrl is not on the compiler include path for those targets.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The switch from `-include_lib("kernel/include/file.hrl")` to `-include("file.hrl")` in modules outside `kernel` (e.g. ssh/ssl/ftp/tftp/tools/etc.) introduces explicit `-I ../../kernel/include` coupling in multiple Makefiles; consider either keeping `include_lib` for cross-application users or centralizing this include-path configuration to avoid fragile relative-path dependencies.
- In `prim_file:adjust_times/2`, the long tuple pattern for `{file_info, ...}` hard-codes the field order; it may be safer and easier to maintain to centralize the tuple-to-`#file_info{}` conversion (or use a small helper) so changes to the record layout only need to be updated in one place.
- Double-check that all places where `-include("file.hrl")` is now used (notably under `erts/preloaded/src/`) have the appropriate include paths configured at build time, as these were previously resolved via `include_lib` and may fail if `file.hrl` is not on the compiler include path for those targets.

## Individual Comments

### Comment 1
<location> `erts/preloaded/src/prim_file.erl:684-690` </location>
<code_context>
         error:_ -> {error, badarg}
     end.

+adjust_times({file_info, S, T, A, AT, MT, CT, M, L,
+              MAD, MID, I, U, G}, TimeType) ->
+    adjust_times(#file_info{size = S, type = T, access = A,
+                            atime = AT, mtime = MT, ctime = CT,
+                            mode = M, links = L,
+                            major_device = MAD, minor_device = MID, inode = I,
+                            uid = U, gid = G}, TimeType);
 adjust_times(FileInfo, posix) ->
     FileInfo;
</code_context>

<issue_to_address>
**issue (bug_risk):** The new #file_info construction requires the record definition to be visible in prim_file.

This clause now uses the `#file_info{}` record, but `prim_file.erl` doesn’t appear to include its definition (previously it only handled the tuple/map from the NIF). Without something like `-include("file.hrl").` (or equivalent) the module won’t compile. Please make the record definition available here, consistent with other callers of `#file_info{}`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +684 to +690
adjust_times({file_info, S, T, A, AT, MT, CT, M, L,
MAD, MID, I, U, G}, TimeType) ->
adjust_times(#file_info{size = S, type = T, access = A,
atime = AT, mtime = MT, ctime = CT,
mode = M, links = L,
major_device = MAD, minor_device = MID, inode = I,
uid = U, gid = G}, TimeType);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): The new #file_info construction requires the record definition to be visible in prim_file.

This clause now uses the #file_info{} record, but prim_file.erl doesn’t appear to include its definition (previously it only handled the tuple/map from the NIF). Without something like -include("file.hrl"). (or equivalent) the module won’t compile. Please make the record definition available here, consistent with other callers of #file_info{}.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This pull request converts the file_info and file_descriptor records from traditional Erlang records to native records. The migration involves:

  1. Moving record definitions from lib/kernel/include/file.hrl to lib/kernel/src/file.erl using the -export_record directive
  2. Updating file.hrl to use -import_record to import the records from the file module
  3. Changing all module includes from -include_lib("kernel/include/file.hrl") to -include("file.hrl") across multiple OTP libraries
  4. Adding -I../../kernel/include or similar include paths to Makefiles to ensure file.hrl can be found
  5. Updating prim_file.erl to handle tuple-to-record conversion for compatibility
  6. Modifying external.c to pass the flags parameter when decoding atoms in native records (for atom cache support)
  7. Adding a new test case in native_record_SUITE for distribution testing
  8. Updating bootstrap beam files

Changes:

  • Record definitions migrated from include file to module with export/import directives
  • Include directives changed from include_lib to plain include across ~50 files
  • Makefile updates to add kernel include path to compilation flags
  • Native record support for distribution with atom cache

Reviewed changes

Copilot reviewed 85 out of 118 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
lib/kernel/include/file.hrl Replaced record definitions with -import_record directive
lib/kernel/src/file.erl Added record definitions with -export_record directive
erts/preloaded/src/prim_file.erl Added tuple-to-record conversion in adjust_times function
erts/emulator/beam/external.c Updated atom decoding to pass flags for atom cache support
erts/emulator/beam/dist.c Added DOP_ALTACT_SIG_SEND constant string
erts/emulator/test/native_record_SUITE.erl Added distribution test for native records
lib/*/src/Makefile Added -I../../kernel/include to compilation flags
lib//src/.erl (multiple) Changed includes from include_lib to include
bootstrap/* Updated bootstrap beam files for new record format
erts/preloaded/src/Makefile Added conditional around dep.mk include
.github/workflows/main.yaml Removed check-beam dependency from pack job

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


pack:
name: Build Erlang/OTP (64-bit)
runs-on: ubuntu-latest

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

The removal of the needs: check-beam dependency from the pack job appears to be unrelated to the main purpose of this PR (converting file_info to a native record). This change allows the pack job to run in parallel with the check-beam job rather than waiting for it to complete.

While this might improve CI performance, it's unclear from the PR description why this change is included. If this is intentional and related to the native record migration (perhaps because bootstrap beam files need to be updated), it should be mentioned in the PR description. Otherwise, this change should be in a separate PR focused on CI improvements.

Copilot uses AI. Check for mistakes.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

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