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