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