1"""Extended file operations available in POSIX.
2
3f = posixfile.open(filename, [mode, [bufsize]])
4      will create a new posixfile object
5
6f = posixfile.fileopen(fileobject)
7      will create a posixfile object from a builtin file object
8
9f.file()
10      will return the original builtin file object
11
12f.dup()
13      will return a new file object based on a new filedescriptor
14
15f.dup2(fd)
16      will return a new file object based on the given filedescriptor
17
18f.flags(mode)
19      will turn on the associated flag (merge)
20      mode can contain the following characters:
21
22  (character representing a flag)
23      a       append only flag
24      c       close on exec flag
25      n       no delay flag
26      s       synchronization flag
27  (modifiers)
28      !       turn flags 'off' instead of default 'on'
29      =       copy flags 'as is' instead of default 'merge'
30      ?       return a string in which the characters represent the flags
31              that are set
32
33      note: - the '!' and '=' modifiers are mutually exclusive.
34            - the '?' modifier will return the status of the flags after they
35              have been changed by other characters in the mode string
36
37f.lock(mode [, len [, start [, whence]]])
38      will (un)lock a region
39      mode can contain the following characters:
40
41  (character representing type of lock)
42      u       unlock
43      r       read lock
44      w       write lock
45  (modifiers)
46      |       wait until the lock can be granted
47      ?       return the first lock conflicting with the requested lock
48              or 'None' if there is no conflict. The lock returned is in the
49              format (mode, len, start, whence, pid) where mode is a
50              character representing the type of lock ('r' or 'w')
51
52      note: - the '?' modifier prevents a region from being locked; it is
53              query only
54"""
55import warnings
56warnings.warn("The posixfile module is deprecated; "
57                "fcntl.lockf() provides better locking", DeprecationWarning, 2)
58
59class _posixfile_:
60    """File wrapper class that provides extra POSIX file routines."""
61
62    states = ['open', 'closed']
63
64    #
65    # Internal routines
66    #
67    def __repr__(self):
68        file = self._file_
69        return "<%s posixfile '%s', mode '%s' at %s>" % \
70                (self.states[file.closed], file.name, file.mode, \
71                 hex(id(self))[2:])
72
73    #
74    # Initialization routines
75    #
76    def open(self, name, mode='r', bufsize=-1):
77        import __builtin__
78        return self.fileopen(__builtin__.open(name, mode, bufsize))
79
80    def fileopen(self, file):
81        import types
82        if repr(type(file)) != "<type 'file'>":
83            raise TypeError, 'posixfile.fileopen() arg must be file object'
84        self._file_  = file
85        # Copy basic file methods
86        for maybemethod in dir(file):
87            if not maybemethod.startswith('_'):
88                attr = getattr(file, maybemethod)
89                if isinstance(attr, types.BuiltinMethodType):
90                    setattr(self, maybemethod, attr)
91        return self
92
93    #
94    # New methods
95    #
96    def file(self):
97        return self._file_
98
99    def dup(self):
100        import posix
101
102        if not hasattr(posix, 'fdopen'):
103            raise AttributeError, 'dup() method unavailable'
104
105        return posix.fdopen(posix.dup(self._file_.fileno()), self._file_.mode)
106
107    def dup2(self, fd):
108        import posix
109
110        if not hasattr(posix, 'fdopen'):
111            raise AttributeError, 'dup() method unavailable'
112
113        posix.dup2(self._file_.fileno(), fd)
114        return posix.fdopen(fd, self._file_.mode)
115
116    def flags(self, *which):
117        import fcntl, os
118
119        if which:
120            if len(which) > 1:
121                raise TypeError, 'Too many arguments'
122            which = which[0]
123        else: which = '?'
124
125        l_flags = 0
126        if 'n' in which: l_flags = l_flags | os.O_NDELAY
127        if 'a' in which: l_flags = l_flags | os.O_APPEND
128        if 's' in which: l_flags = l_flags | os.O_SYNC
129
130        file = self._file_
131
132        if '=' not in which:
133            cur_fl = fcntl.fcntl(file.fileno(), fcntl.F_GETFL, 0)
134            if '!' in which: l_flags = cur_fl & ~ l_flags
135            else: l_flags = cur_fl | l_flags
136
137        l_flags = fcntl.fcntl(file.fileno(), fcntl.F_SETFL, l_flags)
138
139        if 'c' in which:
140            arg = ('!' not in which)    # 0 is don't, 1 is do close on exec
141            l_flags = fcntl.fcntl(file.fileno(), fcntl.F_SETFD, arg)
142
143        if '?' in which:
144            which = ''                  # Return current flags
145            l_flags = fcntl.fcntl(file.fileno(), fcntl.F_GETFL, 0)
146            if os.O_APPEND & l_flags: which = which + 'a'
147            if fcntl.fcntl(file.fileno(), fcntl.F_GETFD, 0) & 1:
148                which = which + 'c'
149            if os.O_NDELAY & l_flags: which = which + 'n'
150            if os.O_SYNC & l_flags: which = which + 's'
151            return which
152
153    def lock(self, how, *args):
154        import struct, fcntl
155
156        if 'w' in how: l_type = fcntl.F_WRLCK
157        elif 'r' in how: l_type = fcntl.F_RDLCK
158        elif 'u' in how: l_type = fcntl.F_UNLCK
159        else: raise TypeError, 'no type of lock specified'
160
161        if '|' in how: cmd = fcntl.F_SETLKW
162        elif '?' in how: cmd = fcntl.F_GETLK
163        else: cmd = fcntl.F_SETLK
164
165        l_whence = 0
166        l_start = 0
167        l_len = 0
168
169        if len(args) == 1:
170            l_len = args[0]
171        elif len(args) == 2:
172            l_len, l_start = args
173        elif len(args) == 3:
174            l_len, l_start, l_whence = args
175        elif len(args) > 3:
176            raise TypeError, 'too many arguments'
177
178        # Hack by davem@magnet.com to get locking to go on freebsd;
179        # additions for AIX by Vladimir.Marangozov@imag.fr
180        import sys, os
181        if sys.platform in ('netbsd1',
182                            'openbsd2',
183                            'freebsd2', 'freebsd3', 'freebsd4', 'freebsd5',
184                            'freebsd6', 'freebsd7', 'freebsd8',
185                            'bsdos2', 'bsdos3', 'bsdos4'):
186            flock = struct.pack('lxxxxlxxxxlhh', \
187                  l_start, l_len, os.getpid(), l_type, l_whence)
188        elif sys.platform in ('aix3', 'aix4'):
189            flock = struct.pack('hhlllii', \
190                  l_type, l_whence, l_start, l_len, 0, 0, 0)
191        else:
192            flock = struct.pack('hhllhh', \
193                  l_type, l_whence, l_start, l_len, 0, 0)
194
195        flock = fcntl.fcntl(self._file_.fileno(), cmd, flock)
196
197        if '?' in how:
198            if sys.platform in ('netbsd1',
199                                'openbsd2',
200                                'freebsd2', 'freebsd3', 'freebsd4', 'freebsd5',
201                                'bsdos2', 'bsdos3', 'bsdos4'):
202                l_start, l_len, l_pid, l_type, l_whence = \
203                    struct.unpack('lxxxxlxxxxlhh', flock)
204            elif sys.platform in ('aix3', 'aix4'):
205                l_type, l_whence, l_start, l_len, l_sysid, l_pid, l_vfs = \
206                    struct.unpack('hhlllii', flock)
207            elif sys.platform == "linux2":
208                l_type, l_whence, l_start, l_len, l_pid, l_sysid = \
209                    struct.unpack('hhllhh', flock)
210            else:
211                l_type, l_whence, l_start, l_len, l_sysid, l_pid = \
212                    struct.unpack('hhllhh', flock)
213
214            if l_type != fcntl.F_UNLCK:
215                if l_type == fcntl.F_RDLCK:
216                    return 'r', l_len, l_start, l_whence, l_pid
217                else:
218                    return 'w', l_len, l_start, l_whence, l_pid
219
220def open(name, mode='r', bufsize=-1):
221    """Public routine to open a file as a posixfile object."""
222    return _posixfile_().open(name, mode, bufsize)
223
224def fileopen(file):
225    """Public routine to get a posixfile object from a Python file object."""
226    return _posixfile_().fileopen(file)
227
228#
229# Constants
230#
231SEEK_SET = 0
232SEEK_CUR = 1
233SEEK_END = 2
234
235#
236# End of posixfile.py
237#
238