From eabe2b6f77da6913b4a6bd51220708c363762fe6 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Tue, 18 Jan 2005 07:36:25 +0000 Subject: [PATCH] windows-smb_vc_t-refcounts-20050117 Rework the reference counting of the smb_vc_t objects to use smb_ReleaseVC and smb_HoldVC. Add missing counts for references from waiting locks. Fix cm_ioctl.c to allow it to compile once again. --- src/WINNT/afsd/cm_ioctl.c | 60 +++--- src/WINNT/afsd/smb.c | 87 +++++--- src/WINNT/afsd/smb.h | 4 + src/WINNT/afsd/smb3.c | 442 +++++++++++++++++++++----------------- 4 files changed, 327 insertions(+), 266 deletions(-) diff --git a/src/WINNT/afsd/cm_ioctl.c b/src/WINNT/afsd/cm_ioctl.c index b3c47b06a0..c73951df71 100644 --- a/src/WINNT/afsd/cm_ioctl.c +++ b/src/WINNT/afsd/cm_ioctl.c @@ -89,8 +89,8 @@ void cm_ResetACLCache(cm_user_t *userp) int hash; lock_ObtainWrite(&cm_scacheLock); - for (hash=0; hash < cm_data.hashTableSize; hash++) { - for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) { + for (hash=0; hash < cm_hashTableSize; hash++) { + for (scp=cm_hashTablep[hash]; scp; scp=scp->nextp) { cm_HoldSCacheNoLock(scp); lock_ReleaseWrite(&cm_scacheLock); lock_ObtainMutex(&scp->mx); @@ -179,7 +179,7 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp, shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath); if ( shareFound ) { /* we found a sharename, therefore use the resulting path */ - code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data, + code = cm_NameI(cm_rootSCachep, ioctlp->prefix->data, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, sharePath, reqp, &substRootp); free(sharePath); @@ -208,7 +208,7 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp, shareName[i] = 0; /* terminate string */ - code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data, + code = cm_NameI(cm_rootSCachep, ioctlp->prefix->data, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, shareName, reqp, &substRootp); if (code) @@ -220,7 +220,7 @@ long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp, return code; } } else { - code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data, + code = cm_NameI(cm_rootSCachep, ioctlp->prefix->data, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, ioctlp->tidPathp, reqp, &substRootp); if (code) @@ -347,7 +347,7 @@ long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp, shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath); if ( shareFound ) { /* we found a sharename, therefore use the resulting path */ - code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data, + code = cm_NameI(cm_rootSCachep, ioctlp->prefix->data, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, sharePath, reqp, &substRootp); free(sharePath); @@ -373,7 +373,7 @@ long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp, shareName[i++] = '/'; /* add trailing slash */ shareName[i] = 0; /* terminate string */ - code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data, + code = cm_NameI(cm_rootSCachep, ioctlp->prefix->data, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, shareName, reqp, &substRootp); if (code) return code; @@ -383,7 +383,7 @@ long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp, if (code) return code; } } else { - code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data, + code = cm_NameI(cm_rootSCachep, ioctlp->prefix->data, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, ioctlp->tidPathp, reqp, &substRootp); if (code) return code; @@ -472,7 +472,7 @@ long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp) { cellp = cm_FindCellByID(scp->fid.cell); if (cellp) { - StringCbCopyA(ioctlp->outDatap, 999999, cellp->name); + StringCbCopyA(ioctlp->outDatap, 999999, cellp->namep); ioctlp->outDatap += strlen(ioctlp->outDatap) + 1; code = 0; } @@ -545,8 +545,8 @@ long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp) cm_ReleaseSCache(scp); lock_ObtainWrite(&cm_scacheLock); - for (i=0; inextp) { + for (i=0; inextp) { if (scp->fid.volume == volume) { cm_HoldSCacheNoLock(scp); lock_ReleaseWrite(&cm_scacheLock); @@ -974,10 +974,10 @@ long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp) memcpy(&temp, ioctlp->inDatap, sizeof(temp)); if (temp == 0) - temp = cm_data.buf_nOrigBuffers; + temp = buf_nOrigBuffers; else { /* temp is in 1K units, convert to # of buffers */ - temp = temp / (cm_data.buf_blockSize / 1024); + temp = temp / (buf_bufferSize / 1024); } /* now adjust the cache size */ @@ -1031,12 +1031,12 @@ long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp) memset(&parms, 0, sizeof(parms)); /* first we get, in 1K units, the cache size */ - parms.parms[0] = cm_data.buf_nbuffers * (cm_data.buf_blockSize / 1024); + parms.parms[0] = buf_nbuffers * (buf_bufferSize / 1024); /* and then the actual # of buffers in use (not in the free list, I guess, * will be what we do). */ - parms.parms[1] = (cm_data.buf_nbuffers - buf_CountFreeList()) * (cm_data.buf_blockSize / 1024); + parms.parms[1] = (buf_nbuffers - buf_CountFreeList()) * (buf_bufferSize / 1024); memcpy(ioctlp->outDatap, &parms, sizeof(parms)); ioctlp->outDatap += sizeof(parms); @@ -1069,7 +1069,7 @@ long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp) } lock_ObtainRead(&cm_cellLock); - for (tcellp = cm_data.allCellsp; tcellp; tcellp = tcellp->nextp) { + for (tcellp = cm_allCellsp; tcellp; tcellp = tcellp->nextp) { if (whichCell == 0) break; whichCell--; } @@ -1097,8 +1097,8 @@ long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp) } lock_ReleaseRead(&cm_serverLock); cp = basep + max * sizeof(afs_int32); - StringCbCopyA(cp, 999999, tcellp->name); - cp += strlen(tcellp->name)+1; + StringCbCopyA(cp, 999999, tcellp->namep); + cp += strlen(tcellp->namep)+1; ioctlp->outDatap = cp; } @@ -1126,18 +1126,18 @@ long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp) cm_SkipIoctlPath(ioctlp); lock_ObtainWrite(&cm_cellLock); - for (cp = cm_data.allCellsp; cp; cp=cp->nextp) + for (cp = cm_allCellsp; cp; cp=cp->nextp) { long code; /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/ cm_FreeServerList(&cp->vlServersp); cp->vlServersp = NULL; - code = cm_SearchCellFile(cp->name, cp->name, cm_AddCellProc, cp); + code = cm_SearchCellFile(cp->namep, cp->namep, cm_AddCellProc, cp); #ifdef AFS_AFSDB_ENV if (code) { if (cm_dnsEnabled) { int ttl; - code = cm_SearchCellByDNS(cp->name, cp->name, &ttl, cm_AddCellProc, cp); + code = cm_SearchCellByDNS(cp->namep, cp->namep, &ttl, cm_AddCellProc, cp); if ( code == 0 ) { /* got cell from DNS */ cp->flags |= CM_CELLFLAG_DNS; cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID; @@ -1169,9 +1169,9 @@ long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp) if (cm_freelanceEnabled) { StringCbCopyA(ioctlp->outDatap, 999999, "Freelance.Local.Root"); ioctlp->outDatap += strlen(ioctlp->outDatap) +1; - } else if (cm_data.rootCellp) { + } else if (cm_rootCellp) { /* return the default cellname to the caller */ - StringCbCopyA(ioctlp->outDatap, 999999, cm_data.rootCellp->name); + StringCbCopyA(ioctlp->outDatap, 999999, cm_rootCellp->namep); ioctlp->outDatap += strlen(ioctlp->outDatap) +1; } else { /* if we don't know our default cell, return failure */ @@ -1481,7 +1481,7 @@ long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp) } #ifdef AFS_FREELANCE_CLIENT - if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) { + if (cm_freelanceEnabled && dscp == cm_rootSCachep) { /* we are adding the mount point to the root dir., so call * the freelance code to do the add. */ osi_Log0(afsd_logp,"IoctlCreateMountPoint within Freelance root dir"); @@ -1530,7 +1530,7 @@ long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp) cp = ioctlp->inDatap; /* contents of link */ #ifdef AFS_FREELANCE_CLIENT - if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) { + if (cm_freelanceEnabled && dscp == cm_rootSCachep) { /* we are adding the symlink to the root dir., so call * the freelance code to do the add. */ if (cp[0] == cp[1] && cp[1] == '\\' && @@ -1595,7 +1595,7 @@ long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp) code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, &req); cm_ReleaseSCache(scp); - if (code == 0 || code == CM_ERROR_PATH_NOT_COVERED) { + if (code == 0) { cp = ioctlp->outDatap; if (newRootScp != NULL) { StringCbCopyA(cp, 999999, cm_mountRoot); @@ -1657,7 +1657,7 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp) cp = ioctlp->inDatap; #ifdef AFS_FREELANCE_CLIENT - if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) { + if (cm_freelanceEnabled && dscp == cm_rootSCachep) { /* we are adding the mount point to the root dir., so call * the freelance code to do the add. */ osi_Log0(afsd_logp,"IoctlDeletelink from Freelance root dir"); @@ -1785,7 +1785,7 @@ long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp) return CM_ERROR_INVAL; #endif /* !DJGPP */ } else { - cellp = cm_data.rootCellp; + cellp = cm_rootCellp; osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified"); } @@ -1904,7 +1904,7 @@ long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp) cp += sizeof(temp); /* cell name */ - StringCbCopyA(cp, 999999, ucellp->cellp->name); + StringCbCopyA(cp, 999999, ucellp->cellp->namep); cp += strlen(cp) + 1; /* user name */ @@ -1993,7 +1993,7 @@ long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp) cp += sizeof(temp); /* cell name */ - StringCbCopyA(cp, 999999, ucellp->cellp->name); + StringCbCopyA(cp, 999999, ucellp->cellp->namep); cp += strlen(cp) + 1; /* user name */ diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index 573b9745c6..365ca1b2dc 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -779,9 +779,9 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana) smb_vc_t *vcp; lock_ObtainWrite(&smb_rctLock); - for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) { + for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) { if (lsn == vcp->lsn && lana == vcp->lana) { - vcp->refCount++; + smb_HoldVCNoLock(vcp); break; } } @@ -842,6 +842,11 @@ int smb_IsStarMask(char *maskp) return 0; } +void smb_ReleaseVCNoLock(smb_vc_t *vcp) +{ + osi_assert(vcp->refCount-- > 0); +} + void smb_ReleaseVC(smb_vc_t *vcp) { lock_ObtainWrite(&smb_rctLock); @@ -849,6 +854,11 @@ void smb_ReleaseVC(smb_vc_t *vcp) lock_ReleaseWrite(&smb_rctLock); } +void smb_HoldVCNoLock(smb_vc_t *vcp) +{ + vcp->refCount++; +} + void smb_HoldVC(smb_vc_t *vcp) { lock_ObtainWrite(&smb_rctLock); @@ -873,7 +883,7 @@ smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags) tidp->nextp = vcp->tidsp; tidp->refCount = 1; tidp->vcp = vcp; - vcp->refCount++; + smb_HoldVCNoLock(vcp); vcp->tidsp = tidp; lock_InitializeMutex(&tidp->mx, "tid_t mutex"); tidp->tid = tid; @@ -887,30 +897,27 @@ void smb_ReleaseTID(smb_tid_t *tidp) smb_tid_t *tp; smb_tid_t **ltpp; cm_user_t *userp; - smb_vc_t *vcp; userp = NULL; - vcp = NULL; lock_ObtainWrite(&smb_rctLock); osi_assert(tidp->refCount-- > 0); if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) { ltpp = &tidp->vcp->tidsp; - for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) { - if (tp == tidp) break; + for (tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) { + if (tp == tidp) + break; } osi_assert(tp != NULL); *ltpp = tp->nextp; lock_FinalizeMutex(&tidp->mx); userp = tidp->userp; /* remember to drop ref later */ - vcp = tidp->vcp; + tidp->userp = NULL; + smb_ReleaseVCNoLock(tidp->vcp); + tidp->vcp = NULL; } lock_ReleaseWrite(&smb_rctLock); - if (userp) { + if (userp) cm_ReleaseUser(userp); - } - if (vcp) { - smb_ReleaseVC(vcp); - } } smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags) @@ -933,7 +940,7 @@ smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags) uidp->nextp = vcp->usersp; uidp->refCount = 1; uidp->vcp = vcp; - vcp->refCount++; + smb_HoldVCNoLock(vcp); vcp->usersp = uidp; lock_InitializeMutex(&uidp->mx, "user_t mutex"); uidp->userID = uid; @@ -992,10 +999,8 @@ void smb_ReleaseUID(smb_user_t *uidp) smb_user_t *up; smb_user_t **lupp; cm_user_t *userp; - smb_vc_t *vcp; userp = NULL; - vcp = NULL; lock_ObtainWrite(&smb_rctLock); osi_assert(uidp->refCount-- > 0); if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) { @@ -1007,10 +1012,10 @@ void smb_ReleaseUID(smb_user_t *uidp) *lupp = up->nextp; lock_FinalizeMutex(&uidp->mx); if (uidp->unp) { - userp = uidp->unp->userp; /* remember to drop ref later */ - uidp->unp->userp = NULL; + userp = uidp->unp->userp; /* avoid deadlock by releasing */ + uidp->unp->userp = NULL; /* after releasing the lock */ } - vcp = uidp->vcp; + smb_ReleaseVCNoLock(uidp->vcp); uidp->vcp = NULL; } lock_ReleaseWrite(&smb_rctLock); @@ -1018,9 +1023,6 @@ void smb_ReleaseUID(smb_user_t *uidp) cm_ReleaseUserVCRef(userp); cm_ReleaseUser(userp); } - if (vcp) { - smb_ReleaseVC(vcp); - } } /* retrieve a held reference to a user structure corresponding to an incoming @@ -1110,7 +1112,7 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags) } retry: - for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) { + for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) { if (fid == fidp->fid) { if (newFid) { fid++; @@ -1141,7 +1143,7 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags) osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q); fidp->refCount = 1; fidp->vcp = vcp; - vcp->refCount++; + smb_HoldVCNoLock(vcp); lock_InitializeMutex(&fidp->mx, "fid_t mutex"); fidp->fid = fid; fidp->curr_chunk = fidp->prev_chunk = -2; @@ -1170,24 +1172,30 @@ void smb_ReleaseFID(smb_fid_t *fidp) osi_assert(fidp->refCount-- > 0); if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) { vcp = fidp->vcp; - if (!(fidp->flags & SMB_FID_IOCTL)) + fidp->vcp = NULL; + if (!(fidp->flags & SMB_FID_IOCTL)) { scp = fidp->scp; + fidp->scp = NULL; + } + osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q); thrd_CloseHandle(fidp->raw_write_event); /* and see if there is ioctl stuff to free */ ioctlp = fidp->ioctlp; if (ioctlp) { - if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix); - if (ioctlp->inAllocp) free(ioctlp->inAllocp); - if (ioctlp->outAllocp) free(ioctlp->outAllocp); + if (ioctlp->prefix) + cm_FreeSpace(ioctlp->prefix); + if (ioctlp->inAllocp) + free(ioctlp->inAllocp); + if (ioctlp->outAllocp) + free(ioctlp->outAllocp); free(ioctlp); } free(fidp); - /* do not call smb_ReleaseVC() because we already have the lock */ - vcp->refCount--; + smb_ReleaseVCNoLock(vcp); } lock_ReleaseWrite(&smb_rctLock); @@ -1854,6 +1862,8 @@ static NCB *GetNCB(void) void smb_FreePacket(smb_packet_t *tbp) { + smb_vc_t * vcp = NULL; + osi_assert(tbp->magic == SMB_PACKETMAGIC); lock_ObtainWrite(&smb_globalLock); @@ -1861,6 +1871,7 @@ void smb_FreePacket(smb_packet_t *tbp) smb_packetFreeListp = tbp; tbp->magic = SMB_PACKETMAGIC; tbp->ncbp = NULL; + vcp = tbp->vcp; tbp->vcp = NULL; tbp->resumeCode = 0; tbp->inCount = 0; @@ -1871,6 +1882,9 @@ void smb_FreePacket(smb_packet_t *tbp) tbp->ncb_length = 0; tbp->flags = 0; lock_ReleaseWrite(&smb_globalLock); + + if (vcp) + smb_ReleaseVC(vcp); } static void FreeNCB(NCB *bufferp) @@ -2966,6 +2980,8 @@ void smb_WaitingLocksDaemon() cm_FreeSpace(inp->spacep); smb_FreePacket(inp); smb_FreePacket(outp); + if (vcp) + smb_ReleaseVC(vcp); FreeNCB(ncbp); free(wL); } while (nwL); @@ -3404,10 +3420,11 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou memcpy(dsp->mask, mask, 11); /* track if this is likely to match a lot of entries */ - if (smb_IsStarMask(mask)) starPattern = 1; - else starPattern = 0; - } - else { + if (smb_IsStarMask(mask)) + starPattern = 1; + else + starPattern = 0; + } else { /* pull the next cookie value out of the search status block */ nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16) + (inCookiep[16]<<24); @@ -3837,7 +3854,7 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou caseFold = CM_FLAG_CASEFOLD; code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp); - if(code) { + if (code) { cm_ReleaseUser(userp); return CM_ERROR_NOSUCHPATH; } diff --git a/src/WINNT/afsd/smb.h b/src/WINNT/afsd/smb.h index 4774e397b6..d98fa59ca9 100644 --- a/src/WINNT/afsd/smb.h +++ b/src/WINNT/afsd/smb.h @@ -436,6 +436,8 @@ extern smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana); extern void smb_ReleaseVC(smb_vc_t *vcp); +extern void smb_ReleaseVCNoLock(smb_vc_t *vcp); + extern smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags); extern void smb_ReleaseTID(smb_tid_t *tidp); @@ -513,6 +515,8 @@ extern void smb_MapNTError(long code, unsigned long *NTStatusp); extern void smb_HoldVC(smb_vc_t *vcp); +extern void smb_HoldVCNoLock(smb_vc_t *vcp); + /* some globals, too */ extern char *smb_localNamep; extern int loggedOut; diff --git a/src/WINNT/afsd/smb3.c b/src/WINNT/afsd/smb3.c index 3f614c6151..f8b221a0ea 100644 --- a/src/WINNT/afsd/smb3.c +++ b/src/WINNT/afsd/smb3.c @@ -1145,7 +1145,8 @@ smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp, /* free a tran2 packet; must be called with smb_globalLock held */ void smb_FreeTran2Packet(smb_tran2Packet_t *t2p) { - if (t2p->vcp) smb_ReleaseVC(t2p->vcp); + if (t2p->vcp) + smb_ReleaseVC(t2p->vcp); if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) { if (t2p->parmsp) free(t2p->parmsp); @@ -3742,10 +3743,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t smb_StripLastComponent(spacep->data, NULL, pathp); code = smb_LookupTIDPath(vcp, p->tid, &tidPathp); if (code) { - lock_ReleaseMutex(&dsp->mx); cm_ReleaseUser(userp); smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES); smb_FreeTran2Packet(outp); + lock_ReleaseMutex(&dsp->mx); smb_DeleteDirSearch(dsp); smb_ReleaseDirSearch(dsp); return 0; @@ -4371,8 +4372,10 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) * and truncate the file if we find it, otherwise we create the * file. */ - if (!lastNamep) lastNamep = pathp; - else lastNamep++; + if (!lastNamep) + lastNamep = pathp; + else + lastNamep++; code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp, &req, &scp); if (code && code != CM_ERROR_NOSUCHFILE) { @@ -4390,7 +4393,8 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) if (code == 0) { code = cm_CheckOpen(scp, openMode, trunc, userp, &req); if (code) { - if (dscp) cm_ReleaseSCache(dscp); + if (dscp) + cm_ReleaseSCache(dscp); cm_ReleaseSCache(scp); cm_ReleaseUser(userp); return code; @@ -4398,7 +4402,8 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) if (excl) { /* oops, file shouldn't be there */ - if (dscp) cm_ReleaseSCache(dscp); + if (dscp) + cm_ReleaseSCache(dscp); cm_ReleaseSCache(scp); cm_ReleaseUser(userp); return CM_ERROR_EXISTS; @@ -4557,7 +4562,8 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK); - if (code) goto doneSync; + if (code) + goto doneSync; LockType = smb_GetSMBParm(inp, 3) & 0xff; Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4); @@ -4619,6 +4625,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) /* Put on waiting list */ waitingLock = malloc(sizeof(smb_waitingLock_t)); waitingLock->vcp = vcp; + smb_HoldVC(vcp); waitingLock->inp = smb_CopyPacket(inp); waitingLock->outp = smb_CopyPacket(outp); waitingLock->timeRemaining = Timeout; @@ -4631,7 +4638,8 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) /* don't send reply immediately */ outp->flags |= SMB_PACKETFLAG_NOSEND; } - if (code) break; + if (code) + break; } if (code) { @@ -4886,9 +4894,14 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) cm_InitReq(&req); + /* This code is very long and has a lot of if-then-else clauses + * scp and dscp get reused frequently and we need to ensure that + * we don't lose a reference. Start by ensuring that they are NULL. + */ + scp = NULL; + dscp = NULL; treeCreate = FALSE; foundscp = FALSE; - scp = NULL; nameLength = smb_GetSMBOffsetParm(inp, 2, 1); flags = smb_GetSMBOffsetParm(inp, 3, 1) @@ -5035,8 +5048,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) if (desiredAccess & AFS_ACCESS_WRITE) fidflags |= SMB_FID_OPENWRITE; - dscp = NULL; code = 0; + /* For an exclusive create, we want to do a case sensitive match for the last component. */ if ( createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE || @@ -5057,15 +5070,17 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) return CM_ERROR_EXISTS; } } - } else - dscp = NULL; + } + /* we have both scp and dscp */ } else { code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp); + /* we might have scp but not dscp */ } - if (code == 0) - foundscp = TRUE; + if (scp) + foundscp = TRUE; + if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) { /* look up parent directory */ /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need* @@ -5073,8 +5088,10 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) * recognize. */ - if ( !dscp ) { - while (1) { + /* we might or might not have scp */ + + if (dscp == NULL) { + do { char *tp; code = cm_NameI(baseDirp, spacep->data, @@ -5094,20 +5111,27 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) smb_ReleaseFID(baseFidp); cm_ReleaseUser(userp); free(realPathp); + if (scp) + cm_ReleaseSCache(scp); return CM_ERROR_BADNTFILENAME; } + code = 0; } - else - break; - } + } while (dscp == NULL && code == 0); } else - code = 0; + code = 0; + + /* we might have scp and we might have dscp */ if (baseFid != 0) smb_ReleaseFID(baseFidp); if (code) { osi_Log0(smb_logp,"NTCreateX parent not found"); + if (scp) + cm_ReleaseSCache(scp); + if (dscp) + cm_ReleaseSCache(dscp); cm_ReleaseUser(userp); free(realPathp); return code; @@ -5115,6 +5139,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) { /* A file exists where we want a directory. */ + if (scp) + cm_ReleaseSCache(scp); cm_ReleaseSCache(dscp); cm_ReleaseUser(userp); free(realPathp); @@ -5127,6 +5153,9 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) lastNamep++; if (!smb_IsLegalFilename(lastNamep)) { + if (scp) + cm_ReleaseSCache(scp); + if (dscp) cm_ReleaseSCache(dscp); cm_ReleaseUser(userp); free(realPathp); @@ -5152,196 +5181,206 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) return code; } } - } - else { + /* we have scp and dscp */ + } else { + /* we have scp but not dscp */ if (baseFid != 0) smb_ReleaseFID(baseFidp); - } + } - /* if we get here, if code is 0, the file exists and is represented by - * scp. Otherwise, we have to create it. The dir may be represented - * by dscp, or we may have found the file directly. If code is non-zero, - * scp is NULL. - */ - if (code == 0 && !treeCreate) { - if (createDisp == FILE_CREATE) { - /* oops, file shouldn't be there */ - if (dscp) cm_ReleaseSCache(dscp); - cm_ReleaseSCache(scp); - cm_ReleaseUser(userp); - free(realPathp); - return CM_ERROR_EXISTS; - } - - if ( createDisp == FILE_OVERWRITE || - createDisp == FILE_OVERWRITE_IF) { - setAttr.mask = CM_ATTRMASK_LENGTH; - setAttr.length.LowPart = 0; - setAttr.length.HighPart = 0; - /* now watch for a symlink */ - code = 0; - while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) { - targetScp = 0; - code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req); - if (code == 0) { - /* we have a more accurate file to use (the - * target of the symbolic link). Otherwise, - * we'll just use the symlink anyway. - */ - osi_Log2(smb_logp, "symlink vp %x to vp %x", - scp, targetScp); - cm_ReleaseSCache(scp); - scp = targetScp; - } - } - code = cm_SetAttr(scp, &setAttr, userp, &req); - openAction = 3; /* truncated existing file */ - } - else - openAction = 1; /* found existing file */ - - code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, - &req); - if (code) { - if (dscp) cm_ReleaseSCache(dscp); - cm_ReleaseSCache(scp); - cm_ReleaseUser(userp); - free(realPathp); - return code; - } - } - else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) { - /* don't create if not found */ - if (dscp) cm_ReleaseSCache(dscp); + /* if we get here, if code is 0, the file exists and is represented by + * scp. Otherwise, we have to create it. The dir may be represented + * by dscp, or we may have found the file directly. If code is non-zero, + * scp is NULL. + */ + if (code == 0 && !treeCreate) { + if (createDisp == FILE_CREATE) { + /* oops, file shouldn't be there */ + if (dscp) + cm_ReleaseSCache(dscp); + cm_ReleaseSCache(scp); cm_ReleaseUser(userp); free(realPathp); - return CM_ERROR_NOSUCHFILE; - } - else if (realDirFlag == 0 || realDirFlag == -1) { - osi_assert(dscp != NULL); - osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s", - osi_LogSaveString(smb_logp, lastNamep)); - openAction = 2; /* created file */ - setAttr.mask = CM_ATTRMASK_CLIENTMODTIME; - setAttr.clientModTime = time(NULL); - code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, - &req); - if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH)) + return CM_ERROR_EXISTS; + } + + if ( createDisp == FILE_OVERWRITE || + createDisp == FILE_OVERWRITE_IF) { + setAttr.mask = CM_ATTRMASK_LENGTH; + setAttr.length.LowPart = 0; + setAttr.length.HighPart = 0; + /* now watch for a symlink */ + code = 0; + while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) { + targetScp = 0; + osi_assert(dscp != NULL); + code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req); + if (code == 0) { + /* we have a more accurate file to use (the + * target of the symbolic link). Otherwise, + * we'll just use the symlink anyway. + */ + osi_Log2(smb_logp, "symlink vp %x to vp %x", + scp, targetScp); + cm_ReleaseSCache(scp); + scp = targetScp; + } + } + code = cm_SetAttr(scp, &setAttr, userp, &req); + openAction = 3; /* truncated existing file */ + } + else + openAction = 1; /* found existing file */ + + code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req); + if (code) { + if (dscp) + cm_ReleaseSCache(dscp); + cm_ReleaseSCache(scp); + cm_ReleaseUser(userp); + free(realPathp); + return code; + } + } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) { + /* don't create if not found */ + if (dscp) + cm_ReleaseSCache(dscp); + if (scp) + cm_ReleaseSCache(scp); + cm_ReleaseUser(userp); + free(realPathp); + return CM_ERROR_NOSUCHFILE; + } else if (realDirFlag == 0 || realDirFlag == -1) { + osi_assert(dscp != NULL); + osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s", + osi_LogSaveString(smb_logp, lastNamep)); + openAction = 2; /* created file */ + setAttr.mask = CM_ATTRMASK_CLIENTMODTIME; + setAttr.clientModTime = time(NULL); + code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req); + if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH)) + smb_NotifyChange(FILE_ACTION_ADDED, + FILE_NOTIFY_CHANGE_FILE_NAME, + dscp, lastNamep, NULL, TRUE); + if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) { + /* Not an exclusive create, and someone else tried + * creating it already, then we open it anyway. We + * don't bother retrying after this, since if this next + * fails, that means that the file was deleted after we + * started this call. + */ + code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, + userp, &req, &scp); + if (code == 0) { + if (createDisp == FILE_OVERWRITE_IF) { + setAttr.mask = CM_ATTRMASK_LENGTH; + setAttr.length.LowPart = 0; + setAttr.length.HighPart = 0; + + /* now watch for a symlink */ + code = 0; + while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) { + targetScp = 0; + code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req); + if (code == 0) { + /* we have a more accurate file to use (the + * target of the symbolic link). Otherwise, + * we'll just use the symlink anyway. + */ + osi_Log2(smb_logp, "symlink vp %x to vp %x", + scp, targetScp); + cm_ReleaseSCache(scp); + scp = targetScp; + } + } + code = cm_SetAttr(scp, &setAttr, userp, &req); + } + } /* lookup succeeded */ + } + } else { + char *tp, *pp; + char *cp; /* This component */ + int clen = 0; /* length of component */ + cm_scache_t *tscp1, *tscp2; + int isLast = 0; + + /* create directory */ + if ( !treeCreate ) + treeStartp = lastNamep; + osi_assert(dscp != NULL); + osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]", + osi_LogSaveString(smb_logp, treeStartp)); + openAction = 2; /* created directory */ + + setAttr.mask = CM_ATTRMASK_CLIENTMODTIME; + setAttr.clientModTime = time(NULL); + + pp = treeStartp; + cp = spacep->data; + tscp1 = dscp; + cm_HoldSCache(tscp1); + tscp2 = NULL; + + while (pp && *pp) { + tp = strchr(pp, '\\'); + if (!tp) { + strcpy(cp,pp); + clen = strlen(cp); + isLast = 1; /* indicate last component. the supplied path never ends in a slash */ + } else { + clen = tp - pp; + strncpy(cp,pp,clen); + *(cp + clen) = 0; + tp++; + } + pp = tp; + + if (clen == 0) + continue; /* the supplied path can't have consecutive slashes either , but */ + + /* cp is the next component to be created. */ + code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req); + if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH)) smb_NotifyChange(FILE_ACTION_ADDED, - FILE_NOTIFY_CHANGE_FILE_NAME, - dscp, lastNamep, NULL, TRUE); - if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) { + FILE_NOTIFY_CHANGE_DIR_NAME, + tscp1, cp, NULL, TRUE); + if (code == 0 || + (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) { /* Not an exclusive create, and someone else tried * creating it already, then we open it anyway. We * don't bother retrying after this, since if this next * fails, that means that the file was deleted after we * started this call. */ - code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, - userp, &req, &scp); - if (code == 0) { - if (createDisp == FILE_OVERWRITE_IF) { - setAttr.mask = CM_ATTRMASK_LENGTH; - setAttr.length.LowPart = 0; - setAttr.length.HighPart = 0; + code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD, + userp, &req, &tscp2); + } + if (code) + break; - /* now watch for a symlink */ - code = 0; - while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) { - targetScp = 0; - code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req); - if (code == 0) { - /* we have a more accurate file to use (the - * target of the symbolic link). Otherwise, - * we'll just use the symlink anyway. - */ - osi_Log2(smb_logp, "symlink vp %x to vp %x", - scp, targetScp); - cm_ReleaseSCache(scp); - scp = targetScp; - } - } - code = cm_SetAttr(scp, &setAttr, userp, &req); - } - } /* lookup succeeded */ + if (!isLast) { /* for anything other than dscp, release it unless it's the last one */ + cm_ReleaseSCache(tscp1); + tscp1 = tscp2; /* Newly created directory will be next parent */ + /* the hold is transfered to tscp1 from tscp2 */ } - } - else { - char *tp, *pp; - char *cp; /* This component */ - int clen = 0; /* length of component */ - cm_scache_t *tscp; - int isLast = 0; - - /* create directory */ - if ( !treeCreate ) - treeStartp = lastNamep; - osi_assert(dscp != NULL); - osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]", - osi_LogSaveString(smb_logp, treeStartp)); - openAction = 2; /* created directory */ + } - setAttr.mask = CM_ATTRMASK_CLIENTMODTIME; - setAttr.clientModTime = time(NULL); - - pp = treeStartp; - cp = spacep->data; - tscp = dscp; - - while (pp && *pp) { - tp = strchr(pp, '\\'); - if (!tp) { - strcpy(cp,pp); - clen = strlen(cp); - isLast = 1; /* indicate last component. the supplied path never ends in a slash */ - } - else { - clen = tp - pp; - strncpy(cp,pp,clen); - *(cp + clen) = 0; - tp++; - } - pp = tp; - - if (clen == 0) - continue; /* the supplied path can't have consecutive slashes either , but */ - - /* cp is the next component to be created. */ - code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req); - if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH)) - smb_NotifyChange(FILE_ACTION_ADDED, - FILE_NOTIFY_CHANGE_DIR_NAME, - tscp, cp, NULL, TRUE); - if (code == 0 || - (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) { - /* Not an exclusive create, and someone else tried - * creating it already, then we open it anyway. We - * don't bother retrying after this, since if this next - * fails, that means that the file was deleted after we - * started this call. - */ - code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD, - userp, &req, &scp); - } - if (code) break; - - if (!isLast) { /* for anything other than dscp, release it unless it's the last one */ - cm_ReleaseSCache(tscp); - tscp = scp; /* Newly created directory will be next parent */ - } - } - - /* - * if we get here and code == 0, then scp is the last directory created, and tscp is the - * parent of scp. dscp got released if dscp != tscp. both tscp and scp are held. - */ - dscp = tscp; - } + cm_ReleaseSCache(dscp); + dscp = tscp1; + cm_ReleaseSCache(scp); + scp = tscp2; + /* + * if we get here and code == 0, then scp is the last directory created, and dscp is the + * parent of scp. + */ + } if (code) { /* something went wrong creating or truncating the file */ - if (scp) cm_ReleaseSCache(scp); - if (dscp) cm_ReleaseSCache(dscp); + if (scp) + cm_ReleaseSCache(scp); + if (dscp) + cm_ReleaseSCache(dscp); cm_ReleaseUser(userp); free(realPathp); return code; @@ -5359,14 +5398,15 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) * target of the symbolic link). Otherwise, * we'll just use the symlink anyway. */ - osi_Log2(smb_logp, "symlink vp %x to vp %x", - scp, targetScp); + osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp); cm_ReleaseSCache(scp); scp = targetScp; } } if (scp->fileType != CM_SCACHETYPE_FILE) { + if (dscp) + cm_ReleaseSCache(dscp); cm_ReleaseSCache(scp); cm_ReleaseUser(userp); free(realPathp); @@ -5377,7 +5417,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) /* (only applies to single component case) */ if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) { cm_ReleaseSCache(scp); - if (dscp) cm_ReleaseSCache(dscp); + cm_ReleaseSCache(dscp); cm_ReleaseUser(userp); free(realPathp); return CM_ERROR_NOTDIR; @@ -5387,7 +5427,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE); osi_assert(fidp); /* save a pointer to the vnode */ - fidp->scp = scp; + fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */ fidp->flags = fidflags; @@ -5401,7 +5441,10 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) fidp->NTopen_wholepathp = realPathp; /* we don't need this any longer */ - if (dscp) cm_ReleaseSCache(dscp); + if (dscp) { + cm_ReleaseSCache(dscp); + dscp = NULL; + } cm_Open(scp, 0, userp); /* set inp->fid so that later read calls in same msg can find fid */ @@ -5442,6 +5485,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) return 0; } + /* * A lot of stuff copied verbatim from NT Create&X to NT Tran Create. * Instead, ultimately, would like to use a subroutine for common code. @@ -6352,7 +6396,6 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter, } smb_SendPacket(vcp, watch); - smb_ReleaseVC(vcp); smb_FreePacket(watch); watch = nextWatch; } @@ -6419,8 +6462,6 @@ long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) ((smb_t *)watch)->errHigh = 0xC0; ((smb_t *)watch)->flg2 |= SMB_FLAGS2_ERR_STATUS; smb_SendPacket(vcp, watch); - if (watch->vcp) - smb_ReleaseVC(watch->vcp); smb_FreePacket(watch); return 0; } @@ -6445,7 +6486,6 @@ long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) { char *oldPathp, *newPathp; long code = 0; - cm_user_t *userp; char * tp; int attrs; int rename_type;