]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/python/posixfile.py
/sys/lib/dist/mkfile: test for .git directory
[plan9front.git] / sys / lib / python / posixfile.py
1 """Extended file operations available in POSIX.
2
3 f = posixfile.open(filename, [mode, [bufsize]])
4       will create a new posixfile object
5
6 f = posixfile.fileopen(fileobject)
7       will create a posixfile object from a builtin file object
8
9 f.file()
10       will return the original builtin file object
11
12 f.dup()
13       will return a new file object based on a new filedescriptor
14
15 f.dup2(fd)
16       will return a new file object based on the given filedescriptor
17
18 f.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
37 f.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 """
55
56
57 class _posixfile_:
58     """File wrapper class that provides extra POSIX file routines."""
59
60     states = ['open', 'closed']
61
62     #
63     # Internal routines
64     #
65     def __repr__(self):
66         file = self._file_
67         return "<%s posixfile '%s', mode '%s' at %s>" % \
68                 (self.states[file.closed], file.name, file.mode, \
69                  hex(id(self))[2:])
70
71     #
72     # Initialization routines
73     #
74     def open(self, name, mode='r', bufsize=-1):
75         import __builtin__
76         return self.fileopen(__builtin__.open(name, mode, bufsize))
77
78     def fileopen(self, file):
79         import types
80         if repr(type(file)) != "<type 'file'>":
81             raise TypeError, 'posixfile.fileopen() arg must be file object'
82         self._file_  = file
83         # Copy basic file methods
84         for maybemethod in dir(file):
85             if not maybemethod.startswith('_'):
86                 attr = getattr(file, maybemethod)
87                 if isinstance(attr, types.BuiltinMethodType):
88                     setattr(self, maybemethod, attr)
89         return self
90
91     #
92     # New methods
93     #
94     def file(self):
95         return self._file_
96
97     def dup(self):
98         import posix
99
100         if not hasattr(posix, 'fdopen'):
101             raise AttributeError, 'dup() method unavailable'
102
103         return posix.fdopen(posix.dup(self._file_.fileno()), self._file_.mode)
104
105     def dup2(self, fd):
106         import posix
107
108         if not hasattr(posix, 'fdopen'):
109             raise AttributeError, 'dup() method unavailable'
110
111         posix.dup2(self._file_.fileno(), fd)
112         return posix.fdopen(fd, self._file_.mode)
113
114     def flags(self, *which):
115         import fcntl, os
116
117         if which:
118             if len(which) > 1:
119                 raise TypeError, 'Too many arguments'
120             which = which[0]
121         else: which = '?'
122
123         l_flags = 0
124         if 'n' in which: l_flags = l_flags | os.O_NDELAY
125         if 'a' in which: l_flags = l_flags | os.O_APPEND
126         if 's' in which: l_flags = l_flags | os.O_SYNC
127
128         file = self._file_
129
130         if '=' not in which:
131             cur_fl = fcntl.fcntl(file.fileno(), fcntl.F_GETFL, 0)
132             if '!' in which: l_flags = cur_fl & ~ l_flags
133             else: l_flags = cur_fl | l_flags
134
135         l_flags = fcntl.fcntl(file.fileno(), fcntl.F_SETFL, l_flags)
136
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         if '?' in which:
142             which = ''                  # Return current flags
143             l_flags = fcntl.fcntl(file.fileno(), fcntl.F_GETFL, 0)
144             if os.O_APPEND & l_flags: which = which + 'a'
145             if fcntl.fcntl(file.fileno(), fcntl.F_GETFD, 0) & 1:
146                 which = which + 'c'
147             if os.O_NDELAY & l_flags: which = which + 'n'
148             if os.O_SYNC & l_flags: which = which + 's'
149             return which
150
151     def lock(self, how, *args):
152         import struct, fcntl
153
154         if 'w' in how: l_type = fcntl.F_WRLCK
155         elif 'r' in how: l_type = fcntl.F_RDLCK
156         elif 'u' in how: l_type = fcntl.F_UNLCK
157         else: raise TypeError, 'no type of lock specified'
158
159         if '|' in how: cmd = fcntl.F_SETLKW
160         elif '?' in how: cmd = fcntl.F_GETLK
161         else: cmd = fcntl.F_SETLK
162
163         l_whence = 0
164         l_start = 0
165         l_len = 0
166
167         if len(args) == 1:
168             l_len = args[0]
169         elif len(args) == 2:
170             l_len, l_start = args
171         elif len(args) == 3:
172             l_len, l_start, l_whence = args
173         elif len(args) > 3:
174             raise TypeError, 'too many arguments'
175
176         # Hack by davem@magnet.com to get locking to go on freebsd;
177         # 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                             'freebsd6', 'freebsd7',
183                             'bsdos2', 'bsdos3', 'bsdos4'):
184             flock = struct.pack('lxxxxlxxxxlhh', \
185                   l_start, l_len, os.getpid(), l_type, l_whence)
186         elif sys.platform in ('aix3', 'aix4'):
187             flock = struct.pack('hhlllii', \
188                   l_type, l_whence, l_start, l_len, 0, 0, 0)
189         else:
190             flock = struct.pack('hhllhh', \
191                   l_type, l_whence, l_start, l_len, 0, 0)
192
193         flock = fcntl.fcntl(self._file_.fileno(), cmd, flock)
194
195         if '?' in how:
196             if sys.platform in ('netbsd1',
197                                 'openbsd2',
198                                 'freebsd2', 'freebsd3', 'freebsd4', 'freebsd5',
199                                 'bsdos2', 'bsdos3', 'bsdos4'):
200                 l_start, l_len, l_pid, l_type, l_whence = \
201                     struct.unpack('lxxxxlxxxxlhh', flock)
202             elif sys.platform in ('aix3', 'aix4'):
203                 l_type, l_whence, l_start, l_len, l_sysid, l_pid, l_vfs = \
204                     struct.unpack('hhlllii', flock)
205             elif sys.platform == "linux2":
206                 l_type, l_whence, l_start, l_len, l_pid, l_sysid = \
207                     struct.unpack('hhllhh', flock)
208             else:
209                 l_type, l_whence, l_start, l_len, l_sysid, l_pid = \
210                     struct.unpack('hhllhh', flock)
211
212             if l_type != fcntl.F_UNLCK:
213                 if l_type == fcntl.F_RDLCK:
214                     return 'r', l_len, l_start, l_whence, l_pid
215                 else:
216                     return 'w', l_len, l_start, l_whence, l_pid
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)
221
222 def fileopen(file):
223     """Public routine to get a posixfile object from a Python file object."""
224     return _posixfile_().fileopen(file)
225
226 #
227 # Constants
228 #
229 SEEK_SET = 0
230 SEEK_CUR = 1
231 SEEK_END = 2
232
233 #
234 # End of posixfile.py
235 #