posixfile.py 7.46 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

class _posixfile_:
57 58
    """File wrapper class that provides extra POSIX file routines."""

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

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

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

77
    def fileopen(self, file):
78 79 80 81 82 83 84
        if `type(file)` != "<type 'file'>":
            raise TypeError, 'posixfile.fileopen() arg must be file object'
        self._file_  = file
        # Copy basic file methods
        for method in file.__methods__:
            setattr(self, method, getattr(file, method))
        return self
Guido van Rossum's avatar
Guido van Rossum committed
85 86 87 88 89

    #
    # New methods
    #
    def file(self):
90
        return self._file_
Guido van Rossum's avatar
Guido van Rossum committed
91 92

    def dup(self):
93
        import posix
Guido van Rossum's avatar
Guido van Rossum committed
94

95 96
        try: ignore = posix.fdopen
        except: raise AttributeError, 'dup() method unavailable'
Guido van Rossum's avatar
Guido van Rossum committed
97

98
        return posix.fdopen(posix.dup(self._file_.fileno()), self._file_.mode)
Guido van Rossum's avatar
Guido van Rossum committed
99 100

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

103 104
        try: ignore = posix.fdopen
        except: raise AttributeError, 'dup() method unavailable'
Guido van Rossum's avatar
Guido van Rossum committed
105

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

109
    def flags(self, *which):
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
        import fcntl, FCNTL

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

        l_flags = 0
        if 'n' in which: l_flags = l_flags | FCNTL.O_NDELAY
        if 'a' in which: l_flags = l_flags | FCNTL.O_APPEND
        if 's' in which: l_flags = l_flags | FCNTL.O_SYNC

        file = self._file_

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

        l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFL, l_flags)

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

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

Guido van Rossum's avatar
Guido van Rossum committed
146
    def lock(self, how, *args):
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
        import struct, fcntl, FCNTL

        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
        else: raise TypeError, 'no type of lock specified'

        if '|' in how: cmd = FCNTL.F_SETLKW
        elif '?' in how: cmd = FCNTL.F_GETLK
        else: cmd = FCNTL.F_SETLK

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

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

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

            if l_type != FCNTL.F_UNLCK:
                if l_type == FCNTL.F_RDLCK:
                    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
211

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

216
def fileopen(file):
217
    """Public routine to get a posixfile object from a Python file object."""
218 219 220 221 222 223 224 225 226
    return _posixfile_().fileopen(file)

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

Guido van Rossum's avatar
Guido van Rossum committed
227 228 229
#
# End of posixfile.py
#