source: trunk/src/testing/bin/fileServer/misc/mmpython/disc/discinfo.py @ 4

Revision 4, 8.9 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

Line 
1# -----------------------------------------------------------------------
2# discinfo.py - basic class for any discs containing collections of
3# media.
4# -----------------------------------------------------------------------
5# $Id: discinfo.py,v 1.23 2004/09/14 20:12:25 dischi Exp $
6#
7# $Log: discinfo.py,v $
8# Revision 1.23  2004/09/14 20:12:25  dischi
9# fix future warning
10#
11# Revision 1.22  2004/08/28 17:27:16  dischi
12# handle empty discs
13#
14# Revision 1.21  2004/06/25 13:20:35  dischi
15# FreeBSD patches
16#
17# Revision 1.20  2004/02/08 17:44:05  dischi
18# close fd
19#
20# Revision 1.19  2004/01/24 18:40:44  dischi
21# add md5 as possible way to generate the id
22#
23# Revision 1.18  2003/11/07 09:43:40  dischi
24# make interface compatible to old one
25#
26# Revision 1.17  2003/11/05 20:58:26  dischi
27# detect mixed audio cds
28#
29# Revision 1.16  2003/10/18 11:13:03  dischi
30# patch from Cyril Lacoux to detect blank discs
31#
32# Revision 1.15  2003/09/23 13:51:27  outlyer
33# More *BSD fixes from Lars; repairs a problem in his older patch.
34#
35# Revision 1.14  2003/09/14 13:32:12  dischi
36# set self.id for audio discs in discinfo.py to make it possible to use the cache for cddb
37#
38# Revision 1.13  2003/09/14 01:41:37  outlyer
39# FreeBSD support
40#
41# Revision 1.12  2003/09/10 18:50:31  dischi
42# error handling
43#
44# Revision 1.11  2003/08/26 21:21:18  outlyer
45# Fix two more Python 2.3 warnings.
46#
47# Revision 1.10  2003/08/26 18:01:26  outlyer
48# Patch from Lars Eggert for FreeBSD support
49#
50# Revision 1.9  2003/08/23 17:54:14  dischi
51# move id translation of bad chars directly after parsing
52#
53# Revision 1.8  2003/07/04 15:32:52  outlyer
54# Fix the label so we don't try to cache into a directory instead of a file.
55#
56# Revision 1.7  2003/07/02 22:04:26  dischi
57# just to be save
58#
59# Revision 1.6  2003/07/02 22:03:13  dischi
60# cache the disc id, it cannot change in 1 sec
61#
62# Revision 1.5  2003/06/23 19:26:16  dischi
63# Fixed bug in the cdrommodule that the file was not closed after usage.
64# The result was a drive you can't eject while the program (e.g. Freevo)
65# is running. Added cvs log for DiscID and cdrommodule to keep track of
66# all changes we did for mmpython.
67#
68# Revision 1.4  2003/06/23 09:22:54  the_krow
69# Typo and Indentation fixes.
70#
71# Revision 1.3  2003/06/10 22:11:36  dischi
72# some fixes
73#
74# Revision 1.2  2003/06/10 11:50:52  dischi
75# Moved all ioctl calls for discs to discinfo.cdrom_disc_status. This function
76# uses try catch around ioctl so it will return 0 (== no disc) for systems
77# without ioctl (e.g. Windows)
78#
79# Revision 1.1  2003/06/10 10:56:54  the_krow
80# - Build try-except blocks around disc imports to make it run on platforms
81#   not compiling / running the C extensions.
82# - moved DiscInfo class to disc module
83# - changed video.VcdInfo to be derived from CollectionInfo instead of
84#   DiskInfo so it can be used without the cdrom extensions which are
85#   hopefully not needed for bin-files.
86#
87#
88# -----------------------------------------------------------------------
89# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
90#
91# This program is free software; you can redistribute it and/or modify
92# it under the terms of the GNU General Public License as published by
93# the Free Software Foundation; either version 2 of the License, or
94# (at your option) any later version.
95#
96# This program is distributed in the hope that it will be useful, but
97# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
98# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
99# Public License for more details.
100#
101# You should have received a copy of the GNU General Public License along
102# with this program; if not, write to the Free Software Foundation, Inc.,
103# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
104#
105# ----------------------------------------------------------------------- */
106#endif
107
108from mmpython import mediainfo
109import os
110import re
111import time
112import array
113import md5
114from struct import *
115
116CREATE_MD5_ID = 0
117
118try:
119    from fcntl import ioctl
120    import DiscID
121except:
122    print 'WARNING: failed to import ioctl, discinfo won\'t work'
123
124
125def cdrom_disc_status(device, handle_mix = 0):
126    """
127    check the current disc in device
128    return: no disc (0), audio cd (1), data cd (2), blank cd (3)
129    """
130    CDROM_DRIVE_STATUS=0x5326
131    CDSL_CURRENT=( (int ) ( ~ 0 >> 1 ) )
132    CDROM_DISC_STATUS=0x5327
133    CDS_AUDIO=100
134    CDS_MIXED=105
135    CDS_DISC_OK=4
136   
137    # FreeBSD ioctls - there is no CDROM.py
138    # XXX 0xc0086305 below creates a warning, but 0xc0086305L
139    # doesn't work. Suppress that warning for Linux users,
140    # until a better solution can be found.
141    if os.uname()[0] == 'FreeBSD':
142        CDIOREADTOCENTRYS = 0xc0086305L
143        CD_MSF_FORMAT = 2
144       
145    try:
146        fd = os.open(device, os.O_RDONLY | os.O_NONBLOCK)
147        if os.uname()[0] == 'FreeBSD':
148            try:
149                cd_toc_entry = array.array('c', '\000'*4096)
150                (address, length) = cd_toc_entry.buffer_info()
151                buf = pack('BBHP', CD_MSF_FORMAT, 0, length, address)
152                s = ioctl(fd, CDIOREADTOCENTRYS, buf)
153                s = CDS_DISC_OK
154            except:
155                s = CDS_NO_DISC
156        else:
157            s = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT)
158    except:
159        print 'ERROR: no permission to read %s' % device
160        print 'Media detection not possible, set drive to \'empty\''
161       
162        # maybe we need to close the fd if ioctl fails, maybe
163        # open fails and there is no fd, maye we aren't running
164        # linux and don't have ioctl
165        try:
166            os.close(fd)
167        except:
168            pass
169        return 0
170
171    if not s == CDS_DISC_OK:
172        # no disc, error, whatever
173        return 0
174   
175    if os.uname()[0] == 'FreeBSD':
176        s = 0
177        # We already have the TOC from above
178        for i in range(0, 4096, 8):
179            control = unpack('B', cd_toc_entry[i+1])[0] & 4
180            track = unpack('B', cd_toc_entry[i+2])[0]
181            if track == 0:
182                break
183            if control == 0 and s != CDS_MIXED:
184                s = CDS_AUDIO
185            elif control != 0:
186                if s == CDS_AUDIO:
187                    s = CDS_MIXED
188                else:
189                    s = 100 + control # ugly, but encodes Linux ioctl returns
190            elif control == 5:
191                s = CDS_MIXED
192
193    else:
194        s = ioctl(fd, CDROM_DISC_STATUS)
195    os.close(fd)
196    if s == CDS_MIXED and handle_mix:
197        return 4
198    if s == CDS_AUDIO or s == CDS_MIXED:
199        return 1
200   
201    try:
202        fd = open(device, 'rb')
203        # try to read from the disc to get information if the disc
204        # is a rw medium not written yet
205       
206        fd.seek(32768) # 2048 multiple boundary for FreeBSD
207        # FreeBSD doesn't return IOError unless we try and read:
208        fd.read(1)
209    except IOError:
210        # not readable
211        fd.close()
212        return 3
213    else:
214        # disc ok
215        fd.close()
216        return 2
217   
218
219id_cache = {}
220
221def cdrom_disc_id(device, handle_mix=0):
222    """
223    return the disc id of the device or None if no disc is there
224    """
225    global id_cache
226    try:
227        if id_cache[device][0] + 0.9 > time.time():
228            return id_cache[device][1:]
229    except:
230        pass
231
232    disc_type = cdrom_disc_status(device, handle_mix=handle_mix)
233    if disc_type == 0 or disc_type == 3:
234        return 0, None
235       
236    elif disc_type == 1 or disc_type == 4:
237        disc_id = DiscID.disc_id(device)
238        id = '%08lx_%d' % (disc_id[0], disc_id[1])
239    else:
240        f = open(device,'rb')
241
242        if os.uname()[0] == 'FreeBSD':
243            # FreeBSD can only seek to 2048 multiple boundaries.
244            # Below works on Linux and FreeBSD:
245            f.seek(32768)
246            id = f.read(829)
247            label = id[40:72]
248            id = id[813:829]
249        else:
250            f.seek(0x0000832d)
251            id = f.read(16)
252            f.seek(32808, 0)
253            label = f.read(32)
254
255        if CREATE_MD5_ID:
256            id_md5 = md5.new()
257            id_md5.update(f.read(51200))
258            id = id_md5.hexdigest()
259
260        f.close()
261           
262        m = re.match("^(.*[^ ]) *$", label)
263        if m:
264            id = '%s%s' % (id, m.group(1))
265        id = re.compile('[^a-zA-Z0-9()_-]').sub('_', id)
266           
267       
268    id_cache[device] = time.time(), disc_type, id
269    id = id.replace('/','_')
270    return disc_type, id
271
272
273class DiscInfo(mediainfo.CollectionInfo):
274    def isDisc(self, device):
275        (type, self.id) = cdrom_disc_id(device, handle_mix=1)
276        if type != 2:
277            if type == 4:
278                self.keys.append('mixed')
279                self.mixed = 1
280                type = 1
281            return type
282       
283        if CREATE_MD5_ID:
284            if len(self.id) == 32:
285                self.label = ''
286            else:
287                self.label = self.id[32:]
288        else:
289            if len(self.id) == 16:
290                self.label = ''
291            else:
292                self.label = self.id[16:]
293
294        self.keys.append('label')
295        return type
Note: See TracBrowser for help on using the repository browser.