core: import NSS bitmap helper directly into libnwcore
All checks were successful
Source release / source-package (push) Successful in 1m10s

This commit is contained in:
Mario Fetka
2026-06-12 13:17:45 +00:00
parent ae3417fa0a
commit e75cb77a3b
5 changed files with 403 additions and 0 deletions

9
AI.md
View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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)

374
src/core/bitmap.c Normal file
View File

@@ -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 <stdlib.h>
/*
* 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 <stdlib.h>
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