Further question on the above. I'm trying to see i...
# kotlin-native
r
Further question on the above. I'm trying to see if a file is on the same device as the initial path that I look at; the st_dev that I'm getting back from stat seems to be identical across all devices. (details in thread)
Here's my code for iterating over paths:
Copy code
val 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):
Copy code
/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:
Copy code
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
statFile is:
Copy code
fun statFile(path: String) = memScoped {
        val info = alloc<stat>()
        lstat(path, info.ptr)
        info
    }
processDirectory is:
Copy code
fun 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)
}
ChatGPT suggested that it was becauseI was using lstat, but that doesn't seem to be the issue
e
your
statFile
is returning a
stat
struct that has already been freed
you can work around it by taking a copy before it is freed with
.readValue()
inside the
memScoped
, or using
cValue()
so that it is placed in Kotlin memory directly
e.g. instead of
Copy code
memScoped {
    val info = alloc<stat>()
    stat(path, info.ptr)
    info.readValue()
}
you can just
Copy code
cValue<stat> {
    stat(path, ptr)
}
r
a) is there good documentation somewhere on this stuff? I don't have good intuition about it. it's completely foreign from regular kotlin and kotlinjs, and it's been 20 years since I did any C. intellij's autosuggest isn't superhelpful either. b) I think you are suggesting either:
Copy code
fun statFile(path: String): stat {
        val info = cValue<stat>()
        lstat(path, info)
        return info
    }
or
Copy code
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 🙂
of course you could also map it to your own Kotlin data structure instead of carrying around a
CValue
(and in reality you want to check the return code of
stat
as well)
r
ah, so along the lines of:
Copy code
fun 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?
e
I meant something more like
Copy code
sealed 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 too
none of this is really well documented so it mostly just comes from mapping experience with other interop systems to what's in K/N
r
got it. thanks