Windows: improved idle dead time handling
[openafs.git] / src / WINNT / afsrdr / user / RDRFunction.c
1 /*
2  * Copyright (c) 2008 Secure Endpoints, Inc.
3  * Copyright (c) 2009-2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * - Redistributions of source code must retain the above copyright notice,
10  *   this list of conditions and the following disclaimer.
11  * - Redistributions in binary form must reproduce the above copyright notice,
12  *   this list of conditions and the following disclaimer in the documentation
13  *   and/or other materials provided with the distribution.
14  * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
15  *   may be used to endorse or promote products derived from this software without
16  *   specific prior written permission from Secure Endpoints, Inc. and
17  *   Your File System, Inc.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
23  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <afsconfig.h>
33 #include <afs/param.h>
34
35 #ifndef _WIN32_WINNT
36 #define _WIN32_WINNT 0x0500
37 #endif
38 #define _CRT_SECURE_NO_DEPRECATE
39 #define _CRT_NON_CONFORMING_SWPRINTFS
40 #define INITGUID        /* define AFS_AUTH_GUID_NO_PAG */
41
42 #include <ntstatus.h>
43 #define WIN32_NO_STATUS
44 #include <windows.h>
45
46 #include <roken.h>
47
48 #include <afs/stds.h>
49
50 #include <ntsecapi.h>
51 #include <sddl.h>
52 #pragma warning(push)
53 #pragma warning(disable: 4005)
54
55 #include <devioctl.h>
56
57 #include "..\\Common\\AFSUserDefines.h"
58 #include "..\\Common\\AFSUserStructs.h"
59
60 #pragma warning(pop)
61
62 #include <tchar.h>
63 #include <wchar.h>
64 #include <winbase.h>
65 #include <winreg.h>
66
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <stdarg.h>
70 #include <strsafe.h>
71
72 #include "afsd.h"
73 #include "smb.h"
74 #include "cm_btree.h"
75 #include "msrpc.h"
76 #include <RDRPrototypes.h>
77 #include <RDRIoctl.h>
78 #include <RDRPipe.h>
79
80 static CHAR * RDR_extentBaseAddress = NULL;
81
82 void
83 RDR_InitReq(cm_req_t *reqp)
84 {
85     cm_InitReq(reqp);
86     reqp->flags |= CM_REQ_SOURCE_REDIR;
87 }
88
89 void
90 RDR_fid2FID( cm_fid_t *fid, AFSFileID *FileId)
91 {
92     FileId->Cell = fid->cell;
93     FileId->Volume = fid->volume;
94     FileId->Vnode = fid->vnode;
95     FileId->Unique = fid->unique;
96     FileId->Hash = fid->hash;
97 }
98
99 void
100 RDR_FID2fid( AFSFileID *FileId, cm_fid_t *fid)
101 {
102     fid->cell = FileId->Cell;
103     fid->volume = FileId->Volume;
104     fid->vnode = FileId->Vnode;
105     fid->unique = FileId->Unique;
106     fid->hash = FileId->Hash;
107 }
108
109 DWORD
110 RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRedirInitInfoLen )
111 {
112     extern char cm_CachePath[];
113     extern cm_config_data_t cm_data;
114     extern int smb_hideDotFiles;
115     size_t cm_CachePathLen = strlen(cm_CachePath);
116     size_t err;
117     DWORD TempPathLen = ExpandEnvironmentStringsW(L"%TEMP%", NULL, 0);
118     MEMORYSTATUSEX memStatus;
119     DWORD maxMemoryCacheSize;
120
121 #if 0
122     /*
123      * For now disable the memory extent interface because there
124      * have been reports of data corruption.
125      */
126     memStatus.dwLength = sizeof(memStatus);
127     if (GlobalMemoryStatusEx(&memStatus)) {
128         /*
129          * Use the memory extent interface in the afs redirector
130          * whenever the cache size is less than equal to 10% of
131          * physical memory.  Do not use too much because this memory
132          * will be locked by the redirector so it can't be swapped
133          * out.
134          */
135         maxMemoryCacheSize = (DWORD)(memStatus.ullTotalPhys / 1024 / 10);
136     } else {
137         /*
138          * If we can't determine the amount of physical memory
139          * in the system, be conservative and limit the use of
140          * memory extent interface to 64MB data caches.
141          */
142         maxMemoryCacheSize = 65536;
143     }
144 #else
145     maxMemoryCacheSize = 0;
146 #endif
147
148     *pRedirInitInfoLen = (DWORD) (sizeof(AFSRedirectorInitInfo) + (cm_CachePathLen + TempPathLen) * sizeof(WCHAR));
149     *ppRedirInitInfo = (AFSRedirectorInitInfo *)malloc(*pRedirInitInfoLen);
150     (*ppRedirInitInfo)->Flags = smb_hideDotFiles ? AFS_REDIR_INIT_FLAG_HIDE_DOT_FILES : 0;
151     (*ppRedirInitInfo)->MaximumChunkLength = cm_data.chunkSize;
152     (*ppRedirInitInfo)->GlobalFileId.Cell   = cm_data.rootFid.cell;
153     (*ppRedirInitInfo)->GlobalFileId.Volume = cm_data.rootFid.volume;
154     (*ppRedirInitInfo)->GlobalFileId.Vnode  = cm_data.rootFid.vnode;
155     (*ppRedirInitInfo)->GlobalFileId.Unique = cm_data.rootFid.unique;
156     (*ppRedirInitInfo)->GlobalFileId.Hash   = cm_data.rootFid.hash;
157     (*ppRedirInitInfo)->ExtentCount.QuadPart = cm_data.buf_nbuffers;
158     (*ppRedirInitInfo)->CacheBlockSize = cm_data.blockSize;
159     (*ppRedirInitInfo)->MaxPathLinkCount = 512; /* this needs to become a registry value */
160     (*ppRedirInitInfo)->NameArrayLength = 32;   /* this needs to become a registry value */
161     if (cm_virtualCache || cm_data.bufferSize <= maxMemoryCacheSize) {
162         osi_Log0(afsd_logp, "RDR_SetInitParams Initializing Memory Extent Interface");
163         (*ppRedirInitInfo)->MemoryCacheOffset.QuadPart = (LONGLONG)cm_data.bufDataBaseAddress;
164         (*ppRedirInitInfo)->MemoryCacheLength.QuadPart = cm_data.bufEndOfData - cm_data.bufDataBaseAddress;
165         (*ppRedirInitInfo)->CacheFileNameLength = 0;
166         RDR_extentBaseAddress = cm_data.bufDataBaseAddress;
167     } else {
168         (*ppRedirInitInfo)->MemoryCacheOffset.QuadPart = 0;
169         (*ppRedirInitInfo)->MemoryCacheLength.QuadPart = 0;
170         (*ppRedirInitInfo)->CacheFileNameLength = (ULONG) (cm_CachePathLen * sizeof(WCHAR));
171         err = mbstowcs((*ppRedirInitInfo)->CacheFileName, cm_CachePath, (cm_CachePathLen + 1) *sizeof(WCHAR));
172         if (err == -1) {
173             free(*ppRedirInitInfo);
174             osi_Log0(afsd_logp, "RDR_SetInitParams Invalid Object Name");
175             return STATUS_OBJECT_NAME_INVALID;
176         }
177         RDR_extentBaseAddress = cm_data.baseAddress;
178     }
179     (*ppRedirInitInfo)->DumpFileLocationOffset = FIELD_OFFSET(AFSRedirectorInitInfo, CacheFileName) + (*ppRedirInitInfo)->CacheFileNameLength;
180     (*ppRedirInitInfo)->DumpFileLocationLength = (TempPathLen - 1) * sizeof(WCHAR);
181     ExpandEnvironmentStringsW(L"%TEMP%",
182                               (LPWSTR)(((PBYTE)(*ppRedirInitInfo)) + (*ppRedirInitInfo)->DumpFileLocationOffset),
183                               TempPathLen);
184
185     osi_Log0(afsd_logp,"RDR_SetInitParams Success");
186     return 0;
187 }
188
189 cm_user_t *
190 RDR_GetLocalSystemUser( void)
191 {
192     smb_username_t *unp;
193     cm_user_t *userp = NULL;
194     wchar_t cname[MAX_COMPUTERNAME_LENGTH+1];
195     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
196
197     GetComputerNameW(cname, &cnamelen);
198     _wcsupr(cname);
199
200     unp = smb_FindUserByName(NTSID_LOCAL_SYSTEM, cname, SMB_FLAG_CREATE);
201     lock_ObtainMutex(&unp->mx);
202     if (!unp->userp)
203         unp->userp = cm_NewUser();
204     unp->flags |= SMB_USERNAMEFLAG_SID;
205     lock_ReleaseMutex(&unp->mx);
206     userp = unp->userp;
207     cm_HoldUser(userp);
208     smb_ReleaseUsername(unp);
209
210     if (!userp) {
211         userp = cm_rootUserp;
212         cm_HoldUser(userp);
213     }
214
215     return userp;
216 }
217
218 cm_user_t *
219 RDR_UserFromCommRequest( IN AFSCommRequest *RequestBuffer)
220 {
221
222     return RDR_UserFromAuthGroup( &RequestBuffer->AuthGroup);
223 }
224
225 cm_user_t *
226 RDR_UserFromAuthGroup( IN GUID *pGuid)
227 {
228     smb_username_t *unp;
229     cm_user_t * userp = NULL;
230     RPC_WSTR UuidString = NULL;
231     wchar_t cname[MAX_COMPUTERNAME_LENGTH+1];
232     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
233
234     if (UuidToStringW((UUID *)pGuid, &UuidString) != RPC_S_OK)
235         goto done;
236
237     GetComputerNameW(cname, &cnamelen);
238     _wcsupr(cname);
239
240     unp = smb_FindUserByName(UuidString, cname, SMB_FLAG_CREATE);
241     lock_ObtainMutex(&unp->mx);
242     if (!unp->userp) {
243         unp->userp = cm_NewUser();
244         memcpy(&unp->userp->authgroup, pGuid, sizeof(GUID));
245     }
246     unp->flags |= SMB_USERNAMEFLAG_SID;
247     lock_ReleaseMutex(&unp->mx);
248     userp = unp->userp;
249     cm_HoldUser(userp);
250     smb_ReleaseUsername(unp);
251
252   done:
253     if (!userp) {
254         userp = cm_rootUserp;
255         cm_HoldUser(userp);
256     }
257
258     osi_Log2(afsd_logp, "RDR_UserFromCommRequest Guid %S userp = 0x%p",
259              osi_LogSaveStringW(afsd_logp, UuidString),
260              userp);
261
262     if (UuidString)
263         RpcStringFreeW(&UuidString);
264
265     return userp;
266 }
267
268 void
269 RDR_ReleaseUser( IN cm_user_t *userp )
270 {
271     osi_Log1(afsd_logp, "RDR_ReleaseUser userp = 0x%p", userp);
272     cm_ReleaseUser(userp);
273 }
274
275
276 /*
277  * RDR_FlagScpInUse flags the scp with CM_SCACHEFLAG_RDR_IN_USE
278  */
279 static void
280 RDR_FlagScpInUse( IN cm_scache_t *scp, IN BOOL bLocked )
281 {
282     if (!bLocked)
283         lock_ObtainWrite(&scp->rw);
284
285     lock_AssertWrite(&scp->rw);
286     scp->flags |= CM_SCACHEFLAG_RDR_IN_USE;
287
288     if (!bLocked)
289         lock_ReleaseWrite(&scp->rw);
290 }
291
292 /*
293  * Obtain the status information for the specified object using
294  * an inline bulk status rpc.  cm_BPlusDirEnumBulkStatOne() will
295  * obtain current status for the directory object, the object
296  * which is the focus of the inquiry and as many other objects
297  * in the directory for which there are not callbacks registered
298  * since we are likely to be asked for other objects in the directory.
299  */
300 static afs_uint32
301 RDR_BulkStatLookup( cm_scache_t *dscp,
302                     cm_scache_t *scp,
303                     cm_user_t   *userp,
304                     cm_req_t    *reqp)
305 {
306     cm_direnum_t *      enump = NULL;
307     afs_uint32  code = 0;
308     cm_dirOp_t    dirop;
309
310     code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
311     if (code == 0) {
312         code = cm_BPlusDirEnumerate(dscp, userp, reqp, TRUE, NULL, TRUE, &enump);
313         if (code) {
314             osi_Log1(afsd_logp, "RDR_BulkStatLookup cm_BPlusDirEnumerate failure code=0x%x",
315                       code);
316         }
317         cm_EndDirOp(&dirop);
318     } else {
319         osi_Log1(afsd_logp, "RDR_BulkStatLookup cm_BeginDirOp failure code=0x%x",
320                   code);
321     }
322
323     if (enump)
324     {
325         code = cm_BPlusDirEnumBulkStatOne(enump, scp);
326         if (code) {
327             osi_Log1(afsd_logp, "RDR_BulkStatLookup cm_BPlusDirEnumBulkStatOne failure code=0x%x",
328                       code);
329         }
330         cm_BPlusDirFreeEnumeration(enump);
331     }
332
333     return code;
334 }
335
336
337 #define RDR_POP_FOLLOW_MOUNTPOINTS 0x01
338 #define RDR_POP_EVALUATE_SYMLINKS  0x02
339 #define RDR_POP_WOW64              0x04
340 #define RDR_POP_NO_GETSTATUS       0x08
341
342 static afs_uint32
343 RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
344                           IN  DWORD             dwMaxEntryLength,
345                           IN  cm_scache_t     * dscp,
346                           IN  cm_scache_t     * scp,
347                           IN  cm_user_t       * userp,
348                           IN  cm_req_t        * reqp,
349                           IN  wchar_t         * name,
350                           IN  wchar_t         * shortName,
351                           IN  DWORD             dwFlags,
352                           IN  afs_uint32        cmError,
353                           OUT AFSDirEnumEntry **ppNextEntry,
354                           OUT DWORD           * pdwRemainingLength)
355 {
356     FILETIME ft;
357     WCHAR *  wname, *wtarget;
358     size_t   len;
359     DWORD      dwEntryLength;
360     afs_uint32 code = 0, code2 = 0;
361     BOOL          bMustFake = FALSE;
362
363     osi_Log5(afsd_logp, "RDR_PopulateCurrentEntry dscp=0x%p scp=0x%p name=%S short=%S flags=0x%x",
364              dscp, scp, osi_LogSaveStringW(afsd_logp, name),
365              osi_LogSaveStringW(afsd_logp, shortName), dwFlags);
366     osi_Log1(afsd_logp, "... maxLength=%d", dwMaxEntryLength);
367
368     if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
369         if (ppNextEntry)
370             *ppNextEntry = pCurrentEntry;
371         if (pdwRemainingLength)
372             *pdwRemainingLength = dwMaxEntryLength;
373         osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry Not Enough Room for Entry %d < %d",
374                  dwMaxEntryLength, sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t));
375         return CM_ERROR_TOOBIG;
376     }
377
378     if (!name)
379         name = L"";
380     if (!shortName)
381         shortName = L"";
382
383     dwEntryLength = sizeof(AFSDirEnumEntry);
384
385     lock_ObtainWrite(&scp->rw);
386     if (dwFlags & RDR_POP_NO_GETSTATUS) {
387         if (!cm_HaveCallback(scp))
388             bMustFake = TRUE;
389     } else {
390 #ifdef AFS_FREELANCE_CLIENT
391         if (scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
392             /*
393              * If the FID is from the Freelance Local Root always perform
394              * a single item status check.
395              */
396             code = cm_SyncOp( scp, NULL, userp, reqp, 0,
397                               CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
398             if (code) {
399                 lock_ReleaseWrite(&scp->rw);
400                 osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_SyncOp failed for scp=0x%p code=0x%x",
401                          scp, code);
402                 return code;
403             }
404         } else
405 #endif
406         {
407             /*
408              * For non-Freelance objects, check to see if we have current
409              * status information.  If not, perform a bulk status lookup of multiple
410              * entries in order to reduce the number of RPCs issued to the file server.
411              */
412             if ((scp->flags & CM_SCACHEFLAG_EACCESS))
413                 bMustFake = TRUE;
414             else if (!cm_HaveCallback(scp)) {
415                 lock_ReleaseWrite(&scp->rw);
416                 code = RDR_BulkStatLookup(dscp, scp, userp, reqp);
417                 if (code) {
418                     osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry RDR_BulkStatLookup failed for scp=0x%p code=0x%x",
419                              scp, code);
420                     return code;
421                 }
422                 lock_ObtainWrite(&scp->rw);
423                 /*
424                  * RDR_BulkStatLookup can succeed but it may be the case that there
425                  * still is not valid status info.  If we get this far, generate fake
426                  * status info.
427                  */
428                 if (!cm_HaveCallback(scp))
429                     bMustFake = TRUE;
430             }
431         }
432     }
433
434     /* Populate the error code */
435     smb_MapNTError(cmError, &pCurrentEntry->NTStatus, TRUE);
436
437     /* Populate the real or fake data */
438     pCurrentEntry->FileId.Cell = scp->fid.cell;
439     pCurrentEntry->FileId.Volume = scp->fid.volume;
440     pCurrentEntry->FileId.Vnode = scp->fid.vnode;
441     pCurrentEntry->FileId.Unique = scp->fid.unique;
442     pCurrentEntry->FileId.Hash = scp->fid.hash;
443
444     pCurrentEntry->FileType = scp->fileType;
445
446     pCurrentEntry->DataVersion.QuadPart = scp->dataVersion;
447
448     if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
449         scp->fid.volume==AFS_FAKE_ROOT_VOL_ID) {
450         cm_LargeSearchTimeFromUnixTime(&ft, MAX_AFS_UINT32);
451     } else {
452         cm_LargeSearchTimeFromUnixTime(&ft, scp->cbExpires);
453     }
454     pCurrentEntry->Expiration.LowPart = ft.dwLowDateTime;
455     pCurrentEntry->Expiration.HighPart = ft.dwHighDateTime;
456
457     if (bMustFake) {
458         /* 1969-12-31 23:59:59 +00 */
459         ft.dwHighDateTime = 0x19DB200;
460         ft.dwLowDateTime = 0x5BB78980;
461     } else
462         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
463     pCurrentEntry->CreationTime.LowPart = ft.dwLowDateTime;
464     pCurrentEntry->CreationTime.HighPart = ft.dwHighDateTime;
465     pCurrentEntry->LastAccessTime = pCurrentEntry->CreationTime;
466     pCurrentEntry->LastWriteTime = pCurrentEntry->CreationTime;
467     pCurrentEntry->ChangeTime = pCurrentEntry->CreationTime;
468
469     pCurrentEntry->EndOfFile = scp->length;
470     pCurrentEntry->AllocationSize = scp->length;
471
472     if (bMustFake) {
473         switch (scp->fileType) {
474         case CM_SCACHETYPE_DIRECTORY:
475             pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY;
476             break;
477         case CM_SCACHETYPE_MOUNTPOINT:
478         case CM_SCACHETYPE_INVALID:
479             pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY | SMB_ATTR_REPARSE_POINT;
480             break;
481         case CM_SCACHETYPE_SYMLINK:
482             if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
483                 pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY | SMB_ATTR_REPARSE_POINT;
484             else
485                 pCurrentEntry->FileAttributes = SMB_ATTR_REPARSE_POINT;
486             break;
487         default:
488             /* if we get here we either have a normal file
489             * or we have a file for which we have never
490             * received status info.  In this case, we can
491             * check the even/odd value of the entry's vnode.
492             * odd means it is to be treated as a directory
493             * and even means it is to be treated as a file.
494             */
495             if (scp->fid.vnode & 0x1)
496                 pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY;
497             else
498                 pCurrentEntry->FileAttributes = SMB_ATTR_NORMAL;
499         }
500     } else
501         pCurrentEntry->FileAttributes = smb_ExtAttributes(scp);
502     pCurrentEntry->EaSize = 0;
503     pCurrentEntry->Links = scp->linkCount;
504
505     len = wcslen(shortName);
506     wcsncpy(pCurrentEntry->ShortName, shortName, len);
507     pCurrentEntry->ShortNameLength = (CCHAR)(len * sizeof(WCHAR));
508
509     pCurrentEntry->FileNameOffset = sizeof(AFSDirEnumEntry);
510     len = wcslen(name);
511     wname = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->FileNameOffset);
512     wcsncpy(wname, name, len);
513     pCurrentEntry->FileNameLength = (ULONG)(sizeof(WCHAR) * len);
514
515     osi_Log3(afsd_logp, "RDR_PopulateCurrentEntry scp=0x%p fileType=%d dv=%u",
516               scp, scp->fileType, (afs_uint32)scp->dataVersion);
517
518     if (!(dwFlags & RDR_POP_NO_GETSTATUS))
519         cm_SyncOpDone( scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
520
521     if ((dwFlags & RDR_POP_NO_GETSTATUS) || !cm_HaveCallback(scp)) {
522         pCurrentEntry->TargetNameOffset = 0;
523         pCurrentEntry->TargetNameLength = 0;
524     }
525     else
526     switch (scp->fileType) {
527     case CM_SCACHETYPE_MOUNTPOINT:
528         if (dwFlags & RDR_POP_FOLLOW_MOUNTPOINTS) {
529             if ((code2 = cm_ReadMountPoint(scp, userp, reqp)) == 0) {
530                 cm_scache_t *targetScp = NULL;
531
532                 pCurrentEntry->TargetNameOffset = pCurrentEntry->FileNameOffset + pCurrentEntry->FileNameLength;
533                 len = strlen(scp->mountPointStringp);
534                 wtarget = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->TargetNameOffset);
535
536 #ifdef UNICODE
537                 cch = MultiByteToWideChar( CP_UTF8, 0, scp->mountPointStringp,
538                                            len * sizeof(char),
539                                            wtarget,
540                                            len * sizeof(WCHAR));
541 #else
542                 mbstowcs(wtarget, scp->mountPointStringp, len);
543 #endif
544                 pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
545
546                 code2 = cm_FollowMountPoint(scp, dscp, userp, reqp, &targetScp);
547
548                 if (code2 == 0) {
549                     pCurrentEntry->TargetFileId.Cell = targetScp->fid.cell;
550                     pCurrentEntry->TargetFileId.Volume = targetScp->fid.volume;
551                     pCurrentEntry->TargetFileId.Vnode = targetScp->fid.vnode;
552                     pCurrentEntry->TargetFileId.Unique = targetScp->fid.unique;
553                     pCurrentEntry->TargetFileId.Hash = targetScp->fid.hash;
554
555                     osi_Log4(afsd_logp, "RDR_PopulateCurrentEntry target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
556                               pCurrentEntry->TargetFileId.Cell, pCurrentEntry->TargetFileId.Volume,
557                               pCurrentEntry->TargetFileId.Vnode, pCurrentEntry->TargetFileId.Unique);
558
559                     cm_ReleaseSCache(targetScp);
560                 } else {
561                     osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_FollowMountPoint failed scp=0x%p code=0x%x",
562                               scp, code2);
563                 }
564             } else {
565                 osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_ReadMountPoint failed scp=0x%p code=0x%x",
566                           scp, code2);
567             }
568         }
569         break;
570     case CM_SCACHETYPE_SYMLINK:
571     case CM_SCACHETYPE_DFSLINK:
572         {
573             pCurrentEntry->TargetNameOffset = pCurrentEntry->FileNameOffset + pCurrentEntry->FileNameLength;
574             wtarget = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->TargetNameOffset);
575
576             if (dwFlags & RDR_POP_EVALUATE_SYMLINKS) {
577                 char * mp;
578
579                 code2 = cm_HandleLink(scp, userp, reqp);
580                 if (code2 == 0) {
581                     mp = scp->mountPointStringp;
582                     len = strlen(mp);
583                     if ( len != 0 ) {
584                         /* Strip off the msdfs: prefix from the target name for the file system */
585                         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
586                             osi_Log0(afsd_logp, "RDR_PopulateCurrentEntry DFSLink Detected");
587                             pCurrentEntry->FileType = scp->fileType;
588
589                             if (!strncmp("msdfs:", mp, 6)) {
590                                 mp += 6;
591                                 len -= 6;
592                             }
593                         }
594                         /* only send one slash to the redirector */
595                         if (mp[0] == '\\' && mp[1] == '\\') {
596                             mp++;
597                             len--;
598                         }
599 #ifdef UNICODE
600                         cch = MultiByteToWideChar( CP_UTF8, 0, mp,
601                                                    len * sizeof(char),
602                                                    wtarget,
603                                                    len * sizeof(WCHAR));
604 #else
605                         mbstowcs(wtarget, mp, len);
606 #endif
607                     }
608                     pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
609                 } else {
610                     osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_HandleLink failed scp=0x%p code=0x%x",
611                              scp, code2);
612                 }
613             }
614
615         }
616         break;
617
618     default:
619         pCurrentEntry->TargetNameOffset = 0;
620         pCurrentEntry->TargetNameLength = 0;
621     }
622     lock_ReleaseWrite(&scp->rw);
623
624     dwEntryLength += pCurrentEntry->FileNameLength + pCurrentEntry->TargetNameLength;
625     dwEntryLength += (dwEntryLength % 8) ? 8 - (dwEntryLength % 8) : 0;   /* quad align */
626     if (ppNextEntry)
627         *ppNextEntry = (AFSDirEnumEntry *)((PBYTE)pCurrentEntry + dwEntryLength);
628     if (pdwRemainingLength)
629         *pdwRemainingLength = dwMaxEntryLength - dwEntryLength;
630
631     osi_Log3(afsd_logp, "RDR_PopulateCurrentEntry Success FileNameLength=%d TargetNameLength=%d RemainingLength=%d",
632               pCurrentEntry->FileNameLength, pCurrentEntry->TargetNameLength, *pdwRemainingLength);
633
634     return code;
635 }
636
637 static afs_uint32
638 RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
639                                IN  DWORD             dwMaxEntryLength,
640                                IN  cm_scache_t     * dscp,
641                                IN  cm_fid_t        * fidp,
642                                IN  cm_user_t       * userp,
643                                IN  cm_req_t        * reqp,
644                                IN  wchar_t         * name,
645                                IN  wchar_t         * shortName,
646                                IN  DWORD             dwFlags,
647                                IN  afs_uint32        cmError,
648                                OUT AFSDirEnumEntry **ppNextEntry,
649                                OUT DWORD           * pdwRemainingLength)
650 {
651     FILETIME ft;
652     WCHAR *  wname;
653     size_t   len;
654     DWORD      dwEntryLength;
655     afs_uint32 code = 0, code2 = 0;
656
657     osi_Log4(afsd_logp, "RDR_PopulateCurrentEntryNoEntry dscp=0x%p name=%S short=%S flags=0x%x",
658              dscp, osi_LogSaveStringW(afsd_logp, name),
659              osi_LogSaveStringW(afsd_logp, shortName), dwFlags);
660     osi_Log1(afsd_logp, "... maxLength=%d", dwMaxEntryLength);
661
662     if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
663         if (ppNextEntry)
664             *ppNextEntry = pCurrentEntry;
665         if (pdwRemainingLength)
666             *pdwRemainingLength = dwMaxEntryLength;
667         osi_Log2(afsd_logp, "RDR_PopulateCurrentEntryNoEntry Not Enough Room for Entry %d < %d",
668                  dwMaxEntryLength, sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t));
669         return CM_ERROR_TOOBIG;
670     }
671
672     if (!name)
673         name = L"";
674     if (!shortName)
675         shortName = L"";
676
677     dwEntryLength = sizeof(AFSDirEnumEntry);
678
679     /* Populate the error code */
680     smb_MapNTError(cmError, &pCurrentEntry->NTStatus, TRUE);
681
682     /* Populate the fake data */
683     pCurrentEntry->FileId.Cell = fidp->cell;
684     pCurrentEntry->FileId.Volume = fidp->volume;
685     pCurrentEntry->FileId.Vnode = fidp->vnode;
686     pCurrentEntry->FileId.Unique = fidp->unique;
687     pCurrentEntry->FileId.Hash = fidp->hash;
688
689     pCurrentEntry->FileType = CM_SCACHETYPE_UNKNOWN;
690
691     pCurrentEntry->DataVersion.QuadPart = CM_SCACHE_VERSION_BAD;
692
693     cm_LargeSearchTimeFromUnixTime(&ft, 0);
694     pCurrentEntry->Expiration.LowPart = ft.dwLowDateTime;
695     pCurrentEntry->Expiration.HighPart = ft.dwHighDateTime;
696
697     cm_LargeSearchTimeFromUnixTime(&ft, 0);
698     pCurrentEntry->CreationTime.LowPart = ft.dwLowDateTime;
699     pCurrentEntry->CreationTime.HighPart = ft.dwHighDateTime;
700     pCurrentEntry->LastAccessTime = pCurrentEntry->CreationTime;
701     pCurrentEntry->LastWriteTime = pCurrentEntry->CreationTime;
702     pCurrentEntry->ChangeTime = pCurrentEntry->CreationTime;
703
704     pCurrentEntry->EndOfFile.QuadPart = 0;
705     pCurrentEntry->AllocationSize.QuadPart = 0;
706     pCurrentEntry->FileAttributes = 0;
707     pCurrentEntry->EaSize = 0;
708     pCurrentEntry->Links = 0;
709
710     len = wcslen(shortName);
711     wcsncpy(pCurrentEntry->ShortName, shortName, len);
712     pCurrentEntry->ShortNameLength = (CCHAR)(len * sizeof(WCHAR));
713
714     pCurrentEntry->FileNameOffset = sizeof(AFSDirEnumEntry);
715     len = wcslen(name);
716     wname = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->FileNameOffset);
717     wcsncpy(wname, name, len);
718     pCurrentEntry->FileNameLength = (ULONG)(sizeof(WCHAR) * len);
719
720     pCurrentEntry->TargetNameOffset = 0;
721     pCurrentEntry->TargetNameLength = 0;
722
723     dwEntryLength += pCurrentEntry->FileNameLength + pCurrentEntry->TargetNameLength;
724     dwEntryLength += (dwEntryLength % 8) ? 8 - (dwEntryLength % 8) : 0;   /* quad align */
725     if (ppNextEntry)
726         *ppNextEntry = (AFSDirEnumEntry *)((PBYTE)pCurrentEntry + dwEntryLength);
727     if (pdwRemainingLength)
728         *pdwRemainingLength = dwMaxEntryLength - dwEntryLength;
729
730     osi_Log3(afsd_logp, "RDR_PopulateCurrentEntryNoScp Success FileNameLength=%d TargetNameLength=%d RemainingLength=%d",
731               pCurrentEntry->FileNameLength, pCurrentEntry->TargetNameLength, *pdwRemainingLength);
732
733     return code;
734 }
735
736 void
737 RDR_EnumerateDirectory( IN cm_user_t *userp,
738                         IN AFSFileID DirID,
739                         IN AFSDirQueryCB *QueryCB,
740                         IN BOOL bWow64,
741                         IN BOOL bSkipStatus,
742                         IN DWORD ResultBufferLength,
743                         IN OUT AFSCommResult **ResultCB)
744 {
745     DWORD status;
746     cm_direnum_t *      enump = NULL;
747     AFSDirEnumResp  * pDirEnumResp;
748     AFSDirEnumEntry * pCurrentEntry;
749     size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
750     DWORD             dwMaxEntryLength;
751     afs_uint32  code = 0;
752     cm_fid_t      fid;
753     cm_scache_t * dscp = NULL;
754     cm_req_t      req;
755
756     RDR_InitReq(&req);
757     if ( bWow64 )
758         req.flags |= CM_REQ_WOW64;
759
760     osi_Log4(afsd_logp, "RDR_EnumerateDirectory FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
761              DirID.Cell, DirID.Volume, DirID.Vnode, DirID.Unique);
762
763     *ResultCB = (AFSCommResult *)malloc(size);
764     if (!(*ResultCB)) {
765         osi_Log0(afsd_logp, "RDR_EnumerateDirectory Out of Memory");
766         return;
767     }
768
769     memset(*ResultCB, 0, size);
770
771     if (QueryCB->EnumHandle == (ULONG_PTR)-1) {
772         osi_Log0(afsd_logp, "RDR_EnumerateDirectory No More Entries");
773         (*ResultCB)->ResultStatus = STATUS_NO_MORE_ENTRIES;
774         (*ResultCB)->ResultBufferLength = 0;
775         return;
776     }
777
778     (*ResultCB)->ResultBufferLength = dwMaxEntryLength = ResultBufferLength;
779     if (ResultBufferLength) {
780         pDirEnumResp = (AFSDirEnumResp *)&(*ResultCB)->ResultData;
781         pCurrentEntry = (AFSDirEnumEntry *)&pDirEnumResp->Entry;
782         dwMaxEntryLength -= FIELD_OFFSET( AFSDirEnumResp, Entry);      /* AFSDirEnumResp */
783     }
784
785     if (DirID.Cell != 0) {
786         fid.cell   = DirID.Cell;
787         fid.volume = DirID.Volume;
788         fid.vnode  = DirID.Vnode;
789         fid.unique = DirID.Unique;
790         fid.hash   = DirID.Hash;
791
792         code = cm_GetSCache(&fid, &dscp, userp, &req);
793         if (code) {
794             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
795             (*ResultCB)->ResultStatus = status;
796             osi_Log2(afsd_logp, "RDR_EnumerateDirectory cm_GetSCache failure code=0x%x status=0x%x",
797                       code, status);
798             return;
799         }
800     } else {
801         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
802         osi_Log0(afsd_logp, "RDR_EnumerateDirectory Object Name Invalid - Cell = 0");
803         return;
804     }
805
806     /* get the directory size */
807     lock_ObtainWrite(&dscp->rw);
808     code = cm_SyncOp(dscp, NULL, userp, &req, PRSFS_LOOKUP,
809                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
810     if (code) {
811         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
812         (*ResultCB)->ResultStatus = status;
813         lock_ReleaseWrite(&dscp->rw);
814         cm_ReleaseSCache(dscp);
815         osi_Log2(afsd_logp, "RDR_EnumerateDirectory cm_SyncOp failure code=0x%x status=0x%x",
816                   code, status);
817         return;
818     }
819
820     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
821     lock_ReleaseWrite(&dscp->rw);
822
823     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
824         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
825         cm_ReleaseSCache(dscp);
826         osi_Log1(afsd_logp, "RDR_EnumerateDirectory Not a Directory dscp=0x%p",
827                  dscp);
828         return;
829     }
830
831     osi_Log1(afsd_logp, "RDR_EnumerateDirectory dv=%u", (afs_uint32)dscp->dataVersion);
832
833     /*
834      * If there is no enumeration handle, then this is a new query
835      * and we must perform an enumeration for the specified object.
836      */
837     if (QueryCB->EnumHandle == (ULONG_PTR)NULL) {
838         cm_dirOp_t    dirop;
839
840         code = cm_BeginDirOp(dscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
841         if (code == 0) {
842             code = cm_BPlusDirEnumerate(dscp, userp, &req,
843                                         TRUE /* dir locked */, NULL /* no mask */,
844                                         TRUE /* fetch status? */, &enump);
845             if (code) {
846                 osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumerate failure code=0x%x",
847                           code);
848             }
849             cm_EndDirOp(&dirop);
850         } else {
851             osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BeginDirOp failure code=0x%x",
852                       code);
853         }
854     } else {
855         enump = (cm_direnum_t *)QueryCB->EnumHandle;
856     }
857
858     if (enump) {
859         if (ResultBufferLength == 0) {
860             code = cm_BPlusDirEnumBulkStat(enump);
861             if (code) {
862                 osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumBulkStat failure code=0x%x",
863                           code);
864             }
865         } else {
866             cm_direnum_entry_t * entryp = NULL;
867
868             pDirEnumResp->SnapshotDataVersion.QuadPart = enump->dataVersion;
869
870           getnextentry:
871             if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
872                 osi_Log0(afsd_logp, "RDR_EnumerateDirectory out of space, returning");
873                 goto outofspace;
874             }
875
876             code = cm_BPlusDirNextEnumEntry(enump, &entryp);
877
878             if ((code == 0 || code == CM_ERROR_STOPNOW) && entryp) {
879                 cm_scache_t *scp = NULL;
880                 int stopnow = (code == CM_ERROR_STOPNOW);
881
882                 if ( !wcscmp(L".", entryp->name) || !wcscmp(L"..", entryp->name) ) {
883                     osi_Log0(afsd_logp, "RDR_EnumerateDirectory skipping . or ..");
884                     if (stopnow)
885                         goto outofspace;
886                     goto getnextentry;
887                 }
888
889                 if (bSkipStatus) {
890                     code = cm_GetSCache(&entryp->fid, &scp, userp, &req);
891                     if (code) {
892                         osi_Log5(afsd_logp, "RDR_EnumerateDirectory cm_GetSCache failure cell %u vol %u vnode %u uniq %u code=0x%x",
893                                  entryp->fid.cell, entryp->fid.volume, entryp->fid.vnode, entryp->fid.unique, code);
894                     }
895                 } else {
896                     code = entryp->errorCode;
897                     scp = code ? NULL : cm_FindSCache(&entryp->fid);
898                 }
899
900                 if (scp) {
901                     code = RDR_PopulateCurrentEntry( pCurrentEntry, dwMaxEntryLength,
902                                                      dscp, scp, userp, &req,
903                                                      entryp->name,
904                                                      cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
905                                                      (bWow64 ? RDR_POP_WOW64 : 0) |
906                                                      (bSkipStatus ? RDR_POP_NO_GETSTATUS : 0),
907                                                      code,
908                                                      &pCurrentEntry, &dwMaxEntryLength);
909                     cm_ReleaseSCache(scp);
910                 } else {
911                     code = RDR_PopulateCurrentEntryNoScp( pCurrentEntry, dwMaxEntryLength,
912                                                           dscp, &entryp->fid, userp, &req,
913                                                           entryp->name,
914                                                           cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
915                                                           (bWow64 ? RDR_POP_WOW64 : 0),
916                                                           code,
917                                                           &pCurrentEntry, &dwMaxEntryLength);
918                 }
919                 if (stopnow)
920                     goto outofspace;
921                 goto getnextentry;
922             }
923         }
924     }
925
926   outofspace:
927
928     if (code || enump->next == enump->count || ResultBufferLength == 0) {
929         cm_BPlusDirFreeEnumeration(enump);
930         enump = (cm_direnum_t *)(ULONG_PTR)-1;
931     }
932
933     if (code == 0 || code == CM_ERROR_STOPNOW) {
934         (*ResultCB)->ResultStatus = STATUS_SUCCESS;
935         osi_Log0(afsd_logp, "RDR_EnumerateDirectory SUCCESS");
936     } else {
937         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
938         (*ResultCB)->ResultStatus = status;
939         osi_Log2(afsd_logp, "RDR_EnumerateDirectory Failure code=0x%x status=0x%x",
940                   code, status);
941     }
942
943     if (ResultBufferLength) {
944         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwMaxEntryLength;
945
946         pDirEnumResp->EnumHandle = (ULONG_PTR) enump;
947         pDirEnumResp->CurrentDataVersion.QuadPart = dscp->dataVersion;
948     }
949
950     if (dscp)
951         cm_ReleaseSCache(dscp);
952
953     return;
954 }
955
956 void
957 RDR_EvaluateNodeByName( IN cm_user_t *userp,
958                         IN AFSFileID ParentID,
959                         IN WCHAR   *FileNameCounted,
960                         IN DWORD    FileNameLength,
961                         IN BOOL     CaseSensitive,
962                         IN BOOL     bWow64,
963                         IN BOOL     bHoldFid,
964                         IN BOOL     bNoFollow,
965                         IN DWORD    ResultBufferLength,
966                         IN OUT AFSCommResult **ResultCB)
967 {
968     AFSFileEvalResultCB *pEvalResultCB = NULL;
969     AFSDirEnumEntry * pCurrentEntry;
970     size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
971     afs_uint32  code = 0;
972     cm_scache_t * scp = NULL;
973     cm_scache_t * dscp = NULL;
974     cm_req_t      req;
975     cm_fid_t      parentFid;
976     DWORD         status;
977     DWORD         dwRemaining;
978     WCHAR       * wszName = NULL;
979     size_t        cbName;
980     BOOL          bVol = FALSE;
981     wchar_t       FileName[260];
982
983     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
984
985     RDR_InitReq(&req);
986     if ( bWow64 )
987         req.flags |= CM_REQ_WOW64;
988
989     osi_Log4(afsd_logp, "RDR_EvaluateNodeByName parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
990              ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
991
992     /* Allocate enough room to add a volume prefix if necessary */
993     cbName = FileNameLength + (CM_PREFIX_VOL_CCH + 1) * sizeof(WCHAR);
994     wszName = malloc(cbName);
995     if (!wszName) {
996         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Out of Memory");
997         return;
998     }
999     StringCbCopyNW(wszName, cbName, FileName, FileNameLength);
1000     osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, wszName));
1001
1002     *ResultCB = (AFSCommResult *)malloc(size);
1003     if (!(*ResultCB)) {
1004         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Out of Memory");
1005         free(wszName);
1006         return;
1007     }
1008
1009     memset(*ResultCB, 0, size);
1010     (*ResultCB)->ResultBufferLength = 0;
1011     dwRemaining = ResultBufferLength;
1012     if (ResultBufferLength >= sizeof( AFSFileEvalResultCB)) {
1013         pEvalResultCB = (AFSFileEvalResultCB *)&(*ResultCB)->ResultData;
1014         pCurrentEntry = &pEvalResultCB->DirEnum;
1015         dwRemaining -= (sizeof( AFSFileEvalResultCB) - sizeof( AFSDirEnumEntry));
1016     }
1017
1018     if (ParentID.Cell != 0) {
1019         parentFid.cell   = ParentID.Cell;
1020         parentFid.volume = ParentID.Volume;
1021         parentFid.vnode  = ParentID.Vnode;
1022         parentFid.unique = ParentID.Unique;
1023         parentFid.hash   = ParentID.Hash;
1024
1025         code = cm_GetSCache(&parentFid, &dscp, userp, &req);
1026         if (code) {
1027             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1028             (*ResultCB)->ResultStatus = status;
1029             if ( status == STATUS_INVALID_HANDLE)
1030                 status = STATUS_OBJECT_PATH_INVALID;
1031             osi_Log2(afsd_logp, "RDR_EvaluateNodeByName cm_GetSCache parentFID failure code=0x%x status=0x%x",
1032                       code, status);
1033             free(wszName);
1034             return;
1035         }
1036     } else {
1037         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
1038         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Object Name Invalid - Cell = 0");
1039         return;
1040     }
1041
1042     /* get the directory size */
1043     lock_ObtainWrite(&dscp->rw);
1044     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1045                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1046     if (code) {
1047         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1048         (*ResultCB)->ResultStatus = status;
1049         lock_ReleaseWrite(&dscp->rw);
1050         cm_ReleaseSCache(dscp);
1051         osi_Log3(afsd_logp, "RDR_EvaluateNodeByName cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
1052                  dscp, code, status);
1053         free(wszName);
1054         return;
1055     }
1056     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1057     lock_ReleaseWrite(&dscp->rw);
1058
1059     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1060         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1061         cm_ReleaseSCache(dscp);
1062         osi_Log1(afsd_logp, "RDR_EvaluateNodeByName Not a Directory dscp=0x%p",
1063                  dscp);
1064         free(wszName);
1065         return;
1066     }
1067
1068     code = cm_Lookup(dscp, wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
1069
1070     if ((code == CM_ERROR_NOSUCHPATH || code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) &&
1071          (wcschr(wszName, '%') != NULL || wcschr(wszName, '#') != NULL)) {
1072         /*
1073          * A volume reference:  <cell>{%,#}<volume> -> @vol:<cell>{%,#}<volume>
1074          */
1075         StringCchCopyNW(wszName, cbName, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
1076         StringCbCatNW(wszName, cbName, FileName, FileNameLength);
1077         cm_strlwr_utf16(wszName);
1078         bVol = TRUE;
1079
1080         code = cm_EvaluateVolumeReference(wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
1081     }
1082
1083     if (code == 0 && scp) {
1084         wchar_t shortName[13]=L"";
1085
1086         if (bVol) {
1087             cm_Gen8Dot3VolNameW(scp->fid.cell, scp->fid.volume, shortName, NULL);
1088         } else if (!cm_Is8Dot3(wszName)) {
1089             cm_dirFid_t dfid;
1090
1091             dfid.vnode = htonl(scp->fid.vnode);
1092             dfid.unique = htonl(scp->fid.unique);
1093
1094             cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
1095         } else {
1096             shortName[0] = '\0';
1097         }
1098
1099         code = RDR_PopulateCurrentEntry(pCurrentEntry, dwRemaining,
1100                                         dscp, scp, userp, &req,
1101                                         FileName, shortName,
1102                                         (bWow64 ? RDR_POP_WOW64 : 0) |
1103                                         (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
1104                                         0, NULL, &dwRemaining);
1105         if (bHoldFid)
1106             RDR_FlagScpInUse( scp, FALSE );
1107         cm_ReleaseSCache(scp);
1108
1109         if (code) {
1110             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1111             (*ResultCB)->ResultStatus = status;
1112             osi_Log2(afsd_logp, "RDR_EvaluateNodeByName FAILURE code=0x%x status=0x%x",
1113                       code, status);
1114         } else {
1115             pEvalResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1116             (*ResultCB)->ResultStatus = STATUS_SUCCESS;
1117             (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1118             osi_Log0(afsd_logp, "RDR_EvaluateNodeByName SUCCESS");
1119         }
1120     } else if (code) {
1121         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1122         (*ResultCB)->ResultStatus = status;
1123         osi_Log2(afsd_logp, "RDR_EvaluateNodeByName FAILURE code=0x%x status=0x%x",
1124                  code, status);
1125     } else {
1126         (*ResultCB)->ResultStatus = STATUS_NO_SUCH_FILE;
1127         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName No Such File");
1128     }
1129     cm_ReleaseSCache(dscp);
1130     free(wszName);
1131
1132     return;
1133 }
1134
1135 void
1136 RDR_EvaluateNodeByID( IN cm_user_t *userp,
1137                       IN AFSFileID ParentID,            /* not used */
1138                       IN AFSFileID SourceID,
1139                       IN BOOL      bWow64,
1140                       IN BOOL      bNoFollow,
1141                       IN BOOL      bHoldFid,
1142                       IN DWORD     ResultBufferLength,
1143                       IN OUT AFSCommResult **ResultCB)
1144 {
1145     AFSFileEvalResultCB *pEvalResultCB = NULL;
1146     AFSDirEnumEntry * pCurrentEntry = NULL;
1147     size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
1148     afs_uint32  code = 0;
1149     cm_scache_t * scp = NULL;
1150     cm_scache_t * dscp = NULL;
1151     cm_req_t      req;
1152     cm_fid_t      Fid;
1153     cm_fid_t      parentFid;
1154     DWORD         status;
1155     DWORD         dwRemaining;
1156
1157     osi_Log4(afsd_logp, "RDR_EvaluateNodeByID source FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1158               SourceID.Cell, SourceID.Volume, SourceID.Vnode, SourceID.Unique);
1159     osi_Log4(afsd_logp, "... parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1160               ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
1161
1162     *ResultCB = (AFSCommResult *)malloc(size);
1163     if (!(*ResultCB)) {
1164         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID Out of Memory");
1165         return;
1166     }
1167
1168     memset(*ResultCB, 0, size);
1169     (*ResultCB)->ResultBufferLength = 0;
1170     dwRemaining = ResultBufferLength;
1171     if (ResultBufferLength >= sizeof( AFSFileEvalResultCB)) {
1172         pEvalResultCB = (AFSFileEvalResultCB *)&(*ResultCB)->ResultData;
1173         pCurrentEntry = &pEvalResultCB->DirEnum;
1174         dwRemaining -= (sizeof( AFSFileEvalResultCB) - sizeof( AFSDirEnumEntry));
1175     }
1176
1177     RDR_InitReq(&req);
1178     if ( bWow64 )
1179         req.flags |= CM_REQ_WOW64;
1180
1181     if (SourceID.Cell != 0) {
1182         Fid.cell   = SourceID.Cell;
1183         Fid.volume = SourceID.Volume;
1184         Fid.vnode  = SourceID.Vnode;
1185         Fid.unique = SourceID.Unique;
1186         Fid.hash   = SourceID.Hash;
1187
1188         code = cm_GetSCache(&Fid, &scp, userp, &req);
1189         if (code) {
1190             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1191             (*ResultCB)->ResultStatus = status;
1192             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache SourceFID failure code=0x%x status=0x%x",
1193                       code, status);
1194             return;
1195         }
1196     } else {
1197         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
1198         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID Object Name Invalid - Cell = 0");
1199         return;
1200     }
1201
1202     if (ParentID.Cell != 0) {
1203         cm_SetFid(&parentFid, ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
1204         code = cm_GetSCache(&parentFid, &dscp, userp, &req);
1205         if (code) {
1206             cm_ReleaseSCache(scp);
1207             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1208             if ( status == STATUS_INVALID_HANDLE)
1209                 status = STATUS_OBJECT_PATH_INVALID;
1210             (*ResultCB)->ResultStatus = status;
1211             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache parentFID failure code=0x%x status=0x%x",
1212                       code, status);
1213             return;
1214         }
1215     } else if (SourceID.Vnode == 1) {
1216         dscp = scp;
1217         cm_HoldSCache(dscp);
1218     } else if (scp->parentVnode) {
1219         cm_SetFid(&parentFid, SourceID.Cell, SourceID.Volume, scp->parentVnode, scp->parentUnique);
1220         code = cm_GetSCache(&parentFid, &dscp, userp, &req);
1221         if (code) {
1222             cm_ReleaseSCache(scp);
1223             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1224             if ( status == STATUS_INVALID_HANDLE)
1225                 status = STATUS_OBJECT_PATH_INVALID;
1226             (*ResultCB)->ResultStatus = status;
1227             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache parentFID failure code=0x%x status=0x%x",
1228                       code, status);
1229             return;
1230         }
1231     } else {
1232         (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
1233         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID Object Path Invalid - Unknown Parent");
1234         return;
1235     }
1236
1237     /* Make sure the directory is current */
1238     lock_ObtainWrite(&dscp->rw);
1239     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1240                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1241     if (code) {
1242         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1243         (*ResultCB)->ResultStatus = status;
1244         lock_ReleaseWrite(&dscp->rw);
1245         cm_ReleaseSCache(dscp);
1246         cm_ReleaseSCache(scp);
1247         osi_Log3(afsd_logp, "RDR_EvaluateNodeByID cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
1248                  dscp, code, status);
1249         return;
1250     }
1251
1252     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1253     lock_ReleaseWrite(&dscp->rw);
1254
1255     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1256         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1257         cm_ReleaseSCache(dscp);
1258         cm_ReleaseSCache(scp);
1259         osi_Log1(afsd_logp, "RDR_EvaluateNodeByID Not a Directory dscp=0x%p", dscp);
1260         return;
1261     }
1262
1263     code = RDR_PopulateCurrentEntry(pCurrentEntry, dwRemaining,
1264                                     dscp, scp, userp, &req, NULL, NULL,
1265                                     (bWow64 ? RDR_POP_WOW64 : 0) |
1266                                     (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
1267                                     0, NULL, &dwRemaining);
1268
1269     if (bHoldFid)
1270         RDR_FlagScpInUse( scp, FALSE );
1271     cm_ReleaseSCache(scp);
1272     cm_ReleaseSCache(dscp);
1273
1274     if (code) {
1275         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1276         (*ResultCB)->ResultStatus = status;
1277         osi_Log2(afsd_logp, "RDR_EvaluateNodeByID FAILURE code=0x%x status=0x%x",
1278                  code, status);
1279     } else {
1280         pEvalResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1281
1282         (*ResultCB)->ResultStatus = STATUS_SUCCESS;
1283         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1284         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID SUCCESS");
1285     }
1286     return;
1287 }
1288
1289 void
1290 RDR_CreateFileEntry( IN cm_user_t *userp,
1291                      IN WCHAR *FileNameCounted,
1292                      IN DWORD FileNameLength,
1293                      IN AFSFileCreateCB *CreateCB,
1294                      IN BOOL bWow64,
1295                      IN BOOL bHoldFid,
1296                      IN DWORD ResultBufferLength,
1297                      IN OUT AFSCommResult **ResultCB)
1298 {
1299     AFSFileCreateResultCB *pResultCB = NULL;
1300     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
1301     cm_fid_t            parentFid;
1302     afs_uint32          code;
1303     cm_scache_t *       dscp = NULL;
1304     afs_uint32          flags = 0;
1305     cm_attr_t           setAttr;
1306     cm_scache_t *       scp = NULL;
1307     cm_req_t            req;
1308     DWORD               status;
1309     wchar_t             FileName[260];
1310
1311     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
1312
1313     osi_Log4(afsd_logp, "RDR_CreateFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1314               CreateCB->ParentId.Cell, CreateCB->ParentId.Volume,
1315               CreateCB->ParentId.Vnode, CreateCB->ParentId.Unique);
1316     osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, FileName));
1317
1318     RDR_InitReq(&req);
1319     if ( bWow64 )
1320         req.flags |= CM_REQ_WOW64;
1321     memset(&setAttr, 0, sizeof(cm_attr_t));
1322
1323     *ResultCB = (AFSCommResult *)malloc(size);
1324     if (!(*ResultCB)) {
1325         osi_Log0(afsd_logp, "RDR_CreateFileEntry out of memory");
1326         return;
1327     }
1328
1329     memset( *ResultCB,
1330             '\0',
1331             size);
1332
1333     parentFid.cell   = CreateCB->ParentId.Cell;
1334     parentFid.volume = CreateCB->ParentId.Volume;
1335     parentFid.vnode  = CreateCB->ParentId.Vnode;
1336     parentFid.unique = CreateCB->ParentId.Unique;
1337     parentFid.hash   = CreateCB->ParentId.Hash;
1338
1339     code = cm_GetSCache(&parentFid, &dscp, userp, &req);
1340     if (code) {
1341         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1342         (*ResultCB)->ResultStatus = status;
1343         if ( status == STATUS_INVALID_HANDLE)
1344             status = STATUS_OBJECT_PATH_INVALID;
1345         osi_Log2(afsd_logp, "RDR_CreateFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
1346                   code, status);
1347         return;
1348     }
1349
1350     lock_ObtainWrite(&dscp->rw);
1351     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1352                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1353     if (code) {
1354         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1355         (*ResultCB)->ResultStatus = status;
1356         lock_ReleaseWrite(&dscp->rw);
1357         cm_ReleaseSCache(dscp);
1358         osi_Log3(afsd_logp, "RDR_CreateFileEntry cm_SyncOp failure (1) dscp=0x%p code=0x%x status=0x%x",
1359                  dscp, code, status);
1360         return;
1361     }
1362
1363     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1364     lock_ReleaseWrite(&dscp->rw);
1365
1366     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1367         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1368         cm_ReleaseSCache(dscp);
1369         osi_Log1(afsd_logp, "RDR_CreateFileEntry Not a Directory dscp=0x%p",
1370                  dscp);
1371         return;
1372     }
1373
1374     /* Use current time */
1375     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
1376     setAttr.clientModTime = time(NULL);
1377
1378     if (CreateCB->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1379         if (smb_unixModeDefaultDir) {
1380             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1381             setAttr.unixModeBits = smb_unixModeDefaultDir;
1382             if (CreateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)
1383                 setAttr.unixModeBits &= ~0222;          /* disable the write bits */
1384         }
1385
1386         code = cm_MakeDir(dscp, FileName, flags, &setAttr, userp, &req, &scp);
1387     } else {
1388         if (smb_unixModeDefaultFile) {
1389             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1390             setAttr.unixModeBits = smb_unixModeDefaultFile;
1391             if (CreateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)
1392                 setAttr.unixModeBits &= ~0222;          /* disable the write bits */
1393         }
1394
1395         setAttr.mask |= CM_ATTRMASK_LENGTH;
1396         setAttr.length.LowPart = CreateCB->AllocationSize.LowPart;
1397         setAttr.length.HighPart = CreateCB->AllocationSize.HighPart;
1398         code = cm_Create(dscp, FileName, flags, &setAttr, &scp, userp, &req);
1399     }
1400     if (code == 0) {
1401         wchar_t shortName[13]=L"";
1402         cm_dirFid_t dfid;
1403         DWORD dwRemaining;
1404
1405         (*ResultCB)->ResultStatus = 0;  // We will be able to fit all the data in here
1406
1407         (*ResultCB)->ResultBufferLength = sizeof( AFSFileCreateResultCB);
1408
1409         pResultCB = (AFSFileCreateResultCB *)(*ResultCB)->ResultData;
1410
1411         dwRemaining = ResultBufferLength - sizeof( AFSFileCreateResultCB) + sizeof( AFSDirEnumEntry);
1412
1413         lock_ObtainWrite(&dscp->rw);
1414         code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1415                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1416         if (code) {
1417             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1418             (*ResultCB)->ResultStatus = status;
1419             lock_ReleaseWrite(&dscp->rw);
1420             cm_ReleaseSCache(dscp);
1421             cm_ReleaseSCache(scp);
1422             osi_Log3(afsd_logp, "RDR_CreateFileEntry cm_SyncOp failure (2) dscp=0x%p code=0x%x status=0x%x",
1423                       dscp, code, status);
1424             return;
1425         }
1426
1427         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1428
1429         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1430         lock_ReleaseWrite(&dscp->rw);
1431
1432         dfid.vnode = htonl(scp->fid.vnode);
1433         dfid.unique = htonl(scp->fid.unique);
1434
1435         if (!cm_Is8Dot3(FileName))
1436             cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
1437         else
1438             shortName[0] = '\0';
1439
1440         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
1441                                         dscp, scp, userp, &req, FileName, shortName,
1442                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
1443                                         0, NULL, &dwRemaining);
1444
1445         if (bHoldFid)
1446             RDR_FlagScpInUse( scp, FALSE );
1447         cm_ReleaseSCache(scp);
1448         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1449         osi_Log0(afsd_logp, "RDR_CreateFileEntry SUCCESS");
1450     } else {
1451         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1452         (*ResultCB)->ResultStatus = status;
1453         (*ResultCB)->ResultBufferLength = 0;
1454         osi_Log2(afsd_logp, "RDR_CreateFileEntry FAILURE code=0x%x status=0x%x",
1455                   code, status);
1456     }
1457
1458     cm_ReleaseSCache(dscp);
1459
1460     return;
1461 }
1462
1463 void
1464 RDR_UpdateFileEntry( IN cm_user_t *userp,
1465                      IN AFSFileID FileId,
1466                      IN AFSFileUpdateCB *UpdateCB,
1467                      IN BOOL bWow64,
1468                      IN DWORD ResultBufferLength,
1469                      IN OUT AFSCommResult **ResultCB)
1470 {
1471     AFSFileUpdateResultCB *pResultCB = NULL;
1472     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
1473     cm_fid_t            Fid;
1474     cm_fid_t            parentFid;
1475     afs_uint32          code;
1476     afs_uint32          flags = 0;
1477     cm_attr_t           setAttr;
1478     cm_scache_t *       scp = NULL;
1479     cm_scache_t *       dscp = NULL;
1480     cm_req_t            req;
1481     time_t              clientModTime;
1482     FILETIME            ft;
1483     DWORD               status;
1484     BOOL                bScpLocked = FALSE;
1485
1486     RDR_InitReq(&req);
1487     if ( bWow64 )
1488         req.flags |= CM_REQ_WOW64;
1489     memset(&setAttr, 0, sizeof(cm_attr_t));
1490
1491     osi_Log4(afsd_logp, "RDR_UpdateFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1492               UpdateCB->ParentId.Cell, UpdateCB->ParentId.Volume,
1493               UpdateCB->ParentId.Vnode, UpdateCB->ParentId.Unique);
1494     osi_Log4(afsd_logp, "... object FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1495               FileId.Cell, FileId.Volume,
1496               FileId.Vnode, FileId.Unique);
1497
1498     *ResultCB = (AFSCommResult *)malloc( size);
1499     if (!(*ResultCB)) {
1500         osi_Log0(afsd_logp, "RDR_UpdateFileEntry Out of Memory");
1501         return;
1502     }
1503
1504     memset( *ResultCB,
1505             '\0',
1506             size);
1507
1508     parentFid.cell   = UpdateCB->ParentId.Cell;
1509     parentFid.volume = UpdateCB->ParentId.Volume;
1510     parentFid.vnode  = UpdateCB->ParentId.Vnode;
1511     parentFid.unique = UpdateCB->ParentId.Unique;
1512     parentFid.hash   = UpdateCB->ParentId.Hash;
1513
1514     code = cm_GetSCache(&parentFid, &dscp, userp, &req);
1515     if (code) {
1516         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1517         (*ResultCB)->ResultStatus = status;
1518         if ( status == STATUS_INVALID_HANDLE)
1519             status = STATUS_OBJECT_PATH_INVALID;
1520         osi_Log2(afsd_logp, "RDR_UpdateFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
1521                   code, status);
1522         return;
1523     }
1524
1525     lock_ObtainWrite(&dscp->rw);
1526     bScpLocked = TRUE;
1527     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1528                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1529     if (code) {
1530         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1531         (*ResultCB)->ResultStatus = status;
1532         lock_ReleaseWrite(&dscp->rw);
1533         cm_ReleaseSCache(dscp);
1534         osi_Log3(afsd_logp, "RDR_UpdateFileEntry cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
1535                  dscp, code, status);
1536         return;
1537     }
1538
1539     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1540     lock_ReleaseWrite(&dscp->rw);
1541     bScpLocked = FALSE;
1542
1543     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1544         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1545         cm_ReleaseSCache(dscp);
1546         osi_Log1(afsd_logp, "RDR_UpdateFileEntry Not a Directory dscp=0x%p",
1547                  dscp);
1548         return;
1549     }
1550
1551     Fid.cell   = FileId.Cell;
1552     Fid.volume = FileId.Volume;
1553     Fid.vnode  = FileId.Vnode;
1554     Fid.unique = FileId.Unique;
1555     Fid.hash   = FileId.Hash;
1556
1557     code = cm_GetSCache(&Fid, &scp, userp, &req);
1558     if (code) {
1559         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1560         (*ResultCB)->ResultStatus = status;
1561         cm_ReleaseSCache(dscp);
1562         osi_Log2(afsd_logp, "RDR_UpdateFileEntry cm_GetSCache object FID failure code=0x%x status=0x%x",
1563                   code, status);
1564         return;
1565     }
1566
1567     lock_ObtainWrite(&scp->rw);
1568     bScpLocked = TRUE;
1569     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1570                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
1571     if (code) {
1572         lock_ReleaseWrite(&scp->rw);
1573         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1574         (*ResultCB)->ResultStatus = status;
1575         (*ResultCB)->ResultBufferLength = 0;
1576         cm_ReleaseSCache(dscp);
1577         cm_ReleaseSCache(scp);
1578         osi_Log3(afsd_logp, "RDR_UpdateFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
1579                  scp, code, status);
1580         return;
1581     }
1582     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1583
1584     if (UpdateCB->ChangeTime.QuadPart) {
1585
1586         if (scp->fileType == CM_SCACHETYPE_FILE) {
1587             /* Do not set length and other attributes at the same time */
1588             if (scp->length.QuadPart != UpdateCB->AllocationSize.QuadPart) {
1589                 osi_Log2(afsd_logp, "RDR_UpdateFileEntry Length Change 0x%x -> 0x%x",
1590                           (afs_uint32)scp->length.QuadPart, (afs_uint32)UpdateCB->AllocationSize.QuadPart);
1591                 setAttr.mask |= CM_ATTRMASK_LENGTH;
1592                 setAttr.length.LowPart = UpdateCB->AllocationSize.LowPart;
1593                 setAttr.length.HighPart = UpdateCB->AllocationSize.HighPart;
1594                 lock_ReleaseWrite(&scp->rw);
1595                 bScpLocked = FALSE;
1596                 code = cm_SetAttr(scp, &setAttr, userp, &req);
1597                 if (code)
1598                     goto on_error;
1599                 setAttr.mask = 0;
1600             }
1601         }
1602
1603         if (!bScpLocked) {
1604             lock_ObtainWrite(&scp->rw);
1605             bScpLocked = TRUE;
1606         }
1607         if ((scp->unixModeBits & 0200) && (UpdateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1608             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1609             setAttr.unixModeBits = scp->unixModeBits & ~0222;
1610         } else if (!(scp->unixModeBits & 0200) && !(UpdateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1611             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1612             setAttr.unixModeBits = scp->unixModeBits | 0222;
1613         }
1614     }
1615
1616     if (UpdateCB->LastWriteTime.QuadPart) {
1617         ft.dwLowDateTime = UpdateCB->LastWriteTime.LowPart;
1618         ft.dwHighDateTime = UpdateCB->LastWriteTime.HighPart;
1619
1620         cm_UnixTimeFromLargeSearchTime(& clientModTime, &ft);
1621
1622         if (!bScpLocked) {
1623             lock_ObtainWrite(&scp->rw);
1624             bScpLocked = TRUE;
1625         }
1626         if (scp->clientModTime != clientModTime) {
1627             setAttr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1628             setAttr.clientModTime = clientModTime;
1629         }
1630
1631         /* call setattr */
1632         if (setAttr.mask) {
1633             lock_ReleaseWrite(&scp->rw);
1634             bScpLocked = FALSE;
1635             code = cm_SetAttr(scp, &setAttr, userp, &req);
1636         } else
1637             code = 0;
1638     }
1639
1640   on_error:
1641     if (bScpLocked) {
1642         lock_ReleaseWrite(&scp->rw);
1643     }
1644
1645     if (code == 0) {
1646         DWORD dwRemaining = ResultBufferLength - sizeof( AFSFileUpdateResultCB) + sizeof( AFSDirEnumEntry);
1647
1648         pResultCB = (AFSFileUpdateResultCB *)(*ResultCB)->ResultData;
1649
1650         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1651
1652         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
1653                                         dscp, scp, userp, &req, NULL, NULL,
1654                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
1655                                         0, NULL, &dwRemaining);
1656         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1657         osi_Log0(afsd_logp, "RDR_UpdateFileEntry SUCCESS");
1658     } else {
1659         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1660         (*ResultCB)->ResultStatus = status;
1661         (*ResultCB)->ResultBufferLength = 0;
1662         osi_Log2(afsd_logp, "RDR_UpdateFileEntry FAILURE code=0x%x status=0x%x",
1663                   code, status);
1664     }
1665     cm_ReleaseSCache(scp);
1666     cm_ReleaseSCache(dscp);
1667
1668     return;
1669 }
1670
1671 void
1672 RDR_CleanupFileEntry( IN cm_user_t *userp,
1673                       IN AFSFileID FileId,
1674                       IN WCHAR *FileNameCounted,
1675                       IN DWORD FileNameLength,
1676                       IN AFSFileCleanupCB *CleanupCB,
1677                       IN BOOL bWow64,
1678                       IN BOOL bLastHandle,
1679                       IN BOOL bDeleteFile,
1680                       IN BOOL bUnlockFile,
1681                       IN DWORD ResultBufferLength,
1682                       IN OUT AFSCommResult **ResultCB)
1683 {
1684     AFSFileCleanupResultCB *pResultCB = NULL;
1685     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
1686     cm_fid_t            Fid;
1687     cm_fid_t            parentFid;
1688     afs_uint32          code = 0;
1689     afs_uint32          flags = 0;
1690     cm_attr_t           setAttr;
1691     cm_scache_t *       scp = NULL;
1692     cm_scache_t *       dscp = NULL;
1693     cm_req_t            req;
1694     time_t              clientModTime;
1695     FILETIME            ft;
1696     DWORD               status;
1697     BOOL                bScpLocked = FALSE;
1698     BOOL                bDscpLocked = FALSE;
1699     BOOL                bFlushFile = FALSE;
1700     cm_key_t            key;
1701
1702     RDR_InitReq(&req);
1703     if ( bWow64 )
1704         req.flags |= CM_REQ_WOW64;
1705     memset(&setAttr, 0, sizeof(cm_attr_t));
1706
1707     osi_Log4(afsd_logp, "RDR_CleanupFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1708               CleanupCB->ParentId.Cell, CleanupCB->ParentId.Volume,
1709               CleanupCB->ParentId.Vnode, CleanupCB->ParentId.Unique);
1710     osi_Log4(afsd_logp, "... object FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1711               FileId.Cell, FileId.Volume,
1712               FileId.Vnode, FileId.Unique);
1713
1714     *ResultCB = (AFSCommResult *)malloc( size);
1715     if (!(*ResultCB)) {
1716         osi_Log0(afsd_logp, "RDR_CleanupFileEntry Out of Memory");
1717         return;
1718     }
1719
1720     memset( *ResultCB,
1721             '\0',
1722             size);
1723
1724     parentFid.cell   = CleanupCB->ParentId.Cell;
1725     parentFid.volume = CleanupCB->ParentId.Volume;
1726     parentFid.vnode  = CleanupCB->ParentId.Vnode;
1727     parentFid.unique = CleanupCB->ParentId.Unique;
1728     parentFid.hash   = CleanupCB->ParentId.Hash;
1729
1730     if (parentFid.cell) {
1731         code = cm_GetSCache(&parentFid, &dscp, userp, &req);
1732         if (code) {
1733             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1734             if ( status == STATUS_INVALID_HANDLE)
1735                 status = STATUS_OBJECT_PATH_INVALID;
1736             (*ResultCB)->ResultStatus = status;
1737             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
1738                      code, status);
1739             return;
1740         }
1741
1742         lock_ObtainWrite(&dscp->rw);
1743         bDscpLocked = TRUE;
1744         code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1745                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1746         if (code) {
1747             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp failure dscp=0x%p code=0x%x",
1748                     dscp, code);
1749             if (code)
1750                 goto on_error;
1751         }
1752
1753         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1754         lock_ReleaseWrite(&dscp->rw);
1755         bDscpLocked = FALSE;
1756
1757         if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1758             (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1759             cm_ReleaseSCache(dscp);
1760             osi_Log1(afsd_logp, "RDR_CleanupFileEntry Not a Directory dscp=0x%p",
1761                      dscp);
1762             if (code)
1763                 goto on_error;
1764         }
1765     }
1766
1767     Fid.cell   = FileId.Cell;
1768     Fid.volume = FileId.Volume;
1769     Fid.vnode  = FileId.Vnode;
1770     Fid.unique = FileId.Unique;
1771     Fid.hash   = FileId.Hash;
1772
1773     code = cm_GetSCache(&Fid, &scp, userp, &req);
1774     if (code) {
1775         osi_Log1(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache object FID failure code=0x%x",
1776                  code);
1777         goto on_error;
1778     }
1779
1780     lock_ObtainWrite(&scp->rw);
1781     bScpLocked = TRUE;
1782     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1783                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
1784     if (code) {
1785         osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp failure scp=0x%p code=0x%x",
1786                  scp, code);
1787         goto on_error;
1788     }
1789     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1790
1791     if ((bLastHandle || bFlushFile) &&
1792         scp->redirBufCount > 0)
1793     {
1794         LARGE_INTEGER heldExtents;
1795         AFSFileExtentCB extentList[1024];
1796         DWORD extentCount = 0;
1797         cm_buf_t *srbp;
1798         time_t now;
1799
1800         time(&now);
1801         heldExtents.QuadPart = 0;
1802
1803         for ( srbp = redirq_to_cm_buf_t(scp->redirQueueT);
1804               srbp;
1805               srbp = redirq_to_cm_buf_t(osi_QPrev(&srbp->redirq)))
1806         {
1807             extentList[extentCount].Flags = 0;
1808             extentList[extentCount].Length = cm_data.blockSize;
1809             extentList[extentCount].FileOffset.QuadPart = srbp->offset.QuadPart;
1810             extentList[extentCount].CacheOffset.QuadPart = srbp->datap - RDR_extentBaseAddress;
1811             lock_ObtainWrite(&buf_globalLock);
1812             srbp->redirReleaseRequested = now;
1813             lock_ReleaseWrite(&buf_globalLock);
1814             extentCount++;
1815
1816             if (extentCount == 1024) {
1817                 lock_ReleaseWrite(&scp->rw);
1818                 code = RDR_RequestExtentRelease(&scp->fid, heldExtents, extentCount, extentList);
1819                 if (code) {
1820                     if (code == CM_ERROR_RETRY) {
1821                         /*
1822                          * The redirector either is not holding the extents or cannot let them
1823                          * go because they are otherwise in use.  At the moment, do nothing.
1824                          */
1825                     } else
1826                         break;
1827                 }
1828                 extentCount = 0;
1829                 bFlushFile = TRUE;
1830                 lock_ObtainWrite(&scp->rw);
1831             }
1832         }
1833
1834         if (code == 0 && extentCount > 0) {
1835             if (bScpLocked) {
1836                 lock_ReleaseWrite(&scp->rw);
1837                 bScpLocked = FALSE;
1838             }
1839             code = RDR_RequestExtentRelease(&scp->fid, heldExtents, extentCount, extentList);
1840             bFlushFile = TRUE;
1841         }
1842     }
1843
1844     /* No longer in use by redirector */
1845     if (!bScpLocked) {
1846         lock_ObtainWrite(&scp->rw);
1847         bScpLocked = TRUE;
1848     }
1849
1850     if (bLastHandle) {
1851         lock_AssertWrite(&scp->rw);
1852         scp->flags &= ~CM_SCACHEFLAG_RDR_IN_USE;
1853     }
1854
1855     if (bLastHandle || bFlushFile) {
1856         if (!bScpLocked) {
1857             lock_ObtainWrite(&scp->rw);
1858             bScpLocked = TRUE;
1859         }
1860         code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
1861                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1862         if (code == 0) {
1863             if (bScpLocked) {
1864                 lock_ReleaseWrite(&scp->rw);
1865                 bScpLocked = FALSE;
1866             }
1867
1868             code = cm_FSync(scp, userp, &req, bScpLocked);
1869         }
1870         if (bLastHandle && code)
1871             goto on_error;
1872     }
1873
1874     if (bUnlockFile || bDeleteFile) {
1875         if (!bScpLocked) {
1876             lock_ObtainWrite(&scp->rw);
1877             bScpLocked = TRUE;
1878         }
1879         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1880                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
1881         if (code) {
1882             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp (2) failure scp=0x%p code=0x%x",
1883                      scp, code);
1884             goto on_error;
1885         }
1886
1887         key = cm_GenerateKey(CM_SESSION_IFS, CleanupCB->ProcessId, 0);
1888
1889         /* the scp is now locked and current */
1890         code = cm_UnlockByKey(scp, key,
1891                               bDeleteFile ? CM_UNLOCK_FLAG_BY_FID : 0,
1892                               userp, &req);
1893
1894         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
1895
1896         if (code)
1897             goto on_error;
1898     }
1899
1900     if (CleanupCB->ChangeTime.QuadPart) {
1901
1902         if (scp->fileType == CM_SCACHETYPE_FILE) {
1903             /* Do not set length and other attributes at the same time */
1904             if (scp->length.QuadPart != CleanupCB->AllocationSize.QuadPart) {
1905                 osi_Log2(afsd_logp, "RDR_CleanupFileEntry Length Change 0x%x -> 0x%x",
1906                           (afs_uint32)scp->length.QuadPart, (afs_uint32)CleanupCB->AllocationSize.QuadPart);
1907                 setAttr.mask |= CM_ATTRMASK_LENGTH;
1908                 setAttr.length.LowPart = CleanupCB->AllocationSize.LowPart;
1909                 setAttr.length.HighPart = CleanupCB->AllocationSize.HighPart;
1910
1911                 if (bScpLocked) {
1912                     lock_ReleaseWrite(&scp->rw);
1913                     bScpLocked = FALSE;
1914                 }
1915                 code = cm_SetAttr(scp, &setAttr, userp, &req);
1916                 if (code)
1917                     goto on_error;
1918                 setAttr.mask = 0;
1919             }
1920         }
1921
1922         if (!bScpLocked) {
1923             lock_ObtainWrite(&scp->rw);
1924             bScpLocked = TRUE;
1925         }
1926
1927         if ((scp->unixModeBits & 0200) && (CleanupCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1928             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1929             setAttr.unixModeBits = scp->unixModeBits & ~0222;
1930         } else if (!(scp->unixModeBits & 0200) && !(CleanupCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1931             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1932             setAttr.unixModeBits = scp->unixModeBits | 0222;
1933         }
1934     }
1935
1936     if (CleanupCB->LastWriteTime.QuadPart) {
1937         ft.dwLowDateTime = CleanupCB->LastWriteTime.LowPart;
1938         ft.dwHighDateTime = CleanupCB->LastWriteTime.HighPart;
1939
1940         cm_UnixTimeFromLargeSearchTime(&clientModTime, &ft);
1941         if (scp->clientModTime != clientModTime) {
1942             setAttr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1943             setAttr.clientModTime = clientModTime;
1944         }
1945     }
1946
1947     /* call setattr */
1948     if (setAttr.mask) {
1949         lock_ReleaseWrite(&scp->rw);
1950         bScpLocked = FALSE;
1951         code = cm_SetAttr(scp, &setAttr, userp, &req);
1952     } else
1953         code = 0;
1954
1955     /* Now drop the lock enforcing the share access */
1956     if ( CleanupCB->FileAccess != AFS_FILE_ACCESS_NOLOCK) {
1957         unsigned int sLockType;
1958         LARGE_INTEGER LOffset, LLength;
1959
1960         if (CleanupCB->FileAccess == AFS_FILE_ACCESS_SHARED)
1961             sLockType = LOCKING_ANDX_SHARED_LOCK;
1962         else
1963             sLockType = 0;
1964
1965         key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, CleanupCB->Identifier);
1966
1967         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
1968         LOffset.LowPart = SMB_FID_QLOCK_LOW;
1969         LLength.HighPart = 0;
1970         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
1971
1972         if (!bScpLocked) {
1973             lock_ObtainWrite(&scp->rw);
1974             bScpLocked = TRUE;
1975         }
1976
1977         code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_LOCK);
1978         if (code == 0)
1979         {
1980             code = cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, &req);
1981
1982             cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
1983
1984             if (code == CM_ERROR_RANGE_NOT_LOCKED)
1985             {
1986                 osi_Log3(afsd_logp, "RDR_CleanupFileEntry Range Not Locked -- FileAccess 0x%x ProcessId 0x%x HandleId 0x%x",
1987                          CleanupCB->FileAccess, CleanupCB->ProcessId, CleanupCB->Identifier);
1988
1989             }
1990         }
1991     }
1992
1993   on_error:
1994     if (bDscpLocked)
1995         lock_ReleaseWrite(&dscp->rw);
1996     if (bScpLocked)
1997         lock_ReleaseWrite(&scp->rw);
1998
1999     if (dscp && bDeleteFile) {
2000         WCHAR FileName[260];
2001
2002         StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
2003
2004         if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
2005             code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
2006         else
2007             code = cm_Unlink(dscp, NULL, FileName, userp, &req);
2008     }
2009
2010     if ( ResultBufferLength >=  sizeof( AFSFileCleanupResultCB))
2011     {
2012         (*ResultCB)->ResultBufferLength = sizeof( AFSFileCleanupResultCB);
2013         pResultCB = (AFSFileCleanupResultCB *)&(*ResultCB)->ResultData;
2014         pResultCB->ParentDataVersion.QuadPart = dscp ? dscp->dataVersion : 0;
2015     } else {
2016         (*ResultCB)->ResultBufferLength = 0;
2017     }
2018
2019     if (code == 0) {
2020         (*ResultCB)->ResultStatus = 0;
2021         osi_Log0(afsd_logp, "RDR_CleanupFileEntry SUCCESS");
2022     } else {
2023         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2024         (*ResultCB)->ResultStatus = status;
2025         osi_Log2(afsd_logp, "RDR_CleanupFileEntry FAILURE code=0x%x status=0x%x",
2026                   code, status);
2027     }
2028     if (scp)
2029         cm_ReleaseSCache(scp);
2030     if (dscp)
2031         cm_ReleaseSCache(dscp);
2032
2033     return;
2034 }
2035
2036 void
2037 RDR_DeleteFileEntry( IN cm_user_t *userp,
2038                      IN AFSFileID ParentId,
2039                      IN ULONGLONG ProcessId,
2040                      IN WCHAR *FileNameCounted,
2041                      IN DWORD FileNameLength,
2042                      IN BOOL bWow64,
2043                      IN BOOL bCheckOnly,
2044                      IN DWORD ResultBufferLength,
2045                      IN OUT AFSCommResult **ResultCB)
2046 {
2047
2048     AFSFileDeleteResultCB *pResultCB = NULL;
2049     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2050     cm_fid_t            parentFid;
2051     afs_uint32          code;
2052     cm_scache_t *       dscp = NULL;
2053     cm_scache_t *       scp = NULL;
2054     afs_uint32          flags = 0;
2055     cm_attr_t           setAttr;
2056     cm_req_t            req;
2057     DWORD               status;
2058     wchar_t             FileName[260];
2059     cm_key_t            key;
2060
2061     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
2062
2063     osi_Log4(afsd_logp, "RDR_DeleteFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2064               ParentId.Cell,  ParentId.Volume,
2065               ParentId.Vnode, ParentId.Unique);
2066     osi_Log2(afsd_logp, "... name=%S checkOnly=%x",
2067              osi_LogSaveStringW(afsd_logp, FileName),
2068              bCheckOnly);
2069
2070     RDR_InitReq(&req);
2071     if ( bWow64 )
2072         req.flags |= CM_REQ_WOW64;
2073     memset(&setAttr, 0, sizeof(cm_attr_t));
2074
2075     *ResultCB = (AFSCommResult *)malloc( size);
2076     if (!(*ResultCB)) {
2077         osi_Log0(afsd_logp, "RDR_DeleteFileEntry out of memory");
2078         return;
2079     }
2080
2081     memset( *ResultCB,
2082             '\0',
2083             size);
2084
2085     parentFid.cell   = ParentId.Cell;
2086     parentFid.volume = ParentId.Volume;
2087     parentFid.vnode  = ParentId.Vnode;
2088     parentFid.unique = ParentId.Unique;
2089     parentFid.hash   = ParentId.Hash;
2090
2091     code = cm_GetSCache(&parentFid, &dscp, userp, &req);
2092     if (code) {
2093         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2094         if ( status == STATUS_INVALID_HANDLE)
2095             status = STATUS_OBJECT_PATH_INVALID;
2096         (*ResultCB)->ResultStatus = status;
2097         osi_Log2(afsd_logp, "RDR_DeleteFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
2098                   code, status);
2099         return;
2100     }
2101
2102     lock_ObtainWrite(&dscp->rw);
2103
2104     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
2105                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2106     if (code) {
2107         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2108         (*ResultCB)->ResultStatus = status;
2109         (*ResultCB)->ResultBufferLength = 0;
2110         lock_ReleaseWrite(&dscp->rw);
2111         cm_ReleaseSCache(dscp);
2112         osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
2113                  dscp, code, status);
2114         return;
2115     }
2116
2117     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2118     lock_ReleaseWrite(&dscp->rw);
2119
2120     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2121         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2122         cm_ReleaseSCache(dscp);
2123         osi_Log1(afsd_logp, "RDR_DeleteFileEntry Not a Directory dscp=0x%p",
2124                  dscp);
2125         return;
2126     }
2127
2128     code = cm_Lookup(dscp, FileName, 0, userp, &req, &scp);
2129     if (code) {
2130         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2131         (*ResultCB)->ResultStatus = status;
2132         (*ResultCB)->ResultBufferLength = 0;
2133         cm_ReleaseSCache(dscp);
2134         osi_Log2(afsd_logp, "RDR_DeleteFileEntry cm_Lookup failure code=0x%x status=0x%x",
2135                  code, status);
2136         return;
2137     }
2138
2139     lock_ObtainWrite(&scp->rw);
2140     code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_DELETE,
2141                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2142     if (code) {
2143         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2144         (*ResultCB)->ResultStatus = status;
2145         (*ResultCB)->ResultBufferLength = 0;
2146         lock_ReleaseWrite(&scp->rw);
2147         cm_ReleaseSCache(scp);
2148         cm_ReleaseSCache(dscp);
2149         osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
2150                  scp, code, status);
2151         return;
2152     }
2153
2154     if (!bCheckOnly) {
2155         /* Drop all locks since the file is being deleted */
2156         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2157                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2158         if (code) {
2159             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2160             (*ResultCB)->ResultStatus = status;
2161             (*ResultCB)->ResultBufferLength = 0;
2162             lock_ReleaseWrite(&scp->rw);
2163             cm_ReleaseSCache(scp);
2164             cm_ReleaseSCache(dscp);
2165             osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp Lock failure scp=0x%p code=0x%x status=0x%x",
2166                      scp, code, status);
2167         }
2168
2169         /* the scp is now locked and current */
2170         key = cm_GenerateKey(CM_SESSION_IFS, ProcessId, 0);
2171
2172         code = cm_UnlockByKey(scp, key,
2173                               CM_UNLOCK_FLAG_BY_FID,
2174                               userp, &req);
2175
2176         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2177         lock_ReleaseWrite(&scp->rw);
2178
2179         if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
2180             code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
2181         else
2182             code = cm_Unlink(dscp, NULL, FileName, userp, &req);
2183     } else {
2184         lock_ReleaseWrite(&scp->rw);
2185     }
2186
2187     if (code == 0) {
2188         (*ResultCB)->ResultStatus = 0;  // We will be able to fit all the data in here
2189
2190         (*ResultCB)->ResultBufferLength = sizeof( AFSFileDeleteResultCB);
2191
2192         pResultCB = (AFSFileDeleteResultCB *)(*ResultCB)->ResultData;
2193
2194         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
2195         osi_Log0(afsd_logp, "RDR_DeleteFileEntry SUCCESS");
2196     } else {
2197         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2198         (*ResultCB)->ResultStatus = status;
2199         (*ResultCB)->ResultBufferLength = 0;
2200         osi_Log2(afsd_logp, "RDR_DeleteFileEntry FAILURE code=0x%x status=0x%x",
2201                   code, status);
2202     }
2203
2204     cm_ReleaseSCache(dscp);
2205     cm_ReleaseSCache(scp);
2206
2207     return;
2208 }
2209
2210 void
2211 RDR_RenameFileEntry( IN cm_user_t *userp,
2212                      IN WCHAR    *SourceFileNameCounted,
2213                      IN DWORD     SourceFileNameLength,
2214                      IN AFSFileID SourceFileId,
2215                      IN AFSFileRenameCB *pRenameCB,
2216                      IN BOOL bWow64,
2217                      IN DWORD ResultBufferLength,
2218                      IN OUT AFSCommResult **ResultCB)
2219 {
2220
2221     AFSFileRenameResultCB *pResultCB = NULL;
2222     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2223     AFSFileID              SourceParentId   = pRenameCB->SourceParentId;
2224     AFSFileID              TargetParentId   = pRenameCB->TargetParentId;
2225     WCHAR *                TargetFileNameCounted = pRenameCB->TargetName;
2226     DWORD                  TargetFileNameLength = pRenameCB->TargetNameLength;
2227     cm_fid_t               SourceParentFid;
2228     cm_fid_t               TargetParentFid;
2229     cm_fid_t               SourceFid;
2230     cm_fid_t               OrigTargetFid = {0,0,0,0,0};
2231     cm_fid_t               TargetFid;
2232     cm_scache_t *          oldDscp;
2233     cm_scache_t *          newDscp;
2234     cm_dirOp_t dirop;
2235     wchar_t                shortName[13];
2236     wchar_t                SourceFileName[260];
2237     wchar_t                TargetFileName[260];
2238     cm_dirFid_t            dfid;
2239     cm_req_t               req;
2240     afs_uint32             code;
2241     DWORD                  status;
2242
2243     RDR_InitReq(&req);
2244     if ( bWow64 )
2245         req.flags |= CM_REQ_WOW64;
2246
2247     StringCchCopyNW(SourceFileName, 260, SourceFileNameCounted, SourceFileNameLength / sizeof(WCHAR));
2248     StringCchCopyNW(TargetFileName, 260, TargetFileNameCounted, TargetFileNameLength / sizeof(WCHAR));
2249
2250     osi_Log4(afsd_logp, "RDR_RenameFileEntry Source Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2251               SourceParentId.Cell,  SourceParentId.Volume,
2252               SourceParentId.Vnode, SourceParentId.Unique);
2253     osi_Log2(afsd_logp, "... Source Name=%S Length %u", osi_LogSaveStringW(afsd_logp, SourceFileName), SourceFileNameLength);
2254     osi_Log4(afsd_logp, "... Target Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2255               TargetParentId.Cell,  TargetParentId.Volume,
2256               TargetParentId.Vnode, TargetParentId.Unique);
2257     osi_Log2(afsd_logp, "... Target Name=%S Length %u", osi_LogSaveStringW(afsd_logp, TargetFileName), TargetFileNameLength);
2258
2259     *ResultCB = (AFSCommResult *)malloc( size);
2260     if (!(*ResultCB))
2261         return;
2262
2263     memset( *ResultCB,
2264             '\0',
2265             size);
2266
2267     pResultCB = (AFSFileRenameResultCB *)(*ResultCB)->ResultData;
2268
2269     if (SourceFileNameLength == 0 || TargetFileNameLength == 0)
2270     {
2271         osi_Log2(afsd_logp, "RDR_RenameFileEntry Invalid Name Length: src %u target %u",
2272                  SourceFileNameLength, TargetFileNameLength);
2273         (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
2274         return;
2275     }
2276
2277     SourceParentFid.cell   = SourceParentId.Cell;
2278     SourceParentFid.volume = SourceParentId.Volume;
2279     SourceParentFid.vnode  = SourceParentId.Vnode;
2280     SourceParentFid.unique = SourceParentId.Unique;
2281     SourceParentFid.hash   = SourceParentId.Hash;
2282
2283     TargetParentFid.cell   = TargetParentId.Cell;
2284     TargetParentFid.volume = TargetParentId.Volume;
2285     TargetParentFid.vnode  = TargetParentId.Vnode;
2286     TargetParentFid.unique = TargetParentId.Unique;
2287     TargetParentFid.hash   = TargetParentId.Hash;
2288
2289     code = cm_GetSCache(&SourceParentFid, &oldDscp, userp, &req);
2290     if (code) {
2291         osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache source parent failed code 0x%x", code);
2292         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2293         if ( status == STATUS_INVALID_HANDLE)
2294             status = STATUS_OBJECT_PATH_INVALID;
2295         (*ResultCB)->ResultStatus = status;
2296         return;
2297     }
2298
2299     lock_ObtainWrite(&oldDscp->rw);
2300     code = cm_SyncOp(oldDscp, NULL, userp, &req, 0,
2301                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2302     if (code) {
2303         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp oldDscp 0x%p failed code 0x%x", oldDscp, code);
2304         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2305         if ( status == STATUS_INVALID_HANDLE)
2306             status = STATUS_OBJECT_PATH_INVALID;
2307         (*ResultCB)->ResultStatus = status;
2308         lock_ReleaseWrite(&oldDscp->rw);
2309         cm_ReleaseSCache(oldDscp);
2310         return;
2311     }
2312
2313     cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2314     lock_ReleaseWrite(&oldDscp->rw);
2315
2316
2317     if (oldDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2318         osi_Log1(afsd_logp, "RDR_RenameFileEntry oldDscp 0x%p not a directory", oldDscp);
2319         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2320         cm_ReleaseSCache(oldDscp);
2321         return;
2322     }
2323
2324     code = cm_GetSCache(&TargetParentFid, &newDscp, userp, &req);
2325     if (code) {
2326         osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache target parent failed code 0x%x", code);
2327         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2328         (*ResultCB)->ResultStatus = status;
2329         cm_ReleaseSCache(oldDscp);
2330         return;
2331     }
2332
2333     lock_ObtainWrite(&newDscp->rw);
2334     code = cm_SyncOp(newDscp, NULL, userp, &req, 0,
2335                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2336     if (code) {
2337         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp newDscp 0x%p failed code 0x%x", newDscp, code);
2338         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2339         (*ResultCB)->ResultStatus = status;
2340         lock_ReleaseWrite(&newDscp->rw);
2341         cm_ReleaseSCache(oldDscp);
2342         cm_ReleaseSCache(newDscp);
2343         return;
2344     }
2345
2346     cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2347     lock_ReleaseWrite(&newDscp->rw);
2348
2349
2350     if (newDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2351         osi_Log1(afsd_logp, "RDR_RenameFileEntry newDscp 0x%p not a directory", newDscp);
2352         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2353         cm_ReleaseSCache(oldDscp);
2354         cm_ReleaseSCache(newDscp);
2355         return;
2356     }
2357
2358     /* Obtain the original FID just for debugging purposes */
2359     code = cm_BeginDirOp( oldDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2360     if (code == 0) {
2361         code = cm_BPlusDirLookup(&dirop, SourceFileName, &SourceFid);
2362         code = cm_BPlusDirLookup(&dirop, TargetFileName, &OrigTargetFid);
2363         cm_EndDirOp(&dirop);
2364     }
2365
2366     code = cm_Rename( oldDscp, NULL, SourceFileName,
2367                       newDscp, TargetFileName, userp, &req);
2368     if (code == 0) {
2369         cm_scache_t *scp = 0;
2370         DWORD dwRemaining;
2371
2372         (*ResultCB)->ResultBufferLength = ResultBufferLength;
2373         dwRemaining = ResultBufferLength - sizeof( AFSFileRenameResultCB) + sizeof( AFSDirEnumEntry);
2374         (*ResultCB)->ResultStatus = 0;
2375
2376         pResultCB->SourceParentDataVersion.QuadPart = oldDscp->dataVersion;
2377         pResultCB->TargetParentDataVersion.QuadPart = newDscp->dataVersion;
2378
2379         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_Rename oldDscp 0x%p newDscp 0x%p SUCCESS",
2380                  oldDscp, newDscp);
2381
2382         code = cm_BeginDirOp( newDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2383         if (code == 0) {
2384             code = cm_BPlusDirLookup(&dirop, TargetFileName, &TargetFid);
2385             cm_EndDirOp(&dirop);
2386         }
2387
2388         if (code != 0) {
2389             osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_BPlusDirLookup failed code 0x%x",
2390                      code);
2391             (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
2392             cm_ReleaseSCache(oldDscp);
2393             cm_ReleaseSCache(newDscp);
2394             return;
2395         }
2396
2397         osi_Log4(afsd_logp, "RDR_RenameFileEntry Target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2398                   TargetFid.cell,  TargetFid.volume,
2399                   TargetFid.vnode, TargetFid.unique);
2400
2401         code = cm_GetSCache(&TargetFid, &scp, userp, &req);
2402         if (code) {
2403             osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache target failed code 0x%x", code);
2404             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2405             (*ResultCB)->ResultStatus = status;
2406             cm_ReleaseSCache(oldDscp);
2407             cm_ReleaseSCache(newDscp);
2408             return;
2409         }
2410
2411         /* Make sure the source vnode is current */
2412         lock_ObtainWrite(&scp->rw);
2413         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2414                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2415         if (code) {
2416             osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp scp 0x%p failed code 0x%x", scp, code);
2417             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2418             (*ResultCB)->ResultStatus = status;
2419             lock_ReleaseWrite(&scp->rw);
2420             cm_ReleaseSCache(oldDscp);
2421             cm_ReleaseSCache(newDscp);
2422             cm_ReleaseSCache(scp);
2423             return;
2424         }
2425
2426         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2427         lock_ReleaseWrite(&scp->rw);
2428
2429         dfid.vnode = htonl(scp->fid.vnode);
2430         dfid.unique = htonl(scp->fid.unique);
2431
2432         if (!cm_Is8Dot3(TargetFileName))
2433             cm_Gen8Dot3NameIntW(TargetFileName, &dfid, shortName, NULL);
2434         else
2435             shortName[0] = '\0';
2436
2437         RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
2438                                  newDscp, scp, userp, &req, TargetFileName, shortName,
2439                                  RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
2440                                  0, NULL, &dwRemaining);
2441         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
2442         cm_ReleaseSCache(scp);
2443
2444         osi_Log0(afsd_logp, "RDR_RenameFileEntry SUCCESS");
2445     } else {
2446         osi_Log3(afsd_logp, "RDR_RenameFileEntry cm_Rename oldDscp 0x%p newDscp 0x%p failed code 0x%x",
2447                  oldDscp, newDscp, code);
2448         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2449         (*ResultCB)->ResultStatus = status;
2450         (*ResultCB)->ResultBufferLength = 0;
2451     }
2452
2453     cm_ReleaseSCache(oldDscp);
2454     cm_ReleaseSCache(newDscp);
2455     return;
2456 }
2457
2458 void
2459 RDR_FlushFileEntry( IN cm_user_t *userp,
2460                     IN AFSFileID FileId,
2461                     IN BOOL bWow64,
2462                     IN DWORD ResultBufferLength,
2463                     IN OUT AFSCommResult **ResultCB)
2464 {
2465     cm_scache_t *scp = NULL;
2466     cm_fid_t    Fid;
2467     afs_uint32  code;
2468     cm_req_t    req;
2469     DWORD       status;
2470 #ifdef ODS_DEBUG
2471     char        dbgstr[1024];
2472 #endif
2473
2474     RDR_InitReq(&req);
2475     if ( bWow64 )
2476         req.flags |= CM_REQ_WOW64;
2477
2478     osi_Log4(afsd_logp, "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x",
2479               FileId.Cell, FileId.Volume,
2480               FileId.Vnode, FileId.Unique);
2481 #ifdef ODS_DEBUG
2482     snprintf( dbgstr, 1024,
2483               "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x\n",
2484               FileId.Cell, FileId.Volume,
2485               FileId.Vnode, FileId.Unique);
2486     OutputDebugStringA( dbgstr);
2487 #endif
2488
2489     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
2490     if (!(*ResultCB)) {
2491         osi_Log0(afsd_logp, "RDR_FlushFileEntry out of memory");
2492         return;
2493     }
2494
2495     memset( *ResultCB,
2496             '\0',
2497             sizeof( AFSCommResult));
2498
2499     /* Process the release */
2500     Fid.cell = FileId.Cell;
2501     Fid.volume = FileId.Volume;
2502     Fid.vnode = FileId.Vnode;
2503     Fid.unique = FileId.Unique;
2504     Fid.hash = FileId.Hash;
2505
2506     code = cm_GetSCache(&Fid, &scp, userp, &req);
2507     if (code) {
2508         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2509         (*ResultCB)->ResultStatus = status;
2510         osi_Log2(afsd_logp, "RDR_FlushFileEntry cm_GetSCache FID failure code=0x%x status=0x%x",
2511                   code, status);
2512         return;
2513     }
2514
2515     lock_ObtainWrite(&scp->rw);
2516     if (scp->flags & CM_SCACHEFLAG_DELETED) {
2517         lock_ReleaseWrite(&scp->rw);
2518         (*ResultCB)->ResultStatus = STATUS_INVALID_HANDLE;
2519         return;
2520     }
2521
2522     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2523                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2524     if (code) {
2525         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2526         (*ResultCB)->ResultStatus = status;
2527         lock_ReleaseWrite(&scp->rw);
2528         cm_ReleaseSCache(scp);
2529         osi_Log3(afsd_logp, "RDR_FlushFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
2530                  scp, code, status);
2531         return;
2532     }
2533
2534     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2535     lock_ReleaseWrite(&scp->rw);
2536
2537     code = cm_FSync(scp, userp, &req, FALSE);
2538     cm_ReleaseSCache(scp);
2539
2540     if (code) {
2541         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2542         (*ResultCB)->ResultStatus = status;
2543         osi_Log2(afsd_logp, "RDR_FlushFileEntry FAILURE code=0x%x status=0x%x",
2544                   code, status);
2545     } else {
2546         (*ResultCB)->ResultStatus = 0;
2547         osi_Log0(afsd_logp, "RDR_FlushFileEntry SUCCESS");
2548     }
2549     (*ResultCB)->ResultBufferLength = 0;
2550
2551     return;
2552 }
2553
2554 afs_uint32
2555 RDR_CheckAccess( IN cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
2556                  ULONG access,
2557                  ULONG *granted)
2558 {
2559     ULONG afs_acc, afs_gr;
2560     BOOLEAN file, dir;
2561     afs_uint32 code = 0;
2562
2563     file = (scp->fileType == CM_SCACHETYPE_FILE);
2564     dir = !file;
2565
2566     /* access definitions from prs_fs.h */
2567     afs_acc = 0;
2568     if (access & FILE_READ_DATA)
2569         afs_acc |= PRSFS_READ;
2570     if (access & FILE_READ_EA || access & FILE_READ_ATTRIBUTES)
2571         afs_acc |= PRSFS_READ;
2572     if (file && ((access & FILE_WRITE_DATA) || (access & FILE_APPEND_DATA)))
2573         afs_acc |= PRSFS_WRITE;
2574     if (access & FILE_WRITE_EA || access & FILE_WRITE_ATTRIBUTES)
2575         afs_acc |= PRSFS_WRITE;
2576     if (dir && ((access & FILE_ADD_FILE) || (access & FILE_ADD_SUBDIRECTORY)))
2577         afs_acc |= PRSFS_INSERT;
2578     if (dir && (access & FILE_LIST_DIRECTORY))
2579         afs_acc |= PRSFS_LOOKUP;
2580     if (file && (access & FILE_EXECUTE))
2581         afs_acc |= PRSFS_WRITE;
2582     if (dir && (access & FILE_TRAVERSE))
2583         afs_acc |= PRSFS_READ;
2584     if (dir && (access & FILE_DELETE_CHILD))
2585         afs_acc |= PRSFS_DELETE;
2586     if ((access & DELETE))
2587         afs_acc |= PRSFS_DELETE;
2588
2589     /* check ACL with server */
2590     lock_ObtainWrite(&scp->rw);
2591     while (1)
2592     {
2593         if (cm_HaveAccessRights(scp, userp, reqp, afs_acc, &afs_gr))
2594         {
2595             break;
2596         }
2597         else
2598         {
2599             /* we don't know the required access rights */
2600             code = cm_GetAccessRights(scp, userp, reqp);
2601             if (code)
2602                 break;
2603             continue;
2604         }
2605     }
2606     lock_ReleaseWrite(&(scp->rw));
2607
2608     if (code == 0) {
2609         *granted = 0;
2610         if (afs_gr & PRSFS_READ)
2611             *granted |= FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE;
2612         if (afs_gr & PRSFS_WRITE)
2613             *granted |= FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_EXECUTE;
2614         if (afs_gr & PRSFS_INSERT)
2615             *granted |= (dir ? FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY : 0) | (file ? FILE_ADD_SUBDIRECTORY : 0);
2616         if (afs_gr & PRSFS_LOOKUP)
2617             *granted |= (dir ? FILE_LIST_DIRECTORY : 0);
2618         if (afs_gr & PRSFS_DELETE)
2619             *granted |= FILE_DELETE_CHILD | DELETE;
2620         if (afs_gr & PRSFS_LOCK)
2621             *granted |= 0;
2622         if (afs_gr & PRSFS_ADMINISTER)
2623             *granted |= 0;
2624
2625         *granted |= SYNCHRONIZE | READ_CONTROL;
2626
2627         /* don't give more access than what was requested */
2628         *granted &= access;
2629         osi_Log3(afsd_logp, "RDR_CheckAccess SUCCESS scp=0x%p requested=0x%x granted=0x%x", scp, access, *granted);
2630     } else
2631         osi_Log2(afsd_logp, "RDR_CheckAccess FAILURE scp=0x%p code=0x%x",
2632                  scp, code);
2633
2634     return code;
2635 }
2636
2637 void
2638 RDR_OpenFileEntry( IN cm_user_t *userp,
2639                    IN AFSFileID FileId,
2640                    IN AFSFileOpenCB *OpenCB,
2641                    IN BOOL bWow64,
2642                    IN BOOL bHoldFid,
2643                    IN DWORD ResultBufferLength,
2644                    IN OUT AFSCommResult **ResultCB)
2645 {
2646     AFSFileOpenResultCB *pResultCB = NULL;
2647     cm_scache_t *scp = NULL;
2648     cm_user_t   *sysUserp = NULL;
2649     cm_fid_t    Fid;
2650     cm_lock_data_t      *ldp = NULL;
2651     afs_uint32  code;
2652     cm_req_t    req;
2653     DWORD       status;
2654
2655     RDR_InitReq(&req);
2656     if ( bWow64 )
2657         req.flags |= CM_REQ_WOW64;
2658
2659     osi_Log4(afsd_logp, "RDR_OpenFileEntry File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2660               FileId.Cell, FileId.Volume,
2661               FileId.Vnode, FileId.Unique);
2662
2663     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof( AFSFileOpenResultCB));
2664     if (!(*ResultCB)) {
2665         osi_Log0(afsd_logp, "RDR_OpenFileEntry out of memory");
2666         return;
2667     }
2668
2669     memset( *ResultCB,
2670             '\0',
2671             sizeof( AFSCommResult) + sizeof( AFSFileOpenResultCB));
2672
2673     pResultCB = (AFSFileOpenResultCB *)(*ResultCB)->ResultData;
2674
2675     /* Process the release */
2676     Fid.cell = FileId.Cell;
2677     Fid.volume = FileId.Volume;
2678     Fid.vnode = FileId.Vnode;
2679     Fid.unique = FileId.Unique;
2680     Fid.hash = FileId.Hash;
2681
2682     code = cm_GetSCache(&Fid, &scp, userp, &req);
2683     if (code) {
2684         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2685         (*ResultCB)->ResultStatus = status;
2686         osi_Log2(afsd_logp, "RDR_OpenFileEntry cm_GetSCache FID failure code=0x%x status=0x%x",
2687                   code, status);
2688         return;
2689     }
2690
2691     lock_ObtainWrite(&scp->rw);
2692     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2693                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2694     if (code) {
2695         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2696         (*ResultCB)->ResultStatus = status;
2697         lock_ReleaseWrite(&scp->rw);
2698         cm_ReleaseSCache(scp);
2699         osi_Log3(afsd_logp, "RDR_OpenFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
2700                  scp, code, status);
2701         return;
2702     }
2703
2704     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2705     lock_ReleaseWrite(&scp->rw);
2706
2707     sysUserp = RDR_GetLocalSystemUser();
2708
2709     /*
2710      * Skip the open check if the request is coming from the local system account.
2711      * The local system has no tokens and therefore any requests sent to a file
2712      * server will fail.  Unfortunately, there are special system processes that
2713      * perform actions on files and directories in preparation for memory mapping
2714      * executables.  If the open check fails, the real request from the user process
2715      * will never be issued.
2716      *
2717      * Permitting the file system to allow subsequent operations to proceed does
2718      * not compromise security.  All requests to obtain file data or directory
2719      * enumerations will subsequently fail if they are not submitted under the
2720      * context of a process for that have access to the necessary credentials.
2721      */
2722
2723     if ( userp == sysUserp)
2724     {
2725         osi_Log1(afsd_logp, "RDR_OpenFileEntry LOCAL_SYSTEM access check skipped scp=0x%p",
2726                  scp);
2727         pResultCB->GrantedAccess = OpenCB->DesiredAccess;
2728         pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
2729         code = 0;
2730     }
2731     else
2732     {
2733         int count = 0;
2734
2735         do {
2736             if (count++ > 0) {
2737                 Sleep(350);
2738                 osi_Log3(afsd_logp,
2739                          "RDR_OpenFileEntry repeating open check scp=0x%p userp=0x%p code=0x%x",
2740                          scp, userp, code);
2741             }
2742             code = cm_CheckNTOpen(scp, OpenCB->DesiredAccess, OpenCB->ShareAccess,
2743                                   OPEN_ALWAYS,
2744                                   OpenCB->ProcessId, OpenCB->Identifier,
2745                                   userp, &req, &ldp);
2746             if (code == 0)
2747                 code = RDR_CheckAccess(scp, userp, &req, OpenCB->DesiredAccess, &pResultCB->GrantedAccess);
2748             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
2749         } while (count < 100 && (code == CM_ERROR_RETRY || code == CM_ERROR_WOULDBLOCK));
2750     }
2751
2752     /*
2753      * If we are restricting sharing, we should do so with a suitable
2754      * share lock.
2755      */
2756     if (code == 0 && scp->fileType == CM_SCACHETYPE_FILE && !(OpenCB->ShareAccess & FILE_SHARE_WRITE)) {
2757         cm_key_t key;
2758         LARGE_INTEGER LOffset, LLength;
2759         int sLockType;
2760
2761         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
2762         LOffset.LowPart = SMB_FID_QLOCK_LOW;
2763         LLength.HighPart = 0;
2764         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
2765
2766         /*
2767          * If we are not opening the file for writing, then we don't
2768          * try to get an exclusive lock.  No one else should be able to
2769          * get an exclusive lock on the file anyway, although someone
2770          * else can get a shared lock.
2771          */
2772         if ((OpenCB->ShareAccess & FILE_SHARE_READ) || !(OpenCB->DesiredAccess & AFS_ACCESS_WRITE))
2773         {
2774             sLockType = LOCKING_ANDX_SHARED_LOCK;
2775         } else {
2776             sLockType = 0;
2777         }
2778
2779         key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, OpenCB->Identifier);
2780
2781         lock_ObtainWrite(&scp->rw);
2782         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
2783         lock_ReleaseWrite(&scp->rw);
2784
2785         if (code) {
2786             code = CM_ERROR_SHARING_VIOLATION;
2787             pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
2788         } else {
2789             if (sLockType == LOCKING_ANDX_SHARED_LOCK)
2790                 pResultCB->FileAccess = AFS_FILE_ACCESS_SHARED;
2791             else
2792                 pResultCB->FileAccess = AFS_FILE_ACCESS_EXCLUSIVE;
2793         }
2794     } else {
2795         pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
2796     }
2797
2798     cm_ReleaseUser(sysUserp);
2799     if (code == 0 && bHoldFid)
2800         RDR_FlagScpInUse( scp, FALSE );
2801     cm_ReleaseSCache(scp);
2802
2803     if (code) {
2804         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2805         (*ResultCB)->ResultStatus = status;
2806         osi_Log2(afsd_logp, "RDR_OpenFileEntry FAILURE code=0x%x status=0x%x",
2807                   code, status);
2808     } else {
2809         (*ResultCB)->ResultStatus = 0;
2810         (*ResultCB)->ResultBufferLength = sizeof( AFSFileOpenResultCB);
2811         osi_Log0(afsd_logp, "RDR_OpenFileEntry SUCCESS");
2812     }
2813     return;
2814 }
2815
2816 void
2817 RDR_ReleaseFileAccess( IN cm_user_t *userp,
2818                        IN AFSFileID FileId,
2819                        IN AFSFileAccessReleaseCB *ReleaseFileCB,
2820                        IN BOOL bWow64,
2821                        IN DWORD ResultBufferLength,
2822                        IN OUT AFSCommResult **ResultCB)
2823 {
2824     cm_key_t key;
2825     unsigned int sLockType;
2826     LARGE_INTEGER LOffset, LLength;
2827     cm_scache_t *scp = NULL;
2828     cm_fid_t    Fid;
2829     afs_uint32  code;
2830     cm_req_t    req;
2831     DWORD       status;
2832
2833     RDR_InitReq(&req);
2834     if ( bWow64 )
2835         req.flags |= CM_REQ_WOW64;
2836
2837     osi_Log4(afsd_logp, "RDR_ReleaseFileAccess File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2838               FileId.Cell, FileId.Volume,
2839               FileId.Vnode, FileId.Unique);
2840
2841     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
2842     if (!(*ResultCB)) {
2843         osi_Log0(afsd_logp, "RDR_ReleaseFileAccess out of memory");
2844         return;
2845     }
2846
2847     memset( *ResultCB, '\0', sizeof( AFSCommResult));
2848
2849     if (ReleaseFileCB->FileAccess == AFS_FILE_ACCESS_NOLOCK)
2850         return;
2851
2852     /* Process the release */
2853     Fid.cell = FileId.Cell;
2854     Fid.volume = FileId.Volume;
2855     Fid.vnode = FileId.Vnode;
2856     Fid.unique = FileId.Unique;
2857     Fid.hash = FileId.Hash;
2858
2859     code = cm_GetSCache(&Fid, &scp, userp, &req);
2860     if (code) {
2861         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2862         (*ResultCB)->ResultStatus = status;
2863         osi_Log2(afsd_logp, "RDR_ReleaseFileAccess cm_GetSCache FID failure code=0x%x status=0x%x",
2864                   code, status);
2865         return;
2866     }
2867
2868     if (ReleaseFileCB->FileAccess == AFS_FILE_ACCESS_SHARED)
2869         sLockType = LOCKING_ANDX_SHARED_LOCK;
2870     else
2871         sLockType = 0;
2872
2873     key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, ReleaseFileCB->Identifier);
2874
2875     LOffset.HighPart = SMB_FID_QLOCK_HIGH;
2876     LOffset.LowPart = SMB_FID_QLOCK_LOW;
2877     LLength.HighPart = 0;
2878     LLength.LowPart = SMB_FID_QLOCK_LENGTH;
2879
2880     lock_ObtainWrite(&scp->rw);
2881
2882     code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_LOCK);
2883     if (code == 0)
2884     {
2885         code = cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, &req);
2886
2887         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2888
2889         if (code == CM_ERROR_RANGE_NOT_LOCKED)
2890         {
2891             osi_Log3(afsd_logp, "RDR_ReleaseFileAccess Range Not Locked -- FileAccess 0x%x ProcessId 0x%x HandleId 0x%x",
2892                      ReleaseFileCB->FileAccess, ReleaseFileCB->ProcessId, ReleaseFileCB->Identifier);
2893         }
2894     }
2895
2896     lock_ReleaseWrite(&scp->rw);
2897
2898     osi_Log0(afsd_logp, "RDR_ReleaseFileAccessEntry SUCCESS");
2899 }
2900
2901 static const char *
2902 HexCheckSum(unsigned char * buf, int buflen, unsigned char * md5cksum)
2903 {
2904     int i, k;
2905     static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
2906
2907     if (buflen < 33)
2908         return "buffer length too small to HexCheckSum";
2909
2910     for (i=0;i<16;i++) {
2911         k = md5cksum[i];
2912
2913         buf[i*2] = tr[k / 16];
2914         buf[i*2+1] = tr[k % 16];
2915     }
2916     buf[32] = '\0';
2917
2918     return buf;
2919 }
2920
2921 /*
2922  * Extent requests from the file system are triggered when a file
2923  * page is not resident in the Windows cache.  The file system is
2924  * responsible for loading the page but cannot block the request
2925  * while doing so.  The AFS Redirector forwards the requests to
2926  * the AFS cache manager while indicating to Windows that the page
2927  * is not yet available.  A polling operation will then ensue with
2928  * the AFS Redirector issuing a RDR_RequestFileExtentsXXX call for
2929  * each poll attempt.  As each request is received and processed
2930  * by a separate worker thread in the service, this can lead to
2931  * contention by multiple threads attempting to claim the same
2932  * cm_buf_t objects.  Therefore, it is important that
2933  *
2934  *  (a) the service avoid processing more than one overlapping
2935  *      extent request at a time
2936  *  (b) background daemon processing be used to avoid blocking
2937  *      of ioctl threads
2938  *
2939  * Beginning with the 20091122 build of the redirector, the redirector
2940  * will not issue an additional RDR_RequestFileExtentsXXX call for
2941  * each poll request.  Instead, afsd_service is required to track
2942  * the requests and return them to the redirector or fail the
2943  * portions of the request that cannot be satisfied.
2944  *
2945  * The request processing returns any extents that can be returned
2946  * immediately to the redirector.  The rest of the requested range(s)
2947  * are queued as background operations using RDR_BkgFetch().
2948  */
2949
2950 /* do the background fetch. */
2951 afs_int32
2952 RDR_BkgFetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
2953              cm_user_t *userp, cm_req_t *reqp)
2954 {
2955     osi_hyper_t length;
2956     osi_hyper_t base;
2957     osi_hyper_t offset;
2958     osi_hyper_t end;
2959     osi_hyper_t fetched;
2960     osi_hyper_t tblocksize;
2961     afs_int32 code;
2962     int rwheld = 0;
2963     cm_buf_t *bufp = NULL;
2964     DWORD dwResultBufferLength;
2965     AFSSetFileExtentsCB *pResultCB;
2966     DWORD status;
2967     afs_uint32 count=0;
2968     AFSFileID FileId;
2969     int reportErrorToRedir = 0;
2970     int force_retry = 0;
2971
2972     FileId.Cell = scp->fid.cell;
2973     FileId.Volume = scp->fid.volume;
2974     FileId.Vnode = scp->fid.vnode;
2975     FileId.Unique = scp->fid.unique;
2976     FileId.Hash = scp->fid.hash;
2977
2978     if ((GetTickCount() - reqp->startTime) / 1000 > HardDeadtimeout * 5) {
2979         RDR_SetFileStatus( &scp->fid, &userp->authgroup, STATUS_IO_TIMEOUT);
2980         return 0;
2981     }
2982
2983     fetched.LowPart = 0;
2984     fetched.HighPart = 0;
2985     tblocksize = ConvertLongToLargeInteger(cm_data.buf_blockSize);
2986     base.LowPart = p1;
2987     base.HighPart = p2;
2988     length.LowPart = p3;
2989     length.HighPart = p4;
2990
2991     end = LargeIntegerAdd(base, length);
2992
2993     osi_Log5(afsd_logp, "Starting BKG Fetch scp 0x%p offset 0x%x:%x length 0x%x:%x",
2994              scp, p2, p1, p4, p3);
2995
2996     /*
2997      * Make sure we have a callback.
2998      * This is necessary so that we can return access denied
2999      * if a callback cannot be granted.
3000      */
3001     lock_ObtainWrite(&scp->rw);
3002     code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_READ,
3003                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3004     if (code) {
3005         lock_ReleaseWrite(&scp->rw);
3006         osi_Log2(afsd_logp, "RDR_BkgFetch cm_SyncOp failure scp=0x%p code=0x%x",
3007                  scp, code);
3008         smb_MapNTError(cm_MapRPCError(code, reqp), &status, TRUE);
3009         RDR_SetFileStatus( &scp->fid, &userp->authgroup, status);
3010         return code;
3011     }
3012     lock_ReleaseWrite(&scp->rw);
3013
3014     dwResultBufferLength = (DWORD)(sizeof( AFSSetFileExtentsCB) + sizeof( AFSSetFileExtentsCB) * (length.QuadPart / cm_data.blockSize + 1));
3015     pResultCB = (AFSSetFileExtentsCB *)malloc( dwResultBufferLength );
3016     if (!pResultCB)
3017         return CM_ERROR_RETRY;
3018
3019     memset( pResultCB, '\0', dwResultBufferLength );
3020     pResultCB->FileId = FileId;
3021
3022     for ( code = 0, offset = base;
3023           code == 0 && LargeIntegerLessThan(offset, end);
3024           offset = LargeIntegerAdd(offset, tblocksize) )
3025     {
3026         int bBufRelease = TRUE;
3027
3028         if (rwheld) {
3029             lock_ReleaseWrite(&scp->rw);
3030             rwheld = 0;
3031         }
3032
3033         code = buf_Get(scp, &offset, reqp, &bufp);
3034         if (code) {
3035             /*
3036              * any error from buf_Get() is non-fatal.
3037              * we need to re-queue this extent fetch.
3038              */
3039             force_retry = 1;
3040             break;
3041         }
3042
3043         if (!rwheld) {
3044             lock_ObtainWrite(&scp->rw);
3045             rwheld = 1;
3046         }
3047
3048         code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
3049         if (code == 0) {
3050             if (!(bufp->qFlags & CM_BUF_QREDIR)) {
3051 #ifdef VALIDATE_CHECK_SUM
3052 #ifdef ODS_DEBUG
3053                 char md5dbg[33];
3054                 char dbgstr[1024];
3055 #endif
3056 #endif
3057                 if (bufp->flags & CM_BUF_DIRTY)
3058                     cm_BufWrite(scp, &bufp->offset, cm_data.buf_blockSize, CM_BUF_WRITE_SCP_LOCKED, userp, reqp);
3059
3060                 lock_ObtainWrite(&buf_globalLock);
3061                 if (!(bufp->flags & CM_BUF_DIRTY) &&
3062                     bufp->cmFlags == 0 &&
3063                     !(bufp->qFlags & CM_BUF_QREDIR)) {
3064                     buf_InsertToRedirQueue(scp, bufp);
3065                     lock_ReleaseWrite(&buf_globalLock);
3066
3067 #ifdef VALIDATE_CHECK_SUM
3068                     buf_ComputeCheckSum(bufp);
3069 #endif
3070                     pResultCB->FileExtents[count].Flags = 0;
3071                     pResultCB->FileExtents[count].FileOffset.QuadPart = bufp->offset.QuadPart;
3072                     pResultCB->FileExtents[count].CacheOffset.QuadPart = bufp->datap - RDR_extentBaseAddress;
3073                     pResultCB->FileExtents[count].Length = cm_data.blockSize;
3074                     count++;
3075                     fetched = LargeIntegerAdd(fetched, tblocksize);
3076                     bBufRelease = FALSE;
3077
3078 #ifdef VALIDATE_CHECK_SUM
3079 #ifdef ODS_DEBUG
3080                     HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
3081                     snprintf( dbgstr, 1024,
3082                               "RDR_BkgFetch md5 %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3083                               md5dbg,
3084                               scp->fid.volume, scp->fid.vnode, scp->fid.unique,
3085                               pResultCB->FileExtents[count].FileOffset.HighPart,
3086                               pResultCB->FileExtents[count].FileOffset.LowPart,
3087                               pResultCB->FileExtents[count].CacheOffset.HighPart,
3088                               pResultCB->FileExtents[count].CacheOffset.LowPart);
3089                     OutputDebugStringA( dbgstr);
3090 #endif
3091 #endif
3092                     osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3093                               bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3094                 } else {
3095                     lock_ReleaseWrite(&buf_globalLock);
3096                     if ((bufp->cmFlags != 0) || (bufp->flags & CM_BUF_DIRTY)) {
3097                         /* An I/O operation is already in progress */
3098                         force_retry = 1;
3099                         osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS Not delivering to Redirector Dirty or Busy bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3100                                   bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3101                     } else {
3102                         osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3103                                   bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3104                     }
3105                 }
3106             } else {
3107                 osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3108                           bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3109             }
3110         } else {
3111             /*
3112              * depending on what the error from cm_GetBuffer is
3113              * it may or may not be fatal.  Only return fatal errors.
3114              * Re-queue a request for others.
3115              */
3116             osi_Log5(afsd_logp, "RDR_BkgFetch Extent2FS FAILURE bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x code 0x%x",
3117                       bufp, offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize, code);
3118             switch (code) {
3119             case CM_ERROR_NOACCESS:
3120             case CM_ERROR_NOSUCHFILE:
3121             case CM_ERROR_NOSUCHPATH:
3122             case CM_ERROR_NOSUCHVOLUME:
3123             case CM_ERROR_NOSUCHCELL:
3124             case CM_ERROR_INVAL:
3125             case CM_ERROR_BADFD:
3126             case CM_ERROR_CLOCKSKEW:
3127             case RXKADNOAUTH:
3128             case CM_ERROR_QUOTA:
3129             case CM_ERROR_LOCK_CONFLICT:
3130                 /*
3131                  * these are fatal errors.  deliver what we can
3132                  * and halt.
3133                  */
3134                 reportErrorToRedir = 1;
3135                 break;
3136             default:
3137                 /*
3138                  * non-fatal errors.  re-queue the exent
3139                  */
3140                 code = CM_ERROR_RETRY;
3141                 force_retry = 1;
3142             }
3143         }
3144
3145         if (bBufRelease)
3146             buf_Release(bufp);
3147     }
3148
3149     if (!rwheld) {
3150         lock_ObtainWrite(&scp->rw);
3151         rwheld = 1;
3152     }
3153
3154     /* wakeup anyone who is waiting */
3155     if (scp->flags & CM_SCACHEFLAG_WAITING) {
3156         osi_Log1(afsd_logp, "RDR Bkg Fetch Waking scp 0x%p", scp);
3157         osi_Wakeup((LONG_PTR) &scp->flags);
3158     }
3159     lock_ReleaseWrite(&scp->rw);
3160
3161     if (count > 0) {
3162         pResultCB->ExtentCount = count;
3163         RDR_SetFileExtents( pResultCB, dwResultBufferLength);
3164     }
3165     free(pResultCB);
3166
3167     if (reportErrorToRedir) {
3168         smb_MapNTError(cm_MapRPCError(code, reqp), &status, TRUE);
3169         RDR_SetFileStatus( &scp->fid, &userp->authgroup, status);
3170     }
3171
3172     osi_Log4(afsd_logp, "Ending BKG Fetch scp 0x%p code 0x%x fetched 0x%x:%x",
3173              scp, code, fetched.HighPart, fetched.LowPart);
3174
3175     return force_retry ? CM_ERROR_RETRY : code;
3176 }
3177
3178
3179 BOOL
3180 RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
3181                              IN AFSFileID FileId,
3182                              IN AFSRequestExtentsCB *RequestExtentsCB,
3183                              IN BOOL bWow64,
3184                              IN OUT DWORD * ResultBufferLength,
3185                              IN OUT AFSSetFileExtentsCB **ResultCB)
3186 {
3187     AFSSetFileExtentsCB *pResultCB = NULL;
3188     DWORD Length;
3189     DWORD count;
3190     DWORD status;
3191     cm_scache_t *scp = NULL;
3192     cm_fid_t    Fid;
3193     cm_buf_t    *bufp;
3194     afs_uint32  code = 0;
3195     osi_hyper_t thyper;
3196     LARGE_INTEGER ByteOffset, BeginOffset, EndOffset, QueueOffset;
3197     afs_uint32  QueueLength;
3198     cm_req_t    req;
3199     BOOLEAN     bBufRelease = TRUE;
3200
3201     RDR_InitReq(&req);
3202     if ( bWow64 )
3203         req.flags |= CM_REQ_WOW64;
3204     req.flags |= CM_REQ_NORETRY;
3205
3206     osi_Log4(afsd_logp, "RDR_RequestFileExtentsAsync File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
3207               FileId.Cell, FileId.Volume,
3208               FileId.Vnode, FileId.Unique);
3209     osi_Log4(afsd_logp, "... Flags 0x%x ByteOffset 0x%x:%x Length 0x%x",
3210              RequestExtentsCB->Flags,
3211              RequestExtentsCB->ByteOffset.HighPart, RequestExtentsCB->ByteOffset.LowPart,
3212              RequestExtentsCB->Length);
3213     Length = sizeof( AFSSetFileExtentsCB) + sizeof( AFSFileExtentCB) * (RequestExtentsCB->Length / cm_data.blockSize + 1);
3214
3215     pResultCB = *ResultCB = (AFSSetFileExtentsCB *)malloc( Length );
3216     if (*ResultCB == NULL) {
3217         *ResultBufferLength = 0;
3218         return FALSE;
3219     }
3220     *ResultBufferLength = Length;
3221
3222     memset( pResultCB, '\0', Length );
3223     pResultCB->FileId = FileId;
3224
3225     Fid.cell = FileId.Cell;
3226     Fid.volume = FileId.Volume;
3227     Fid.vnode = FileId.Vnode;
3228     Fid.unique = FileId.Unique;
3229     Fid.hash = FileId.Hash;
3230
3231     code = cm_GetSCache(&Fid, &scp, userp, &req);
3232     if (code) {
3233         osi_Log1(afsd_logp, "RDR_RequestFileExtentsAsync cm_GetSCache FID failure code=0x%x",
3234                   code);
3235         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3236         return FALSE;
3237     }
3238
3239     /*
3240      * Make sure we have a callback.
3241      * This is necessary so that we can return access denied
3242      * if a callback cannot be granted.
3243      */
3244     lock_ObtainWrite(&scp->rw);
3245     code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
3246                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3247     lock_ReleaseWrite(&scp->rw);
3248     if (code) {
3249         cm_ReleaseSCache(scp);
3250         osi_Log2(afsd_logp, "RDR_RequestFileExtentsAsync cm_SyncOp failure scp=0x%p code=0x%x",
3251                  scp, code);
3252         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3253         RDR_SetFileStatus( &scp->fid, &userp->authgroup, status);
3254         return FALSE;
3255     }
3256
3257     /* Allocate the extents from the buffer package */
3258     for ( count = 0,
3259           ByteOffset = BeginOffset = RequestExtentsCB->ByteOffset,
3260           EndOffset.QuadPart = ByteOffset.QuadPart + RequestExtentsCB->Length;
3261           code == 0 && ByteOffset.QuadPart < EndOffset.QuadPart;
3262           ByteOffset.QuadPart += cm_data.blockSize)
3263     {
3264         BOOL bHaveBuffer = FALSE;
3265
3266         QueueLength = 0;
3267         thyper.QuadPart = ByteOffset.QuadPart;
3268
3269         code = buf_Get(scp, &thyper, &req, &bufp);
3270         if (code == 0) {
3271             lock_ObtainMutex(&bufp->mx);
3272             bBufRelease = TRUE;
3273
3274             if (bufp->qFlags & CM_BUF_QREDIR) {
3275                 bHaveBuffer = TRUE;
3276             } else if (bufp->flags & CM_BUF_DIRTY) {
3277                 bHaveBuffer = FALSE;
3278 #if 0
3279                 code = buf_CleanAsyncLocked(scp, bufp, &req, 0, NULL);
3280                 switch (code) {
3281                 case 0:
3282                     bHaveBuffer = TRUE;
3283                     break;
3284                 case CM_ERROR_RETRY:
3285                     /* Couldn't flush it, obtain it asynchronously so we don't block the thread. */
3286                     bHaveBuffer = FALSE;
3287                     code = 0;
3288                     break;
3289                 default:
3290                     smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3291                     RDR_SetFileStatus(&FileId, &userp->authgroup, status);
3292                     bHaveBuffer = FALSE;
3293                     code = 0;
3294                 }
3295 #endif
3296             } else {
3297                 osi_hyper_t minLength;  /* effective end of file */
3298
3299                 lock_ObtainRead(&scp->rw);
3300                 bHaveBuffer = cm_HaveBuffer(scp, bufp, TRUE);
3301
3302                 if (LargeIntegerGreaterThan(scp->length, scp->serverLength))
3303                     minLength = scp->serverLength;
3304                 else
3305                     minLength = scp->length;
3306
3307                 if (!bHaveBuffer &&
3308                     LargeIntegerGreaterThanOrEqualTo(bufp->offset, minLength)) {
3309                     memset(bufp->datap, 0, cm_data.buf_blockSize);
3310                     bufp->dataVersion = scp->dataVersion;
3311                     bHaveBuffer = TRUE;
3312                 }
3313                 else if ((RequestExtentsCB->Flags & AFS_EXTENT_FLAG_CLEAN) &&
3314                          ByteOffset.QuadPart <= bufp->offset.QuadPart &&
3315                          EndOffset.QuadPart >= bufp->offset.QuadPart + cm_data.blockSize)
3316                 {
3317                     memset(bufp->datap, 0, cm_data.blockSize);
3318                     bufp->dataVersion = scp->dataVersion;
3319                     buf_SetDirty(bufp, &req, 0, cm_data.blockSize, userp);
3320                     bHaveBuffer = TRUE;
3321                 }
3322                 lock_ReleaseRead(&scp->rw);
3323             }
3324
3325             /*
3326              * if this buffer is already up to date, skip it.
3327              */
3328             if (bHaveBuffer) {
3329                 if (ByteOffset.QuadPart == BeginOffset.QuadPart) {
3330                     BeginOffset.QuadPart += cm_data.blockSize;
3331                 } else {
3332                     QueueLength = (afs_uint32)(ByteOffset.QuadPart - BeginOffset.QuadPart);
3333                     QueueOffset = BeginOffset;
3334                     BeginOffset = ByteOffset;
3335                 }
3336
3337                 if (!(bufp->qFlags & CM_BUF_QREDIR)) {
3338 #ifdef VALIDATE_CHECK_SUM
3339 #ifdef ODS_DEBUG
3340                     char md5dbg[33];
3341                     char dbgstr[1024];
3342 #endif
3343 #endif
3344                     lock_ObtainWrite(&buf_globalLock);
3345                     if (!(bufp->qFlags & CM_BUF_QREDIR)) {
3346                         buf_InsertToRedirQueue(scp, bufp);
3347                         lock_ReleaseWrite(&buf_globalLock);
3348
3349 #ifdef VALIDATE_CHECK_SUM
3350                         buf_ComputeCheckSum(bufp);
3351 #endif
3352                         /* we already have the buffer, return it now */
3353                         pResultCB->FileExtents[count].Flags = 0;
3354                         pResultCB->FileExtents[count].FileOffset = ByteOffset;
3355                         pResultCB->FileExtents[count].CacheOffset.QuadPart = bufp->datap - RDR_extentBaseAddress;
3356                         pResultCB->FileExtents[count].Length = cm_data.blockSize;
3357                         count++;
3358
3359                         bBufRelease = FALSE;
3360
3361 #ifdef VALIDATE_CHECK_SUM
3362 #ifdef ODS_DEBUG
3363                         HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
3364                         snprintf( dbgstr, 1024,
3365                                   "RDR_RequestFileExtentsAsync md5 %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3366                                   md5dbg,
3367                                   scp->fid.volume, scp->fid.vnode, scp->fid.unique,
3368                                   pResultCB->FileExtents[count].FileOffset.HighPart,
3369                                   pResultCB->FileExtents[count].FileOffset.LowPart,
3370                                   pResultCB->FileExtents[count].CacheOffset.HighPart,
3371                                   pResultCB->FileExtents[count].CacheOffset.LowPart);
3372                         OutputDebugStringA( dbgstr);
3373 #endif
3374 #endif
3375                         osi_Log4(afsd_logp, "RDR_RequestFileExtentsAsync Extent2FS bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3376                                  bufp, ByteOffset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3377                     } else {
3378                         lock_ReleaseWrite(&buf_globalLock);
3379                     }
3380                 } else {
3381                     if (bBufRelease) {
3382                         /*
3383                          * The service is not handing off the extent to the redirector in this pass.
3384                          * However, we know the buffer is in recent use so move the buffer to the
3385                          * front of the queue
3386                          */
3387                         lock_ObtainWrite(&buf_globalLock);
3388                         buf_MoveToHeadOfRedirQueue(scp, bufp);
3389                         lock_ReleaseWrite(&buf_globalLock);
3390
3391                         osi_Log4(afsd_logp, "RDR_RequestFileExtentsAsync Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3392                                  bufp, ByteOffset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3393                     }
3394                 }
3395             }
3396             lock_ReleaseMutex(&bufp->mx);
3397             if (bBufRelease)
3398                 buf_Release(bufp);
3399
3400             if (QueueLength) {
3401                 cm_QueueBKGRequest(scp, RDR_BkgFetch, QueueOffset.LowPart, QueueOffset.HighPart,
3402                                    QueueLength, 0, userp, &req);
3403                 osi_Log3(afsd_logp, "RDR_RequestFileExtentsAsync Queued a Background Fetch offset 0x%x:%x length 0x%x",
3404                          QueueOffset.HighPart, QueueOffset.LowPart, QueueLength);
3405             }
3406         } else {
3407             /* No error from buf_Get() can be fatal */
3408             osi_Log3(afsd_logp, "RDR_RequestFileExtentsAsync buf_Get FAILURE offset 0x%x:%x code 0x%x",
3409                      BeginOffset.HighPart, BeginOffset.LowPart, code);
3410         }
3411     }
3412
3413     if (BeginOffset.QuadPart != EndOffset.QuadPart) {
3414         afs_uint32 length = (afs_uint32)(EndOffset.QuadPart - BeginOffset.QuadPart);
3415
3416         cm_QueueBKGRequest(scp, RDR_BkgFetch, BeginOffset.LowPart, BeginOffset.HighPart,
3417                            length, 0, userp, &req);
3418         osi_Log3(afsd_logp, "RDR_RequestFileExtentsAsync Queued a Background Fetch offset 0x%x:%x length 0x%x",
3419                   BeginOffset.HighPart, BeginOffset.LowPart, length);
3420     }
3421     cm_ReleaseSCache(scp);
3422
3423     (*ResultCB)->ExtentCount = count;
3424     osi_Log1(afsd_logp, "RDR_RequestFileExtentsAsync replying with 0x%x extent records", count);
3425     return FALSE;
3426 }
3427
3428 /*
3429  * When processing an extent release the extents must be accepted back by
3430  * the service even if there is an error condition returned to the redirector.
3431  * For example, there may no longer be a callback present or the file may
3432  * have been deleted on the file server.  Regardless, the extents must be
3433  * put back into the pool.
3434  */
3435 void
3436 RDR_ReleaseFileExtents( IN cm_user_t *userp,
3437                         IN AFSFileID FileId,
3438                         IN AFSReleaseExtentsCB *ReleaseExtentsCB,
3439                         IN BOOL bWow64,
3440                         IN DWORD ResultBufferLength,
3441                         IN OUT AFSCommResult **ResultCB)
3442 {
3443     DWORD count;
3444     cm_scache_t *scp = NULL;
3445     cm_fid_t    Fid;
3446     cm_buf_t    *bufp;
3447     afs_uint32  code;
3448     osi_hyper_t thyper;
3449     cm_req_t    req;
3450     int         dirty = 0;
3451     int         released = 0;
3452     int         deleted = 0;
3453     DWORD       status;
3454 #ifdef ODS_DEBUG
3455 #ifdef VALIDATE_CHECK_SUM
3456     char md5dbg[33], md5dbg2[33], md5dbg3[33];
3457 #endif
3458     char dbgstr[1024];
3459 #endif
3460
3461     RDR_InitReq(&req);
3462     if ( bWow64 )
3463         req.flags |= CM_REQ_WOW64;
3464
3465     osi_Log4(afsd_logp, "RDR_ReleaseFileExtents File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
3466               FileId.Cell, FileId.Volume,
3467               FileId.Vnode, FileId.Unique);
3468
3469     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
3470     if (!(*ResultCB))
3471         return;
3472
3473     memset( *ResultCB,
3474             '\0',
3475             sizeof( AFSCommResult));
3476
3477     /* Process the release */
3478     Fid.cell = FileId.Cell;
3479     Fid.volume = FileId.Volume;
3480     Fid.vnode = FileId.Vnode;
3481     Fid.unique = FileId.Unique;
3482     Fid.hash = FileId.Hash;
3483
3484     code = cm_GetSCache(&Fid, &scp, userp, &req);
3485     if (code) {
3486         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3487         (*ResultCB)->ResultStatus = status;
3488         osi_Log2(afsd_logp, "RDR_ReleaseFileExtents cm_GetSCache FID failure code=0x%x status=0x%x",
3489                   code, status);
3490     }
3491
3492     deleted = scp && (scp->flags & CM_SCACHEFLAG_DELETED);
3493
3494     /*
3495      * We do not stop processing as a result of being unable to find the cm_scache object.
3496      * If this occurs something really bad has happened since the cm_scache object must have
3497      * been recycled while extents were held by the redirector.  However, we will be resilient
3498      * and carry on without it.
3499      *
3500      * If the file is known to be deleted, there is no point attempting to ask the
3501      * file server about it or update the attributes.
3502      */
3503     if (scp && ReleaseExtentsCB->AllocationSize.QuadPart != scp->length.QuadPart &&
3504         !deleted)
3505     {
3506         cm_attr_t setAttr;
3507
3508         memset(&setAttr, 0, sizeof(cm_attr_t));
3509         lock_ObtainWrite(&scp->rw);
3510         if (ReleaseExtentsCB->AllocationSize.QuadPart != scp->length.QuadPart) {
3511
3512             osi_Log4(afsd_logp, "RDR_ReleaseFileExtents new length fid vol 0x%x vno 0x%x length 0x%x:%x",
3513                       scp->fid.volume, scp->fid.vnode,
3514                       ReleaseExtentsCB->AllocationSize.HighPart,
3515                       ReleaseExtentsCB->AllocationSize.LowPart);
3516
3517             setAttr.mask |= CM_ATTRMASK_LENGTH;
3518             setAttr.length.LowPart = ReleaseExtentsCB->AllocationSize.LowPart;
3519             setAttr.length.HighPart = ReleaseExtentsCB->AllocationSize.HighPart;
3520         }
3521         lock_ReleaseWrite(&scp->rw);
3522         if (setAttr.mask)
3523             code = cm_SetAttr(scp, &setAttr, userp, &req);
3524     }
3525
3526     for ( count = 0; count < ReleaseExtentsCB->ExtentCount; count++) {
3527         AFSFileExtentCB * pExtent = &ReleaseExtentsCB->FileExtents[count];
3528
3529         thyper.QuadPart = pExtent->FileOffset.QuadPart;
3530
3531         bufp = buf_Find(&Fid, &thyper);
3532         if (bufp) {
3533             if (pExtent->Flags & AFS_EXTENT_FLAG_UNKNOWN) {
3534                 if (!(bufp->qFlags & CM_BUF_QREDIR)) {
3535                     osi_Log4(afsd_logp, "RDR_ReleaseFileExtents extent vol 0x%x vno 0x%x foffset 0x%x:%x",
3536                               Fid.volume, Fid.vnode,
3537                               pExtent->FileOffset.HighPart,
3538                               pExtent->FileOffset.LowPart);
3539                     osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; previously released",
3540                               pExtent->CacheOffset.HighPart,
3541                               pExtent->CacheOffset.LowPart);
3542                 } else {
3543                     osi_Log4(afsd_logp, "RDR_ReleaseFileExtents extent vol 0x%x vno 0x%x foffset 0x%x:%x",
3544                               Fid.volume, Fid.vnode,
3545                               pExtent->FileOffset.HighPart,
3546                               pExtent->FileOffset.LowPart);
3547                     osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; owned by redirector",
3548                               pExtent->CacheOffset.HighPart,
3549                               pExtent->CacheOffset.LowPart);
3550                 }
3551                 buf_Release(bufp);
3552                 continue;
3553             }
3554
3555             if (pExtent->Flags & AFS_EXTENT_FLAG_IN_USE) {
3556                 osi_Log4(afsd_logp, "RDR_ReleaseFileExtents extent vol 0x%x vno 0x%x foffset 0x%x:%x",
3557                           Fid.volume, Fid.vnode,
3558                           pExtent->FileOffset.HighPart,
3559                           pExtent->FileOffset.LowPart);
3560                 osi_Log2(afsd_logp, "... coffset 0x%x:%x IN_USE by file system",
3561                           pExtent->CacheOffset.HighPart,
3562                           pExtent->CacheOffset.LowPart);
3563
3564                 /* Move the buffer to the front of the queue */
3565                 lock_ObtainWrite(&buf_globalLock);
3566                 buf_MoveToHeadOfRedirQueue(scp, bufp);
3567                 lock_ReleaseWrite(&buf_globalLock);
3568                 buf_Release(bufp);
3569                 continue;
3570             }
3571
3572             if (bufp->datap - RDR_extentBaseAddress == pExtent->CacheOffset.QuadPart) {
3573                 if (!(bufp->qFlags & CM_BUF_QREDIR)) {
3574                     osi_Log4(afsd_logp, "RDR_ReleaseFileExtents extent vol 0x%x vno 0x%x foffset 0x%x:%x not held by file system",
3575                              Fid.volume, Fid.vnode, pExtent->FileOffset.HighPart,
3576                              pExtent->FileOffset.LowPart);
3577                     osi_Log2(afsd_logp, "... coffset 0x%x:%x",
3578                              pExtent->CacheOffset.HighPart,
3579                              pExtent->CacheOffset.LowPart);
3580                 } else {
3581                     osi_Log4(afsd_logp, "RDR_ReleaseFileExtents bufp 0x%p vno 0x%x foffset 0x%x:%x",
3582                               bufp, bufp->fid.vnode, pExtent->FileOffset.HighPart,
3583                               pExtent->FileOffset.LowPart);
3584                     osi_Log2(afsd_logp, "... coffset 0x%x:%x",
3585                              pExtent->CacheOffset.HighPart,
3586                              pExtent->CacheOffset.LowPart);
3587
3588                     if (pExtent->Flags || ReleaseExtentsCB->Flags) {
3589                         lock_ObtainMutex(&bufp->mx);
3590                         if ( (ReleaseExtentsCB->Flags & AFS_EXTENT_FLAG_RELEASE) ||
3591                              (pExtent->Flags & AFS_EXTENT_FLAG_RELEASE) )
3592                         {
3593                             if (bufp->qFlags & CM_BUF_QREDIR) {
3594                                 lock_ObtainWrite(&buf_globalLock);
3595                                 if (bufp->qFlags & CM_BUF_QREDIR) {
3596                                     buf_RemoveFromRedirQueue(scp, bufp);
3597                                     buf_ReleaseLocked(bufp, TRUE);
3598                                 }
3599                                 lock_ReleaseWrite(&buf_globalLock);
3600                             }
3601 #ifdef ODS_DEBUG
3602                             snprintf( dbgstr, 1024,
3603                                       "RDR_ReleaseFileExtents releasing: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3604                                       Fid.volume, Fid.vnode, Fid.unique,
3605                                       pExtent->FileOffset.HighPart,
3606                                       pExtent->FileOffset.LowPart,
3607                                       pExtent->CacheOffset.HighPart,
3608                                       pExtent->CacheOffset.LowPart);
3609                             OutputDebugStringA( dbgstr);
3610 #endif
3611                             released++;
3612                         } else {
3613 #ifdef ODS_DEBUG
3614                             snprintf( dbgstr, 1024,
3615                                       "RDR_ReleaseFileExtents not releasing: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3616                                       Fid.volume, Fid.vnode, Fid.unique,
3617                                       pExtent->FileOffset.HighPart,
3618                                       pExtent->FileOffset.LowPart,
3619                                       pExtent->CacheOffset.HighPart,
3620                                       pExtent->CacheOffset.LowPart);
3621                             OutputDebugStringA( dbgstr);
3622 #endif
3623                             osi_Log4( afsd_logp, "RDR_ReleaseFileExtents not releasing vol 0x%x vno 0x%x foffset 0x%x:%x",
3624                                       Fid.volume, Fid.vnode,
3625                                       pExtent->FileOffset.HighPart,
3626                                       pExtent->FileOffset.LowPart);
3627                             osi_Log2( afsd_logp, "... coffset 0x%x:%x",
3628                                       pExtent->CacheOffset.HighPart,
3629                                       pExtent->CacheOffset.LowPart);
3630                         }
3631
3632                         if ( (ReleaseExtentsCB->Flags & AFS_EXTENT_FLAG_DIRTY) ||
3633                              (pExtent->Flags & AFS_EXTENT_FLAG_DIRTY) )
3634                         {
3635 #ifdef VALIDATE_CHECK_SUM
3636 #ifdef ODS_DEBUG
3637                             HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
3638 #endif
3639
3640                             /*
3641                              * if the saved checksum matches the checksum of the current state of the buffer
3642                              * then the buffer is the same as what was given to the kernel.
3643                              */
3644                             if ( buf_ValidateCheckSum(bufp) ) {
3645                                 buf_ComputeCheckSum(bufp);
3646
3647                                 if (pExtent->Flags & AFS_EXTENT_FLAG_MD5_SET)
3648                                 {
3649 #ifdef ODS_DEBUG
3650                                     HexCheckSum(md5dbg2, sizeof(md5dbg2), pExtent->MD5);
3651                                     HexCheckSum(md5dbg3, sizeof(md5dbg3), bufp->md5cksum);
3652 #endif
3653                                     if (memcmp(bufp->md5cksum, pExtent->MD5, 16))
3654                                     {
3655 #ifdef ODS_DEBUG
3656                                         snprintf( dbgstr, 1024,
3657                                                   "RDR_ReleaseFileExtents dirty flag set but not dirty and user != kernel: old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3658                                                   md5dbg, md5dbg2,md5dbg3,
3659                                                   Fid.volume, Fid.vnode, Fid.unique,
3660                                                   pExtent->FileOffset.HighPart,
3661                                                   pExtent->FileOffset.LowPart,
3662                                                   pExtent->CacheOffset.HighPart,
3663                                                   pExtent->CacheOffset.LowPart);
3664                                         OutputDebugStringA( dbgstr);
3665 #endif
3666                                         osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag set and checksums do not match! vol 0x%x vno 0x%x foffset 0x%x:%x",
3667                                                   Fid.volume, Fid.vnode,
3668                                                   pExtent->FileOffset.HighPart,
3669                                                   pExtent->FileOffset.LowPart);
3670                                         osi_Log2( afsd_logp, "... coffset 0x%x:%x",
3671                                                   pExtent->CacheOffset.HighPart,
3672                                                   pExtent->CacheOffset.LowPart);
3673                                         buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
3674                                         dirty++;
3675                                     } else {
3676 #ifdef ODS_DEBUG
3677                                         snprintf( dbgstr, 1024,
3678                                                   "RDR_ReleaseFileExtents dirty flag set but not dirty and user == kernel: old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3679                                                   md5dbg, md5dbg2, md5dbg3,
3680                                                   Fid.volume, Fid.vnode, Fid.unique,
3681                                                   pExtent->FileOffset.HighPart,
3682                                                   pExtent->FileOffset.LowPart,
3683                                                   pExtent->CacheOffset.HighPart,
3684                                                   pExtent->CacheOffset.LowPart);
3685                                         OutputDebugStringA( dbgstr);
3686 #endif
3687                                         osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag set but extent has not changed vol 0x%x vno 0x%x foffset 0x%x:%x",
3688                                                   Fid.volume, Fid.vnode,
3689                                                   pExtent->FileOffset.HighPart,
3690                                                   pExtent->FileOffset.LowPart);
3691                                         osi_Log2( afsd_logp, "... coffset 0x%x:%x",
3692                                                   pExtent->CacheOffset.HighPart,
3693                                                   pExtent->CacheOffset.LowPart);
3694                                     }
3695                                 } else {
3696 #ifdef ODS_DEBUG
3697                                         snprintf( dbgstr, 1024,
3698                                                   "RDR_ReleaseFileExtents dirty flag set but not dirty: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3699                                                   Fid.volume, Fid.vnode, Fid.unique,
3700                                                   pExtent->FileOffset.HighPart,
3701                                                   pExtent->FileOffset.LowPart,
3702                                                   pExtent->CacheOffset.HighPart,
3703                                                   pExtent->CacheOffset.LowPart);
3704                                         OutputDebugStringA( dbgstr);
3705 #endif
3706                                         osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag set but extent has not changed vol 0x%x vno 0x%x foffset 0x%x:%x",
3707                                                   Fid.volume, Fid.vnode,
3708                                                   pExtent->FileOffset.HighPart,
3709                                                   pExtent->FileOffset.LowPart);
3710                                         osi_Log2( afsd_logp, "... coffset 0x%x:%x",
3711                                                   pExtent->CacheOffset.HighPart,
3712                                                   pExtent->CacheOffset.LowPart);
3713                                 }
3714                             } else {
3715                                 buf_ComputeCheckSum(bufp);
3716 #ifdef ODS_DEBUG
3717                                 if (pExtent->Flags & AFS_EXTENT_FLAG_MD5_SET)
3718                                 {
3719                                     HexCheckSum(md5dbg3, sizeof(md5dbg3), bufp->md5cksum);
3720                                     if (memcmp(bufp->md5cksum, pExtent->MD5, 16))
3721                                     {
3722                                         snprintf( dbgstr, 1024,
3723                                                   "RDR_ReleaseFileExtents dirty flag set and dirty and user != kernel: old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3724                                                   md5dbg, md5dbg2,md5dbg3,
3725                                                   Fid.volume, Fid.vnode, Fid.unique,
3726                                                   pExtent->FileOffset.HighPart,
3727                                                   pExtent->FileOffset.LowPart,
3728                                                   pExtent->CacheOffset.HighPart,
3729                                                   pExtent->CacheOffset.LowPart);
3730                                         OutputDebugStringA( dbgstr);
3731                                     } else {
3732                                         snprintf( dbgstr, 1024,
3733                                                   "RDR_ReleaseFileExtents dirty flag set and dirty and user == kernel: old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3734                                                   md5dbg, md5dbg2,md5dbg3,
3735                                                   Fid.volume, Fid.vnode, Fid.unique,
3736                                                   pExtent->FileOffset.HighPart,
3737                                                   pExtent->FileOffset.LowPart,
3738                                                   pExtent->CacheOffset.HighPart,
3739                                                   pExtent->CacheOffset.LowPart);
3740                                         OutputDebugStringA( dbgstr);
3741                                     }
3742                                 } else {
3743                                     snprintf( dbgstr, 1024,
3744                                               "RDR_ReleaseFileExtents dirty flag set: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3745                                               Fid.volume, Fid.vnode, Fid.unique,
3746                                               pExtent->FileOffset.HighPart,
3747                                               pExtent->FileOffset.LowPart,
3748                                               pExtent->CacheOffset.HighPart,
3749                                               pExtent->CacheOffset.LowPart);
3750                                     OutputDebugStringA( dbgstr);
3751                                 }
3752 #endif
3753                                 buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
3754                                 dirty++;
3755                             }
3756 #else /* !VALIDATE_CHECK_SUM */
3757                             buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
3758                             dirty++;
3759 #endif /* VALIDATE_CHECK_SUM */
3760                         }
3761 #ifdef VALIDATE_CHECK_SUM
3762                         else {
3763 #ifdef ODS_DEBUG
3764                             HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
3765 #endif
3766                             if ( !buf_ValidateCheckSum(bufp) ) {
3767                                 buf_ComputeCheckSum(bufp);
3768 #ifdef ODS_DEBUG
3769                                 HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
3770                                 snprintf( dbgstr, 1024,
3771                                           "RDR_ReleaseFileExtents dirty flag not set but dirty! old %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3772                                           md5dbg, md5dbg3,
3773                                           Fid.volume, Fid.vnode, Fid.unique,
3774                                           pExtent->FileOffset.HighPart,
3775                                           pExtent->FileOffset.LowPart,
3776                                           pExtent->CacheOffset.HighPart,
3777                                           pExtent->CacheOffset.LowPart);
3778                                 OutputDebugStringA( dbgstr);
3779 #endif
3780                                 osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag not set but extent has changed vol 0x%x vno 0x%x foffset 0x%x:%x",
3781                                           Fid.volume, Fid.vnode,
3782                                           pExtent->FileOffset.HighPart,
3783                                           pExtent->FileOffset.LowPart);
3784                                 osi_Log2( afsd_logp, "... coffset 0x%x:%x",
3785                                           pExtent->CacheOffset.HighPart,
3786                                           pExtent->CacheOffset.LowPart);
3787                                 buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
3788                                 dirty++;
3789                             } else {
3790                                 buf_ComputeCheckSum(bufp);
3791 #ifdef ODS_DEBUG
3792                                 HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
3793                                 snprintf( dbgstr, 1024,
3794                                           "RDR_ReleaseFileExtents dirty flag not set: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3795                                           Fid.volume, Fid.vnode, Fid.unique,
3796                                           pExtent->FileOffset.HighPart,
3797                                           pExtent->FileOffset.LowPart,
3798                                           pExtent->CacheOffset.HighPart,
3799                                           pExtent->CacheOffset.LowPart);
3800                                 OutputDebugStringA( dbgstr);
3801 #endif
3802                                 osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag not set: vol 0x%x vno 0x%x foffset 0x%x:%x",
3803                                           Fid.volume, Fid.vnode,
3804                                           pExtent->FileOffset.HighPart,
3805                                           pExtent->FileOffset.LowPart);
3806                                 osi_Log2( afsd_logp, "... coffset 0x%x:%x",
3807                                           pExtent->CacheOffset.HighPart,
3808                                           pExtent->CacheOffset.LowPart);
3809                             }
3810                         }
3811 #endif /* VALIDATE_CHECK_SUM */
3812                         lock_ReleaseMutex(&bufp->mx);
3813                     }
3814                 }
3815             }
3816             else {
3817                 char * datap = RDR_extentBaseAddress + pExtent->CacheOffset.QuadPart;
3818                 cm_buf_t *wbp;
3819
3820                 for (wbp = cm_data.buf_allp; wbp; wbp = wbp->allp) {
3821                     if (wbp->datap == datap)
3822                         break;
3823                 }
3824
3825 #ifdef ODS_DEBUG
3826                 snprintf( dbgstr, 1024,
3827                           "RDR_ReleaseFileExtents non-matching extent vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3828                           Fid.volume, Fid.vnode, Fid.unique,
3829                           pExtent->FileOffset.HighPart,
3830                           pExtent->FileOffset.LowPart,
3831                           pExtent->CacheOffset.HighPart,
3832                           pExtent->CacheOffset.LowPart);
3833                 OutputDebugStringA( dbgstr);
3834 #endif
3835                 osi_Log4( afsd_logp, "RDR_ReleaseFileExtents non-matching extent vol 0x%x vno 0x%x foffset 0x%x:%x",
3836                           Fid.volume, Fid.vnode,
3837                           pExtent->FileOffset.HighPart,
3838                           pExtent->FileOffset.LowPart);
3839                 osi_Log2( afsd_logp, "... coffset 0x%x:%x",
3840                           pExtent->CacheOffset.HighPart,
3841                           pExtent->CacheOffset.LowPart);
3842                 osi_Log5( afsd_logp, "... belongs to bp 0x%p vol 0x%x vno 0x%x foffset 0x%x:%x",
3843                           wbp, wbp->fid.volume, wbp->fid.vnode, wbp->offset.HighPart, wbp->offset.LowPart);
3844 #ifdef DEBUG
3845                 DebugBreak();
3846 #endif
3847             }
3848             buf_Release(bufp);
3849         }
3850         else {
3851             char * datap = RDR_extentBaseAddress + pExtent->CacheOffset.QuadPart;
3852             cm_buf_t *wbp;
3853
3854             for (wbp = cm_data.buf_allp; wbp; wbp = wbp->allp) {
3855                 if (wbp->datap == datap)
3856                     break;
3857             }
3858
3859 #ifdef ODS_DEBUG
3860             snprintf( dbgstr, 1024,
3861                       "RDR_ReleaseFileExtents unknown extent vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3862                       Fid.volume, Fid.vnode, Fid.unique,
3863                       pExtent->FileOffset.HighPart,
3864                       pExtent->FileOffset.LowPart,
3865                       pExtent->CacheOffset.HighPart,
3866                       pExtent->CacheOffset.LowPart);
3867             OutputDebugStringA( dbgstr);
3868 #endif
3869             osi_Log4( afsd_logp, "RDR_ReleaseFileExtents unknown extent vol 0x%x vno 0x%x foffset 0x%x:%x",
3870                       Fid.volume, Fid.vnode,
3871                       pExtent->FileOffset.HighPart,
3872                       pExtent->FileOffset.LowPart);
3873             osi_Log2( afsd_logp, "... coffset 0x%x:%x",
3874                       pExtent->CacheOffset.HighPart,
3875                       pExtent->CacheOffset.LowPart);
3876             osi_Log5( afsd_logp, "... belongs to bp 0x%p vol 0x%x vno 0x%x foffset 0x%x:%x",
3877                       wbp, wbp->fid.volume, wbp->fid.vnode, wbp->offset.HighPart, wbp->offset.LowPart);
3878         }
3879     }
3880
3881     if (scp) {
3882         if (ReleaseExtentsCB->Flags & AFS_EXTENT_FLAG_FLUSH) {
3883             lock_ObtainWrite(&scp->rw);
3884             code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
3885                              CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3886             lock_ReleaseWrite(&scp->rw);
3887             if (code == 0)
3888                 code = cm_FSync(scp, userp, &req, FALSE);
3889         }
3890         else if (dirty) {
3891             osi_hyper_t offset = {0,0};
3892             afs_uint32  length = 0;
3893             afs_uint32  rights = 0;
3894
3895             lock_ObtainWrite(&scp->rw);
3896             code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
3897                              CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3898             lock_ReleaseWrite(&scp->rw);
3899             if (code == 0) {
3900                 /*
3901                  * there is at least one dirty extent on this file.  queue up background store
3902                  * requests for contiguous blocks
3903                  */
3904                 for ( count = 0; count < ReleaseExtentsCB->ExtentCount; count++) {
3905                     if (ReleaseExtentsCB->FileExtents[count].FileOffset.QuadPart == offset.QuadPart + length &&
3906                          length + cm_data.buf_blockSize <= cm_chunkSize)
3907                     {
3908                         length += cm_data.buf_blockSize;
3909                     } else {
3910                         if (!(offset.QuadPart == 0 && length == 0))
3911                             cm_QueueBKGRequest(scp, cm_BkgStore, offset.LowPart, offset.HighPart,
3912                                                 length, 0, userp, &req);
3913                         offset.QuadPart = ReleaseExtentsCB->FileExtents[count].FileOffset.QuadPart;
3914                         length = cm_data.buf_blockSize;
3915                     }
3916                 }
3917                 cm_QueueBKGRequest(scp, cm_BkgStore, offset.LowPart, offset.HighPart,
3918                                    length, 0, userp, &req);
3919             }
3920         }
3921         cm_ReleaseSCache(scp);
3922     }
3923
3924     osi_Log5(afsd_logp, "RDR_ReleaseFileExtents File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x Released %d",
3925               FileId.Cell, FileId.Volume,
3926               FileId.Vnode, FileId.Unique, released);
3927     if (code && code != CM_ERROR_WOULDBLOCK) {
3928         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3929         (*ResultCB)->ResultStatus = status;
3930         osi_Log2(afsd_logp, "RDR_ReleaseFileExtents FAILURE code=0x%x status=0x%x",
3931                   code, status);
3932     } else {
3933         (*ResultCB)->ResultStatus = 0;
3934         osi_Log0(afsd_logp, "RDR_ReleaseFileExtents SUCCESS");
3935     }
3936     (*ResultCB)->ResultBufferLength = 0;
3937
3938     return;
3939 }
3940
3941 DWORD
3942 RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFileExtentsResultCB,
3943                                      IN DWORD ResultBufferLength)
3944 {
3945     afs_uint32  code = 0;
3946     cm_req_t    req;
3947     osi_hyper_t thyper;
3948     cm_buf_t    *bufp;
3949     unsigned int fileno, extentno, total_extents = 0;
3950     AFSReleaseFileExtentsResultFileCB *pNextFileCB;
3951 #ifdef ODS_DEBUG
3952 #ifdef VALIDATE_CHECK_SUM
3953     char md5dbg[33], md5dbg2[33], md5dbg3[33];
3954 #endif
3955     char dbgstr[1024];
3956 #endif
3957     RDR_InitReq(&req);
3958
3959     for ( fileno = 0, pNextFileCB = &ReleaseFileExtentsResultCB->Files[0];
3960           fileno < ReleaseFileExtentsResultCB->FileCount;
3961           fileno++ ) {
3962         AFSReleaseFileExtentsResultFileCB *pFileCB = pNextFileCB;
3963         cm_user_t       *userp = NULL;
3964         cm_fid_t         Fid;
3965         cm_scache_t *    scp = NULL;
3966         int              dirty = 0;
3967         int              released = 0;
3968         int              deleted = 0;
3969         char * p;
3970
3971         userp = RDR_UserFromAuthGroup( &pFileCB->AuthGroup);
3972
3973         osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult %d.%d.%d.%d",
3974                   pFileCB->FileId.Cell, pFileCB->FileId.Volume,
3975                   pFileCB->FileId.Vnode, pFileCB->FileId.Unique);
3976
3977         /* Process the release */
3978         Fid.cell = pFileCB->FileId.Cell;
3979         Fid.volume = pFileCB->FileId.Volume;
3980         Fid.vnode = pFileCB->FileId.Vnode;
3981         Fid.unique = pFileCB->FileId.Unique;
3982         Fid.hash = pFileCB->FileId.Hash;
3983
3984         if (Fid.cell == 0) {
3985             osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult Invalid FID %d.%d.%d.%d",
3986                      Fid.cell, Fid.volume, Fid.vnode, Fid.unique);
3987             code = CM_ERROR_INVAL;
3988             goto cleanup_file;
3989         }
3990
3991         code = cm_GetSCache(&Fid, &scp, userp, &req);
3992         if (code) {
3993             osi_Log1(afsd_logp, "RDR_ProcessReleaseFileExtentsResult cm_GetSCache FID failure code=0x%x",
3994                      code);
3995             /*
3996              * A failure to find the cm_scache object cannot prevent the service
3997              * from accepting the extents back from the redirector.
3998              */
3999         }
4000
4001         deleted = scp && (scp->flags & CM_SCACHEFLAG_DELETED);
4002
4003         /* if the scp was not found, do not perform the length check */
4004         if (scp && (pFileCB->AllocationSize.QuadPart != scp->length.QuadPart)) {
4005             cm_attr_t setAttr;
4006
4007             memset(&setAttr, 0, sizeof(cm_attr_t));
4008             lock_ObtainWrite(&scp->rw);
4009             if (pFileCB->AllocationSize.QuadPart != scp->length.QuadPart) {
4010                 osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult length change vol 0x%x vno 0x%x length 0x%x:%x",
4011                           scp->fid.volume, scp->fid.vnode,
4012                           pFileCB->AllocationSize.HighPart,
4013                           pFileCB->AllocationSize.LowPart);
4014                 setAttr.mask |= CM_ATTRMASK_LENGTH;
4015                 setAttr.length.LowPart = pFileCB->AllocationSize.LowPart;
4016                 setAttr.length.HighPart = pFileCB->AllocationSize.HighPart;
4017             }
4018             lock_ReleaseWrite(&scp->rw);
4019             if (setAttr.mask)
4020                 code = cm_SetAttr(scp, &setAttr, userp, &req);
4021         }
4022
4023         for ( extentno = 0; extentno < pFileCB->ExtentCount; total_extents++, extentno++ ) {
4024             AFSFileExtentCB *pExtent = &pFileCB->FileExtents[extentno];
4025
4026             thyper.QuadPart = pExtent->FileOffset.QuadPart;
4027
4028             bufp = buf_Find(&Fid, &thyper);
4029             if (bufp) {
4030                 if (pExtent->Flags & AFS_EXTENT_FLAG_UNKNOWN) {
4031                     if (!(bufp->qFlags & CM_BUF_QREDIR)) {
4032                         osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4033                                  Fid.volume, Fid.vnode,
4034                                  pExtent->FileOffset.HighPart,
4035                                  pExtent->FileOffset.LowPart);
4036                         osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; previously released",
4037                                  pExtent->CacheOffset.HighPart,
4038                                  pExtent->CacheOffset.LowPart);
4039                     } else {
4040                         osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4041                                  Fid.volume, Fid.vnode,
4042                                  pExtent->FileOffset.HighPart,
4043                                  pExtent->FileOffset.LowPart);
4044                         osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; owned by redirector",
4045                                  pExtent->CacheOffset.HighPart,
4046                                  pExtent->CacheOffset.LowPart);
4047                     }
4048                     buf_Release(bufp);
4049                     continue;
4050                 }
4051
4052                 if (pExtent->Flags & AFS_EXTENT_FLAG_IN_USE) {
4053                     osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4054                               Fid.volume, Fid.vnode,
4055                               pExtent->FileOffset.HighPart,
4056                               pExtent->FileOffset.LowPart);
4057                     osi_Log2(afsd_logp, "... coffset 0x%x:%x IN_USE by file system",
4058                               pExtent->CacheOffset.HighPart,
4059                               pExtent->CacheOffset.LowPart);
4060
4061                     /* Move the buffer to the front of the queue */
4062                     lock_ObtainWrite(&buf_globalLock);
4063                     buf_MoveToHeadOfRedirQueue(scp, bufp);
4064                     lock_ReleaseWrite(&buf_globalLock);
4065                     buf_Release(bufp);
4066                     continue;
4067                 }
4068
4069                 if (bufp->datap - RDR_extentBaseAddress == pExtent->CacheOffset.QuadPart) {
4070                     if (!(bufp->qFlags & CM_BUF_QREDIR)) {
4071                         osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4072                                  Fid.volume, Fid.vnode,
4073                                  pExtent->FileOffset.HighPart,
4074                                  pExtent->FileOffset.LowPart);
4075                         osi_Log2(afsd_logp, "... coffset 0x%x:%x not held by file system",
4076                                  pExtent->CacheOffset.HighPart,
4077                                  pExtent->CacheOffset.LowPart);
4078 #ifdef ODS_DEBUG
4079                         snprintf(dbgstr, 1024,
4080                                   "RDR_ProcessReleaseFileExtentsResult not held by redirector! flags 0x%x:%x vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4081                                   ReleaseFileExtentsResultCB->Flags, pExtent->Flags,
4082                                   Fid.volume, Fid.vnode, Fid.unique,
4083                                   pExtent->FileOffset.HighPart,
4084                                   pExtent->FileOffset.LowPart,
4085                                   pExtent->CacheOffset.HighPart,
4086                                   pExtent->CacheOffset.LowPart);
4087                         OutputDebugStringA( dbgstr);
4088 #endif
4089                     } else {
4090                         osi_Log5(afsd_logp, "RDR_ProcessReleaseFileExtentsResult bufp 0x%p foffset 0x%x:%x coffset 0x%x:%x",
4091                                  bufp, pExtent->FileOffset.HighPart, pExtent->FileOffset.LowPart,
4092                                  pExtent->CacheOffset.HighPart, pExtent->CacheOffset.LowPart);
4093
4094                         if (pExtent->Flags || ReleaseFileExtentsResultCB->Flags) {
4095                             lock_ObtainMutex(&bufp->mx);
4096                             if ( (ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_RELEASE) ||
4097                                  (pExtent->Flags & AFS_EXTENT_FLAG_RELEASE) )
4098                             {
4099                                 if (bufp->qFlags & CM_BUF_QREDIR) {
4100                                     lock_ObtainWrite(&buf_globalLock);
4101                                     if (bufp->qFlags & CM_BUF_QREDIR) {
4102                                         buf_RemoveFromRedirQueue(scp, bufp);
4103                                         buf_ReleaseLocked(bufp, TRUE);
4104                                     }
4105                                     lock_ReleaseWrite(&buf_globalLock);
4106                                 }
4107
4108 #ifdef ODS_DEBUG
4109                                 snprintf(dbgstr, 1024,
4110                                           "RDR_ProcessReleaseFileExtentsResult extent released: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4111                                           Fid.volume, Fid.vnode, Fid.unique,
4112                                           pExtent->FileOffset.HighPart,
4113                                           pExtent->FileOffset.LowPart,
4114                                           pExtent->CacheOffset.HighPart,
4115                                           pExtent->CacheOffset.LowPart);
4116                                 OutputDebugStringA( dbgstr);
4117 #endif
4118
4119                                 released++;
4120                             } else {
4121                                 osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult not releasing vol 0x%x vno 0x%x foffset 0x%x:%x",
4122                                          Fid.volume, Fid.vnode,
4123                                          pExtent->FileOffset.HighPart,
4124                                          pExtent->FileOffset.LowPart);
4125                                 osi_Log2(afsd_logp, "... coffset 0x%x:%x",
4126                                          pExtent->CacheOffset.HighPart,
4127                                          pExtent->CacheOffset.LowPart);
4128 #ifdef ODS_DEBUG
4129                                 snprintf(dbgstr, 1024,
4130                                           "RDR_ProcessReleaseFileExtentsResult not released! vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4131                                           Fid.volume, Fid.vnode, Fid.unique,
4132                                           pExtent->FileOffset.HighPart,
4133                                           pExtent->FileOffset.LowPart,
4134                                           pExtent->CacheOffset.HighPart,
4135                                           pExtent->CacheOffset.LowPart);
4136                                 OutputDebugStringA( dbgstr);
4137 #endif
4138                             }
4139
4140                             if ((ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_DIRTY) ||
4141                                 (pExtent->Flags & AFS_EXTENT_FLAG_DIRTY))
4142                             {
4143 #ifdef VALIDATE_CHECK_SUM
4144                                 if ( buf_ValidateCheckSum(bufp) ) {
4145 #ifdef ODS_DEBUG
4146                                     HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
4147                                     if (ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_MD5_SET)
4148                                         HexCheckSum(md5dbg2, sizeof(md5dbg2), pExtent->MD5);
4149 #endif
4150                                     buf_ComputeCheckSum(bufp);
4151 #ifdef ODS_DEBUG
4152                                     HexCheckSum(md5dbg3, sizeof(md5dbg), bufp->md5cksum);
4153 #endif
4154                                     if (ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_MD5_SET)
4155                                     {
4156                                         if (memcmp(bufp->md5cksum, pExtent->MD5, 16))
4157                                         {
4158 #ifdef ODS_DEBUG
4159                                             snprintf(dbgstr, 1024,
4160                                                       "RDR_ProcessReleaseFileExtentsResult dirty flag set and checksums do not match! user %s kernel %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4161                                                       md5dbg3, md5dbg2,
4162                                                       Fid.volume, Fid.vnode, Fid.unique,
4163                                                       pExtent->FileOffset.HighPart,
4164                                                       pExtent->FileOffset.LowPart,
4165                                                       pExtent->CacheOffset.HighPart,
4166                                                       pExtent->CacheOffset.LowPart);
4167                                             OutputDebugStringA( dbgstr);
4168 #endif
4169                                             osi_Log4(afsd_logp,
4170                                                       "RDR_ProcessReleaseFileExtentsResult dirty flag set and checksums do not match! vol 0x%x vno 0x%x foffset 0x%x:%x",
4171                                                       Fid.volume, Fid.vnode,
4172                                                       pExtent->FileOffset.HighPart,
4173                                                       pExtent->FileOffset.LowPart);
4174                                             osi_Log2(afsd_logp,
4175                                                       "... coffset 0x%x:%x",
4176                                                       pExtent->CacheOffset.HighPart,
4177                                                       pExtent->CacheOffset.LowPart);
4178
4179                                             if (!deleted) {
4180                                                 buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
4181                                                 dirty++;
4182                                             }
4183                                         } else {
4184 #ifdef ODS_DEBUG
4185                                             snprintf(dbgstr, 1024,
4186                                                       "RDR_ProcessReleaseFileExtentsResult dirty flag set but extent has not changed! old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4187                                                       md5dbg, md5dbg2, md5dbg3,
4188                                                       Fid.volume, Fid.vnode, Fid.unique,
4189                                                       pExtent->FileOffset.HighPart,
4190                                                       pExtent->FileOffset.LowPart,
4191                                                       pExtent->CacheOffset.HighPart,
4192                                                       pExtent->CacheOffset.LowPart);
4193                                             OutputDebugStringA( dbgstr);
4194 #endif
4195                                             osi_Log4(afsd_logp,
4196                                                       "RDR_ProcessReleaseFileExtentsResult dirty flag set but extent has not changed vol 0x%x vno 0x%x foffset 0x%x:%x",
4197                                                       Fid.volume, Fid.vnode,
4198                                                       pExtent->FileOffset.HighPart,
4199                                                       pExtent->FileOffset.LowPart);
4200                                             osi_Log2(afsd_logp,
4201                                                       "... coffset 0x%x:%x",
4202                                                       pExtent->CacheOffset.HighPart,
4203                                                       pExtent->CacheOffset.LowPart);
4204                                         }
4205                                     }
4206                                 }
4207 #else /* !VALIDATE_CHECK_SUM */
4208                                 if (!deleted) {
4209                                     buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
4210                                     dirty++;
4211                                 }
4212 #ifdef ODS_DEBUG
4213                                 snprintf(dbgstr, 1024,
4214                                           "RDR_ProcessReleaseFileExtentsResult dirty! vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4215                                           Fid.volume, Fid.vnode, Fid.unique,
4216                                           pExtent->FileOffset.HighPart,
4217                                           pExtent->FileOffset.LowPart,
4218                                           pExtent->CacheOffset.HighPart,
4219                                           pExtent->CacheOffset.LowPart);
4220                                 OutputDebugStringA( dbgstr);
4221 #endif
4222 #endif /* VALIDATE_CHECK_SUM */
4223                             }
4224 #ifdef VALIDATE_CHECK_SUM
4225                             else {
4226 #ifdef ODS_DEBUG
4227                                 HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
4228 #endif
4229                                 if (!buf_ValidateCheckSum(bufp) ) {
4230                                     buf_ComputeCheckSum(bufp);
4231 #ifdef ODS_DEBUG
4232                                     HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
4233                                     snprintf(dbgstr, 1024,
4234                                              "RDR_ProcessReleaseFileExtentsResult dirty flag not set but dirty! old %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4235                                              md5dbg, md5dbg3,
4236                                              Fid.volume, Fid.vnode, Fid.unique,
4237                                              pExtent->FileOffset.HighPart,
4238                                              pExtent->FileOffset.LowPart,
4239                                              pExtent->CacheOffset.HighPart,
4240                                              pExtent->CacheOffset.LowPart);
4241                                     OutputDebugStringA( dbgstr);
4242 #endif
4243                                     osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult dirty flag NOT set but extent has changed! vol 0x%x vno 0x%x foffset 0x%x:%x",
4244                                              Fid.volume, Fid.vnode,
4245                                              pExtent->FileOffset.HighPart,
4246                                              pExtent->FileOffset.LowPart);
4247                                     osi_Log2(afsd_logp, "... coffset 0x%x:%x",
4248                                              pExtent->CacheOffset.HighPart,
4249                                              pExtent->CacheOffset.LowPart);
4250 #ifdef DEBUG
4251                                     DebugBreak();
4252 #endif
4253                                     if (!deleted) {
4254                                         buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
4255                                         dirty++;
4256                                     }
4257                                 } else {
4258                                     buf_ComputeCheckSum(bufp);
4259 #ifdef ODS_DEBUG
4260                                     HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
4261                                     snprintf(dbgstr, 1024,
4262                                              "RDR_ProcessReleaseFileExtentsResult dirty flag not set and not dirty! old %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4263                                              md5dbg, md5dbg3,
4264                                              Fid.volume, Fid.vnode, Fid.unique,
4265                                              pExtent->FileOffset.HighPart,
4266                                              pExtent->FileOffset.LowPart,
4267                                              pExtent->CacheOffset.HighPart,
4268                                              pExtent->CacheOffset.LowPart);
4269                                     OutputDebugStringA( dbgstr);
4270 #endif
4271                                 }
4272                             }
4273 #endif /* VALIDATE_CHECK_SUM */
4274                             lock_ReleaseMutex(&bufp->mx);
4275                         }
4276                     }
4277                 } else {
4278                     /* CacheOffset doesn't match bufp->datap */
4279                     char * datap = RDR_extentBaseAddress + pExtent->CacheOffset.QuadPart;
4280                     cm_buf_t *wbp;
4281
4282                     for (wbp = cm_data.buf_allp; wbp; wbp = wbp->allp) {
4283                         if (wbp->datap == datap)
4284                             break;
4285                     }
4286
4287 #ifdef ODS_DEBUG
4288                     snprintf(dbgstr, 1024,
4289                              "RDR_ProcessReleaseFileExtentsResult non-matching extent vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x flags 0x%x\n",
4290                              Fid.volume, Fid.vnode, Fid.unique,
4291                              pExtent->FileOffset.HighPart,
4292                              pExtent->FileOffset.LowPart,
4293                              pExtent->CacheOffset.HighPart,
4294                              pExtent->CacheOffset.LowPart,
4295                              pExtent->Flags);
4296                     OutputDebugStringA( dbgstr);
4297 #endif
4298                     osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult non-matching extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4299                              Fid.volume, Fid.vnode,
4300                              pExtent->FileOffset.HighPart,
4301                              pExtent->FileOffset.LowPart);
4302                     osi_Log3(afsd_logp, "... coffset 0x%x:%x flags 0x%x",
4303                              pExtent->CacheOffset.HighPart,
4304                              pExtent->CacheOffset.LowPart,
4305                              pExtent->Flags);
4306                     if (wbp)
4307                         osi_Log5(afsd_logp, "... coffset belongs to bp 0x%p vol 0x%x vno 0x%x foffset 0x%x:%x",
4308                                  wbp, wbp->fid.volume, wbp->fid.vnode, wbp->offset.HighPart, wbp->offset.LowPart);
4309                     else
4310                         osi_Log0(afsd_logp, "... coffset cannot be found");
4311 #ifdef DEBUG
4312                     DebugBreak();
4313 #endif
4314                 }
4315                 buf_Release(bufp);
4316             } else {
4317                 if (pExtent->Flags & AFS_EXTENT_FLAG_UNKNOWN) {
4318                     osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4319                              Fid.volume, Fid.vnode, pExtent->FileOffset.HighPart,
4320                              pExtent->FileOffset.LowPart);
4321                     osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; cm_buf not found -- recycled?",
4322                              pExtent->CacheOffset.HighPart,
4323                              pExtent->CacheOffset.LowPart);
4324
4325                     continue;
4326                 }
4327
4328 #ifdef ODS_DEBUG
4329                 snprintf(dbgstr, 1024,
4330                          "RDR_ProcessReleaseFileExtentsResult buf not found vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4331                          Fid.volume, Fid.vnode, Fid.unique,
4332                          pExtent->FileOffset.HighPart,
4333                          pExtent->FileOffset.LowPart,
4334                          pExtent->CacheOffset.HighPart,
4335                          pExtent->CacheOffset.LowPart);
4336                 OutputDebugStringA( dbgstr);
4337 #endif
4338                 osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult buf not found vol 0x%x vno 0x%x foffset 0x%x:%x",
4339                          Fid.volume, Fid.vnode,
4340                          pExtent->FileOffset.HighPart,
4341                          pExtent->FileOffset.LowPart);
4342                 osi_Log2(afsd_logp, "... coffset 0x%x:%x",
4343                          pExtent->CacheOffset.HighPart,
4344                          pExtent->CacheOffset.LowPart);
4345             }
4346         }
4347
4348         if (scp && dirty) {
4349             osi_hyper_t offset = {0,0};
4350             afs_uint32  length = 0;
4351
4352             /*
4353              * there is at least one dirty extent on this file.  queue up background store
4354              * requests for contiguous blocks
4355              */
4356             for ( extentno = 0; extentno < pFileCB->ExtentCount; extentno++ ) {
4357                 AFSFileExtentCB *pExtent = &pFileCB->FileExtents[extentno];
4358                 if (pExtent->FileOffset.QuadPart == offset.QuadPart + length &&
4359                      length < cm_chunkSize) {
4360                     length += cm_data.buf_blockSize;
4361                 } else {
4362                     if (!(offset.QuadPart == 0 && length == 0))
4363                         cm_QueueBKGRequest(scp, cm_BkgStore, offset.LowPart, offset.HighPart,
4364                                             length, 0, userp, &req);
4365                     offset.QuadPart = pExtent->FileOffset.QuadPart;
4366                     length = cm_data.buf_blockSize;
4367                 }
4368             }
4369             cm_QueueBKGRequest(scp, cm_BkgStore, offset.LowPart, offset.HighPart,
4370                                 length, 0, userp, &req);
4371         }
4372
4373         osi_Log5(afsd_logp, "RDR_ProcessReleaseFileExtentsResult File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x Released %d",
4374                   Fid.cell, Fid.volume, Fid.vnode, Fid.unique, released);
4375
4376       cleanup_file:
4377         if (userp)
4378             cm_ReleaseUser(userp);
4379         if (scp)
4380             cm_ReleaseSCache(scp);
4381
4382         p = (char *)pFileCB;
4383         p += sizeof(AFSReleaseFileExtentsResultFileCB);
4384         p += sizeof(AFSFileExtentCB) * (pFileCB->ExtentCount - 1);
4385         pNextFileCB = (AFSReleaseFileExtentsResultFileCB *)p;
4386     }
4387
4388     if (total_extents == 0) {
4389         osi_Log0(afsd_logp, "RDR_ProcessReleaseFileExtentsResult is empty");
4390         code = CM_ERROR_RETRY;
4391     }
4392
4393     if (code)
4394         osi_Log1(afsd_logp, "RDR_ProcessReleaseFileExtentsResult FAILURE code=0x%x", code);
4395     else
4396         osi_Log1(afsd_logp, "RDR_ProcessReleaseFileExtentsResult DONE code=0x%x", code);
4397
4398     return code;
4399 }
4400
4401 DWORD
4402 RDR_ReleaseFailedSetFileExtents( IN cm_user_t *userp,
4403                                  IN AFSSetFileExtentsCB *SetFileExtentsResultCB,
4404                                  IN DWORD ResultBufferLength)
4405 {
4406     afs_uint32  code = 0;
4407     cm_req_t    req;
4408     unsigned int extentno;
4409     cm_fid_t         Fid;
4410     cm_scache_t *    scp = NULL;
4411     int              dirty = 0;
4412
4413     RDR_InitReq(&req);
4414
4415     osi_Log4(afsd_logp, "RDR_ReleaseFailedSetFileExtents %d.%d.%d.%d",
4416               SetFileExtentsResultCB->FileId.Cell, SetFileExtentsResultCB->FileId.Volume,
4417               SetFileExtentsResultCB->FileId.Vnode, SetFileExtentsResultCB->FileId.Unique);
4418
4419     /* Process the release */
4420     Fid.cell = SetFileExtentsResultCB->FileId.Cell;
4421     Fid.volume = SetFileExtentsResultCB->FileId.Volume;
4422     Fid.vnode = SetFileExtentsResultCB->FileId.Vnode;
4423     Fid.unique = SetFileExtentsResultCB->FileId.Unique;
4424     Fid.hash = SetFileExtentsResultCB->FileId.Hash;
4425
4426     if (Fid.cell == 0) {
4427         osi_Log4(afsd_logp, "RDR_ReleaseFailedSetFile Invalid FID %d.%d.%d.%d",
4428                   Fid.cell, Fid.volume, Fid.vnode, Fid.unique);
4429         code = CM_ERROR_INVAL;
4430         goto cleanup_file;
4431     }
4432
4433     code = cm_GetSCache(&Fid, &scp, userp, &req);
4434     if (code) {
4435         osi_Log1(afsd_logp, "RDR_ReleaseFailedSetFileExtents cm_GetSCache FID failure code=0x%x",
4436                   code);
4437         /* Failure to find the cm_scache object cannot block return of the extents */
4438     }
4439
4440     for ( extentno = 0; extentno < SetFileExtentsResultCB->ExtentCount; extentno++ ) {
4441         osi_hyper_t thyper;
4442         cm_buf_t    *bufp;
4443         AFSFileExtentCB *pExtent = &SetFileExtentsResultCB->FileExtents[extentno];
4444
4445         thyper.QuadPart = pExtent->FileOffset.QuadPart;
4446
4447         bufp = buf_Find(&Fid, &thyper);
4448         if (bufp) {
4449             osi_Log5(afsd_logp, "RDR_ReleaseFailedSetFileExtents bufp 0x%p foffset 0x%x:%x coffset 0x%x:%x",
4450                       bufp, pExtent->FileOffset.HighPart, pExtent->FileOffset.LowPart,
4451                       pExtent->CacheOffset.HighPart, pExtent->CacheOffset.LowPart);
4452
4453             lock_ObtainMutex(&bufp->mx);
4454             if (bufp->qFlags & CM_BUF_QREDIR) {
4455                 lock_ObtainWrite(&buf_globalLock);
4456                 if (bufp->qFlags & CM_BUF_QREDIR) {
4457                     buf_RemoveFromRedirQueue(scp, bufp);
4458                     buf_ReleaseLocked(bufp, TRUE);
4459                 }
4460                 lock_ReleaseWrite(&buf_globalLock);
4461             }
4462             lock_ReleaseMutex(&bufp->mx);
4463             buf_Release(bufp);
4464         }
4465     }
4466
4467   cleanup_file:
4468     if (userp)
4469         cm_ReleaseUser(userp);
4470     if (scp)
4471         cm_ReleaseSCache(scp);
4472
4473     osi_Log1(afsd_logp, "RDR_ReleaseFailedSetFileExtents DONE code=0x%x", code);
4474     return code;
4475 }
4476
4477 void
4478 RDR_PioctlOpen( IN cm_user_t *userp,
4479                 IN AFSFileID  ParentId,
4480                 IN AFSPIOCtlOpenCloseRequestCB *pPioctlCB,
4481                 IN BOOL bWow64,
4482                 IN DWORD ResultBufferLength,
4483                 IN OUT AFSCommResult **ResultCB)
4484 {
4485     cm_fid_t    ParentFid;
4486     cm_fid_t    RootFid;
4487
4488     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
4489     if (!(*ResultCB))
4490         return;
4491
4492     memset( *ResultCB,
4493             '\0',
4494             sizeof( AFSCommResult));
4495
4496     /* Get the active directory */
4497     ParentFid.cell = ParentId.Cell;
4498     ParentFid.volume = ParentId.Volume;
4499     ParentFid.vnode = ParentId.Vnode;
4500     ParentFid.unique = ParentId.Unique;
4501     ParentFid.hash = ParentId.Hash;
4502
4503     /* Get the root directory */
4504     RootFid.cell = pPioctlCB->RootId.Cell;
4505     RootFid.volume = pPioctlCB->RootId.Volume;
4506     RootFid.vnode = pPioctlCB->RootId.Vnode;
4507     RootFid.unique = pPioctlCB->RootId.Unique;
4508     RootFid.hash = pPioctlCB->RootId.Hash;
4509
4510     /* Create the pioctl index */
4511     RDR_SetupIoctl(pPioctlCB->RequestId, &ParentFid, &RootFid, userp);
4512
4513     return;
4514 }
4515
4516
4517 void
4518 RDR_PioctlClose( IN cm_user_t *userp,
4519                  IN AFSFileID  ParentId,
4520                  IN AFSPIOCtlOpenCloseRequestCB *pPioctlCB,
4521                  IN BOOL bWow64,
4522                  IN DWORD ResultBufferLength,
4523                  IN OUT AFSCommResult **ResultCB)
4524 {
4525     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
4526     if (!(*ResultCB))
4527         return;
4528
4529     memset( *ResultCB,
4530             '\0',
4531             sizeof( AFSCommResult));
4532
4533     /* Cleanup the pioctl index */
4534     RDR_CleanupIoctl(pPioctlCB->RequestId);
4535
4536     return;
4537 }
4538
4539
4540 void
4541 RDR_PioctlWrite( IN cm_user_t *userp,
4542                  IN AFSFileID  ParentId,
4543                  IN AFSPIOCtlIORequestCB *pPioctlCB,
4544                  IN BOOL bWow64,
4545                  IN DWORD ResultBufferLength,
4546                  IN OUT AFSCommResult **ResultCB)
4547 {
4548     AFSPIOCtlIOResultCB *pResultCB;
4549     cm_scache_t *dscp = NULL;
4550     afs_uint32  code;
4551     cm_req_t    req;
4552     DWORD       status;
4553
4554     RDR_InitReq(&req);
4555     if ( bWow64 )
4556         req.flags |= CM_REQ_WOW64;
4557
4558     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
4559     if (!(*ResultCB))
4560         return;
4561
4562     memset( *ResultCB,
4563             '\0',
4564             sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
4565
4566     pResultCB = (AFSPIOCtlIOResultCB *)(*ResultCB)->ResultData;
4567
4568     code = RDR_IoctlWrite(userp, pPioctlCB->RequestId, pPioctlCB->BufferLength, pPioctlCB->MappedBuffer, &req);
4569     if (code) {
4570         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
4571         (*ResultCB)->ResultStatus = status;
4572         return;
4573     }
4574
4575     pResultCB->BytesProcessed = pPioctlCB->BufferLength;
4576     (*ResultCB)->ResultBufferLength = sizeof( AFSPIOCtlIOResultCB);
4577 }
4578
4579 void
4580 RDR_PioctlRead( IN cm_user_t *userp,
4581                 IN AFSFileID  ParentId,
4582                 IN AFSPIOCtlIORequestCB *pPioctlCB,
4583                 IN BOOL bWow64,
4584                 IN BOOL bIsLocalSystem,
4585                 IN DWORD ResultBufferLength,
4586                 IN OUT AFSCommResult **ResultCB)
4587 {
4588     AFSPIOCtlIOResultCB *pResultCB;
4589     cm_scache_t *dscp = NULL;
4590     afs_uint32  code;
4591     cm_req_t    req;
4592     DWORD       status;
4593     afs_uint32  pflags = (bIsLocalSystem ? AFSCALL_FLAG_LOCAL_SYSTEM : 0);
4594
4595     RDR_InitReq(&req);
4596     if ( bWow64 )
4597         req.flags |= CM_REQ_WOW64;
4598
4599     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
4600     if (!(*ResultCB))
4601         return;
4602
4603     memset( *ResultCB,
4604             '\0',
4605             sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
4606
4607     pResultCB = (AFSPIOCtlIOResultCB *)(*ResultCB)->ResultData;
4608
4609     code = RDR_IoctlRead(userp, pPioctlCB->RequestId, pPioctlCB->BufferLength, pPioctlCB->MappedBuffer,
4610                          &pResultCB->BytesProcessed, &req, pflags);
4611     if (code) {
4612         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
4613         (*ResultCB)->ResultStatus = status;
4614         return;
4615     }
4616
4617     (*ResultCB)->ResultBufferLength = sizeof( AFSPIOCtlIOResultCB);
4618 }
4619
4620 void
4621 RDR_ByteRangeLockSync( IN cm_user_t     *userp,
4622                        IN AFSFileID     FileId,
4623                        IN AFSByteRangeLockRequestCB *pBRLRequestCB,
4624                        IN BOOL bWow64,
4625                        IN DWORD ResultBufferLength,
4626                        IN OUT AFSCommResult **ResultCB)
4627 {
4628     AFSByteRangeLockResultCB *pResultCB = NULL;
4629     LARGE_INTEGER ProcessId;
4630     DWORD       Length;
4631     cm_scache_t *scp = NULL;
4632     cm_fid_t    Fid;
4633     afs_uint32  code;
4634     cm_req_t    req;
4635     cm_key_t    key;
4636     DWORD       i;
4637     DWORD       status;
4638
4639     ProcessId.QuadPart = pBRLRequestCB->ProcessId;
4640
4641     RDR_InitReq(&req);
4642     if ( bWow64 )
4643         req.flags |= CM_REQ_WOW64;
4644
4645     osi_Log4(afsd_logp, "RDR_ByteRangeLockSync File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
4646               FileId.Cell, FileId.Volume,
4647               FileId.Vnode, FileId.Unique);
4648     osi_Log2(afsd_logp, "... ProcessId 0x%x:%x",
4649              ProcessId.HighPart, ProcessId.LowPart);
4650
4651     Length = sizeof( AFSByteRangeLockResultCB) + ((pBRLRequestCB->Count - 1) * sizeof(AFSByteRangeLockResult));
4652     if (Length > ResultBufferLength) {
4653         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult));
4654         if (!(*ResultCB))
4655             return;
4656         memset( *ResultCB, 0, sizeof(AFSCommResult));
4657         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
4658         return;
4659     }
4660
4661     *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
4662     if (!(*ResultCB))
4663         return;
4664     memset( *ResultCB, '\0', Length + sizeof( AFSCommResult) );
4665     (*ResultCB)->ResultBufferLength = Length;
4666
4667     pResultCB = (AFSByteRangeLockResultCB *)(*ResultCB)->ResultData;
4668     pResultCB->FileId = FileId;
4669     pResultCB->Count = pBRLRequestCB->Count;
4670
4671     /* Allocate the extents from the buffer package */
4672     Fid.cell = FileId.Cell;
4673     Fid.volume = FileId.Volume;
4674     Fid.vnode = FileId.Vnode;
4675     Fid.unique = FileId.Unique;
4676     Fid.hash = FileId.Hash;
4677
4678     code = cm_GetSCache(&Fid, &scp, userp, &req);
4679     if (code) {
4680         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
4681         (*ResultCB)->ResultStatus = status;
4682         (*ResultCB)->ResultBufferLength = 0;
4683         osi_Log2(afsd_logp, "RDR_ByteRangeLockSync cm_GetSCache FID failure code=0x%x status=0x%x",
4684                   code, status);
4685         return;
4686     }
4687
4688     lock_ObtainWrite(&scp->rw);
4689
4690     /* start by looking up the file's end */
4691     code = cm_SyncOp(scp, NULL, userp, &req, 0,
4692                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
4693     if (code) {
4694         lock_ReleaseWrite(&scp->rw);
4695         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
4696         (*ResultCB)->ResultStatus = status;
4697         (*ResultCB)->ResultBufferLength = 0;
4698         osi_Log3(afsd_logp, "RDR_ByteRangeLockSync cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
4699                  scp, code, status);
4700         return;
4701     }
4702
4703     /* the scp is now locked and current */
4704     key = cm_GenerateKey(CM_SESSION_IFS, ProcessId.QuadPart, 0);
4705
4706     for ( i=0; i<pBRLRequestCB->Count; i++ ) {
4707         pResultCB->Result[i].LockType = pBRLRequestCB->Request[i].LockType;
4708         pResultCB->Result[i].Offset = pBRLRequestCB->Request[i].Offset;
4709         pResultCB->Result[i].Length = pBRLRequestCB->Request[i].Length;
4710
4711         code = cm_Lock(scp,
4712                        pBRLRequestCB->Request[i].LockType == AFS_BYTE_RANGE_LOCK_TYPE_SHARED,
4713                        pBRLRequestCB->Request[i].Offset,
4714                        pBRLRequestCB->Request[i].Length,
4715                        key, 0, userp, &req, NULL);
4716
4717         if (code) {
4718             osi_Log4(afsd_logp, "RDR_ByteRangeLockSync FAILURE code 0x%x type 0x%u offset 0x%x:%x",
4719                      code,
4720                      pBRLRequestCB->Request[i].LockType,
4721                      pBRLRequestCB->Request[i].Offset.HighPart,
4722                      pBRLRequestCB->Request[i].Offset.LowPart);
4723             osi_Log2(afsd_logp, "... length 0x%x:%x",
4724                      pBRLRequestCB->Request[i].Length.HighPart,
4725                      pBRLRequestCB->Request[i].Length.LowPart);
4726         }
4727
4728         switch (code) {
4729         case 0:
4730             pResultCB->Result[i].Status = 0;
4731             break;
4732         case CM_ERROR_WOULDBLOCK:
4733             pResultCB->Result[i].Status = STATUS_FILE_LOCK_CONFLICT;
4734             break;
4735         default:
4736             pResultCB->Result[i].Status = STATUS_LOCK_NOT_GRANTED;
4737         }
4738     }
4739
4740     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
4741     lock_ReleaseWrite(&scp->rw);
4742     cm_ReleaseSCache(scp);
4743
4744     (*ResultCB)->ResultStatus = 0;
4745     osi_Log0(afsd_logp, "RDR_ByteRangeLockSync SUCCESS");
4746     return;
4747 }
4748
4749 void
4750 RDR_ByteRangeUnlock( IN cm_user_t     *userp,
4751                      IN AFSFileID     FileId,
4752                      IN AFSByteRangeUnlockRequestCB *pBRURequestCB,
4753                      IN BOOL bWow64,
4754                      IN DWORD ResultBufferLength,
4755                      IN OUT AFSCommResult **ResultCB)
4756 {
4757     AFSByteRangeUnlockResultCB *pResultCB = NULL;
4758     LARGE_INTEGER ProcessId;
4759     DWORD       Length;
4760     cm_scache_t *scp = NULL;
4761     cm_fid_t    Fid;
4762     afs_uint32  code;
4763     cm_req_t    req;
4764     cm_key_t    key;
4765     DWORD       i;
4766     DWORD       status;
4767
4768     ProcessId.QuadPart = pBRURequestCB->ProcessId;
4769
4770     RDR_InitReq(&req);
4771     if ( bWow64 )
4772         req.flags |= CM_REQ_WOW64;
4773
4774     osi_Log4(afsd_logp, "RDR_ByteRangeUnlock File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
4775               FileId.Cell, FileId.Volume,
4776               FileId.Vnode, FileId.Unique);
4777     osi_Log2(afsd_logp, "... ProcessId 0x%x:%x",
4778              ProcessId.HighPart, ProcessId.LowPart);
4779
4780     Length = sizeof( AFSByteRangeUnlockResultCB) + ((pBRURequestCB->Count - 1) * sizeof(AFSByteRangeLockResult));
4781     if (Length > ResultBufferLength) {
4782         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult));
4783         if (!(*ResultCB))
4784             return;
4785         memset( *ResultCB, 0, sizeof(AFSCommResult));
4786         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
4787         return;
4788     }
4789
4790     *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
4791     if (!(*ResultCB))
4792         return;
4793     memset( *ResultCB, '\0', Length + sizeof( AFSCommResult) );
4794     (*ResultCB)->ResultBufferLength = Length;
4795
4796     pResultCB = (AFSByteRangeUnlockResultCB *)(*ResultCB)->ResultData;
4797     pResultCB->Count = pBRURequestCB->Count;
4798
4799     /* Allocate the extents from the buffer package */
4800     Fid.cell = FileId.Cell;
4801     Fid.volume = FileId.Volume;
4802     Fid.vnode = FileId.Vnode;
4803     Fid.unique = FileId.Unique;
4804     Fid.hash = FileId.Hash;
4805
4806     code = cm_GetSCache(&Fid, &scp, userp, &req);
4807     if (code) {
4808         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
4809         (*ResultCB)->ResultStatus = status;
4810         (*ResultCB)->ResultBufferLength = 0;
4811         osi_Log2(afsd_logp, "RDR_ByteRangeUnlock cm_GetSCache FID failure code=0x%x status=0x%x",
4812                   code, status);
4813         return;
4814     }
4815
4816     lock_ObtainWrite(&scp->rw);
4817
4818     /* start by looking up the file's end */
4819     code = cm_SyncOp(scp, NULL, userp, &req, 0,
4820                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
4821     if (code) {
4822         lock_ReleaseWrite(&scp->rw);
4823         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
4824         (*ResultCB)->ResultStatus = status;
4825         (*ResultCB)->ResultBufferLength = 0;
4826         osi_Log3(afsd_logp, "RDR_ByteRangeUnlock cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
4827                  scp, code, status);
4828         return;
4829     }
4830
4831     /* the scp is now locked and current */
4832     key = cm_GenerateKey(CM_SESSION_IFS, ProcessId.QuadPart, 0);
4833
4834     for ( i=0; i<pBRURequestCB->Count; i++ ) {
4835         pResultCB->Result[i].LockType = pBRURequestCB->Request[i].LockType;
4836         pResultCB->Result[i].Offset = pBRURequestCB->Request[i].Offset;
4837         pResultCB->Result[i].Length = pBRURequestCB->Request[i].Length;
4838
4839         code = cm_Unlock(scp,
4840                          pBRURequestCB->Request[i].LockType == AFS_BYTE_RANGE_LOCK_TYPE_SHARED,
4841                          pBRURequestCB->Request[i].Offset,
4842                          pBRURequestCB->Request[i].Length,
4843                          key, CM_UNLOCK_FLAG_MATCH_RANGE, userp, &req);
4844
4845         if (code) {
4846             osi_Log4(afsd_logp, "RDR_ByteRangeUnlock FAILURE code 0x%x type 0x%u offset 0x%x:%x",
4847                      code, pBRURequestCB->Request[i].LockType,
4848                      pBRURequestCB->Request[i].Offset.HighPart,
4849                      pBRURequestCB->Request[i].Offset.LowPart);
4850             osi_Log2(afsd_logp, "... length 0x%x:%x",
4851                      pBRURequestCB->Request[i].Length.HighPart,
4852                      pBRURequestCB->Request[i].Length.LowPart);
4853         }
4854         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
4855         pResultCB->Result[i].Status = status;
4856     }
4857
4858     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
4859     lock_ReleaseWrite(&scp->rw);
4860     cm_ReleaseSCache(scp);
4861
4862     (*ResultCB)->ResultStatus = 0;
4863     osi_Log0(afsd_logp, "RDR_ByteRangeUnlock SUCCESS");
4864     return;
4865 }
4866
4867 void
4868 RDR_ByteRangeUnlockAll( IN cm_user_t     *userp,
4869                         IN AFSFileID     FileId,
4870                         IN AFSByteRangeUnlockRequestCB *pBRURequestCB,
4871                         IN BOOL bWow64,
4872                         IN DWORD ResultBufferLength,
4873                         IN OUT AFSCommResult **ResultCB)
4874 {
4875     AFSByteRangeUnlockResultCB *pResultCB = NULL;
4876     LARGE_INTEGER ProcessId;
4877     cm_scache_t *scp = NULL;
4878     cm_fid_t    Fid;
4879     afs_uint32  code;
4880     cm_req_t    req;
4881     cm_key_t    key;
4882     DWORD       status;
4883
4884     ProcessId.QuadPart = pBRURequestCB->ProcessId;
4885
4886     RDR_InitReq(&req);
4887     if ( bWow64 )
4888         req.flags |= CM_REQ_WOW64;
4889
4890     osi_Log4(afsd_logp, "RDR_ByteRangeUnlockAll File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
4891               FileId.Cell, FileId.Volume,
4892               FileId.Vnode, FileId.Unique);
4893     osi_Log2(afsd_logp, "... ProcessId 0x%x:%x",
4894              ProcessId.HighPart, ProcessId.LowPart);
4895
4896     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
4897     if (!(*ResultCB))
4898         return;
4899     memset( *ResultCB, '\0', sizeof( AFSCommResult));
4900     (*ResultCB)->ResultBufferLength = 0;
4901
4902     /* Allocate the extents from the buffer package */
4903     Fid.cell = FileId.Cell;
4904     Fid.volume = FileId.Volume;
4905     Fid.vnode = FileId.Vnode;
4906     Fid.unique = FileId.Unique;
4907     Fid.hash = FileId.Hash;
4908
4909     code = cm_GetSCache(&Fid, &scp, userp, &req);
4910     if (code) {
4911         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
4912         (*ResultCB)->ResultStatus = status;
4913         (*ResultCB)->ResultBufferLength = 0;
4914         osi_Log2(afsd_logp, "RDR_ByteRangeUnlockAll cm_GetSCache FID failure code=0x%x status=0x%x",
4915                   code, status);
4916         return;
4917     }
4918
4919     lock_ObtainWrite(&scp->rw);
4920
4921     /* start by looking up the file's end */
4922     code = cm_SyncOp(scp, NULL, userp, &req, 0,
4923                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
4924     if (code) {
4925         lock_ReleaseWrite(&scp->rw);
4926         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
4927         (*ResultCB)->ResultStatus = status;
4928         (*ResultCB)->ResultBufferLength = 0;
4929         osi_Log3(afsd_logp, "RDR_ByteRangeUnlockAll cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
4930                  scp, code, status);
4931         return;
4932     }
4933
4934     /* the scp is now locked and current */
4935     key = cm_GenerateKey(CM_SESSION_IFS, ProcessId.QuadPart, 0);
4936
4937     code = cm_UnlockByKey(scp, key, 0, userp, &req);
4938
4939     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
4940     lock_ReleaseWrite(&scp->rw);
4941     cm_ReleaseSCache(scp);
4942
4943     smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
4944     (*ResultCB)->ResultStatus = status;
4945
4946     if (code)
4947         osi_Log1(afsd_logp, "RDR_ByteRangeUnlockAll FAILURE code 0x%x", code);
4948     else
4949         osi_Log0(afsd_logp, "RDR_ByteRangeUnlockAll SUCCESS");
4950     return;
4951
4952 }
4953
4954 void
4955 RDR_GetVolumeInfo( IN cm_user_t     *userp,
4956                    IN AFSFileID     FileId,
4957                    IN BOOL bWow64,
4958                    IN DWORD ResultBufferLength,
4959                    IN OUT AFSCommResult **ResultCB)
4960 {
4961     AFSVolumeInfoCB *pResultCB = NULL;
4962     DWORD       Length;
4963     cm_scache_t *scp = NULL;
4964     cm_volume_t *volp = NULL;
4965     cm_vol_state_t *volstatep = NULL;
4966     afs_uint32   volType;
4967     cm_cell_t   *cellp = NULL;
4968     cm_fid_t    Fid;
4969     afs_uint32  code;
4970     cm_req_t    req;
4971     DWORD       status;
4972     FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
4973
4974     char volName[32]="(unknown)";
4975     char offLineMsg[256]="server temporarily inaccessible";
4976     char motd[256]="server temporarily inaccessible";
4977     cm_conn_t *connp;
4978     AFSFetchVolumeStatus volStat;
4979     char *Name;
4980     char *OfflineMsg;
4981     char *MOTD;
4982     struct rx_connection * rxconnp;
4983
4984     RDR_InitReq(&req);
4985     if ( bWow64 )
4986         req.flags |= CM_REQ_WOW64;
4987
4988     osi_Log4(afsd_logp, "RDR_GetVolumeInfo File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
4989              FileId.Cell, FileId.Volume,
4990              FileId.Vnode, FileId.Unique);
4991
4992     Length = sizeof( AFSCommResult) + sizeof(AFSVolumeInfoCB);
4993     if (sizeof(AFSVolumeInfoCB) > ResultBufferLength) {
4994         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
4995         if (!(*ResultCB))
4996             return;
4997         memset( *ResultCB, 0, sizeof(AFSCommResult));
4998         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
4999         return;
5000     }
5001
5002     *ResultCB = (AFSCommResult *)malloc( Length );
5003     if (!(*ResultCB))
5004         return;
5005     memset( *ResultCB, '\0', Length );
5006     (*ResultCB)->ResultBufferLength = sizeof(AFSVolumeInfoCB);
5007     pResultCB = (AFSVolumeInfoCB *)(*ResultCB)->ResultData;
5008
5009     /* Allocate the extents from the buffer package */
5010     if (FileId.Cell != 0) {
5011         Fid.cell = FileId.Cell;
5012         Fid.volume = FileId.Volume;
5013         Fid.vnode = FileId.Vnode;
5014         Fid.unique = FileId.Unique;
5015         Fid.hash = FileId.Hash;
5016
5017         code = cm_GetSCache(&Fid, &scp, userp, &req);
5018         if (code) {
5019             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5020             (*ResultCB)->ResultStatus = status;
5021             (*ResultCB)->ResultBufferLength = 0;
5022             osi_Log2(afsd_logp, "RDR_GetVolumeInfo cm_GetSCache FID failure code=0x%x status=0x%x",
5023                       code, status);
5024             return;
5025         }
5026     } else {
5027         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
5028         osi_Log0(afsd_logp, "RDR_GetVolumeInfo Object Name Invalid - Cell = 0");
5029         return;
5030     }
5031     lock_ObtainWrite(&scp->rw);
5032
5033     /* start by looking up the file's end */
5034     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5035                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5036     if (code) {
5037         lock_ReleaseWrite(&scp->rw);
5038         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5039         (*ResultCB)->ResultStatus = status;
5040         (*ResultCB)->ResultBufferLength = 0;
5041         osi_Log3(afsd_logp, "RDR_GetVolumeInfo cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
5042                  scp, code, status);
5043         return;
5044     }
5045
5046     /* Fake for now */
5047     pResultCB->SectorsPerAllocationUnit = 1;
5048     pResultCB->BytesPerSector = 1024;
5049
5050     pResultCB->CellID = scp->fid.cell;
5051     pResultCB->VolumeID = scp->fid.volume;
5052     pResultCB->Characteristics = FILE_REMOTE_DEVICE;
5053     pResultCB->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK |
5054         FILE_SUPPORTS_REPARSE_POINTS;
5055
5056     if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
5057          scp->fid.volume==AFS_FAKE_ROOT_VOL_ID)
5058     {
5059         pResultCB->TotalAllocationUnits.QuadPart = 100;
5060         memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
5061
5062         pResultCB->AvailableAllocationUnits.QuadPart = 0;
5063         pResultCB->Characteristics |= FILE_READ_ONLY_DEVICE;
5064
5065         pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( "Freelance.Local.Root", -1, pResultCB->VolumeLabel,
5066                                                        (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
5067         if ( pResultCB->VolumeLabelLength )
5068             pResultCB->VolumeLabelLength--;
5069     } else {
5070         memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
5071
5072         volp = cm_GetVolumeByFID(&scp->fid);
5073         if (!volp) {
5074             code = CM_ERROR_NOSUCHVOLUME;
5075             goto _done;
5076         }
5077         volstatep = cm_VolumeStateByID(volp, scp->fid.volume);
5078         volType = cm_VolumeType(volp, scp->fid.volume);
5079
5080         pResultCB->Characteristics |= ((volType == ROVOL || volType == BACKVOL) ? FILE_READ_ONLY_DEVICE : 0);
5081
5082         Name = volName;
5083         OfflineMsg = offLineMsg;
5084         MOTD = motd;
5085         lock_ReleaseWrite(&scp->rw);
5086         do {
5087             code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
5088             if (code) continue;
5089
5090             rxconnp = cm_GetRxConn(connp);
5091             code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
5092                                          &volStat, &Name, &OfflineMsg, &MOTD);
5093             rx_PutConnection(rxconnp);
5094
5095         } while (cm_Analyze(connp, userp, &req, &scp->fid, 0, NULL, NULL, NULL, code));
5096         code = cm_MapRPCError(code, &req);
5097         if (code == 0) {
5098             pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;
5099             pResultCB->AvailableAllocationUnits.QuadPart = volStat.PartBlocksAvail;
5100
5101             pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( Name, -1, pResultCB->VolumeLabel,
5102                                                            (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
5103         } else {
5104             pResultCB->TotalAllocationUnits.QuadPart = 0x7FFFFFFF;
5105             pResultCB->AvailableAllocationUnits.QuadPart = (volType == ROVOL || volType == BACKVOL) ? 0 : 0x3F000000;
5106
5107             pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( volp->namep, -1, pResultCB->VolumeLabel,
5108                                                            (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
5109             code = 0;
5110         }
5111         if ( pResultCB->VolumeLabelLength )
5112             pResultCB->VolumeLabelLength--;
5113
5114         lock_ObtainWrite(&scp->rw);
5115     }
5116     pResultCB->VolumeLabelLength *= sizeof(WCHAR);  /* convert to bytes from chars */
5117
5118     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5119
5120   _done:
5121     lock_ReleaseWrite(&scp->rw);
5122     if (volp)
5123        cm_PutVolume(volp);
5124     cm_ReleaseSCache(scp);
5125
5126     smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5127     (*ResultCB)->ResultStatus = status;
5128     osi_Log0(afsd_logp, "RDR_GetVolumeInfo SUCCESS");
5129     return;
5130 }
5131
5132 void
5133 RDR_HoldFid( IN cm_user_t     *userp,
5134              IN AFSHoldFidRequestCB * pHoldFidCB,
5135              IN BOOL bFast,
5136              IN DWORD ResultBufferLength,
5137              IN OUT AFSCommResult **ResultCB)
5138 {
5139     AFSHoldFidResultCB *pResultCB = NULL;
5140     DWORD       index;
5141     DWORD       Length;
5142     cm_req_t    req;
5143
5144     RDR_InitReq(&req);
5145
5146     osi_Log1(afsd_logp, "RDR_HoldFid Count=%u", pHoldFidCB->Count);
5147
5148     Length = sizeof(AFSHoldFidResultCB) + (pHoldFidCB->Count-1) * sizeof(AFSFidResult);
5149     if (Length > ResultBufferLength) {
5150         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
5151         if (!(*ResultCB))
5152             return;
5153         memset( *ResultCB, 0, sizeof(AFSCommResult));
5154         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
5155         return;
5156     }
5157     *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
5158     if (!(*ResultCB))
5159         return;
5160     memset( *ResultCB, '\0', Length );
5161     (*ResultCB)->ResultBufferLength = Length;
5162     pResultCB = (AFSHoldFidResultCB *)(*ResultCB)->ResultData;
5163
5164     for ( index = 0; index < pHoldFidCB->Count; index++ )
5165     {
5166         cm_scache_t *scp = NULL;
5167         cm_fid_t    Fid;
5168
5169         Fid.cell   = pResultCB->Result[index].FileID.Cell   = pHoldFidCB->FileID[index].Cell;
5170         Fid.volume = pResultCB->Result[index].FileID.Volume = pHoldFidCB->FileID[index].Volume;
5171         Fid.vnode  = pResultCB->Result[index].FileID.Vnode  = pHoldFidCB->FileID[index].Vnode;
5172         Fid.unique = pResultCB->Result[index].FileID.Unique = pHoldFidCB->FileID[index].Unique;
5173         Fid.hash   = pResultCB->Result[index].FileID.Hash   = pHoldFidCB->FileID[index].Hash;
5174
5175         osi_Log4( afsd_logp,
5176                   "RDR_HoldFid File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
5177                   Fid.cell, Fid.volume, Fid.vnode, Fid.unique);
5178
5179         scp = cm_FindSCache(&Fid);
5180         if (scp) {
5181             RDR_FlagScpInUse( scp, FALSE );
5182             cm_ReleaseSCache(scp);
5183         }
5184         pResultCB->Result[index].Status = 0;
5185     }
5186
5187     (*ResultCB)->ResultStatus = 0;
5188     osi_Log0(afsd_logp, "RDR_HoldFid SUCCESS");
5189     return;
5190 }
5191
5192 void
5193 RDR_ReleaseFid( IN cm_user_t     *userp,
5194                 IN AFSReleaseFidRequestCB * pReleaseFidCB,
5195                 IN BOOL bFast,
5196                 IN DWORD ResultBufferLength,
5197                 IN OUT AFSCommResult **ResultCB)
5198 {
5199     AFSReleaseFidResultCB *pResultCB = NULL;
5200     DWORD       index;
5201     DWORD       Length;
5202     cm_req_t    req;
5203
5204     RDR_InitReq(&req);
5205
5206     osi_Log1(afsd_logp, "RDR_ReleaseFid Count=%u", pReleaseFidCB->Count);
5207
5208     Length = sizeof(AFSReleaseFidResultCB) + (pReleaseFidCB->Count ? pReleaseFidCB->Count-1 : 0) * sizeof(AFSFidResult);
5209     if (Length > ResultBufferLength) {
5210         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
5211         if (!(*ResultCB))
5212             return;
5213         memset( *ResultCB, 0, sizeof(AFSCommResult));
5214         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
5215         return;
5216     }
5217     *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
5218     if (!(*ResultCB))
5219         return;
5220     memset( *ResultCB, '\0', Length );
5221     (*ResultCB)->ResultBufferLength = Length;
5222     pResultCB = (AFSReleaseFidResultCB *)(*ResultCB)->ResultData;
5223
5224     for ( index = 0; index < pReleaseFidCB->Count; index++ )
5225     {
5226         cm_scache_t *scp = NULL;
5227         cm_fid_t    Fid;
5228
5229         Fid.cell   = pResultCB->Result[index].FileID.Cell   = pReleaseFidCB->FileID[index].Cell;
5230         Fid.volume = pResultCB->Result[index].FileID.Volume = pReleaseFidCB->FileID[index].Volume;
5231         Fid.vnode  = pResultCB->Result[index].FileID.Vnode  = pReleaseFidCB->FileID[index].Vnode;
5232         Fid.unique = pResultCB->Result[index].FileID.Unique = pReleaseFidCB->FileID[index].Unique;
5233         Fid.hash   = pResultCB->Result[index].FileID.Hash   = pReleaseFidCB->FileID[index].Hash;
5234
5235         osi_Log4( afsd_logp,
5236                   "RDR_ReleaseFid File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
5237                   Fid.cell, Fid.volume, Fid.vnode, Fid.unique);
5238
5239         scp = cm_FindSCache(&Fid);
5240         if (scp) {
5241             lock_ObtainWrite(&scp->rw);
5242             scp->flags &= ~CM_SCACHEFLAG_RDR_IN_USE;
5243             lock_ReleaseWrite(&scp->rw);
5244
5245             cm_ReleaseSCache(scp);
5246         }
5247         pResultCB->Result[index].Status = 0;
5248     }
5249     pResultCB->Count = pReleaseFidCB->Count;
5250
5251     (*ResultCB)->ResultStatus = 0;
5252     osi_Log0(afsd_logp, "RDR_ReleaseFid SUCCESS");
5253     return;
5254 }
5255
5256 /*
5257  * The redirector makes several assumptions regarding the
5258  * SRVSVC and WKSSVC pipes transactions.  First, the interface
5259  * versions are those indicated below.  Secondly, the encoding
5260  * will be performed using NDR version 2.  These assumptions
5261  * may not hold in the future and end-to-end MSRPC Bind
5262  * negotiations may need to be supported.  Of course, these
5263  * are the only interface versions that are supported by the
5264  * service.
5265  */
5266 #define MSRPC_PIPE_PREFIX L".\\"
5267
5268 static const UUID MSRPC_SRVSVC_UUID = {0x4B324FC8, 0x1670, 0x01D3,
5269                                        {0x12, 0x78, 0x5A, 0x47, 0xBF, 0x6E, 0xE1, 0x88}};
5270 #define MSRPC_SRVSVC_NAME L"PIPE\\SRVSVC"
5271 #define MSRPC_SRVSVC_VERS 3
5272
5273 static const UUID MSRPC_WKSSVC_UUID = {0x6BFFD098, 0xA112, 0x3610,
5274                                        {0x98, 0x33, 0x46, 0xC3, 0xF8, 0x7E, 0x34, 0x5A}};
5275 #define MSRPC_WKSSVC_NAME L"PIPE\\WKSSVC"
5276 #define MSRPC_WKSSVC_VERS 1
5277
5278 static const UUID MSRPC_NDR_UUID = {0x8A885D04, 0x1CEB, 0x11C9,
5279                                     {0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60}};
5280 #define MSRPC_NDR_NAME    L"NDR"
5281 #define MSRPC_NDR_VERS    2
5282
5283 extern RPC_IF_HANDLE srvsvc_v3_0_s_ifspec;
5284 extern RPC_IF_HANDLE wkssvc_v1_0_s_ifspec;
5285
5286 void
5287 RDR_PipeOpen( IN cm_user_t *userp,
5288               IN AFSFileID  ParentId,
5289               IN WCHAR     *Name,
5290               IN DWORD      NameLength,
5291               IN AFSPipeOpenCloseRequestCB *pPipe_CB,
5292               IN BOOL bWow64,
5293               IN DWORD ResultBufferLength,
5294               IN OUT AFSCommResult **ResultCB)
5295 {
5296     cm_fid_t    ParentFid;
5297     cm_fid_t    RootFid;
5298
5299     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
5300     if (!(*ResultCB))
5301         return;
5302
5303     memset( *ResultCB,
5304             '\0',
5305             sizeof( AFSCommResult));
5306
5307     /* Get the active directory */
5308     ParentFid.cell = ParentId.Cell;
5309     ParentFid.volume = ParentId.Volume;
5310     ParentFid.vnode = ParentId.Vnode;
5311     ParentFid.unique = ParentId.Unique;
5312     ParentFid.hash = ParentId.Hash;
5313
5314     /* Get the root directory */
5315     RootFid.cell = pPipe_CB->RootId.Cell;
5316     RootFid.volume = pPipe_CB->RootId.Volume;
5317     RootFid.vnode = pPipe_CB->RootId.Vnode;
5318     RootFid.unique = pPipe_CB->RootId.Unique;
5319     RootFid.hash = pPipe_CB->RootId.Hash;
5320
5321     /* Create the pipe index */
5322     (*ResultCB)->ResultStatus =
5323       RDR_SetupPipe( pPipe_CB->RequestId, &ParentFid, &RootFid,
5324                      Name, NameLength, userp);
5325     return;
5326 }
5327
5328
5329 void
5330 RDR_PipeClose( IN cm_user_t *userp,
5331                IN AFSFileID  ParentId,
5332                IN AFSPipeOpenCloseRequestCB *pPipe_CB,
5333                IN BOOL bWow64,
5334                IN DWORD ResultBufferLength,
5335                IN OUT AFSCommResult **ResultCB)
5336 {
5337     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
5338     if (!(*ResultCB))
5339         return;
5340
5341     memset( *ResultCB,
5342             '\0',
5343             sizeof( AFSCommResult));
5344
5345     /* Cleanup the pipe index */
5346     RDR_CleanupPipe(pPipe_CB->RequestId);
5347
5348     return;
5349 }
5350
5351
5352 void
5353 RDR_PipeWrite( IN cm_user_t *userp,
5354                IN AFSFileID  ParentId,
5355                IN AFSPipeIORequestCB *pPipe_CB,
5356                IN BYTE *pPipe_Data,
5357                IN BOOL bWow64,
5358                IN DWORD ResultBufferLength,
5359                IN OUT AFSCommResult **ResultCB)
5360 {
5361     AFSPipeIOResultCB *pResultCB;
5362     cm_scache_t *dscp = NULL;
5363     afs_uint32  code;
5364     cm_req_t    req;
5365     DWORD       status;
5366
5367     RDR_InitReq(&req);
5368     if ( bWow64 )
5369         req.flags |= CM_REQ_WOW64;
5370
5371     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPipeIOResultCB));
5372     if (!(*ResultCB))
5373         return;
5374
5375     memset( *ResultCB,
5376             '\0',
5377             sizeof( AFSCommResult) + sizeof(AFSPipeIOResultCB));
5378
5379     pResultCB = (AFSPipeIOResultCB *)(*ResultCB)->ResultData;
5380
5381     code = RDR_Pipe_Write( pPipe_CB->RequestId, pPipe_CB->BufferLength, pPipe_Data, &req, userp);
5382     if (code) {
5383         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5384         (*ResultCB)->ResultStatus = status;
5385         return;
5386     }
5387
5388     pResultCB->BytesProcessed = pPipe_CB->BufferLength;
5389     (*ResultCB)->ResultBufferLength = sizeof( AFSPipeIOResultCB);
5390 }
5391
5392
5393 void
5394 RDR_PipeRead( IN cm_user_t *userp,
5395               IN AFSFileID  ParentId,
5396               IN AFSPipeIORequestCB *pPipe_CB,
5397               IN BOOL bWow64,
5398               IN DWORD ResultBufferLength,
5399               IN OUT AFSCommResult **ResultCB)
5400 {
5401     BYTE *pPipe_Data;
5402     cm_scache_t *dscp = NULL;
5403     afs_uint32  code;
5404     cm_req_t    req;
5405     DWORD       status;
5406
5407     RDR_InitReq(&req);
5408     if ( bWow64 )
5409         req.flags |= CM_REQ_WOW64;
5410
5411     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + ResultBufferLength);
5412     if (!(*ResultCB))
5413         return;
5414
5415     memset( *ResultCB,
5416             '\0',
5417             sizeof( AFSCommResult));
5418
5419     pPipe_Data = (BYTE *)(*ResultCB)->ResultData;
5420
5421     code = RDR_Pipe_Read( pPipe_CB->RequestId, ResultBufferLength, pPipe_Data,
5422                           &(*ResultCB)->ResultBufferLength, &req, userp);
5423     if (code) {
5424         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5425         (*ResultCB)->ResultStatus = status;
5426         return;
5427     }
5428 }
5429
5430
5431 void
5432 RDR_PipeSetInfo( IN cm_user_t *userp,
5433                  IN AFSFileID  ParentId,
5434                  IN AFSPipeInfoRequestCB *pPipeInfo_CB,
5435                  IN BYTE *pPipe_Data,
5436                  IN BOOL bWow64,
5437                  IN DWORD ResultBufferLength,
5438                  IN OUT AFSCommResult **ResultCB)
5439 {
5440     cm_scache_t *dscp = NULL;
5441     cm_req_t    req;
5442     DWORD       status;
5443
5444     RDR_InitReq(&req);
5445     if ( bWow64 )
5446         req.flags |= CM_REQ_WOW64;
5447
5448     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
5449     if (!(*ResultCB))
5450         return;
5451
5452     memset( *ResultCB,
5453             '\0',
5454             sizeof( AFSCommResult));
5455
5456     status = RDR_Pipe_SetInfo( pPipeInfo_CB->RequestId, pPipeInfo_CB->InformationClass,
5457                                pPipeInfo_CB->BufferLength, pPipe_Data, &req, userp);
5458
5459     (*ResultCB)->ResultStatus = status;
5460 }
5461
5462
5463 void
5464 RDR_PipeQueryInfo( IN cm_user_t *userp,
5465                    IN AFSFileID  ParentId,
5466                    IN AFSPipeInfoRequestCB *pPipeInfo_CB,
5467                    IN BOOL bWow64,
5468                    IN DWORD ResultBufferLength,
5469                    IN OUT AFSCommResult **ResultCB)
5470 {
5471     BYTE *pPipe_Data;
5472     cm_scache_t *dscp = NULL;
5473     cm_req_t    req;
5474     DWORD       status;
5475
5476     RDR_InitReq(&req);
5477     if ( bWow64 )
5478         req.flags |= CM_REQ_WOW64;
5479
5480     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + ResultBufferLength);
5481     if (!(*ResultCB))
5482         return;
5483
5484     memset( *ResultCB,
5485             '\0',
5486             sizeof( AFSCommResult) + sizeof(AFSPipeIOResultCB));
5487
5488     pPipe_Data = (BYTE *)(*ResultCB)->ResultData;
5489
5490     status = RDR_Pipe_QueryInfo( pPipeInfo_CB->RequestId, pPipeInfo_CB->InformationClass,
5491                                  ResultBufferLength, pPipe_Data,
5492                                  &(*ResultCB)->ResultBufferLength, &req, userp);
5493
5494     (*ResultCB)->ResultStatus = status;
5495 }
5496
5497 void
5498 RDR_PipeTransceive( IN cm_user_t     *userp,
5499                     IN AFSFileID  ParentId,
5500                     IN AFSPipeIORequestCB *pPipe_CB,
5501                     IN BYTE *pPipe_InData,
5502                     IN BOOL bWow64,
5503                     IN DWORD ResultBufferLength,
5504                     IN OUT AFSCommResult **ResultCB)
5505 {
5506     /*
5507      * This function processes a Pipe Service request
5508      * that would normally be sent to a LAN Manager server
5509      * across an authenticated SMB-PIPE/MSRPC/SVC request
5510      * stack.  The request is being sent here because the
5511      * application (e.g., Explorer Shell or Common Control File
5512      * dialog) believes that because the UNC path it is
5513      * processing has specified a server name that is not
5514      * "." and that the Server is remote and that the Share
5515      * list cannot be obtained using the Network Provider
5516      * interface.
5517      *
5518      * The file system driver is faking the Bind-Ack response
5519      * to the MSRPC Bind request but cannot decode the NDR
5520      * encoded Pipe Service requests.  For that we will use
5521      * the service's MSRPC module.  However, unlike the SMB
5522      * server usage we must fake the MSRPC Bind exchange and
5523      * map the PipeName to an interface instead of using the
5524      * GUID specified in the MSRPC Bind request.
5525      *
5526      * None of the requests that are being processed by the
5527      * service require authentication.  As a result the userp
5528      * parameter will be ignored.
5529      *
5530      * Although there are dozens of Pipe Services, the only
5531      * ones that we are implementing are WKSSVC and SRVSVC.
5532      * These support NetShareEnum, NetShareGetInfo,
5533      * NetServerGetInfo, and NetWorkstaGetInfo which are
5534      * commonly queried by NET VIEW, the Explorer Shell,
5535      * and the Common Control File dialog.
5536      */
5537     BYTE *pPipe_OutData;
5538     cm_scache_t *dscp = NULL;
5539     afs_uint32  code;
5540     cm_req_t    req;
5541     DWORD       status;
5542     DWORD Length = ResultBufferLength + sizeof( AFSCommResult);
5543
5544     RDR_InitReq(&req);
5545     if ( bWow64 )
5546         req.flags |= CM_REQ_WOW64;
5547
5548     *ResultCB = (AFSCommResult *)malloc( Length);
5549     if (!(*ResultCB))
5550         return;
5551     memset( *ResultCB, '\0', Length );
5552
5553     code = RDR_Pipe_Write( pPipe_CB->RequestId, pPipe_CB->BufferLength, pPipe_InData, &req, userp);
5554     if (code) {
5555         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5556         osi_Log2( afsd_logp, "RDR_Pipe_Transceive Write FAILURE code=0x%x status=0x%x",
5557                   code, status);
5558         (*ResultCB)->ResultStatus = status;
5559         return;
5560     }
5561
5562     pPipe_OutData = (BYTE *)(*ResultCB)->ResultData;
5563     code = RDR_Pipe_Read( pPipe_CB->RequestId, ResultBufferLength, pPipe_OutData,
5564                           &(*ResultCB)->ResultBufferLength, &req, userp);
5565     if (code) {
5566         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5567         osi_Log2( afsd_logp, "RDR_Pipe_Transceive Read FAILURE code=0x%x status=0x%x",
5568                   code, status);
5569         (*ResultCB)->ResultStatus = status;
5570         return;
5571     }
5572
5573     (*ResultCB)->ResultStatus = 0;
5574     osi_Log0(afsd_logp, "RDR_Pipe_Transceive SUCCESS");
5575 }