posixfile.py 7.66 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
"""
Guido van Rossum's avatar
Guido van Rossum committed
55

56

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

60 61
    states = ['open', 'closed']

Guido van Rossum's avatar
Guido van Rossum committed
62 63 64 65
    #
    # Internal routines
    #
    def __repr__(self):
66 67 68 69
        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
70 71 72 73

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

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

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

    def dup(self):
98
        import posix
Guido van Rossum's avatar
Guido van Rossum committed
99

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

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

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

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

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

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

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

        l_flags = 0
124 125 126
        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
127 128 129 130

        file = self._file_

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

135
        l_flags = fcntl.fcntl(file.fileno(), fcntl.F_SETFL, l_flags)
136

Tim Peters's avatar
Tim Peters committed
137
        if 'c' in which:
138
            arg = ('!' not in which)    # 0 is don't, 1 is do close on exec
139
            l_flags = fcntl.fcntl(file.fileno(), fcntl.F_SETFD, arg)
140 141 142

        if '?' in which:
            which = ''                  # Return current flags
143 144 145
            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:
146
                which = which + 'c'
147 148
            if os.O_NDELAY & l_flags: which = which + 'n'
            if os.O_SYNC & l_flags: which = which + 's'
149
            return which
Tim Peters's avatar
Tim Peters committed
150

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

154 155 156
        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
157 158
        else: raise TypeError, 'no type of lock specified'

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

        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
178
        import sys, os
179
        if sys.platform in ('netbsd1',
180
                            'openbsd2',
181
                            'freebsd2', 'freebsd3', 'freebsd4', 'freebsd5',
182 183
                            'freebsd6', 'freebsd7',
                            'bsdos2', 'bsdos3', 'bsdos4'):
184
            flock = struct.pack('lxxxxlxxxxlhh', \
Tim Peters's avatar
Tim Peters committed
185
                  l_start, l_len, os.getpid(), l_type, l_whence)
186
        elif sys.platform in ('aix3', 'aix4'):
187 188
            flock = struct.pack('hhlllii', \
                  l_type, l_whence, l_start, l_len, 0, 0, 0)
189 190 191
        else:
            flock = struct.pack('hhllhh', \
                  l_type, l_whence, l_start, l_len, 0, 0)
192

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

195
        if '?' in how:
196
            if sys.platform in ('netbsd1',
197
                                'openbsd2',
198
                                'freebsd2', 'freebsd3', 'freebsd4', 'freebsd5',
199
                                'bsdos2', 'bsdos3', 'bsdos4'):
200 201
                l_start, l_len, l_pid, l_type, l_whence = \
                    struct.unpack('lxxxxlxxxxlhh', flock)
202
            elif sys.platform in ('aix3', 'aix4'):
203 204
                l_type, l_whence, l_start, l_len, l_sysid, l_pid, l_vfs = \
                    struct.unpack('hhlllii', flock)
205 206 207 208 209 210 211
            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)

212 213
            if l_type != fcntl.F_UNLCK:
                if l_type == fcntl.F_RDLCK:
214 215 216
                    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
217

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

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

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

Guido van Rossum's avatar
Guido van Rossum committed
233 234 235
#
# End of posixfile.py
#