Reuben Firmin
03/25/2023, 11:38 AMReuben Firmin
03/25/2023, 11:41 AMval dirInfo = statFile("/")
device = dirInfo.st_dev
val res = processDirectory(dir)
for (path in res.otherPaths) {
val info = statFile(path)
println("$path ${info.st_dev} $device")
}
And this prints (partial):
/snap 11282602126717852345 11282602126717852345
/home 11282602126717852345 11282602126717852345
/opt 11282602126717852345 11282602126717852345
/root 11282602126717852345 11282602126717852345
/usr 11282602126717852345 11282602126717852345
/backup 11282602126717852345 11282602126717852345
/proc 11282602126717852345 11282602126717852345
/spinner 11282602126717852345 11282602126717852345
However, compared against df, you can see these are multiple devices:
Filesystem Size Used Avail Use% Mounted on
tmpfs 3.1G 2.3M 3.1G 1% /run
/dev/sdc2 48G 43G 2.9G 94% /
tmpfs 16G 344M 15G 3% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
/dev/sdc3 227G 28K 215G 1% /data
/dev/sdc4 182G 141G 32G 82% /home
/dev/sdc1 400M 9.5M 390M 3% /boot/efi
/dev/sdb1 458G 28K 435G 1% /backup
/dev/sda1 917G 804G 67G 93% /spinner
tmpfs 3.1G 148K 3.1G 1% /run/user/1000
Reuben Firmin
03/25/2023, 11:41 AMfun statFile(path: String) = memScoped {
val info = alloc<stat>()
lstat(path, info.ptr)
info
}
Reuben Firmin
03/25/2023, 11:42 AMfun processDirectory(path: String): Result {
val subPaths = mutableListOf<String>() // TODO deallocate using shared mem?
val directory = opendir(path)
var fileSize = 0L
if (directory != null) {
try {
var entry = readdir(directory)?.pointed
while (entry != null) {
val info = entry.toFileInfo(path)
if (info != null && info.second.isOnDevice(device)) {
if (info.second.isDirectory()) {
subPaths.add(info.first)
} else if (info.second.isFile()) {
fileSize += info.second.st_size
}
}
entry = readdir(directory)?.pointed
}
} finally {
closedir(directory)
}
}
return Result(path, fileSize, subPaths)
}
Reuben Firmin
03/25/2023, 12:53 PMephemient
03/25/2023, 11:07 PMstatFile
is returning a stat
struct that has already been freedephemient
03/25/2023, 11:14 PM.readValue()
inside the memScoped
, or using cValue()
so that it is placed in Kotlin memory directlyephemient
03/26/2023, 2:07 AMmemScoped {
val info = alloc<stat>()
stat(path, info.ptr)
info.readValue()
}
you can just
cValue<stat> {
stat(path, ptr)
}
Reuben Firmin
03/26/2023, 2:09 AMfun statFile(path: String): stat {
val info = cValue<stat>()
lstat(path, info)
return info
}
or
fun statFile(path: String) = memScoped {
val info = alloc<stat>()
lstat(path, info.ptr)
info.readValue()
}
In both cases I end up with a CValue<stat> -- but how do I use it?
https://kotlinlang.org/api/latest/jvm/stdlib/kotlinx.cinterop/-c-value/ doesn't specify, and chatgpt just hallucinates when I ask it 🙂ephemient
03/26/2023, 2:10 AMephemient
03/26/2023, 2:11 AMCValue
ephemient
03/26/2023, 2:12 AMstat
as well)Reuben Firmin
03/26/2023, 2:18 AMfun statFile(path: String): stat {
val info = cValue<stat>()
val err = lstat(path, info)
// todo check err
info.useContents {
FileInfo(st_mode, st_dev, etc)
}
}
and on my first question, what's the best way to learn this? are there any docs that go into depth?ephemient
03/26/2023, 2:21 AMsealed class StatOrError
data class Stat(...) : StatOrError()
data class Error(...) : StatOrError()
fun statFile(path: String): StatOrError = memScoped {
val info = alloc<stat>()
val rc = lstat(path, info)
if (rc == 0) Stat(info.st_dev, ...) else Error(errno)
}
but that would work tooephemient
03/26/2023, 2:22 AMReuben Firmin
03/26/2023, 2:23 AM