posixfile.py 7.82 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
"""Extended file operations available in POSIX.

f = posixfile.open(filename, [mode, [bufsize]])
      will create a new posixfile object

f = posixfile.fileopen(fileobject)
      will create a posixfile object from a builtin file object

f.file()
      will return the original builtin file object

f.dup()
      will return a new file object based on a new filedescriptor

f.dup2(fd)
      will return a new file object based on the given filedescriptor

f.flags(mode)
      will turn on the associated flag (merge)
      mode can contain the following characters:

  (character representing a flag)
      a       append only flag
      c       close on exec flag
      n       no delay flag
      s       synchronization flag
  (modifiers)
      !       turn flags 'off' instead of default 'on'
      =       copy flags 'as is' instead of default 'merge'
      ?       return a string in which the characters represent the flags
              that are set

      note: - the '!' and '=' modifiers are mutually exclusive.
            - the '?' modifier will return the status of the flags after they
              have been changed by other characters in the mode string

f.lock(mode [, len [, start [, whence]]])
      will (un)lock a region
      mode can contain the following characters:

  (character representing type of lock)
      u       unlock
      r       read lock
      w       write lock
  (modifiers)
      |       wait until the lock can be granted
      ?       return the first lock conflicting with the requested lock
              or 'None' if there is no conflict. The lock returned is in the
              format (mode, len, start, whence, pid) where mode is a
              character representing the type of lock ('r' or 'w')

      note: - the '?' modifier prevents a region from being locked; it is
              query only
"""
55 56 57
import warnings
warnings.warn("The posixfile module is deprecated; "
                "fcntl.lockf() provides better locking", DeprecationWarning, 2)
58

Guido van Rossum's avatar
Guido van Rossum committed
59
class _posixfile_:
60 61
    """File wrapper class that provides extra POSIX file routines."""

62 63
    states = ['open', 'closed']

Guido van Rossum's avatar
Guido van Rossum committed
64 65 66 67
    #
    # Internal routines
    #
    def __repr__(self):
68 69 70 71
        file = self._file_
        return "<%s posixfile '%s', mode '%s' at %s>" % \
                (self.states[file.closed], file.name, file.mode, \
                 hex(id(self))[2:])
Guido van Rossum's avatar
Guido van Rossum committed
72 73 74 75

    #
    # Initialization routines
    #
76
    def open(self, name, mode='r', bufsize=-1):
77 78
        import __builtin__
        return self.fileopen(__builtin__.open(name, mode, bufsize))
Guido van Rossum's avatar
Guido van Rossum committed
79

80
    def fileopen(self, file):
81
        import types
82
        if repr(type(file)) != "<type 'file'>":
83 84 85
            raise TypeError, 'posixfile.fileopen() arg must be file object'
        self._file_  = file
        # Copy basic file methods
86 87 88 89 90
        for maybemethod in dir(file):
            if not maybemethod.startswith('_'):
                attr = getattr(file, maybemethod)
                if isinstance(attr, types.BuiltinMethodType):
                    setattr(self, maybemethod, attr)
91
        return self
Guido van Rossum's avatar
Guido van Rossum committed
92 93 94 95 96

    #
    # New methods
    #
    def file(self):
97
        return self._file_
Guido van Rossum's avatar
Guido van Rossum committed
98 99

    def dup(self):
100
        import posix
Guido van Rossum's avatar
Guido van Rossum committed
101

102 103
        if not hasattr(posix, 'fdopen'):
            raise AttributeError, 'dup() method unavailable'
Guido van Rossum's avatar
Guido van Rossum committed
104

105
        return posix.fdopen(posix.dup(self._file_.fileno()), self._file_.mode)
Guido van Rossum's avatar
Guido van Rossum committed
106 107

    def dup2(self, fd):
108
        import posix
Guido van Rossum's avatar
Guido van Rossum committed
109

110 111
        if not hasattr(posix, 'fdopen'):
            raise AttributeError, 'dup() method unavailable'
Guido van Rossum's avatar
Guido van Rossum committed
112

113 114
        posix.dup2(self._file_.fileno(), fd)
        return posix.fdopen(fd, self._file_.mode)
Guido van Rossum's avatar
Guido van Rossum committed
115

116
    def flags(self, *which):
117
        import fcntl, os
118 119 120 121 122 123 124 125

        if which:
            if len(which) > 1:
                raise TypeError, 'Too many arguments'
            which = which[0]
        else: which = '?'

        l_flags = 0
126 127 128
        if 'n' in which: l_flags = l_flags | os.O_NDELAY
        if 'a' in which: l_flags = l_flags | os.O_APPEND
        if 's' in which: l_flags = l_flags | os.O_SYNC
