Skip to content

Commit 7f6f35f

Browse files
authored
Merge pull request #2444 from effigies/fix/filesystem_table
RF: Update and factor mount table parsing
2 parents 166e06c + e8b0341 commit 7f6f35f

File tree

2 files changed

+161
-21
lines changed

2 files changed

+161
-21
lines changed

nipype/utils/filemanip.py

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -275,34 +275,49 @@ def hash_timestamp(afile):
275275
return md5hex
276276

277277

278-
def _generate_cifs_table():
279-
"""Construct a reverse-length-ordered list of mount points that
280-
fall under a CIFS mount.
281-
282-
This precomputation allows efficient checking for whether a given path
283-
would be on a CIFS filesystem.
278+
def _parse_mount_table(exit_code, output):
279+
"""Parses the output of ``mount`` to produce (path, fs_type) pairs
284280
285-
On systems without a ``mount`` command, or with no CIFS mounts, returns an
286-
empty list.
281+
Separated from _generate_cifs_table to enable testing logic with real
282+
outputs
287283
"""
288-
exit_code, output = sp.getstatusoutput("mount")
289284
# Not POSIX
290285
if exit_code != 0:
291286
return []
292287

288+
# Linux mount example: sysfs on /sys type sysfs (rw,nosuid,nodev,noexec)
289+
# <PATH>^^^^ ^^^^^<FSTYPE>
290+
# OSX mount example: /dev/disk2 on / (hfs, local, journaled)
291+
# <PATH>^ ^^^<FSTYPE>
292+
pattern = re.compile(r'.*? on (/.*?) (?:type |\()([^\s,]+)(?:, |\)| )')
293+
293294
# (path, fstype) tuples, sorted by path length (longest first)
294-
mount_info = sorted(
295-
(line.split()[2:5:2] for line in output.splitlines()),
296-
key=lambda x: len(x[0]),
297-
reverse=True)
298-
cifs_paths = [path for path, fstype in mount_info if fstype == 'cifs']
295+
mount_info = sorted((pattern.match(l).groups()
296+
for l in output.splitlines()),
297+
key=lambda x: len(x[0]), reverse=True)
298+
cifs_paths = [path for path, fstype in mount_info
299+
if fstype.lower() == 'cifs']
299300

300301
return [
301302
mount for mount in mount_info
302303
if any(mount[0].startswith(path) for path in cifs_paths)
303304
]
304305

305306

307+
def _generate_cifs_table():
308+
"""Construct a reverse-length-ordered list of mount points that
309+
fall under a CIFS mount.
310+
311+
This precomputation allows efficient checking for whether a given path
312+
would be on a CIFS filesystem.
313+
314+
On systems without a ``mount`` command, or with no CIFS mounts, returns an
315+
empty list.
316+
"""
317+
exit_code, output = sp.getstatusoutput("mount")
318+
return _parse_mount_table(exit_code, output)
319+
320+
306321
_cifs_table = _generate_cifs_table()
307322

308323

@@ -763,8 +778,8 @@ def emptydirs(path, noexist_ok=False):
763778
elcont = os.listdir(path)
764779
if ex.errno == errno.ENOTEMPTY and not elcont:
765780
fmlogger.warning(
766-
'An exception was raised trying to remove old %s, but the path '
767-
'seems empty. Is it an NFS mount?. Passing the exception.',
781+
'An exception was raised trying to remove old %s, but the path'
782+
' seems empty. Is it an NFS mount?. Passing the exception.',
768783
path)
769784
elif ex.errno == errno.ENOTEMPTY and elcont:
770785
fmlogger.debug('Folder %s contents (%d items).', path, len(elcont))

nipype/utils/tests/test_filemanip.py

Lines changed: 130 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@
1212
from ...testing import TempFATFS
1313
from ...utils.filemanip import (
1414
save_json, load_json, fname_presuffix, fnames_presuffix, hash_rename,
15-
check_forhash, _cifs_table, on_cifs, copyfile, copyfiles, filename_to_list,
16-
list_to_filename, check_depends, split_filename, get_related_files)
17-
18-
import numpy as np
15+
check_forhash, _parse_mount_table, _cifs_table, on_cifs, copyfile,
16+
copyfiles, filename_to_list, list_to_filename, check_depends,
17+
split_filename, get_related_files)
1918

2019

2120
def _ignore_atime(stat):
@@ -123,7 +122,7 @@ def test_copyfiles(_temp_analyze_files, _temp_analyze_files_prime):
123122
pth, fname = os.path.split(orig_img2)
124123
new_img2 = os.path.join(pth, 'secondfile.img')
125124
new_hdr2 = os.path.join(pth, 'secondfile.hdr')
126-
newfiles = copyfiles([orig_img1, orig_img2], [new_img1, new_img2])
125+
copyfiles([orig_img1, orig_img2], [new_img1, new_img2])
127126
assert os.path.exists(new_img1)
128127
assert os.path.exists(new_hdr1)
129128
assert os.path.exists(new_img2)
@@ -335,6 +334,132 @@ def test_related_files(file, length, expected_files):
335334
assert ef in related_files
336335

337336

337+
MOUNT_OUTPUTS = (
338+
# Linux, no CIFS
339+
(r'''sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
340+
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
341+
udev on /dev type devtmpfs (rw,nosuid,relatime,size=8121732k,nr_inodes=2030433,mode=755)
342+
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
343+
tmpfs on /run type tmpfs (rw,nosuid,noexec,relatime,size=1628440k,mode=755)
344+
/dev/nvme0n1p2 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
345+
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
346+
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
347+
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
348+
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
349+
pstore on /sys/fs/pstore type pstore (rw,nosuid,nodev,noexec,relatime)
350+
efivarfs on /sys/firmware/efi/efivars type efivarfs (rw,nosuid,nodev,noexec,relatime)
351+
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
352+
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
353+
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
354+
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
355+
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=26,pgrp=1,timeout=0,minproto=5,maxproto=5,direct)
356+
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime)
357+
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
358+
mqueue on /dev/mqueue type mqueue (rw,relatime)
359+
fusectl on /sys/fs/fuse/connections type fusectl (rw,relatime)
360+
/dev/nvme0n1p1 on /boot/efi type vfat (rw,relatime,fmask=0077,dmask=0077,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro)
361+
/dev/nvme0n1p2 on /var/lib/docker/aufs type ext4 (rw,relatime,errors=remount-ro,data=ordered)
362+
gvfsd-fuse on /run/user/1002/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,relatime,user_id=1002,group_id=1002)
363+
''', 0, []),
364+
# OS X, no CIFS
365+
(r'''/dev/disk2 on / (hfs, local, journaled)
366+
devfs on /dev (devfs, local, nobrowse)
367+
map -hosts on /net (autofs, nosuid, automounted, nobrowse)
368+
map auto_home on /home (autofs, automounted, nobrowse)
369+
map -fstab on /Network/Servers (autofs, automounted, nobrowse)
370+
/dev/disk3s2 on /Volumes/MyBookData (hfs, local, nodev, nosuid, journaled)
371+
afni:/elrond0 on /Volumes/afni (nfs)
372+
afni:/var/www/INCOMING on /Volumes/INCOMING (nfs)
373+
afni:/fraid on /Volumes/afni (nfs, asynchronous)
374+
boromir:/raid.bot on /Volumes/raid.bot (nfs)
375+
elros:/volume2/AFNI_SHARE on /Volumes/AFNI_SHARE (nfs)
376+
map -static on /Volumes/safni (autofs, automounted, nobrowse)
377+
map -static on /Volumes/raid.top (autofs, automounted, nobrowse)
378+
/dev/disk1s3 on /Volumes/Boot OS X (hfs, local, journaled, nobrowse)
379+
''', 0, []),
380+
# Non-zero exit code
381+
('', 1, []),
382+
# Variant of Linux example with CIFS added manually
383+
(r'''sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
384+
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
385+
udev on /dev type devtmpfs (rw,nosuid,relatime,size=8121732k,nr_inodes=2030433,mode=755)
386+
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
387+
tmpfs on /run type tmpfs (rw,nosuid,noexec,relatime,size=1628440k,mode=755)
388+
/dev/nvme0n1p2 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
389+
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
390+
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
391+
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
392+
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
393+
pstore on /sys/fs/pstore type pstore (rw,nosuid,nodev,noexec,relatime)
394+
efivarfs on /sys/firmware/efi/efivars type efivarfs (rw,nosuid,nodev,noexec,relatime)
395+
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
396+
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
397+
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
398+
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
399+
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=26,pgrp=1,timeout=0,minproto=5,maxproto=5,direct)
400+
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime)
401+
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
402+
mqueue on /dev/mqueue type mqueue (rw,relatime)
403+
fusectl on /sys/fs/fuse/connections type fusectl (rw,relatime)
404+
/dev/nvme0n1p1 on /boot/efi type vfat (rw,relatime,fmask=0077,dmask=0077,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro)
405+
/dev/nvme0n1p2 on /var/lib/docker/aufs type ext4 (rw,relatime,errors=remount-ro,data=ordered)
406+
gvfsd-fuse on /run/user/1002/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,relatime,user_id=1002,group_id=1002)
407+
''', 0, []),
408+
# Variant of OS X example with CIFS added manually
409+
(r'''/dev/disk2 on / (hfs, local, journaled)
410+
devfs on /dev (devfs, local, nobrowse)
411+
afni:/elrond0 on /Volumes/afni (cifs)
412+
afni:/var/www/INCOMING on /Volumes/INCOMING (nfs)
413+
afni:/fraid on /Volumes/afni/fraid (nfs, asynchronous)
414+
boromir:/raid.bot on /Volumes/raid.bot (nfs)
415+
elros:/volume2/AFNI_SHARE on /Volumes/AFNI_SHARE (nfs)
416+
''', 0, [('/Volumes/afni/fraid', 'nfs'), ('/Volumes/afni', 'cifs')]),
417+
# From Windows: docker run --rm -it -v C:\:/data busybox mount
418+
(r'''overlay on / type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/26UTYITLF24YE7KEGTMHUNHPPG:/var/lib/docker/overlay2/l/SWGNP3T2EEB4CNBJFN3SDZLXHP,upperdir=/var/lib/docker/overlay2/a4c54ab1aa031bb5a14a424abd655510521e183ee4fa4158672e8376c89df394/diff,workdir=/var/lib/docker/overlay2/a4c54ab1aa031bb5a14a424abd655510521e183ee4fa4158672e8376c89df394/work)
419+
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
420+
tmpfs on /dev type tmpfs (rw,nosuid,size=65536k,mode=755)
421+
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666)
422+
sysfs on /sys type sysfs (ro,nosuid,nodev,noexec,relatime)
423+
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,relatime,mode=755)
424+
cpuset on /sys/fs/cgroup/cpuset type cgroup (ro,nosuid,nodev,noexec,relatime,cpuset)
425+
cpu on /sys/fs/cgroup/cpu type cgroup (ro,nosuid,nodev,noexec,relatime,cpu)
426+
cpuacct on /sys/fs/cgroup/cpuacct type cgroup (ro,nosuid,nodev,noexec,relatime,cpuacct)
427+
blkio on /sys/fs/cgroup/blkio type cgroup (ro,nosuid,nodev,noexec,relatime,blkio)
428+
memory on /sys/fs/cgroup/memory type cgroup (ro,nosuid,nodev,noexec,relatime,memory)
429+
devices on /sys/fs/cgroup/devices type cgroup (ro,nosuid,nodev,noexec,relatime,devices)
430+
freezer on /sys/fs/cgroup/freezer type cgroup (ro,nosuid,nodev,noexec,relatime,freezer)
431+
net_cls on /sys/fs/cgroup/net_cls type cgroup (ro,nosuid,nodev,noexec,relatime,net_cls)
432+
perf_event on /sys/fs/cgroup/perf_event type cgroup (ro,nosuid,nodev,noexec,relatime,perf_event)
433+
net_prio on /sys/fs/cgroup/net_prio type cgroup (ro,nosuid,nodev,noexec,relatime,net_prio)
434+
hugetlb on /sys/fs/cgroup/hugetlb type cgroup (ro,nosuid,nodev,noexec,relatime,hugetlb)
435+
pids on /sys/fs/cgroup/pids type cgroup (ro,nosuid,nodev,noexec,relatime,pids)
436+
cgroup on /sys/fs/cgroup/systemd type cgroup (ro,nosuid,nodev,noexec,relatime,name=systemd)
437+
mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime)
438+
//10.0.75.1/C on /data type cifs (rw,relatime,vers=3.02,sec=ntlmsspi,cache=strict,username=filo,domain=MSI,uid=0,noforceuid,gid=0,noforcegid,addr=10.0.75.1,file_mode=0755,dir_mode=0755,iocharset=utf8,nounix,serverino,mapposix,nobrl,mfsymlinks,noperm,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1)
439+
/dev/sda1 on /etc/resolv.conf type ext4 (rw,relatime,data=ordered)
440+
/dev/sda1 on /etc/hostname type ext4 (rw,relatime,data=ordered)
441+
/dev/sda1 on /etc/hosts type ext4 (rw,relatime,data=ordered)
442+
shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=65536k)
443+
devpts on /dev/console type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666)
444+
proc on /proc/bus type proc (ro,relatime)
445+
proc on /proc/fs type proc (ro,relatime)
446+
proc on /proc/irq type proc (ro,relatime)
447+
proc on /proc/sys type proc (ro,relatime)
448+
proc on /proc/sysrq-trigger type proc (ro,relatime)
449+
tmpfs on /proc/kcore type tmpfs (rw,nosuid,size=65536k,mode=755)
450+
tmpfs on /proc/timer_list type tmpfs (rw,nosuid,size=65536k,mode=755)
451+
tmpfs on /proc/sched_debug type tmpfs (rw,nosuid,size=65536k,mode=755)
452+
tmpfs on /proc/scsi type tmpfs (ro,relatime)
453+
tmpfs on /sys/firmware type tmpfs (ro,relatime)
454+
''', 0, [('/data', 'cifs')])
455+
)
456+
457+
458+
@pytest.mark.parametrize("output, exit_code, expected", MOUNT_OUTPUTS)
459+
def test_parse_mount_table(output, exit_code, expected):
460+
assert _parse_mount_table(exit_code, output) == expected
461+
462+
338463
def test_cifs_check():
339464
assert isinstance(_cifs_table, list)
340465
assert isinstance(on_cifs('/'), bool)

0 commit comments

Comments
 (0)