1 /* quotactl.cc: code for manipulating disk quotas
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
18 #include <sys/mount.h>
19 #include <sys/quota.h>
21 #define PGQI_SIZE (sizeof (FILE_GET_QUOTA_INFORMATION) + SECURITY_MAX_SID_SIZE)
22 #define PFQI_SIZE (sizeof (FILE_QUOTA_INFORMATION) + SECURITY_MAX_SID_SIZE)
24 /* Modelled after the Linux quotactl function. */
26 quotactl (int cmd
, const char *special
, int id
, caddr_t addr
)
28 ACCESS_MASK access
= FILE_READ_DATA
;
33 OBJECT_ATTRIBUTES attr
;
37 FILE_FS_CONTROL_INFORMATION ffci
;
40 uint32_t subcmd
= (uint32_t) cmd
>> SUBCMDSHIFT
;
41 uint32_t type
= (uint32_t) cmd
& SUBCMDMASK
;
43 if (type
!= USRQUOTA
&& type
!= GRPQUOTA
)
53 access
|= FILE_WRITE_DATA
;
56 if (id
< QFMT_VFS_OLD
|| id
> QFMT_VFS_V1
)
64 access
|= FILE_WRITE_DATA
;
70 access
|= FILE_WRITE_DATA
;
73 /* Windows feature: Default limits. Get or set them with id == -1. */
77 sid
= sidfromuid (id
, NULL
);
79 sid
= sidfromgid (id
, NULL
);
92 pc
.check (special
, PC_SYM_FOLLOW
, stat_suffixes
);
103 if (!S_ISBLK (pc
.dev
.mode ()))
108 pc
.get_object_attr (attr
, sec_none_nih
);
109 /* For the following functions to work, we must attach the virtual path to
110 the quota file to the device path.
112 FIXME: Note that this is NTFS-specific. Adding ReFS in another step. */
114 RtlCopyUnicodeString (&path
, attr
.ObjectName
);
115 RtlAppendUnicodeToString (&path
, L
"\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION");
116 attr
.ObjectName
= &path
;
118 /* Open filesystem */
119 status
= NtOpenFile (&fh
, access
, &attr
, &io
, FILE_SHARE_VALID_FLAGS
, 0);
120 if (NT_SUCCESS (status
))
124 /* No sync, just report success. */
125 status
= STATUS_SUCCESS
;
129 /* Ignore filename in addr. */
130 status
= NtQueryVolumeInformationFile (fh
, &io
, &ffci
, sizeof ffci
,
131 FileFsControlInformation
);
132 if (!NT_SUCCESS (status
))
134 ffci
.FileSystemControlFlags
&= ~FILE_VC_QUOTA_ENFORCE
135 & ~FILE_VC_QUOTA_TRACK
136 & ~FILE_VC_QUOTAS_INCOMPLETE
137 & ~FILE_VC_QUOTAS_REBUILDING
;
138 if (subcmd
== Q_QUOTAON
)
139 ffci
.FileSystemControlFlags
|= FILE_VC_QUOTA_ENFORCE
;
140 status
= NtSetVolumeInformationFile (fh
, &io
, &ffci
, sizeof ffci
,
141 FileFsControlInformation
);
146 uint32_t *retval
= (uint32_t *) addr
;
148 /* Always fake the latest format. */
149 *retval
= QFMT_VFS_V1
;
157 status
= STATUS_SUCCESS
;
162 struct dqinfo
*dqi
= (struct dqinfo
*) addr
;
164 dqi
->dqi_bgrace
= dqi
->dqi_igrace
= UINT64_MAX
;
166 dqi
->dqi_valid
= IIF_BGRACE
| IIF_IGRACE
;
174 status
= STATUS_SUCCESS
;
177 /* No settings possible, just report success. */
178 status
= STATUS_SUCCESS
;
181 /* Windows feature: Default limits. Get or set them with id == -1. */
184 status
= NtQueryVolumeInformationFile (fh
, &io
, &ffci
, sizeof ffci
,
185 FileFsControlInformation
);
186 if (!NT_SUCCESS (status
))
190 struct dqblk
*dq
= (struct dqblk
*) addr
;
192 dq
->dqb_bhardlimit
= (uint64_t) ffci
.DefaultQuotaLimit
.QuadPart
;
193 if (dq
->dqb_bhardlimit
!= UINT64_MAX
)
194 dq
->dqb_bhardlimit
/= BLOCK_SIZE
;
196 (uint64_t) ffci
.DefaultQuotaThreshold
.QuadPart
;
197 if (dq
->dqb_bsoftlimit
!= UINT64_MAX
)
198 dq
->dqb_bsoftlimit
/= BLOCK_SIZE
;
199 dq
->dqb_curspace
= 0;
200 dq
->dqb_ihardlimit
= UINT64_MAX
;
201 dq
->dqb_isoftlimit
= UINT64_MAX
;
202 dq
->dqb_curinodes
= 0;
203 dq
->dqb_btime
= UINT64_MAX
;
204 dq
->dqb_itime
= UINT64_MAX
;
205 dq
->dqb_valid
= QIF_BLIMITS
;
216 PFILE_GET_QUOTA_INFORMATION pgqi
= (PFILE_GET_QUOTA_INFORMATION
)
218 PFILE_QUOTA_INFORMATION pfqi
= (PFILE_QUOTA_INFORMATION
)
221 pgqi
->NextEntryOffset
= 0;
222 pgqi
->SidLength
= RtlLengthSid (sid
);
223 RtlCopySid (RtlLengthSid (sid
), &pgqi
->Sid
, sid
);
224 status
= NtQueryQuotaInformationFile (fh
, &io
, pfqi
, PFQI_SIZE
,
225 TRUE
, pgqi
, PGQI_SIZE
,
227 if (!NT_SUCCESS (status
))
231 struct dqblk
*dq
= (struct dqblk
*) addr
;
233 dq
->dqb_bhardlimit
= (uint64_t) pfqi
->QuotaLimit
.QuadPart
;
234 if (dq
->dqb_bhardlimit
!= UINT64_MAX
)
235 dq
->dqb_bhardlimit
/= BLOCK_SIZE
;
236 dq
->dqb_bsoftlimit
= (uint64_t) pfqi
->QuotaThreshold
.QuadPart
;
237 if (dq
->dqb_bsoftlimit
!= UINT64_MAX
)
238 dq
->dqb_bsoftlimit
/= BLOCK_SIZE
;
239 dq
->dqb_curspace
= (uint64_t) pfqi
->QuotaUsed
.QuadPart
;
240 if (dq
->dqb_curspace
!= UINT64_MAX
)
241 dq
->dqb_curspace
/= BLOCK_SIZE
;
242 dq
->dqb_ihardlimit
= UINT64_MAX
;
243 dq
->dqb_isoftlimit
= UINT64_MAX
;
244 dq
->dqb_curinodes
= 0;
245 dq
->dqb_btime
= UINT64_MAX
;
246 dq
->dqb_itime
= UINT64_MAX
;
247 dq
->dqb_valid
= QIF_BLIMITS
| QIF_SPACE
;
258 /* Windows feature: Default limits. Get or set them with id == -1. */
261 status
= NtQueryVolumeInformationFile (fh
, &io
, &ffci
, sizeof ffci
,
262 FileFsControlInformation
);
263 if (!NT_SUCCESS (status
))
267 struct dqblk
*dq
= (struct dqblk
*) addr
;
269 if (!(dq
->dqb_valid
& QIF_BLIMITS
))
271 ffci
.DefaultQuotaLimit
.QuadPart
= dq
->dqb_bhardlimit
;
272 if (ffci
.DefaultQuotaLimit
.QuadPart
!= -1)
273 ffci
.DefaultQuotaLimit
.QuadPart
*= BLOCK_SIZE
;
274 ffci
.DefaultQuotaThreshold
.QuadPart
= dq
->dqb_bsoftlimit
;
275 if (ffci
.DefaultQuotaThreshold
.QuadPart
!= -1)
276 ffci
.DefaultQuotaThreshold
.QuadPart
*= BLOCK_SIZE
;
284 status
= NtSetVolumeInformationFile (fh
, &io
, &ffci
, sizeof ffci
,
285 FileFsControlInformation
);
289 PFILE_GET_QUOTA_INFORMATION pgqi
= (PFILE_GET_QUOTA_INFORMATION
)
291 PFILE_QUOTA_INFORMATION pfqi
= (PFILE_QUOTA_INFORMATION
)
294 pgqi
->NextEntryOffset
= 0;
295 pgqi
->SidLength
= RtlLengthSid (sid
);
296 RtlCopySid (RtlLengthSid (sid
), &pgqi
->Sid
, sid
);
297 status
= NtQueryQuotaInformationFile (fh
, &io
, pfqi
, PFQI_SIZE
,
298 TRUE
, pgqi
, PGQI_SIZE
,
300 if (!NT_SUCCESS (status
))
304 struct dqblk
*dq
= (struct dqblk
*) addr
;
306 if (!(dq
->dqb_valid
& QIF_BLIMITS
))
308 pfqi
->QuotaLimit
.QuadPart
= dq
->dqb_bhardlimit
;
309 if (pfqi
->QuotaLimit
.QuadPart
!= -1)
310 pfqi
->QuotaLimit
.QuadPart
*= BLOCK_SIZE
;
311 pfqi
->QuotaThreshold
.QuadPart
= dq
->dqb_bsoftlimit
;
312 if (pfqi
->QuotaThreshold
.QuadPart
!= -1)
313 pfqi
->QuotaThreshold
.QuadPart
*= BLOCK_SIZE
;
321 status
= NtSetQuotaInformationFile (fh
, &io
, pfqi
, PFQI_SIZE
);
325 if (!NT_SUCCESS (status
))
327 __seterrno_from_nt_status (status
);