129 130 131 132

        file = self._file_

        if '=' not in which:
133
            cur_fl = fcntl.fcntl(file.fileno(), fcntl.F_GETFL, 0)
134 135 136
            if '!' in which: l_flags = cur_fl & ~ l_flags
            else: l_flags = cur_fl | l_flags

137
        l_flags = fcntl.fcntl(file.fileno(), fcntl.F_SETFL, l_flags)
138

Tim Peters's avatar
Tim Peters committed
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 144

        if '?' in which:
            which = ''                  # Return current flags
145 146 147
            l_flags = fcntl.fcntl(file.fileno(), fcntl.F_GETFL, 0)
            if os.O_APPEND & l_flags: which = which + 'a'
            if fcntl.fcntl(file.fileno(), fcntl.F_GETFD, 0) & 1:
148
                which = which + 'c'
149 150
            if os.O_NDELAY & l_flags: which = which + 'n'
            if os.O_SYNC & l_flags: which = which + 's'
151
            return which
Tim Peters's avatar
Tim Peters committed
152

Guido van Rossum's avatar
Guido van Rossum committed
153
    def lock(self, how, *args):
154
        import struct, fcntl
155

156 157 158
        if 'w' in how: l_type = fcntl.F_WRLCK
        elif 'r' in how: l_type = fcntl.F_RDLCK
        elif 'u' in how: l_type = fcntl.F_UNLCK
159 160
        else: raise TypeError, 'no type of lock specified'

161 162 163
        if '|' in how: cmd = fcntl.F_SETLKW
        elif '?' in how: cmd = fcntl.F_GETLK
        else: cmd = fcntl.F_SETLK
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179

        l_whence = 0
        l_start = 0
        l_len = 0

        if len(args) == 1:
            l_len = args[0]
        elif len(args) == 2:
            l_len, l_start = args
        elif len(args) == 3:
            l_len, l_start, l_whence = args
        elif len(args) > 3:
            raise TypeError, 'too many arguments'

        # Hack by davem@magnet.com to get locking to go on freebsd;
        # 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', \
Tim Peters's avatar
Tim Peters committed
187
                  l_start, l_len, os.getpid(), l_type, l_whence)
188
        elif sys.platform in ('aix3', 'aix4'):
189 190
            flock = struct.pack('hhlllii', \
                  l_type, l_whence, l_start, l_len, 0, 0, 0)
191 192 193
        else:
            flock = struct.pack('hhllhh', \
                  l_type, l_whence, l_start, l_len, 0, 0)
194

195
        flock = fcntl.fcntl(self._file_.fileno(), cmd, flock)
Guido van Rossum's avatar
Guido van Rossum committed
196

197
        if '?' in how:
198
            if sys.platform in ('netbsd1',
199
                                'openbsd2',
200
                                'freebsd2', 'freebsd3', 'freebsd4', 'freebsd5',
201
                                'bsdos2', 'bsdos3', 'bsdos4'):
202 203
                l_start, l_len, l_pid, l_type, l_whence = \
                    struct.unpack('lxxxxlxxxxlhh', flock)
204
            elif sys.platform in ('aix3', 'aix4'):
205 206
                l_type, l_whence, l_start, l_len, l_sysid, l_pid, l_vfs = \
                    struct.unpack('hhlllii', flock)
207 208 209 210 211 212 213
            elif sys.platform == "linux2":
                l_type, l_whence, l_start, l_len, l_pid, l_sysid = \
                    struct.unpack('hhllhh', flock)
            else:
                l_type, l_whence, l_start, l_len, l_sysid, l_pid = \
                    struct.unpack('hhllhh', flock)

214 215
            if l_type != fcntl.F_UNLCK:
                if l_type == fcntl.F_RDLCK:
216 217 218
                    return 'r', l_len, l_start, l_whence, l_pid
                else:
                    return 'w', l_len, l_start, l_whence, l_pid
Guido van Rossum's avatar
Guido van Rossum committed
219

220
def open(name, mode='r', bufsize=-1):
221
    """Public routine to open a file as a posixfile object."""
222
    return _posixfile_().open(name, mode, bufsize)
Guido van Rossum's avatar
Guido van Rossum committed
223

224
def fileopen(file):
225
    """Public routine to get a posixfile object from a Python file object."""
226 227 228 229 230 231 232 233 234
    return _posixfile_().fileopen(file)

#
# Constants
#
SEEK_SET = 0
SEEK_CUR = 1
SEEK_END = 2

Guido van Rossum's avatar
Guido van Rossum committed
235 236 237
#
# End of posixfile.py
#