- Timestamp:
- Sep 2, 2016, 6:32:50 PM (9 years ago)
- Location:
- trunk/src/lib/nt
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/lib/nt/kFsCache.c
r2862 r2863 62 62 # define KFSCACHE_LOG2(a) do { } while (0) 63 63 #endif 64 65 66 /********************************************************************************************************************************* 67 * Structures and Typedefs * 68 *********************************************************************************************************************************/ 69 /** 70 * Used by the code re-populating a directory. 71 */ 72 typedef struct KFSDIRREPOP 73 { 74 /** The old papChildren array. */ 75 PKFSOBJ *papOldChildren; 76 /** Number of children in the array. */ 77 KU32 cOldChildren; 78 /** The index into papOldChildren we expect to find the next entry. */ 79 KU32 iNextOldChild; 80 /** Add this to iNextOldChild . */ 81 KI32 cNextOldChildInc; 82 /** Pointer to the cache (name changes). */ 83 PKFSCACHE pCache; 84 } KFSDIRREPOP; 85 /** Pointer to directory re-population data. */ 86 typedef KFSDIRREPOP *PKFSDIRREPOP; 64 87 65 88 … … 231 254 232 255 /** 256 * For use when kFsCacheIAreEqualW hit's something non-trivial. 257 * 258 * @returns K_TRUE if equal, K_FALSE if different. 259 * @param pwcName1 The first string. 260 * @param pwcName2 The second string. 261 * @param cwcName The length of the two strings (in wchar_t's). 262 */ 263 KBOOL kFsCacheIAreEqualSlowW(const wchar_t *pwcName1, const wchar_t *pwcName2, KU16 cwcName) 264 { 265 MY_UNICODE_STRING UniStr1 = { cwcName * sizeof(wchar_t), cwcName * sizeof(wchar_t), (wchar_t *)pwcName1 }; 266 MY_UNICODE_STRING UniStr2 = { cwcName * sizeof(wchar_t), cwcName * sizeof(wchar_t), (wchar_t *)pwcName2 }; 267 return g_pfnRtlEqualUnicodeString(&UniStr1, &UniStr2, TRUE /*fCaseInsensitive*/); 268 } 269 270 271 /** 272 * Compares two UTF-16 strings in a case-insensitive fashion. 273 * 274 * You would think we should be using _wscnicmp here instead, however it is 275 * locale dependent and defaults to ASCII upper/lower handling setlocale hasn't 276 * been called. 277 * 278 * @returns K_TRUE if equal, K_FALSE if different. 279 * @param pwcName1 The first string. 280 * @param pwcName2 The second string. 281 * @param cwcName The length of the two strings (in wchar_t's). 282 */ 283 K_INLINE KBOOL kFsCacheIAreEqualW(const wchar_t *pwcName1, const wchar_t *pwcName2, KU32 cwcName) 284 { 285 while (cwcName > 0) 286 { 287 wchar_t wc1 = *pwcName1; 288 wchar_t wc2 = *pwcName2; 289 if (wc1 == wc2) 290 { /* not unlikely */ } 291 else if ( (KU16)wc1 < (KU16)0xc0 /* U+00C0 is the first upper/lower letter after 'z'. */ 292 && (KU16)wc2 < (KU16)0xc0) 293 { 294 /* ASCII upper case. */ 295 if ((KU16)wc1 - (KU16)0x61 < (KU16)26) 296 wc1 &= ~(wchar_t)0x20; 297 if ((KU16)wc2 - (KU16)0x61 < (KU16)26) 298 wc2 &= ~(wchar_t)0x20; 299 if (wc1 != wc2) 300 return K_FALSE; 301 } 302 else 303 return kFsCacheIAreEqualSlowW(pwcName1, pwcName2, (KU16)cwcName); 304 305 pwcName2++; 306 pwcName1++; 307 cwcName--; 308 } 309 310 return K_TRUE; 311 } 312 313 314 /** 233 315 * Looks for '..' in the path. 234 316 * … … 405 487 static KBOOL kFsCacheDirAddChild(PKFSCACHE pCache, PKFSDIR pParent, PKFSOBJ pChild, KFSLOOKUPERROR *penmError) 406 488 { 407 if ( (pParent->cChildren % 16) == 0)408 { 409 void *pvNew = kHlpRealloc(pParent->papChildren, (pParent->cChildren + 16) * sizeof(pParent->papChildren[0]));489 if (pParent->cChildren >= pParent->cChildrenAllocated) 490 { 491 void *pvNew = kHlpRealloc(pParent->papChildren, (pParent->cChildrenAllocated + 16) * sizeof(pParent->papChildren[0])); 410 492 if (!pvNew) 411 493 return K_FALSE; 412 494 pParent->papChildren = (PKFSOBJ *)pvNew; 495 pParent->cChildrenAllocated += 16; 413 496 pCache->cbObjects += 16 * sizeof(pParent->papChildren[0]); 414 497 } … … 533 616 { 534 617 PKFSDIR pDirObj = (PKFSDIR)pObj; 535 pDirObj->cChildren = 0; 536 pDirObj->papChildren = NULL; 537 pDirObj->cHashTab = 0; 538 pDirObj->paHashTab = NULL; 539 pDirObj->hDir = INVALID_HANDLE_VALUE; 540 pDirObj->uDevNo = pParent->uDevNo; 541 pDirObj->iLastWrite = 0; 542 pDirObj->fPopulated = K_FALSE; 618 pDirObj->cChildren = 0; 619 pDirObj->cChildrenAllocated = 0; 620 pDirObj->papChildren = NULL; 621 pDirObj->cHashTab = 0; 622 pDirObj->paHashTab = NULL; 623 pDirObj->hDir = INVALID_HANDLE_VALUE; 624 pDirObj->uDevNo = pParent->uDevNo; 625 pDirObj->iLastWrite = 0; 626 pDirObj->fPopulated = K_FALSE; 543 627 } 544 628 } … … 685 769 } 686 770 771 /** 772 * Worker for kFsCacheDirFindOldChild that refreshes the file ID value on an 773 * object found by name. 774 * 775 * @returns Pointer to the existing object if found, NULL if not. 776 * @param pDirRePop Repopulation data. 777 * @param pCur The object to check the names of. 778 * @param idFile The file ID. 779 */ 780 static PKFSOBJ kFsCacheDirRefreshOldChildFileId(PKFSDIRREPOP pDirRePop, PKFSOBJ pCur, KI64 idFile) 781 { 782 KFSCACHE_LOG(("Refreshing %s/%s/ - %s changed file ID from %#llx -> %#llx...\n", 783 pCur->pParent->Obj.pParent->Obj.pszName, pCur->pParent->Obj.pszName, pCur->pszName, 784 pCur->Stats.st_ino, idFile)); 785 pCur->Stats.st_ino = idFile; 786 /** @todo inform user data items... */ 787 return pCur; 788 } 789 790 791 /** 792 * Worker for kFsCacheDirFindOldChild that checks the names after an old object 793 * has been found the file ID. 794 * 795 * @returns Pointer to the existing object if found, NULL if not. 796 * @param pDirRePop Repopulation data. 797 * @param pCur The object to check the names of. 798 * @param pwcName The file name. 799 * @param cwcName The length of the filename (in wchar_t's). 800 * @param pwcShortName The short name, if present. 801 * @param cwcShortName The length of the short name (in wchar_t's). 802 */ 803 static PKFSOBJ kFsCacheDirRefreshOldChildName(PKFSDIRREPOP pDirRePop, PKFSOBJ pCur, wchar_t const *pwcName, KU32 cwcName 804 #ifdef KFSCACHE_CFG_SHORT_NAMES 805 , wchar_t const *pwcShortName, KU32 cwcShortName 806 #endif 807 ) 808 { 809 __debugbreak(); 810 /** @todo implement this. It's not entirely straight forward, especially if 811 * the name increases! Also, it's something that may happend during 812 * individual object refresh and we might want to share code... */ 813 814 return pCur; 815 } 816 817 818 /** 819 * Worker for kFsCacheDirFindOldChild that checks the names after an old object 820 * has been found the file ID. 821 * 822 * @returns Pointer to the existing object if found, NULL if not. 823 * @param pDirRePop Repopulation data. 824 * @param pCur The object to check the names of. 825 * @param pwcName The file name. 826 * @param cwcName The length of the filename (in wchar_t's). 827 * @param pwcShortName The short name, if present. 828 * @param cwcShortName The length of the short name (in wchar_t's). 829 */ 830 K_INLINE PKFSOBJ kFsCacheDirCheckOldChildName(PKFSDIRREPOP pDirRePop, PKFSOBJ pCur, wchar_t const *pwcName, KU32 cwcName 831 #ifdef KFSCACHE_CFG_SHORT_NAMES 832 , wchar_t const *pwcShortName, KU32 cwcShortName 833 #endif 834 ) 835 { 836 if ( pCur->cwcName == cwcName 837 && kHlpMemComp(pCur->pwszName, pwcName, cwcName * sizeof(wchar_t)) == 0) 838 { 839 #ifdef KFSCACHE_CFG_SHORT_NAMES 840 if (cwcShortName == 0 841 ? pCur->pwszShortName == pCur->pwszName 842 || ( pCur->cwcShortName == cwcName 843 && kHlpMemComp(pCur->pwszShortName, pCur->pwszName, cwcName * sizeof(wchar_t)) == 0) 844 : pCur->cwcShortName == cwcShortName 845 && kHlpMemComp(pCur->pwszShortName, pwcShortName, cwcShortName * sizeof(wchar_t)) == 0 ) 846 #endif 847 { 848 return pCur; 849 } 850 } 851 #ifdef KFSCACHE_CFG_SHORT_NAMES 852 return kFsCacheDirRefreshOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); 853 #else 854 return kFsCacheDirRefreshOldChildName(pDirRePop, pCur, pwcName, cwcName); 855 #endif 856 } 857 858 859 /** 860 * Worker for kFsCachePopuplateOrRefreshDir that locates an old child object 861 * while re-populating a directory. 862 * 863 * @returns Pointer to the existing object if found, NULL if not. 864 * @param pDirRePop Repopulation data. 865 * @param idFile The file ID, 0 if none. 866 * @param pwcName The file name. 867 * @param cwcName The length of the filename (in wchar_t's). 868 * @param pwcShortName The short name, if present. 869 * @param cwcShortName The length of the short name (in wchar_t's). 870 */ 871 static PKFSOBJ kFsCacheDirFindOldChildSlow(PKFSDIRREPOP pDirRePop, KI64 idFile, wchar_t const *pwcName, KU32 cwcName 872 #ifdef KFSCACHE_CFG_SHORT_NAMES 873 , wchar_t const *pwcShortName, KU32 cwcShortName 874 #endif 875 ) 876 { 877 KU32 cOldChildren = pDirRePop->cOldChildren; 878 KU32 const iNextOldChild = K_MIN(pDirRePop->iNextOldChild, cOldChildren - 1); 879 KU32 iCur; 880 KI32 cInc; 881 KI32 cDirLefts; 882 883 kHlpAssertReturn(cOldChildren > 0, NULL); 884 885 /* 886 * Search by file ID first, if we've got one. 887 * ASSUMES that KU32 wraps around when -1 is added to 0. 888 */ 889 if ( idFile != 0 890 && idFile != KI64_MAX 891 && idFile != KI64_MIN) 892 { 893 cInc = pDirRePop->cNextOldChildInc; 894 kHlpAssert(cInc == -1 || cInc == 1); 895 for (cDirLefts = 2; cDirLefts > 0; cDirLefts--) 896 { 897 for (iCur = iNextOldChild; iCur < cOldChildren; iCur += cInc) 898 { 899 PKFSOBJ pCur = pDirRePop->papOldChildren[iCur]; 900 if (pCur->Stats.st_ino == idFile) 901 { 902 /* Remove it and check the name. */ 903 pDirRePop->cOldChildren = --cOldChildren; 904 if (iCur < cOldChildren) 905 pDirRePop->papOldChildren[iCur] = pDirRePop->papOldChildren[cOldChildren]; 906 else 907 cInc = -1; 908 pDirRePop->cNextOldChildInc = cInc; 909 pDirRePop->iNextOldChild = iCur + cInc; 910 911 #ifdef KFSCACHE_CFG_SHORT_NAMES 912 return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); 913 #else 914 return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); 915 #endif 916 } 917 } 918 cInc = -cInc; 919 } 920 } 921 922 /* 923 * Search by name. 924 * ASSUMES that KU32 wraps around when -1 is added to 0. 925 */ 926 cInc = pDirRePop->cNextOldChildInc; 927 kHlpAssert(cInc == -1 || cInc == 1); 928 for (cDirLefts = 2; cDirLefts > 0; cDirLefts--) 929 { 930 for (iCur = iNextOldChild; iCur < cOldChildren; iCur += cInc) 931 { 932 PKFSOBJ pCur = pDirRePop->papOldChildren[iCur]; 933 if ( ( pCur->cwcName == cwcName 934 && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName)) 935 #ifdef KFSCACHE_CFG_SHORT_NAMES 936 || ( pCur->cwcShortName == cwcName 937 && pCur->pwszShortName != pCur->pwszName 938 && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName)) 939 #endif 940 ) 941 { 942 /* Do this first so the compiler can share the rest with the above file ID return. */ 943 if (pCur->Stats.st_ino == idFile) 944 { /* likely */ } 945 else 946 pCur = kFsCacheDirRefreshOldChildFileId(pDirRePop, pCur, idFile); 947 948 /* Remove it and check the name. */ 949 pDirRePop->cOldChildren = --cOldChildren; 950 if (iCur < cOldChildren) 951 pDirRePop->papOldChildren[iCur] = pDirRePop->papOldChildren[cOldChildren]; 952 else 953 cInc = -1; 954 pDirRePop->cNextOldChildInc = cInc; 955 pDirRePop->iNextOldChild = iCur + cInc; 956 957 #ifdef KFSCACHE_CFG_SHORT_NAMES 958 return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); 959 #else 960 return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); 961 #endif 962 } 963 } 964 cInc = -cInc; 965 } 966 967 return NULL; 968 } 969 970 971 972 /** 973 * Worker for kFsCachePopuplateOrRefreshDir that locates an old child object 974 * while re-populating a directory. 975 * 976 * @returns Pointer to the existing object if found, NULL if not. 977 * @param pDirRePop Repopulation data. 978 * @param idFile The file ID, 0 if none. 979 * @param pwcName The file name. 980 * @param cwcName The length of the filename (in wchar_t's). 981 * @param pwcShortName The short name, if present. 982 * @param cwcShortName The length of the short name (in wchar_t's). 983 */ 984 K_INLINE PKFSOBJ kFsCacheDirFindOldChild(PKFSDIRREPOP pDirRePop, KI64 idFile, wchar_t const *pwcName, KU32 cwcName 985 #ifdef KFSCACHE_CFG_SHORT_NAMES 986 , wchar_t const *pwcShortName, KU32 cwcShortName 987 #endif 988 ) 989 { 990 /* 991 * We only check the iNextOldChild element here, hoping that the compiler 992 * will actually inline this code, letting the slow version of the function 993 * do the rest. 994 */ 995 KU32 cOldChildren = pDirRePop->cOldChildren; 996 if (cOldChildren > 0) 997 { 998 KU32 const iNextOldChild = K_MIN(pDirRePop->iNextOldChild, cOldChildren); 999 PKFSOBJ pCur = pDirRePop->papOldChildren[iNextOldChild]; 1000 1001 if ( pCur->Stats.st_ino == idFile 1002 && idFile != 0 1003 && idFile != KI64_MAX 1004 && idFile != KI64_MIN) 1005 pCur = kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); 1006 else if ( pCur->cwcName == cwcName 1007 && kHlpMemComp(pCur->pwszName, pwcName, cwcName * sizeof(wchar_t)) == 0) 1008 { 1009 if (pCur->Stats.st_ino == idFile) 1010 { /* likely */ } 1011 else 1012 pCur = kFsCacheDirRefreshOldChildFileId(pDirRePop, pCur, idFile); 1013 1014 #ifdef KFSCACHE_CFG_SHORT_NAMES 1015 if (cwcShortName == 0 1016 ? pCur->pwszShortName == pCur->pwszName 1017 || ( pCur->cwcShortName == cwcName 1018 && kHlpMemComp(pCur->pwszShortName, pCur->pwszName, cwcName * sizeof(wchar_t)) == 0) 1019 : pCur->cwcShortName == cwcShortName 1020 && kHlpMemComp(pCur->pwszShortName, pwcShortName, cwcShortName * sizeof(wchar_t)) == 0 ) 1021 { /* likely */ } 1022 else 1023 pCur = kFsCacheDirRefreshOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName); 1024 #endif 1025 } 1026 else 1027 pCur = NULL; 1028 if (pCur) 1029 { 1030 /* 1031 * Got a match. Remove the child from the array, replacing it with 1032 * the last element. (This means we're reversing the second half of 1033 * the elements, which is why we need cNextOldChildInc.) 1034 */ 1035 pDirRePop->cOldChildren = --cOldChildren; 1036 if (iNextOldChild < cOldChildren) 1037 pDirRePop->papOldChildren[iNextOldChild] = pDirRePop->papOldChildren[cOldChildren]; 1038 pDirRePop->iNextOldChild = iNextOldChild + pDirRePop->cNextOldChildInc; 1039 return pCur; 1040 } 1041 1042 #ifdef KFSCACHE_CFG_SHORT_NAMES 1043 return kFsCacheDirFindOldChildSlow(pDirRePop, idFile, pwcName, cwcName, pwcShortName, cwcShortName); 1044 #else 1045 return kFsCacheDirFindOldChildSlow(pDirRePop, idFile, pwcName, cwcName); 1046 #endif 1047 } 1048 1049 return NULL; 1050 } 1051 1052 687 1053 688 1054 /** … … 699 1065 static KBOOL kFsCachePopuplateOrRefreshDir(PKFSCACHE pCache, PKFSDIR pDir, KFSLOOKUPERROR *penmError) 700 1066 { 701 KBOOL fRefreshing = K_FALSE; 702 /** @todo will have to make this more flexible wrt information classes since 1067 KBOOL fRefreshing = K_FALSE; 1068 KFSDIRREPOP DirRePop = { NULL, 0, 0, 0, NULL }; 1069 MY_UNICODE_STRING UniStrStar = { 1 * sizeof(wchar_t), 2 * sizeof(wchar_t), L"*" }; 1070 1071 /** @todo May have to make this more flexible wrt information classes since 703 1072 * older windows versions (XP, w2K) might not correctly support the 704 1073 * ones with file ID on all file systems. */ … … 720 1089 KU8 abBuf[56*1024]; 721 1090 } uBuf; 1091 722 1092 723 1093 /* … … 763 1133 } 764 1134 } 1135 /* 1136 * When re-populating, we replace papChildren in the directory and pick 1137 * from the old one as we go along. 1138 */ 765 1139 else if (pDir->fPopulated) 766 1140 { 767 /** @todo refreshing directories. */ 768 __debugbreak(); 1141 KU32 cAllocated = K_ALIGN_Z(pDir->cChildren, 16); 1142 void *pvNew = kHlpAlloc(sizeof(pDir->papChildren[0]) * cAllocated); 1143 if (pvNew) 1144 { 1145 DirRePop.papOldChildren = pDir->papChildren; 1146 DirRePop.cOldChildren = pDir->cChildren; 1147 DirRePop.iNextOldChild = 0; 1148 DirRePop.cNextOldChildInc = 1; 1149 DirRePop.pCache = pCache; 1150 1151 pDir->cChildren = 0; 1152 pDir->cChildrenAllocated = cAllocated; 1153 pDir->papChildren = (PKFSOBJ *)pvNew; 1154 } 1155 else 1156 { 1157 *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY; 1158 return K_FALSE; 1159 } 1160 769 1161 fRefreshing = K_TRUE; 770 1162 } … … 776 1168 /* 777 1169 * Enumerate the directory content. 1170 * 1171 * Note! The "*" filter is necessary because kFsCacheRefreshObj may have 1172 * previously quried a single file name and just passing NULL would 1173 * restart that single file name query. 778 1174 */ 779 1175 Ios.Information = -1; … … 788 1184 enmInfoClass, 789 1185 FALSE, /* fReturnSingleEntry */ 790 NULL,/* Filter / restart pos. */1186 &UniStrStar, /* Filter / restart pos. */ 791 1187 TRUE); /* fRestartScan */ 792 1188 while (MY_NT_SUCCESS(rcNt)) … … 812 1208 KU32 offNext; 813 1209 KU32 cbMinCur; 814 wchar_t *pw szFilename;1210 wchar_t *pwchFilename; 815 1211 816 1212 /* ASSUME only the FileName member differs between the two structures. */ … … 818 1214 if (enmInfoClass == enmInfoClassWithId) 819 1215 { 820 pw szFilename = &uPtr.pWithId->FileName[0];1216 pwchFilename = &uPtr.pWithId->FileName[0]; 821 1217 cbMinCur = (KU32)((uintptr_t)&uPtr.pWithId->FileName[0] - (uintptr_t)uPtr.pWithId); 822 1218 cbMinCur += uPtr.pNoId->FileNameLength; … … 824 1220 else 825 1221 { 826 pw szFilename = &uPtr.pNoId->FileName[0];1222 pwchFilename = &uPtr.pNoId->FileName[0]; 827 1223 cbMinCur = (KU32)((uintptr_t)&uPtr.pNoId->FileName[0] - (uintptr_t)uPtr.pNoId); 828 1224 cbMinCur += uPtr.pNoId->FileNameLength; … … 830 1226 831 1227 /* We need to skip the '.' and '..' entries. */ 832 if ( *pw szFilename != '.'1228 if ( *pwchFilename != '.' 833 1229 || uPtr.pNoId->FileNameLength > 4 834 1230 || !( uPtr.pNoId->FileNameLength == 2 835 1231 || ( uPtr.pNoId->FileNameLength == 4 836 && pw szFilename[1] == '.') )1232 && pwchFilename[1] == '.') ) 837 1233 ) 838 1234 { 1235 KBOOL fRc; 1236 KU8 const bObjType = uPtr.pNoId->FileAttributes & FILE_ATTRIBUTE_DIRECTORY ? KFSOBJ_TYPE_DIR 1237 : uPtr.pNoId->FileAttributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT) 1238 ? KFSOBJ_TYPE_OTHER : KFSOBJ_TYPE_FILE; 1239 839 1240 /* 840 * Create the entry (not linked yet). 1241 * If refreshing, we must first see if this directory entry already 1242 * exists. 841 1243 */ 842 pCur = kFsCacheCreateObjectW(pCache, pDir, pwszFilename, uPtr.pNoId->FileNameLength / sizeof(wchar_t), 1244 if (!fRefreshing) 1245 pCur = NULL; 1246 else 1247 { 1248 pCur = kFsCacheDirFindOldChild(&DirRePop, 1249 enmInfoClass == enmInfoClassWithId ? uPtr.pWithId->FileId.QuadPart : 0, 1250 pwchFilename, uPtr.pWithId->FileNameLength / sizeof(wchar_t) 843 1251 #ifdef KFSCACHE_CFG_SHORT_NAMES 844 uPtr.pNoId->ShortName, uPtr.pNoId->ShortNameLength / sizeof(wchar_t), 845 #endif 846 uPtr.pNoId->FileAttributes & FILE_ATTRIBUTE_DIRECTORY ? KFSOBJ_TYPE_DIR 847 : uPtr.pNoId->FileAttributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT) 848 ? KFSOBJ_TYPE_OTHER : KFSOBJ_TYPE_FILE, 849 penmError); 1252 , uPtr.pWithId->ShortName, uPtr.pWithId->ShortNameLength / sizeof(wchar_t) 1253 #endif 1254 ); 1255 if (pCur) 1256 { 1257 if (pCur->bObjType == bObjType) 1258 { 1259 if (pCur->bObjType == KFSOBJ_TYPE_DIR) 1260 { 1261 PKFSDIR pCurDir = (PKFSDIR)pCur; 1262 if ( !pCurDir->fPopulated 1263 || ( pCurDir->iLastWrite == uPtr.pWithId->LastWriteTime.QuadPart 1264 && (pCur->fFlags & KFSOBJ_F_WORKING_DIR_MTIME) ) ) 1265 { /* kind of likely */ } 1266 else 1267 { 1268 KFSCACHE_LOG(("Refreshing %s/%s/ - %s/ needs re-populating...\n", 1269 pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pCur->pszName)); 1270 pCurDir->fNeedRePopulating = K_TRUE; 1271 } 1272 } 1273 } 1274 else if (pCur->bObjType == KFSOBJ_TYPE_MISSING) 1275 { 1276 KFSCACHE_LOG(("Refreshing %s/%s/ - %s appeared as %u, was missing.\n", 1277 pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pCur->pszName, bObjType)); 1278 pCur->bObjType = bObjType; 1279 } 1280 else 1281 { 1282 KFSCACHE_LOG(("Refreshing %s/%s/ - %s changed type from %u to %u! Dropping old object.\n", 1283 pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pCur->pszName, 1284 pCur->bObjType, bObjType)); 1285 kFsCacheObjRelease(pCache, pCur); 1286 pCur = NULL; 1287 } 1288 } 1289 else 1290 KFSCACHE_LOG(("Refreshing %s/%s/ - %*.*ls added.\n", pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, 1291 uPtr.pNoId->FileNameLength / sizeof(wchar_t), uPtr.pNoId->FileNameLength / sizeof(wchar_t), 1292 pwchFilename)); 1293 } 1294 850 1295 if (!pCur) 851 return K_FALSE; 852 kHlpAssert(pCur->cRefs == 1); 1296 { 1297 /* 1298 * Create the entry (not linked yet). 1299 */ 1300 pCur = kFsCacheCreateObjectW(pCache, pDir, pwchFilename, uPtr.pNoId->FileNameLength / sizeof(wchar_t), 1301 #ifdef KFSCACHE_CFG_SHORT_NAMES 1302 uPtr.pNoId->ShortName, uPtr.pNoId->ShortNameLength / sizeof(wchar_t), 1303 #endif 1304 bObjType, penmError); 1305 if (!pCur) 1306 return K_FALSE; 1307 kHlpAssert(pCur->cRefs == 1); 1308 } 853 1309 854 1310 #ifdef KFSCACHE_CFG_SHORT_NAMES … … 867 1323 868 1324 /* 869 * If we're updating we have to check the data.1325 * Add the entry to the directory. 870 1326 */ 871 if (fRefreshing) 1327 fRc = kFsCacheDirAddChild(pCache, pDir, pCur, penmError); 1328 kFsCacheObjRelease(pCache, pCur); 1329 if (fRc) 1330 { /* likely */ } 1331 else 872 1332 { 873 __debugbreak(); 874 } 875 876 /* 877 * If we've still got pCur, add it to the directory. 878 */ 879 if (pCur) 880 { 881 KBOOL fRc = kFsCacheDirAddChild(pCache, pDir, pCur, penmError); 882 kFsCacheObjRelease(pCache, pCur); 883 if (fRc) 884 { /* likely */ } 885 else 886 return K_FALSE; 1333 rcNt = STATUS_NO_MEMORY; 1334 break; 887 1335 } 888 1336 } … … 929 1377 enmInfoClass, 930 1378 FALSE, /* fReturnSingleEntry */ 931 NULL,/* Filter / restart pos. */1379 &UniStrStar, /* Filter / restart pos. */ 932 1380 FALSE); /* fRestartScan */ 933 1381 } … … 935 1383 if (rcNt == MY_STATUS_NO_MORE_FILES) 936 1384 { 1385 /* 1386 * If refreshing, add missing children objects and ditch the rest. 1387 * We ignore errors while adding missing children (lazy bird). 1388 */ 1389 if (!fRefreshing) 1390 { /* more likely */ } 1391 else 1392 { 1393 while (DirRePop.cOldChildren > 0) 1394 { 1395 KFSLOOKUPERROR enmErrorIgn; 1396 PKFSOBJ pOldChild = DirRePop.papOldChildren[--DirRePop.cOldChildren]; 1397 if (pOldChild->bObjType == KFSOBJ_TYPE_MISSING) 1398 kFsCacheDirAddChild(pCache, pDir, pOldChild, &enmErrorIgn); 1399 else 1400 { 1401 KFSCACHE_LOG(("Refreshing %s/%s/ - %s was removed.\n", 1402 pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pOldChild->pszName)); 1403 kHlpAssert(pOldChild->bObjType != KFSOBJ_TYPE_DIR); 1404 } 1405 kFsCacheObjRelease(pCache, pOldChild); 1406 } 1407 kHlpFree(DirRePop.papOldChildren); 1408 } 1409 937 1410 /* 938 1411 * Mark the directory as fully populated and up to date. 939 1412 */ 940 pDir->fPopulated = K_TRUE; 1413 pDir->fPopulated = K_TRUE; 1414 pDir->fNeedRePopulating = K_FALSE; 941 1415 if (pDir->Obj.uCacheGen != KFSOBJ_CACHE_GEN_IGNORE) 942 1416 pDir->Obj.uCacheGen = pCache->uGeneration; 943 1417 return K_TRUE; 1418 } 1419 1420 /* 1421 * If we failed during refresh, add back remaining old children. 1422 */ 1423 if (!fRefreshing) 1424 { 1425 while (DirRePop.cOldChildren > 0) 1426 { 1427 KFSLOOKUPERROR enmErrorIgn; 1428 PKFSOBJ pOldChild = DirRePop.papOldChildren[--DirRePop.cOldChildren]; 1429 kFsCacheDirAddChild(pCache, pDir, pOldChild, &enmErrorIgn); 1430 kFsCacheObjRelease(pCache, pOldChild); 1431 } 1432 kHlpFree(DirRePop.papOldChildren); 944 1433 } 945 1434 … … 1069 1558 1070 1559 1560 /** 1561 * Generic object refresh. 1562 * 1563 * This does not refresh the content of directories. 1564 * 1565 * @returns K_TRUE on success. K_FALSE and *penmError on failure. 1566 * @param pCache The cache. 1567 * @param pObj The object. 1568 * @param penmError Where to return error info. 1569 */ 1071 1570 static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *penmError) 1072 1571 { … … 1131 1630 } 1132 1631 #else 1133 /* This alternative lets us keep the inode number up to date. */ 1632 /* This alternative lets us keep the inode number up to date and 1633 detect name case changes. */ 1134 1634 MY_UNICODE_STRING UniStr; 1135 1635 # ifdef KFSCACHE_CFG_SHORT_NAMES … … 1200 1700 } 1201 1701 #endif 1702 if (MY_NT_SUCCESS(rcNt)) 1703 { 1704 pObj->uCacheGen = pCache->uGeneration; 1705 fRc = K_TRUE; 1706 } 1707 else 1708 { 1709 /* ouch! */ 1710 kHlpAssertMsgFailed(("%#x\n", rcNt)); 1711 __debugbreak(); 1712 fRc = K_FALSE; 1713 } 1202 1714 } 1203 1715 else … … 1227 1739 / BIRD_STAT_BLOCK_SIZE; 1228 1740 1229 if ( pDir->iLastWrite -= uBuf.FullInfo.LastWriteTime.QuadPart1741 if ( pDir->iLastWrite == uBuf.FullInfo.LastWriteTime.QuadPart 1230 1742 && (pObj->fFlags & KFSOBJ_F_WORKING_DIR_MTIME) ) 1231 1743 KFSCACHE_LOG(("Refreshing %s/%s/ - no re-populating necessary.\n", … … 1246 1758 } 1247 1759 } 1248 1249 } 1250 if (MY_NT_SUCCESS(rcNt)) 1251 { 1252 pObj->uCacheGen = pCache->uGeneration; 1253 fRc = K_TRUE; 1254 } 1255 else 1256 { 1257 /* ouch! */ 1258 kHlpAssertMsgFailed(("%#x\n", rcNt)); 1259 __debugbreak(); 1260 fRc = K_FALSE; 1760 if (MY_NT_SUCCESS(rcNt)) 1761 { 1762 pObj->uCacheGen = pCache->uGeneration; 1763 fRc = K_TRUE; 1764 } 1765 else 1766 { 1767 /* ouch! */ 1768 kHlpAssertMsgFailed(("%#x\n", rcNt)); 1769 __debugbreak(); 1770 fRc = K_FALSE; 1771 } 1261 1772 } 1262 1773 } … … 1506 2017 1507 2018 /** 1508 * For use when kFsCacheIAreEqualW hit's something non-trivial.1509 *1510 * @returns K_TRUE if equal, K_FALSE if different.1511 * @param pwcName1 The first string.1512 * @param pwcName2 The second string.1513 * @param cwcName The length of the two strings (in wchar_t's).1514 */1515 KBOOL kFsCacheIAreEqualSlowW(const wchar_t *pwcName1, const wchar_t *pwcName2, KU16 cwcName)1516 {1517 MY_UNICODE_STRING UniStr1 = { cwcName * sizeof(wchar_t), cwcName * sizeof(wchar_t), (wchar_t *)pwcName1 };1518 MY_UNICODE_STRING UniStr2 = { cwcName * sizeof(wchar_t), cwcName * sizeof(wchar_t), (wchar_t *)pwcName2 };1519 return g_pfnRtlEqualUnicodeString(&UniStr1, &UniStr2, TRUE /*fCaseInsensitive*/);1520 }1521 1522 1523 /**1524 * Compares two UTF-16 strings in a case-insensitive fashion.1525 *1526 * You would think we should be using _wscnicmp here instead, however it is1527 * locale dependent and defaults to ASCII upper/lower handling setlocale hasn't1528 * been called.1529 *1530 * @returns K_TRUE if equal, K_FALSE if different.1531 * @param pwcName1 The first string.1532 * @param pwcName2 The second string.1533 * @param cwcName The length of the two strings (in wchar_t's).1534 */1535 K_INLINE KBOOL kFsCacheIAreEqualW(const wchar_t *pwcName1, const wchar_t *pwcName2, KU32 cwcName)1536 {1537 while (cwcName > 0)1538 {1539 wchar_t wc1 = *pwcName1;1540 wchar_t wc2 = *pwcName2;1541 if (wc1 == wc2)1542 { /* not unlikely */ }1543 else if ( (KU16)wc1 < (KU16)0xc0 /* U+00C0 is the first upper/lower letter after 'z'. */1544 && (KU16)wc2 < (KU16)0xc0)1545 {1546 /* ASCII upper case. */1547 if ((KU16)wc1 - (KU16)0x61 < (KU16)26)1548 wc1 &= ~(wchar_t)0x20;1549 if ((KU16)wc2 - (KU16)0x61 < (KU16)26)1550 wc2 &= ~(wchar_t)0x20;1551 if (wc1 != wc2)1552 return K_FALSE;1553 }1554 else1555 return kFsCacheIAreEqualSlowW(pwcName1, pwcName2, (KU16)cwcName);1556 1557 pwcName2++;1558 pwcName1++;1559 cwcName--;1560 }1561 1562 return K_TRUE;1563 }1564 1565 1566 /**1567 2019 * Look up a child node, UTF-16 version. 1568 2020 * … … 2701 3153 kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC); 2702 3154 3155 KFSCACHE_LOG(("Destroying %s/%s, type=%d\n", pObj->pParent ? pObj->pParent->Obj.pszName : "", pObj->pszName, pObj->bObjType)); 3156 __debugbreak(); 3157 2703 3158 /* 2704 3159 * Invalidate the structure. … … 3243 3698 #endif 3244 3699 pCache->RootDir.cChildren = 0; 3700 pCache->RootDir.cChildrenAllocated = 0; 3245 3701 pCache->RootDir.papChildren = NULL; 3246 3702 pCache->RootDir.hDir = INVALID_HANDLE_VALUE; -
trunk/src/lib/nt/kFsCache.h
r2862 r2863 221 221 /** The number of child objects. */ 222 222 KU32 cChildren; 223 223 /** The allocated size of papChildren. */ 224 KU32 cChildrenAllocated; 225 226 /** Pointer to the hash table. 227 * @todo this isn't quite there yet, structure wise. sigh. */ 228 PKFSOBJHASH paHashTab; 224 229 /** The size of the hash table. 225 230 * @remarks The hash table is optional and only used when there are a lot of 226 231 * entries in the directory. */ 227 232 KU32 cHashTab; 228 /** Pointer to the hash table.229 * @todo this isn't quite there yet, structure wise. sigh. */230 PKFSOBJHASH paHashTab;231 233 232 234 /** Handle to the directory (we generally keep it open). */
Note:
See TracChangeset
for help on using the changeset viewer.