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
|
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
include <knet.h>
include <mach.h>
include "fmio.h"
# FM_LFBINWRITE -- Asynchronous blocked binary write to an lfile. We deal
# only with binary data here; unpacking of text must be done at a higher
# level. The basic procedure is to convert the indicated lfile segment into
# a range of lfile pages, then use the pagemap for the lfile to map these onto
# physical datafile pages. I/O is done in chunks of contiguous pages until
# the requested amount of data has been transferred. When writing at or
# beyond EOF, new pages are automatically allocated upon demand.
procedure fm_lfbinwrite (lf, buf, nbytes, offset)
pointer lf #I lfile descriptor
char buf[ARB] #I input data buffer
int nbytes #I nbytes to write
long offset #I lfile offset
pointer fm, pm
int status, chan, nleft, szbpage
int lfile, l1,l2, p1,p2, d1,d2, ip, nb, nt
int fmio_extend()
begin
fm = LF_FM(lf)
pm = LF_PAGEMAP(lf)
# Verify descriptor.
if (fm == NULL || pm == NULL) {
LF_STATUS(lf) = ERR
return
} else
LF_STATUS(lf) = 0
chan = FM_CHAN(fm)
szbpage = FM_SZBPAGE(fm)
lfile = (lf - FM_FTABLE(fm)) / LEN_FTE
nleft = nbytes
# Extend the pagemap?
while (offset + nbytes > LF_NPAGES(lf)*szbpage + 1)
if (fmio_extend (fm, lfile, 1) == ERR) {
LF_STATUS(lf) = ERR
return
} else
pm = LF_PAGEMAP(lf)
# Map lfile offset,nbytes into a range of lfile pages.
# I/O transfers are required to be aligned on page boundaries.
l1 = (offset - 1) / szbpage + 1
l2 = l1 + ((nleft + szbpage-1) / szbpage) - 1
# Write the data from the user buffer to the physical datafile,
# mapping lfile pages to physical offsets and moving data in chunks
# of as many contiguous pages as possible.
ip = 1
for (p1=l1; nleft > 0 && p1 <= l2; p1=p2) {
# Get a contiguous range of datafile pages.
d1 = Memi[pm+p1-1]
for (p2=p1+1; p2 <= l2; p2=p2+1) {
d2 = Memi[pm+p2-1]
if (d2 - d1 != p2 - p1)
break
}
# Compute the logical transfer size NB, and the amount of data
# to be physically written NT. The latter is always an integral
# number of datafile pages in size. NOTE that this requires that
# the user buffer be an integral multiple of the page size, to
# prevent referencing off the end of the buffer.
nb = min (nleft, (p2 - p1) * szbpage)
nt = (nb + szbpage-1) / szbpage * szbpage
LF_LTSIZE(lf) = nb
# Write the file segment.
call zawrbf (chan, buf[ip], nt, (d1-1)*szbpage + FM_DATASTART(fm))
LF_FLAGS(lf) = or (LF_FLAGS(lf), LFF_IOINPROGRESS)
# Bump the i/o counters.
ip = ip + nb / SZB_CHAR
nleft = nleft - nb
# If we didn't write all the data, wait until the write completes.
if (nleft > 0) {
call zawtbf (chan, status)
LF_FLAGS(lf) = and (LF_FLAGS(lf), not(LFF_IOINPROGRESS))
if (status == ERR) {
LF_STATUS(lf) = ERR
return
} else if (status == 0) {
break
} else
LF_STATUS(lf) = LF_STATUS(lf) + min(LF_LTSIZE(lf),status)
}
}
# Update the lfile size counter.
nb = offset + nbytes - 1
if (nb > LF_FSIZE(lf)) {
LF_FSIZE(lf) = nb
FM_DHMODIFIED(fm) = YES
}
end
|