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
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use {Result, NixPath, from_ffi};
use errno::Errno;
use libc::{c_int, c_char};

#[cfg(all(target_os = "linux",
          any(target_arch = "x86",
              target_arch = "x86_64",
              target_arch = "arm")),
          )]
pub mod quota {
	use libc::c_int;

	pub struct QuotaCmd(pub QuotaSubCmd, pub QuotaType);
	pub type QuotaSubCmd = c_int;

	impl QuotaCmd {
		pub fn as_int(&self) -> c_int {
			((self.0 << 8) | (self.1 & 0x00ff)) as c_int 
		}
	}

	// linux quota version >= 2
	pub const Q_SYNC:	QuotaSubCmd = 0x800001;
	pub const Q_QUOTAON:	QuotaSubCmd = 0x800002;
	pub const Q_QUOTAOFF:	QuotaSubCmd = 0x800003;
	pub const Q_GETFMT:	QuotaSubCmd = 0x800004;
	pub const Q_GETINFO:	QuotaSubCmd = 0x800005;
	pub const Q_SETINFO:	QuotaSubCmd = 0x800006;
	pub const Q_GETQUOTA:	QuotaSubCmd = 0x800007;
	pub const Q_SETQUOTA:	QuotaSubCmd = 0x800008;

	pub type QuotaType = c_int;

	pub const USRQUOTA:	QuotaType = 0;
	pub const GRPQUOTA:	QuotaType = 1;

	pub type QuotaFmt = c_int;

	pub const QFMT_VFS_OLD:	QuotaFmt = 1;
	pub const QFMT_VFS_V0:	QuotaFmt = 2;
	pub const QFMT_VFS_V1:  QuotaFmt = 4;

	bitflags!(
		#[derive(Default)]
		flags QuotaValidFlags: u32 {
			const QIF_BLIMITS	 = 1,
			const QIF_SPACE		 = 2,
			const QIF_ILIMITS	 = 4,
			const QIF_INODES	 = 8,
			const QIF_BTIME 	 = 16,
			const QIF_ITIME 	 = 32,
			const QIF_LIMITS 	 = QIF_BLIMITS.bits | QIF_ILIMITS.bits,
			const QIF_USAGE 	 = QIF_SPACE.bits | QIF_INODES.bits,
			const QIF_TIMES 	 = QIF_BTIME.bits | QIF_ITIME.bits,
			const QIF_ALL 		 = QIF_LIMITS.bits | QIF_USAGE.bits | QIF_TIMES.bits
		}
	);

	#[repr(C)]
	#[derive(Default,Debug,Copy,Clone)]
	pub struct Dqblk {
		pub bhardlimit: u64,
		pub bsoftlimit: u64,
		pub curspace:   u64,
		pub ihardlimit: u64,
		pub isoftlimit: u64,
		pub curinodes: u64,
		pub btime: u64,
		pub itime: u64,
		pub valid: QuotaValidFlags,
	}
}

mod ffi {
	use libc::{c_int, c_char};

	extern {
		pub fn quotactl(cmd: c_int, special: * const c_char, id: c_int, data: *mut c_char) -> c_int;
	}
}

use std::ptr;

fn quotactl<P: ?Sized + NixPath>(cmd: quota::QuotaCmd, special: Option<&P>, id: c_int, addr: *mut c_char) -> Result<()> {
	unsafe {
		Errno::clear();
		let res = try!(
			match special {
				Some(dev) => dev.with_nix_path(|path| ffi::quotactl(cmd.as_int(), path.as_ptr(), id, addr)),
				None => Ok(ffi::quotactl(cmd.as_int(), ptr::null(), id, addr)),
			}
		);
		from_ffi(res)
	}
}

pub fn quotactl_on<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P, format: quota::QuotaFmt, quota_file: &P) -> Result<()> {
	try!(quota_file.with_nix_path(|path| {
		let mut path_copy = path.to_bytes_with_nul().to_owned();
		let p: *mut i8 = path_copy.as_mut_ptr() as *mut i8;
		quotactl(quota::QuotaCmd(quota::Q_QUOTAON, which), Some(special), format as c_int, p)
	}))
}

pub fn quotactl_off<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P) -> Result<()> {
	quotactl(quota::QuotaCmd(quota::Q_QUOTAOFF, which), Some(special), 0, ptr::null_mut())
}

pub fn quotactl_sync<P: ?Sized + NixPath>(which: quota::QuotaType, special: Option<&P>) -> Result<()> {
	quotactl(quota::QuotaCmd(quota::Q_SYNC, which), special, 0, ptr::null_mut())
}

pub fn quotactl_get<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P, id: c_int, dqblk: &mut quota::Dqblk) -> Result<()> {
	use std::mem;
	unsafe {
		quotactl(quota::QuotaCmd(quota::Q_GETQUOTA, which), Some(special), id, mem::transmute(dqblk))
	}
}

pub fn quotactl_set<P: ?Sized + NixPath>(which: quota::QuotaType, special: &P, id: c_int, dqblk: &quota::Dqblk) -> Result<()> {
	use std::mem;
	let mut dqblk_copy = *dqblk;
	unsafe {
		quotactl(quota::QuotaCmd(quota::Q_SETQUOTA, which), Some(special), id, mem::transmute(&mut dqblk_copy))
	}
}