chiark / gitweb /
16d05775a24904c147cbe531b6d4bd29a1b1631b
[cura.git] / Cura / util / removableStorage.py
1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
2 import platform
3 import string
4 import glob
5 import os
6 import stat
7 import time
8 import subprocess
9 import threading
10 try:
11         from xml.etree import cElementTree as ElementTree
12 except:
13         from xml.etree import ElementTree
14
15 from Cura.util import profile
16
17 _removableCacheUpdateThread = None
18 _removableCache = []
19
20 def _parseStupidPListXML(e):
21         if e.tag == 'plist':
22                 return _parseStupidPListXML(list(e)[0])
23         if e.tag == 'array':
24                 ret = []
25                 for c in list(e):
26                         ret.append(_parseStupidPListXML(c))
27                 return ret
28         if e.tag == 'dict':
29                 ret = {}
30                 key = None
31                 for c in list(e):
32                         if c.tag == 'key':
33                                 key = c.text
34                         elif key is not None:
35                                 ret[key] = _parseStupidPListXML(c)
36                                 key = None
37                 return ret
38         if e.tag == 'true':
39                 return True
40         if e.tag == 'false':
41                 return False
42         return e.text
43
44 def _findInTree(t, n):
45         ret = []
46         if type(t) is dict:
47                 if '_name' in t and t['_name'] == n:
48                         ret.append(t)
49                 for k, v in t.items():
50                         ret += _findInTree(v, n)
51         if type(t) is list:
52                 for v in t:
53                         ret += _findInTree(v, n)
54         return ret
55
56 def getPossibleSDcardDrives():
57         global _removableCache, _removableCacheUpdateThread
58
59         if profile.getPreference('auto_detect_sd') == 'False':
60                 return []
61
62         if _removableCacheUpdateThread is None:
63                 _removableCacheUpdateThread = threading.Thread(target=_updateCache)
64                 _removableCacheUpdateThread.daemon = True
65                 _removableCacheUpdateThread.start()
66         return _removableCache
67
68 def _updateCache():
69         global _removableCache
70
71         while True:
72                 drives = []
73                 if platform.system() == "Windows":
74                         from ctypes import windll
75                         import ctypes
76                         bitmask = windll.kernel32.GetLogicalDrives()
77                         for letter in string.uppercase:
78                                 if letter != 'A' and letter != 'B' and bitmask & 1 and windll.kernel32.GetDriveTypeA(letter + ':/') == 2:
79                                         volumeName = ''
80                                         nameBuffer = ctypes.create_unicode_buffer(1024)
81                                         if windll.kernel32.GetVolumeInformationW(ctypes.c_wchar_p(letter + ':/'), nameBuffer, ctypes.sizeof(nameBuffer), None, None, None, None, 0) == 0:
82                                                 volumeName = nameBuffer.value
83                                         if volumeName == '':
84                                                 volumeName = 'NO NAME'
85
86                                         freeBytes = ctypes.c_longlong(0)
87                                         if windll.kernel32.GetDiskFreeSpaceExA(letter + ':/', ctypes.byref(freeBytes), None, None) == 0:
88                                                 continue
89                                         if freeBytes.value < 1:
90                                                 continue
91                                         drives.append(('%s (%s:)' % (volumeName, letter), letter + ':/', volumeName))
92                                 bitmask >>= 1
93                 elif platform.system() == "Darwin":
94                         p = subprocess.Popen(['system_profiler', 'SPUSBDataType', '-xml'], stdout=subprocess.PIPE)
95                         xml = ElementTree.fromstring(p.communicate()[0])
96                         p.wait()
97
98                         xml = _parseStupidPListXML(xml)
99                         for dev in _findInTree(xml, 'Mass Storage Device'):
100                                 if 'removable_media' in dev and dev['removable_media'] == 'yes' and 'volumes' in dev and len(dev['volumes']) > 0:
101                                         for vol in dev['volumes']:
102                                                 if 'mount_point' in vol:
103                                                         volume = vol['mount_point']
104                                                         drives.append((os.path.basename(volume), volume + '/', os.path.basename(volume)))
105
106                         p = subprocess.Popen(['system_profiler', 'SPCardReaderDataType', '-xml'], stdout=subprocess.PIPE)
107                         xml = ElementTree.fromstring(p.communicate()[0])
108                         p.wait()
109
110                         xml = _parseStupidPListXML(xml)
111                         for entry in xml:
112                                 if '_items' in entry:
113                                         for item in entry['_items']:
114                                                 for dev in item['_items']:
115                                                         if 'removable_media' in dev and dev['removable_media'] == 'yes' and 'volumes' in dev and len(dev['volumes']) > 0:
116                                                                 for vol in dev['volumes']:
117                                                                         if 'mount_point' in vol:
118                                                                                 volume = vol['mount_point']
119                                                                                 drives.append((os.path.basename(volume), volume + '/', os.path.basename(volume)))
120                 else:
121                         for volume in glob.glob('/media/*'):
122                                 drives.append((os.path.basename(volume), volume + '/', os.path.basename(volume)))
123
124                 _removableCache = drives
125                 time.sleep(1)
126
127 def ejectDrive(driveName):
128         if platform.system() == "Windows":
129                 cmd = [os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'EjectMedia.exe')), driveName]
130         elif platform.system() == "Darwin":
131                 cmd = ["diskutil", "eject", driveName]
132         else:
133                 cmd = ["umount", driveName]
134
135         kwargs = {}
136         if subprocess.mswindows:
137                 su = subprocess.STARTUPINFO()
138                 su.dwFlags |= subprocess.STARTF_USESHOWWINDOW
139                 su.wShowWindow = subprocess.SW_HIDE
140                 kwargs['startupinfo'] = su
141         p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
142         output = p.communicate()
143
144         if p.wait():
145                 print output[0]
146                 print output[1]
147                 return False
148         else:
149                 return True
150
151 if __name__ == '__main__':
152         print getPossibleSDcardDrives()