diff --git a/AI.md b/AI.md index 8f4bb60..30798a5 100644 --- a/AI.md +++ b/AI.md @@ -2400,3 +2400,12 @@ logs/archives are usually copied or uploaded later by a normal desktop user. (`no-device`, `unsupported`, `probe-failed`). A real Linuxquota `set-failed` on a QUOTA-style volume is an error to fix, not a reason to create a parallel metadata-authoritative state. + +## NSS low-level library import policy + +- Keep original NSS file names and public API names when importing small GPL-2 NSS library helpers. +- Do not hide imported helpers under an artificial `nss/` public API/source path in `libnwcore`; imported core helpers live directly in `src/core/` and expose the original header/API names so their NSS origin remains recognizable. +- First imported compiled helper: NSS `public_core/nss/lib/bitmap.c` -> MARS-NWE `src/core/bitmap.c`, linked into `libnwcore` with original `bitmap.h` API (`BitMap_s`, `newBitMap`, `findBits`, etc.). +- The existing NSS SDK include layout under `include/nwfs/nss/sdk/...` remains available for compatibility and provenance; the compiled library source is what moves into `src/core/`. +- NSS runtime-only dependencies may be reduced only as needed to compile outside NSS; for bitmap this only maps NSS `zalloc()` to libc `calloc()`. +- Future candidates to import with original names: CRC/hash helpers after Unicode dependency review, queue macros, bit helpers, and media/type helpers already represented by the SDK headers. diff --git a/REDESIGN.md b/REDESIGN.md index dd10ae0..121d167 100644 --- a/REDESIGN.md +++ b/REDESIGN.md @@ -3568,3 +3568,11 @@ restore source, not an alternate authority after a kernel `set-failed`. - No private MARS persistent usage xattr is part of the design. - The live all-smoke and DOS board-tool quota smoke are the regression gates for this area. + + +### NSS low-level library imports + +- Prefer importing small GPL-2 NSS low-level library helpers with original file/API names where they can be compiled outside the NSS runtime. +- Imported compiled helpers should live directly in `libnwcore` source/include space rather than in an artificial `nss/` subpath; existing NSS SDK compatibility headers may keep their original source-like paths. +- Initial compiled import is `bitmap.c`/`bitmap.h` in `libnwcore`; replace local duplicate bitmap/bit allocation helpers gradually only after tests cover each call site. +- Keep libowfat-provided primitives where they are already the better fit; use NSS helpers where NetWare/NSS source compatibility or media-layout semantics matter. diff --git a/TODO.md b/TODO.md index 40ffb0a..683cd75 100644 --- a/TODO.md +++ b/TODO.md @@ -190,3 +190,11 @@ These items are no longer active TODOs. Keep patch-by-patch chronology in SYS metadata, NWQUOTA userquota and an `nw.log` slice. - The DOS quota smoke proves the same write-deny boundary from DOS board tools for both `QUOTA` and `SYS`. + + +### NSS low-level library imports + +- Import small GPL-2 NSS low-level library helpers with original file/API names where they can be compiled outside the NSS runtime. +- Keep imported compiled helpers directly in `src/core/`/`libnwcore`, not under a new artificial `nss/` subdirectory; preserve original names so the NSS provenance and possible external-source compatibility remain clear. +- Initial compiled import is `bitmap.c`/`bitmap.h` in `libnwcore`; replace local duplicate bitmap/bit allocation helpers gradually only after tests cover each call site. +- Keep libowfat-provided primitives where they are already the better fit; use NSS helpers where NetWare/NSS source compatibility or media-layout semantics matter. diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c71aa04..3eaf256 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -40,9 +40,13 @@ configure_file( "${NWCORE_BUILD_INCLUDE_DIR}/yyjson.h" COPYONLY) +set(NWCORE_IMPORTED_NSS_SOURCES + bitmap.c) + add_library(nwcore SHARED core.c ${NWCORE_ZLOG_SOURCES} + ${NWCORE_IMPORTED_NSS_SOURCES} "${NWCORE_YYJSON_DIR}/src/yyjson.c") add_library(mars_nwe::core ALIAS nwcore) diff --git a/src/core/bitmap.c b/src/core/bitmap.c new file mode 100644 index 0000000..446b587 --- /dev/null +++ b/src/core/bitmap.c @@ -0,0 +1,374 @@ +/**************************************************************************** + | + | (C) Copyright 1995-2005 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Services (NSS) Initialization module + | + |--------------------------------------------------------------------------- + | + | $Author: randys $ + | $Date: 2005-01-11 23:43:47 +0530 (Tue, 11 Jan 2005) $ + | + | $RCSfile$ + | $Revision: 511 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Define routines for manipulating bit maps. + +-------------------------------------------------------------------------*/ +#include + +/* + * MARS-NWE imports this NSS low-level helper with its original public + * function names and header name. The file is installed directly in the + * libnwcore source directory instead of an artificial nss/ subdirectory so + * the original NSS API remains recognizable. The original NSS source path + * is public_core/nss/lib/bitmap.c. NSS normally gets zalloc() from its + * loader/runtime library; libnwcore builds the helper outside that runtime, + * so map the allocator to libc calloc while keeping the NSS API surface. + */ +#ifndef zalloc +#define zalloc(_bytes) calloc(1, (_bytes)) +#endif + +#include "omni.h" +#include "bitmap.h" + +NINT getMaxBits (BitMap_s *bitMap) +{ + return bitMap->max; +} + +BOOL testABit (BitMap_s *bitMap, NINT bitNum) +{ + return TST_BIT(bitMap->bits, bitNum); +} +void setAbit (BitMap_s *bitMap, NINT bitNum) +{ + SET_BIT(bitMap->bits, bitNum); + if (bitNum < bitMap->start) + { + bitMap->start = bitNum; + } +} + +void setBits (BitMap_s *bitMap, NINT startBit, NINT numBits) +{ + NINT *bits = bitMap->bits; + NINT endBit = startBit + numBits; + NINT i; + + if (endBit > bitMap->max) + { + endBit = bitMap->max; + } + for (i = startBit; i < endBit; ++i) + { + SET_BIT(bits, i); + } + if (startBit < bitMap->start) + { + bitMap->start = startBit; + } +} + +void clearAbit (BitMap_s *bitMap, NINT bitNum) +{ + NINT *bits = bitMap->bits; + + CLR_BIT(bits, bitNum); +} + +void clearBits (BitMap_s *bitMap, NINT startBit, NINT numBits) +{ + NINT *bits = bitMap->bits; + NINT endBit = startBit + numBits; + NINT i; + + if (endBit > bitMap->max) + { + endBit = bitMap->max; + } + for (i = startBit; i < endBit; ++i) + { + CLR_BIT(bits, i); + } +} + +BitMap_s *newBitMap (BitMap_s *bitMap, NINT numBits) +{ + NINT max = ALIGN(numBits, BITS_PER_NINT); + NINT numBytes = max / BITS_PER_BYTE; + NINT *bits; + + bits = zalloc(numBytes); + if (bits == NULL) return NULL; + + bitMap->bits = bits; + bitMap->max = max; + bitMap->start = 0; + + setBits(bitMap, 0, numBits); + bitMap->max = numBits; + + return bitMap; +} + +void freeBitMap (BitMap_s *bitMap) +{ + if (bitMap->bits != NULL) + { + free(bitMap->bits); + } +} + +NINT countBits (BitMap_s *bitMap) +{ + NINT *bits = bitMap->bits; + NINT max = bitMap->max; + NINT numBits = 0; + NINT i; + + for (i = 0; i < max; ++i) + { + if (TST_BIT(bits, i)) + { + ++numBits; + } + } + return numBits; +} + +SNINT findBits (BitMap_s *bitMap, NINT bitsNeeded) +{ + NINT *bits = bitMap->bits; + NINT numBits = 0; + NINT start = 0; + NINT i; + + /* + * Position start at the first set bit + */ + for (i = bitMap->start; i < bitMap->max; ++i) + { + if (TST_BIT(bits, i)) + { + break; + } + } + bitMap->start = i; + + for (; i < bitMap->max; ++i) + { + if (TST_BIT(bits, i)) + { + ++numBits; + if (numBits == bitsNeeded) + { + start = (i + 1) - numBits; + clearBits(bitMap, start, numBits); + return start; + } + } + else + { + numBits = 0; + } + } + return -1; +} + +#if 0 + +void printBitMap (BitMap_s *bitMap) +{ + NINT i; + const NINT max = bitMap->max; + const NINT *bits = bitMap->bits; + + printf(" max = %3d start = %3d\n", bitMap->max, bitMap->start); + for (i = 0; i < max; ++i) + { + if (TST_BIT(bits, i)) + { + printf("%d", i % 10); + } + else + { + printf("."); + } + if ((i + 1) % 64 == 0) + { + printf("\n"); + } + } +// printf(" %d", countBits(bitMap)); +// if (i % 64 != 0) printf("\n"); +} +#include + +typedef struct Allocated_s { + NINT start; + NINT length; +} Allocated_s; + +enum { + USERS = 20, + BLOCKS = 8, +}; + +Allocated_s Users[USERS] = { 0 }; +BitMap_s BitMap; +BitMap_s UsedBits; + +void printUsers (void) +{ + NINT i; + + printf("Users:\n"); + for (i = 0; i < USERS; ++i) { + printf("%d. %10d %10d\n", i, Users[i].start, Users[i].length); + } +} + +void outOfMemory (NINT length) +{ + printf("Could not allocate %d\n", length); + + printBitMap( &BitMap); + + printUsers(); +} + +void checkUsers (void) +{ + NINT i, j; + + for (i = 0; i < USERS; ++i) { + if (Users[i].length == 0) continue; + for (j = 0; j < USERS; ++j) { + if (i == j) continue; + if (Users[j].length == 0) continue; + if (Users[i].start + Users[i].length <= Users[j].start) continue; + if (Users[j].start + Users[j].length <= Users[i].start) continue; + printf("Overlapping users: %d %d\n", i, j); + printUsers(); + exit(1); + } + } +} + +int main (int argc, char *argv[]) +{ + Allocated_s *user; + NINT length; + SNINT start; + NINT i, j; + + if (newBitMap( &BitMap, BLOCKS) == NULL) return 1; + if (newBitMap( &UsedBits, BLOCKS) == NULL) return 2; + clearBits( &UsedBits, 0, BLOCKS); + clearBits( &BitMap, 0, BLOCKS); + + SET_BIT(BitMap.bits, BLOCKS); + setBits( &BitMap, 0, BLOCKS); + for (i = 0; i < 1000; ++i) + { + printBitMap( &BitMap); + if (findBits( &BitMap, 4) == -1) + { + for (j = 0; j < 3*BLOCKS / 4; ++j) + { + setAbit( &BitMap, rand() % BLOCKS); + } + } + } + + for (i = 0; i < 1000; ++i) + { + NINT bitNum = rand() % BLOCKS; + NINT numBits = 2; + + printBitMap( &BitMap); + if (TST_BIT(BitMap.bits, bitNum)) + { +printf(" Clear %3d ", bitNum); + clearBits( &BitMap, bitNum, numBits); + //clearAbit( &BitMap, bitNum); + } + else + { +printf(" Set %3d ", bitNum); + setBits( &BitMap, bitNum, numBits); + //setAbit( &BitMap, bitNum); + } + } + printBitMap( &BitMap); +#if 0 + for (i = 0; i < 30; ++i) { +// printBitMap( &BitMap); +// printUsers(); + checkUsers(); + user = &Users[rand() % USERS]; + if (user->length == 0) { + length = rand() % (BLOCKS / 6) + 1; + start = findBits( &BitMap, length); + if (start < 0) { + NINT freeBits = countBits( &BitMap); + + printf("%d %d %f\n", length, freeBits, + (double)freeBits / (double)length); +// outOfMemory(length); + } else { + user->length = length; + user->start = start; + } + } else { + setBits( &BitMap, user->start, user->length); + user->length = 0; + user->start = -1; + } + } +/***************************************************************/ + if (newBitMap( &BitMap, BLOCKS) == NULL) return 1; + if (newBitMap( &UsedBits, BLOCKS) == NULL) return 2; + clearBits( &UsedBits, 0, BLOCKS); + + for (i = 0; i < 10000; ++i) + { + NINT bitNum = rand() % BLOCKS; + + if (TST_BIT(BitMap.bits, bitNum)) + { + clearAbit( &BitMap, bitNum); + } + else + { + setAbit( &BitMap, bitNum); + } + } + printf(" high=%d low = %d\n", BitMap.high, BitMap.low); + printf("minHigh=%d maxLow = %d\n", BitMap.minHigh, BitMap.maxLow); +#endif + return 0; +} + +#endif