summaryrefslogtreecommitdiffstats
path: root/Lib/posixfile.py
blob: 64cda986223f373a1cc10d43c712e67dd1ef55ec (plain)
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
#
# Start of posixfile.py
#

#
# Extended file operations
#
# 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
#

class _posixfile_:
    states = ['open', 'closed']

    #
    # Internal routines
    #
    def __repr__(self):
	file = self._file_
	return "<%s posixfile '%s', mode '%s' at %s>" % \
		(self.states[file.closed], file.name, file.mode, \
		 hex(id(self))[2:])

    def __del__(self):
	self._file_.close()

    #
    # Initialization routines
    #
    def open(self, name, mode='r', bufsize=-1):
	import __builtin__
	return self.fileopen(__builtin__.open(name, mode, bufsize))

    def fileopen(self, file):
	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

    #
    # New methods
    #
    def file(self):
	return self._file_

    def dup(self):
	import posix

	try: ignore = posix.fdopen
	except: raise AttributeError, 'dup() method unavailable'

	return posix.fdopen(posix.dup(self._file_.fileno()), self._file_.mode)

    def dup2(self, fd):
	import posix

	try: ignore = posix.fdopen
	except: raise AttributeError, 'dup() method unavailable'

	posix.dup2(self._file_.fileno(), fd)
	return posix.fdopen(fd, self._file_.mode)

    def flags(self, *which):
	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)

	if 'c' in which:	
	    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
	
    def lock(self, how, *args):
	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
        import sys, os
        if sys.platform == 'freebsd2':
	    flock = struct.pack('lxxxxlxxxxlhh', \
		  l_start, l_len, os.getpid(), l_type, l_whence) 
	else:
	    flock = struct.pack('hhllhh', \
		  l_type, l_whence, l_start, l_len, 0, 0)

	flock = fcntl.fcntl(self._file_.fileno(), cmd, flock)

	if '?' in how:
	    if sys.platform == 'freebsd2':
		l_start, l_len, l_pid, l_type, l_whence = \
		    struct.unpack('lxxxxlxxxxlhh', 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

#
# Public routine to obtain a posixfile object
#
def open(name, mode='r', bufsize=-1):
    return _posixfile_().open(name, mode, bufsize)

def fileopen(file):
    return _posixfile_().fileopen(file)

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

#
# End of posixfile.py
#