/*
* Copyright (c) 2008 Secure Endpoints, Inc.
- * Copyright (c) 2009-2013 Your File System, Inc.
+ * Copyright (c) 2009-2014 Your File System, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
fid->hash = FileId->Hash;
}
+unsigned long
+RDR_ExtAttributes(cm_scache_t *scp)
+{
+ unsigned long attrs;
+
+ if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+ scp->fid.vnode & 0x1)
+ {
+ attrs = SMB_ATTR_DIRECTORY;
+#ifdef SPECIAL_FOLDERS
+ attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
+#endif /* SPECIAL_FOLDERS */
+ } else if ( scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+ scp->fileType == CM_SCACHETYPE_DFSLINK ||
+ scp->fileType == CM_SCACHETYPE_INVALID)
+ {
+ attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_REPARSE_POINT;
+ } else if ( scp->fileType == CM_SCACHETYPE_SYMLINK) {
+ attrs = SMB_ATTR_REPARSE_POINT;
+ } else {
+ attrs = 0;
+ }
+
+ if ((scp->unixModeBits & 0200) == 0)
+ attrs |= SMB_ATTR_READONLY; /* Read-only */
+
+ if (attrs == 0)
+ attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
+
+ return attrs;
+}
+
DWORD
RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRedirInitInfoLen )
{
(*ppRedirInitInfo)->CacheBlockSize = cm_data.blockSize;
(*ppRedirInitInfo)->MaxPathLinkCount = MAX_FID_COUNT;
(*ppRedirInitInfo)->NameArrayLength = MAX_FID_COUNT;
+ (*ppRedirInitInfo)->GlobalReparsePointPolicy = rdr_ReparsePointPolicy;
if (cm_virtualCache || cm_data.bufferSize <= maxMemoryCacheSize) {
osi_Log0(afsd_logp, "RDR_SetInitParams Initializing Memory Extent Interface");
(*ppRedirInitInfo)->MemoryCacheOffset.QuadPart = (LONGLONG)cm_data.bufDataBaseAddress;
break;
case CM_SCACHETYPE_MOUNTPOINT:
case CM_SCACHETYPE_INVALID:
+ case CM_SCACHETYPE_DFSLINK:
pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY | SMB_ATTR_REPARSE_POINT;
break;
case CM_SCACHETYPE_SYMLINK:
pCurrentEntry->FileAttributes = SMB_ATTR_NORMAL;
}
} else
- pCurrentEntry->FileAttributes = smb_ExtAttributes(scp);
+ pCurrentEntry->FileAttributes = RDR_ExtAttributes(scp);
pCurrentEntry->EaSize = 0;
pCurrentEntry->Links = scp->linkCount;
if (!(dwFlags & RDR_POP_NO_GETSTATUS))
cm_SyncOpDone( scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if ((dwFlags & RDR_POP_NO_GETSTATUS) || !cm_HaveCallback(scp)) {
- pCurrentEntry->TargetNameOffset = 0;
- pCurrentEntry->TargetNameLength = 0;
- }
- else
+ pCurrentEntry->TargetNameOffset = 0;
+ pCurrentEntry->TargetNameLength = 0;
+ if (!(dwFlags & RDR_POP_NO_GETSTATUS) && cm_HaveCallback(scp)) {
switch (scp->fileType) {
case CM_SCACHETYPE_MOUNTPOINT:
- if (dwFlags & RDR_POP_FOLLOW_MOUNTPOINTS) {
+ {
if ((code2 = cm_ReadMountPoint(scp, userp, reqp)) == 0) {
cm_scache_t *targetScp = NULL;
#endif
pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
- code2 = cm_FollowMountPoint(scp, dscp, userp, reqp, &targetScp);
-
- if (code2 == 0) {
- pCurrentEntry->TargetFileId.Cell = targetScp->fid.cell;
- pCurrentEntry->TargetFileId.Volume = targetScp->fid.volume;
- pCurrentEntry->TargetFileId.Vnode = targetScp->fid.vnode;
- pCurrentEntry->TargetFileId.Unique = targetScp->fid.unique;
- pCurrentEntry->TargetFileId.Hash = targetScp->fid.hash;
-
- osi_Log4(afsd_logp, "RDR_PopulateCurrentEntry target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
- pCurrentEntry->TargetFileId.Cell, pCurrentEntry->TargetFileId.Volume,
- pCurrentEntry->TargetFileId.Vnode, pCurrentEntry->TargetFileId.Unique);
-
- cm_ReleaseSCache(targetScp);
- } else {
- osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_FollowMountPoint failed scp=0x%p code=0x%x",
- scp, code2);
+ if (dwFlags & RDR_POP_FOLLOW_MOUNTPOINTS) {
+ code2 = cm_FollowMountPoint(scp, dscp, userp, reqp, &targetScp);
+ if (code2 == 0) {
+ pCurrentEntry->TargetFileId.Cell = targetScp->fid.cell;
+ pCurrentEntry->TargetFileId.Volume = targetScp->fid.volume;
+ pCurrentEntry->TargetFileId.Vnode = targetScp->fid.vnode;
+ pCurrentEntry->TargetFileId.Unique = targetScp->fid.unique;
+ pCurrentEntry->TargetFileId.Hash = targetScp->fid.hash;
+
+ osi_Log4(afsd_logp, "RDR_PopulateCurrentEntry target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+ pCurrentEntry->TargetFileId.Cell, pCurrentEntry->TargetFileId.Volume,
+ pCurrentEntry->TargetFileId.Vnode, pCurrentEntry->TargetFileId.Unique);
+
+ cm_ReleaseSCache(targetScp);
+ } else {
+ osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_FollowMountPoint failed scp=0x%p code=0x%x",
+ scp, code2);
+ }
}
} else {
osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_ReadMountPoint failed scp=0x%p code=0x%x",
code2 = cm_HandleLink(scp, userp, reqp);
if (code2 == 0) {
- size_t wtarget_len = 0;
-
if (scp->mountPointStringp[0]) {
char * mp;
char * s;
size_t offset = 0;
+ size_t wtarget_len = 0;
len = strlen(scp->mountPointStringp) + 1;
mp = strdup(scp->mountPointStringp);
} else if (mp[offset] == '\\') {
size_t nbNameLen = strlen(cm_NetbiosName);
- if ( strncmp(&mp[offset + 1], cm_NetbiosName, nbNameLen) == 0 &&
+ if ( strnicmp(&mp[offset + 1], cm_NetbiosName, nbNameLen) == 0 &&
mp[offset + nbNameLen + 1] == '\\')
{
/* an AFS symlink */
mbstowcs(wtarget, &mp[offset], wtarget_len);
#endif
} else if ( mp[offset + 1] == '\\' &&
- strncmp(&mp[offset + 2], cm_NetbiosName, strlen(cm_NetbiosName)) == 0 &&
+ strnicmp(&mp[offset + 2], cm_NetbiosName, strlen(cm_NetbiosName)) == 0 &&
mp[offset + nbNameLen + 2] == '\\')
{
/* an AFS symlink */
}
free(mp);
- }
- pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * (wtarget_len - 1));
+ pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * (wtarget_len - 1));
+ }
} else {
osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_HandleLink failed scp=0x%p code=0x%x",
scp, code2);
pCurrentEntry->TargetNameOffset = 0;
pCurrentEntry->TargetNameLength = 0;
}
+ }
lock_ReleaseWrite(&scp->rw);
dwEntryLength += pCurrentEntry->FileNameLength + pCurrentEntry->TargetNameLength;
pCurrentEntry->FileId.Unique = fidp->unique;
pCurrentEntry->FileId.Hash = fidp->hash;
- pCurrentEntry->FileType = CM_SCACHETYPE_UNKNOWN;
-
pCurrentEntry->DataVersion.QuadPart = CM_SCACHE_VERSION_BAD;
cm_LargeSearchTimeFromUnixTime(&ft, 0);
pCurrentEntry->EndOfFile.QuadPart = 0;
pCurrentEntry->AllocationSize.QuadPart = 0;
- pCurrentEntry->FileAttributes = 0;
+ if (fidp->vnode & 0x1) {
+ pCurrentEntry->FileType = CM_SCACHETYPE_DIRECTORY;
+ pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY;
+ } else {
+ pCurrentEntry->FileType = CM_SCACHETYPE_UNKNOWN;
+ pCurrentEntry->FileAttributes = SMB_ATTR_NORMAL;
pCurrentEntry->EaSize = 0;
+ }
pCurrentEntry->Links = 0;
len = wcslen(shortName);
entryp->name,
cm_shortNames && cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
(bWow64 ? RDR_POP_WOW64 : 0) |
- (bSkipStatus ? RDR_POP_NO_GETSTATUS : 0),
+ (bSkipStatus ? RDR_POP_NO_GETSTATUS : 0) |
+ RDR_POP_EVALUATE_SYMLINKS,
code,
&pCurrentEntry, &dwMaxEntryLength);
cm_ReleaseSCache(scp);
IN BOOL CaseSensitive,
IN BOOL LastComponent,
IN BOOL bWow64,
- IN BOOL bHoldFid,
IN BOOL bNoFollow,
+ IN BOOL bHoldFid,
IN DWORD ResultBufferLength,
IN OUT AFSCommResult **ResultCB)
{
dscp, scp, userp, &req,
FileName, shortName,
(bWow64 ? RDR_POP_WOW64 : 0) |
- (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
+ (bNoFollow ? 0 : RDR_POP_FOLLOW_MOUNTPOINTS) |
+ RDR_POP_EVALUATE_SYMLINKS,
0, NULL, &dwRemaining);
if (bHoldFid)
RDR_FlagScpInUse( scp, FALSE );
code = RDR_PopulateCurrentEntry(pCurrentEntry, dwRemaining,
dscp, scp, userp, &req, NULL, NULL,
(bWow64 ? RDR_POP_WOW64 : 0) |
- (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
+ (bNoFollow ? 0 : RDR_POP_FOLLOW_MOUNTPOINTS) |
+ RDR_POP_EVALUATE_SYMLINKS,
0, NULL, &dwRemaining);
if (bHoldFid)
return;
}
+ if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
+ cm_dirOp_t dirop;
+
+ lock_ReleaseWrite(&scp->rw);
+
+ code = cm_BeginDirOp(scp, userp, &req, CM_DIRLOCK_READ,
+ CM_DIROP_FLAG_NONE, &dirop);
+ if (code == 0) {
+ /* is the directory empty? if not, CM_ERROR_NOTEMPTY */
+ afs_uint32 bEmpty;
+
+ code = cm_BPlusDirIsEmpty(&dirop, &bEmpty);
+ if (code == 0 && !bEmpty)
+ code = CM_ERROR_NOTEMPTY;
+
+ cm_EndDirOp(&dirop);
+ }
+
+ if (code) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ (*ResultCB)->ResultBufferLength = 0;
+ cm_ReleaseSCache(scp);
+ cm_ReleaseSCache(dscp);
+ osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
+ scp, code, status);
+ return;
+ }
+ lock_ObtainWrite(&scp->rw);
+ }
+
if (!bCheckOnly) {
/* Drop all locks since the file is being deleted */
code = cm_SyncOp(scp, NULL, userp, &req, 0,
cm_req_t req;
DWORD status;
FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
- afs_uint32 flags;
char volName[32]="(unknown)";
char offLineMsg[256]="server temporarily inaccessible";
char *OfflineMsg;
char *MOTD;
struct rx_connection * rxconnp;
- int sync_done = 0;
int scp_locked = 0;
RDR_InitReq(&req, bWow64);
pResultCB->CellID = scp->fid.cell;
pResultCB->VolumeID = scp->fid.volume;
pResultCB->Characteristics = FILE_REMOTE_DEVICE;
- pResultCB->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK |
- FILE_SUPPORTS_HARD_LINKS | FILE_SUPPORTS_REPARSE_POINTS;
+ pResultCB->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
+ FILE_UNICODE_ON_DISK | FILE_SUPPORTS_HARD_LINKS | FILE_SUPPORTS_REPARSE_POINTS;
if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
scp->fid.volume==AFS_FAKE_ROOT_VOL_ID)
if ( pResultCB->CellLength )
pResultCB->CellLength--;
} else {
- volp = cm_GetVolumeByFID(&scp->fid);
- if (!volp) {
+ volp = cm_FindVolumeByFID(&scp->fid, userp, &req);
+ if (!volp) {
code = CM_ERROR_NOSUCHVOLUME;
goto _done;
}
+
volType = cm_VolumeType(volp, scp->fid.volume);
if (cm_volumeInfoReadOnlyFlag && (volType == ROVOL || volType == BACKVOL))
pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
- flags = CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS;
- if (scp->volumeCreationDate == 0)
- flags |= CM_SCACHESYNC_FORCECB;
- code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ, flags);
- if (code == 0)
- {
- sync_done = 1;
-
- Name = volName;
- OfflineMsg = offLineMsg;
- MOTD = motd;
- lock_ReleaseWrite(&scp->rw);
- scp_locked = 0;
-
- do {
- code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
- if (code) continue;
+ code = -1;
- rxconnp = cm_GetRxConn(connp);
- code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
- &volStat, &Name, &OfflineMsg, &MOTD);
- rx_PutConnection(rxconnp);
-
- } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, NULL, code));
- code = cm_MapRPCError(code, &req);
+ if ( volType == ROVOL &&
+ (volp->flags & CM_VOLUMEFLAG_RO_SIZE_VALID))
+ {
+ lock_ObtainRead(&volp->rw);
+ if (volp->flags & CM_VOLUMEFLAG_RO_SIZE_VALID) {
+ volStat.BlocksInUse = volp->volumeSizeRO / 1024;
+ code = 0;
+ }
+ lock_ReleaseRead(&volp->rw);
+ }
+
+ if (code == -1)
+ {
+ Name = volName;
+ OfflineMsg = offLineMsg;
+ MOTD = motd;
+ lock_ReleaseWrite(&scp->rw);
+ scp_locked = 0;
+
+ do {
+ code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
+ if (code) continue;
+
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
+ &volStat, &Name, &OfflineMsg, &MOTD);
+ rx_PutConnection(rxconnp);
+
+ } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, NULL, code));
+ code = cm_MapRPCError(code, &req);
+
+ if (code == 0 && volType == ROVOL)
+ {
+ lock_ObtainWrite(&volp->rw);
+ volp->volumeSizeRO = volStat.BlocksInUse * 1024;
+ _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RO_SIZE_VALID);
+ lock_ReleaseWrite(&volp->rw);
+ }
}
if ( scp->volumeCreationDate )
pResultCB->AvailableAllocationUnits.QuadPart = volStat.PartBlocksAvail;
}
}
- } else {
+ } else if ( code != CM_ERROR_ALLBUSY &&
+ code != CM_ERROR_ALLOFFLINE &&
+ code != CM_ERROR_ALLDOWN)
+ {
/*
* Lie about the available space. Out of quota errors will need
* detected when the file server rejects the store data.
/* do not include the trailing nul */
if ( pResultCB->CellLength )
pResultCB->CellLength--;
-
- if (sync_done) {
- if (!scp_locked) {
- lock_ObtainWrite(&scp->rw);
- scp_locked = 1;
- }
- cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- }
}
pResultCB->VolumeLabelLength *= sizeof(WCHAR); /* convert to bytes from chars */
pResultCB->CellLength *= sizeof(WCHAR); /* convert to bytes from chars */
char *OfflineMsg;
char *MOTD;
struct rx_connection * rxconnp;
- int sync_done = 0;
int scp_locked = 0;
RDR_InitReq(&req, bWow64);
pResultCB->TotalAllocationUnits.QuadPart = 100;
pResultCB->AvailableAllocationUnits.QuadPart = 0;
} else {
- volp = cm_GetVolumeByFID(&scp->fid);
- if (!volp) {
+ volp = cm_FindVolumeByFID(&scp->fid, userp, &req);
+ if (!volp) {
code = CM_ERROR_NOSUCHVOLUME;
goto _done;
}
volType = cm_VolumeType(volp, scp->fid.volume);
- code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
- CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code == 0)
- {
- sync_done = 1;
+ code = -1;
- Name = volName;
- OfflineMsg = offLineMsg;
- MOTD = motd;
- lock_ReleaseWrite(&scp->rw);
- scp_locked = 0;
-
- do {
- code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
- if (code) continue;
-
- rxconnp = cm_GetRxConn(connp);
- code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
- &volStat, &Name, &OfflineMsg, &MOTD);
- rx_PutConnection(rxconnp);
-
- } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, NULL, code));
- code = cm_MapRPCError(code, &req);
+ if ( volType == ROVOL &&
+ (volp->flags & CM_VOLUMEFLAG_RO_SIZE_VALID))
+ {
+ lock_ObtainRead(&volp->rw);
+ if (volp->flags & CM_VOLUMEFLAG_RO_SIZE_VALID) {
+ volStat.BlocksInUse = volp->volumeSizeRO / 1024;
+ code = 0;
+ }
+ lock_ReleaseRead(&volp->rw);
+ }
+
+ if (code == -1)
+ {
+ Name = volName;
+ OfflineMsg = offLineMsg;
+ MOTD = motd;
+ lock_ReleaseWrite(&scp->rw);
+ scp_locked = 0;
+
+ do {
+ code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
+ if (code) continue;
+
+ rxconnp = cm_GetRxConn(connp);
+ code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
+ &volStat, &Name, &OfflineMsg, &MOTD);
+ rx_PutConnection(rxconnp);
+
+ } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, NULL, code));
+ code = cm_MapRPCError(code, &req);
+
+ if (code == 0 && volType == ROVOL)
+ {
+ lock_ObtainWrite(&volp->rw);
+ volp->volumeSizeRO = volStat.BlocksInUse * 1024;
+ _InterlockedOr(&volp->flags, CM_VOLUMEFLAG_RO_SIZE_VALID);
+ lock_ReleaseWrite(&volp->rw);
+ }
}
if (code == 0) {
pResultCB->AvailableAllocationUnits.QuadPart = (volType == ROVOL || volType == BACKVOL) ? 0 : 0x3F000000;
code = 0;
}
-
- if (sync_done) {
- if (!scp_locked) {
- lock_ObtainWrite(&scp->rw);
- scp_locked = 1;
- }
- cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- }
}
_done:
/* Ensure that the caller can access this file */
lock_ObtainWrite(&scp->rw);
- code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
+ /*
+ * Request PRSFS_WRITE | PRSFS_LOCK in order to bypass the unix mode
+ * check in cm_HaveAccessRights(). By the time RDR_WriteFile is called
+ * it is already too late to deny the write due to the readonly attribute.
+ * The Windows cache may have already accepted the data. Only if the
+ * user does not have real write permission should the write be denied.
+ */
+ code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE | PRSFS_LOCK,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
if (code == CM_ERROR_NOACCESS && scp->creator == userp) {
code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_INSERT,