Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows - psutil does not detect mounted folders without drive letters as disks #775

Closed
MattGirolami opened this issue Feb 23, 2016 · 11 comments

Comments

@MattGirolami
Copy link

Windows supports assigning NTFS disks a mounted folder/mount point value instead of (or in addition to) a drive letter. Psutil does not recognize drives that only have a mount point and not a drive letter.

In the example below, I've attached and formatted a hard drive, but instead of assigning it it's own drive letter, I've assigned it a mount point path of C:\mountedfolder\ . I can iterate the drive in powershell/wmi:

C:\>  Get-WmiObject -namespace "root/cimv2" -query "SELECT Name, Capacity, FreeSpace, deviceid FROM Win32_Volume WHERE DriveType = 3" | select deviceid,name,capacity | format-list


deviceid : \\?\Volume{343e9a8f-c1de-11e4-b98f-806e6f6e6963}\
name     : \\?\Volume{343e9a8f-c1de-11e4-b98f-806e6f6e6963}\
capacity : 523235328

deviceid : \\?\Volume{07ec83a6-0000-0000-0000-010000000000}\
name     : C:\mountedfolder\
capacity : 1070592000

deviceid : \\?\Volume{58dafacc-c28b-11e4-95bb-3863bbba0e0f}\
name     : C:\
capacity : 253377900544

