Ignore:
Timestamp:
Aug 31, 2016, 10:56:48 PM (9 years ago)
Author:
bird
Message:

updates

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/lib/nt/ntdircache.c

    r2852 r2853  
    4949//#include <winternl.h>
    5050
    51 
    52 
    53 /*********************************************************************************************************************************
    54 *   Defined Constants And Macros                                                                                                 *
    55 *********************************************************************************************************************************/
    56 /** @def KFSCACHE_CFG_UTF16
    57  * Whether to compile in the UTF-16 names support. */
    58 #define KFSCACHE_CFG_UTF16                  1
    59 /** @def KFSCACHE_CFG_SHORT_NAMES
    60  * Whether to compile in the short name support. */
    61 #define KFSCACHE_CFG_SHORT_NAMES            1
    62 /** @def KFSCACHE_CFG_PATH_HASH_TAB_SIZE
    63  * Size of the path hash table. */
    64 #define KFSCACHE_CFG_PATH_HASH_TAB_SIZE     16381
    65 /** The max length paths we consider. */
    66 #define KFSCACHE_CFG_MAX_PATH               1024
    67 /** The max ANSI name length. */
    68 #define KFSCACHE_CFG_MAX_ANSI_NAME          (256*3 + 16)
    69 /** The max UTF-16 name length. */
    70 #define KFSCACHE_CFG_MAX_UTF16_NAME         (256*2 + 16)
    71 
    72 
    73 
    74 /** Special KFSOBJ::uCacheGen number indicating that it does not apply. */
    75 #define KFSWOBJ_CACHE_GEN_IGNORE            KU32_MAX
    76 
    77 /** @def KW_LOG
    78  * Generic logging.
    79  * @param a     Argument list for kFsCacheDbgPrintf  */
    80 #ifndef NDEBUG
    81 # define KFSCACHE_LOG(a) kFsCacheDbgPrintf a
    82 #else
    83 # define KFSCACHE_LOG(a) do { } while (0)
    84 #endif
    85 
    86 
    87 /** @name KFSOBJ_TYPE_XXX - KFSOBJ::bObjType
    88  * @{  */
    89 /** Directory, type KFSDIR. */
    90 #define KFSOBJ_TYPE_DIR         KU8_C(0x01)
    91 /** Regular file - type KFSOBJ. */
    92 #define KFSOBJ_TYPE_FILE        KU8_C(0x02)
    93 /** Other file - type KFSOBJ. */
    94 #define KFSOBJ_TYPE_OTHER       KU8_C(0x03)
    95 /** Caching of a negative result - type KFSOBJ.
    96  * @remarks We will allocate enough space for the largest cache node, so this
    97  *          can metamorph into any other object should it actually turn up.  */
    98 #define KFSOBJ_TYPE_MISSING     KU8_C(0x04)
    99 ///** Invalidated entry flag. */
    100 //#define KFSOBJ_TYPE_F_INVALID   KU8_C(0x20)
    101 /** @} */
    102 
    103 /** @name KFSOBJ_F_XXX - KFSOBJ::fFlags
    104  * @{ */
    105 /** Whether the file system update the modified timestamp of directories
    106  * when something is removed from it or added to it.
    107  * @remarks They say NTFS is the only windows filesystem doing this.  */
    108 #define KFSOBJ_F_WORKING_DIR_MTIME      KU32_C(0x00000001)
    109 /** NTFS file system volume. */
    110 #define KFSOBJ_F_NTFS                   KU32_C(0x80000000)
    111 /** @} */
    112 
    113 
    114 #define IS_ALPHA(ch) ( ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') )
    115 #define IS_SLASH(ch) ((ch) == '\\' || (ch) == '/')
    116 
    117 
    118 /*********************************************************************************************************************************
    119 *   Structures and Typedefs                                                                                                      *
    120 *********************************************************************************************************************************/
    121 /** Pointer to a core object.  */
    122 typedef struct KFSOBJ *PKFSOBJ;
    123 /** Pointer to a directory object.  */
    124 typedef struct KFSDIR *PKFSDIR;
    125 /** Pointer to a directory hash table entry. */
    126 typedef struct KFSOBJHASH *PKFSOBJHASH;
    127 
    128 
    129 /**
    130  * Directory hash table entry.
    131  *
    132  * There can be two of these per directory entry when the short name differs
    133  * from the long name.
    134  */
    135 typedef struct KFSOBJHASH
    136 {
    137     /** Pointer to the next entry with the same hash. */
    138     PKFSOBJHASH         pNext;
    139     /** Pointer to the object. */
    140     PKFSOBJ             pObj;
    141 } KFSOBJHASH;
    142 
    143 
    144 /**
    145  * Base cache node.
    146  */
    147 typedef struct KFSOBJ
    148 {
    149     /** Magic value (KFSOBJ_MAGIC). */
    150     KU32                u32Magic;
    151     /** Number of references. */
    152     KU32 volatile       cRefs;
    153     /** The cache generation, see KFSWOBJ_CACHE_GEN_IGNORE. */
    154     KU32                uCacheGen;
    155     /** The object type, KFSOBJ_TYPE_XXX.   */
    156     KU8                 bObjType;
    157     /** Set if the Stats member is valid, clear if not. */
    158     KBOOL               fHaveStats;
    159     /** Unused flags. */
    160     KBOOL               abUnused[2];
    161     /** Flags, KFSOBJ_F_XXX. */
    162     KU32                fFlags;
    163 
    164     /** Pointer to the parent (directory).
    165      * This is only NULL for a root. */
    166     PKFSDIR             pParent;
    167 
    168     /** The directory name.  (Allocated after the structure.) */
    169     const char         *pszName;
    170     /** The length of pszName. */
    171     KU16                cchName;
    172     /** The length of the parent path (up to where pszName starts).
    173      * @note This is valuable when constructing an absolute path to this node by
    174      *       means of the parent pointer (no need for recursion). */
    175     KU16                cchParent;
    176 #ifdef KFSCACHE_CFG_UTF16
    177     /** The length of pwszName (in wchar_t's). */
    178     KU16                cwcName;
    179     /** The length of the parent UTF-16 path (in wchar_t's).
    180      * @note This is valuable when constructing an absolute path to this node by
    181      *       means of the parent pointer (no need for recursion). */
    182     KU16                cwcParent;
    183     /** The UTF-16 object name.  (Allocated after the structure.) */
    184     const wchar_t      *pwszName;
    185 #endif
    186 
    187 #ifdef KFSCACHE_CFG_SHORT_NAMES
    188     /** The short object name.  (Allocated after the structure, could be same
    189      *  as pszName.) */
    190     const char         *pszShortName;
    191     /** The length of pszShortName. */
    192     KU16                cchShortName;
    193     /** The length of the short parent path (up to where pszShortName starts). */
    194     KU16                cchShortParent;
    195 # ifdef KFSCACHE_CFG_UTF16
    196     /** The length of pwszShortName (in wchar_t's). */
    197     KU16                cwcShortName;
    198     /** The length of the short parent UTF-16 path (in wchar_t's). */
    199     KU16                cwcShortParent;
    200     /** The UTF-16 short object name.  (Allocated after the structure, possibly
    201      *  same as pwszName.) */
    202     const wchar_t      *pwszShortName;
    203 # endif
    204 #endif
    205 
    206     /** Stats - only valid when fHaveStats is set. */
    207     BirdStat_T          Stats;
    208 } KFSOBJ;
    209 
    210 /** The magic for a KFSOBJ structure (Thelonious Sphere Monk). */
    211 #define KFSOBJ_MAGIC                KU32_C(0x19171010)
    212 
    213 
    214 /**
    215  * Directory node in the cache.
    216  */
    217 typedef struct KFSDIR
    218 {
    219     /** The core object information. */
    220     KFSOBJ             Obj;
    221 
    222     /** Child objects. */
    223     PKFSOBJ            *papChildren;
    224     /** The number of child objects. */
    225     KU32                cChildren;
    226 
    227     /** The size of the hash table.
    228      * @remarks The hash table is optional and only used when there are a lot of
    229      *          entries in the directory. */
    230     KU32                cHashTab;
    231     /** Pointer to the hash table.
    232      * @todo this isn't quite there yet, structure wise. sigh.  */
    233     PKFSOBJHASH         paHashTab;
    234 
    235     /** Handle to the directory (we generally keep it open). */
    236     HANDLE              hDir;
    237     /** The device number we queried/inherited when opening it. */
    238     KU64                uDevNo;
    239 
    240     /** Set if populated. */
    241     KBOOL               fPopulated;
    242 } KFSDIR;
    243 
    244 
    245 /**
    246  * Lookup errors.
    247  */
    248 typedef enum KFSLOOKUPERROR
    249 {
    250     /** Lookup was a success. */
    251     KFSLOOKUPERROR_SUCCESS = 0,
    252     /** A path component was not found. */
    253     KFSLOOKUPERROR_PATH_COMP_NOT_FOUND,
    254     /** A path component is not a directory. */
    255     KFSLOOKUPERROR_PATH_COMP_NOT_DIR,
    256     /** The final path entry is not a directory (trailing slash). */
    257     KFSLOOKUPERROR_NOT_DIR,
    258     /** Not found. */
    259     KFSLOOKUPERROR_NOT_FOUND,
    260     /** The path is too long. */
    261     KFSLOOKUPERROR_PATH_TOO_LONG,
    262     /** Unsupported path type. */
    263     KFSLOOKUPERROR_UNSUPPORTED,
    264     /** We're out of memory. */
    265     KFSLOOKUPERROR_OUT_OF_MEMORY,
    266 
    267     /** Error opening directory. */
    268     KFSLOOKUPERROR_DIR_OPEN_ERROR,
    269     /** Error reading directory. */
    270     KFSLOOKUPERROR_DIR_READ_ERROR,
    271     /** UTF-16 to ANSI conversion error. */
    272     KFSLOOKUPERROR_ANSI_CONVERSION_ERROR,
    273     /** ANSI to UTF-16 conversion error. */
    274     KFSLOOKUPERROR_UTF16_CONVERSION_ERROR,
    275     /** Internal error. */
    276     KFSLOOKUPERROR_INTERNAL_ERROR
    277 } KFSLOOKUPERROR;
    278 
    279 
    280 /** Pointer to an ANSI path hash table entry. */
    281 typedef struct KFSHASHA *PKFSHASHA;
    282 /**
    283  * ANSI file system path hash table entry.
    284  * The path hash table allows us to skip parsing and walking a path.
    285  */
    286 typedef struct KFSHASHA
    287 {
    288     /** Next entry with the same hash table slot. */
    289     PKFSHASHA           pNext;
    290     /** Path hash value. */
    291     KU32                uHashPath;
    292     /** The path length. */
    293     KU32                cchPath;
    294     /** The cache generation ID. */
    295     KU32                uCacheGen;
    296     /** The lookup error (when pFsObj is NULL). */
    297     KFSLOOKUPERROR      enmError;
    298     /** The path.  (Allocated after the structure.) */
    299     const char         *pszPath;
    300     /** Pointer to the matching FS object.
    301      * This is NULL for negative path entries? */
    302     PKFSOBJ             pFsObj;
    303 } KFSHASHA;
    304 
    305 
    306 #ifdef KFSCACHE_CFG_UTF16
    307 /** Pointer to an UTF-16 path hash table entry. */
    308 typedef struct KFSHASHW *PKFSHASHW;
    309 /**
    310  * UTF-16 file system path hash table entry. The path hash table allows us
    311  * to skip parsing and walking a path.
    312  */
    313 typedef struct KFSHASHW
    314 {
    315     /** Next entry with the same hash table slot. */
    316     PKFSHASHW           pNext;
    317     /** Path hash value. */
    318     KU32                uHashPath;
    319     /** The path length (in wchar_t units). */
    320     KU32                cwcPath;
    321     /** The cache generation ID. */
    322     KU32                uCacheGen;
    323     /** The lookup error (when pFsObj is NULL). */
    324     KFSLOOKUPERROR      enmError;
    325     /** The path.  (Allocated after the structure.) */
    326     const wchar_t      *pwszPath;
    327     /** Pointer to the matching FS object.
    328      * This is NULL for negative path entries? */
    329     PKFSOBJ             pFsObj;
    330 } KFSHASHW;
    331 #endif
    332 
    333 
    334 /** @name KFSCACHE_F_XXX
    335  * @{ */
    336 /** Whether to cache missing directory entries (KFSOBJ_TYPE_MISSING). */
    337 #define KFSCACHE_F_MISSING_OBJECTS  KU32_C(0x00000001)
    338 /** Whether to cache missing paths. */
    339 #define KFSCACHE_F_MISSING_PATHS    KU32_C(0x00000002)
    340 /** @} */
    341 
    342 
    343 /** Pointer to a cache.   */
    344 typedef struct KFSCACHE *PKFSCACHE;
    345 /**
    346  * Directory cache instance.
    347  */
    348 typedef struct KFSCACHE
    349 {
    350     /** Magic value (KFSCACHE_MAGIC). */
    351     KU32                u32Magic;
    352     /** Cache flags. */
    353     KU32                fFlags;
    354 
    355     /** The current cache generation for objects that already exists. */
    356     KU32                uGeneration;
    357     /** The current cache generation for missing objects, negative results, ++. */
    358     KU32                uGenerationMissing;
    359 
    360     /** Number of cache objects. */
    361     KSIZE               cObjects;
    362     /** Memory occupied by the cache object structures. */
    363     KSIZE               cbObjects;
    364     /** Number of lookups. */
    365     KSIZE               cLookups;
    366     /** Number of hits in the path hash tables. */
    367     KSIZE               cPathHashHits;
    368     /** Number of hits walking the file system hierarchy. */
    369     KSIZE               cWalkHits;
    370 
    371     /** The root directory. */
    372     KFSDIR              RootDir;
    373 
    374     /** File system hash table for ANSI filename strings. */
    375     PKFSHASHA           apAnsiPaths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE];
    376     /** Number of paths in the apAnsiPaths hash table. */
    377     KSIZE               cAnsiPaths;
    378     /** Number of collisions in the apAnsiPaths hash table. */
    379     KSIZE               cAnsiPathCollisions;
    380     /** Amount of memory used by the path entries. */
    381     KSIZE               cbAnsiPaths;
    382 
    383 #ifdef KFSCACHE_CFG_UTF16
    384     /** Number of paths in the apUtf16Paths hash table. */
    385     KSIZE               cUtf16Paths;
    386     /** Number of collisions in the apUtf16Paths hash table. */
    387     KSIZE               cUtf16PathCollisions;
    388     /** Amount of memory used by the UTF-16 path entries. */
    389     KSIZE               cbUtf16Paths;
    390     /** File system hash table for UTF-16 filename strings. */
    391     PKFSHASHW           apUtf16Paths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE];
    392 #endif
    393 } KFSCACHE;
    394 
    395 /** Magic value for KFSCACHE::u32Magic (Jon Batiste).  */
    396 #define KFSCACHE_MAGIC              KU32_C(0x19861111)
    397 
    398 
    399 /*********************************************************************************************************************************
    400 *   Internal Functions                                                                                                           *
    401 *********************************************************************************************************************************/
    402 KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj);
     51#include "kFsCache.h"
     52
     53
     54
    40355
    40456
     
    42577 * @param   ...                 Format argument.
    42678 */
    427 static void kFsCacheDbgPrintfV(const char *pszFormat, va_list va)
     79void kFsCacheDbgPrintfV(const char *pszFormat, va_list va)
    42880{
    42981    if (1)
     
    44496 * @param   ...                 Format argument.
    44597 */
    446 static void kFsCacheDbgPrintf(const char *pszFormat, ...)
     98void kFsCacheDbgPrintf(const char *pszFormat, ...)
    44799{
    448100    if (1)
     
    927579            pHashEntry->uCacheGen = pCache->uGenerationMissing;
    928580        else
    929             pHashEntry->uCacheGen = KFSWOBJ_CACHE_GEN_IGNORE;
     581            pHashEntry->uCacheGen = KFSOBJ_CACHE_GEN_IGNORE;
    930582
    931583        pHashEntry->pNext = pCache->apAnsiPaths[idxHashTab];
     
    969621            pHashEntry->uCacheGen = pCache->uGenerationMissing;
    970622        else
    971             pHashEntry->uCacheGen = KFSWOBJ_CACHE_GEN_IGNORE;
     623            pHashEntry->uCacheGen = KFSOBJ_CACHE_GEN_IGNORE;
    972624
    973625        pHashEntry->pNext = pCache->apUtf16Paths[idxHashTab];
     
    1026678 * @param   penmError       Where to explain failures.
    1027679 */
    1028 static PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,
    1029                                     char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName,
     680PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,
     681                             char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName,
    1030682#ifdef KFSCACHE_CFG_SHORT_NAMES
    1031                                     char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName,
    1032 #endif
    1033                                     KU8 bObjType, KFSLOOKUPERROR *penmError)
     683                             char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName,
     684#endif
     685                             KU8 bObjType, KFSLOOKUPERROR *penmError)
    1034686{
    1035687    /*
     
    1149801 * @param   penmError       Where to explain failures.
    1150802 */
    1151 static PKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName,
     803PKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName,
    1152804#ifdef KFSCACHE_CFG_SHORT_NAMES
    1153                                      wchar_t const *pwszShortName, KU32 cwcShortName,
    1154 #endif
    1155                                      KU8 bObjType, KFSLOOKUPERROR *penmError)
     805                              wchar_t const *pwszShortName, KU32 cwcShortName,
     806#endif
     807                              KU8 bObjType, KFSLOOKUPERROR *penmError)
    1156808{
    1157809    /* Convert names to ANSI first so we know their lengths. */
     
    20061658    if (offEnd >= cchPath)
    20071659    {
    2008         if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1660        if (   pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    20091661            || pChild->uCacheGen == (pChild->bObjType != KFSOBJ_TYPE_MISSING ? pCache->uGeneration : pCache->uGenerationMissing)
    20101662            || kFsCacheRefreshObj(pCache, pChild, penmError))
     
    20191671    {
    20201672        kHlpAssert(pChild->bObjType == KFSOBJ_TYPE_MISSING);
    2021         kHlpAssert(pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);
     1673        kHlpAssert(pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);
    20221674        return pChild;
    20231675    }
     
    20561708         */
    20571709        if (   pParent->fPopulated
    2058             && (   pParent->Obj.uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1710            && (   pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    20591711                || pParent->Obj.uCacheGen == pCache->uGeneration) )
    20601712        { /* likely */ }
     
    20941746        {
    20951747            if (   pChild->bObjType != KFSOBJ_TYPE_MISSING
    2096                 || pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1748                || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    20971749                || pChild->uCacheGen == pCache->uGenerationMissing
    20981750                || kFsCacheRefreshMissing(pCache, pChild, penmError) )
     
    21141766            return NULL;
    21151767        }
    2116         else if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1768        else if (   pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    21171769                 || pChild->uCacheGen == pCache->uGenerationMissing)
    21181770        {
     
    21941846    if (offEnd >= cwcPath)
    21951847    {
    2196         if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1848        if (   pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    21971849            || pChild->uCacheGen == (pChild->bObjType != KFSOBJ_TYPE_MISSING ? pCache->uGeneration : pCache->uGenerationMissing)
    21981850            || kFsCacheRefreshObj(pCache, pChild, penmError))
     
    22071859    {
    22081860        kHlpAssert(pChild->bObjType == KFSOBJ_TYPE_MISSING);
    2209         kHlpAssert(pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);
     1861        kHlpAssert(pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);
    22101862        return pChild;
    22111863    }
     
    22441896         */
    22451897        if (   pParent->fPopulated
    2246             && (   pParent->Obj.uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1898            && (   pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    22471899                || pParent->Obj.uCacheGen == pCache->uGeneration) )
    22481900        { /* likely */ }
     
    22821934        {
    22831935            if (   pChild->bObjType != KFSOBJ_TYPE_MISSING
    2284                 || pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1936                || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    22851937                || pChild->uCacheGen == pCache->uGenerationMissing
    22861938                || kFsCacheRefreshMissing(pCache, pChild, penmError) )
     
    23021954            return NULL;
    23031955        }
    2304         else if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1956        else if (   pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    23051957                 || pChild->uCacheGen == pCache->uGenerationMissing)
    23061958        {
     
    24872139                && kHlpMemComp(pHashEntry->pszPath, pszPath, cchPath) == 0)
    24882140            {
    2489                 if (   pHashEntry->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     2141                if (   pHashEntry->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    24902142                    || pHashEntry->uCacheGen == pCache->uGeneration
    24912143                    || (pHashEntry = kFsCacheRefreshPathA(pCache, pHashEntry, idxHashTab)) )
     
    25762228                && kHlpMemComp(pHashEntry->pwszPath, pwszPath, cwcPath) == 0)
    25772229            {
    2578                 if (   pHashEntry->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     2230                if (   pHashEntry->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    25792231                    || pHashEntry->uCacheGen == pCache->uGeneration
    25802232                    || (pHashEntry = kFsCacheRefreshPathW(pCache, pHashEntry, idxHashTab)) )
     
    27072359        pCache->RootDir.Obj.u32Magic        = KFSOBJ_MAGIC;
    27082360        pCache->RootDir.Obj.cRefs           = 1;
    2709         pCache->RootDir.Obj.uCacheGen       = KFSWOBJ_CACHE_GEN_IGNORE;
     2361        pCache->RootDir.Obj.uCacheGen       = KFSOBJ_CACHE_GEN_IGNORE;
    27102362        pCache->RootDir.Obj.bObjType        = KFSOBJ_TYPE_DIR;
    27112363        pCache->RootDir.Obj.fHaveStats      = K_FALSE;
Note: See TracChangeset for help on using the changeset viewer.