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