* common.din (quotactl): Export.
* ntdll.h: Define FILE_FS_CONTROL_INFORMATION::FileSystemControlFlags
flag values.
(struct _FILE_FS_CONTROL_INFORMATION): Define.
(struct _FILE_GET_QUOTA_INFORMATION): Define.
(typedef struct _FILE_QUOTA_INFORMATION): Define.
(NtQueryObject): Use PVOID rather than VOID*.
(NtQueryVolumeInformationFile): Ditto.
(NtQueryQuotaInformationFile): Declare.
(NtSetQuotaInformationFile): Declare.
(NtSetVolumeInformationFile): Declare.
* quotactl.cc: New file implementing quotactl().
* include/sys/mount.h (BLOCK_SIZE): Define.
(BLOCK_SIZE_BITS): Define.
* include/sys/quota.h: New header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
+2014-10-16 Corinna Vinschen <corinna@vinschen.de>
+
+ * Makefile.in (DLL_OFILES): Add quotactl.o.
+ * common.din (quotactl): Export.
+ * ntdll.h: Define FILE_FS_CONTROL_INFORMATION::FileSystemControlFlags
+ flag values.
+ (struct _FILE_FS_CONTROL_INFORMATION): Define.
+ (struct _FILE_GET_QUOTA_INFORMATION): Define.
+ (typedef struct _FILE_QUOTA_INFORMATION): Define.
+ (NtQueryObject): Use PVOID rather than VOID*.
+ (NtQueryVolumeInformationFile): Ditto.
+ (NtQueryQuotaInformationFile): Declare.
+ (NtSetQuotaInformationFile): Declare.
+ (NtSetVolumeInformationFile): Declare.
+ * quotactl.cc: New file implementing quotactl().
+ * include/sys/mount.h (BLOCK_SIZE): Define.
+ (BLOCK_SIZE_BITS): Define.
+ * include/sys/quota.h: New header.
+ * include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
+
2014-10-16 Corinna Vinschen <corinna@vinschen.de>
* Makefile.in (DLL_OFILES): Rearrange with one file per line.
posix_ipc.o \
pseudo-reloc.o \
pthread.o \
+ quotactl.o \
random.o \
regcomp.o \
regerror.o \
putwchar SIGFE
pwrite SIGFE
qsort NOSIGFE
+quotactl SIGFE
raise SIGFE
rand NOSIGFE
rand_r NOSIGFE
CW_CYGNAME_FROM_WINNAME.
276: Export ffsl, ffsll.
277: Add setsockopt(SO_PEERCRED).
+ 278: Add quotactl.
*/
/* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
#define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 277
+#define CYGWIN_VERSION_API_MINOR 278
/* There is also a compatibity version number associated with the
shared memory regions. It is incremented when incompatible
/* sys/mount.h
- Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2008, 2009, 2010, 2012
- Red Hat, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2008, 2009, 2010, 2012,
+ 2014 Red Hat, Inc.
This file is part of Cygwin.
#ifndef _SYS_MOUNT_H
#define _SYS_MOUNT_H
+#define BLOCK_SIZE 1024
+#define BLOCK_SIZE_BITS 10
+
#ifdef __cplusplus
extern "C" {
#endif
--- /dev/null
+/* Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _SYS_QUOTA_H
+#define _SYS_QUOTA_H 1
+
+#include <features.h>
+#include <sys/types.h>
+
+/* This file is copied from Linux and kept verbatim, except for the below
+ Cygwin-specific blocks. */
+
+#ifdef __CYGWIN__
+/* On Linux these defines live in <linux/quota.h>. Move them here for easier
+ access. */
+/* Quota format type IDs */
+#define QFMT_VFS_OLD 1
+#define QFMT_VFS_V0 2
+#define QFMT_OCFS2 3
+#define QFMT_VFS_V1 4
+#endif
+
+/*
+ * Select between different incompatible quota versions.
+ * Default to the version used by Linux kernel version 2.4.22
+ * or later. */
+#ifndef _LINUX_QUOTA_VERSION
+# define _LINUX_QUOTA_VERSION 2
+#endif
+
+#if defined (__CYGWIN__) && _LINUX_QUOTA_VERSION != 2
+#error Cygwin only supports quota version 2.
+#endif
+
+/*
+ * Convert diskblocks to blocks and the other way around.
+ * currently only to fool the BSD source. :-)
+ */
+#define dbtob(num) ((num) << 10)
+#define btodb(num) ((num) >> 10)
+
+/*
+ * Convert count of filesystem blocks to diskquota blocks, meant
+ * for filesystems where i_blksize != BLOCK_SIZE
+ */
+#define fs_to_dq_blocks(num, blksize) (((num) * (blksize)) / BLOCK_SIZE)
+
+/*
+ * Definitions for disk quotas imposed on the average user
+ * (big brother finally hits Linux).
+ *
+ * The following constants define the amount of time given a user
+ * before the soft limits are treated as hard limits (usually resulting
+ * in an allocation failure). The timer is started when the user crosses
+ * their soft limit, it is reset when they go below their soft limit.
+ */
+#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */
+#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */
+
+#define MAXQUOTAS 2
+#define USRQUOTA 0 /* element used for user quotas */
+#define GRPQUOTA 1 /* element used for group quotas */
+
+/*
+ * Definitions for the default names of the quotas files.
+ */
+#define INITQFNAMES { \
+ "user", /* USRQUOTA */ \
+ "group", /* GRPQUOTA */ \
+ "undefined", \
+};
+
+#define QUOTAFILENAME "quota"
+#define QUOTAGROUP "staff"
+
+#define NR_DQHASH 43 /* Just an arbitrary number any suggestions ? */
+#define NR_DQUOTS 256 /* Number of quotas active at one time */
+
+/*
+ * Command definitions for the 'quotactl' system call.
+ * The commands are broken into a main command defined below
+ * and a subcommand that is used to convey the type of
+ * quota that is being manipulated (see above).
+ */
+#define SUBCMDMASK 0x00ff
+#define SUBCMDSHIFT 8
+#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
+
+#if _LINUX_QUOTA_VERSION < 2
+# define Q_QUOTAON 0x0100 /* enable quotas */
+# define Q_QUOTAOFF 0x0200 /* disable quotas */
+# define Q_GETQUOTA 0x0300 /* get limits and usage */
+# define Q_SETQUOTA 0x0400 /* set limits and usage */
+# define Q_SETUSE 0x0500 /* set usage */
+# define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */
+# define Q_SETQLIM 0x0700 /* set limits */
+# define Q_GETSTATS 0x0800 /* get collected stats */
+# define Q_RSQUASH 0x1000 /* set root_squash option */
+#else
+# define Q_SYNC 0x800001 /* sync disk copy of a filesystems quotas */
+# define Q_QUOTAON 0x800002 /* turn quotas on */
+# define Q_QUOTAOFF 0x800003 /* turn quotas off */
+# define Q_GETFMT 0x800004 /* get quota format used on given filesystem */
+# define Q_GETINFO 0x800005 /* get information about quota files */
+# define Q_SETINFO 0x800006 /* set information about quota files */
+# define Q_GETQUOTA 0x800007 /* get user quota structure */
+# define Q_SETQUOTA 0x800008 /* set user quota structure */
+#endif
+
+/*
+ * The following structure defines the format of the disk quota file
+ * (as it appears on disk) - the file is an array of these structures
+ * indexed by user or group number.
+ */
+#if _LINUX_QUOTA_VERSION < 2
+struct dqblk
+ {
+ u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
+ u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */
+ u_int32_t dqb_curblocks; /* current block count */
+ u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */
+ u_int32_t dqb_isoftlimit; /* preferred inode limit */
+ u_int32_t dqb_curinodes; /* current # allocated inodes */
+ time_t dqb_btime; /* time limit for excessive disk use */
+ time_t dqb_itime; /* time limit for excessive files */
+ };
+#else
+
+/* Flags that indicate which fields in dqblk structure are valid. */
+#define QIF_BLIMITS 1
+#define QIF_SPACE 2
+#define QIF_ILIMITS 4
+#define QIF_INODES 8
+#define QIF_BTIME 16
+#define QIF_ITIME 32
+#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS)
+#define QIF_USAGE (QIF_SPACE | QIF_INODES)
+#define QIF_TIMES (QIF_BTIME | QIF_ITIME)
+#define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES)
+
+struct dqblk
+ {
+ u_int64_t dqb_bhardlimit; /* absolute limit on disk quota blocks alloc */
+ u_int64_t dqb_bsoftlimit; /* preferred limit on disk quota blocks */
+ u_int64_t dqb_curspace; /* current quota block count */
+ u_int64_t dqb_ihardlimit; /* maximum # allocated inodes */
+ u_int64_t dqb_isoftlimit; /* preferred inode limit */
+ u_int64_t dqb_curinodes; /* current # allocated inodes */
+ u_int64_t dqb_btime; /* time limit for excessive disk use */
+ u_int64_t dqb_itime; /* time limit for excessive files */
+ u_int32_t dqb_valid; /* bitmask of QIF_* constants */
+ };
+#endif
+
+/*
+ * Shorthand notation.
+ */
+#define dq_bhardlimit dq_dqb.dqb_bhardlimit
+#define dq_bsoftlimit dq_dqb.dqb_bsoftlimit
+#if _LINUX_QUOTA_VERSION < 2
+# define dq_curblocks dq_dqb.dqb_curblocks
+#else
+# define dq_curspace dq_dqb.dqb_curspace
+# define dq_valid dq_dqb.dqb_valid
+#endif
+#define dq_ihardlimit dq_dqb.dqb_ihardlimit
+#define dq_isoftlimit dq_dqb.dqb_isoftlimit
+#define dq_curinodes dq_dqb.dqb_curinodes
+#define dq_btime dq_dqb.dqb_btime
+#define dq_itime dq_dqb.dqb_itime
+
+#define dqoff(UID) ((loff_t)((UID) * sizeof (struct dqblk)))
+
+#if _LINUX_QUOTA_VERSION < 2
+struct dqstats
+ {
+ u_int32_t lookups;
+ u_int32_t drops;
+ u_int32_t reads;
+ u_int32_t writes;
+ u_int32_t cache_hits;
+ u_int32_t pages_allocated;
+ u_int32_t allocated_dquots;
+ u_int32_t free_dquots;
+ u_int32_t syncs;
+ };
+#else
+
+/* Flags that indicate which fields in dqinfo structure are valid. */
+# define IIF_BGRACE 1
+# define IIF_IGRACE 2
+# define IIF_FLAGS 4
+# define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS)
+
+struct dqinfo
+ {
+ u_int64_t dqi_bgrace;
+ u_int64_t dqi_igrace;
+ u_int32_t dqi_flags;
+ u_int32_t dqi_valid;
+ };
+#endif
+
+__BEGIN_DECLS
+
+extern int quotactl (int __cmd, const char *__special, int __id,
+ caddr_t __addr) __THROW;
+
+__END_DECLS
+
+#endif /* sys/quota.h */
#define HEAP_FLAG_EXECUTABLE 0x40000
#define HEAP_FLAG_DEBUGGED 0x40000000
+#define FILE_VC_QUOTA_NONE 0x00000000
+#define FILE_VC_QUOTA_TRACK 0x00000001
+#define FILE_VC_QUOTA_ENFORCE 0x00000002
+#define FILE_VC_QUOTA_MASK 0x00000003
+#define FILE_VC_CONTENT_INDEX_DISABLED 0x00000008
+#define FILE_VC_LOG_QUOTA_THRESHOLD 0x00000010
+#define FILE_VC_LOG_QUOTA_LIMIT 0x00000020
+#define FILE_VC_LOG_VOLUME_THRESHOLD 0x00000040
+#define FILE_VC_LOG_VOLUME_LIMIT 0x00000080
+#define FILE_VC_QUOTAS_INCOMPLETE 0x00000100
+#define FILE_VC_QUOTAS_REBUILDING 0x00000200
+#define FILE_VC_VALID_MASK 0x000003ff
+
/* IOCTL code to impersonate client of named pipe. */
#define FSCTL_PIPE_IMPERSONATE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 7, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
ULONG BytesPerSector;
} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;
+/* Checked on 64 bit. */
+typedef struct _FILE_FS_CONTROL_INFORMATION {
+ LARGE_INTEGER FreeSpaceStartFiltering;
+ LARGE_INTEGER FreeSpaceThreshold;
+ LARGE_INTEGER FreeSpaceStopFiltering;
+ LARGE_INTEGER DefaultQuotaThreshold;
+ LARGE_INTEGER DefaultQuotaLimit;
+ ULONG FileSystemControlFlags;
+} FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION;
+
/* Checked on 64 bit. */
typedef struct _FILE_FS_FULL_SIZE_INFORMATION
{
UNICODE_STRING ObjectTypeName;
} DIRECTORY_BASIC_INFORMATION, *PDIRECTORY_BASIC_INFORMATION;
+/* Checked on 64 bit. */
+typedef struct _FILE_GET_QUOTA_INFORMATION {
+ ULONG NextEntryOffset;
+ ULONG SidLength;
+ SID Sid;
+} FILE_GET_QUOTA_INFORMATION, *PFILE_GET_QUOTA_INFORMATION;
+
+/* Checked on 64 bit. */
+typedef struct _FILE_QUOTA_INFORMATION {
+ ULONG NextEntryOffset;
+ ULONG SidLength;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER QuotaUsed;
+ LARGE_INTEGER QuotaThreshold;
+ LARGE_INTEGER QuotaLimit;
+ SID Sid;
+} FILE_QUOTA_INFORMATION, *PFILE_QUOTA_INFORMATION;
+
/* Checked on 64 bit. */
typedef struct _FILE_GET_EA_INFORMATION
{
ULONG, PULONG);
NTSTATUS NTAPI NtQueryInformationToken (HANDLE, TOKEN_INFORMATION_CLASS,
PVOID, ULONG, PULONG);
- NTSTATUS NTAPI NtQueryObject (HANDLE, OBJECT_INFORMATION_CLASS, VOID *,
- ULONG, ULONG *);
+ NTSTATUS NTAPI NtQueryObject (HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG,
+ PULONG);
+ NTSTATUS NTAPI NtQueryQuotaInformationFile (HANDLE, PIO_STATUS_BLOCK, PVOID,
+ ULONG, BOOLEAN, PVOID, ULONG,
+ PSID, BOOLEAN);
NTSTATUS NTAPI NtQuerySemaphore (HANDLE, SEMAPHORE_INFORMATION_CLASS,
PVOID, ULONG, PULONG);
NTSTATUS NTAPI NtQuerySystemInformation (SYSTEM_INFORMATION_CLASS,
PULONG);
NTSTATUS NTAPI NtQueryVirtualMemory (HANDLE, PVOID, MEMORY_INFORMATION_CLASS,
PVOID, SIZE_T, PSIZE_T);
- NTSTATUS NTAPI NtQueryVolumeInformationFile (HANDLE, IO_STATUS_BLOCK *,
- VOID *, ULONG,
- FS_INFORMATION_CLASS);
+ NTSTATUS NTAPI NtQueryVolumeInformationFile (HANDLE, PIO_STATUS_BLOCK, PVOID,
+ ULONG, FS_INFORMATION_CLASS);
NTSTATUS NTAPI NtReadFile (HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID,
PIO_STATUS_BLOCK, PVOID, ULONG, PLARGE_INTEGER,
PULONG);
NTSTATUS NTAPI NtSetInformationThread (HANDLE, THREADINFOCLASS, PVOID, ULONG);
NTSTATUS NTAPI NtSetInformationToken (HANDLE, TOKEN_INFORMATION_CLASS, PVOID,
ULONG);
+ NTSTATUS NTAPI NtSetQuotaInformationFile (HANDLE, PIO_STATUS_BLOCK, PVOID,
+ ULONG);
NTSTATUS NTAPI NtSetSecurityObject (HANDLE, SECURITY_INFORMATION,
PSECURITY_DESCRIPTOR);
NTSTATUS NTAPI NtSetTimer (HANDLE, PLARGE_INTEGER, PTIMER_APC_ROUTINE, PVOID,
NTSTATUS NTAPI NtSetTimerResolution (ULONG, BOOLEAN, PULONG);
NTSTATUS NTAPI NtSetValueKey (HANDLE, PUNICODE_STRING, ULONG, ULONG, PVOID,
ULONG);
+ NTSTATUS NTAPI NtSetVolumeInformationFile (HANDLE, PIO_STATUS_BLOCK, PVOID,
+ ULONG, FS_INFORMATION_CLASS);
NTSTATUS NTAPI NtUnlockFile (HANDLE, PIO_STATUS_BLOCK, PLARGE_INTEGER,
PLARGE_INTEGER, ULONG);
NTSTATUS NTAPI NtUnlockVirtualMemory (HANDLE, PVOID *, PSIZE_T, ULONG);
--- /dev/null
+/* quotactl.cc: code for manipulating disk quotas
+
+ Copyright 2014 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include "cygtls.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "ntdll.h"
+#include "tls_pbuf.h"
+#include <sys/mount.h>
+#include <sys/quota.h>
+
+#define PGQI_SIZE (sizeof (FILE_GET_QUOTA_INFORMATION) + SECURITY_MAX_SID_SIZE)
+#define PFQI_SIZE (sizeof (FILE_QUOTA_INFORMATION) + SECURITY_MAX_SID_SIZE)
+
+/* Modelled after the Linux quotactl function. */
+extern "C" int
+quotactl (int cmd, const char *special, int id, caddr_t addr)
+{
+ ACCESS_MASK access = FILE_READ_DATA;
+ cygsid sid;
+ path_conv pc;
+ tmp_pathbuf tp;
+ UNICODE_STRING path;
+ OBJECT_ATTRIBUTES attr;
+ NTSTATUS status;
+ HANDLE fh;
+ IO_STATUS_BLOCK io;
+ FILE_FS_CONTROL_INFORMATION ffci;
+ int ret = 0;
+
+ uint32_t subcmd = (uint32_t) cmd >> SUBCMDSHIFT;
+ uint32_t type = (uint32_t) cmd & SUBCMDMASK;
+
+ if (type != USRQUOTA && type != GRPQUOTA)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ switch (subcmd)
+ {
+ case Q_SYNC:
+ if (!special)
+ return 0;
+ access |= FILE_WRITE_DATA;
+ break;
+ case Q_QUOTAON:
+ if (id < QFMT_VFS_OLD || id > QFMT_VFS_V1)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ /*FALLTHRU*/
+ case Q_QUOTAOFF:
+ case Q_SETINFO:
+ access |= FILE_WRITE_DATA;
+ break;
+ case Q_GETFMT:
+ case Q_GETINFO:
+ break;
+ case Q_SETQUOTA:
+ access |= FILE_WRITE_DATA;
+ /*FALLTHRU*/
+ case Q_GETQUOTA:
+ /* Windows feature: Default limits. Get or set them with id == -1. */
+ if (id != -1)
+ {
+ struct passwd *pw = NULL;
+ struct group *gr = NULL;
+
+ if (type == USRQUOTA)
+ pw = internal_getpwuid (id);
+ else
+ gr = internal_getgrgid (id);
+ if (pw)
+ sid.getfrompw (pw);
+ else if (gr)
+ sid.getfromgr (gr);
+ else
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ }
+ break;
+ default:
+ set_errno (EINVAL);
+ return -1;
+ }
+ /* Check path */
+ pc.check (special, PC_SYM_FOLLOW | PC_NOWARN, stat_suffixes);
+ if (pc.error)
+ {
+ set_errno (pc.error);
+ return -1;
+ }
+ if (!pc.exists ())
+ {
+ set_errno (ENOENT);
+ return -1;
+ }
+ if (!S_ISBLK (pc.dev.mode))
+ {
+ set_errno (ENOTBLK);
+ return -1;
+ }
+ pc.get_object_attr (attr, sec_none_nih);
+ /* For the following functions to work, we must attach the virtual path to
+ the quota file to the device path.
+
+ FIXME: Note that this is NTFS-specific. Adding ReFS in another step. */
+ tp.u_get (&path);
+ RtlCopyUnicodeString (&path, attr.ObjectName);
+ RtlAppendUnicodeToString (&path, L"\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION");
+ attr.ObjectName = &path;
+
+ /* Open filesystem */
+ status = NtOpenFile (&fh, access, &attr, &io, FILE_SHARE_VALID_FLAGS, 0);
+ if (NT_SUCCESS (status))
+ switch (subcmd)
+ {
+ case Q_SYNC:
+ /* No sync, just report success. */
+ status = STATUS_SUCCESS;
+ break;
+ case Q_QUOTAON:
+ case Q_QUOTAOFF:
+ /* Ignore filename in addr. */
+ status = NtQueryVolumeInformationFile (fh, &io, &ffci, sizeof ffci,
+ FileFsControlInformation);
+ if (!NT_SUCCESS (status))
+ break;
+ ffci.FileSystemControlFlags &= ~FILE_VC_QUOTA_ENFORCE
+ & ~FILE_VC_QUOTA_TRACK
+ & ~FILE_VC_QUOTAS_INCOMPLETE
+ & ~FILE_VC_QUOTAS_REBUILDING;
+ if (subcmd == Q_QUOTAON)
+ ffci.FileSystemControlFlags |= FILE_VC_QUOTA_ENFORCE;
+ status = NtSetVolumeInformationFile (fh, &io, &ffci, sizeof ffci,
+ FileFsControlInformation);
+ break;
+ case Q_GETFMT:
+ __try
+ {
+ uint32_t *retval = (uint32_t *) addr;
+
+ /* Always fake the latest format. */
+ *retval = QFMT_VFS_V1;
+ }
+ __except (EFAULT)
+ {
+ ret = -1;
+ break;
+ }
+ __endtry
+ status = STATUS_SUCCESS;
+ break;
+ case Q_GETINFO:
+ __try
+ {
+ struct dqinfo *dqi = (struct dqinfo *) addr;
+
+ dqi->dqi_bgrace = dqi->dqi_igrace = UINT64_MAX;
+ dqi->dqi_flags = 0;
+ dqi->dqi_valid = IIF_BGRACE | IIF_IGRACE;
+ }
+ __except (EFAULT)
+ {
+ ret = -1;
+ break;
+ }
+ __endtry
+ status = STATUS_SUCCESS;
+ break;
+ case Q_SETINFO:
+ /* No settings possible, just report success. */
+ status = STATUS_SUCCESS;
+ break;
+ case Q_GETQUOTA:
+ /* Windows feature: Default limits. Get or set them with id == -1. */
+ if (id == -1)
+ {
+ status = NtQueryVolumeInformationFile (fh, &io, &ffci, sizeof ffci,
+ FileFsControlInformation);
+ if (!NT_SUCCESS (status))
+ break;
+ __try
+ {
+ struct dqblk *dq = (struct dqblk *) addr;
+
+ dq->dqb_bhardlimit = (uint64_t) ffci.DefaultQuotaLimit.QuadPart;
+ if (dq->dqb_bhardlimit != UINT64_MAX)
+ dq->dqb_bhardlimit /= BLOCK_SIZE;
+ dq->dqb_bsoftlimit =
+ (uint64_t) ffci.DefaultQuotaThreshold.QuadPart;
+ if (dq->dqb_bsoftlimit != UINT64_MAX)
+ dq->dqb_bsoftlimit /= BLOCK_SIZE;
+ dq->dqb_curspace = 0;
+ dq->dqb_ihardlimit = UINT64_MAX;
+ dq->dqb_isoftlimit = UINT64_MAX;
+ dq->dqb_curinodes = 0;
+ dq->dqb_btime = UINT64_MAX;
+ dq->dqb_itime = UINT64_MAX;
+ dq->dqb_valid = QIF_BLIMITS;
+ }
+ __except (EFAULT)
+ {
+ ret = -1;
+ break;
+ }
+ __endtry
+ }
+ else
+ {
+ PFILE_GET_QUOTA_INFORMATION pgqi = (PFILE_GET_QUOTA_INFORMATION)
+ alloca (PGQI_SIZE);
+ PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)
+ alloca (PFQI_SIZE);
+
+ pgqi->NextEntryOffset = 0;
+ pgqi->SidLength = RtlLengthSid (sid);
+ RtlCopySid (RtlLengthSid (sid), &pgqi->Sid, sid);
+ status = NtQueryQuotaInformationFile (fh, &io, pfqi, PFQI_SIZE,
+ TRUE, pgqi, PGQI_SIZE,
+ NULL, TRUE);
+ if (!NT_SUCCESS (status))
+ break;
+ __try
+ {
+ struct dqblk *dq = (struct dqblk *) addr;
+
+ dq->dqb_bhardlimit = (uint64_t) pfqi->QuotaLimit.QuadPart;
+ if (dq->dqb_bhardlimit != UINT64_MAX)
+ dq->dqb_bhardlimit /= BLOCK_SIZE;
+ dq->dqb_bsoftlimit = (uint64_t) pfqi->QuotaThreshold.QuadPart;
+ if (dq->dqb_bsoftlimit != UINT64_MAX)
+ dq->dqb_bsoftlimit /= BLOCK_SIZE;
+ dq->dqb_curspace = (uint64_t) pfqi->QuotaUsed.QuadPart;
+ if (dq->dqb_curspace != UINT64_MAX)
+ dq->dqb_curspace /= BLOCK_SIZE;
+ dq->dqb_ihardlimit = UINT64_MAX;
+ dq->dqb_isoftlimit = UINT64_MAX;
+ dq->dqb_curinodes = 0;
+ dq->dqb_btime = UINT64_MAX;
+ dq->dqb_itime = UINT64_MAX;
+ dq->dqb_valid = QIF_BLIMITS | QIF_SPACE;
+ }
+ __except (EFAULT)
+ {
+ ret = -1;
+ break;
+ }
+ __endtry
+ }
+ break;
+ case Q_SETQUOTA:
+ /* Windows feature: Default limits. Get or set them with id == -1. */
+ if (id == -1)
+ {
+ status = NtQueryVolumeInformationFile (fh, &io, &ffci, sizeof ffci,
+ FileFsControlInformation);
+ if (!NT_SUCCESS (status))
+ break;
+ __try
+ {
+ struct dqblk *dq = (struct dqblk *) addr;
+
+ if (!(dq->dqb_valid & QIF_BLIMITS))
+ break;
+ ffci.DefaultQuotaLimit.QuadPart = dq->dqb_bhardlimit;
+ if (ffci.DefaultQuotaLimit.QuadPart != -1)
+ ffci.DefaultQuotaLimit.QuadPart *= BLOCK_SIZE;
+ ffci.DefaultQuotaThreshold.QuadPart = dq->dqb_bsoftlimit;
+ if (ffci.DefaultQuotaThreshold.QuadPart != -1)
+ ffci.DefaultQuotaThreshold.QuadPart *= BLOCK_SIZE;
+ }
+ __except (EFAULT)
+ {
+ ret = -1;
+ break;
+ }
+ __endtry
+ status = NtSetVolumeInformationFile (fh, &io, &ffci, sizeof ffci,
+ FileFsControlInformation);
+ }
+ else
+ {
+ PFILE_GET_QUOTA_INFORMATION pgqi = (PFILE_GET_QUOTA_INFORMATION)
+ alloca (PGQI_SIZE);
+ PFILE_QUOTA_INFORMATION pfqi = (PFILE_QUOTA_INFORMATION)
+ alloca (PFQI_SIZE);
+
+ pgqi->NextEntryOffset = 0;
+ pgqi->SidLength = RtlLengthSid (sid);
+ RtlCopySid (RtlLengthSid (sid), &pgqi->Sid, sid);
+ status = NtQueryQuotaInformationFile (fh, &io, pfqi, PFQI_SIZE,
+ TRUE, pgqi, PGQI_SIZE,
+ NULL, TRUE);
+ if (!NT_SUCCESS (status))
+ break;
+ __try
+ {
+ struct dqblk *dq = (struct dqblk *) addr;
+
+ if (!(dq->dqb_valid & QIF_BLIMITS))
+ break;
+ pfqi->QuotaLimit.QuadPart = dq->dqb_bhardlimit;
+ if (pfqi->QuotaLimit.QuadPart != -1)
+ pfqi->QuotaLimit.QuadPart *= BLOCK_SIZE;
+ pfqi->QuotaThreshold.QuadPart = dq->dqb_bsoftlimit;
+ if (pfqi->QuotaThreshold.QuadPart != -1)
+ pfqi->QuotaThreshold.QuadPart *= BLOCK_SIZE;
+ }
+ __except (EFAULT)
+ {
+ ret = -1;
+ break;
+ }
+ __endtry
+ status = NtSetQuotaInformationFile (fh, &io, pfqi, PFQI_SIZE);
+ }
+ break;
+ }
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ ret = -1;
+ }
+ return ret;
+}