From 271cda4e5b478a9f51ac98544e34de768a7e69ae Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 30 May 2026 10:55:45 +0300 Subject: creat: keep pathname on failed creat; lock in fd->path mapping creat(pathname, mode) is equivalent to open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode): on success it returns a new fd, on failure -1. handlePathExit already special-cased creat to register the returned fd->path mapping in fdState (matching handleOpenExit for open/openat/openat2), but on failure (ret<0) it left ep.File unset, silently dropping the path. handleOpenExit keeps the path via NewPathname for failed opens so error scenarios stay observable; align the creat branch with that behavior. Strengthen CreatEventTest to assert the returned fd is registered with the correct path and synthesized open flags, and add a negative FailedCreatEventTest covering the ret<0 path (no fd registered, path retained). Co-Authored-By: Claude Opus 4.8 --- internal/eventloop_exit.go | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'internal/eventloop_exit.go') diff --git a/internal/eventloop_exit.go b/internal/eventloop_exit.go index a5b38d4..c1465fc 100644 --- a/internal/eventloop_exit.go +++ b/internal/eventloop_exit.go @@ -105,10 +105,17 @@ func (e *eventLoop) handlePathExit(ep *event.Pair, pathEv *types.PathEvent) bool return false } if fd := int32(retEvent.Ret); fd >= 0 { + // creat(pathname, mode) == open(pathname, O_CREAT|O_WRONLY|O_TRUNC, + // mode): on success it returns a new fd, so register the fd->path + // mapping just like handleOpenExit does for open/openat/openat2. fdFile := file.NewFd(fd, types.StringValue(pathEv.Pathname[:]), syscall.O_CREAT|syscall.O_WRONLY|syscall.O_TRUNC) e.fdState().set(fd, fdFile) ep.File = fdFile + } else { + // Failed creat (-1): keep the path so error scenarios stay + // observable, mirroring handleOpenExit's failed-open branch. + ep.File = file.NewPathname(pathEv.Pathname[:]) } } else { ep.File = file.NewPathname(pathEv.Pathname[:]) -- cgit v1.2.3