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