Skip to content

Commit b8f4007

Browse files
committed
Migrate quota module to libc FFI types
1 parent 28c5b4a commit b8f4007

File tree

1 file changed

+196
-74
lines changed

1 file changed

+196
-74
lines changed

src/sys/quota.rs

Lines changed: 196 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,192 @@
1-
use {Errno, Result, NixPath};
1+
//! Set and configure disk quotas for users, groups, or projects.
2+
use std::default::Default;
3+
use std::{mem, ptr};
24
use libc::{self, c_int, c_char};
5+
use {Errno, Result, NixPath};
6+
7+
struct QuotaCmd(QuotaSubCmd, QuotaType);
8+
9+
impl QuotaCmd {
10+
fn as_int(&self) -> c_int {
11+
(((self.0 as i32) << 8) | ((self.1 as i32) & 0x00ff)) as c_int
12+
}
13+
}
14+
15+
// linux quota version >= 2
16+
libc_enum!{
17+
#[repr(i32)]
18+
enum QuotaSubCmd {
19+
Q_SYNC,
20+
Q_QUOTAON,
21+
Q_QUOTAOFF,
22+
Q_GETFMT,
23+
Q_GETINFO,
24+
Q_SETINFO,
25+
Q_GETQUOTA,
26+
Q_SETQUOTA,
27+
}
28+
}
29+
30+
libc_enum!{
31+
/// The scope of the quota.
32+
#[repr(i32)]
33+
pub enum QuotaType {
34+
/// Specify a user quota
35+
USRQUOTA,
36+
/// Specify a group quota
37+
GRPQUOTA,
38+
}
39+
}
40+
41+
libc_enum!{
42+
/// The type of quota format to use.
43+
#[repr(i32)]
44+
pub enum QuotaFmt {
45+
/// Use the original quota format.
46+
QFMT_VFS_OLD,
47+
/// Use the standard VFS v0 quota format.
48+
///
49+
/// Handles 32-bit UIDs/GIDs and quota limits up to 2^42 bytes/2^32 inodes.
50+
QFMT_VFS_V0,
51+
/// Use the VFS v1 quota format.
52+
///
53+
/// Handles 32-bit UIDs/GIDs and quota limits of 2^64 bytes/2^64 inodes.
54+
QFMT_VFS_V1,
55+
}
56+
}
57+
58+
libc_bitflags!(
59+
/// Indicates the quota fields that are valid to read from.
60+
#[derive(Default)]
61+
pub struct QuotaValidFlags: u32 {
62+
/// The block hard & soft limit fields.
63+
QIF_BLIMITS;
64+
/// The current space field.
65+
QIF_SPACE;
66+
/// The inode hard & soft limit fields.
67+
QIF_ILIMITS;
68+
/// The current inodes field.
69+
QIF_INODES;
70+
/// The disk use time limit field.
71+
QIF_BTIME;
72+
/// The file quote time limit field.
73+
QIF_ITIME;
74+
/// All block & inode limits.
75+
QIF_LIMITS;
76+
/// The space & inodes usage fields.
77+
QIF_USAGE;
78+
/// The time limit fields.
79+
QIF_TIMES;
80+
/// All fields.
81+
QIF_ALL;
82+
}
83+
);
84+
85+
// FIXME: Change to repr(transparent)
86+
#[repr(C)]
87+
#[derive(Clone, Copy)]
88+
pub struct Dqblk(libc::dqblk);
89+
90+
impl Default for Dqblk {
91+
fn default() -> Dqblk {
92+
Dqblk(libc::dqblk {
93+
dqb_bhardlimit: 0,
94+
dqb_bsoftlimit: 0,
95+
dqb_curspace: 0,
96+
dqb_ihardlimit: 0,
97+
dqb_isoftlimit: 0,
98+
dqb_curinodes: 0,
99+
dqb_btime: 0,
100+
dqb_itime: 0,
101+
dqb_valid: 0,
102+
})
103+
}
104+
}
3105

