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