deviceid : \\?\Volume{25083962-0000-0000-0000-c01d3b000000}\
name     : D:\
capacity : 2148532224`

If I attempt to iterate the disks in psutil, I do not see my disk at C:\mountedfolder\

C:\> py
Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:54:25) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import psutil
>>> psutil.disk_partitions()
[sdiskpart(device='C:\\', mountpoint='C:\\', fstype='NTFS', opts='rw,fixed'), 
 sdiskpart(device='D:\\', mountpoint='D:\\', fstype='FAT32', opts='rw,fixed')]
>>>

If I assign a drive letter ( like E:) to the same disk at c:\mountedfolder\ I can list it in powershell

C:\>  Get-WmiObject -namespace "root/cimv2" -query "SELECT Name, Capacity, FreeSpace, deviceid FROM Win32_Volume WHERE DriveType = 3" | select deviceid,name,capacity | format-list


deviceid : \\?\Volume{343e9a8f-c1de-11e4-b98f-806e6f6e6963}\
name     : \\?\Volume{343e9a8f-c1de-11e4-b98f-806e6f6e6963}\
capacity : 523235328

deviceid : \\?\Volume{07ec83a6-0000-0000-0000-010000000000}\
name     : E:\
capacity : 1070592000

deviceid : \\?\Volume{58dafacc-c28b-11e4-95bb-3863bbba0e0f}\
name     : C:\
capacity : 253377900544

deviceid : \\?\Volume{25083962-0000-0000-0000-c01d3b000000}\
name     : D:\
capacity : 2148532224

Note the deviceid of E:\ matches the deviceid of C:\mountedfolder\ from the previous powershell block.

Now that the same disk is assigned E:, I can iterate it in psutil

C:\> py
Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:54:25) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import psutil
>>> psutil.disk_partitions()
[sdiskpart(device='C:\\', mountpoint='C:\\', fstype='NTFS', opts='rw,fixed'), 
 sdiskpart(device='D:\\', mountpoint='D:\\', fstype='FAT32', opts='rw,fixed'), 
 sdiskpart(device='E:\\', mountpoint='E:\\', fstype='NTFS', opts='rw,fixed')]
>>> 
@giampaolo
Copy link
Owner

I think the issue may be here:

(type == DRIVE_NO_ROOT_DIR) ||
(skipping drives with no root dir).
If you can compile psutil you can try to remove that (type == DRIVE_NO_ROOT_DIR) || line and see if it makes any difference.
If you can't compile psutil, I should try myself: how do you mount a folder such as C:\mountedfolder?

@MattGirolami
Copy link
Author

Having some issues getting it to compile myself, never hacked on python so trying to get all of the prereqs figured out 😄 .

To try it yourself on Windows, do Start -> Run -> mmc

Under File, select add/remove snapin, then add the Disk Management Snapin and connect to your local computer when prompted.

Right click on Disk Management in the left hand pane and select 'Create VHD' . This will allow you to create a virtual hard drive. Set a size and a file location, you will get a .vhd file. You could also attach a new hard drive, usb drive, etc. instead.

In the lower center pane you should have a new disk that is offline/not initialized. Right click on the disk and select initialize. Then, right click on box to the right that says X MB unallocated. Select new simple volume. When prompted to assign a drive letter, select the radio button for 'Mount in the following empty NTFS folder' and select any empty folder on a different drive. When prompted, format the volume as NTFS.

You can then browse to that file path in Windows explorer. It will have a hard drive icon in Windows explorer rather than the standard folder icon.

In the upper center pane of Disk Management you can right click on any volume to assign/unassign/change mounted folders and drive letters at any time.

@giampaolo
Copy link
Owner

I forgot about all argument. Can you try psutil.disk_partitions(all=True)? That will skip the DRIVE_NO_ROOT check.

@jomann09
Copy link
Contributor

jomann09 commented Jun 4, 2016

I can confirm that even with all=True it still does not show up. A good way to do it is mount a partition as a drive letter, say Z: and in the computer management window, under disk management, right click on the Z: drive > Change Drive Letter and Paths, then click on "Add..." which will bring up a menu to select a folder to mount the partition to. I did it with some extra space on one of my spare hard drives since it was the most reliable test.

@masci
Copy link

masci commented Jun 13, 2016

Any update on this?

@giampaolo
Copy link
Owner

@JHomann can you try removing this line and see what happens?

(type == DRIVE_NO_ROOT_DIR) ||

@giampaolo
Copy link
Owner

Actually nevermind, you already stated that all=True does not make any difference.

@jomann09
Copy link
Contributor

jomann09 commented Dec 8, 2017

So I know this isn't done "properly" (sorry I don't really program in C) because I don't know how we would want to do the loop, but essentially I have a way to show mount points - and I restricted it to only show if all=True and to only check if mount points can exist.

Let me know what you think, and whether or not we can do something to refactor this. I did compile it and test that it does output mount points properly.

jomann09@988f7d4

Also side note, it's not checking for rw/etc specifically on these mount points. Just using opts that were already set for the time being.

Test output:

C:\Users\jomann\Documents\psutil_jake>python
Python 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:19:30) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import psutil
>>> psutil.disk_partitions()
[sdiskpart(device='C:\\', mountpoint='C:\\', fstype='NTFS', opts='rw,fixed'), 
 sdiskpart(device='D:\\', mountpoint='D:\\', fstype='NTFS', opts='rw,fixed'), 
 sdiskpart(device='E:\\', mountpoint='E:\\', fstype='NTFS', opts='rw,fixed'), 
 sdiskpart(device='G:\\', mountpoint='G:\\', fstype='', opts='cdrom')]
>>> psutil.disk_partitions(all=True)
[sdiskpart(device='C:\\', mountpoint='C:\\xampp\\test2mount\\', fstype='NTFS', opts='rw'), 
 sdiskpart(device='C:\\', mountpoint='C:\\test\\', fstype='NTFS', opts='rw'), 
 sdiskpart(device='C:\\', mountpoint='C:\\testmount\\', fstype='NTFS', opts='rw'), 
 sdiskpart(device='C:\\', mountpoint='C:\\', fstype='NTFS', opts='rw,fixed'), 
 sdiskpart(device='D:\\', mountpoint='D:\\', fstype='NTFS', opts='rw,fixed'), 
 sdiskpart(device='E:\\', mountpoint='E:\\', fstype='NTFS', opts='rw,fixed'), 
 sdiskpart(device='G:\\', mountpoint='G:\\', fstype='', opts='cdrom'), 
 sdiskpart(device='I:\\', mountpoint='I:\\', fstype='NTFS', opts='rw,remote'), 
 sdiskpart(device='K:\\', mountpoint='K:\\', fstype='NTFS', opts='rw,remote'), 
 sdiskpart(device='S:\\', mountpoint='S:\\', fstype='NTFS', opts='rw,remote'), 
 sdiskpart(device='T:\\', mountpoint='T:\\', fstype='NTFS', opts='rw,remote'), 
 sdiskpart(device='Z:\\', mountpoint='Z:\\', fstype='NTFS', opts='rw,remote')]

@giampaolo
Copy link
Owner

Nice! This is certainly desirable.
About your patch, I would use a utility function to reuse this part:

+                        py_tuple = Py_BuildValue(
 +                            "(ssss)",
 +                            drive_letter,
 +                            mp_path,
 +                            fs_type,  // either FAT, FAT32, NTFS, HPFS, CDFS, UDF or NWFS
 +                            opts);
 +                        if (!py_tuple)
 +                            goto error;
 +                        if (PyList_Append(py_retlist, py_tuple))
 +                            goto error;
 +                        Py_DECREF(py_tuple);

...which is repeated 3 times (2 by "you", 1 by "me" later).
Also, I think it makes sense to show these mountpoints also if all=False. That would be in line with the Linux implementation:

>>> pp(psutil.disk_partitions())
[...
 sdiskpart(device='/dev/nvme0n1p4', mountpoint='/var/lib/docker/plugins', fstype='ext4', opts='rw,relatime,errors=remount-ro,data=ordered'),
 sdiskpart(device='/dev/nvme0n1p4', mountpoint='/var/lib/docker/aufs', fstype='ext4', opts='rw,relatime,errors=remount-ro,data=ordered')]
>>> 

A PR for this would be great.

@jomann09
Copy link
Contributor

jomann09 commented Dec 9, 2017

Awesome thanks for the info, I will re-work it a little bit with that in mind and will make a PR soon!

Thanks for the quick response.

giampaolo pushed a commit that referenced this issue Dec 12, 2017
* POC for adding mountpoints to disk_partitions() with all=True

* Refactor check for mount points
- Less code duplication
- Show even with all=False like in Linux

* Goto error and close mp handler
@giampaolo
Copy link
Owner

Fixed in #1192.

nlevitt added a commit to nlevitt/psutil that referenced this issue Apr 9, 2019
* 'pslisten' of github.com:nlevitt/psutil: (922 commits)
  Update INSTALL.rst
  Pass python_requires argument to setuptools (giampaolo#1208)
  giampaolo#1152: fix doc to mention CLI command necessary to enable disk_io_counters() on win
  pre release
  pre release
  pre release
  pre-release
  fix giampaolo#1201: document that timeout kwarg is expressed in seconds
  Add mount points to disk_partitions() in Windows (giampaolo#775) (giampaolo#1192)
  add test for cpu_affinity
  what a stupid bug! (giampaolo#1190)
  update doc
  pre release
  pre-release; also get rid of PSUTIL_DEBUG doc instructions (it's kinda useless for the user after all)
  Use FutureWarning instead of DeprecationWarning (giampaolo#1188)
  fix test
  refactor environ() test
  Fix OSX pid 0 bug (giampaolo#1187)
  change assert in test
  refactor Process.__repr__
  Faster Process.children(recursive=True) (giampaolo#1186)
  Speedup Process.children()  (giampaolo#1185)
  update doc
  update HISTORY
  fix giampaolo#1179 / linux / cmdline: handle processes erroneously overwriting /proc/pid/cmdline by using spaces instead of null bytes as args separator
  set x bit to test_aix.py
  fix giampaolo#1181: raise AD if task_for_pid() fails with 5 and errno == ENOENT
  fix posix failure
  Arguments for NoSuchProcess and AccessDenied for the C ext (giampaolo#1180)
  fix travis failure https://travis-ci.org/giampaolo/psutil/jobs/306424509
  be smarter in searching python exe
  do not test platf specific modules on wheelhouse
  try to fix travis failure
  fix travis failures
  try to use PYTHON_EXE instead of sys.executable
  giampaolo#1177: give credits to @wiggin15
  OSX: implement sensors_battery (giampaolo#1177)
  improve error msg for old windows systems giampaolo#811
  add debug messages
  do not mention apt-get as method of installation as it's not recommended
  syntax highlight in doc files
  syntax highlight in doc files
  fix doc indentation
  1173 debug mode (giampaolo#1176)
  code style
  update MANIFEST
  giampaolo#1174: use TimeoutExpired in wait_pid()
  sort imports by name
  Move exceptions to separate file (giampaolo#1174)
  appveyor: enable python warnings when running tests
  refactor winmake.py
  use a C global variable to figure out whether we're in testing mode
  fix unicode err
  define a setup() function which is called on import by all C modules
  move PyUnicode compt fun definition up in the file
  rename C func
  re-enable test on appveyor; remove unused C code
  refactor PSUTIL_TESTING C APIs
  inspect PSUTIL_TESTING env var from C again
  giampaolo#1152: (DeviceIOControl), skip disk on ERROR_INVALID_FUNCTION and ERROR_NOT_SUPPORTED
  giampaolo#1152 / win / disk_io_counters(): DeviceIOControl errors were ignored; che return value and retry call on ERROR_INSUFFICIENT_BUFFER
  upgrade dist cmds
  change make cmds
  disable IPv6 tests if IPv6 is not supported
  travis / OSX: run py 3.6 instead of 3.4
  fix giampaolo#1169: (Linux) users() hostname returns username instead
  update README, bump up version
  get rid of PSUTIL_TESTING env var: it must be necessarily set from cmdline, hence 'python -m psutil.tests' won't work out of the box
  try to set PSUTIL_TESTING env var from python before failing
  skip cpu_freq tests if not available (giampaolo#1170)
  update doc
  pre-release
  giampaolo#1053: drop python 3.3 support
  try to fix appveyor failure; also refactor generate_manifest.py
  giampaolo#1167 give CREDITS to @matray
  Including non-unicast packets in packet count calculation (giampaolo#1167)
  fix giampaolo#1166 (doc mistake)
  provide a 'make help' command
  ifconfig.py humanize bytes
  try to limit false positives on appveyor/windows
  reap_children() in a finally block in order to limit false positives
  unicode tests: use different name for test dir
  fix failure on osx/travis
  update Makefile
  fix test
  giampaolo#1164 give CREDITS to @wiggin15
  AIX: implement num_ctx_switches (giampaolo#1164)
  use new PYTHON_EXE
  improve logic to determine python exe location
  add DEVNOTES file; move TODO.aix into _psutil_aix.c
  Fix test_emulate_energy_full_not_avail (giampaolo#1163)
  update README
  try to limit occasional appveyor failure
  Remove trove classifiers for untested and unsupported platforms (giampaolo#1162)
  Fix giampaolo#1154: remove 'threads' method on older AIX (giampaolo#1156)
  give CREDITS to @adpag for giampaolo#1159, giampaolo#1160 and giampaolo#1161
  Fix test asserts due to leftover test subprocesses (giampaolo#1161)
  Fix network tests for newer ifconfig versions. (giampaolo#1160)
  Fix pre-commit hook for python 3.x. (giampaolo#1159)
  revert last commit
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants