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