summaryrefslogtreecommitdiff
path: root/integrationtests/cmd/ioworkload/scenario_dir.go
diff options
context:
space:
mode:
Diffstat (limited to 'integrationtests/cmd/ioworkload/scenario_dir.go')
-rw-r--r--integrationtests/cmd/ioworkload/scenario_dir.go186
1 files changed, 186 insertions, 0 deletions
diff --git a/integrationtests/cmd/ioworkload/scenario_dir.go b/integrationtests/cmd/ioworkload/scenario_dir.go
new file mode 100644
index 0000000..0c48d54
--- /dev/null
+++ b/integrationtests/cmd/ioworkload/scenario_dir.go
@@ -0,0 +1,186 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "runtime"
+ "syscall"
+ "unsafe"
+)
+
+// dirBasic creates a directory via raw SYS_MKDIR, checks access, then removes it
+// via raw SYS_RMDIR. We use raw syscalls because Go's syscall.Mkdir wraps mkdirat
+// and syscall.Rmdir wraps unlinkat on amd64.
+func dirBasic() error {
+ dir, cleanup, err := makeTempDir("dir-basic")
+ if err != nil {
+ return err
+ }
+ defer cleanup()
+
+ subDir := filepath.Join(dir, "subdir")
+ pathBytes, err := syscall.BytePtrFromString(subDir)
+ if err != nil {
+ return fmt.Errorf("path bytes: %w", err)
+ }
+ _, _, errno := syscall.Syscall(syscall.SYS_MKDIR, uintptr(unsafe.Pointer(pathBytes)), 0o755, 0)
+ runtime.KeepAlive(pathBytes)
+ if errno != 0 {
+ return fmt.Errorf("mkdir: %w", errno)
+ }
+
+ if err := syscall.Access(subDir, syscall.F_OK); err != nil {
+ return fmt.Errorf("access: %w", err)
+ }
+
+ pathBytes2, err := syscall.BytePtrFromString(subDir)
+ if err != nil {
+ return fmt.Errorf("path bytes: %w", err)
+ }
+ _, _, errno = syscall.Syscall(syscall.SYS_RMDIR, uintptr(unsafe.Pointer(pathBytes2)), 0, 0)
+ runtime.KeepAlive(pathBytes2)
+ if errno != 0 {
+ return fmt.Errorf("rmdir: %w", errno)
+ }
+ return nil
+}
+
+// dirMkdirat creates a directory via mkdirat(2) using Go's syscall.Mkdir
+// which wraps mkdirat with AT_FDCWD on amd64.
+func dirMkdirat() error {
+ dir, cleanup, err := makeTempDir("dir-mkdirat")
+ if err != nil {
+ return err
+ }
+ defer cleanup()
+
+ subDir := filepath.Join(dir, "mkdirat-subdir")
+ if err := syscall.Mkdir(subDir, 0o755); err != nil {
+ return fmt.Errorf("mkdirat: %w", err)
+ }
+ return nil
+}
+
+// dirChdir creates a temp directory, then changes to it via chdir(2).
+// Restores the original working directory afterward.
+func dirChdir() error {
+ origDir, err := os.Getwd()
+ if err != nil {
+ return fmt.Errorf("getwd: %w", err)
+ }
+
+ dir, cleanup, err := makeTempDir("dir-chdir")
+ if err != nil {
+ return err
+ }
+ defer cleanup()
+ defer syscall.Chdir(origDir)
+
+ if err := syscall.Chdir(dir); err != nil {
+ return fmt.Errorf("chdir: %w", err)
+ }
+ return nil
+}
+
+// dirGetdents opens a directory and reads its entries via getdents64(2).
+func dirGetdents() error {
+ dir, cleanup, err := makeTempDir("dir-getdents")
+ if err != nil {
+ return err
+ }
+ defer cleanup()
+
+ // Create a file so getdents has something to return.
+ filePath := filepath.Join(dir, "getdents-file.txt")
+ fd, err := syscall.Open(filePath, syscall.O_RDWR|syscall.O_CREAT, 0o644)
+ if err != nil {
+ return fmt.Errorf("open file: %w", err)
+ }
+ syscall.Close(fd)
+
+ dirFD, err := syscall.Open(dir, syscall.O_RDONLY|syscall.O_DIRECTORY, 0)
+ if err != nil {
+ return fmt.Errorf("open dir: %w", err)
+ }
+ defer syscall.Close(dirFD)
+
+ buf := make([]byte, 4096)
+ _, _, errno := syscall.Syscall(syscall.SYS_GETDENTS64, uintptr(dirFD), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
+ runtime.KeepAlive(buf)
+ if errno != 0 {
+ return fmt.Errorf("getdents64: %w", errno)
+ }
+ return nil
+}
+
+// dirMkdirEexist attempts to create a directory that already exists via raw
+// SYS_MKDIR. The syscall fails with EEXIST, but ior captures the tracepoint
+// on entry.
+func dirMkdirEexist() error {
+ dir, cleanup, err := makeTempDir("dir-mkdir-eexist")
+ if err != nil {
+ return err
+ }
+ defer cleanup()
+
+ subDir := filepath.Join(dir, "mkdir-eexist-subdir")
+ pathBytes, err := syscall.BytePtrFromString(subDir)
+ if err != nil {
+ return fmt.Errorf("path bytes: %w", err)
+ }
+
+ // Create the directory first so the second attempt fails.
+ _, _, errno := syscall.Syscall(syscall.SYS_MKDIR, uintptr(unsafe.Pointer(pathBytes)), 0o755, 0)
+ runtime.KeepAlive(pathBytes)
+ if errno != 0 {
+ return fmt.Errorf("first mkdir: %w", errno)
+ }
+
+ // Second mkdir on the same path should fail with EEXIST.
+ pathBytes2, err := syscall.BytePtrFromString(subDir)
+ if err != nil {
+ return fmt.Errorf("path bytes: %w", err)
+ }
+ _, _, errno = syscall.Syscall(syscall.SYS_MKDIR, uintptr(unsafe.Pointer(pathBytes2)), 0o755, 0)
+ runtime.KeepAlive(pathBytes2)
+ if errno == 0 {
+ return fmt.Errorf("expected EEXIST, but mkdir succeeded")
+ }
+ return nil
+}
+
+// dirChdirEnoent attempts to change to a nonexistent directory via raw
+// SYS_CHDIR. The syscall fails with ENOENT, but ior captures the tracepoint
+// on entry.
+func dirChdirEnoent() error {
+ dir, cleanup, err := makeTempDir("dir-chdir-enoent")
+ if err != nil {
+ return err
+ }
+ defer cleanup()
+
+ badPath := filepath.Join(dir, "chdir-enoent-missing")
+ pathBytes, err := syscall.BytePtrFromString(badPath)
+ if err != nil {
+ return fmt.Errorf("path bytes: %w", err)
+ }
+ _, _, errno := syscall.Syscall(syscall.SYS_CHDIR, uintptr(unsafe.Pointer(pathBytes)), 0, 0)
+ runtime.KeepAlive(pathBytes)
+ if errno == 0 {
+ return fmt.Errorf("expected ENOENT, but chdir succeeded")
+ }
+ return nil
+}
+
+// dirGetdentsEbadf calls getdents64(2) with an invalid file descriptor.
+// The syscall fails with EBADF, but ior captures the tracepoint on entry.
+func dirGetdentsEbadf() error {
+ buf := make([]byte, 4096)
+ _, _, errno := syscall.Syscall(syscall.SYS_GETDENTS64, uintptr(9999), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
+ runtime.KeepAlive(buf)
+ if errno == 0 {
+ return fmt.Errorf("expected EBADF, but getdents64 succeeded")
+ }
+ return nil
+}