package main

import (
	"fmt"
	"io/fs"
	"os"
	"path/filepath"
)

func main() {
	// Direktori kerja sementara agar program aman dijalankan berulang.
	dir, err := os.MkdirTemp("", "contoh-perm-*")
	if err != nil {
		fmt.Println("gagal membuat direktori:", err)
		return
	}
	defer os.RemoveAll(dir)

	// Berkas data biasa: pemilik baca-tulis, lainnya baca saja.
	biasa := filepath.Join(dir, "biasa.txt")
	if err := os.WriteFile(biasa, []byte("data\n"), 0644); err != nil {
		fmt.Println("gagal menulis berkas:", err)
		return
	}
	laporkan(biasa, "WriteFile 0644")

	// os.Create meminta 0666; umask merampingkan hasil akhirnya.
	buat := filepath.Join(dir, "buat.txt")
	f, err := os.Create(buat)
	if err != nil {
		fmt.Println("gagal membuat berkas:", err)
		return
	}
	if _, err := f.WriteString("data\n"); err != nil {
		fmt.Println("gagal menulis:", err)
		f.Close()
		return
	}
	if err := f.Close(); err != nil {
		fmt.Println("gagal menutup berkas:", err)
		return
	}
	laporkan(buat, "os.Create 0666")

	// Berkas rahasia: hanya pemilik yang boleh membaca dan menulis.
	rahasia := filepath.Join(dir, "rahasia.txt")
	if err := os.WriteFile(rahasia, []byte("token\n"), 0600); err != nil {
		fmt.Println("gagal menulis berkas:", err)
		return
	}
	laporkan(rahasia, "WriteFile 0600")

	// os.Chmod mengubah permission berkas yang sudah ada, tanpa pengaruh umask.
	if err := os.Chmod(biasa, 0755); err != nil {
		fmt.Println("gagal mengubah permission:", err)
		return
	}
	laporkan(biasa, "Chmod 0755")

	// Direktori: huruf d memimpin notasi simboliknya.
	folder := filepath.Join(dir, "folder")
	if err := os.Mkdir(folder, 0755); err != nil {
		fmt.Println("gagal membuat direktori:", err)
		return
	}
	info, err := os.Stat(folder)
	if err != nil {
		fmt.Println("gagal membaca metadata:", err)
		return
	}
	fmt.Printf("Mkdir 0755  : %s (%s) isDir=%v ModeDir=%v\n",
		info.Mode(), oktal(info), info.IsDir(), info.Mode()&fs.ModeDir != 0)

	// fs.ModePerm adalah topeng sembilan bit permission penuh.
	fmt.Printf("fs.ModePerm : %o\n", fs.ModePerm)
}

// laporkan mencetak permission simbolik dan oktal sebuah berkas.
func laporkan(path, label string) {
	info, err := os.Stat(path)
	if err != nil {
		fmt.Println("gagal membaca metadata:", err)
		return
	}
	fmt.Printf("%-16s %s (%s)\n", label, info.Mode(), oktal(info))
}

// oktal memformat sembilan bit permission sebagai tiga digit oktal.
func oktal(info os.FileInfo) string {
	return fmt.Sprintf("%03o", info.Mode().Perm())
}
