Skip to content

Commit

Permalink
disk_partitions() maxfile and maxpath (#1863)
Browse files Browse the repository at this point in the history
  • Loading branch information
giampaolo authored Oct 24, 2020
1 parent 241f8ed commit 40abe5c
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 53 deletions.
10 changes: 10 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
*Bug tracker at https://github.com/giampaolo/psutil/issues*

5.7.4 (development version)
===========================

XXXX-XX-XX

**Enhancements**

- 1875_: `disk_partitions()` exposes 2 extra fields: `maxfile` and `maxpath`,
which are the maximum file name and path name length.

5.7.3
=====

Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ Disks
.. code-block:: python
>>> psutil.disk_partitions()
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid', maxfile=255, maxpath=4096),
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw', maxfile=255, maxpath=4096)]
>>>
>>> psutil.disk_usage('/')
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
Expand Down
30 changes: 19 additions & 11 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -410,19 +410,27 @@ Disks
(e.g. pseudo, memory, duplicate, inaccessible filesystems).
Note that this may not be fully reliable on all systems (e.g. on BSD this
parameter is ignored).
Named tuple's **fstype** field is a string which varies depending on the
platform.
On Linux it can be one of the values found in /proc/filesystems (e.g.
``'ext3'`` for an ext3 hard drive o ``'iso9660'`` for the CD-ROM drive).
On Windows it is determined via `GetDriveType`_ and can be either
``"removable"``, ``"fixed"``, ``"remote"``, ``"cdrom"``, ``"unmounted"`` or
``"ramdisk"``. On macOS and BSD it is retrieved via `getfsstat`_ syscall.
See `disk_usage.py`_ script providing an example usage.
Returns a list of namedtuples with the following fields:

* **device**: the device path (e.g. ``"/dev/hda1"``). On Windows this is the
drive letter (e.g. ``"C:\\"``).
* **mountpoint**: the mount point path (e.g. ``"/"``). On Windows this is the
drive letter (e.g. ``"C:\\"``).
* **fstype**: the partition filesystem (e.g. ``"ext3"`` on UNIX or ``"NTFS"``
on Windows).
* **opts**: a comma-separated string indicating different mount options for
the drive/partition. Platform-dependent.
* **maxfile**: the maximum length a file name can have.
* **maxpath**: the maximum length a path name (directory name + base file
name) can have.

>>> import psutil
>>> psutil.disk_partitions()
[sdiskpart(device='/dev/sda3', mountpoint='/', fstype='ext4', opts='rw,errors=remount-ro'),
sdiskpart(device='/dev/sda7', mountpoint='/home', fstype='ext4', opts='rw')]
>>> import psutil
>>> psutil.disk_partitions()
[sdiskpart(device='/dev/sda3', mountpoint='/', fstype='ext4', opts='rw,errors=remount-ro', maxfile=255, maxpath=4096),
sdiskpart(device='/dev/sda7', mountpoint='/home', fstype='ext4', opts='rw', maxfile=255, maxpath=4096)]

.. versionchanged:: 5.7.4 added *maxfile* and *maxpath* fields

.. function:: disk_usage(path)

Expand Down
20 changes: 18 additions & 2 deletions psutil/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@
AF_LINK = _psplatform.AF_LINK

__author__ = "Giampaolo Rodola'"
__version__ = "5.7.3"
__version__ = "5.7.4"
version_info = tuple([int(num) for num in __version__.split('.')])

_timer = getattr(time, 'monotonic', time.time)
Expand Down Expand Up @@ -2002,7 +2002,23 @@ def disk_partitions(all=False):
If *all* parameter is False return physical devices only and ignore
all others.
"""
return _psplatform.disk_partitions(all)
def pathconf(path, name):
try:
return os.pathconf(path, name)
except (OSError, AttributeError):
pass

ret = _psplatform.disk_partitions(all)
if POSIX:
new = []
for item in ret:
nt = item._replace(
maxfile=pathconf(item.mountpoint, 'PC_NAME_MAX'),
maxpath=pathconf(item.mountpoint, 'PC_PATH_MAX'))
new.append(nt)
return new
else:
return ret


def disk_io_counters(perdisk=False, nowrap=True):
Expand Down
3 changes: 2 additions & 1 deletion psutil/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ class BatteryTime(enum.IntEnum):
'read_bytes', 'write_bytes',
'read_time', 'write_time'])
# psutil.disk_partitions()
sdiskpart = namedtuple('sdiskpart', ['device', 'mountpoint', 'fstype', 'opts'])
sdiskpart = namedtuple('sdiskpart', ['device', 'mountpoint', 'fstype', 'opts',
'maxfile', 'maxpath'])
# psutil.net_io_counters()
snetio = namedtuple('snetio', ['bytes_sent', 'bytes_recv',
'packets_sent', 'packets_recv',
Expand Down
4 changes: 3 additions & 1 deletion psutil/_psaix.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ def disk_partitions(all=False):
# filter by filesystem having a total size > 0.
if not disk_usage(mountpoint).total:
continue
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
maxfile = maxpath = None # set later
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts,
maxfile, maxpath)
retlist.append(ntuple)
return retlist

Expand Down
4 changes: 3 additions & 1 deletion psutil/_psbsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,9 @@ def disk_partitions(all=False):
partitions = cext.disk_partitions()
for partition in partitions:
device, mountpoint, fstype, opts = partition
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
maxfile = maxpath = None # set later
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts,
maxfile, maxpath)
retlist.append(ntuple)
return retlist

Expand Down
4 changes: 3 additions & 1 deletion psutil/_pslinux.py
Original file line number Diff line number Diff line change
Expand Up @@ -1171,7 +1171,9 @@ def disk_partitions(all=False):
if not all:
if device == '' or fstype not in fstypes:
continue
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
maxfile = maxpath = None # set later
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts,
maxfile, maxpath)
retlist.append(ntuple)

return retlist
Expand Down
4 changes: 3 additions & 1 deletion psutil/_psosx.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,9 @@ def disk_partitions(all=False):
if not all:
if not os.path.isabs(device) or not os.path.exists(device):
continue
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
maxfile = maxpath = None # set later
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts,
maxfile, maxpath)
retlist.append(ntuple)
return retlist

Expand Down
4 changes: 3 additions & 1 deletion psutil/_pssunos.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,9 @@ def disk_partitions(all=False):
# https://github.com/giampaolo/psutil/issues/1674
debug("skipping %r: %r" % (mountpoint, err))
continue
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
maxfile = maxpath = None # set later
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts,
maxfile, maxpath)
retlist.append(ntuple)
return retlist

Expand Down
5 changes: 0 additions & 5 deletions psutil/_psutil_bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,17 +443,12 @@ psutil_proc_environ(PyObject *self, PyObject *args) {

// On *BSD kernels there are a few kernel-only system processes without an
// environment (See e.g. "procstat -e 0 | 1 | 2 ..." on FreeBSD.)
//
// Some system process have no stats attached at all
// (they are marked with P_SYSTEM.)
//
// On FreeBSD, it's possible that the process is swapped or paged out,
// then there no access to the environ stored in the process' user area.
//
// On NetBSD, we cannot call kvm_getenvv2() for a zombie process.
//
// To make unittest suite happy, return an empty environment.
//
#if defined(PSUTIL_FREEBSD)
#if (defined(__FreeBSD_version) && __FreeBSD_version >= 700000)
if (!((p)->ki_flag & P_INMEM) || ((p)->ki_flag & P_SYSTEM)) {
Expand Down
24 changes: 12 additions & 12 deletions psutil/arch/freebsd/specific.c
Original file line number Diff line number Diff line change
Expand Up @@ -1142,19 +1142,19 @@ psutil_proc_setrlimit(PyObject *self, PyObject *args) {
name[4] = resource;

#if defined(HAVE_LONG_LONG)
new.rlim_cur = PyLong_AsLongLong(py_soft);
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
new.rlim_max = PyLong_AsLongLong(py_hard);
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
new.rlim_cur = PyLong_AsLongLong(py_soft);
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
new.rlim_max = PyLong_AsLongLong(py_hard);
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
#else
new.rlim_cur = PyLong_AsLong(py_soft);
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
new.rlim_max = PyLong_AsLong(py_hard);
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
new.rlim_cur = PyLong_AsLong(py_soft);
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
new.rlim_max = PyLong_AsLong(py_hard);
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
#endif
newp = &new;
ret = sysctl(name, 5, NULL, 0, newp, sizeof(*newp));
Expand Down
30 changes: 22 additions & 8 deletions psutil/arch/windows/disk.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
BOOL mp_flag= TRUE;
LPTSTR fs_type[MAX_PATH + 1] = { 0 };
DWORD pflags = 0;
DWORD lpMaximumComponentLength = 0; // max file name
PyObject *py_all;
PyObject *py_retlist = PyList_New(0);
PyObject *py_tuple = NULL;
Expand Down Expand Up @@ -257,8 +258,14 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
}

ret = GetVolumeInformation(
(LPCTSTR)drive_letter, NULL, _ARRAYSIZE(drive_letter),
NULL, NULL, &pflags, (LPTSTR)fs_type, _ARRAYSIZE(fs_type));
(LPCTSTR)drive_letter,
NULL,
_ARRAYSIZE(drive_letter),
NULL,
&lpMaximumComponentLength,
&pflags,
(LPTSTR)fs_type,
_ARRAYSIZE(fs_type));
if (ret == 0) {
// We might get here in case of a floppy hard drive, in
// which case the error is (21, "device not ready").
Expand All @@ -274,6 +281,8 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
strcat_s(opts, _countof(opts), "rw");
if (pflags & FILE_VOLUME_IS_COMPRESSED)
strcat_s(opts, _countof(opts), ",compressed");
if (pflags & FILE_READ_ONLY_VOLUME)
strcat_s(opts, _countof(opts), ",readonly");

// Check for mount points on this volume and add/get info
// (checks first to know if we can even have mount points)
Expand All @@ -282,17 +291,19 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
drive_letter, mp_buf, MAX_PATH);
if (mp_h != INVALID_HANDLE_VALUE) {
while (mp_flag) {

// Append full mount path with drive letter
strcpy_s(mp_path, _countof(mp_path), drive_letter);
strcat_s(mp_path, _countof(mp_path), mp_buf);

py_tuple = Py_BuildValue(
"(ssss)",
"(ssssIi)",
drive_letter,
mp_path,
fs_type, // Typically NTFS
opts);
fs_type, // typically "NTFS"
opts,
lpMaximumComponentLength, // max file length
MAX_PATH // max path length
);

if (!py_tuple ||
PyList_Append(py_retlist, py_tuple) == -1) {
Expand All @@ -317,11 +328,14 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
strcat_s(opts, _countof(opts), psutil_get_drive_type(type));

py_tuple = Py_BuildValue(
"(ssss)",
"(ssssIi)",
drive_letter,
drive_letter,
fs_type, // either FAT, FAT32, NTFS, HPFS, CDFS, UDF or NWFS
opts);
opts,
lpMaximumComponentLength, // max file length
MAX_PATH // max path length
);
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
Expand Down
2 changes: 2 additions & 0 deletions psutil/tests/test_contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ def test_disk_partitions(self):
self.assertIsInstance(disk.mountpoint, str)
self.assertIsInstance(disk.fstype, str)
self.assertIsInstance(disk.opts, str)
self.assertIsInstance(disk.maxfile, int)
self.assertIsInstance(disk.maxpath, int)

@unittest.skipIf(SKIP_SYSCONS, "requires root")
def test_net_connections(self):
Expand Down
20 changes: 14 additions & 6 deletions psutil/tests/test_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,17 +592,24 @@ def test_disk_usage_bytes(self):
psutil.disk_usage(b'.')

def test_disk_partitions(self):
def check_ntuple(nt):
self.assertIsInstance(nt.device, str)
self.assertIsInstance(nt.mountpoint, str)
self.assertIsInstance(nt.fstype, str)
self.assertIsInstance(nt.opts, str)
self.assertIsInstance(nt.maxfile, int)
self.assertIsInstance(nt.maxpath, int)
self.assertGreater(nt.maxfile, 0)
self.assertGreater(nt.maxpath, 0)

# all = False
ls = psutil.disk_partitions(all=False)
# on travis we get:
# self.assertEqual(p.cpu_affinity(), [n])
# AssertionError: Lists differ: [0, 1, 2, 3, 4, 5, 6, 7,... != [0]
self.assertTrue(ls, msg=ls)
for disk in ls:
self.assertIsInstance(disk.device, str)
self.assertIsInstance(disk.mountpoint, str)
self.assertIsInstance(disk.fstype, str)
self.assertIsInstance(disk.opts, str)
check_ntuple(disk)
if WINDOWS and 'cdrom' in disk.opts:
continue
if not POSIX:
Expand All @@ -619,6 +626,7 @@ def test_disk_partitions(self):
ls = psutil.disk_partitions(all=True)
self.assertTrue(ls, msg=ls)
for disk in psutil.disk_partitions(all=True):
check_ntuple(disk)
if not WINDOWS and disk.mountpoint:
try:
os.stat(disk.mountpoint)
Expand All @@ -632,8 +640,8 @@ def test_disk_partitions(self):
raise
else:
assert os.path.exists(disk.mountpoint), disk
self.assertIsInstance(disk.fstype, str)
self.assertIsInstance(disk.opts, str)

# ---

def find_mount_point(path):
path = os.path.abspath(path)
Expand Down
2 changes: 1 addition & 1 deletion scripts/internal/download_wheels_appveyor.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def get_file_urls(options):
file_url = job_url + '/' + item['fileName']
urls.append(file_url)
if not urls:
print_color("no artifacts found", 'ret')
print_color("no artifacts found", 'red')
sys.exit(1)
else:
for url in sorted(urls, key=lambda x: os.path.basename(x)):
Expand Down

0 comments on commit 40abe5c

Please sign in to comment.