Cygwin: strptime: add release note
[newlib-cygwin.git] / winsup / cygwin / quotactl.cc
blobf98a32d0b5cb56e403d661c09d1d495c3748cfed
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
7 details. */
9 #include "winsup.h"
10 #include "cygtls.h"
11 #include "security.h"
12 #include "path.h"
13 #include "fhandler.h"
14 #include "dtable.h"
15 #include "cygheap.h"
16 #include "ntdll.h"
17 #include "tls_pbuf.h"
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. */
25 extern "C" int
26 quotactl (int cmd, const char *special, int id, caddr_t addr)
28 ACCESS_MASK access = FILE_READ_DATA;
29 PSID sid = NO_SID;
30 path_conv pc;
31 tmp_pathbuf tp;
32 UNICODE_STRING path;
33 OBJECT_ATTRIBUTES attr;
34 NTSTATUS status;
35 HANDLE fh;
36 IO_STATUS_BLOCK io;
37 FILE_FS_CONTROL_INFORMATION ffci;
38 int ret = 0;
40 uint32_t subcmd = (uint32_t) cmd >> SUBCMDSHIFT;
41 uint32_t type = (uint32_t) cmd & SUBCMDMASK;
43 if (type != USRQUOTA && type != GRPQUOTA)
45 set_errno (EINVAL);
46 return -1;
48 switch (subcmd)
50 case Q_SYNC:
51 if (!special)
52 return 0;
53 access |= FILE_WRITE_DATA;
54 break;
55 case Q_QUOTAON:
56 if (id < QFMT_VFS_OLD || id > QFMT_VFS_V1)
58 set_errno (EINVAL);
59 return -1;
61 fallthrough;
62 case Q_QUOTAOFF:
63 case Q_SETINFO:
64 access |= FILE_WRITE_DATA;
65 break;
66 case Q_GETFMT:
67 case Q_GETINFO:
68 break;
69 case Q_SETQUOTA:
70 access |= FILE_WRITE_DATA;
71 fallthrough;
72 case Q_GETQUOTA:
73 /* Windows feature: Default limits. Get or set them with id == -1. */
74 if (id != -1)
76 if (type == USRQUOTA)
77 sid = sidfromuid (id, NULL);
78 else
79 sid = sidfromgid (id, NULL);
80 if (sid == NO_SID)
82 set_errno (EINVAL);
83 return -1;
86 break;
87 default:
88 set_errno (EINVAL);
89 return -1;
91 /* Check path */
92 pc.check (special, PC_SYM_FOLLOW, stat_suffixes);
93 if (pc.error)
95 set_errno (pc.error);
96 return -1;
98 if (!pc.exists ())
100 set_errno (ENOENT);
101 return -1;
103 if (!S_ISBLK (pc.dev.mode ()))
105 set_errno (ENOTBLK);
106 return -1;
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. */
113 tp.u_get (&path);
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))
121 switch (subcmd)
123 case Q_SYNC:
124 /* No sync, just report success. */
125 status = STATUS_SUCCESS;
126 break;
127 case Q_QUOTAON:
128 case Q_QUOTAOFF:
129 /* Ignore filename in addr. */
130 status = NtQueryVolumeInformationFile (fh, &io, &ffci, sizeof ffci,
131 FileFsControlInformation);
132 if (!NT_SUCCESS (status))
133 break;
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);
142 break;
143 case Q_GETFMT:
144 __try
146 uint32_t *retval = (uint32_t *) addr;
148 /* Always fake the latest format. */
149 *retval = QFMT_VFS_V1;
151 __except (EFAULT)
153 ret = -1;
154 break;
156 __endtry
157 status = STATUS_SUCCESS;
158 break;
159 case Q_GETINFO:
160 __try
162 struct dqinfo *dqi = (struct dqinfo *) addr;
164 dqi->dqi_bgrace = dqi->dqi_igrace = UINT64_MAX;
165 dqi->dqi_flags = 0;
166 dqi->dqi_valid = IIF_BGRACE | IIF_IGRACE;
168 __except (EFAULT)
170 ret = -1;
171 break;
173 __endtry
174 status = STATUS_SUCCESS;
175 break;
176 case Q_SETINFO:
177 /* No settings possible, just report success. */
178 status = STATUS_SUCCESS;
179 break;
180 case Q_GETQUOTA:
181 /* Windows feature: Default limits. Get or set them with id == -1. */
182 if (id == -1)
184 status = NtQueryVolumeInformationFile (fh, &io, &ffci, sizeof ffci,
185 FileFsControlInformation);
186 if (!NT_SUCCESS (status))
187 break;
188 __try
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;
195 dq->dqb_bsoftlimit =
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;
207 __except (EFAULT)
209 ret = -1;
210 break;
212 __endtry
214 else
216 PFILE_GET_QUOTA_INFORMATION pgqi = (PFILE_GET_QUOTA_INFORMATION)
217 alloca (PGQI_SIZE);
218 PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)
219 alloca (PFQI_SIZE);
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,
226 NULL, TRUE);
227 if (!NT_SUCCESS (status))
228 break;
229 __try
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;
249 __except (EFAULT)
251 ret = -1;
252 break;
254 __endtry
256 break;
257 case Q_SETQUOTA:
258 /* Windows feature: Default limits. Get or set them with id == -1. */
259 if (id == -1)
261 status = NtQueryVolumeInformationFile (fh, &io, &ffci, sizeof ffci,
262 FileFsControlInformation);
263 if (!NT_SUCCESS (status))
264 break;
265 __try
267 struct dqblk *dq = (struct dqblk *) addr;
269 if (!(dq->dqb_valid & QIF_BLIMITS))
270 break;
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;
278 __except (EFAULT)
280 ret = -1;
281 break;
283 __endtry
284 status = NtSetVolumeInformationFile (fh, &io, &ffci, sizeof ffci,
285 FileFsControlInformation);
287 else
289 PFILE_GET_QUOTA_INFORMATION pgqi = (PFILE_GET_QUOTA_INFORMATION)
290 alloca (PGQI_SIZE);
291 PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)
292 alloca (PFQI_SIZE);
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,
299 NULL, TRUE);
300 if (!NT_SUCCESS (status))
301 break;
302 __try
304 struct dqblk *dq = (struct dqblk *) addr;
306 if (!(dq->dqb_valid & QIF_BLIMITS))
307 break;
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;
315 __except (EFAULT)
317 ret = -1;
318 break;
320 __endtry
321 status = NtSetQuotaInformationFile (fh, &io, pfqi, PFQI_SIZE);
323 break;
325 if (!NT_SUCCESS (status))
327 __seterrno_from_nt_status (status);
328 ret = -1;
330 return ret;