summaryrefslogtreecommitdiff
path: root/src/main/kotlin/FilePermissions.kt
blob: ce25d233c234d700f39f53ea24058147d69c49b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
 * The permissions of a newly created file.
 */
class FilePermissions {

    /**
     * The permissions for the file's owning user.
     */
    val userPerms: Permissions

    /**
     * The permissions for the file's owning group.
     */
    val groupPerms: Permissions

    /**
     * The permissions for everyone else.
     */
    val elsePerms: Permissions

    /**
     * Is the file a directory? If not, it's a regular file.
     */
    val isDirectory: Boolean

    private val DIRECTORY_BIT: UInt = 0x80000000u

    enum class Permissions(val bits: UByte) {
        READ(0x4u),
        WRITE(0x2u),
        EXECUTE(0x1u),
        READ_WRITE(READ.bits.or(WRITE.bits)),
        READ_EXECUTE(READ.bits.or(EXECUTE.bits)),
        WRITE_EXECUTE(WRITE.bits.or(EXECUTE.bits)),
        READ_WRITE_EXECUTE(READ.bits.or(WRITE.bits.or(EXECUTE.bits)));

        companion object {
            /**
             * Obtain a [Permissions] instance by matching its value.
             *
             * @throws NoSuchElementException if no such element has the provided value.
             */
            fun fromByte(bits: UByte) = Permissions.entries.first { it.bits == bits }
        }
    }

    /**
     * Constructor for file permissions with separate fields.
     *
     * @param userPerms The permissions for the file's owning user.
     * @param groupPerms The permissions for the file's owning group.
     * @param elsePerms The permissions for everyone else.
     * @param isDirectory Is the file a directory? If not, it's a regular file.
     */
    constructor(userPerms: Permissions, groupPerms: Permissions, elsePerms: Permissions, isDirectory: Boolean) {
        this.userPerms = userPerms
        this.groupPerms = groupPerms
        this.elsePerms = elsePerms
        this.isDirectory = isDirectory
    }

    /**
     * Constructor for raw file permission data. Only the first 4 elements are read.
     *
     * @param raw The raw file permission data.
     * @throws IllegalArgumentException if [raw] does not have at least 4 elements.
     */
    constructor(raw: List<UByte>) {
        require(raw.size >= 4)
        val raw = raw.slice(0..4)
        val dirValue = raw[0].toUInt().xor(this.DIRECTORY_BIT)
        this.isDirectory = dirValue > 0u
        this.userPerms = Permissions.fromByte(raw[1])
        this.groupPerms = Permissions.fromByte(raw[2])
        this.elsePerms = Permissions.fromByte(raw[3])
    }

    /**
     * Turn the permissions described by the [FilePermissions] fields into a permission integer (4 bytes).
     */
    fun toPermissionInt(): UInt {
        val permFileds = listOf(userPerms, groupPerms, elsePerms)
        val perms: UInt = 0u
        for (i in 0..permFileds.size) {
            perms.or(permFileds[i].bits.toUInt().shl(8 * (permFileds.size - 1 - i)))
        }
        if (isDirectory) {
            perms.or(this.DIRECTORY_BIT)
        }
        return perms
    }
}