Tue, 18 Mar 2025 18:14:12 +0100
Streamlined some code in the filesystem utilities module.
src/eric7/SystemUtilities/FileSystemUtilities.py | file | annotate | diff | comparison | revisions |
--- a/src/eric7/SystemUtilities/FileSystemUtilities.py Mon Mar 17 17:58:39 2025 +0100 +++ b/src/eric7/SystemUtilities/FileSystemUtilities.py Tue Mar 18 18:14:12 2025 +0100 @@ -8,7 +8,6 @@ """ import contextlib -import ctypes import fnmatch import os import pathlib @@ -533,7 +532,7 @@ return [] -def findVolume(volumeName, findAll=False): +def findVolume(volumeName, findAll=False, markerFile=None): """ Function to find the directory belonging to a given volume name. @@ -542,87 +541,81 @@ @param findAll flag indicating to get the directories for all volumes starting with the given name (defaults to False) @type bool (optional) + @param markerFile name of a file to check for its existence (defaults to None) + @type str (optional) @return directory path or list of directory paths for the given volume name @rtype str or list of str """ - volumeDirectories = [] - volumeDirectory = None - if OSUtilities.isWindowsPlatform(): # we are on a Windows platform - def getVolumeName(diskName): - """ - Local function to determine the volume of a disk or device. - - Each disk or external device connected to windows has an - attribute called "volume name". This function returns the - volume name for the given disk/device. + drives = [] + output = subprocess.run( + [ + "wmic", + "PATH", + "Win32_LogicalDisk", + "get", + "DeviceID,", + "DriveType,", + "FileSystem,", + "VolumeName", + ], + check=True, + capture_output=True, + text=True, + encoding="utf-8", + ).stdout.splitlines() - Code from http://stackoverflow.com/a/12056414 - """ - volumeNameBuffer = ctypes.create_unicode_buffer(1024) - ctypes.windll.kernel32.GetVolumeInformationW( - ctypes.c_wchar_p(diskName), - volumeNameBuffer, - ctypes.sizeof(volumeNameBuffer), - None, - None, - None, - None, - 0, - ) - return volumeNameBuffer.value + for line in output: + words = line.split() + if len(words) >= 4 and words[1] == "2" and words[2] == "FAT": + drive = words[0] + volume = " ".join(words[3:]) + if findAll: + if volume.startswith(volumeName): + drives.append(f"{drive}\\") + else: + if volume == volumeName: + return f"{drive}\\" - # - # In certain circumstances, volumes are allocated to USB - # storage devices which cause a Windows popup to raise if their - # volume contains no media. Wrapping the check in SetErrorMode - # with SEM_FAILCRITICALERRORS (1) prevents this popup. - # - oldMode = ctypes.windll.kernel32.SetErrorMode(1) - try: - for disk in "ABCDEFGHIJKLMNOPQRSTUVWXYZ": - dirpath = "{0}:\\".format(disk) - if os.path.exists(dirpath): - if findAll: - if getVolumeName(dirpath).startswith(volumeName): - volumeDirectories.append(dirpath) - else: - if getVolumeName(dirpath) == volumeName: - volumeDirectory = dirpath - break - finally: - ctypes.windll.kernel32.SetErrorMode(oldMode) + return drives else: # we are on a Linux, FreeBSD or macOS platform - for mountCommand in ["mount", "/sbin/mount", "/usr/sbin/mount"]: - with contextlib.suppress(FileNotFoundError): - mountOutput = subprocess.run( # secok - mountCommand, check=True, capture_output=True, text=True - ).stdout.splitlines() - mountedVolumes = [ - x.split(" type", 1)[0].split(" (", 1)[0].split(maxsplit=2)[-1] - for x in mountOutput - ] - if findAll: - for volume in mountedVolumes: - if os.path.basename(volume).startswith(volumeName): - volumeDirectories.append(volume) - if volumeDirectories: - break - else: - for volume in mountedVolumes: - if os.path.basename(volume) == volumeName: - volumeDirectory = volume - break - if volumeDirectory: - break + # FreeBSD needs a marker file because it does not use the volume name. + directories = [] + if OSUtilities.isMacPlatform(): + # macOS + mountPathStart = "/Volumes" + elif OSUtilities.isLinuxPlatform(): + # Linux + mountPathStart = "/media/{0}/".format(OSUtilities.getUserName()) + if not os.path.isdir(mountPathStart): + # no user mount available + return [] if findAll else None + elif OSUtilities.isFreeBsdPlatform(): + # FreeBSD + mountPathStart = "/media/" + else: + # unsupported platform + return [] if findAll else None - if findAll: - return volumeDirectories - else: - return volumeDirectory + for d in os.listdir(mountPathStart): + dPath = os.path.join(mountPathStart, d) + if findAll: + if d.startswith(volumeName) or ( + markerFile is not None + and os.path.exists(os.path.join(dPath, markerFile)) + ): + directories.append(dPath) + else: + if d == volumeName or ( + markerFile is not None + and os.path.exists(os.path.join(dPath, markerFile)) + ): + return dPath + + return directories def getUserMounts(): @@ -634,14 +627,13 @@ @return list of user mounts or drives @rtype list of str """ - mountedPaths = [] - if OSUtilities.isWindowsPlatform(): # we are on a Windows platform - for disk in "ABCDEFGHIJKLMNOPQRSTUVWXYZ": - dirpath = "{0}:\\".format(disk) - if os.path.exists(dirpath): - mountedPaths.append(dirpath) + return [ + f"{disk}:\\" + for disk in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + if os.path.exists(f"{disk}:\\") + ] else: # we are on a Linux, FreeBSD or macOS platform if OSUtilities.isMacPlatform(): @@ -650,6 +642,9 @@ elif OSUtilities.isLinuxPlatform(): # Linux mountPathStart = "/media/{0}/".format(OSUtilities.getUserName()) + if not os.path.isdir(mountPathStart): + # no user mount available + return [] elif OSUtilities.isFreeBsdPlatform(): # FreeBSD mountPathStart = "/media/" @@ -657,19 +652,7 @@ # unsupported platform return [] - for mountCommand in ["mount", "/sbin/mount", "/usr/sbin/mount"]: - with contextlib.suppress(FileNotFoundError): - mountOutput = subprocess.run( # secok - mountCommand, check=True, capture_output=True, text=True - ).stdout.splitlines() - mounts = [ - x.split(" type", 1)[0].split(" (", 1)[0].split(maxsplit=2)[-1] - for x in mountOutput - ] - mountedPaths = [x for x in mounts if x.startswith(mountPathStart)] - break - - return mountedPaths + return [os.path.join(mountPathStart, d) for d in os.listdir(mountPathStart)] def startfile(filePath):