Windows: remove trailing whitespace
[openafs.git] / src / WINNT / afsd / rawops.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <roken.h>
13
14 #include <osi.h>
15 #include "afsd.h"
16
17 #define CM_BUF_SIZE             4096
18 long buf_bufferSize = CM_BUF_SIZE;
19
20 long ReadData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
21               cm_user_t *userp, long *readp)
22 {
23     //osi_hyper_t offset;
24     long code;
25     cm_buf_t *bufferp;
26     osi_hyper_t fileLength;
27     osi_hyper_t thyper;
28     osi_hyper_t lastByte;
29     osi_hyper_t bufferOffset;
30     long bufIndex, nbytes;
31     int sequential = 0;
32     cm_req_t req;
33
34     cm_InitReq(&req);
35
36     bufferp = NULL;
37
38     lock_ObtainWrite(&scp->rw);
39
40     /* start by looking up the file's end */
41     code = cm_SyncOp(scp, NULL, userp, &req, 0,
42                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
43     if (code)
44         goto done;
45
46     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
47
48     /* now we have the entry locked, look up the length */
49     fileLength = scp->length;
50
51     /* adjust count down so that it won't go past EOF */
52     thyper.LowPart = count;
53     thyper.HighPart = 0;
54     thyper = LargeIntegerAdd(offset, thyper);   /* where read should end */
55     lastByte = thyper;
56     if (LargeIntegerGreaterThan(thyper, fileLength)) {
57         /* we'd read past EOF, so just stop at fileLength bytes.
58         * Start by computing how many bytes remain in the file.
59         */
60         thyper = LargeIntegerSubtract(fileLength, offset);
61
62         /* if we are past EOF, read 0 bytes */
63         if (LargeIntegerLessThanZero(thyper))
64             count = 0;
65         else
66             count = thyper.LowPart;
67     }
68
69     *readp = count;
70
71     /* now, copy the data one buffer at a time,
72      * until we've filled the request packet
73      */
74     while (1) {
75         /* if we've copied all the data requested, we're done */
76         if (count <= 0) break;
77
78         /* otherwise, load up a buffer of data */
79         thyper.HighPart = offset.HighPart;
80         thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
81         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
82             /* wrong buffer */
83             if (bufferp) {
84                 buf_Release(bufferp);
85                 bufferp = NULL;
86             }
87             lock_ReleaseWrite(&scp->rw);
88
89             code = buf_Get(scp, &thyper, &req, &bufferp);
90
91             lock_ObtainWrite(&scp->rw);
92             if (code) goto done;
93             bufferOffset = thyper;
94
95             /* now get the data in the cache */
96             while (1) {
97                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
98                                   CM_SCACHESYNC_NEEDCALLBACK
99                                   | CM_SCACHESYNC_READ);
100                 if (code)
101                     goto done;
102
103                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
104
105                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
106
107                 /* otherwise, load the buffer and try again */
108                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
109                 if (code) break;
110             }
111             if (code) {
112                 buf_Release(bufferp);
113                 bufferp = NULL;
114                 goto done;
115             }
116         }       /* if (wrong buffer) ... */
117
118         /* now we have the right buffer loaded.  Copy out the
119          * data from here to the user's buffer.
120          */
121         bufIndex = offset.LowPart & (buf_bufferSize - 1);
122
123         /* and figure out how many bytes we want from this buffer */
124         nbytes = buf_bufferSize - bufIndex;     /* what remains in buffer */
125         if (nbytes > count) nbytes = count;     /* don't go past EOF */
126
127         /* now copy the data */
128         memcpy(op, bufferp->datap + bufIndex, nbytes);
129
130         /* adjust counters, pointers, etc. */
131         op += nbytes;
132         count -= nbytes;
133         thyper.LowPart = nbytes;
134         thyper.HighPart = 0;
135         offset = LargeIntegerAdd(thyper, offset);
136     } /* while 1 */
137
138   done:
139     lock_ReleaseWrite(&scp->rw);
140     //lock_ReleaseMutex(&fidp->mx);
141     if (bufferp)
142         buf_Release(bufferp);
143
144     if (code == 0 && sequential)
145         cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
146
147     return code;
148 }
149
150
151 long WriteData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
152                cm_user_t *userp, long *writtenp)
153 {
154     long code = 0;
155     long written = 0;
156     osi_hyper_t fileLength;     /* file's length at start of write */
157     osi_hyper_t minLength;      /* don't read past this */
158     afs_uint32 nbytes;          /* # of bytes to transfer this iteration */
159     cm_buf_t *bufferp;
160     osi_hyper_t thyper;         /* hyper tmp variable */
161     osi_hyper_t bufferOffset;
162     afs_uint32 bufIndex;        /* index in buffer where our data is */
163     int doWriteBack;
164     osi_hyper_t writeBackOffset;/* offset of region to write back when
165     * I/O is done */
166     DWORD filter = 0;
167     cm_req_t req;
168
169     cm_InitReq(&req);
170
171     bufferp = NULL;
172     doWriteBack = 0;
173
174     lock_ObtainWrite(&scp->rw);
175
176     /* start by looking up the file's end */
177     code = cm_SyncOp(scp, NULL, userp, &req, 0,
178                      CM_SCACHESYNC_NEEDCALLBACK
179                       | CM_SCACHESYNC_SETSTATUS
180                       | CM_SCACHESYNC_GETSTATUS);
181     if (code)
182         goto done;
183
184     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
185
186 #if 0
187     /* make sure we have a writable FD */
188     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
189     code = CM_ERROR_BADFDOP;
190     goto done;
191     }
192 #endif
193
194     /* now we have the entry locked, look up the length */
195     fileLength = scp->length;
196     minLength = fileLength;
197     if (LargeIntegerGreaterThan(minLength, scp->serverLength))
198         minLength = scp->serverLength;
199
200     /* adjust file length if we extend past EOF */
201     thyper.LowPart = count;
202     thyper.HighPart = 0;
203     thyper = LargeIntegerAdd(offset, thyper);   /* where write should end */
204     if (LargeIntegerGreaterThan(thyper, fileLength)) {
205         /* we'd write past EOF, so extend the file */
206         scp->mask |= CM_SCACHEMASK_LENGTH;
207         scp->length = thyper;
208         filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
209     } else
210         filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
211
212     /* now, if the new position (thyper) and the old (offset) are in
213      * different storeback windows, remember to store back the previous
214      * storeback window when we're done with the write.
215      */
216     if ((thyper.LowPart & (-cm_chunkSize)) !=
217          (offset.LowPart & (-cm_chunkSize))) {
218         /* they're different */
219         doWriteBack = 1;
220         writeBackOffset.HighPart = offset.HighPart;
221         writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
222     }
223
224     *writtenp = count;
225
226     /* now, copy the data one buffer at a time, until we've filled the
227      * request packet */
228     while (1) {
229         /* if we've copied all the data requested, we're done */
230         if (count <= 0) break;
231
232         /* handle over quota or out of space */
233         if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
234             *writtenp = written;
235             break;
236         }
237
238         /* otherwise, load up a buffer of data */
239         thyper.HighPart = offset.HighPart;
240         thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
241         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
242             /* wrong buffer */
243             if (bufferp) {
244                 lock_ReleaseMutex(&bufferp->mx);
245                 buf_Release(bufferp);
246                 bufferp = NULL;
247             }
248             lock_ReleaseWrite(&scp->rw);
249
250             code = buf_Get(scp, &thyper, &req, &bufferp);
251
252             lock_ObtainMutex(&bufferp->mx);
253             lock_ObtainWrite(&scp->rw);
254             if (code)
255                 goto done;
256
257             bufferOffset = thyper;
258
259             /* now get the data in the cache */
260             while (1) {
261                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
262                                   CM_SCACHESYNC_NEEDCALLBACK
263                                   | CM_SCACHESYNC_WRITE
264                                   | CM_SCACHESYNC_BUFLOCKED);
265                 if (code)
266                     goto done;
267
268                 cm_SyncOpDone(scp, bufferp,
269                                CM_SCACHESYNC_NEEDCALLBACK
270                                | CM_SCACHESYNC_WRITE
271                                | CM_SCACHESYNC_BUFLOCKED);
272
273                 /* If we're overwriting the entire buffer, or
274                  * if we're writing at or past EOF, mark the
275                  * buffer as current so we don't call
276                  * cm_GetBuffer.  This skips the fetch from the
277                  * server in those cases where we're going to
278                  * obliterate all the data in the buffer anyway,
279                  * or in those cases where there is no useful
280                  * data at the server to start with.
281                  *
282                  * Use minLength instead of scp->length, since
283                  * the latter has already been updated by this
284                  * call.
285                  */
286                 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength) ||
287                      LargeIntegerEqualTo(offset, bufferp->offset) &&
288                      (count >= buf_bufferSize ||
289                        LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset, ConvertLongToLargeInteger(count)), minLength))) {
290                     if (count < buf_bufferSize
291                          && bufferp->dataVersion == CM_BUF_VERSION_BAD)
292                         memset(bufferp->datap, 0,
293                                 buf_bufferSize);
294                     bufferp->dataVersion = scp->dataVersion;
295                 }
296
297                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
298
299                 /* otherwise, load the buffer and try again */
300                 lock_ReleaseMutex(&bufferp->mx);
301                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
302                                      &req);
303                 lock_ReleaseWrite(&scp->rw);
304                 lock_ObtainMutex(&bufferp->mx);
305                 lock_ObtainWrite(&scp->rw);
306                 if (code)
307                     break;
308             }
309             if (code) {
310                 lock_ReleaseMutex(&bufferp->mx);
311                 buf_Release(bufferp);
312                 bufferp = NULL;
313                 goto done;
314             }
315         }       /* if (wrong buffer) ... */
316
317         /* now we have the right buffer loaded.  Copy out the
318          * data from here to the user's buffer.
319          */
320         bufIndex = offset.LowPart & (buf_bufferSize - 1);
321
322         /* and figure out how many bytes we want from this buffer */
323         nbytes = buf_bufferSize - bufIndex;     /* what remains in buffer */
324         if (nbytes > count)
325             nbytes = count;     /* don't go past end of request */
326
327         /* now copy the data */
328         memcpy(bufferp->datap + bufIndex, op, nbytes);
329         buf_SetDirty(bufferp, bufIndex, nbytes, userp);
330
331         /* adjust counters, pointers, etc. */
332         op += nbytes;
333         count -= nbytes;
334         written += nbytes;
335         thyper.LowPart = nbytes;
336         thyper.HighPart = 0;
337         offset = LargeIntegerAdd(thyper, offset);
338     } /* while 1 */
339
340   done:
341     lock_ReleaseWrite(&scp->rw);
342     if (bufferp) {
343         lock_ReleaseMutex(&bufferp->mx);
344         buf_Release(bufferp);
345     }
346
347     if (code == 0 && doWriteBack) {
348         lock_ObtainWrite(&scp->rw);
349         code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
350         lock_ReleaseWrite(&scp->rw);
351         if (code == 0)
352             cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
353                                writeBackOffset.HighPart, cm_chunkSize, 0, userp);
354     }
355
356     /* cm_SyncOpDone is called when cm_BkgStore completes */
357     return code;
358 }
359
360