Skip to content

Commit 66041fa

Browse files
committed
example of integration with libc via ctypes
1 parent 45a5ea4 commit 66041fa

File tree

6 files changed

+127
-0
lines changed

6 files changed

+127
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Examples
3636
* [Read the DOS-type (MBR) partition table](https://python-cstruct.readthedocs.io/en/latest/examples/fdisk/)
3737
* [Print information about logged uses](https://python-cstruct.readthedocs.io/en/latest/examples/who/)
3838
* [Flexible Array Member (FAM)](https://python-cstruct.readthedocs.io/en/latest/examples/flexible_array/)
39+
* [libc integration (using ctypes)](https://python-cstruct.readthedocs.io/en/latest/examples/dir/)
3940

4041

4142
Features

docs/examples/dir.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
The following program prints the names of the files in a directory,
2+
calling the libc functions `getcwd`, `opendir`, `readdir`, and `closedir`:
3+
4+
```
5+
{!examples/dir.py!}
6+
```

examples/dir.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/* https://www.gnu.org/software/libc/manual/html_mono/libc.html#Simple-Directory-Lister */
2+
3+
#include <stdio.h>
4+
#include <sys/types.h>
5+
#include <dirent.h>
6+
7+
int main (void) {
8+
DIR *dp;
9+
struct dirent *ep;
10+
11+
dp = opendir(".");
12+
if (dp != NULL) {
13+
while (ep = readdir (dp)) {
14+
puts(ep->d_name);
15+
}
16+
closedir(dp);
17+
} else {
18+
perror("Couldn't open the directory");
19+
}
20+
21+
return 0;
22+
}

examples/dir.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/env python
2+
import cstruct
3+
import ctypes
4+
import sys
5+
6+
libc = ctypes.cdll.LoadLibrary("libc.so.6")
7+
# opendir
8+
libc.opendir.argtypes = [ctypes.c_char_p]
9+
libc.opendir.restype = ctypes.c_void_p
10+
# readdir
11+
libc.readdir.argtypes = [ctypes.c_void_p]
12+
libc.readdir.restype = ctypes.c_void_p
13+
# closedir
14+
libc.closedir.argtypes = [ctypes.c_void_p]
15+
libc.closedir.restype = ctypes.c_int
16+
17+
18+
class DType(cstruct.CEnum):
19+
__size__ = 1
20+
__def__ = """
21+
enum d_type {
22+
DT_UNKNOWN = 0x0,
23+
DT_FIFO = 0x1,
24+
DT_CHR = 0x2,
25+
DT_DIR = 0x4,
26+
DT_BLK = 0x6,
27+
DT_REG = 0x8,
28+
DT_LNK = 0xa,
29+
DT_SOCK = 0xc
30+
};
31+
"""
32+
33+
def __str__(self):
34+
return {
35+
DType.DT_UNKNOWN: "<unknown>",
36+
DType.DT_FIFO: "<fifo>",
37+
DType.DT_CHR: "<char>",
38+
DType.DT_DIR: "<dir>",
39+
DType.DT_BLK: "<block>",
40+
DType.DT_REG: "<regular>",
41+
DType.DT_LNK: "<link>",
42+
DType.DT_SOCK: "<socket>",
43+
}[self]
44+
45+
46+
class Dirent(cstruct.MemCStruct):
47+
__def__ = """
48+
#define PATH_MAX 4096
49+
50+
typedef long ino_t;
51+
typedef long off_t;
52+
53+
struct dirent {
54+
ino_t d_ino; /* Inode number */
55+
off_t d_off; /* Not an offset */
56+
unsigned short d_reclen; /* Length of this record */
57+
unsigned char d_type; /* Type of file; not supported
58+
by all filesystem types */
59+
char d_name[256]; /* Null-terminated filename */
60+
};
61+
"""
62+
63+
@property
64+
def name(self):
65+
return ctypes.c_char_p(self.d_name).value.decode("ascii")
66+
67+
@property
68+
def type(self):
69+
return DType(self.d_type)
70+
71+
72+
def main():
73+
if len(sys.argv) > 1:
74+
cwd = ctypes.create_string_buffer(sys.argv[1].encode("ascii"))
75+
else:
76+
# Get current dir
77+
cwd = ctypes.create_string_buffer(cstruct.getdef("PATH_MAX") + 1)
78+
assert libc.getcwd(cwd, ctypes.sizeof(cwd)) != 0
79+
# Open dir
80+
dp = libc.opendir(cwd)
81+
assert dp != 0
82+
# Read dir entries
83+
ep = libc.readdir(dp)
84+
while ep:
85+
contents = ctypes.cast(ep, ctypes.POINTER(ctypes.c_char * Dirent.size)).contents
86+
dirent = Dirent(contents)
87+
print(f"{dirent.d_ino:8} {dirent.type:10} {dirent.name}")
88+
ep = libc.readdir(dp)
89+
# Close dir
90+
libc.closedir(dp)
91+
92+
93+
if __name__ == "__main__":
94+
main()

examples/dir.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env sh
2+
cd "$(dirname "$0")/.." || exit
3+
python -m examples.dir $*

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ nav:
2020
- Code of Conduct: CODE_OF_CONDUCT.md
2121
- Source Code Repository: "https://github.com/andreax79/python-cstruct"
2222
- Examples:
23+
- "dir.py": examples/dir.md
2324
- "fdisk.py": examples/fdisk.md
2425
- "flexible_array.py": examples/flexible_array.md
2526
- "who.py": examples/who.md

0 commit comments

Comments
 (0)