4-
#[cfg(all(target_os = "linux",
5-
any(target_arch = "x86",
6-
target_arch = "x86_64",
7-
target_arch = "arm")),
8-
)]
9-
pub mod quota {
10-
use libc::{self, c_int};
106+
impl Dqblk {
107+
/// The absolute limit on disk quota blocks allocated.
108+
pub fn blocks_hard_limit(&self) -> Option<u64> {
109+
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
110+
if valid_fields.contains(QIF_BLIMITS) {
111+
Some(self.0.dqb_bhardlimit)
112+
} else {
113+
None
114+
}
115+
}Set quota information for user/group id.
11116

12-
pub struct QuotaCmd(pub QuotaSubCmd, pub QuotaType);
13-
pub type QuotaSubCmd = c_int;
14117

15-
impl QuotaCmd {
16-
pub fn as_int(&self) -> c_int {
17-
((self.0 << 8) | (self.1 & 0x00ff)) as c_int
118+
/// Preferred limit on disk quota blocks
119+
pub fn blocks_soft_limit(&self) -> Option<u64> {
120+
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
121+
if valid_fields.contains(QIF_BLIMITS) {
122+
Some(self.0.dqb_bsoftlimit)
123+
} else {
124+
None
18125
}
19126
}
20127

21-
// linux quota version >= 2
22-
pub const Q_SYNC: QuotaSubCmd = 0x800001;
23-
pub const Q_QUOTAON: QuotaSubCmd = 0x800002;
24-
pub const Q_QUOTAOFF: QuotaSubCmd = 0x800003;
25-
pub const Q_GETFMT: QuotaSubCmd = 0x800004;
26-
pub const Q_GETINFO: QuotaSubCmd = 0x800005;
27-
pub const Q_SETINFO: QuotaSubCmd = 0x800006;
28-
pub const Q_GETQUOTA: QuotaSubCmd = 0x800007;
29-
pub const Q_SETQUOTA: QuotaSubCmd = 0x800008;
30-
31-
pub type QuotaType = c_int;
32-
33-
pub const USRQUOTA: QuotaType = 0;
34-
pub const GRPQUOTA: QuotaType = 1;
35-
36-
pub type QuotaFmt = c_int;
37-
38-
pub const QFMT_VFS_OLD: QuotaFmt = 1;
39-
pub const QFMT_VFS_V0: QuotaFmt = 2;
40-
pub const QFMT_VFS_V1: QuotaFmt = 4;
41-
42-
libc_bitflags!(
43-
#[derive(Default)]
44-
pub struct QuotaValidFlags: u32 {
45-
QIF_BLIMITS;
46-
QIF_SPACE;
47-
QIF_ILIMITS;
48-
QIF_INODES;
49-
QIF_BTIME;
50-
QIF_ITIME;
51-
QIF_LIMITS;
52-
QIF_USAGE;
53-
QIF_TIMES;
54-
QIF_ALL;
128+
/// Current occupied space (bytes)
129+
pub fn occupied_space(&self) -> Option<u64> {
130+
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
131+
if valid_fields.contains(QIF_SPACE) {
132+
Some(self.0.dqb_curspace)
133+
} else {
134+
None
135+
}
136+
}
137+
138+
/// Maximum number of allocated inodes
139+
pub fn inodes_hard_limit(&self) -> Option<u64> {
140+
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
141+
if valid_fields.contains(QIF_ILIMITS) {
142+
Some(self.0.dqb_ihardlimit)
143+
} else {
144+
None
145+
}
146+
}
147+
148+
/// Preferred inode limit
149+
pub fn inodes_soft_limit(&self) -> Option<u64> {
150+
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
151+
if valid_fields.contains(QIF_ILIMITS) {
152+
Some(self.0.dqb_isoftlimit)
153+
} else {
154+
None
55155
}
56-
);
57-
58-
#[repr(C)]
59-
#[derive(Default,Debug,Copy,Clone)]
60-
pub struct Dqblk {
61-
pub bhardlimit: u64,
62-
pub bsoftlimit: u64,
63-
pub curspace: u64,
64-
pub ihardlimit: u64,
65-
pub isoftlimit: u64,
66-
pub curinodes: u64,
67-
pub btime: u64,
68-
pub itime: u64,
69-
pub valid: QuotaValidFlags,
70156
}
71-
}
72157

73-
use std::ptr;
158+
/// Current number of allocated inodes.
159+
pub fn allocated_inodes(&self) -> Option<u64> {
160+
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
161+
if valid_fields.contains(QIF_INODES) {
162+
Some(self.0.dqb_curinodes)
163+
} else {
164+
None
165+
}
166+
}
167+
168+
/// Time limit for excessive disk use.
169+
pub fn block_time_limit(&self) -> Option<u64> {
170+
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
171+
if valid_fields.contains(QIF_BTIME) {
172+
Some(self.0.dqb_btime)
173+
} else {
174+
None
175+
}
176+
}
177+
178+
/// Time limit for excessive files.
179+
pub fn inode_time_limit(&self) -> Option<u64> {
180+
let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
181+
if valid_fields.contains(QIF_ITIME) {
182+
Some(self.0.dqb_itime)
183+
} else {
184+
None
185+
}
186+
}
187+
}
74188

75-
fn quotactl<P: ?Sized + NixPath>(cmd: quota::QuotaCmd, special: Option<&P>, id: c_int, addr: *mut c_char) -> Result<()> {
189+
fn quotactl<P: ?Sized + NixPath>(cmd: QuotaCmd, special: Option<&P>, id: c_int, addr: *mut c_char) -> Result<()> {
76190
unsafe {
77191
Errno::clear();
78192
let res = try!(
@@ -86,27 +200,35 @@ fn quotactl<P: ?Sized + NixPath>(cmd: quota::QuotaCmd, special: Option<&P>, id:
86200
}
87201
}
88202

89-
pub fn quotactl_on<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P, format: quota::QuotaFmt, quota_file: &P) -> Result<()> {
203+
/// Turn on disk quotas for a block device.
204+
pub fn quotactl_on<P: ?Sized + NixPath>(which: QuotaType, special: &P, format: QuotaFmt, quota_file: &P) -> Result<()> {
90205
try!(quota_file.with_nix_path(|path| {
91206
let mut path_copy = path.to_bytes_with_nul().to_owned();
92207
let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char;
93-
quotactl(quota::QuotaCmd(quota::Q_QUOTAON, which), Some(special), format as c_int, p)
208+
quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), Some(special), format as c_int, p)
94209
}))
95210
}
96211

97-
pub fn quotactl_off<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P) -> Result<()> {
98-
quotactl(quota::QuotaCmd(quota::Q_QUOTAOFF, which), Some(special), 0, ptr::null_mut())
212+
/// Disable disk quotas for a block device.
213+
pub fn quotactl_off<P: ?Sized + NixPath>(which: QuotaType, special: &P) -> Result<()> {
214+
quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which), Some(special), 0, ptr::null_mut())
99215
}
100216

101-
pub fn quotactl_sync<P: ?Sized + NixPath>(which: quota::QuotaType, special: Option<&P>) -> Result<()> {
102-
quotactl(quota::QuotaCmd(quota::Q_SYNC, which), special, 0, ptr::null_mut())
217+
/// Update the on-disk copy of quota usages for a filesystem.
218+
pub fn quotactl_sync<P: ?Sized + NixPath>(which: QuotaType, special: Option<&P>) -> Result<()> {
219+
quotactl(QuotaCmd(QuotaSubCmd::Q_SYNC, which), special, 0, ptr::null_mut())
103220
}
104221

105-
pub fn quotactl_get<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P, id: c_int, dqblk: &mut quota::Dqblk) -> Result<()> {
106-
quotactl(quota::QuotaCmd(quota::Q_GETQUOTA, which), Some(special), id, dqblk as *mut _ as *mut c_char)
222+
/// Get disk quota limits and current usage for the given user/group id.
223+
pub fn quotactl_get<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int) -> Result<Dqblk> {
224+
let mut dqblk = unsafe { mem::uninitialized() };
225+
quotactl(QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, &mut dqblk as *mut _ as *mut c_char)?;
226+
dqblk
107227
}
108228

109-
pub fn quotactl_set<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P, id: c_int, dqblk: &quota::Dqblk) -> Result<()> {
229+
/// Configure quota values for the specified fields for a given user/group id.
230+
pub fn quotactl_set<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int, dqblk: &Dqblk, fields: QuotaValidFlags) -> Result<()> {
110231
let mut dqblk_copy = *dqblk;
111-
quotactl(quota::QuotaCmd(quota::Q_SETQUOTA, which), Some(special), id, &mut dqblk_copy as *mut _ as *mut c_char)
232+
dqblk_copy.0.dqb_valid = fields.bits();
233+
quotactl(QuotaCmd(QuotaSubCmd::Q_SETQUOTA, which), Some(special), id, &mut dqblk_copy as *mut _ as *mut c_char)
112234
}

0 commit comments

Comments
 (0)