Overview
The market is tough. I wish I had an easier time interviewing. But, it gets easier every time I write an article, do a leetcode problem, or finish a day-job task. They passed on me in my most recent SRE interview, but that's OK. It just tells me that, for whatever reason, I wasn't the best candidate. Or it meant that they weren't the right employer for me. Either way, I'm still going to practice, study, and persevere.
Listing in Bash on Linux
One of the questions that they asked me was, what does this command do on Linux?
$ ls -l *
The Output
Here's an example of the output:
➜ pwd $ ls -l *
-rw-r--r--@ 1 user group 0 Month 01 14:05 LICENSE
-rw-r--r--@ 1 user group 202 Month 01 14:05 go.mod
-rw-r--r--@ 1 user group 896 Month 01 14:05 go.sum
-rw-r--r--@ 1 user group 138 Month 01 14:05 main.go
cmd:
total 8
-rw-r--r--@ 1 user group 1444 Month 01 14:05 root.go
internal:
total 16
-rw-r--r--@ 1 user group 37 Month 01 16:05 main.go
-rw-r--r--@ 1 user group 225 Month 01 14:10 main_test.go
Here are some things we see so far:
- It shows the current working directory and all its non-hidden contents.
- It shows permissions of the files in symbolic notation (as opposed to file mode notation like 0755). These permissions include owner, group, and other permissions (in that order) along with
@indicating extended attributes like for SELinux.
- It shows the total number of child elements below each directory child below the current working directory (pwd).
- This listing shows the user and group indicated on the child (file or dir)
- The last mod date/time for the file.
How does ls get this information?
stat- for getting file and directory info for each item listed, even with symbolic links and not using the-l(long-listing) option.
lstat- for getting metadata information for when using-l(long-listing) on symbolic link file types.
Code Sample
In an attempt to implement ls with -l support in go, here is a code sample.
Here's the stat_t parsing section:
func New(n string, stat *syscall.Stat_t) Stat {
var m Stat
m.BaseName = path.Base(n)
m.AbsolutePath, _ = filepath.Abs(n)
if stat.Mode&syscall.S_IFDIR == syscall.S_IFDIR {
m.Type = "directory"
} else if stat.Mode&syscall.S_IFREG == syscall.S_IFREG {
m.Type = "file"
} else if stat.Mode&syscall.S_IFLNK == syscall.S_IFLNK {
m.Type = "symlink"
} else if stat.Mode&syscall.S_IFIFO == syscall.S_IFIFO {
m.Type = "fifo"
} else if stat.Mode&syscall.S_IFSOCK == syscall.S_IFSOCK {
m.Type = "socket"
} else if stat.Mode&syscall.S_IFCHR == syscall.S_IFCHR {
m.Type = "character_device"
} else if stat.Mode&syscall.S_IFBLK == syscall.S_IFBLK {
m.Type = "block_device"
} else {
m.Type = "unknown"
}
m.SizeBytes = stat.Size
m.Mode = stat.Mode
m.UserID = stat.Uid
m.GroupID = stat.Gid
m.LastAccessedTime = time.Unix(stat.Atimespec.Sec, stat.Atimespec.Nsec)
m.LastModifiedTime = time.Unix(stat.Mtimespec.Sec, stat.Mtimespec.Nsec)
m.CreateTime = time.Unix(stat.Ctimespec.Sec, stat.Ctimespec.Nsec)
m.BirthTime = time.Unix(stat.Birthtimespec.Sec, stat.Birthtimespec.Nsec)
m.BlockSize = uint32(stat.Blksize)
m.NumBlocks = uint64(stat.Blocks)
var err error
u, err := user.LookupId(fmt.Sprintf("%d", stat.Uid))
if err == nil {
m.Owner = u.Username
m.UserName = u.Username
} else {
m.Owner = "unknown"
m.UserName = "unknown"
}
u, err = user.LookupId(fmt.Sprintf("%d", stat.Gid))
if err == nil {
m.GroupName = u.Username
} else {
m.GroupName = "unknown"
}
m.HardLinkReferenceCount = uint16(stat.Nlink)
octalPerm := os.FileMode(stat.Mode) & os.ModePerm
m.Permissions.Octal = fmt.Sprintf("%o", octalPerm)
const (
ownerStatTOffset = 6
groupStatTOffset = 3
otherStatTOffset = 1
)
// https://man7.org/linux/man-pages/man7/inode.7.html
// who-has-what-perms section starts at offset 6 and ends at offset 10.
// The >> operator in Go shifts the bits of a number to the right.
// Think of the number as a row of lights (1 = on, 0 = off).
// - >> 1 moves all the lights 1 step to the right, filling empty spaces on the left:
// - Positive numbers fill with 0 (e.g., 8 >> 1: 00001000 -> 00000100 = 4).
// - Negative numbers fill with 1 to keep the number negative.
// - Bits that fall off the right edge disappear.
var (
ownerPerms = uint8(octalPerm >> ownerStatTOffset)
groupPerms = uint8(octalPerm >> groupStatTOffset)
otherPerms = uint8(octalPerm >> otherStatTOffset)
)
m.Permissions.Symbolic.Owner = perm.New(ownerPerms)
m.Permissions.Symbolic.Group = perm.New(groupPerms)
m.Permissions.Symbolic.Other = perm.New(otherPerms)
return m
}
And here is the permissions parsing code:
func New(mode uint8) SymbolicPermission {
var (
read bool
write bool
execute bool
)
const (
readOffset = 4
writeOffset = 2
executeOffset = 1
)
// bitIsSet determines whether a specific bit is set in an unsigned int.
// Example:
// mode := uint8(5) // Binary: 101
// bitIsSet(mode, 4) // Returns true (read bit is set)
// 0b101 & 0b100 = 0b100 (comparison: 0b100 == 0b100 → true)
// bitIsSet(mode, 2) // Returns false (write bit is not set)
// 0b101 & 0b010 = 0b000 (comparison: 0b000 == 0b010 → false)
// bitIsSet(mode, 1) // Returns true (execute bit is set)
// 0b101 & 0b001 = 0b001 (comparison: 0b001 == 0b001 → true)
bitIsSet := func(mode, offset uint8) bool {
return mode&offset == offset
}
read = bitIsSet(mode, readOffset)
write = bitIsSet(mode, writeOffset)
execute = bitIsSet(mode, executeOffset)
return SymbolicPermission{
Read: read,
Write: write,
Execute: execute,
}
}
SOCIAL SHARE CARD GENERATOR