don't use devfs names: /dev/mtdblock/6 -> /dev/mtdblock6
[enigma2.git] / lib / python / Tools / Directories.py
1 # -*- coding: utf-8 -*-
2
3 from os import path as os_path, mkdir, rmdir, system, walk, stat as os_stat, listdir, readlink, makedirs, error as os_error, symlink, access, F_OK, R_OK, W_OK
4 from stat import S_IMODE
5 from re import compile
6 from enigma import eEnv
7
8 try:
9         from os import chmod
10         have_chmod = True
11 except:
12         have_chmod = False
13
14 try:
15         from os import utime
16         have_utime = True
17 except:
18         have_utime = False
19
20 SCOPE_TRANSPONDERDATA = 0
21 SCOPE_SYSETC = 1
22 SCOPE_FONTS = 2
23 SCOPE_SKIN = 3
24 SCOPE_SKIN_IMAGE = 4
25 SCOPE_USERETC = 5
26 SCOPE_CONFIG = 6
27 SCOPE_LANGUAGE = 7
28 SCOPE_HDD = 8
29 SCOPE_PLUGINS = 9
30 SCOPE_MEDIA = 10
31 SCOPE_PLAYLIST = 11
32 SCOPE_CURRENT_SKIN = 12
33 SCOPE_DEFAULTDIR = 13
34 SCOPE_DEFAULTPARTITION = 14
35 SCOPE_DEFAULTPARTITIONMOUNTDIR = 15
36 SCOPE_METADIR = 16
37 SCOPE_CURRENT_PLUGIN = 17
38
39 PATH_CREATE = 0
40 PATH_DONTCREATE = 1
41 PATH_FALLBACK = 2
42 defaultPaths = {
43                 SCOPE_TRANSPONDERDATA: (eEnv.resolve("${sysconfdir}/"), PATH_DONTCREATE),
44                 SCOPE_SYSETC: (eEnv.resolve("${sysconfdir}/"), PATH_DONTCREATE),
45                 SCOPE_FONTS: (eEnv.resolve("${datadir}/fonts/"), PATH_DONTCREATE),
46                 SCOPE_CONFIG: (eEnv.resolve("${sysconfdir}/enigma2/"), PATH_CREATE),
47                 SCOPE_PLUGINS: (eEnv.resolve("${libdir}/enigma2/python/Plugins/"), PATH_CREATE),
48
49                 SCOPE_LANGUAGE: (eEnv.resolve("${datadir}/enigma2/po/"), PATH_DONTCREATE),
50
51                 SCOPE_SKIN: (eEnv.resolve("${datadir}/enigma2/"), PATH_DONTCREATE),
52                 SCOPE_SKIN_IMAGE: (eEnv.resolve("${datadir}/enigma2/"), PATH_DONTCREATE),
53                 SCOPE_HDD: ("/hdd/movie/", PATH_DONTCREATE),
54                 SCOPE_MEDIA: ("/media/", PATH_DONTCREATE),
55                 SCOPE_PLAYLIST: (eEnv.resolve("${sysconfdir}/enigma2/playlist/"), PATH_CREATE),
56                 
57                 SCOPE_USERETC: ("", PATH_DONTCREATE), # user home directory
58                 
59                 SCOPE_DEFAULTDIR: (eEnv.resolve("${datadir}/enigma2/defaults/"), PATH_CREATE),
60                 SCOPE_DEFAULTPARTITION: ("/dev/mtdblock6", PATH_DONTCREATE),
61                 SCOPE_DEFAULTPARTITIONMOUNTDIR: (eEnv.resolve("${datadir}/enigma2/dealer"), PATH_CREATE),
62                 SCOPE_METADIR: (eEnv.resolve("${datadir}/meta"), PATH_CREATE),
63         }
64
65 FILE_COPY = 0 # copy files from fallback dir to the basedir
66 FILE_MOVE = 1 # move files
67 PATH_COPY = 2 # copy the complete fallback dir to the basedir
68 PATH_MOVE = 3 # move the fallback dir to the basedir (can be used for changes in paths)
69 fallbackPaths = {
70                 SCOPE_CONFIG: [("/home/root/", FILE_MOVE),
71                                            (eEnv.resolve("${datadir}/enigma2/defaults/"), FILE_COPY)],
72                 SCOPE_HDD: [("/hdd/movies", PATH_MOVE)]
73         }
74
75 def resolveFilename(scope, base = "", path_prefix = None):
76         if base[0:2] == "~/":
77                 # you can only use the ~/ if we have a prefix directory
78                 assert path_prefix is not None
79                 base = os_path.join(path_prefix, base[2:])
80
81         # don't resolve absolute paths
82         if base[0:1] == '/':
83                 return base
84
85         if scope == SCOPE_CURRENT_SKIN:
86                 from Components.config import config
87                 tmp = defaultPaths[SCOPE_SKIN]
88                 pos = config.skin.primary_skin.value.rfind('/')
89                 if pos != -1:
90                         #if basefile is not available use default skin path as fallback
91                         tmpfile = tmp[0]+config.skin.primary_skin.value[:pos+1] + base
92                         if fileExists(tmpfile):
93                                 path = tmp[0]+config.skin.primary_skin.value[:pos+1]
94                         else:
95                                 path = tmp[0]
96                 else:
97                         path = tmp[0]
98
99         elif scope == SCOPE_CURRENT_PLUGIN:
100                 tmp = defaultPaths[SCOPE_PLUGINS]
101                 from Components.config import config
102                 skintmp = defaultPaths[SCOPE_SKIN]
103                 pos = config.skin.primary_skin.value.rfind('/')
104                 if pos != -1:
105                         #if basefile is not available inside current skin path, use the original provided file as fallback
106                         skintmpfile = skintmp[0]+config.skin.primary_skin.value[:pos+1] + base
107                         if fileExists(skintmpfile):
108                                 path = skintmp[0]+config.skin.primary_skin.value[:pos+1]
109                         else:
110                                 path = tmp[0]
111                 else:
112                         path = tmp[0]
113         else:
114                 tmp = defaultPaths[scope]
115                 path = tmp[0]
116
117         flags = tmp[1]
118
119         if flags == PATH_CREATE:
120                 if not pathExists(path):
121                         mkdir(path)
122
123         fallbackPath = fallbackPaths.get(scope)
124
125         if fallbackPath and not fileExists(path + base):
126                 for x in fallbackPath:
127                         if x[1] == FILE_COPY:
128                                 if fileExists(x[0] + base):
129                                         system("cp " + x[0] + base + " " + path + base)
130                                         break
131                         elif x[1] == FILE_MOVE:
132                                 if fileExists(x[0] + base):
133                                         system("mv " + x[0] + base + " " + path + base)
134                                         break
135                         elif x[1] == PATH_COPY:
136                                 if pathExists(x[0]):
137                                         if not pathExists(defaultPaths[scope][0]):
138                                                 mkdir(path)
139                                         system("cp -a " + x[0] + "* " + path)
140                                         break
141                         elif x[1] == PATH_MOVE:
142                                 if pathExists(x[0]):
143                                         system("mv " + x[0] + " " + path)
144                                         break
145
146         # FIXME: we also have to handle DATADIR etc. here.
147         return path + base
148         # this is only the BASE - an extension must be added later.
149
150 def pathExists(path):
151         return os_path.exists(path)
152
153 def isMount(path):
154         return os_path.ismount(path)
155
156 def createDir(path, makeParents = False):
157         try:
158                 if makeParents:
159                         makedirs(path)
160                 else:
161                         mkdir(path)
162         except:
163                 ret = 0
164         else:
165                 ret = 1
166         return ret
167
168 def removeDir(path):
169         try:
170                 rmdir(path)
171         except:
172                 ret = 0
173         else:
174                 ret = 1
175         return ret
176
177 def fileExists(f, mode='r'):
178         if mode == 'r':
179                 acc_mode = R_OK
180         elif mode == 'w':
181                 acc_mode = W_OK
182         else:
183                 acc_mode = F_OK
184         return access(f, acc_mode)
185
186 def getRecordingFilename(basename, dirname = None):
187         # filter out non-allowed characters
188         non_allowed_characters = "/.\\:*?<>|\""
189         filename = ""
190         
191         basename = basename.replace('\xc2\x86', '').replace('\xc2\x87', '')
192         
193         for c in basename:
194                 if c in non_allowed_characters or ord(c) < 32:
195                         c = "_"
196                 filename += c
197
198         if dirname is not None:
199                 filename = ''.join((dirname, filename))
200
201         while len(filename) > 240:
202                 filename = filename.decode('UTF-8')
203                 filename = filename[:-1]
204                 filename = filename.encode('UTF-8')
205
206         i = 0
207         while True:
208                 path = resolveFilename(SCOPE_HDD, filename)
209                 if i > 0:
210                         path += "_%03d" % i
211                 try:
212                         open(path + ".ts")
213                         i += 1
214                 except IOError:
215                         return path
216
217 # this is clearly a hack:
218 def InitFallbackFiles():
219         resolveFilename(SCOPE_CONFIG, "userbouquet.favourites.tv")
220         resolveFilename(SCOPE_CONFIG, "bouquets.tv")
221         resolveFilename(SCOPE_CONFIG, "userbouquet.favourites.radio")
222         resolveFilename(SCOPE_CONFIG, "bouquets.radio")
223
224 # returns a list of tuples containing pathname and filename matching the given pattern
225 # example-pattern: match all txt-files: ".*\.txt$"
226 def crawlDirectory(directory, pattern):
227         expression = compile(pattern)
228         list = []
229         for root, dirs, files in walk(directory):
230                 for file in files:
231                         if expression.match(file) is not None:
232                                 list.append((root, file))
233         return list
234
235 def copyfile(src, dst):
236         try:
237                 f1 = open(src, "rb")
238                 if os_path.isdir(dst):
239                         dst = os_path.join(dst, os_path.basename(src))
240                 f2 = open(dst, "w+b")
241                 while True:
242                         buf = f1.read(16*1024)
243                         if not buf:
244                                 break
245                         f2.write(buf)
246                 st = os_stat(src)
247                 mode = S_IMODE(st.st_mode)
248                 if have_chmod:
249                         chmod(dst, mode)
250                 if have_utime:
251                         utime(dst, (st.st_atime, st.st_mtime))
252         except:
253                 print "copy", src, "to", dst, "failed!"
254                 return -1
255         return 0
256
257 def copytree(src, dst, symlinks=False):
258         names = listdir(src)
259         if os_path.isdir(dst):
260                 dst = os_path.join(dst, os_path.basename(src))
261                 if not os_path.isdir(dst):
262                         mkdir(dst)
263         else:
264                 makedirs(dst)
265         for name in names:
266                 srcname = os_path.join(src, name)
267                 dstname = os_path.join(dst, name)
268                 try:
269                         if symlinks and os_path.islink(srcname):
270                                 linkto = readlink(srcname)
271                                 symlink(linkto, dstname)
272                         elif os_path.isdir(srcname):
273                                 copytree(srcname, dstname, symlinks)
274                         else:
275                                 copyfile(srcname, dstname)
276                 except:
277                         print "dont copy srcname (no file or link or folder)"
278         try:
279                 st = os_stat(src)
280                 mode = S_IMODE(st.st_mode)
281                 if have_chmod:
282                         chmod(dst, mode)
283                 if have_utime:
284                         utime(dst, (st.st_atime, st.st_mtime))
285         except:
286                 print "copy stats for", src, "failed!"
287
288 def getSize(path, pattern=".*"):
289         path_size = 0
290         if os_path.isdir(path):
291                 files = crawlDirectory(path, pattern)
292                 for file in files:
293                         filepath = os_path.join(file[0], file[1])
294                         path_size += os_path.getsize(filepath)
295         elif os_path.isfile(path):
296                 path_size = os_path.getsize(path)
297         return path_size