/*
* Copyright (c) 2008 Secure Endpoints, Inc.
- * Copyright (c) 2009-2011 Your File System, Inc.
+ * Copyright (c) 2009-2013 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 = (AFSRedirectorInitInfo *)malloc(*pRedirInitInfoLen);
(*ppRedirInitInfo)->Flags = smb_hideDotFiles ? AFS_REDIR_INIT_FLAG_HIDE_DOT_FILES : 0;
(*ppRedirInitInfo)->Flags |= cm_shortNames ? 0 : AFS_REDIR_INIT_FLAG_DISABLE_SHORTNAMES;
+ (*ppRedirInitInfo)->Flags |= cm_directIO ? AFS_REDIR_INIT_PERFORM_SERVICE_IO : 0;
(*ppRedirInitInfo)->MaximumChunkLength = cm_data.chunkSize;
(*ppRedirInitInfo)->GlobalFileId.Cell = cm_data.rootFid.cell;
(*ppRedirInitInfo)->GlobalFileId.Volume = cm_data.rootFid.volume;
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;
wtarget = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->TargetNameOffset);
if (dwFlags & RDR_POP_EVALUATE_SYMLINKS) {
- char * mp;
code2 = cm_HandleLink(scp, userp, reqp);
if (code2 == 0) {
- mp = scp->mountPointStringp;
- len = strlen(mp);
- if ( len != 0 ) {
- /* Strip off the msdfs: prefix from the target name for the file system */
- if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
- osi_Log0(afsd_logp, "RDR_PopulateCurrentEntry DFSLink Detected");
- pCurrentEntry->FileType = scp->fileType;
-
- if (!strncmp("msdfs:", mp, 6)) {
- mp += 6;
- len -= 6;
- }
+ size_t wtarget_len = 0;
+
+ if (scp->mountPointStringp[0]) {
+ char * mp;
+ char * s;
+ size_t offset = 0;
+
+ len = strlen(scp->mountPointStringp) + 1;
+ mp = strdup(scp->mountPointStringp);
+
+ for (s=mp; *s; s++) {
+ if (*s == '/')
+ *s = '\\';
}
- /* only send one slash to the redirector */
- if (mp[0] == '\\' && mp[1] == '\\') {
- mp++;
- len--;
+
+ if (strncmp("msdfs:", mp, 6) == 0) {
+ offset = 6;
}
+
+
+ if ( mp[offset + 1] == ':' && mp[offset] != '\\') {
+ /* Local drive letter. Must return <drive>:\<path> */
+ pCurrentEntry->FileType = CM_SCACHETYPE_DFSLINK;
+ wtarget_len = len - offset;
+#ifdef UNICODE
+ cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset],
+ wtarget_len * sizeof(char),
+ wtarget,
+ wtarget_len * sizeof(WCHAR));
+#else
+ mbstowcs(wtarget, &mp[offset], wtarget_len);
+#endif
+ } else if (mp[offset] == '\\') {
+ size_t nbNameLen = strlen(cm_NetbiosName);
+
+ if ( strnicmp(&mp[offset + 1], cm_NetbiosName, nbNameLen) == 0 &&
+ mp[offset + nbNameLen + 1] == '\\')
+ {
+ /* an AFS symlink */
+ pCurrentEntry->FileType = CM_SCACHETYPE_SYMLINK;
+ wtarget_len = len - offset;
#ifdef UNICODE
- cch = MultiByteToWideChar( CP_UTF8, 0, mp,
- len * sizeof(char),
- wtarget,
- len * sizeof(WCHAR));
+ cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset],
+ wtarget_len * sizeof(char),
+ wtarget,
+ wtarget_len * sizeof(WCHAR));
#else
- mbstowcs(wtarget, mp, len);
+ mbstowcs(wtarget, &mp[offset], wtarget_len);
#endif
+ } else if ( mp[offset + 1] == '\\' &&
+ strnicmp(&mp[offset + 2], cm_NetbiosName, strlen(cm_NetbiosName)) == 0 &&
+ mp[offset + nbNameLen + 2] == '\\')
+ {
+ /* an AFS symlink */
+ pCurrentEntry->FileType = CM_SCACHETYPE_SYMLINK;
+ wtarget_len = len - offset - 1;
+#ifdef UNICODE
+ cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset + 1],
+ wtarget_len * sizeof(char),
+ wtarget,
+ wtarget_len * sizeof(WCHAR));
+#else
+ mbstowcs(wtarget, &mp[offset + 1], wtarget_len);
+#endif
+ } else {
+ /*
+ * treat as a UNC path. Needs to be \<server>\<share\<path>
+ */
+ pCurrentEntry->FileType = CM_SCACHETYPE_DFSLINK;
+
+ if ( mp[offset] == '\\' && mp[offset + 1] == '\\')
+ offset++;
+
+ wtarget_len = len - offset;
+#ifdef UNICODE
+ cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset],
+ wtarget_len * sizeof(char),
+ wtarget,
+ wtarget_len * sizeof(WCHAR));
+#else
+ mbstowcs(wtarget, &mp[offset], wtarget_len);
+#endif
+ }
+ } else {
+ /* Relative AFS Symlink */
+ pCurrentEntry->FileType = CM_SCACHETYPE_SYMLINK;
+ wtarget_len = len - offset;
+#ifdef UNICODE
+ cch = MultiByteToWideChar( CP_UTF8, 0, &mp[offset],
+ wtarget_len * sizeof(char),
+ wtarget,
+ wtarget_len * sizeof(WCHAR));
+#else
+ mbstowcs(wtarget, &mp[offset], wtarget_len);
+#endif
+ }
+
+ free(mp);
}
- pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
+
+ 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->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);
IN WCHAR *FileNameCounted,
IN DWORD FileNameLength,
IN BOOL CaseSensitive,
+ IN BOOL LastComponent,
IN BOOL bWow64,
IN BOOL bHoldFid,
IN BOOL bNoFollow,
size_t cbName;
BOOL bVol = FALSE;
wchar_t FileName[260];
+ afs_uint32 lookupFlags;
StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
return;
}
- code = cm_Lookup(dscp, wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
+ lookupFlags = CM_FLAG_NOMOUNTCHASE;
+
+ if ( !LastComponent )
+ lookupFlags |= CM_FLAG_CHECKPATH;
+ code = cm_Lookup(dscp, wszName, lookupFlags, userp, &req, &scp);
+
+ if (!CaseSensitive &&
+ (code == CM_ERROR_NOSUCHPATH || code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)) {
+ lookupFlags |= CM_FLAG_CASEFOLD;
+ code = cm_Lookup(dscp, wszName, lookupFlags, userp, &req, &scp);
+ }
if ((code == CM_ERROR_NOSUCHPATH || code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) &&
dscp == cm_data.rootSCachep) {
}
lock_ObtainWrite(&dscp->rw);
- bScpLocked = TRUE;
code = cm_SyncOp(dscp, NULL, userp, &req, 0,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
if (code) {
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
lock_ReleaseWrite(&dscp->rw);
- bScpLocked = FALSE;
if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
(*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
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,
return;
}
+
+void
+RDR_CreateSymlinkEntry( IN cm_user_t *userp,
+ IN AFSFileID FileId,
+ IN WCHAR *FileNameCounted,
+ IN DWORD FileNameLength,
+ IN AFSCreateSymlinkCB *SymlinkCB,
+ IN BOOL bWow64,
+ IN DWORD ResultBufferLength,
+ IN OUT AFSCommResult **ResultCB)
+{
+ AFSCreateSymlinkResultCB *pResultCB = NULL;
+ size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
+ cm_fid_t parentFid;
+ cm_fid_t Fid;
+ afs_uint32 code;
+ cm_scache_t * dscp = NULL;
+ afs_uint32 flags = 0;
+ cm_attr_t setAttr;
+ cm_scache_t * scp = NULL;
+ cm_req_t req;
+ DWORD status;
+ wchar_t FileName[260];
+ char *TargetPath = NULL;
+
+ StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
+ TargetPath = cm_Utf16ToUtf8Alloc( SymlinkCB->TargetName, SymlinkCB->TargetNameLength / sizeof(WCHAR), NULL);
+
+ osi_Log4( afsd_logp, "RDR_CreateSymlinkEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+ SymlinkCB->ParentId.Cell, SymlinkCB->ParentId.Volume,
+ SymlinkCB->ParentId.Vnode, SymlinkCB->ParentId.Unique);
+ osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, FileName));
+
+ RDR_InitReq(&req, bWow64);
+ memset(&setAttr, 0, sizeof(cm_attr_t));
+
+ *ResultCB = (AFSCommResult *)malloc(size);
+ if (!(*ResultCB)) {
+ osi_Log0(afsd_logp, "RDR_CreateSymlinkEntry out of memory");
+ free(TargetPath);
+ return;
+ }
+
+ memset( *ResultCB,
+ '\0',
+ size);
+
+ parentFid.cell = SymlinkCB->ParentId.Cell;
+ parentFid.volume = SymlinkCB->ParentId.Volume;
+ parentFid.vnode = SymlinkCB->ParentId.Vnode;
+ parentFid.unique = SymlinkCB->ParentId.Unique;
+ parentFid.hash = SymlinkCB->ParentId.Hash;
+
+ code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
+ if (code) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ if ( status == STATUS_INVALID_HANDLE)
+ status = STATUS_OBJECT_PATH_INVALID;
+ osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
+ code, status);
+ free(TargetPath);
+ return;
+ }
+
+ lock_ObtainWrite(&dscp->rw);
+ code = cm_SyncOp(dscp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ lock_ReleaseWrite(&dscp->rw);
+ cm_ReleaseSCache(dscp);
+ osi_Log3(afsd_logp, "RDR_CreateSymlinkEntry cm_SyncOp failure (1) dscp=0x%p code=0x%x status=0x%x",
+ dscp, code, status);
+ free(TargetPath);
+ return;
+ }
+
+ cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ReleaseWrite(&dscp->rw);
+
+ if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
+ (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
+ cm_ReleaseSCache(dscp);
+ osi_Log1(afsd_logp, "RDR_CreateSymlinkEntry Not a Directory dscp=0x%p",
+ dscp);
+ free(TargetPath);
+ return;
+ }
+
+ Fid.cell = FileId.Cell;
+ Fid.volume = FileId.Volume;
+ Fid.vnode = FileId.Vnode;
+ Fid.unique = FileId.Unique;
+ Fid.hash = FileId.Hash;
+
+ code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
+ if (code) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ if ( status == STATUS_INVALID_HANDLE)
+ status = STATUS_OBJECT_PATH_INVALID;
+ osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry cm_GetSCache FID failure code=0x%x status=0x%x",
+ code, status);
+ free(TargetPath);
+ return;
+ }
+
+ lock_ObtainWrite(&scp->rw);
+ code = cm_SyncOp(scp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
+ osi_Log3(afsd_logp, "RDR_CreateSymlinkEntry cm_SyncOp failure (1) scp=0x%p code=0x%x status=0x%x",
+ scp, code, status);
+ free(TargetPath);
+ return;
+ }
+
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ReleaseWrite(&scp->rw);
+
+ /* Remove the temporary object */
+ if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
+ code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
+ else
+ code = cm_Unlink(dscp, NULL, FileName, userp, &req);
+ cm_ReleaseSCache(scp);
+ scp = NULL;
+ if (code && code != CM_ERROR_NOSUCHFILE) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ cm_ReleaseSCache(dscp);
+ osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry Unable to delete file dscp=0x%p code=0x%x",
+ dscp, code);
+ free(TargetPath);
+ return;
+ }
+
+ /*
+ * The target path is going to be provided by the redirector in one of the following forms:
+ *
+ * 1. Relative path.
+ * 2. Absolute path prefaced as \??\UNC\<server>\<share>\<path>
+ * 3. Absolute path prefaced as \??\<drive-letter>:\<path>
+ *
+ * Relative paths can be used with just slash conversion. Absolute paths must be converted.
+ * UNC paths with a server name that matches cm_NetbiosName then the path is an AFS path and
+ * it must be converted to /<server>/<share>/<path>. Other UNC paths must be converted to
+ * msdfs:\\<server>\<share>\<path>. Local disk paths should be converted to
+ * msdfs:<drive-letter>:<path>.
+ */
+
+ if ( TargetPath[0] == '\\' ) {
+ size_t nbNameLen = strlen(cm_NetbiosName);
+ size_t len;
+ char *s;
+
+ if ( strncmp(TargetPath, "\\??\\UNC\\", 8) == 0) {
+
+ if (strncmp(&TargetPath[8], cm_NetbiosName, nbNameLen) == 0 &&
+ TargetPath[8 + nbNameLen] == '\\')
+ {
+ /* AFS path */
+ s = strdup(&TargetPath[8 + nbNameLen]);
+ free(TargetPath);
+ TargetPath = s;
+ for (; *s; s++) {
+ if (*s == '\\')
+ *s = '/';
+ }
+ } else {
+ /*
+ * non-AFS UNC path (msdfs:\\server\share\path)
+ * strlen("msdfs:\\") == 7 + 1 for the NUL
+ */
+ len = 8 + strlen(&TargetPath[7]);
+ s = malloc(8 + strlen(&TargetPath[7]));
+ StringCbCopy(s, len, "msdfs:\\");
+ StringCbCat(s, len, &TargetPath[7]);
+ free(TargetPath);
+ TargetPath = s;
+ }
+ } else {
+ /* non-UNC path (msdfs:<drive>:\<path> */
+ s = strdup(&TargetPath[4]);
+ free(TargetPath);
+ TargetPath = s;
+ }
+
+ } else {
+ /* relative paths require slash conversion */
+ char *s = TargetPath;
+ for (; *s; s++) {
+ if (*s == '\\')
+ *s = '/';
+ }
+ }
+
+ /* Use current time */
+ setAttr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
+ setAttr.unixModeBits = 0755;
+ setAttr.clientModTime = time(NULL);
+
+ code = cm_SymLink(dscp, FileName, TargetPath, flags, &setAttr, userp, &req, &scp);
+ free(TargetPath);
+
+ if (code == 0) {
+ wchar_t shortName[13]=L"";
+ cm_dirFid_t dfid;
+ DWORD dwRemaining;
+
+ if (dscp->flags & CM_SCACHEFLAG_ANYWATCH) {
+ smb_NotifyChange(FILE_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_DIR_NAME,
+ dscp, FileName, NULL, TRUE);
+ }
+
+ (*ResultCB)->ResultStatus = 0; // We will be able to fit all the data in here
+
+ (*ResultCB)->ResultBufferLength = sizeof( AFSCreateSymlinkResultCB);
+
+ pResultCB = (AFSCreateSymlinkResultCB *)(*ResultCB)->ResultData;
+
+ dwRemaining = ResultBufferLength - sizeof( AFSCreateSymlinkResultCB) + sizeof( AFSDirEnumEntry);
+
+ lock_ObtainWrite(&dscp->rw);
+ code = cm_SyncOp(dscp, NULL, userp, &req, 0,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ lock_ReleaseWrite(&dscp->rw);
+ cm_ReleaseSCache(dscp);
+ cm_ReleaseSCache(scp);
+ osi_Log3(afsd_logp, "RDR_CreateSymlinkEntry cm_SyncOp failure (2) dscp=0x%p code=0x%x status=0x%x",
+ dscp, code, status);
+ return;
+ }
+
+ pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
+
+ cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ReleaseWrite(&dscp->rw);
+
+ if (cm_shortNames) {
+ dfid.vnode = htonl(scp->fid.vnode);
+ dfid.unique = htonl(scp->fid.unique);
+
+ if (!cm_Is8Dot3(FileName))
+ cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
+ else
+ shortName[0] = '\0';
+ }
+
+ code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
+ dscp, scp, userp, &req, FileName, shortName,
+ RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
+ 0, NULL, &dwRemaining);
+ cm_ReleaseSCache(scp);
+ (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
+ osi_Log0(afsd_logp, "RDR_CreateSymlinkEntry SUCCESS");
+ } else {
+ (*ResultCB)->ResultStatus = STATUS_FILE_DELETED;
+ (*ResultCB)->ResultBufferLength = 0;
+ osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry FAILURE code=0x%x status=0x%x",
+ code, STATUS_FILE_DELETED);
+ }
+
+ cm_ReleaseSCache(dscp);
+
+ return;
+}
+
+
void
RDR_FlushFileEntry( IN cm_user_t *userp,
IN AFSFileID FileId,
rwheld = 0;
}
- code = buf_Get(scp, &offset, reqp, &bufp);
+ code = buf_Get(scp, &offset, reqp, 0, &bufp);
if (code) {
/*
* any error from buf_Get() is non-fatal.
QueueLength = 0;
thyper.QuadPart = ByteOffset.QuadPart;
- code = buf_Get(scp, &thyper, &req, &bufp);
+ code = buf_Get(scp, &thyper, &req, 0, &bufp);
if (code == 0) {
lock_ObtainMutex(&bufp->mx);
bBufRelease = TRUE;
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";
memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
pResultCB->AvailableAllocationUnits.QuadPart = 0;
- pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
+ if (cm_volumeInfoReadOnlyFlag)
+ pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( "Freelance.Local.Root", -1, pResultCB->VolumeLabel,
(sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
if ( pResultCB->CellLength )
pResultCB->CellLength--;
} else {
- memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
-
volp = cm_GetVolumeByFID(&scp->fid);
if (!volp) {
code = CM_ERROR_NOSUCHVOLUME;
}
volType = cm_VolumeType(volp, scp->fid.volume);
- if (volType == ROVOL || volType == BACKVOL)
+ if (cm_volumeInfoReadOnlyFlag && (volType == ROVOL || volType == BACKVOL))
pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
- code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
- CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
- if (code == 0)
+ code = -1;
+
+ if ( volType == ROVOL &&
+ (volp->flags & CM_VOLUMEFLAG_RO_SIZE_VALID))
{
- sync_done = 1;
+ 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)
+ {
+ 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;
+ 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;
- 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);
- 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);
- } 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 )
+ cm_LargeSearchTimeFromUnixTime(&ft, scp->volumeCreationDate);
+ memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
+
if (code == 0) {
if (volType == ROVOL || volType == BACKVOL) {
pResultCB->TotalAllocationUnits.QuadPart = volStat.BlocksInUse;
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)
+ code = -1;
+
+ if ( volType == ROVOL &&
+ (volp->flags & CM_VOLUMEFLAG_RO_SIZE_VALID))
{
- sync_done = 1;
+ 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)
+ {
+ code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code == 0)
+ {
+ sync_done = 1;
- Name = volName;
- OfflineMsg = offLineMsg;
- MOTD = motd;
- lock_ReleaseWrite(&scp->rw);
- scp_locked = 0;
+ 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;
- 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);
- 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);
- } 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) {
(*ResultCB)->ResultStatus = 0;
osi_Log0(afsd_logp, "RDR_Pipe_Transceive SUCCESS");
}
+
+void
+RDR_ReadFile( IN cm_user_t *userp,
+ IN AFSFileID FileID,
+ IN LARGE_INTEGER *Offset,
+ IN ULONG BytesToRead,
+ IN PVOID Buffer,
+ IN BOOL bWow64,
+ IN BOOL bCacheBypass,
+ IN DWORD ResultBufferLength,
+ IN OUT AFSCommResult **ResultCB)
+{
+ AFSFileIOResultCB * pFileIOResultCB;
+ DWORD status;
+ ULONG Length;
+ ULONG ulBytesRead = 0;
+ afs_uint32 code = 0;
+ cm_fid_t fid;
+ cm_scache_t * scp = NULL;
+ cm_req_t req;
+
+ RDR_InitReq(&req, bWow64);
+
+ osi_Log4(afsd_logp, "RDR_ReadFile FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+ FileID.Cell, FileID.Volume, FileID.Vnode, FileID.Unique);
+
+ Length = sizeof(AFSFileIOResultCB);
+ if (Length > ResultBufferLength) {
+ *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
+ if (!(*ResultCB))
+ return;
+ memset( *ResultCB, 0, sizeof(AFSCommResult));
+ (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
+ return;
+ }
+ *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
+ if (!(*ResultCB))
+ return;
+ memset( *ResultCB, '\0', Length );
+ (*ResultCB)->ResultBufferLength = Length;
+ pFileIOResultCB = (AFSFileIOResultCB *)(*ResultCB)->ResultData;
+
+ if ( Buffer == NULL) {
+ (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
+ osi_Log0(afsd_logp, "RDR_ReadFile Null IOctl Buffer");
+ return;
+ }
+
+ if (FileID.Cell != 0) {
+ fid.cell = FileID.Cell;
+ fid.volume = FileID.Volume;
+ fid.vnode = FileID.Vnode;
+ fid.unique = FileID.Unique;
+ fid.hash = FileID.Hash;
+
+ code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
+ if (code) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ osi_Log2(afsd_logp, "RDR_ReadFile cm_GetSCache failure code=0x%x status=0x%x",
+ code, status);
+ return;
+ }
+ } else {
+ (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
+ osi_Log0(afsd_logp, "RDR_ReadFile Object Name Invalid - Cell = 0");
+ return;
+ }
+
+ /* Ensure that the caller can access this file */
+ lock_ObtainWrite(&scp->rw);
+ code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
+ osi_Log2(afsd_logp, "RDR_ReadFile cm_SyncOp failure code=0x%x status=0x%x",
+ code, status);
+ return;
+ }
+
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+ if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
+ (*ResultCB)->ResultStatus = STATUS_FILE_IS_A_DIRECTORY;
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
+ osi_Log1(afsd_logp, "RDR_ReadFile File is a Directory scp=0x%p",
+ scp);
+ return;
+ }
+
+ if (scp->fileType != CM_SCACHETYPE_FILE) {
+ (*ResultCB)->ResultStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
+ osi_Log1(afsd_logp, "RDR_ReadFile File is a MountPoint or Link scp=0x%p",
+ scp);
+ return;
+ }
+
+ if ( bCacheBypass) {
+ //
+ // Read the file directly into the buffer bypassing the AFS Cache
+ //
+ code = cm_GetData( scp, Offset, Buffer, BytesToRead, &ulBytesRead, userp, &req);
+ } else {
+ //
+ // Read the file via the AFS Cache
+ //
+ code = raw_ReadData( scp, Offset, BytesToRead, Buffer, &ulBytesRead, userp, &req);
+ }
+
+ if (code) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ osi_Log2(afsd_logp, "RDR_ReadFile failure code=0x%x status=0x%x",
+ code, status);
+ } else {
+ (*ResultCB)->ResultStatus = STATUS_SUCCESS;
+ pFileIOResultCB->Length = ulBytesRead;
+ pFileIOResultCB->DataVersion.QuadPart = scp->dataVersion;
+ pFileIOResultCB->Expiration.QuadPart = scp->cbExpires;
+ }
+
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
+ return;
+}
+
+void
+RDR_WriteFile( IN cm_user_t *userp,
+ IN AFSFileID FileID,
+ IN AFSFileIOCB *FileIOCB,
+ IN LARGE_INTEGER *Offset,
+ IN ULONG BytesToWrite,
+ IN PVOID Buffer,
+ IN BOOL bWow64,
+ IN BOOL bCacheBypass,
+ IN DWORD ResultBufferLength,
+ IN OUT AFSCommResult **ResultCB)
+{
+ AFSFileIOResultCB * pFileIOResultCB;
+ DWORD status;
+ ULONG Length;
+ ULONG ulBytesWritten = 0;
+ afs_uint32 code = 0;
+ cm_fid_t fid;
+ cm_scache_t * scp = NULL;
+ cm_req_t req;
+
+ RDR_InitReq(&req, bWow64);
+
+ osi_Log4(afsd_logp, "RDR_WriteFile FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+ FileID.Cell, FileID.Volume, FileID.Vnode, FileID.Unique);
+
+ Length = sizeof(AFSFileIOResultCB);
+ if (Length > ResultBufferLength) {
+ *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
+ if (!(*ResultCB))
+ return;
+ memset( *ResultCB, 0, sizeof(AFSCommResult));
+ (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
+ return;
+ }
+ *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
+ if (!(*ResultCB))
+ return;
+ memset( *ResultCB, '\0', Length );
+ (*ResultCB)->ResultBufferLength = Length;
+ pFileIOResultCB = (AFSFileIOResultCB *)(*ResultCB)->ResultData;
+
+ if ( Buffer == NULL) {
+ (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
+ osi_Log0(afsd_logp, "RDR_WriteFile Null IOctl Buffer");
+ return;
+ }
+
+ if (FileID.Cell != 0) {
+ fid.cell = FileID.Cell;
+ fid.volume = FileID.Volume;
+ fid.vnode = FileID.Vnode;
+ fid.unique = FileID.Unique;
+ fid.hash = FileID.Hash;
+
+ code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
+ if (code) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ osi_Log2(afsd_logp, "RDR_WriteFile cm_GetSCache failure code=0x%x status=0x%x",
+ code, status);
+ return;
+ }
+ } else {
+ (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
+ osi_Log0(afsd_logp, "RDR_WriteFile Object Name Invalid - Cell = 0");
+ return;
+ }
+
+ /* Ensure that the caller can access this file */
+ lock_ObtainWrite(&scp->rw);
+ code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ if (code == CM_ERROR_NOACCESS && scp->creator == userp) {
+ code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_INSERT,
+ CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ }
+ if (code) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
+ osi_Log2(afsd_logp, "RDR_WriteFile cm_SyncOp failure code=0x%x status=0x%x",
+ code, status);
+ return;
+ }
+
+ cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+ if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
+ (*ResultCB)->ResultStatus = STATUS_FILE_IS_A_DIRECTORY;
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
+ osi_Log1(afsd_logp, "RDR_WriteFile File is a Directory scp=0x%p",
+ scp);
+ return;
+ }
+
+ if (scp->fileType != CM_SCACHETYPE_FILE) {
+ (*ResultCB)->ResultStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
+ osi_Log1(afsd_logp, "RDR_WriteFile File is a MountPoint or Link scp=0x%p",
+ scp);
+ return;
+ }
+
+ if (FileIOCB->EndOfFile.QuadPart != scp->length.QuadPart)
+ {
+ cm_attr_t setAttr;
+
+ memset(&setAttr, 0, sizeof(cm_attr_t));
+ if (FileIOCB->EndOfFile.QuadPart != scp->length.QuadPart) {
+ osi_Log4(afsd_logp, "RDR_WriteFile new length fid vol 0x%x vno 0x%x length 0x%x:%x",
+ scp->fid.volume, scp->fid.vnode,
+ FileIOCB->EndOfFile.HighPart,
+ FileIOCB->EndOfFile.LowPart);
+
+ setAttr.mask |= CM_ATTRMASK_LENGTH;
+ setAttr.length.LowPart = FileIOCB->EndOfFile.LowPart;
+ setAttr.length.HighPart = FileIOCB->EndOfFile.HighPart;
+ lock_ReleaseWrite(&scp->rw);
+ code = cm_SetAttr(scp, &setAttr, userp, &req);
+ osi_Log2(afsd_logp, "RDR_WriteFile cm_SetAttr failure scp=0x%p code 0x%x",
+ scp, code);
+ code = 0; /* ignore failure */
+ lock_ObtainWrite(&scp->rw);
+ }
+ }
+
+ /*
+ * The input buffer may contain data beyond the end of the file.
+ * Such data must be discarded.
+ */
+ if ( Offset->QuadPart + BytesToWrite > scp->length.QuadPart)
+ {
+ if ( Offset->QuadPart > scp->length.QuadPart) {
+ (*ResultCB)->ResultStatus = STATUS_SUCCESS;
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
+ osi_Log1(afsd_logp, "RDR_WriteFile Nothing to do scp=0x%p",
+ scp);
+ return;
+ }
+
+ BytesToWrite -= (afs_uint32)(Offset->QuadPart + BytesToWrite - scp->length.QuadPart);
+ }
+
+ if (bCacheBypass) {
+ code = cm_DirectWrite( scp, Offset, BytesToWrite,
+ CM_DIRECT_SCP_LOCKED,
+ userp, &req, Buffer, &ulBytesWritten);
+ } else {
+ code = raw_WriteData( scp, Offset, BytesToWrite, Buffer, userp, &req, &ulBytesWritten);
+ }
+
+ if (code) {
+ smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+ (*ResultCB)->ResultStatus = status;
+ osi_Log2(afsd_logp, "RDR_WriteFile failure code=0x%x status=0x%x",
+ code, status);
+ } else {
+ (*ResultCB)->ResultStatus = STATUS_SUCCESS;
+ pFileIOResultCB->Length = ulBytesWritten;
+ pFileIOResultCB->DataVersion.QuadPart = scp->dataVersion;
+ pFileIOResultCB->Expiration.QuadPart = scp->cbExpires;
+ }
+
+ lock_ReleaseWrite(&scp->rw);
+ cm_ReleaseSCache(scp);
+ return;
+}