* fhandler_proc.cc (proc_tab_cmp): Fix typo in comment.
(fhandler_proc::fill_filebuf): Handle return value of 0 from format function as error. (format_proc_stat): Set errno when returning 0 size. (format_proc_partitions): Rewrite method to fetch partition info.
This commit is contained in:
parent
d6d9c269e4
commit
483e9d0022
|
@ -1,3 +1,11 @@
|
|||
2011-01-17 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* fhandler_proc.cc (proc_tab_cmp): Fix typo in comment.
|
||||
(fhandler_proc::fill_filebuf): Handle return value of 0 from format
|
||||
function as error.
|
||||
(format_proc_stat): Set errno when returning 0 size.
|
||||
(format_proc_partitions): Rewrite method to fetch partition info.
|
||||
|
||||
2011-01-13 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* fhandler_disk_file.cc (fhandler_base::fstat_helper): Always set
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* fhandler_proc.cc: fhandler for /proc virtual filesystem
|
||||
|
||||
Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 Red Hat, Inc.
|
||||
Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011 Red Hat, Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
|
@ -24,9 +24,9 @@ details. */
|
|||
#include <sys/utsname.h>
|
||||
#include <sys/param.h>
|
||||
#include "ntdll.h"
|
||||
#include <ctype.h>
|
||||
#include <winioctl.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include "cpuid.h"
|
||||
#include "mount.h"
|
||||
|
||||
|
@ -85,7 +85,7 @@ proc_tab_cmp (const void *key, const void *memb)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Helper function to perform a binary search of the incoming pathname
|
||||
/* Helper function to perform a binary search of the incoming pathname
|
||||
against the alpha-sorted virtual file table. */
|
||||
virt_tab_t *
|
||||
virt_tab_search (const char *path, bool prefix, const virt_tab_t *table,
|
||||
|
@ -351,7 +351,8 @@ fhandler_proc::fill_filebuf ()
|
|||
if (fileid < PROC_LINK_COUNT && proc_tab[fileid].format_func)
|
||||
{
|
||||
filesize = proc_tab[fileid].format_func (NULL, filebuf);
|
||||
return true;
|
||||
if (filesize > 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -550,7 +551,10 @@ format_proc_stat (void *, char *&destbuf)
|
|||
"status %p", ret);
|
||||
}
|
||||
if (!NT_SUCCESS (ret))
|
||||
return 0;
|
||||
{
|
||||
__seterrno_from_nt_status (ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pages_in = spi->PagesRead;
|
||||
pages_out = spi->PagefilePagesWritten + spi->MappedFilePagesWritten;
|
||||
|
@ -1085,15 +1089,15 @@ format_proc_cpuinfo (void *, char *&destbuf)
|
|||
static _off64_t
|
||||
format_proc_partitions (void *, char *&destbuf)
|
||||
{
|
||||
char devname[NAME_MAX + 1];
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
HANDLE dirhdl, devhdl;
|
||||
IO_STATUS_BLOCK io;
|
||||
NTSTATUS status;
|
||||
HANDLE dirhdl;
|
||||
tmp_pathbuf tp;
|
||||
|
||||
char *buf = tp.c_get ();
|
||||
char *bufptr = buf;
|
||||
char *ioctl_buf = tp.c_get ();
|
||||
|
||||
/* Open \Device object directory. */
|
||||
wchar_t wpath[MAX_PATH] = L"\\Device";
|
||||
|
@ -1103,102 +1107,157 @@ format_proc_partitions (void *, char *&destbuf)
|
|||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
debug_printf ("NtOpenDirectoryObject, status %p", status);
|
||||
__seterrno_from_nt_status (status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
print ("major minor #blocks name\n\n");
|
||||
/* Traverse \Device directory ... */
|
||||
PDIRECTORY_BASIC_INFORMATION dbi = (PDIRECTORY_BASIC_INFORMATION)
|
||||
alloca (640);
|
||||
BOOLEAN restart = TRUE;
|
||||
bool got_one = false;
|
||||
ULONG context = 0;
|
||||
while (NT_SUCCESS (NtQueryDirectoryObject (dirhdl, dbi, 640, TRUE, restart,
|
||||
&context, NULL)))
|
||||
{
|
||||
HANDLE devhdl;
|
||||
PARTITION_INFORMATION_EX *pix = NULL;
|
||||
PARTITION_INFORMATION *pi = NULL;
|
||||
DWORD bytes_read;
|
||||
DWORD part_cnt;
|
||||
unsigned long long size;
|
||||
device dev;
|
||||
|
||||
restart = FALSE;
|
||||
sys_wcstombs (devname, NAME_MAX + 1, dbi->ObjectName.Buffer,
|
||||
dbi->ObjectName.Length / 2);
|
||||
/* ... and check for a "Harddisk[0-9]*" entry. */
|
||||
if (!strncasematch (devname, "Harddisk", 8)
|
||||
|| dbi->ObjectName.Length < 18
|
||||
|| !isdigit (devname[8]))
|
||||
if (dbi->ObjectName.Length < 18
|
||||
|| wcsncasecmp (dbi->ObjectName.Buffer, L"Harddisk", 8) != 0
|
||||
|| !iswdigit (dbi->ObjectName.Buffer[8]))
|
||||
continue;
|
||||
/* Construct path name for partitions, starting with 0, which is the
|
||||
whole disk, and try to open.
|
||||
Note that the correct way to do this would be to open the HarddiskX
|
||||
directory and enumerate the Partition entries. However, while the
|
||||
partition entries itself are accessible for query by everyone, the
|
||||
HarddiskX parent directory is only queryable by SYSTEM and Admins.
|
||||
This way we circumvent this nonsensical restriction. Let's assume
|
||||
we never have more than 99 partitions per disk for now... */
|
||||
for (int part_num = 0; part_num < 99; ++part_num)
|
||||
/* Got it. Now construct the path to the entire disk, which is
|
||||
"\\Device\\HarddiskX\\Partition0", and open the disk with
|
||||
minimum permssions. */
|
||||
unsigned long drive_num = wcstoul (dbi->ObjectName.Buffer + 8, NULL, 10);
|
||||
wcscpy (wpath, dbi->ObjectName.Buffer);
|
||||
PWCHAR wpart = wpath + dbi->ObjectName.Length / sizeof (WCHAR);
|
||||
__small_swprintf (wpart, L"\\Partition0");
|
||||
upath.Length = dbi->ObjectName.Length
|
||||
+ wcslen (wpart) * sizeof (WCHAR);
|
||||
upath.MaximumLength = upath.Length + sizeof (WCHAR);
|
||||
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
|
||||
dirhdl, NULL);
|
||||
/* Up to W2K the handle needs read access to fetch the partition info. */
|
||||
status = NtOpenFile (&devhdl, wincap.has_disk_ex_ioctls ()
|
||||
? READ_CONTROL
|
||||
: READ_CONTROL | FILE_READ_DATA,
|
||||
&attr, &io, FILE_SHARE_VALID_FLAGS, 0);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
wcscpy (wpath, dbi->ObjectName.Buffer);
|
||||
__small_swprintf (wpath + dbi->ObjectName.Length / 2,
|
||||
L"\\Partition%d", part_num);
|
||||
upath.Length = 22 + dbi->ObjectName.Length;
|
||||
upath.MaximumLength = upath.Length + 2;
|
||||
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
|
||||
dirhdl, NULL);
|
||||
status = NtOpenFile (&devhdl, READ_CONTROL, &attr, &io,
|
||||
FILE_SHARE_VALID_FLAGS, 0);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
if (status == STATUS_OBJECT_NAME_NOT_FOUND
|
||||
|| status == STATUS_OBJECT_PATH_NOT_FOUND)
|
||||
break;
|
||||
debug_printf ("NtOpenFile(%s), status %p", devname, status);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Use a buffer since some ioctl buffers aren't fixed size. */
|
||||
char buf[256];
|
||||
PARTITION_INFORMATION *pi = NULL;
|
||||
PARTITION_INFORMATION_EX *pix = NULL;
|
||||
DISK_GEOMETRY *dg = NULL;
|
||||
DWORD bytes;
|
||||
unsigned long drive_number = strtoul (devname + 8, NULL, 10);
|
||||
unsigned long long size;
|
||||
|
||||
if (wincap.has_disk_ex_ioctls ()
|
||||
&& DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO_EX,
|
||||
NULL, 0, buf, 256, &bytes, NULL))
|
||||
{
|
||||
pix = (PARTITION_INFORMATION_EX *) buf;
|
||||
size = pix->PartitionLength.QuadPart;
|
||||
}
|
||||
else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO,
|
||||
NULL, 0, buf, 256, &bytes, NULL))
|
||||
{
|
||||
pi = (PARTITION_INFORMATION *) buf;
|
||||
size = pi->PartitionLength.QuadPart;
|
||||
}
|
||||
else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
||||
NULL, 0, buf, 256, &bytes, NULL))
|
||||
{
|
||||
dg = (DISK_GEOMETRY *) buf;
|
||||
size = (unsigned long long) dg->Cylinders.QuadPart
|
||||
* dg->TracksPerCylinder
|
||||
* dg->SectorsPerTrack
|
||||
* dg->BytesPerSector;
|
||||
}
|
||||
else
|
||||
size = 0;
|
||||
if (!pi && !pix && !dg)
|
||||
debug_printf ("DeviceIoControl %E");
|
||||
else
|
||||
{
|
||||
device dev;
|
||||
dev.parsedisk (drive_number, part_num);
|
||||
bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s\n",
|
||||
dev.major, dev.minor,
|
||||
size >> 10, dev.name + 5);
|
||||
}
|
||||
NtClose (devhdl);
|
||||
debug_printf ("NtOpenFile(%S), status %p", &upath, status);
|
||||
__seterrno_from_nt_status (status);
|
||||
continue;
|
||||
}
|
||||
if (!got_one)
|
||||
{
|
||||
print ("major minor #blocks name\n\n");
|
||||
got_one = true;
|
||||
}
|
||||
/* Fetch partition info for the entire disk to get its size. */
|
||||
if (wincap.has_disk_ex_ioctls ()
|
||||
&& DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0,
|
||||
ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
|
||||
{
|
||||
pix = (PARTITION_INFORMATION_EX *) ioctl_buf;
|
||||
size = pix->PartitionLength.QuadPart;
|
||||
}
|
||||
else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0,
|
||||
ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
|
||||
{
|
||||
pi = (PARTITION_INFORMATION *) ioctl_buf;
|
||||
size = pi->PartitionLength.QuadPart;
|
||||
}
|
||||
else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
|
||||
ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
|
||||
{
|
||||
/* NT4 doesn't support to call IOCTL_DISK_GET_PARTITION_INFO for the
|
||||
entire drive. */
|
||||
DISK_GEOMETRY *dg = (DISK_GEOMETRY *) ioctl_buf;
|
||||
size = (unsigned long long) dg->Cylinders.QuadPart
|
||||
* dg->TracksPerCylinder
|
||||
* dg->SectorsPerTrack
|
||||
* dg->BytesPerSector;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf ("DeviceIoControl (%S, "
|
||||
"IOCTL_DISK_GET_PARTITION_INFO{_EX}) %E", &upath);
|
||||
size = 0;
|
||||
}
|
||||
dev.parsedisk (drive_num, 0);
|
||||
bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s\n",
|
||||
dev.major, dev.minor,
|
||||
size >> 10, dev.name + 5);
|
||||
/* Fetch drive layout info to get size of all partitions on the disk. */
|
||||
if (wincap.has_disk_ex_ioctls ()
|
||||
&& DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
|
||||
NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
|
||||
{
|
||||
PDRIVE_LAYOUT_INFORMATION_EX pdlix = (PDRIVE_LAYOUT_INFORMATION_EX)
|
||||
ioctl_buf;
|
||||
part_cnt = pdlix->PartitionCount;
|
||||
pix = pdlix->PartitionEntry;
|
||||
}
|
||||
else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT,
|
||||
NULL, 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
|
||||
{
|
||||
PDRIVE_LAYOUT_INFORMATION pdli = (PDRIVE_LAYOUT_INFORMATION) ioctl_buf;
|
||||
part_cnt = pdli->PartitionCount;
|
||||
pi = pdli->PartitionEntry;
|
||||
}
|
||||
else
|
||||
debug_printf ("DeviceIoControl(%S, "
|
||||
"IOCTL_DISK_GET_DRIVE_LAYOUT{_EX}): %E", &upath);
|
||||
/* Loop over partitions. */
|
||||
if (pix || pi)
|
||||
for (DWORD i = 0; i < part_cnt; ++i)
|
||||
{
|
||||
DWORD part_num;
|
||||
|
||||
if (pix)
|
||||
{
|
||||
size = pix->PartitionLength.QuadPart;
|
||||
part_num = pix->PartitionNumber;
|
||||
++pix;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = pi->PartitionLength.QuadPart;
|
||||
/* Pre-W2K you can't rely on the partition number info for
|
||||
unused partitions. */
|
||||
if (pi->PartitionType == PARTITION_ENTRY_UNUSED
|
||||
|| pi->PartitionType == PARTITION_EXTENDED)
|
||||
part_num = 0;
|
||||
else
|
||||
part_num = pi->PartitionNumber;
|
||||
++pi;
|
||||
}
|
||||
/* A partition number of 0 denotes an extended partition or a
|
||||
filler entry as described in fhandler_dev_floppy::lock_partition.
|
||||
Just skip. */
|
||||
if (part_num == 0)
|
||||
continue;
|
||||
dev.parsedisk (drive_num, part_num);
|
||||
bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s\n",
|
||||
dev.major, dev.minor,
|
||||
size >> 10, dev.name + 5);
|
||||
}
|
||||
NtClose (devhdl);
|
||||
}
|
||||
NtClose (dirhdl);
|
||||
|
||||
if (!got_one)
|
||||
return 0;
|
||||
|
||||
destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
|
||||
memcpy (destbuf, buf, bufptr - buf);
|
||||
return bufptr - buf;
|
||||
|
|
Loading…
Reference in New Issue