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