blob: 2db37e04ee20b0c3f17dd75eb3b8b4d5eed30741 [file] [log] [blame]
Guido van Rossumaad67612000-05-08 17:31:04 +00001"""Extended file operations available in POSIX.
Guido van Rossum5c971671996-07-22 15:23:25 +00002
Guido van Rossumaad67612000-05-08 17:31:04 +00003f = 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"""
Guido van Rossum5c971671996-07-22 15:23:25 +000055
56class _posixfile_:
Guido van Rossumaad67612000-05-08 17:31:04 +000057 """File wrapper class that provides extra POSIX file routines."""
58
Guido van Rossum5c971671996-07-22 15:23:25 +000059 states = ['open', 'closed']
60
61 #
62 # Internal routines
63 #
64 def __repr__(self):
Guido van Rossum548703a1998-03-26 22:14:20 +000065 file = self._file_
66 return "<%s posixfile '%s', mode '%s' at %s>" % \
67 (self.states[file.closed], file.name, file.mode, \
68 hex(id(self))[2:])
Guido van Rossum5c971671996-07-22 15:23:25 +000069
70 def __del__(self):
Guido van Rossum548703a1998-03-26 22:14:20 +000071 self._file_.close()
Guido van Rossum5c971671996-07-22 15:23:25 +000072
73 #
74 # Initialization routines
75 #
76 def open(self, name, mode='r', bufsize=-1):
Guido van Rossum548703a1998-03-26 22:14:20 +000077 import __builtin__
78 return self.fileopen(__builtin__.open(name, mode, bufsize))
Guido van Rossum5c971671996-07-22 15:23:25 +000079
80 def fileopen(self, file):
Guido van Rossum548703a1998-03-26 22:14:20 +000081 if `type(file)` != "<type 'file'>":
82 raise TypeError, 'posixfile.fileopen() arg must be file object'
83 self._file_ = file
84 # Copy basic file methods
85 for method in file.__methods__:
86 setattr(self, method, getattr(file, method))
87 return self
Guido van Rossum5c971671996-07-22 15:23:25 +000088
89 #
90 # New methods
91 #
92 def file(self):
Guido van Rossum548703a1998-03-26 22:14:20 +000093 return self._file_
Guido van Rossum5c971671996-07-22 15:23:25 +000094
95 def dup(self):
Guido van Rossum548703a1998-03-26 22:14:20 +000096 import posix
Guido van Rossum5c971671996-07-22 15:23:25 +000097
Guido van Rossum548703a1998-03-26 22:14:20 +000098 try: ignore = posix.fdopen
99 except: raise AttributeError, 'dup() method unavailable'
Guido van Rossum5c971671996-07-22 15:23:25 +0000100
Guido van Rossum548703a1998-03-26 22:14:20 +0000101 return posix.fdopen(posix.dup(self._file_.fileno()), self._file_.mode)
Guido van Rossum5c971671996-07-22 15:23:25 +0000102
103 def dup2(self, fd):
Guido van Rossum548703a1998-03-26 22:14:20 +0000104 import posix
Guido van Rossum5c971671996-07-22 15:23:25 +0000105
Guido van Rossum548703a1998-03-26 22:14:20 +0000106 try: ignore = posix.fdopen
107 except: raise AttributeError, 'dup() method unavailable'
Guido van Rossum5c971671996-07-22 15:23:25 +0000108
Guido van Rossum548703a1998-03-26 22:14:20 +0000109 posix.dup2(self._file_.fileno(), fd)
110 return posix.fdopen(fd, self._file_.mode)
Guido van Rossum5c971671996-07-22 15:23:25 +0000111
112 def flags(self, *which):
Guido van Rossum548703a1998-03-26 22:14:20 +0000113 import fcntl, FCNTL
Guido van Rossum5c971671996-07-22 15:23:25 +0000114
Guido van Rossum548703a1998-03-26 22:14:20 +0000115 if which:
116 if len(which) > 1:
117 raise TypeError, 'Too many arguments'
118 which = which[0]
119 else: which = '?'
Guido van Rossum5c971671996-07-22 15:23:25 +0000120
Guido van Rossum548703a1998-03-26 22:14:20 +0000121 l_flags = 0
122 if 'n' in which: l_flags = l_flags | FCNTL.O_NDELAY
123 if 'a' in which: l_flags = l_flags | FCNTL.O_APPEND
124 if 's' in which: l_flags = l_flags | FCNTL.O_SYNC
Guido van Rossum5c971671996-07-22 15:23:25 +0000125
Guido van Rossum548703a1998-03-26 22:14:20 +0000126 file = self._file_
Guido van Rossum5c971671996-07-22 15:23:25 +0000127
Guido van Rossum548703a1998-03-26 22:14:20 +0000128 if '=' not in which:
129 cur_fl = fcntl.fcntl(file.fileno(), FCNTL.F_GETFL, 0)
130 if '!' in which: l_flags = cur_fl & ~ l_flags
131 else: l_flags = cur_fl | l_flags
Guido van Rossum5c971671996-07-22 15:23:25 +0000132
Guido van Rossum548703a1998-03-26 22:14:20 +0000133 l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFL, l_flags)
Guido van Rossum5c971671996-07-22 15:23:25 +0000134
Guido van Rossum548703a1998-03-26 22:14:20 +0000135 if 'c' in which:
136 arg = ('!' not in which) # 0 is don't, 1 is do close on exec
137 l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_SETFD, arg)
Guido van Rossum5c971671996-07-22 15:23:25 +0000138
Guido van Rossum548703a1998-03-26 22:14:20 +0000139 if '?' in which:
140 which = '' # Return current flags
141 l_flags = fcntl.fcntl(file.fileno(), FCNTL.F_GETFL, 0)
142 if FCNTL.O_APPEND & l_flags: which = which + 'a'
143 if fcntl.fcntl(file.fileno(), FCNTL.F_GETFD, 0) & 1:
144 which = which + 'c'
145 if FCNTL.O_NDELAY & l_flags: which = which + 'n'
146 if FCNTL.O_SYNC & l_flags: which = which + 's'
147 return which
148
Guido van Rossum5c971671996-07-22 15:23:25 +0000149 def lock(self, how, *args):
Guido van Rossum548703a1998-03-26 22:14:20 +0000150 import struct, fcntl, FCNTL
Guido van Rossum5c971671996-07-22 15:23:25 +0000151
Guido van Rossum548703a1998-03-26 22:14:20 +0000152 if 'w' in how: l_type = FCNTL.F_WRLCK
153 elif 'r' in how: l_type = FCNTL.F_RDLCK
154 elif 'u' in how: l_type = FCNTL.F_UNLCK
155 else: raise TypeError, 'no type of lock specified'
Guido van Rossum5c971671996-07-22 15:23:25 +0000156
Guido van Rossum548703a1998-03-26 22:14:20 +0000157 if '|' in how: cmd = FCNTL.F_SETLKW
158 elif '?' in how: cmd = FCNTL.F_GETLK
159 else: cmd = FCNTL.F_SETLK
Guido van Rossum5c971671996-07-22 15:23:25 +0000160
Guido van Rossum548703a1998-03-26 22:14:20 +0000161 l_whence = 0
162 l_start = 0
163 l_len = 0
Guido van Rossum5c971671996-07-22 15:23:25 +0000164
Guido van Rossum548703a1998-03-26 22:14:20 +0000165 if len(args) == 1:
166 l_len = args[0]
167 elif len(args) == 2:
168 l_len, l_start = args
169 elif len(args) == 3:
170 l_len, l_start, l_whence = args
171 elif len(args) > 3:
172 raise TypeError, 'too many arguments'
Guido van Rossum5c971671996-07-22 15:23:25 +0000173
Guido van Rossum548703a1998-03-26 22:14:20 +0000174 # Hack by davem@magnet.com to get locking to go on freebsd;
175 # additions for AIX by Vladimir.Marangozov@imag.fr
Guido van Rossum3bb710d1996-07-30 16:35:26 +0000176 import sys, os
Guido van Rossum9a744a91999-04-08 20:27:54 +0000177 if sys.platform in ('netbsd1',
Guido van Rossumaad67612000-05-08 17:31:04 +0000178 'openbsd2',
Guido van Rossum9a744a91999-04-08 20:27:54 +0000179 'freebsd2', 'freebsd3',
180 'bsdos2', 'bsdos3', 'bsdos4'):
Guido van Rossum548703a1998-03-26 22:14:20 +0000181 flock = struct.pack('lxxxxlxxxxlhh', \
182 l_start, l_len, os.getpid(), l_type, l_whence)
Guido van Rossuma8763e51996-08-26 18:33:32 +0000183 elif sys.platform in ['aix3', 'aix4']:
184 flock = struct.pack('hhlllii', \
185 l_type, l_whence, l_start, l_len, 0, 0, 0)
Guido van Rossum548703a1998-03-26 22:14:20 +0000186 else:
187 flock = struct.pack('hhllhh', \
188 l_type, l_whence, l_start, l_len, 0, 0)
Guido van Rossum3bb710d1996-07-30 16:35:26 +0000189
Guido van Rossum548703a1998-03-26 22:14:20 +0000190 flock = fcntl.fcntl(self._file_.fileno(), cmd, flock)
Guido van Rossum5c971671996-07-22 15:23:25 +0000191
Guido van Rossum548703a1998-03-26 22:14:20 +0000192 if '?' in how:
Guido van Rossum9a744a91999-04-08 20:27:54 +0000193 if sys.platform in ('netbsd1',
Guido van Rossumaad67612000-05-08 17:31:04 +0000194 'openbsd2',
Guido van Rossum9a744a91999-04-08 20:27:54 +0000195 'freebsd2', 'freebsd3',
196 'bsdos2', 'bsdos3', 'bsdos4'):
Guido van Rossum548703a1998-03-26 22:14:20 +0000197 l_start, l_len, l_pid, l_type, l_whence = \
198 struct.unpack('lxxxxlxxxxlhh', flock)
Guido van Rossuma8763e51996-08-26 18:33:32 +0000199 elif sys.platform in ['aix3', 'aix4']:
200 l_type, l_whence, l_start, l_len, l_sysid, l_pid, l_vfs = \
201 struct.unpack('hhlllii', flock)
Guido van Rossum548703a1998-03-26 22:14:20 +0000202 elif sys.platform == "linux2":
203 l_type, l_whence, l_start, l_len, l_pid, l_sysid = \
204 struct.unpack('hhllhh', flock)
205 else:
206 l_type, l_whence, l_start, l_len, l_sysid, l_pid = \
207 struct.unpack('hhllhh', flock)
Guido van Rossum3bb710d1996-07-30 16:35:26 +0000208
Guido van Rossum548703a1998-03-26 22:14:20 +0000209 if l_type != FCNTL.F_UNLCK:
210 if l_type == FCNTL.F_RDLCK:
211 return 'r', l_len, l_start, l_whence, l_pid
212 else:
213 return 'w', l_len, l_start, l_whence, l_pid
Guido van Rossum5c971671996-07-22 15:23:25 +0000214
Guido van Rossum5c971671996-07-22 15:23:25 +0000215def open(name, mode='r', bufsize=-1):
Guido van Rossumaad67612000-05-08 17:31:04 +0000216 """Public routine to open a file as a posixfile object."""
Guido van Rossum5c971671996-07-22 15:23:25 +0000217 return _posixfile_().open(name, mode, bufsize)
218
219def fileopen(file):
Guido van Rossumaad67612000-05-08 17:31:04 +0000220 """Public routine to get a posixfile object from a Python file object."""
Guido van Rossum5c971671996-07-22 15:23:25 +0000221 return _posixfile_().fileopen(file)
222
223#
224# Constants
225#
226SEEK_SET = 0
227SEEK_CUR = 1
228SEEK_END = 2
229
230#
231# End of posixfile.py
232#