int cm_enableServerLocks = 1;
+int cm_followBackupPath = 0;
+
/*
* Case-folding array. This was constructed by inspecting of SMBtrace output.
* I do not know anything more about it.
long rights;
long code;
- osi_assert(ldpp != NULL);
+ osi_assertx(ldpp != NULL, "null cm_lock_data_t");
*ldpp = NULL;
/* Always allow delete; the RPC will tell us if it's OK */
long code;
osi_hyper_t thyper;
cm_buf_t *bufferp;
- cm_dirEntry_t *dep;
+ cm_dirEntry_t *dep = 0;
unsigned short *hashTable;
unsigned int i, idx;
int BeyondPage = 0, HaveDot = 0, HaveDotDot = 0;
{
char *tp;
long code;
- cm_dirEntry_t *dep;
+ cm_dirEntry_t *dep = 0;
cm_buf_t *bufferp;
long temp;
osi_hyper_t dirLength;
char mtType;
cm_fid_t tfid;
size_t vnLength;
- int type;
+ int targetType;
if (scp->mountRootFid.cell != 0 && scp->mountRootGen >= cm_data.mountRootGen) {
tfid = scp->mountRootFid;
/* normal mt pt */
strcpy(volNamep, mpNamep+1);
- cellp = cm_FindCellByID(scp->fid.cell);
+ cellp = cm_FindCellByID(scp->fid.cell, 0);
}
if (!cellp) {
vnLength = strlen(volNamep);
if (vnLength >= 8 && strcmp(volNamep + vnLength - 7, ".backup") == 0)
- type = BACKVOL;
+ targetType = BACKVOL;
else if (vnLength >= 10
&& strcmp(volNamep + vnLength - 9, ".readonly") == 0)
- type = ROVOL;
+ targetType = ROVOL;
else
- type = RWVOL;
+ targetType = RWVOL;
/* check for backups within backups */
- if (type == BACKVOL
+ if (targetType == BACKVOL
&& (scp->flags & (CM_SCACHEFLAG_RO | CM_SCACHEFLAG_PURERO))
== CM_SCACHEFLAG_RO) {
code = CM_ERROR_NOSUCHVOLUME;
lock_ReleaseMutex(&volp->mx);
scp->mountRootFid.cell = cellp->cellID;
+
+ /* if the mt pt originates in a .backup volume (not a .readonly)
+ * and FollowBackupPath is active, and if there is a .backup
+ * volume for the target, then use the .backup of the target
+ * instead of the read-write.
+ */
+ if (cm_followBackupPath &&
+ volp->bk.ID != 0 &&
+ (dscp->flags & (CM_SCACHEFLAG_RO|CM_SCACHEFLAG_PURERO)) == CM_SCACHEFLAG_RO &&
+ (targetType == RWVOL || targetType == ROVOL && volp->ro.ID == 0)
+ ) {
+ targetType = BACKVOL;
+ }
/* if the mt pt is in a read-only volume (not just a
* backup), and if there is a read-only volume for the
- * target, and if this is a type '#' mount point, use
+ * target, and if this is a targetType '#' mount point, use
* the read-only, otherwise use the one specified.
*/
- if (mtType == '#' && (scp->flags & CM_SCACHEFLAG_PURERO)
- && volp->ro.ID != 0 && type == RWVOL)
- type = ROVOL;
- if (type == ROVOL)
+ else if (mtType == '#' && targetType == RWVOL &&
+ (scp->flags & CM_SCACHEFLAG_PURERO) &&
+ volp->ro.ID != 0) {
+ targetType = ROVOL;
+ }
+ if (targetType == ROVOL)
scp->mountRootFid.volume = volp->ro.ID;
- else if (type == BACKVOL)
+ else if (targetType == BACKVOL)
scp->mountRootFid.volume = volp->bk.ID;
else
scp->mountRootFid.volume = volp->rw.ID;
else
return CM_ERROR_NOSUCHFILE;
}
- else { /* nonexistent dir on freelance root, so add it */
+ else if (!strchr(namep, '#') && !strchr(namep, '%') &&
+ strcmp(namep, "srvsvc") && strcmp(namep, "wkssvc") &&
+ strcmp(namep, "ipc$")) {
+ /* nonexistent dir on freelance root, so add it */
char fullname[200] = ".";
int found = 0;
osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %s",
osi_LogSaveString(afsd_logp,namep));
+
+ /*
+ * There is an ugly behavior where a share name "foo" will be searched
+ * for as "fo". If the searched for name differs by an already existing
+ * symlink or mount point in the Freelance directory, do not add the
+ * new value automatically.
+ */
+
+ code = -1;
if (namep[0] == '.') {
if (cm_GetCell_Gen(&namep[1], &fullname[1], CM_FLAG_CREATE)) {
found = 1;
- if ( stricmp(&namep[1], &fullname[1]) )
+ if (!cm_FreelanceMountPointExists(fullname, 0))
+ code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell.", 1, &rock.fid);
+ if ( stricmp(&namep[1], &fullname[1]) &&
+ !cm_FreelanceMountPointExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
+ !cm_FreelanceSymlinkExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
- else
- code = cm_FreelanceAddMount(namep, &fullname[1], "root.cell.", 1, &rock.fid);
}
} else {
if (cm_GetCell_Gen(namep, fullname, CM_FLAG_CREATE)) {
found = 1;
- if ( stricmp(namep, fullname) )
+ if (!cm_FreelanceMountPointExists(fullname, 0))
+ code = cm_FreelanceAddMount(fullname, fullname, "root.cell.", 0, &rock.fid);
+ if ( stricmp(namep, fullname) &&
+ !cm_FreelanceMountPointExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
+ !cm_FreelanceSymlinkExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
- else
- code = cm_FreelanceAddMount(namep, fullname, "root.cell.", 0, &rock.fid);
}
}
if (!found || code < 0) { /* add mount point failed, so give up */
#endif
{
long code;
- char tname[256];
+ char tname[AFSPATHMAX];
int sysNameIndex = 0;
cm_scache_t *scp = NULL;
cm_dnlcRemove(dscp, namep);
cm_SyncOpDone(dscp, NULL, sflags);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
} else if (code == CM_ERROR_NOSUCHFILE) {
/* windows would not have allowed the request to delete the file
* if it did not believe the file existed. therefore, we must
/* read the link data */
lock_ReleaseMutex(&linkScp->mx);
thyper.LowPart = thyper.HighPart = 0;
+ lock_ObtainRead(&linkScp->bufCreateLock);
code = buf_Get(linkScp, &thyper, &bufp);
+ lock_ReleaseRead(&linkScp->bufCreateLock);
lock_ObtainMutex(&linkScp->mx);
if (code)
return code;
if (!linkScp->mountPointStringp[0]) {
strncpy(linkScp->mountPointStringp, bufp->datap, temp);
linkScp->mountPointStringp[temp] = 0; /* null terminate */
+
+ if ( !strnicmp(linkScp->mountPointStringp, "msdfs:", strlen("msdfs:")) )
+ linkScp->fileType = CM_SCACHETYPE_DFSLINK;
}
buf_Release(bufp);
} /* don't have sym link contents cached */
char *linkp;
cm_space_t *tsp;
+ *newRootScpp = NULL;
+ *newSpaceBufferp = NULL;
+
lock_ObtainMutex(&linkScp->mx);
code = cm_HandleLink(linkScp, userp, reqp);
- if (code)
+ if (code)
goto done;
/* if we may overflow the buffer, bail out; buffer is signficantly
} else {
linkScp->fileType = CM_SCACHETYPE_DFSLINK;
strcpy(tsp->data, linkp);
- *newRootScpp = NULL;
code = CM_ERROR_PATH_NOT_COVERED;
}
- } else if ( !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
+ } else if ( linkScp->fileType == CM_SCACHETYPE_DFSLINK ||
+ !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
linkScp->fileType = CM_SCACHETYPE_DFSLINK;
strcpy(tsp->data, linkp);
- *newRootScpp = NULL;
code = CM_ERROR_PATH_NOT_COVERED;
} else if (*linkp == '\\' || *linkp == '/') {
#if 0
*/
linkScp->fileType = CM_SCACHETYPE_INVALID;
strcpy(tsp->data, linkp);
- *newRootScpp = NULL;
code = CM_ERROR_NOSUCHPATH;
#endif
} else {
/* a relative link */
strcpy(tsp->data, linkp);
- *newRootScpp = NULL;
}
if (pathSuffixp[0] != 0) { /* if suffix string is non-null */
strcat(tsp->data, "\\");
strcat(tsp->data, pathSuffixp);
}
- *newSpaceBufferp = tsp;
+ if (code == 0)
+ *newSpaceBufferp = tsp;
+ else {
+ cm_FreeSpace(tsp);
+
+ if (code == CM_ERROR_PATH_NOT_COVERED && reqp->tidPathp && reqp->relPathp)
+ cm_VolStatus_Notify_DFS_Mapping(linkScp, reqp->tidPathp, reqp->relPathp);
+ }
done:
lock_ReleaseMutex(&linkScp->mx);
char *tp; /* ptr moving through input buffer */
char tc; /* temp char */
int haveComponent; /* has new component started? */
- char component[256]; /* this is the new component */
+ char component[AFSPATHMAX]; /* this is the new component */
char *cp; /* component name being assembled */
cm_scache_t *tscp; /* current location in the hierarchy */
cm_scache_t *nscp; /* next dude down */
if (!cm_FidCmp(&nscp->fid, &fids[i]))
break;
}
+ fid_count = i+1;
} else {
/* add the new fid to the list */
for ( i=0; i<fid_count; i++) {
osi_Log1(afsd_logp, "cm_TryBulkStat dir 0x%p", dscp);
/* should be on a buffer boundary */
- osi_assert((offsetp->LowPart & (cm_data.buf_blockSize - 1)) == 0);
+ osi_assertx((offsetp->LowPart & (cm_data.buf_blockSize - 1)) == 0, "invalid offset");
memset(&bb, 0, sizeof(bb));
bb.bufOffset = *offsetp;
return CM_ERROR_ATSYS;
}
+#ifdef AFS_FREELANCE_CLIENT
+ /* Freelance root volume does not hold files */
+ if (cm_freelanceEnabled &&
+ dscp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+ dscp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+ {
+ return CM_ERROR_NOACCESS;
+ }
+#endif /* AFS_FREELANCE_CLIENT */
+
/* before starting the RPC, mark that we're changing the file data, so
* that someone who does a chmod will know to wait until our call
* completes.
lock_ObtainMutex(&dscp->mx);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
}
lock_ReleaseMutex(&dscp->mx);
return CM_ERROR_ATSYS;
}
+#ifdef AFS_FREELANCE_CLIENT
+ /* Freelance root volume does not hold subdirectories */
+ if (cm_freelanceEnabled &&
+ dscp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+ dscp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+ {
+ return CM_ERROR_NOACCESS;
+ }
+#endif /* AFS_FREELANCE_CLIENT */
+
/* before starting the RPC, mark that we're changing the directory
* data, so that someone who does a chmod on the dir will wait until
* our call completes.
lock_ObtainMutex(&dscp->mx);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
}
lock_ReleaseMutex(&dscp->mx);
lock_ObtainMutex(&dscp->mx);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
}
lock_ReleaseMutex(&dscp->mx);
lock_ObtainMutex(&dscp->mx);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
}
lock_ReleaseMutex(&dscp->mx);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
cm_dnlcRemove(dscp, namep);
- cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+ cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
}
lock_ReleaseMutex(&dscp->mx);
if (code == 0)
cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
- userp, 0);
+ userp, CM_MERGEFLAG_DIROP);
lock_ReleaseMutex(&oldDscp->mx);
if (code == 0) {
cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0)
cm_MergeStatus(NULL, newDscp, &updatedNewDirStatus, &volSync,
- userp, 0);
+ userp, CM_MERGEFLAG_DIROP);
lock_ReleaseMutex(&newDscp->mx);
if (code == 0) {
osi_QRemove(&cm_freeFileLocks, &l->q);
} else {
l = malloc(sizeof(cm_file_lock_t));
- osi_assert(l);
+ osi_assertx(l, "null cm_file_lock_t");
}
memset(l, 0, sizeof(cm_file_lock_t));
rights |= PRSFS_WRITE | PRSFS_LOCK;
else {
/* hmmkay */
- osi_assert(FALSE);
+ osi_assertx(FALSE, "invalid lock type");
return 0;
}
osi_Log0(afsd_logp,
" attempting to UPGRADE from LockRead to LockWrite.");
osi_Log1(afsd_logp,
- " dataVersion on scp: %d", scp->dataVersion);
+ " dataVersion on scp: %I64d", scp->dataVersion);
/* we assume at this point (because scp->serverLock
was valid) that we had a valid server lock. */
newLock = Which;
/* am I sane? */
- osi_assert(newLock == LockRead);
+ osi_assertx(newLock == LockRead, "lock type not read");
code = cm_IntSetLock(scp, userp, newLock, reqp);
}
osi_Log0(afsd_logp,
" Data version mismatch while upgrading lock.");
osi_Log2(afsd_logp,
- " Data versions before=%d, after=%d",
+ " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
osi_Log1(afsd_logp,
fileLock->scp->fid.volume,
fileLock->scp->fid.vnode,
fileLock->scp->fid.unique);
- osi_assert(FALSE);
+ osi_assertx(FALSE, "invalid fid value");
}
#endif
/* since scp->serverLock looked sane, we are going to assume
that we have a valid server lock. */
scp->lockDataVersion = scp->dataVersion;
- osi_Log1(afsd_logp, " dataVersion on scp = %d", scp->dataVersion);
+ osi_Log1(afsd_logp, " dataVersion on scp = %I64d", scp->dataVersion);
code = cm_IntReleaseLock(scp, userp, reqp);
we have lost the lock we had during the transition. */
osi_Log0(afsd_logp, "Data version mismatch during lock downgrade");
- osi_Log2(afsd_logp, " Data versions before=%d, after=%d",
+ osi_Log2(afsd_logp, " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
fileLock->scp->fid.volume,
fileLock->scp->fid.vnode,
fileLock->scp->fid.unique);
- osi_assert(FALSE);
+ osi_assertx(FALSE, "invalid fid value");
}
#endif
if (!IS_LOCK_DELETED(fileLock) &&
lock_ReleaseRead(&cm_scacheLock);
/* The lock didn't exist anyway. *shrug* */
- return 0;
+ return CM_ERROR_RANGE_NOT_LOCKED;
}
lock_ReleaseRead(&cm_scacheLock);
/* Since we already had a lock, we assume that there is a
valid server lock. */
scp->lockDataVersion = scp->dataVersion;
- osi_Log1(afsd_logp, " dataVersion on scp is %d", scp->dataVersion);
+ osi_Log1(afsd_logp, " dataVersion on scp is %I64d", scp->dataVersion);
/* before we downgrade, make sure that we have enough
permissions to get the read lock. */
osi_Log0(afsd_logp,
"Data version mismatch while downgrading lock");
osi_Log2(afsd_logp,
- " Data versions before=%d, after=%d",
+ " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
#ifdef DEBUG
/* With the current code, we can't lose a lock on a RO scp */
- osi_assert(!(scp->flags & CM_SCACHEFLAG_RO));
+ osi_assertx(!(scp->flags & CM_SCACHEFLAG_RO), "CM_SCACHEFLAG_RO unexpected");
#endif
/* cm_scacheLock needed because we are modifying fileLock->flags */
/* Server locks must have been enabled for us to have
received an active non-client-only lock. */
- osi_assert(cm_enableServerLocks);
+ osi_assertx(cm_enableServerLocks, "!cm_enableServerLocks");
scp = fileLock->scp;
- osi_assert(scp != NULL);
+ osi_assertx(scp != NULL, "null cm_scache_t");
cm_HoldSCacheNoLock(scp);
fileLock->scp->fid.volume,
fileLock->scp->fid.vnode,
fileLock->scp->fid.unique);
- osi_assert(FALSE);
+ osi_assertx(FALSE, "invalid fid");
}
#endif
/* Server locks are extended once per scp per refresh
"Data version mismatch on scp 0x%p",
scp);
osi_Log2(afsd_logp,
- " Data versions: before=%d, after=%d",
+ " Data versions: before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
scp = oldFileLock->scp;
- osi_assert(scp != NULL);
+ osi_assertx(scp != NULL, "null cm_scache_t");
lock_ReleaseRead(&cm_scacheLock);
lock_ObtainMutex(&scp->mx);
oldFileLock->flags |= CM_FILELOCK_FLAG_WAITLOCK;
}
- osi_assert(IS_LOCK_WAITLOCK(oldFileLock));
+ osi_assertx(IS_LOCK_WAITLOCK(oldFileLock), "!IS_LOCK_WAITLOCK");
if (force_client_lock ||
!SERVERLOCKS_ENABLED(scp) ||
if (scp->serverLock == LockRead) {
- osi_assert(newLock == LockWrite);
+ osi_assertx(newLock == LockWrite, "!LockWrite");
osi_Log0(afsd_logp, " Attempting to UPGRADE from LockRead to LockWrite");
osi_Log0(afsd_logp,
" Data version mismatch while upgrading lock.");
osi_Log2(afsd_logp,
- " Data versions before=%d, after=%d",
+ " Data versions before=%I64d, after=%I64d",
scp->lockDataVersion,
scp->dataVersion);
osi_Log1(afsd_logp,
cm_key_t cm_GenerateKey(unsigned int session_id, unsigned long process_id, unsigned int file_id)
{
#ifdef DEBUG
- osi_assert((process_id & 0xffffffff) == process_id);
- osi_assert((session_id & 0xffff) == session_id);
- osi_assert((file_id & 0xffff) == file_id);
+ osi_assertx((process_id & 0xffffffff) == process_id, "unexpected process_id");
+ osi_assertx((session_id & 0xffff) == session_id, "unexpected session_id");
+ osi_assertx((file_id & 0xffff) == file_id, "unexpected file_id");
#endif
return