Revamp device parsing code. Introducing support for more partitions into the shilka-generated parser has the unfortunate side-effect of raising the size of the DLL by almost 2 Megs. Therefore we split out the handling for /dev/sdXY devices into a tiny bit of hand-written code. While at it, remove some unused cruft from devices.* and generally clean up the device class to provide access methods instead of direct access to members. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
		
			
				
	
	
		
			332 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			332 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* quotactl.cc: code for manipulating disk quotas
 | |
| 
 | |
| 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;
 | |
|   PSID sid = NO_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)
 | |
| 	{
 | |
| 	  if (type == USRQUOTA)
 | |
| 	    sid = sidfromuid (id, NULL);
 | |
| 	  else
 | |
| 	    sid = sidfromgid (id, NULL);
 | |
| 	  if (sid == NO_SID)
 | |
| 	    {
 | |
| 	      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;
 | |
| }
 |