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