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