// 构造函数 // paramter: // dbColl 数据库集合指针 // user 帐户对象指针 // dom 检索式DOM public Query(DatabaseCollection dbColl, User user, XmlDocument dom) { m_dbColl = dbColl; m_oUser = user; m_dom = dom; // 从dom里找到warnging的处理级别信息 string strWarningLevel = ""; XmlNode nodeWarningLevel = dom.SelectSingleNode("//option"); if (nodeWarningLevel != null) strWarningLevel = DomUtil.GetAttr(nodeWarningLevel, "warning"); if (StringUtil.RegexCompare(@"\d", strWarningLevel) == true) m_nWarningLevel = Convert.ToInt32(strWarningLevel); }
// 新建数据库 // parameter: // user 帐户对象 // logicNames LogicNameItem数组 // strType 数据库类型,以逗号分隔,可以是file,accout // strSqlDbName 指定的Sql数据库名称,可以为null,系统自动生成一个,,如果数据库为文为文件型数据库,则认作数据源目录的名称 // strKeysDefault keys配置信息 // strBrowseDefault browse配置信息 // return: // -3 在新建库中,发现已经存在同名数据库, 本次不能创建 // -2 没有足够的权限 // -1 一般性错误,例如输入参数不合法等 // 0 操作成功 public int CreateDb(User user, LogicNameItem[] logicNames, string strType, string strSqlDbName, string strKeysDefault, string strBrowseDefault, out string strError) { strError = ""; if (strKeysDefault == null) strKeysDefault = ""; if (strBrowseDefault == null) strBrowseDefault = ""; if (strKeysDefault != "") { XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strKeysDefault); } catch (Exception ex) { strError = "加载keys配置文件内容到dom出错,原因:" + ex.Message; return -1; } } if (strBrowseDefault != "") { XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strBrowseDefault); } catch (Exception ex) { strError = "加载browse配置文件内容到dom出错,原因:" + ex.Message; return -1; } } string strEnLoginName = ""; // 可以一个逻辑库名也没有,不出错 string strLogicNames = ""; for (int i = 0; i < logicNames.Length; i++) { string strLang = logicNames[i].Lang; string strLogicName = logicNames[i].Value; if (strLang.Length != 2 && strLang.Length != 5) { strError = "语言版本字符串长度只能是2位或者5位,'" + strLang + "'语言版本不合法"; return -1; } if (this.IsExistLogicName(strLogicName, null) == true) { strError = "数据库中已存在'" + strLogicName + "'逻辑库名"; return -3; // 已存在相同数据库名 } strLogicNames += "<caption lang='" + strLang + "'>" + strLogicName + "</caption>"; if (String.Compare(logicNames[i].Lang.Substring(0, 2), "en", true) == 0) strEnLoginName = strLogicName; } strLogicNames = "<logicname>" + strLogicNames + "</logicname>"; // 检查当前帐户是否有创建数据库的权限 string strTempDbName = "test"; if (logicNames.Length > 0) strTempDbName = logicNames[0].Value; string strExistRights = ""; bool bHasRight = user.HasRights(strTempDbName, ResType.Database, "create", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对数据库没有'创建(create)'权限,目前的权限值为'" + strExistRights + "'。"; return -2; // 权限不够 } //**********对库集合加写锁**************** m_lock.AcquireWriterLock(m_nTimeOut); #if DEBUG_LOCK this.WriteDebugInfo("CreateDb(),对库集合加写锁。"); #endif try { if (strType == null) strType = ""; // 得到库的ID string strDbID = Convert.ToString(this.GetNewDbID()); string strPureCfgsDir = ""; string strTempSqlDbName = ""; if (strEnLoginName != "") { strTempSqlDbName = strEnLoginName + "_db"; strPureCfgsDir = strEnLoginName + "_cfgs"; } else { strTempSqlDbName = "dprms_" + strDbID + "_db"; strPureCfgsDir = "dprms_" + strDbID + "_cfgs"; } if (strSqlDbName == null || strSqlDbName == "") strSqlDbName = strTempSqlDbName; if (StringUtil.IsInList("file", strType, true) == false) { strSqlDbName = this.GetFinalSqlDbName(strSqlDbName); if (this.IsExistSqlName(strSqlDbName) == true) { strError = "不可能的情况,数据库中已存在'" + strSqlDbName + "'Sql库名"; return -1; } if (this.InstanceName != "") strSqlDbName = this.InstanceName + "_" + strSqlDbName; } string strDataSource = ""; if (StringUtil.IsInList("file", strType, true) == true) { strDataSource = strSqlDbName; strDataSource = this.GetFinalDataSource(strDataSource); if (this.IsExistFileDbSource(strDataSource) == true) { strError = "不可能的情况,数据库中已存在''文件数据目录"; return -1; } string strDataDir = this.DataDir + "\\" + strDataSource; if (Directory.Exists(strDataDir) == true) { strError = "不可能的情况,本地不会有重名的目录。"; return -1; } Directory.CreateDirectory(strDataDir); } strPureCfgsDir = this.GetFinalCfgsDir(strPureCfgsDir); // 把配置文件目录自动创建好 string strCfgsDir = this.DataDir + "\\" + strPureCfgsDir + "\\cfgs"; if (Directory.Exists(strCfgsDir) == true) { strError = "服务器已存在'" + strPureCfgsDir + "'配置文件目录,请指定其它的英文逻辑库名。"; return -1; } Directory.CreateDirectory(strCfgsDir); string strPureKeysLocalName = "keys.xml"; string strPureBrowseLocalName = "browse.xml"; int nRet = 0; // 写keys配置文件 nRet = DatabaseUtil.CreateXmlFile(strCfgsDir + "\\" + strPureKeysLocalName, strKeysDefault, out strError); if (nRet == -1) return -1; // 写browse配置文件 nRet = DatabaseUtil.CreateXmlFile(strCfgsDir + "\\" + strPureBrowseLocalName, strBrowseDefault, out strError); if (nRet == -1) return -1; if (StringUtil.IsInList("file", strType) == true) strSqlDbName = ""; // 这里发生xml片断可能会有小问题,应当用XmlTextWriter来发生? string strDbXml = "<database type='" + strType + "' id='" + strDbID + "' localdir='" + strPureCfgsDir + "' dbo='"+user.Name+"'>" // dbo参数为2006/7/4增加 + "<property>" + strLogicNames + "<datasource>" + strDataSource + "</datasource>" + "<seed>0</seed>" + "<sqlserverdb name='" + strSqlDbName + "'/>" + "</property>" + "<dir name='cfgs' localdir='cfgs'>" + "<file name='keys' localname='" + strPureKeysLocalName + "'/>" + "<file name='browse' localname='" + strPureBrowseLocalName + "'/>" + "</dir>" + "</database>"; this.NodeDbs.InnerXml = this.NodeDbs.InnerXml + strDbXml; XmlNodeList nodeListDb = this.NodeDbs.SelectNodes("database"); if (nodeListDb.Count == 0) { strError = "刚新建数据库,不可能一个数据库都不存在。"; return -1; } // 最后一个库为新建的数据库,加到集合里 XmlNode nodeDb = nodeListDb[nodeListDb.Count - 1]; // return: // -1 出错 // 0 成功 nRet = this.AddDatabase(nodeDb, out strError); if (nRet == -1) return -1; // 及时加入dbo特性 user.AddOwnerDbName(strTempDbName); // 及时保存到database.xml this.Changed = true; this.SaveXml(); } finally { m_lock.ReleaseWriterLock(); //***********对库集合解写锁**************** #if DEBUG_LOCK this.WriteDebugInfo("CreateDb(),对库集合解写锁。"); #endif } return 0; }
// 写入一批 XML 记录 // 这里利用 WriteXml 实现了基本功能,但速度没有得到优化。派生类可以重写此函数,以求得最快的速度 // return: // -1 出错 // >=0 如果是 rebuildkeys,则返回总共处理的 keys 行数 public virtual int WriteRecords( // SessionInfo sessininfo, User oUser, List<RecordBody> records, string strStyle, out List<RecordBody> outputs, out string strError) { strError = ""; outputs = new List<RecordBody>(); if (StringUtil.IsInList("rebuildkeys", strStyle) == true) { strError = "目前 Database::WriteRecords() 尚未实现重建检索点的功能"; return -1; } foreach (RecordBody record in records) { string strPath = record.Path; // 包括数据库名的路径 string strDbName = StringUtil.GetFirstPartPath(ref strPath); bool bObject = false; string strRecordID = ""; string strObjectID = ""; string strXPath = ""; string strFirstPart = StringUtil.GetFirstPartPath(ref strPath); //***********吃掉第2层************* // 到此为止,strPath不含记录号层了,下级分情况判断 strRecordID = strFirstPart; // 只到记录号层的路径 if (strPath == "") { bObject = false; } else { strFirstPart = StringUtil.GetFirstPartPath(ref strPath); //***********吃掉第2层************* // 到此为止,strPath不含object或xpath层 strFirstPart可能是object 或 xpath if (strFirstPart != "object" && strFirstPart != "xpath") { record.Result.Value = -1; record.Result.ErrorString = "资源路径 '" + record.Path + "' 不合法, 第3级必须是 'object' 或 'xpath' "; record.Result.ErrorCode = ErrorCodeValue.PathError; // -7; continue; } if (string.IsNullOrEmpty(strPath) == true) //object或xpath下级必须有值 { record.Result.Value = -1; record.Result.ErrorString = "资源路径 '" + record.Path + "' 不合法,当第3级是 'object' 或 'xpath' 时,第4级必须有内容"; record.Result.ErrorCode = ErrorCodeValue.PathError; // -7; continue; } if (strFirstPart == "object") { strObjectID = strPath; bObject = true; } else { strXPath = strPath; bObject = false; } } if (bObject == true) { record.Result.Value = -1; record.Result.ErrorString = "目前不允许用 WriteRecords 写入对象资源"; record.Result.ErrorCode = ErrorCodeValue.CommonError; continue; } byte[] baContent = Encoding.UTF8.GetBytes(record.Xml); string strRanges = "0-" + (baContent.Length - 1).ToString(); byte[] outputTimestamp = null; string strOutputID = ""; string strOutputValue = ""; int nRet = WriteXml(oUser, strRecordID, strXPath, strRanges, baContent.Length, baContent, record.Metadata, strStyle, record.Timestamp, out outputTimestamp, out strOutputID, out strOutputValue, false, out strError); if (nRet <= -1) { record.Result.Value = -1; record.Result.ErrorCode = KernelApplication.Ret2ErrorCode(nRet); record.Result.ErrorString = strError; } else { if (string.IsNullOrEmpty(strXPath) == true) record.Path = strDbName + "/" + strOutputID; else record.Path = strDbName + "/" + strOutputID + "/xpath/" + strXPath; record.Result.Value = nRet; record.Result.ErrorCode = ErrorCodeValue.NoError; record.Result.ErrorString = strOutputValue; } record.Timestamp = outputTimestamp; record.Metadata = null; record.Xml = null; outputs.Add(record); } return 0; }
// 写xml数据 // parameter: // strID 记录ID -1:表示追加一条记录 // strRanges 目标的位置,多个range用逗号分隔 // nTotalLength 总长度 // inputTimestamp 输入的时间戳 // outputTimestamp 返回的时间戳 // strOutputID 返回的记录ID,当strID == -1时,得到实际的ID // strError // return: // -1 出错 // -2 时间戳不匹配 // -4 记录不存在 // -6 权限不够 // 0 成功 public override int WriteXml(User oUser, //null,则不检索权限 string strID, string strXPath, string strRanges, long lTotalLength, byte[] baSource, Stream streamSource, string strMetadata, string strStyle, byte[] inputTimestamp, out byte[] outputTimestamp, out string strOutputID, out string strOutputValue, //当AddInteger 或 AppendString时 返回值最后的值 bool bCheckAccount, out string strError) { strOutputValue = ""; outputTimestamp = null; strOutputID = ""; strError = ""; if (strID == "?") strID = "-1"; bool bPushTailNo = false; strID = this.EnsureID(strID, out bPushTailNo); //加好写锁 if (oUser != null) { string strTempRecordPath = this.GetCaption("zh-cn") + "/" + strID; if (bPushTailNo == true) { string strExistRights = ""; bool bHasRight = oUser.HasRights(strTempRecordPath, ResType.Record, "create",//"append", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + oUser.Name + "',对'" + strTempRecordPath + "'记录没有'创建(create)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } } else { string strExistRights = ""; bool bHasRight = oUser.HasRights(strTempRecordPath, ResType.Record, "overwrite", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + oUser.Name + "',对'" + strTempRecordPath + "'记录没有'覆盖(overwrite)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } } } strOutputID = DbPath.GetCompressedID(strID); int nRet = 0; bool bFull = false; //*********对数据库加读锁************* m_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK_SQLDATABASE this.container.WriteDebugInfo("WriteXml(),对'" + this.GetCaption("zh-cn") + "'数据库加读锁。"); #endif try { strID = DbPath.GetID10(strID); //**********对记录加写锁*************** this.m_recordLockColl.LockForWrite(strID, m_nTimeOut); #if DEBUG_LOCK_SQLDATABASE this.container.WriteDebugInfo("WriteXml(),对'" + this.GetCaption("zh-cn") + "/" + strID + "'记录加写锁。"); #endif try // 记录锁 { SqlConnection connection = new SqlConnection(this.m_strConnString); connection.Open(); try // 连接 { // 1.如果记录不存在,插入一条字节的记录,以确保得到textPtr // return: // -1 出错 // 0 不存在 // 1 存在 nRet = this.RecordIsExist(connection, strID, out strError); if (nRet == -1) return -1; bool bExist = false; if (nRet == 1) bExist = true; // 新记录时,插入一个字节,并生成新时间戳 if (bExist == false) { byte[] tempInputTimestamp = inputTimestamp; // 注意新记录的时间戳,用inputTimestamp变量 nRet = this.InsertRecord(connection, strID, out inputTimestamp,//tempTimestamp,// out strError); if (nRet == -1) return -1; } // 写数据 // return: // -1 一般性错误 // -2 时间戳不匹配 // 0 成功 nRet = this.WriteSqlRecord(connection, strID, strRanges, (int)lTotalLength, baSource, streamSource, strMetadata, strStyle, inputTimestamp, out outputTimestamp, out bFull, out strError); if (nRet <= -1) return nRet; // 检查范围 //string strCurrentRange = this.GetRange(connection, // strID); if (bFull == true) //覆盖完了 { byte[] baOldPreamble = new byte[0]; byte[] baNewPreamble = new byte[0]; // 1.得到新旧检索点 string strOldXml = ""; if (bExist == true) { // return: // -1 出错 // -4 记录不存在 // 0 正确 nRet = this.GetXmlData( connection, strID, "data", out strOldXml, out baOldPreamble, out strError); if (nRet <= -1 && nRet != -3) return nRet; } string strNewXml = ""; // return: // -1 出错 // -4 记录不存在 // 0 正确 nRet = this.GetXmlData( connection, strID, "newdata", out strNewXml, out baNewPreamble, out strError); if (nRet == -1) return -1; // 修改部分 if (strXPath != null && strXPath != "") { string strLocateXPath = ""; string strCreatePath = ""; string strNewRecordTemplate = ""; string strAction = ""; nRet = DatabaseUtil.PaseXPathParameter(strXPath, out strLocateXPath, out strCreatePath, out strNewRecordTemplate, out strAction, out strError); if (nRet == -1) return -1; XmlDocument tempDom = new XmlDocument(); tempDom.PreserveWhitespace = true; //设PreserveWhitespace为true try { if (strOldXml == "") { if (strNewRecordTemplate == "") tempDom.LoadXml("<root/>"); else tempDom.LoadXml(strNewRecordTemplate); } else tempDom.LoadXml(strOldXml); } catch (Exception ex) { strError = "WriteXml() 在给'" + this.GetCaption("zh-cn") + "'库写入记录'" + strID + "'时,装载旧记录到dom出错,原因:" + ex.Message; return -1; } if (strLocateXPath == "") { strError = "xpath表达式中的locate参数不能为空值"; return -1; } // 通过strLocateXPath定位到指定的节点 XmlNode node = null; try { node = tempDom.DocumentElement.SelectSingleNode(strLocateXPath); } catch (Exception ex) { strError = "WriteXml() 在给'" + this.GetCaption("zh-cn") + "'库写入记录'" + strID + "'时,XPath式子'" + strXPath + "'选择元素时出错,原因:" + ex.Message; return -1; } if (node == null) { if (strCreatePath == "") { strError = "给'" + this.GetCaption("zh-cn") + "'库写入记录'" + strID + "'时,XPath式子'" + strXPath + "'指定的节点未找到。此时xpath表达式中的create参数不能为空值"; return -1; } node = DomUtil.CreateNodeByPath(tempDom.DocumentElement, strCreatePath); if (node == null) { strError = "内部错误!"; return -1; } } if (node.NodeType == XmlNodeType.Attribute) { if (strAction == "AddInteger" || strAction == "+AddInteger" || strAction == "AddInteger+") { int nNumber = 0; try { nNumber = Convert.ToInt32(strNewXml); } catch (Exception ex) { strError = "传入的内容'" + strNewXml + "'不是数字格式。" + ex.Message; return -1; } string strOldValue = node.Value; string strLastValue; nRet = StringUtil.IncreaseNumber(strOldValue, nNumber, out strLastValue, out strError); if (nRet == -1) return -1; if (strAction == "AddInteger+") { strOutputValue = node.Value; } else { strOutputValue = strLastValue; } node.Value = strLastValue; //strOutputValue = node.Value; } else if (strAction == "AppendString") { node.Value = node.Value + strNewXml; strOutputValue = node.Value; } else if (strAction == "Push") { string strLastValue; nRet = StringUtil.GetBiggerLedNumber(node.Value, strNewXml, out strLastValue, out strError); if (nRet == -1) return -1; node.Value = strLastValue; strOutputValue = node.Value; } else { node.Value = strNewXml; strOutputValue = node.Value; } } else if (node.NodeType == XmlNodeType.Element) { //Create a document fragment. XmlDocumentFragment docFrag = tempDom.CreateDocumentFragment(); //Set the contents of the document fragment. docFrag.InnerXml = strNewXml; //Add the children of the document fragment to the //original document. node.ParentNode.InsertBefore(docFrag, node); if (strAction == "AddInteger" || strAction == "AppendString") { XmlNode newNode = node.PreviousSibling; if (newNode == null) { strError = "newNode不可能为null"; return -1; } string strNewValue = newNode.InnerText; string strOldValue = DomUtil.GetNodeText(node); if (strAction == "AddInteger") { int nNumber = 0; try { nNumber = Convert.ToInt32(strNewValue); } catch (Exception ex) { strError = "传入的内容'" + strNewValue + "'不是数字格式。" + ex.Message; return -1; } string strLastValue; nRet = StringUtil.IncreaseNumber(strOldValue, nNumber, out strLastValue, out strError); if (nRet == -1) return -1; /* string strLastValue; nRet = Database.AddInteger(strNewValue, strOldValue, out strLastValue, out strError); if (nRet == -1) return -1; */ newNode.InnerText = strLastValue; strOutputValue = newNode.OuterXml; } else if (strAction == "AppendString") { newNode.InnerText = strOldValue + strNewValue; strOutputValue = newNode.OuterXml; } else if (strAction == "Push") { string strLastValue; nRet = StringUtil.GetBiggerLedNumber(strOldValue, strNewValue, out strLastValue, out strError); if (nRet == -1) return -1; newNode.InnerText = strLastValue; strOutputValue = newNode.OuterXml; } } node.ParentNode.RemoveChild(node); } strNewXml = tempDom.OuterXml; byte[] baRealXml = DatabaseUtil.StringToByteArray( strNewXml, baNewPreamble); string strMyRange = ""; strMyRange = "0-" + Convert.ToString(baRealXml.Length - 1); lTotalLength = baRealXml.Length; // return: // -1 一般性错误 // -2 时间戳不匹配 // 0 成功 nRet = this.WriteSqlRecord(connection, strID, strMyRange, (int)lTotalLength, baRealXml, null, strMetadata, strStyle, outputTimestamp, //注意这儿 out outputTimestamp, out bFull, out strError); if (nRet <= -1) return nRet; } KeyCollection newKeys = null; KeyCollection oldKeys = null; XmlDocument newDom = null; XmlDocument oldDom = null; // return: // -1 出错 // 0 成功 nRet = this.MergeKeys(strID, strNewXml, strOldXml, true, out newKeys, out oldKeys, out newDom, out oldDom, out strError); if (nRet == -1) return -1; // 处理检索点 // return: // -1 出错 // 0 成功 nRet = this.ModifyKeys(connection, newKeys, oldKeys, out strError); if (nRet == -1) return -1; // 处理子文件 // return: // -1 出错 // 0 成功 nRet = this.ModifyFiles(connection, strID, newDom, oldDom, out strError); if (nRet == -1) return -1; // 4.用new更新data // return: // -1 出错 // >=0 成功 返回影响的记录数 nRet = this.UpdateDataField(connection, strID, out strError); if (nRet == -1) return -1; // 5.删除newdata字段 // return: // -1 出错 // 0 成功 nRet = this.DeleteDuoYuImage(connection, strID, "newdata", 0, out strError); if (nRet == -1) return -1; } } catch (SqlException sqlEx) { if (sqlEx.Errors is SqlErrorCollection) strError = "数据库'" + this.GetCaption("zh") + "'尚未初始化。"; else strError = "WriteXml() 在给'" + this.GetCaption("zh-cn") + "'库写入记录'" + strID + "'时出错,原因:" + sqlEx.Message; return -1; } catch (Exception ex) { strError = "WriteXml() 在给'" + this.GetCaption("zh-cn") + "'库写入记录'" + strID + "'时出错,原因:" + ex.Message; return -1; } finally // 连接 { connection.Close(); } } finally // 记录锁 { //******对记录解写锁**************************** m_recordLockColl.UnlockForWrite(strID); #if DEBUG_LOCK_SQLDATABASE this.container.WriteDebugInfo("WriteXml(),对'" + this.GetCaption("zh-cn") + "/" + strID + "'记录解写锁。"); #endif } } finally { //********对数据库解读锁**************** m_lock.ReleaseReaderLock(); #if DEBUG_LOCK_SQLDATABASE this.container.WriteDebugInfo("WriteXml(),对'" + this.GetCaption("zh-cn") + "'数据库解读锁。"); #endif } // 当本函数被明知为账户库的写操作调用时, 一定要用bCheckAccount==false // 来调用,否则容易引起不必要的递归 if (bFull == true && bCheckAccount == true && StringUtil.IsInList("account", this.TypeSafety) == true) { string strResPath = this.FullID + "/" + strID; this.container.UserColl.RefreshUserSafety(strResPath); } return 0; }
// 写对象 // strRecordID 记录ID // strObjectID 资源ID // strRanges 范围 // nTotalLength 总长度 // sourceBuffer 源数据 // strMetadata 元数据 // strStyle 样式 // inputTimestamp 输入的时间戳 // outputTimestamp out参数,返回的时间戳 // return: // -1 出错 // -2 时间戳不匹配 // -4 记录或对象资源不存在 // -6 权限不够 // 0 成功 public override int WriteObject(User user, string strRecordID, string strObjectID, string strRanges, long lTotalLength, byte[] baSource, // Stream streamSource, string strMetadata, string strStyle, byte[] inputTimestamp, out byte[] outputTimestamp, out string strError) { outputTimestamp = null; strError = ""; int nRet = 0; if (user != null) { string strTempRecordPath = this.GetCaption("zh-CN") + "/" + strRecordID; string strExistRights = ""; bool bHasRight = user.HasRights(strTempRecordPath, ResType.Record, "overwrite", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对'" + strTempRecordPath + "'记录没有'覆盖(overwrite)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } } //**********对数据库加读锁************ m_db_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK this.container.WriteDebugInfo("WriteObject(),对'" + this.GetCaption("zh-CN") + "'数据库加读锁。"); #endif try { string strOutputRecordID = ""; // return: // -1 出错 // 0 成功 nRet = this.CanonicalizeRecordID(strRecordID, out strOutputRecordID, out strError); if (nRet == -1) return -1; if (strOutputRecordID == "-1") { strError = "保存对象资源不支持记录号参数值为'" + strRecordID + "'。"; return -1; } strRecordID = strOutputRecordID; //**********对记录加写锁*************** m_recordLockColl.LockForWrite(strRecordID, m_nTimeOut); #if DEBUG_LOCK this.container.WriteDebugInfo("WriteObject(),对'" + this.GetCaption("zh-CN") + "/" + strRecordID + "'记录加写锁。"); #endif try { ////////////////////////////////////////////// // 1.在对应的xml数据,用对象路径找到对象ID /////////////////////////////////////////////// string strXmlFilePath = this.GetXmlFilePath(strRecordID); XmlDocument xmlDom = new XmlDocument(); xmlDom.PreserveWhitespace = true; //设PreserveWhitespace为true xmlDom.Load(strXmlFilePath); XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDom.NameTable); nsmgr.AddNamespace("dprms", DpNs.dprms); XmlNode fileNode = xmlDom.DocumentElement.SelectSingleNode("//dprms:file[@id='" + strObjectID + "']", nsmgr); if (fileNode == null) { strError = "在数据xml里没有找到该ID对应的dprms:file节点"; return -1; } string strObjectFilePath = this.GetObjectFileName(strRecordID, strObjectID); if (File.Exists(strObjectFilePath) == false) { strError = "服务器错误:资源记录'" + strObjectFilePath + "'不存在,不可能的情况"; return -1; } string strNewObjectFileName = DatabaseUtil.GetNewFileName(strObjectFilePath); if (File.Exists(strNewObjectFileName) == false) { this.UpdateObject(strObjectFilePath, strStyle, inputTimestamp, out inputTimestamp); // Updata后,记录临时文件有一个字节,所有信息都存在了. } int nFull; nRet = this.WriteFileDbTempRecord(strObjectFilePath, strRanges, lTotalLength, baSource, // streamSource, strMetadata, strStyle, inputTimestamp, out outputTimestamp, out nFull, out strError); if (nRet <= -1) return nRet; if (nFull == 1) //覆盖完了 { // 1. 替换data字段 File.Copy(strNewObjectFileName, strObjectFilePath, true); // 2. 删除newdata字段 File.Delete(strNewObjectFileName); } } catch (Exception ex) { strError = "WriteXml() 在给'" + this.GetCaption("zh-CN") + "'库写入资源'" + strRecordID + "_" + strObjectID + "'时出错,原因:" + ex.Message; return -1; } finally { //********对记录解写锁**************************** m_recordLockColl.UnlockForWrite(strRecordID); #if DEBUG_LOCK this.container.WriteDebugInfo("WriteObject(),对'" + this.GetCaption("zh-CN") + "/" + strRecordID + "'记录解写锁。"); #endif } } finally { //*******对数据库解读锁**************** m_db_lock.ReleaseReaderLock(); #if DEBUG_LOCK this.container.WriteDebugInfo("WriteObject(),对'" + this.GetCaption("zh-CN") + "'数据库解读锁。"); #endif } return 0; }
// 删除数据库 // parameters: // strDbName 数据库名称,可以是各种语言版本的逻辑名,也可以是id号 // strError out参数,返回出错信息 // return: // -1 出错 // -6 无足够的权限 // 0 成功 public int DeleteDb(User user, string strDbName, out string strError) { strError = ""; if (user == null) { strError = "DeleteDb()调用错误,user参数不能为null。"; return -1; } if (String.IsNullOrEmpty(strDbName) == true) { strError = "DeleteDb()调用错误,strDbName参数值不能为null或空字符串。"; return -1; } //**********对库集合加写锁**************** m_lock.AcquireWriterLock(m_nTimeOut); #if DEBUG_LOCK this.WriteDebugInfo("DeleteDb(),对库集合加写锁。"); #endif try { Database db = this.GetDatabase(strDbName); if (db == null) { strError = "未找到名为'" + strDbName + "'的数据库"; return -1; } // 检查当前帐户是否有写权限 string strExistRights = ""; bool bHasRight = user.HasRights(db.GetCaption("zh-cn"), ResType.Database, "delete", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对'" + strDbName + "'数据库没有'删除(delete)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } // 调database的Delete()函数,删除该库使用的配置文件,与物理数据库 // return: // -1 出错 // 0 成功 int nRet = db.Delete(out strError); if (nRet == -1) return -1; //this.m_nodeDbs.RemoveChild(db.m_selfNode); List<XmlNode> nodes = DatabaseUtil.GetNodes(this.NodeDbs, strDbName); if (nodes.Count != 1) { strError = "未找到名为'" + db.GetCaption("zh") + "'的数据库。"; return -1; } this.NodeDbs.RemoveChild(nodes[0]); // 删除内存对象 this.Remove(db); // 及时除去dbo特性 user.RemoveOwerDbName(strDbName); // 及时保存到database.xml this.Changed = true; this.SaveXml(); return 0; } finally { m_lock.ReleaseWriterLock(); //***********对库集合解写锁**************** #if DEBUG_LOCK this.WriteDebugInfo("DeleteDb(),对库集合解写锁。"); #endif } }
// 列出服务器下当前帐户有显示权限的数据库 // 线:不安全的 // parameters: // strStyle 是否要列出所有语言的名字? "alllang"表示要列出所有语言的名字 public int GetDirableChildren(User user, string strLang, string strStyle, out ArrayList aItem, out string strError) { aItem = new ArrayList(); strError = ""; if (this.NodeDbs == null) { strError = "服装器配置文件不合法,未定义<dbs>元素"; return -1; } foreach (XmlNode child in this.NodeDbs.ChildNodes) { string strChildName = DomUtil.GetAttr(child, "name"); if (String.Compare(child.Name, "database", true) != 0 && strChildName == "") continue; if (String.Compare(child.Name, "database", true) != 0 && String.Compare(child.Name, "dir", true) != 0 && String.Compare(child.Name, "file", true) != 0) { continue; } string strExistRights; bool bHasRight = false; ResInfoItem resInfoItem = new ResInfoItem(); if (String.Compare(child.Name, "database", true) == 0) { string strID = DomUtil.GetAttr(child, "id"); Database db = this.GetDatabaseByID("@" + strID); if (db == null) { strError = "未找到id为'" + strID + "'的数据库"; return -1; } bHasRight = user.HasRights(db.GetCaption("zh"), ResType.Database, "list", out strExistRights); if (bHasRight == false) continue; if (StringUtil.IsInList("account", db.GetDbType(), true) == true) resInfoItem.Style = 1; else resInfoItem.Style = 0; resInfoItem.TypeString = db.GetDbType(); resInfoItem.Name = db.GetCaptionSafety(strLang); resInfoItem.Type = 0; // 数据库 resInfoItem.HasChildren = true; // 如果要获得全部语言的名字 if (StringUtil.IsInList("alllang", strStyle) == true) { List<string> results = db.GetAllLangCaptionSafety(); string [] names = new string[results.Count]; results.CopyTo(names); resInfoItem.Names = names; } } else if (String.Compare(child.Name, "dir", true) == 0) { bHasRight = user.HasRights(strChildName, ResType.Directory, "list", out strExistRights); if (bHasRight == false) continue; resInfoItem.HasChildren = true; resInfoItem.Type = 4; // 目录 resInfoItem.Name = strChildName; resInfoItem.TypeString = DomUtil.GetAttr(child, "type"); // xietao 2006/6/5 add } else { bHasRight = user.HasRights(strChildName, ResType.File, "list", out strExistRights); if (bHasRight == false) continue; resInfoItem.HasChildren = false; resInfoItem.Name = strChildName; resInfoItem.Type = 5; // 文件? resInfoItem.TypeString = DomUtil.GetAttr(child, "type"); // xietao 2006/6/5 add } aItem.Add(resInfoItem); } return 0; }
// 根据服务器上的指定路径列出其下级的事项 // parameters: // strPath 路径,不带服务器部分, // 格式为: "数据库名/下级名/下级名", // 当为null或者为""时,表示列出该服务器下所有的数据库 // lStart 起始位置,从0开始 ,不能小于0 // lLength 长度 -1表示从lStart到最后 // strLang 语言版本 用标准字母表示法,如zh-cn // strStyle 是否要列出所有语言的名字? "alllang"表示要列出全部语言 // items out参数,返回下级事项数组 // return: // -1 出错 // -6 权限不够 // 0 正常 // 说明 只有当前帐户对事项有"list"权限时,才能列出来。 // 如果列本服务器的数据库时,对所有的数据库都没有list权限,都按错误处理,与没有数据库事项区分开。 public int Dir(string strResPath, long lStart, long lLength, long lMaxLength, string strLang, string strStyle, User user, out ResInfoItem[] items, out int nTotalLength, out string strError) { items = new ResInfoItem[0]; nTotalLength = 0; ArrayList aItem = new ArrayList(); strError = ""; int nRet = 0; //******************加库集合加读锁****** this.m_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK this.WriteDebugInfo("Dir(),对库集合加读锁。"); #endif try { if (strResPath == "" || strResPath == null) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 1.取服务器下的数据库 nRet = this.GetDirableChildren(user, strLang, strStyle, out aItem, out strError); if (this.Count > 0 && aItem.Count == 0) { strError = "您的帐户名为'" + user.Name + "',对所有的数据库都没有'显示(list)'权限。"; return -6; } } else { string strPath = strResPath; string strDbName = StringUtil.GetFirstPartPath(ref strPath); // 可以是数据库也可以是配置事项 if (strPath == "") { Database db = this.GetDatabase(strDbName); if (db != null) { // return: // -1 出错 // 0 成功 nRet = db.GetDirableChildren(user, strLang, strStyle, out aItem, out strError); if (nRet == -1) return -1; goto END1; } } // return: // -1 出错 // 0 成功 nRet = this.DirCfgItem(user, strResPath, out aItem, out strError); if (nRet == -1) return -1; } } finally { m_lock.ReleaseReaderLock(); //*************对库集合解读锁*********** #if DEBUG_LOCK this.WriteDebugInfo("Dir(),对库集合解读锁。"); #endif } END1: // 列出实际需要的项 nTotalLength = aItem.Count; int nOutputLength; // return: // -1 出错 // 0 成功 nRet = DatabaseUtil.GetRealLength((int)lStart, (int)lLength, nTotalLength, (int)lMaxLength, out nOutputLength, out strError); if (nRet == -1) return -1; items = new ResInfoItem[(int)nOutputLength]; for (int i = 0; i < items.Length; i++) { items[i] = (ResInfoItem)(aItem[i + (int)lStart]); } return 0; }
// 检索 // parameter: // strQuery 检索式XML字符串 // resultSet 结果集,用于存放检索结果 // oUser 帐户对象,用于检索该帐户对某库是否有读权限 // 为null,则不进行权限的检查,即按有权限算 // isConnected delegate对象,用于通讯是否连接正常 // 为null,则不调delegate函数 // strError out参数,返回出错信息 // return: // -1 出错 // -6 权限不够 // 0 成功 // 线: 安全的 public int Search(string strQuery, DpResultSet resultSet, User oUser, Delegate_isConnected isConnected, out string strError) { strError = ""; //对库集合加读锁********************************* m_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK this.WriteDebugInfo("Search(),对库集合加读锁。"); #endif try { if (String.IsNullOrEmpty(strQuery) == true) { strError = "Search()调用错误,strQuery不能为null或空字符串"; return -1; } // 一进来先给结果集的m_strQuery成员赋值, // 不管是否是合法的XML,在用结果集的时候再判断 resultSet.m_strQuery = strQuery; XmlDocument dom = new XmlDocument(); dom.PreserveWhitespace = true; //设PreserveWhitespace为true try { dom.LoadXml(strQuery); } catch (Exception ex) { strError += "检索式字符串加载到dom出错,原因:" + ex.Message + "\r\n" + "检索式字符串如下:\r\n" + strQuery; return -1; } //创建Query对象 Query query = new Query(this, oUser, dom); //进行检索 // return: // -1 出错 // -6 无权限 // 0 成功 int nRet = query.DoQuery(dom.DocumentElement, resultSet, isConnected, out strError); if (nRet <= -1) return nRet; } finally { //****************对库集合解读锁************** m_lock.ReleaseReaderLock(); #if DEBUG_LOCK this.WriteDebugInfo("Search(),对库集合解读锁。"); #endif } return 0; }
// ???对库集合加读锁 // 初始化数据库 // parameters: // user 帐户对象 // strDbName 数据库名称 // strError out参数,返回出错信息 // return: // -1 出错 // -5 数据库不存在 // -6 权限不够 // 0 成功 // 线:安全 代码没跟上 public int InitializePhysicalDatabase(User user, string strDbName, out string strError) { strError = ""; Debug.Assert(user != null, "InitializeDb()调用错误,user参数值不能为null。"); if (String.IsNullOrEmpty(strDbName) == true) { strError = "InitializeDb()调用错误,strDbName参数值不能为null或空字符串。"; return -1; } // 1.得到数据库 Database db = this.GetDatabaseSafety(strDbName); if (db == null) { strError = "没有找到名为'" + strDbName + "'的数据库"; return -5; } string strExistRights = ""; bool bHasRight = user.HasRights(db.GetCaption("zh-cn"), ResType.Database, "clear", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对'" + strDbName + "'数据库没有'初始化(clear)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } // 3.初始化 // return: // -1 出错 // 0 成功 return db.InitialPhysicalDatabase(out strError); }
// 设置数据库基本信息 // parameter: // strDbName 数据库名称 // strLang 对应的语言版本,如果语言版本为null或者为空字符串,则从所有的语言版本中找 // logicNames LogicNameItem数组 // strType 数据库类型,以逗号分隔,可以是file,accout,目前无效,因为涉及到是文件库,还是sql库的问题 // strSqlDbName 指定的新Sql数据库名称,,目前无效 // strKeysDefault keys配置信息 // strBrowseDefault browse配置信息 // return: // -1 一般性错误 // -2 已存在同名的数据库 // -5 未找到数据库对象 // -6 没有足够的权限 // 0 成功 public int SetDbInfo(User user, string strDbName, LogicNameItem[] logicNames, string strType, string strSqlDbName, string strKeysText, string strBrowseText, out string strError) { strError = ""; Debug.Assert(user != null, "SetDbInfo()调用错误,user参数不能为null。"); if (String.IsNullOrEmpty(strDbName) == true) { strError = "SetDbInfo()调用错误,strDbName参数值不能为null或空字符串。"; return -1; } // 为避免死锁的问题,将查看权限的函数放在外面了 // 检查当前帐户是否有覆盖数据库结构的权限 string strExistRights = ""; bool bHasRight = user.HasRights(strDbName, ResType.Database, "overwrite", out strExistRights); //******************对库集合加读锁****** this.m_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK this.WriteDebugInfo("SetDbInfo(),对库集合加读锁。"); #endif try { Database db = this.GetDatabase(strDbName); if (db == null) { strError = "未找到名为'" + strDbName + "'的数据库。"; return -5; } if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对'" + strDbName + "'数据库没有'覆盖(overwrite)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } // return: // -1 出错 // -2 已存在同名的数据库 // 0 成功 int nRet = db.SetInfo(logicNames, strType, strSqlDbName, strKeysText, strBrowseText, out strError); if (nRet <= -1) return nRet; // 及时保存databases.xml this.Changed = true; this.SaveXml(); return 0; } finally { this.m_lock.ReleaseReaderLock(); //*****************对库集合解读锁************* #if DEBUG_LOCK this.WriteDebugInfo("SetDbInfo(),对库集合解读锁。"); #endif } }
// 得到数据库可以显示的下级 // parameters: // oUser 帐户对象 // db 数据库对象 // strLang 语言版本 // aItem out参数,返回数据库可以显示的下级 // strError out参数,返回出错信息 // return: // -1 出错 // 0 成功 public int GetDirableChildren(User user, string strLang, string strStyle, out ArrayList aItem, out string strError) { aItem = new ArrayList(); strError = ""; //**********对数据库加读锁************** this.m_db_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK this.container.WriteDebugInfo("Dir(),对'" + this.GetCaption("zh-CN") + "'数据库加读锁。"); #endif try { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 1.配置事项 foreach (XmlNode child in this.m_selfNode.ChildNodes) { string strElementName = child.Name; if (String.Compare(strElementName, "dir", true) != 0 && String.Compare(strElementName, "file", true) != 0) { continue; } string strChildName = DomUtil.GetAttr(child, "name"); if (strChildName == "") continue; string strCfgPath = this.GetCaption("zh-CN") + "/" + strChildName; string strExistRights; bool bHasRight = false; ResInfoItem resInfoItem = new ResInfoItem(); resInfoItem.Name = strChildName; if (child.Name == "dir") { bHasRight = user.HasRights(strCfgPath, ResType.Directory, "list", out strExistRights); if (bHasRight == false) continue; resInfoItem.HasChildren = true; resInfoItem.Type = 4; // 目录 resInfoItem.TypeString = DomUtil.GetAttr(child, "type"); // xietao 2006/6/5 } else { bHasRight = user.HasRights(strCfgPath, ResType.File, "list", out strExistRights); if (bHasRight == false) continue; resInfoItem.HasChildren = false; resInfoItem.Type = 5; // 文件 resInfoItem.TypeString = DomUtil.GetAttr(child, "type"); // xietao 2006/6/5 add } aItem.Add(resInfoItem); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 2.检索途径 KeysCfg keysCfg = null; int nRet = this.GetKeysCfg(out keysCfg, out strError); if (nRet == -1) return -1; if (keysCfg != null) { List<TableInfo> aTableInfo = null; nRet = keysCfg.GetTableInfosRemoveDup( out aTableInfo, out strError); if (nRet == -1) return -1; // 对于检索途径,全部都有权限 for (int i = 0; i < aTableInfo.Count; i++) { TableInfo tableInfo = aTableInfo[i]; Debug.Assert(tableInfo.Dup == false, "不可能再有重复的了。"); ResInfoItem resInfoItem = new ResInfoItem(); resInfoItem.Type = 1; resInfoItem.Name = tableInfo.GetCaption(strLang); resInfoItem.HasChildren = false; resInfoItem.TypeString = tableInfo.TypeString; // xietao 2006/6/5 add // 2012/5/16 if (string.IsNullOrEmpty(tableInfo.ExtTypeString) == false) { if (string.IsNullOrEmpty(resInfoItem.TypeString) == false) resInfoItem.TypeString += ","; resInfoItem.TypeString += tableInfo.ExtTypeString; } // 如果需要, 列出所有语言下的名字 if (StringUtil.IsInList("alllang", strStyle) == true) { List<string> results = tableInfo.GetAllLangCaption(); string[] names = new string[results.Count]; results.CopyTo(names); resInfoItem.Names = names; } aItem.Add(resInfoItem); } } // 加__id ResInfoItem resInfoItemID = new ResInfoItem(); resInfoItemID.Type = 1; resInfoItemID.Name = "__id"; resInfoItemID.HasChildren = false; resInfoItemID.TypeString = "recid"; aItem.Add(resInfoItemID); return 0; } finally { //***************对数据库解读锁************ this.m_db_lock.ReleaseReaderLock(); #if DEBUG_LOCK this.container.WriteDebugInfo("Dir(),对'" + this.GetCaption("zh-CN") + "'数据库解读锁。"); #endif } }
// parameters: // strRecordID 记录ID // strObjectID 对象ID // 其它同WriteXml,无strOutputID参数 // return: // -1 出错 // -2 时间戳不匹配 // -4 记录或对象资源不存在 // -6 权限不够 // 0 成功 // 线: 安全的 public virtual int WriteObject(User user, string strRecordID, string strObjectID, string strRanges, long lTotalLength, byte[] baSource, // Stream streamSource, string strMetadata, string strStyle, byte[] intputTimestamp, out byte[] outputTimestamp, out string strError) { outputTimestamp = intputTimestamp; strError = ""; return 0; }
// 写xml数据 // parameter: // strRecordID 记录ID // strRanges 写入的片断范围 // nTotalLength 数据总长度 // sourceBuffer 写入的数据字节数组 // strMetadata 元数据 // intputTimestamp 输入的时间戳 // outputTimestamp out参数,返回的时间戳,出错时,也返回时间戳 // strOutputID out参数,返回的记录ID,追加记录时,有用 // strError out参数,返回出错信息 // return: // return: // -1 出错 // -2 时间戳不匹配 // -4 记录不存在 // -6 权限不够 // 0 成功 // 说明,总长度与源流如果 != null,就写到库里,片断合并后会把新片断记到库里,如果已满,则新片断为空字符串 // 线: 安全的 public virtual int WriteXml(User oUser, string strID, string strXPath, string strRanges, long lTotalLength, byte[] baSource, // Stream streamSource, string strMetadata, string strStyle, byte[] inputTimestamp, out byte[] outputTimestamp, out string strOutputID, out string strOutputValue, bool bCheckAccount, out string strError) { outputTimestamp = null; strOutputID = ""; strOutputValue = ""; strError = ""; return 0; }
// 删除资源,可以是记录 或 配置事项,不支持对象资源或部分记录体 // parameter: // strResPath 资源路径,不能为null或空字符串 // 资源类型可以是数据库配置事项(目录或文件),记录 // 配置事项: 库名/配置事项路径 // 记录: 库名/记录号 // user 当前帐户对象,不能为null // baInputTimestamp 输入的时间戳 // baOutputTimestamp out参数,返回时间戳 // strError out参数,返回出错信息 // return: // -1 一般性错误,例如输入参数不合法等 // -2 时间戳不匹配 // -4 未找到路径对应的资源 // -5 未找到数据库 // -6 没有足够的权限 // -7 路径不合法 // 0 操作成功 // 说明: // 1)删除需要当前帐户对将被删除的记录的有delete权限 // 2)删除记录的明确含义是删除记录体,并且删除该记录包含的所有对象资源 // 3)删除配置目录不要求时间戳,同时baOutputTimestamp也是null public int DeleteRes(string strResPath, User user, byte[] baInputTimestamp, out byte[] baOutputTimestamp, out string strError) { baOutputTimestamp = null; strError = ""; //----------------------------------------- //对输入参数做例行检查 //--------------------------------------- if (strResPath == null || strResPath == "") { strError = "DeleteRes()调用错误,strResPath参数不能为null或空字符串。"; return -1; } if (user == null) { strError = "DeleteRes()调用错误,user参数不能为null。"; return -1; } //----------------------------------------- //开始做事情 //--------------------------------------- //******************加库集合加读锁****** this.m_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK this.WriteDebugInfo("CheckDbsTailNoSafety(),对库集合加读锁。"); #endif try { int nRet = 0; bool bRecordPath = this.IsRecordPath(strResPath); if (bRecordPath == false) { // 也可能是数据库对象 // 删除实际的物理文件 // -1 一般性错误 // -2 时间戳不匹配 // -4 未找到路径对应的资源 // -6 没有足够的权限 // 0 成功 nRet = this.DeleteCfgItem(user, strResPath, baInputTimestamp, out baOutputTimestamp, out strError); if (nRet <= -1) return nRet; } else { string strPath = strResPath; string strDbName = StringUtil.GetFirstPartPath(ref strPath); if (strPath == "") { strError = "资源路径'" + strResPath + "'不合法,未指定库的下级。"; return -7; } // 根据资源类型,写资源 Database db = this.GetDatabase(strDbName); if (db == null) { strError = "没找到名为'" + strDbName + "'的数据库。"; return -5; } string strFirstPart = StringUtil.GetFirstPartPath(ref strPath); //***********吃掉第2层************* // 到此为止,strPath不含cfgs或记录号层了,下级分情况判断 // strFirstPart可能是为cfg或记录号 string strRecordID = strFirstPart; // 检查当前帐户是否有删除记录 string strExistRights = ""; bool bHasRight = user.HasRights(strResPath,//db.GetCaption("zh-cn"), ResType.Record, "delete", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对'" + strDbName + "'数据库没有'删除记录(delete)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } // return: // -1 一般性错误 // -2 时间戳不匹配 // -4 未找到记录 // 0 成功 nRet = db.DeleteRecord(strRecordID, baInputTimestamp, out baOutputTimestamp, out strError); if (nRet <= -1) return nRet; } } finally { m_lock.ReleaseReaderLock(); //*************对库集合解读锁*********** #if DEBUG_LOCK this.WriteDebugInfo("CheckDbsTailNoSafety(),对库集合解读锁。"); #endif } //及时保存database.xml // 是用加锁的函数吗? if (this.Changed == true) this.SaveXmlSafety(); return 0; }
// 删除一个配置事项,可以是目录,也可以是文件 // return: // -1 一般性错误 // -2 时间戳不匹配 // -4 未找到路径对应的资源 // -6 没有足够的权限 // 0 成功 public int DeleteCfgItem(User user, string strCfgItemPath, byte[] intputTimestamp, out byte[] outputTimestamp, out string strError) { outputTimestamp = null; strError = ""; if (strCfgItemPath == null || strCfgItemPath == "") { strError = "DeleteCfgItem()调用错误,strCfgItemPath参数值不能为null或空字符串。"; return -1; } List<XmlNode> nodes = DatabaseUtil.GetNodes(this.NodeDbs, strCfgItemPath); if (nodes.Count == 0) { strError = "服务器不存在路径为'" + strCfgItemPath + "'的配置事项。"; return -4; } if (nodes.Count != 1) { strError = "服务器上路径为'" + strCfgItemPath + "'的配置事项个数为'" + Convert.ToString(nodes.Count) + "',database.xml配置文件异常。"; return -1; } string strExistRights = ""; bool bHasRight = false; XmlNode node = nodes[0]; if (node.Name == "dir") { // 检查当前帐户是否有删除记录' bHasRight = user.HasRights(strCfgItemPath, ResType.Directory, "delete", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对'" + strCfgItemPath + "'配置事项没有'删除(delete)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } string strDir = DatabaseUtil.GetLocalDir(this.NodeDbs, node).Trim(); Directory.Delete(this.DataDir + "\\" + strDir, true); node.ParentNode.RemoveChild(node); return 0; } else if (String.Compare(node.Name, "database", true) == 0) { } // 检查当前帐户是否有删除记录' bHasRight = user.HasRights(strCfgItemPath, ResType.File, "delete", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对'" + strCfgItemPath + "'配置事项没有'删除(delete)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } string strFilePath = "";//GetCfgItemLacalPath(strCfgItemPath); // return: // -1 一般性错误,比如调用错误,参数不合法等 // -2 没找到节点 // -3 localname属性未定义或为值空 // -4 localname在本地不存在 // -5 存在多个节点 // 0 成功 int nRet = this.GetFileCfgItemLacalPath(strCfgItemPath, out strFilePath, out strError); if (nRet != 0) { if (nRet == -1 || nRet == -5) return -1; } if (strFilePath != "") { string strNewFileName = DatabaseUtil.GetNewFileName(strFilePath); if (File.Exists(strFilePath) == true) { byte[] oldTimestamp = null; if (File.Exists(strNewFileName) == true) oldTimestamp = DatabaseUtil.CreateTimestampForCfg(strNewFileName); else oldTimestamp = DatabaseUtil.CreateTimestampForCfg(strFilePath); outputTimestamp = oldTimestamp; if (ByteArray.Compare(oldTimestamp, intputTimestamp) != 0) { strError = "时间戳不匹配"; return -2; } } File.Delete(strNewFileName); File.Delete(strFilePath); string strRangeFileName = DatabaseUtil.GetRangeFileName(strFilePath); if (File.Exists(strRangeFileName) == false) File.Delete(strRangeFileName); string strMetadataFileName = DatabaseUtil.GetMetadataFileName(strFilePath); if (File.Exists(strMetadataFileName) == false) File.Delete(strMetadataFileName); } node.ParentNode.RemoveChild(node); this.Changed = true; this.SaveXml(); return 0; }
// 拷贝一条源记录到目标记录,要求对源记录有读权限,对目标记录有写权限 // 关键点是锁的问题 // Parameter: // user 用户对象 // strOriginRecordPath 源记录路径 // strTargetRecordPath 目标记录路径 // bDeleteOriginRecord 是否删除源记录 // strOutputRecordPath 返回目标记录的路径,用于目标记录是新建一条记录 // baOutputRecordTimestamp 返回目标记录的时间戳 // strError 出错信息 // return: // -1 一般性错误 // -4 未找到记录 // -5 未找到数据库 // -6 没有足够的权限 // -7 路径不合法 // 0 成功 public int CopyRecord(User user, string strOriginRecordPath, string strTargetRecordPath, bool bDeleteOriginRecord, out string strTargetRecordOutputPath, out byte[] baOutputRecordTimestamp, out string strError) { Debug.Assert(user != null, "CopyRecord()调用错误,user对象不能为null。"); this.WriteErrorLog("走到CopyRecord(),strOriginRecordPath='" + strOriginRecordPath + "' strTargetRecordPath='" + strTargetRecordPath + "'"); strTargetRecordOutputPath = ""; baOutputRecordTimestamp = null; strError = ""; if (String.IsNullOrEmpty(strOriginRecordPath) == true) { strError = "CopyRecord()调用错误,strOriginRecordPath参数值不能为nul或空字符串"; return -1; } if (String.IsNullOrEmpty(strTargetRecordPath) == true) { strError = "CopyRecord()调用错误,strTargetRecordPath参数值不能为null或空字符串"; return -1; } long nRet = 0; // 得到源记录的xml string strOriginRecordStyle = "data,metadata,timestamp"; byte[] baOriginRecordData = null; string strOriginRecordMetadata = ""; string strOriginRecordOutputPath = ""; byte[] baOriginRecordOutputTimestamp = null; int nAdditionError = 0; // return: // -1 一般性错误 // -4 未找到路径指定的资源 // -5 未找到数据库 // -6 没有足够的权限 // -7 路径不合法 // -10 未找到记录xpath对应的节点 // 此次调用不可能出现这种情况 // >= 0 成功,返回最大长度 nRet = this.GetRes(strOriginRecordPath, 0, -1, strOriginRecordStyle, user, -1, out baOriginRecordData, out strOriginRecordMetadata, out strOriginRecordOutputPath, out baOriginRecordOutputTimestamp, out nAdditionError, out strError); if (nRet <= -1) return (int)nRet; // 写目标记录xml string strTargetRecordRanges = ""; long lTargetRecordTotalLength = baOriginRecordData.Length; byte[] baTargetRecordData = baOriginRecordData; string strTargetRecordMetadata = strOriginRecordMetadata; string strTargetRecordStyle = "ignorechecktimestamp"; byte[] baTargetRecordOutputTimestamp = null; string strTargetRecordOutputValue = ""; // return: // -1 一般性错误 // -2 时间戳不匹配 // 此处调用不可能出现这种情况 // -4 未找到路径指定的资源 // -5 未找到数据库 // -6 没有足够的权限 // -7 路径不合法 // -8 已经存在同名同类型的项 // 此处调用不可能出现这种情况 // -9 已经存在同名但不同类型的项 // 此处调用不可能出现这种情况 // 0 成功 nRet = this.WriteRes(strTargetRecordPath, strTargetRecordRanges, lTargetRecordTotalLength, baTargetRecordData, null, //streamSource strTargetRecordMetadata, strTargetRecordStyle, null, //baInputTimestamp user, out strTargetRecordOutputPath, out baTargetRecordOutputTimestamp, out strTargetRecordOutputValue, out strError); if (nRet <= -1) return (int)nRet; // 处理资源 byte[] baPreamble; string strXml = DatabaseUtil.ByteArrayToString(baOriginRecordData, out baPreamble); XmlDocument dom = new XmlDocument(); dom.PreserveWhitespace = true; //设PreserveWhitespace为true try { dom.LoadXml(strXml); } catch (Exception ex) { strError = "加载'" + strOriginRecordPath + "'的记录体到dom出错,原因:" + ex.Message; return -1; } XmlNamespaceManager nsmgr = new XmlNamespaceManager(dom.NameTable); nsmgr.AddNamespace("dprms", DpNs.dprms); XmlNodeList fileList = dom.DocumentElement.SelectNodes("//dprms:file", nsmgr); foreach (XmlNode fileNode in fileList) { // 获取源资源对象 string strObjectID = DomUtil.GetAttr(fileNode, "id"); string strOriginObjectPath = strOriginRecordPath + "/object/" + strObjectID; byte[] baOriginObjectData = null; string strOriginObjectMetadata = ""; string strOriginObjectOutputPath = ""; byte[] baOriginObjectOutputTimestamp = null; this.WriteErrorLog("走到CopyRecord(),获取资源,源路径='" + strOriginObjectPath + "'"); // int nAdditionError = 0; // return: // -1 一般性错误 // -4 未找到路径指定的资源 // -5 未找到数据库 // -6 没有足够的权限 // -7 路径不合法 // -10 未找到记录xpath对应的节点 // >= 0 成功,返回最大长度 nRet = this.GetRes(strOriginObjectPath, 0, -1, "data,metadata", user, -1, out baOriginObjectData, out strOriginObjectMetadata, out strOriginObjectOutputPath, out baOriginObjectOutputTimestamp, out nAdditionError, out strError); if (nRet <= -1) return (int)nRet; // 写目标资源对象 string strTargetObjectPath = strTargetRecordOutputPath + "/object/" + strObjectID; long lTargetObjectTotalLength = baOriginObjectData.Length; string strTargetObjectMetadata = strOriginObjectMetadata; string strTargetObjectStyle = "ignorechecktimestamp"; string strTargetObjectOutputPath = ""; byte[] baTargetObjectOutputTimestamp = null; string strTargetObjectOutputValue = ""; //this.WriteErrorLog("走到CopyRecord(),写资源,目标路径='" + strTargetObjectPath + "'"); // return: // -1 一般性错误 // -2 时间戳不匹配 // -4 未找到路径指定的资源 // -5 未找到数据库 // -6 没有足够的权限 // -7 路径不合法 // -8 已经存在同名同类型的项 // -9 已经存在同名但不同类型的项 // 0 成功 nRet = this.WriteRes(strTargetObjectPath, "", lTargetObjectTotalLength, baOriginObjectData, null, strTargetObjectMetadata, strTargetObjectStyle, null, user, out strTargetObjectOutputPath, out baTargetObjectOutputTimestamp, out strTargetObjectOutputValue, out strError); if (nRet <= -1) return (int)nRet; } // 判断是否删除源记录 if (bDeleteOriginRecord == true) { // return: // -1 一般性错误,例如输入参数不合法等 // -2 时间戳不匹配 // 建议忽略时间戳,不应出现这种情况 // -4 未找到路径对应的资源 // -5 未找到数据库 // -6 没有足够的权限 // -7 路径不合法 // 0 操作成功 nRet = this.DeleteRes(strOriginRecordPath, user, baOriginRecordOutputTimestamp, out baOriginRecordOutputTimestamp, out strError); if (nRet <= -1) return (int)nRet; } // 取出目标记录的最终时间戳 // return: // -1 出错 // -4 未找到记录 // 0 成功 nRet = this.GetTimestampFromDb( strTargetRecordOutputPath, out baOutputRecordTimestamp, out strError); if (nRet <= -1) { strError = "拷贝记录完成,但获取目标记录的时间戳时出错:" + strError; return -1; } return 0; }
// 得到某一指定路径strPath的可以显示的下级 // parameters: // oUser 当前帐户 // db 当前数据库 // strPath 配置事项的路径 // strLang 语言版本 // aItem out参数,返回可以显示的下级 // strError out参数,出错信息 // return: // -1 出错 // 0 成功 private int DirCfgItem(User user, string strCfgItemPath, out ArrayList aItem, out string strError) { strError = ""; aItem = new ArrayList(); if (this.NodeDbs == null) { strError = "服务器配置文件未定义<dbs>元素"; return -1; } List<XmlNode> list = DatabaseUtil.GetNodes(this.NodeDbs, strCfgItemPath); if (list.Count == 0) { strError = "未找到路径为'" + strCfgItemPath + "'对应的事项。"; return -1; } if (list.Count > 1) { strError = "服务器端总配置文件不合法,检查到路径为'" + strCfgItemPath + "'对应的节点有'" + Convert.ToString(list.Count) + "'个,有且只能有一个。"; return -1; } XmlNode node = list[0]; for (int i = 0; i < node.ChildNodes.Count; i++) { XmlNode child = node.ChildNodes[i]; string strChildName = DomUtil.GetAttr(child, "name"); if (strChildName == "") continue; string strTempPath = strCfgItemPath + "/" + strChildName; string strExistRights; bool bHasRight = false; ResInfoItem resInfoItem = new ResInfoItem(); resInfoItem.Name = strChildName; if (child.Name == "dir") { bHasRight = user.HasRights(strTempPath, ResType.Directory, "list", out strExistRights); if (bHasRight == false) continue; resInfoItem.HasChildren = true; resInfoItem.Type = 4; resInfoItem.TypeString = DomUtil.GetAttr(child, "type"); // xietao 2006/6/5 add } else { bHasRight = user.HasRights(strTempPath, ResType.File, "list", out strExistRights); if (bHasRight == false) continue; resInfoItem.HasChildren = false; resInfoItem.Type = 5; resInfoItem.TypeString = DomUtil.GetAttr(child, "type"); // xietao 2006/6/5 add } aItem.Add(resInfoItem); } return 0; }
// 写资源 // parameter: // strResPath 资源路径,不能为null或空字符串 // 资源类型可以是数据库配置事项(目录或文件),记录体,对象资源,部分记录体 // 配置事项: 库名/配置事项路径 // 记录体: 库名/记录号 // 对象资源: 库名/记录号/object/资源ID // 部分记录体: 库名/记录/xpath/<locate>hitcount</locate><action>AddInteger</action> 或者 库名/记录/xpath/@hitcount // strRanges 目标的位置,多个range用逗号分隔,null认为是空字符串,空字符串认为是0-(lTotalLength-1) // lTotalLength 资源总长度,可以为0 // baContent 用byte[]数据传送的资源内容,如果为null则表示是0字节的数组 // streamContent 内容流 // strMetadata 元数据内容,null认为是空字符串,注:有些元数据虽然传过来,但服务器不认,比如长度 // strStyle 风格,null认为是空字符串 // ignorechecktimestamp 忽略时间戳; // createdir,创建目录,路径表示待创建的目录路径 // autocreatedir 自动创建中间层的目录 // content 数据放在baContent参数里 // attachment 数据放在附件里 // baInputTimestamp 输入的时间戳,对于创建目录,不检查时间戳 // user 帐户对象,不能为null // strOutputResPath 返回的资源路径 // 比如追加记录时,返回实际的路径 // 其它资源返回的路径与输入的路径相同 // baOutputTimestamp 返回时间戳 // 当为目录时,返回的时间戳为null // strOutputValue 返回的值,比如做累加计算时 // strError 出错信息 // 说明: // 本函数实际代表了两种情况,新建资源,覆盖资源 // baContent,strAttachmentID只能使用一个,与strStyle配置使用 // return: // -1 一般性错误 // -2 时间戳不匹配 // -4 未找到路径指定的资源 // -5 未找到数据库 // -6 没有足够的权限 // -7 路径不合法 // -8 已经存在同名同类型的项 // -9 已经存在同名但不同类型的项 // 0 成功 // 线:安全 public int WriteRes(string strResPath, string strRanges, long lTotalLength, byte[] baSource, Stream streamSource, string strMetadata, string strStyle, byte[] baInputTimestamp, User user, out string strOutputResPath, out byte[] baOutputTimestamp, out string strOutputValue, out string strError) { baOutputTimestamp = null; strOutputResPath = strResPath; strOutputValue = ""; strError = ""; //**********对库集合加写锁**************** m_lock.AcquireWriterLock(m_nTimeOut); #if DEBUG_LOCK this.WriteDebugInfo("WriteRes(),对库集合加写锁。"); #endif try { //------------------------------------------------ //检查输入参数是否合法,并规范输入参数 //--------------------------------------------------- if (user == null) { strError = "WriteRes()调用错误,user对象不能为null"; return -1; } if (String.IsNullOrEmpty(strResPath) == true) { strError = "资源路径'" + strResPath + "'不合法,不能为null或空字符串。"; return -7; } if (lTotalLength < 0) { strError = "WriteRes(),lTotalLength不能为'" + Convert.ToString(lTotalLength) + "',必须>=0。"; return -1; } if (strRanges == null) //里面的函数,会处理成代表的范围 strRanges = ""; if (strMetadata == null) strMetadata = ""; if (strStyle == null) strStyle = ""; if (baSource == null && streamSource == null) { strError = "WriteRes()调用错误,baSource参数与streamSource参数不能同时为null。"; return -1; } if (baSource != null && streamSource != null) { strError = "WriteRes()调用错误,baSource参数与streamSource参数只能有一个被赋值。"; return -1; } //------------------------------------------------ //分析出资源的类型 //--------------------------------------------------- int nRet = 0; bool bRecordPath = this.IsRecordPath(strResPath); if (bRecordPath == false) { // 关于配置目录 if (StringUtil.IsInList("createdir", strStyle, true) == true) { // return: // -1 一般性错误 // -4 未指定路径对应的对象 // -6 权限不够 // -8 目录已存在 // -9 存在其它类型的事项 // 0 成功 nRet = this.WriteDirCfgItem(strResPath, strStyle, user, out strError); } else { // return: // -1 一般性错误 // -2 时间戳不匹配 // -4 自动创建目录时,未找到上级 // -6 权限不够 // -9 存在其它类型的事项 // 0 成功 nRet = this.WriteFileCfgItem(strResPath, strRanges, lTotalLength, baSource, streamSource, strMetadata, strStyle, baInputTimestamp, user, out baOutputTimestamp, out strError); } strOutputResPath = strResPath; // 保存database.xml文件 if (this.Changed == true) this.SaveXmlSafety(); } else { bool bObject = false; string strRecordID = ""; string strObjectID = ""; string strXPath = ""; string strPath = strResPath; string strDbName = StringUtil.GetFirstPartPath(ref strPath); //***********吃掉第1层************* // 到此为止,strPath不含数据库名了,下面的路径有两种情况:cfgs;其余都被当作记录id if (strPath == "") { strError = "资源路径'" + strResPath + "'路径不合法,未指定库的下级。"; return -7; } // 找到数据库对象 Database db = this.GetDatabaseSafety(strDbName); if (db == null) { strError = "名'" + strDbName + "'的数据库不存在。"; return -5; } string strFirstPart = StringUtil.GetFirstPartPath(ref strPath); //***********吃掉第2层************* // 到此为止,strPath不含记录号层了,下级分情况判断 strRecordID = strFirstPart; // 只到记录号层的路径 if (strPath == "") { bObject = false; goto DOWRITE; } strFirstPart = StringUtil.GetFirstPartPath(ref strPath); //***********吃掉第2层************* // 到此为止,strPath不含object或xpath层 strFirstPart可能是object 或 xpath if (strFirstPart != "object" && strFirstPart != "xpath") { strError = "资源路径 '" + strResPath + "' 不合法,第3级必须是'object'或'xpath'"; return -7; } if (strPath == "") //object或xpath下级必须有值 { strError = "资源路径 '" + strResPath + "' 不合法,当第3级是'object'或'xpath',第4级必须有内容。"; return -7; } if (strFirstPart == "object") { strObjectID = strPath; bObject = true; } else { strXPath = strPath; bObject = false; } //------------------------------------------------ //开始处理资源 //--------------------------------------------------- DOWRITE: // **************************************** string strOutputRecordID = ""; nRet = db.CanonicalizeRecordID(strRecordID, out strOutputRecordID, out strError); if (nRet == -1) { strError = "资源路径 '" + strResPath + "' 不合法,原因:记录号不能为'" + strRecordID + "'"; return -1; } // ************************************ // 处理记录和记录里的对象 if (bObject == true) //对像 { if (strOutputRecordID == "-1") { strError = "资源路径 '" + strResPath + "' 不合法,原因:保存对象资源时,记录号不能为'" + strRecordID + "'。"; return -1; } strRecordID = strOutputRecordID; // return: // -1 出错 // -2 时间戳不匹配 // -4 记录或对象资源不存在 // -6 权限不够 // 0 成功 nRet = db.WriteObject(user, strRecordID, strObjectID, strRanges, lTotalLength, baSource, streamSource, strMetadata, strStyle, baInputTimestamp, out baOutputTimestamp, out strError); strOutputResPath = strDbName + "/" + strRecordID + "/object/" + strObjectID; } else // 记录体 { strRecordID = strOutputRecordID; string strOutputID = ""; // return: // -1 出错 // -2 时间戳不匹配 // -4 记录不存在 // -6 权限不够 // 0 成功 nRet = db.WriteXml(user, strRecordID, strXPath, strRanges, lTotalLength, baSource, streamSource, strMetadata, strStyle, baInputTimestamp, out baOutputTimestamp, out strOutputID, out strOutputValue, true, out strError); strRecordID = strOutputID; if (strXPath == "") strOutputResPath = strDbName + "/" + strRecordID; else strOutputResPath = strDbName + "/" + strRecordID + "/xpath/" + strXPath; } } return nRet; } finally { //**********对库集合解写锁**************** m_lock.ReleaseWriterLock(); #if DEBUG_LOCK this.WriteDebugInfo("WriteRes(),对库集合写写锁。"); #endif } }
// 根据用户名从库中查找用户记录,得到用户对象 // 对象尚未进入集合, 因此无需为对象加锁 // parameters: // strBelongDb 用户从属的数据库,中文名称 // user out参数,返回帐户对象 // strError out参数,返回出错信息 // return: // -1 出错 // 0 未找到帐户 // 1 找到了 // 线:安全 internal int ShearchUser(string strUserName, out User user, out string strError) { user = null; strError = ""; int nRet = 0; DpResultSet resultSet = new DpResultSet(); //*********对帐户库集合加读锁*********** m_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK this.WriteDebugInfo("ShearchUser(),对帐户库集合加读锁。"); #endif try { // return: // -1 出错 // 0 成功 nRet = this.SearchUserInternal(strUserName, resultSet, out strError); if (nRet == -1) return -1; } finally { //*********对帐户库集合解读锁************* m_lock.ReleaseReaderLock(); #if DEBUG_LOCK this.m_dbColl.WriteDebugInfo("ShearchUser(),对帐户库集合解读锁。"); #endif } // 根据用户名没找到对应的帐户记录 long lCount = resultSet.Count; if (lCount == 0) return 0; if (lCount > 1) { strError = "用户名'" + strUserName + "'对应多条记录"; return -1; } // 按第一个帐户算 DpRecord record = (DpRecord)resultSet[0]; // 创建一个DpPsth实例 DbPath path = new DbPath(record.ID); // 找到指定帐户数据库 Database db = this.GetDatabaseSafety(path.Name); if (db == null) { strError = "未找到'" + strUserName + "'帐户对应的名为'" + path.Name + "'的数据库对象"; return -1; } // 从帐户库中找到记录 string strXml = ""; // return: // -1 出错 // -4 记录不存在 // 0 正确 nRet = db.GetXmlDataSafety(path.ID, out strXml, out strError); if (nRet <= -1) // 将-4与-1都作为-1返回 return -1; //加载到dom XmlDocument dom = new XmlDocument(); //dom.PreserveWhitespace = true; //设PreserveWhitespace为true try { dom.LoadXml(strXml); } catch (Exception ex) { strError = "加载用户 '" + strUserName + "' 的帐户记录到dom时出错,原因:" + ex.Message; return -1; } user = new User(); // return: // -1 出错 // 0 成功 nRet = user.Initial( record.ID, dom, db, this, out strError); if (nRet == -1) return -1; return 1; }
// 写目录配置事项 // parameters: // strResPath 资源路径带库名 // 原来是没有这个参数,为什么加上呢? // 是为报错时忠于原路径。如果为null或空字符串,则改为:库名路径/strCfgItemPath // strStyle 风格 null认为是空字符串 // clear 表示清除下级 // autocreatedir 表示自动创建缺省的目录 // user User对象,用来判断是否有权限,不能为null // strCfgItemPath 配置事项路径,不带库名,不能为null或空字符串。???可以与strResPath一起用,但易乱 // strError out参数,返回出错信息 // return: // -1 一般性错误 // -4 未指定路径对应的对象 // -6 权限不够 // -8 目录已存在 // -9 存在其它类型的事项 // 0 成功 // 线:不安全 public int WriteDirCfgItem(string strCfgItemPath, string strStyle, User user, out string strError) { strError = ""; int nRet = 0; if (String.IsNullOrEmpty(strCfgItemPath) == true) { strError = "WriteDirCfgItem()调入错误,strCfgItemPath不能为null或空字符串。"; return -1; } List<XmlNode> list = DatabaseUtil.GetNodes(this.NodeDbs, strCfgItemPath); if (list.Count > 1) { strError = "服务器总配置文件不合法,路径为'" + strCfgItemPath + "'的配置事项对应的节点有'" + Convert.ToString(list.Count) + "'个。"; return -1; } string strExistRights = ""; bool bHasRight = false; // 已存在同名配置事项的情况 if (list.Count == 1) { XmlNode node = list[0]; if (node.Name == "file") { strError = "服务器已存在路径为'" + strCfgItemPath + "'的配置文件,不能用目录覆盖文件。"; return -9; } if (node.Name == "database") { strError = "服务器已存在名为'" + strCfgItemPath + "'的数据库,不能用目录覆盖数据库。"; return -9; } if (StringUtil.IsInList("clear", strStyle) == true) { // 如果配置事项已存在,则检索是否有clear权限 string strPathForRights = strCfgItemPath; bHasRight = user.HasRights(strPathForRights, ResType.Directory, "clear", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对路径为'" + strCfgItemPath + "'的配置事项没有'清空下级(clear)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } // 清空目录 // return: // -1 出错 // -4 未指定路径对应的对象 // 0 成功 return this.ClearDirCfgItem(strCfgItemPath, node, out strError); } else { strError = "服务器已存在路径为'" + strCfgItemPath + "'的配置目录。"; return -8; } } //*************************************** bHasRight = user.HasRights(strCfgItemPath, ResType.Directory, "create", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对路径为'" + strCfgItemPath + "'的配置事项没有'清空下级(clear)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } // return: // -1 出错 // 0 成功 nRet = this.AutoCreateDirCfgItem(strCfgItemPath, out strError); if (nRet == -1) return -1; return 0; }
// 获得数据定义方面的信息 // parameters: // strStyle 获得那些输出参数? all表示全部 分别指定则是logicnames/type/sqldbname/keystext/browsetext // return: // -1 一般性错误 // -5 未找到数据库对象 // -6 没有足够的权限 // 0 成功 public int GetDbInfo(User user, string strDbName, string strStyle, out LogicNameItem[] logicNames, out string strType, out string strSqlDbName, out string strKeysText, out string strBrowseText, out string strError) { strError = ""; logicNames = null; strType = ""; strSqlDbName = ""; strKeysText = ""; strBrowseText = ""; Debug.Assert(user != null, "GetDbInfo()调用错误,user参数不能为null。"); if (String.IsNullOrEmpty(strDbName) == true) { strError = "GetDbInfo()调用不合法,strDbName参数值不能为null或空字符串。"; return -1; } // 检查当前帐户是否有显示权限 string strExistRights = ""; bool bHasRight = user.HasRights(strDbName, ResType.Database, "read", out strExistRights); //******************对库集合加读锁****** this.m_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK this.WriteDebugInfo("GetDbInfo(),对库集合加读锁。"); #endif try { Database db = this.GetDatabase(strDbName); if (db == null) { strError = "未找到名为'" + strDbName + "'的数据库。"; return -5; } if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对'" + strDbName + "'数据库没有'读(read)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } // return: // -1 出错 // 0 正常 return db.GetInfo( strStyle, out logicNames, out strType, out strSqlDbName, out strKeysText, out strBrowseText, out strError); } finally { this.m_lock.ReleaseReaderLock(); //*****************对库集合解读锁************* #if DEBUG_LOCK this.WriteDebugInfo("GetDbInfo(),对库集合解读锁。"); #endif } }
// 写文件配置事项 // return: // -1 一般性错误 // -2 时间戳不匹配 // -4 自动创建目录时,未找到上级 // -6 权限不够 // -9 存在其它类型的事项 // 0 成功 // 线程,不安全的 internal int WriteFileCfgItem(string strCfgItemPath, string strRanges, long lTotalLength, byte[] baSource, Stream streamSource, string strMetadata, string strStyle, byte[] baInputTimestamp, User user, out byte[] baOutputTimestamp, out string strError) { baOutputTimestamp = null; strError = ""; int nRet = 0; Debug.Assert(user != null, "WriteFileCfgItem()调用错误,user对象不能为null"); //------------------------------------------------ // 检查输入参数,并规范化输入参数 //-------------------------------------------------- if (lTotalLength <= -1) { strError = "WriteFileCfgItem()调用错误,lTotalLength值为'" + Convert.ToString(lTotalLength) + "'不合法,必须大于等于0。"; return -1; } if (strStyle == null) strStyle = ""; if (strRanges == null) strRanges = null; if (strMetadata == null) strMetadata = ""; if (baSource == null && streamSource == null) { strError = "WriteFileCfgItem()调用错误,baSource参数与streamSource参数不能同时为null。"; return -1; } if (baSource != null && streamSource != null) { strError = "WriteFileCfgItem()调用错误,baSource参数与streamSource参数只能有一个被赋值。"; return -1; } if (strCfgItemPath == null || strCfgItemPath == "") { strError = "WriteFileCfgItem()调用错误,strResPath不能为null或空字符串。"; return -1; } //------------------------------------------------ // 开始做事情 //-------------------------------------------------- List<XmlNode> list = DatabaseUtil.GetNodes(this.NodeDbs, strCfgItemPath); if (list.Count > 1) { strError = "服务器总配置文件不合法,路径为'" + strCfgItemPath + "'的配置事项对应的节点有'" + Convert.ToString(list.Count) + "'个。"; return -1; } string strExistRights = ""; bool bHasRight = false; //------------------------------------------------ // 已存在同名配置事项的情况 //-------------------------------------------------- if (list.Count == 1) { XmlNode node = list[0]; if (node.Name == "dir") { strError = "服务器已存在路径为'" + strCfgItemPath + "'的配置目录,不能用文件覆盖目录。"; return -9; } if (node.Name == "database") { strError = "服务器已存在名为'" + strCfgItemPath + "'的数据库,不能用文件覆盖数据库。"; return -9; } // 如果配置事项已存在,则检索是否有overwrite权限 string strPathForRights = strCfgItemPath; bHasRight = user.HasRights(strPathForRights, ResType.File, "overwrite", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对路径为'" + strCfgItemPath + "'的配置事项没有'覆盖(overwrite)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } // 如果按正规的渠道创建配置文件, // 则内存对象中已存在,那么物理文件名一定存在,则物理文件一定存在 string strLocalPath = ""; // return: // -1 一般性错误,比如调用错误,参数不合法等 // -2 没找到节点 // -3 localname属性未定义或为值空 // -4 localname在本地不存在 // -5 存在多个节点 // 0 成功 nRet = this.GetFileCfgItemLacalPath(strCfgItemPath, out strLocalPath, out strError); if (nRet != 0) { if (nRet != -4) return -1; } goto DOWRITE; } //------------------------------------------------ // 不存在配置事项的情况 //-------------------------------------------------- string strParentCfgItemPath = ""; //父亲的路径 string strThisCfgItemName = ""; //本配置事项的名称 int nIndex = strCfgItemPath.LastIndexOf('/'); if (nIndex != -1) { strParentCfgItemPath = strCfgItemPath.Substring(0, nIndex); strThisCfgItemName = strCfgItemPath.Substring(nIndex + 1); } else { strThisCfgItemName = strCfgItemPath; } XmlNode nodeParent = null; // 对上级路径进行检查 if (strParentCfgItemPath != "") { List<XmlNode> parentNodes = DatabaseUtil.GetNodes(this.NodeDbs, strParentCfgItemPath); if (parentNodes.Count > 1) { nIndex = strCfgItemPath.LastIndexOf("/"); string strTempParentPath = strCfgItemPath.Substring(0, nIndex); strError = "服务器端路径为'" + strTempParentPath + "'的配置事项有'" + Convert.ToString(parentNodes.Count) + "'个,配置文件不合法。"; return -1; } if (parentNodes.Count == 1) { nodeParent = parentNodes[0]; } else { if (StringUtil.IsInList("autocreatedir", strStyle, true) == false) { nIndex = strCfgItemPath.LastIndexOf("/"); string strTempParentPath = strCfgItemPath.Substring(0, nIndex); strError = "未找到路径为'" + strTempParentPath + "'配置事项,无法创建下级文件。"; return -4; } // return: // -1 出错 // 0 成功 nRet = this.AutoCreateDirCfgItem(strParentCfgItemPath, out strError); if (nRet == -1) return -1; parentNodes = DatabaseUtil.GetNodes(this.NodeDbs, strParentCfgItemPath); if (parentNodes.Count != 1) { strError = "WriteFileCfgItem(),自动创建好上级目录了,此时不可能找不到路径为'" + strParentCfgItemPath + "'的配置事项了。"; return -1; } nodeParent = parentNodes[0]; } } else { nodeParent = this.NodeDbs; } // 检查上级是否有指定权限 bHasRight = user.HasRights(strCfgItemPath, ResType.File, "create", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对'" + strCfgItemPath + "',没有'创建(create)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } // return: // -1 出错 // 0 成功 nRet = this.SetFileCfgItem(strParentCfgItemPath, nodeParent, strThisCfgItemName, out strError); if (nRet == -1) return -1; DOWRITE: string strFilePath = "";//GetCfgItemLacalPath(strCfgItemPath); // return: // -1 一般性错误,比如调用错误,参数不合法等 // -2 没找到节点 // -3 localname属性未定义或为值空 // -4 localname在本地不存在 // -5 存在多个节点 // 0 成功 nRet = this.GetFileCfgItemLacalPath(strCfgItemPath, out strFilePath, out strError); if (nRet != 0) { if (nRet != -4) return -1; } string strTempPath = strCfgItemPath; string strFirstPart = StringUtil.GetFirstPartPath(ref strTempPath); Database db = this.GetDatabase(strFirstPart); if (db != null) { // return: // -1 一般性错误 // -2 时间戳不匹配 // 0 成功 return db.WriteFileForCfgItem(strCfgItemPath, strFilePath, strRanges, lTotalLength, baSource, streamSource, strMetadata, strStyle, baInputTimestamp, out baOutputTimestamp, out strError); } else { // 不从属于某一个数据库的配置文件 // return: // -1 一般性错误 // -2 时间戳不匹配 // 0 成功 return this.WriteFileForCfgItem(strFilePath, strRanges, lTotalLength, baSource, streamSource, strMetadata, strStyle, baInputTimestamp, out baOutputTimestamp, out strError); } }
// 写xml数据 // parameter: // strID 记录ID -1:表示追加一条记录 // strRanges 目标的位置,多个range用逗号分隔 // nTotalLength 总长度 // inputTimestamp 输入的时间戳 // outputTimestamp out参数,返回的时间戳 // strOutputID out参数,返回的记录ID,当strID == -1时,得到实际的ID // strError out参数,返回出错信息 // return: // return: // -1 出错 // -2 时间戳不匹配 // -4 记录不存在 // -6 权限不够 // 0 成功 // ??? AddInteger+,+AddInteger,Push好像没有实现 public override int WriteXml(User oUser, string strID, string strXPath, string strRanges, long lTotalLength, byte[] baSource, // Stream streamSource, string strMetadata, string strStyle, byte[] inputTimestamp, out byte[] outputTimestamp, out string strOutputID, out string strOutputValue, bool bCheckAccount, out string strError) { outputTimestamp = null; strOutputID = ""; strOutputValue = ""; strError = ""; if (strID == "?") strID = "-1"; // 确保ID,并且给返回值赋值 bool bPushTailNo = false; bPushTailNo = this.EnsureID(ref strID); if (oUser != null) { string strTempRecordPath = this.GetCaption("zh-CN") + "/" + strID; if (bPushTailNo == true) { string strExistRights = ""; bool bHasRight = oUser.HasRights(strTempRecordPath, ResType.Record, "create", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + oUser.Name + "',对'" + strTempRecordPath + "'记录没有'创建(create)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } } else { string strExistRights = ""; bool bHasRight = oUser.HasRights(strTempRecordPath, ResType.Record, "overwrite", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + oUser.Name + "',对'" + strTempRecordPath + "'记录没有'覆盖(overwrite)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } } } strOutputID = DbPath.GetCompressedID(strID); int nRet; int nFull = -1; //***********对数据库加读锁*********** m_db_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK this.container.WriteDebugInfo("WriteXml(),对'" + this.GetCaption("zh-CN") + "'数据库加读锁。"); #endif try { strID = DbPath.GetID10(strID); //**********对记录加写锁*************** m_recordLockColl.LockForWrite(strID, m_nTimeOut); #if DEBUG_LOCK this.container.WriteDebugInfo("WriteXml(),对'" + this.GetCaption("zh-CN") + "/" + strID + "'记录加写锁。"); #endif try { string strXmlFilePath = this.GetXmlFilePath(strID); bool bExist = File.Exists(strXmlFilePath); if (bExist == false) { //创建新文件,并把辅助信息创建好 this.InsertRecord(strID, strStyle, inputTimestamp, out inputTimestamp); // 创建后存在一个字节,所有信息都有了 } nRet = this.WriteFileDbTempRecord(strXmlFilePath, strRanges, lTotalLength, baSource, // streamSource, strMetadata, strStyle, inputTimestamp, out outputTimestamp, out nFull, out strError); if (nRet <= -1) return nRet; if (nFull == 1) // 文件已满 { // 1.得到新旧检索点 string strNewFileName = DatabaseUtil.GetNewFileName(strXmlFilePath); string strNewXml = FileUtil.File2StringE(strNewFileName); string strOldXml = FileUtil.File2StringE(strXmlFilePath); if (strXPath != null && strXPath != "") { string strLocateXPath = ""; string strCreatePath = ""; string strNewRecordTemplate = ""; string strAction = ""; nRet = DatabaseUtil.ParseXPathParameter(strXPath, out strLocateXPath, out strCreatePath, out strNewRecordTemplate, out strAction, out strError); if (nRet == -1) return -1; XmlDocument tempDom = new XmlDocument(); tempDom.PreserveWhitespace = true; //设PreserveWhitespace为true try { if (strOldXml == "") { if (strNewRecordTemplate == "") tempDom.LoadXml("<root/>"); else tempDom.LoadXml(strNewRecordTemplate); } else tempDom.LoadXml(strOldXml); } catch (Exception ex) { strError = "WriteXml() 在给'" + this.GetCaption("zh-CN") + "'库写入记录'" + strID + "'时,装载旧记录到dom出错,原因:" + ex.Message; return -1; } if (strLocateXPath == "") { strError = "xpath表达式中的locate参数不能为空值"; return -1; } // 通过strLocateXPath定位到指定的节点 XmlNode node = null; try { node = tempDom.DocumentElement.SelectSingleNode(strLocateXPath); } catch (Exception ex) { strError = "WriteXml() 在给'" + this.GetCaption("zh-CN") + "'库写入记录'" + strID + "'时,XPath式子'" + strXPath + "'选择元素时出错,原因:" + ex.Message; return -1; } if (node == null) { if (strLocateXPath == "") { strError = "xpath表达式中的create参数不能为空值"; return -1; } node = DomUtil.CreateNodeByPath(tempDom.DocumentElement, strCreatePath); if (node == null) { strError = "内部错误!"; return -1; } } //Create a document fragment. XmlDocumentFragment docFrag = tempDom.CreateDocumentFragment(); //Set the contents of the document fragment. docFrag.InnerXml = strNewXml; //Add the children of the document fragment to the //original document. node.ParentNode.InsertBefore(docFrag, node); if (strAction == "AddInteger" || strAction == "AppendString") { XmlNode newNode = node.PreviousSibling; if (newNode == null) { strError = "newNode不可能为null"; return -1; } string strNewValue = newNode.InnerText; string strOldValue = node.InnerText.Trim(); // 2012/2/16 if (strAction == "AddInteger") { int nNumber = 0; try { nNumber = Convert.ToInt32(strNewValue); } catch (Exception ex) { strError = "传入的内容'" + strNewXml + "'不是数字格式。" + ex.Message; return -1; } string strLastValue; nRet = StringUtil.IncreaseNumber(strOldValue, nNumber, out strLastValue, out strError); if (nRet == -1) return -1; newNode.InnerText = strLastValue; strOutputValue = newNode.OuterXml; } else if (strAction == "AppendString") { newNode.InnerText = strOldValue + strNewValue; strOutputValue = newNode.OuterXml; } } node.ParentNode.RemoveChild(node); strNewXml = tempDom.OuterXml; } KeyCollection newKeys = null; KeyCollection oldKeys = null; XmlDocument newDom = null; XmlDocument oldDom = null; // return: // -1 出错 // 0 成功 nRet = this.MergeKeys(strID, strNewXml, strOldXml, true, out newKeys, out oldKeys, out newDom, out oldDom, out strError); if (nRet == -1) return -1; this.AddKeys(newKeys); this.DeleteKeys(oldKeys); // 3.处理子文件 nRet = this.ProcessFiles(strID, newDom, oldDom, out strError); if (nRet <= -1) return nRet; // 4.用newdata替换data // 先把xml数据更新了,再更新检索点 if (strXPath != null && strXPath != "") { FileUtil.String2File(strNewXml, strXmlFilePath); } else { File.Copy(strNewFileName, strXmlFilePath, true); } // 5.删除newdata字段 File.Delete(strNewFileName); } } catch (Exception ex) { strError = "WriteXml() 在给'" + this.GetCaption("zh-CN") + "'库写入记录'" + strID + "'时出错,原因:" + ex.Message; return -1; } finally { //*********对记录解写锁**************************** m_recordLockColl.UnlockForWrite(strID); #if DEBUG_LOCK this.container.WriteDebugInfo("WriteXml(),对'" + this.GetCaption("zh-CN") + "/" + strID + "'记录解写锁。"); #endif } } finally { //**********对数据库解读锁************** m_db_lock.ReleaseReaderLock(); #if DEBUG_LOCK this.container.WriteDebugInfo("WriteXml(),对'" + this.GetCaption("zh-CN") + "'数据库解读锁。"); #endif } // 当本函数被明知为账户库的写操作调用时, 一定要用bCheckAccount==false // 来调用,否则容易引起不必要的递归 if (nFull == 1 && bCheckAccount == true && StringUtil.IsInList("account", this.TypeSafety) == true) { string strResPath = this.FullID + "/" + strID; this.container.UserColl.RefreshUserSafety( strResPath); } return 0; }
// GetRes()用range不太好实现,因为原来当请求的长度超过允许的长度时,长度会自动为截取 // 而如果用range来表示,则不知该截短哪部分好。 // parameter: // strResPath 资源路径,不能为null或空字符串 // 资源类型可以是数据库配置事项(目录或文件),记录体,对象资源,部分记录体 // 配置事项: 库名/配置事项路径 // 记录体: 库名/记录号 // 对象资源: 库名/记录号/object/资源ID // 部分记录体: 库名/记录/xpath/<locate>hitcount</locate><action>AddInteger</action> 或者 库名/记录/xpath/@hitcount // lStart 起始长度 // lLength 总长度,-1:从start到最后 // strStyle 取资源的风格,以逗豆间隔的字符串 /* strStyle用法 1.控制数据存放的位置 content 把返回的数据放到字节数组参数里 attachment 把返回的数据放到附件中,并返回附件的id 2.控制返回的数据 metadata 返回metadata信息 timestamp 返回timestamp length 数据总长度,始终都有值 data 返回数据体 respath 返回记录路径,目前始终都有值 all 返回所有值 3.控制记录号 prev 前一条 prev,self 自己或前一条 next 下一条 next,self 自己或下一条 放到strOutputResPath参数里 */ // baContent 用content字节数组返回资源内容 // strAttachmentID 用附件返回资源内容 // strMetadata 返回的metadata内容 // strOutputResPath 返回的资源路径 // baTimestamp 返回的资源时间戳 // return: // -1 一般性错误 // -4 未找到路径指定的资源 // -5 未找到数据库 // -6 没有足够的权限 // -7 路径不合法 // -10 未找到记录xpath对应的节点 // >= 0 成功,返回最大长度 // nAdditionError -50 有一个以上下级资源记录不存在 // 线:安全 public long GetRes(string strResPath, int nStart, int nLength, string strStyle, User user, int nMaxLength, out byte[] baData, out string strMetadata, out string strOutputResPath, out byte[] baOutputTimestamp, out int nAdditionError, // 附加的错误码 out string strError) { baData = null; strMetadata = ""; strOutputResPath = ""; baOutputTimestamp = null; strError = ""; nAdditionError = 0; //------------------------------------------------ //检查输入参数是否合法,并规范输入参数 //--------------------------------------------------- Debug.Assert(user != null, "GetRes()调用错误,user对象不能为null。"); if (user == null) { strError = "GetRes()调用错误,user对象不能为null。"; return -1; } if (String.IsNullOrEmpty(strResPath) == true) { strError = "资源路径'" + strResPath + "'不合法,不能为null或空字符串。"; return -7; } if (nStart < 0) { strError = "GetRes()调用错误,nStart不能小于0。"; return -1; } if (strStyle == null) strStyle = ""; //------------------------------------------------ // 开始做事情 //--------------------------------------------------- //******************加库集合加读锁****** this.m_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK this.WriteDebugInfo("GetRes(),对库集合加读锁。"); #endif try { long nRet = 0; bool bRecordPath = this.IsRecordPath(strResPath); if (bRecordPath == false) { //当配置事项处理 // return: // -1 一般性错误 // -4 未找到路径对应的对象 // -6 没有足够的权限 // >= 0 成功 返回最大长度 nRet = this.GetFileCfgItem(strResPath, nStart, nLength, nMaxLength, strStyle, user, out baData, out strMetadata, out baOutputTimestamp, out strError); if (StringUtil.IsInList("outputpath", strStyle) == true) { strOutputResPath = strResPath; } } else { // 判断资源类型 string strPath = strResPath; string strDbName = StringUtil.GetFirstPartPath(ref strPath); //***********吃掉第1层************* // 到此为止,strPath不含数据库名了,下面的路径有两种情况:cfgs;其余都被当作记录id if (strPath == "") { strError = "资源路径'" + strResPath + "'路径不合法,未指定库的下级。"; return -7; } // 从这里区别是数据库还是服务器端配置文件 // 根据资源类型,写资源 Database db = this.GetDatabase(strDbName); if (db == null) { strError = "未找到'" + strDbName + "'库"; return -5; } bool bObject = false; string strRecordID = ""; string strObjectID = ""; string strXPath = ""; string strFirstPart = StringUtil.GetFirstPartPath(ref strPath); //***********吃掉第2层************* // 到此为止,strPath记录号层了,下级分情况判断 strRecordID = strFirstPart; // 只到记录号层的路径 if (strPath == "") { bObject = false; goto DOGET; } strFirstPart = StringUtil.GetFirstPartPath(ref strPath); //***********吃掉第2层************* // 到此为止,strPath不含object或xpath层 strFirstPart可能是object 或 xpath if (strFirstPart != "object" && strFirstPart != "xpath") { strError = "资源路径 '" + strResPath + "' 不合法,第3级必须是'object'或'xpath'"; return -7; } if (strPath == "") //object或xpath下级必须有值 { strError = "资源路径 '" + strResPath + "' 不合法,当第3级是'object'或'xpath',第4级必须有内容。"; return -7; } if (strFirstPart == "object") { strObjectID = strPath; bObject = true; } else { strXPath = strPath; bObject = false; } /////////////////////////////////// ///开始做事情 ////////////////////////////////////////// DOGET: // 检查对数据库中记录的权限 string strExistRights = ""; bool bHasRight = user.HasRights(strDbName + "/" + strRecordID, ResType.Record, "read", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对'" + strDbName + "'库没有'读记录(read)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } if (bObject == true) //对像 { // -1 出错 // -4 记录不存在 // >=0 资源总长度 nRet = db.GetObject(strRecordID, strObjectID, nStart, nLength, nMaxLength, strStyle, out baData, out strMetadata, out baOutputTimestamp, out strError); if (StringUtil.IsInList("outputpath", strStyle) == true) { strOutputResPath = strDbName + "/" + strRecordID + "/object/" + strObjectID; } } else { string strOutputID; // return: // -1 出错 // -4 未找到记录 // -10 记录局部未找到 // >=0 资源总长度 // nAdditionError -50 有一个以上下级资源记录不存在 nRet = db.GetXml(strRecordID, strXPath, nStart, nLength, nMaxLength, strStyle, out baData, out strMetadata, out strOutputID, out baOutputTimestamp, true, out nAdditionError, out strError); if (StringUtil.IsInList("outputpath", strStyle) == true) { strRecordID = strOutputID; } if (StringUtil.IsInList("outputpath", strStyle) == true) { if (strXPath == "") strOutputResPath = strDbName + "/" + strRecordID; else strOutputResPath = strDbName + "/" + strRecordID + "/xpath/" + strXPath; } } } return nRet; } finally { //******************对库集合解读锁****** this.m_lock.ReleaseReaderLock(); #if DEBUG_LOCK this.WriteDebugInfo("GetRes(),对库集合解读锁。"); #endif } }
// parameters: // strRecorID 记录ID // strObjectID 对象ID // 其它参数同WriteXml,无strOutputID参数 // return: // -1 出错 // -2 时间戳不匹配 // -4 记录或对象资源不存在 // -6 权限不够 // 0 成功 public override int WriteObject(User user, string strRecordID, string strObjectID, string strRanges, long lTotalLength, byte[] baSource, Stream streamSource, string strMetadata, string strStyle, byte[] inputTimestamp, out byte[] outputTimestamp, out string strError) { outputTimestamp = null; strError = ""; int nRet = 0; if (user != null) { string strTempRecordPath = this.GetCaption("zh-cn") + "/" + strRecordID; string strExistRights = ""; bool bHasRight = user.HasRights(strTempRecordPath, ResType.Record, "overwrite", out strExistRights); if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对'" + strTempRecordPath + "'记录没有'覆盖(overwrite)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } } //**********对数据库加读锁************ m_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK_SQLDATABASE this.container.WriteDebugInfo("WriteObject(),对'" + this.GetCaption("zh-cn") + "'数据库加读锁。"); #endif try { string strOutputRecordID = ""; // return: // -1 出错 // 0 成功 nRet = this.CanonicalizeRecordID(strRecordID, out strOutputRecordID, out strError); if (nRet == -1) return -1; if (strOutputRecordID == "-1") { strError = "保存对象资源不支持记录号参数值为'" + strRecordID + "'。"; return -1; } strRecordID = strOutputRecordID; //**********对记录加写锁*************** m_recordLockColl.LockForWrite(strRecordID, m_nTimeOut); #if DEBUG_LOCK_SQLDATABASE this.container.WriteDebugInfo("WriteObject(),对'" + this.GetCaption("zh-cn") + "/" + strRecordID + "'记录加写锁。"); #endif try // 记录锁 { // 打开连接对象 SqlConnection connection = new SqlConnection(this.m_strConnString); connection.Open(); try // 连接 { // 1.在对应的xml数据,用对象路径找到对象ID string strXml; // return: // -1 出错 // -4 记录不存在 // 0 正确 nRet = this.GetXmlString(connection, strRecordID, out strXml, out strError); if (nRet <= -1) { strError = "保存'" + strRecordID + "/" + strObjectID + "'资源失败,原因:" + strError; return nRet; } XmlDocument xmlDom = new XmlDocument(); xmlDom.PreserveWhitespace = true; //设PreserveWhitespace为true xmlDom.LoadXml(strXml); XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDom.NameTable); nsmgr.AddNamespace("dprms", DpNs.dprms); XmlNode fileNode = xmlDom.DocumentElement.SelectSingleNode("//dprms:file[@id='" + strObjectID + "']", nsmgr); if (fileNode == null) { strError = "在数据xml里没有找到该ID对应的dprms:file节点"; return -1; } strObjectID = strRecordID + "_" + strObjectID; // 2. 当记录为空记录时,用updata更改文本指针 if (this.IsEmptyObject(connection, strObjectID) == true) { // return // -1 出错 // 0 成功 nRet = this.UpdateObject(connection, strObjectID, out inputTimestamp, out strError); if (nRet == -1) return -1; } // 3.把数据写到range指定的范围 bool bFull = false; // return: // -1 一般性错误 // -2 时间戳不匹配 // 0 成功 nRet = this.WriteSqlRecord(connection, strObjectID, strRanges, (int)lTotalLength, baSource, streamSource, strMetadata, strStyle, inputTimestamp, out outputTimestamp, out bFull, out strError); if (nRet <= -1) return nRet; //string strCurrentRange = this.GetRange(connection,strObjectID); if (bFull == true) //覆盖完了 { // 1. 用newdata替换data字段 // return: // -1 出错 // >=0 成功 返回影响的记录数 nRet = this.UpdateDataField(connection, strObjectID, out strError); if (nRet == -1) return -1; // 2. 删除newdata字段 // return: // -1 出错 // 0 成功 nRet = this.DeleteDuoYuImage(connection, strObjectID, "newdata", 0, out strError); if (nRet == -1) return -1; } // 负责修改一下记录的时间戳 string strNewTimestamp = this.CreateTimestampForDb(); // return: // -1 出错 // >=0 成功 返回被影响的记录数 nRet = this.SetTimestampForDb(connection, strRecordID, strNewTimestamp, out strError); if (nRet == -1) return -1; } catch (SqlException sqlEx) { if (sqlEx.Errors is SqlErrorCollection) strError = "数据库'" + this.GetCaption("zh") + "'尚未初始化。"; else strError = sqlEx.Message; return -1; } catch (Exception ex) { strError = "WriteXml() 在给'" + this.GetCaption("zh-cn") + "'库写入资源'" + strObjectID + "'时出错,原因:" + ex.Message; return -1; } finally // 连接 { connection.Close(); } } finally // 记录锁 { //*********对记录解写锁**************************** m_recordLockColl.UnlockForWrite(strRecordID); #if DEBUG_LOCK_SQLDATABASE this.container.WriteDebugInfo("WriteObject(),对'" + this.GetCaption("zh-cn") + "/" + strRecordID + "'记录解写锁。"); #endif } } finally { //************对数据库解读锁************ m_lock.ReleaseReaderLock(); #if DEBUG_LOCK_SQLDATABASE this.container.WriteDebugInfo("WriteObject(),对'" + this.GetCaption("zh-cn") + "'数据库解读锁。"); #endif } return 0; }
// 按指定范围读配置文件 // strRoleName: 角色名,大小写均可 // 其它参数同GetXml(),无strOutputResPath参数 // 线: 安全的 // return: // -1 一般性错误 // -4 未找到路径对应的对象 // -6 没有足够的权限 // >= 0 成功 返回最大长度 // 线:安全 public int GetFileCfgItem(string strCfgItemPath, int nStart, int nLength, int nMaxLength, string strStyle, User user, out byte[] destBuffer, out string strMetadata, out byte[] outputTimestamp, out string strError) { strMetadata = ""; destBuffer = null; outputTimestamp = null; strError = ""; // 检查当前帐户对配置事项的权限,暂时不报权限的错,检查完对象是否存在,再报错 string strExistRights = ""; bool bHasRight = user.HasRights(strCfgItemPath, ResType.File, "read", out strExistRights); //**********对数据库集合加读锁************** this.m_lock.AcquireReaderLock(m_nTimeOut); #if DEBUG_LOCK this.container.WriteDebugInfo("GetCfgFile(),对'" + this.GetCaption("zh-cn") + "'数据库集合加读锁。"); #endif try { string strFilePath = "";//this.GetCfgItemLacalPath(strCfgItemPath); // return: // -1 一般性错误,比如调用错误,参数不合法等 // -2 没找到节点 // -3 localname属性未定义或为值空 // -4 localname在本地不存在 // -5 存在多个节点 // 0 成功 int nRet = this.GetFileCfgItemLacalPath(strCfgItemPath, out strFilePath, out strError); if (nRet != 0) { if (nRet == -2) return -4; return -1; } // 此时再报权限的错 if (bHasRight == false) { strError = "您的帐户名为'" + user.Name + "',对路径为'" + strCfgItemPath + "'的配置事项没有'读(read)'权限,目前的权限值为'" + strExistRights + "'。"; return -6; } // return: // -1 出错 // >= 0 成功,返回最大长度 return DatabaseCollection.GetFileForCfgItem(strFilePath, nStart, nLength, nMaxLength, strStyle, out destBuffer, out strMetadata, out outputTimestamp, out strError); } finally { //****************对数据库集合解读锁************** this.m_lock.ReleaseReaderLock(); #if DEBUG_LOCK this.container.WriteDebugInfo("GetCfgFile(),对'" + this.GetCaption("zh-cn") + "'数据库集合解读锁。"); #endif } }