]>
Commit | Line | Data |
---|---|---|
558d2836 A |
1 | // |
2 | // quotas.c | |
3 | // hfs | |
4 | // | |
5 | // Created by Chris Suter on 8/13/15. | |
6 | // | |
7 | // | |
8 | ||
9 | #include <TargetConditionals.h> | |
10 | ||
11 | #include <unistd.h> | |
12 | #include <stdio.h> | |
13 | #include <fcntl.h> | |
14 | #include <sys/types.h> | |
15 | #include <sys/quota.h> | |
16 | #include <sys/stat.h> | |
17 | ||
18 | #include "hfs-tests.h" | |
19 | #include "disk-image.h" | |
20 | #include "test-utils.h" | |
21 | ||
22 | #define QUOTA_DMG "/tmp/quota-test.sparseimage" | |
23 | #define QUOTA_DMG_MOUNT_POINT "/tmp/quota-test-mount" | |
24 | ||
25 | TEST(quotas, .run_as_root = true) | |
26 | ||
27 | // This is what the quota file looks like after running edquota | |
28 | char quota_file[] = { | |
29 | 0xff, 0x31, 0xff, 0x35, 0x00, 0x00, 0x00, 0x01, | |
30 | 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, | |
31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
32 | 0x00, 0x09, 0x3a, 0x80, 0x00, 0x09, 0x3a, 0x80, | |
33 | 0x51, 0x55, 0x4f, 0x54, 0x41, 0x20, 0x48, 0x41, | |
34 | 0x53, 0x48, 0x20, 0x46, 0x49, 0x4c, 0x45, 0x00, | |
35 | // Zero padding up to 131136 bytes | |
36 | }; | |
37 | ||
38 | int run_quotas(__unused test_ctx_t *ctx) | |
39 | { | |
40 | disk_image_t *di = disk_image_create(QUOTA_DMG, | |
41 | &(disk_image_opts_t) { | |
42 | #if TARGET_OS_EMBEDDED | |
43 | .mount_point = QUOTA_DMG_MOUNT_POINT, | |
44 | #endif | |
45 | .size = 64 * 1024 * 1024, | |
46 | .enable_owners = true | |
47 | }); | |
48 | ||
49 | char *path; | |
50 | asprintf(&path, "%s/.quota.ops.user", di->mount_point); | |
51 | int fd = open(path, O_CREAT | O_RDWR, 0777); | |
52 | assert_with_errno(fd >= 0); | |
53 | free(path); | |
54 | assert_no_err(close(fd)); | |
55 | ||
56 | asprintf(&path, "%s/.quota.user", di->mount_point); | |
57 | fd = open(path, O_CREAT | O_RDWR, 0777); | |
58 | assert_with_errno(fd >= 0); | |
59 | check_io(write(fd, quota_file, lengthof(quota_file)), lengthof(quota_file)); | |
60 | assert_no_err(ftruncate(fd, 131136)); | |
61 | assert_no_err(close(fd)); | |
62 | ||
63 | assert_no_err(quotactl(di->mount_point, QCMD(Q_QUOTAON, USRQUOTA), 0, path)); | |
64 | free(path); | |
65 | ||
66 | struct dqblk dqb = { | |
67 | .dqb_bhardlimit = 1024 * 1024, | |
68 | .dqb_ihardlimit = 10, | |
69 | .dqb_isoftlimit = 10, | |
70 | }; | |
71 | ||
72 | assert_no_err(quotactl(di->mount_point, QCMD(Q_SETQUOTA, USRQUOTA), | |
73 | 501, (caddr_t)&dqb)); | |
74 | ||
75 | assert_no_err(chmod(di->mount_point, 0777)); | |
76 | ||
77 | // Now try and create a 2 MB file as UID 501 | |
78 | assert_no_err(seteuid(501)); | |
79 | ||
80 | asprintf(&path, "%s/test-file", di->mount_point); | |
81 | ||
82 | fd = open(path, O_CREAT | O_RDWR, 0777); | |
83 | assert_with_errno(fd >= 0); | |
84 | free(path); | |
85 | ||
86 | /* | |
87 | * Not sure why we can't do the full 4 KB, but it's not a big deal | |
88 | * so let's not worry about it. | |
89 | */ | |
90 | assert_no_err(ftruncate(fd, 1024 * 1024 - 4096)); | |
91 | ||
92 | assert(ftruncate(fd, 2 * 1024 * 1024) == -1 && errno == EDQUOT); | |
93 | ||
94 | assert_no_err(close(fd)); | |
95 | ||
96 | for (int i = 0; i < 10; ++i) { | |
97 | asprintf(&path, "%s/test-file.%u", di->mount_point, i); | |
98 | /* | |
99 | * There might be an off by one error. It's not a big deal, | |
100 | * so we let it go for now. | |
101 | */ | |
102 | fd = open(path, O_CREAT | O_RDWR, 0777); | |
103 | if (fd == -1) { | |
104 | assert(i >= 8); | |
105 | assert_with_errno(errno == EDQUOT); | |
106 | } else { | |
107 | assert(i < 8); | |
108 | free(path); | |
109 | assert_no_err(close(fd)); | |
110 | } | |
111 | } | |
112 | ||
113 | return 0; | |
114 | } |