if (fstat(f->fd, &s)) {
goto fail;
}
- f->size = (size_t)s.st_size;
+ f->size = (size_t)s.st_size; // for munmap()
+ // mmap is used for speed and simple random access
void *x = mmap(NULL, f->size, PROT_READ, MAP_PRIVATE, f->fd, 0);
if (x == MAP_FAILED) {
goto fail;
#include <stdlib.h>
+// Magic value at the beginning of each nsscash file (8 byte, without the
+// trailing NUL)
#define MAGIC "NSS-CASH"
// Defined in Makefile
#endif
+// header describes the on-disk (and, after loading via mmap, in-memory)
+// structure of nsscash files.
struct header {
char magic[8]; // magic string
uint64_t version; // also doubles as byte-order check
- uint64_t count;
+ uint64_t count; // number of entries in this file
// All offsets are relative to data
uint64_t off_orig_index;
char data[];
} __attribute__((packed));
+// file represents an open nsscash file.
struct file {
int fd;
size_t size;
struct group_entry {
uint64_t gid;
- // off_name = 0
+ // off_name = 0, not stored on disk
uint16_t off_passwd;
uint16_t off_mem_off;
*
* All offsets are relative to the beginning of data.
*/
- uint16_t data_size;
+ uint16_t data_size; // size of data in bytes
const char data[];
} __attribute__((packed));
static bool entry_to_group(const struct group_entry *e, struct group *g, char *tmp, size_t space) {
+ // Space required for the gr_mem array
const size_t mem_size = (size_t)(e->mem_count + 1) * sizeof(char *);
if (space < e->data_size + mem_size) {
uint64_t uid;
uint64_t gid;
- // off_name = 0
+ // off_name = 0, not stored on disk
uint16_t off_passwd;
uint16_t off_gecos;
uint16_t off_dir;
uint16_t off_shell;
- uint16_t data_size;
/*
* Data contains all strings (name, passwd, gecos, dir, shell)
* concatenated, with their trailing NUL. The off_* variables point to
* beginning of each string.
*/
+ uint16_t data_size; // size of data in bytes
const char data[];
} __attribute__((packed));
static int bsearch_callback(const void *x, const void *y) {
const struct search_key *key = x;
- uint64_t offset = *(const uint64_t *)y;
+ uint64_t offset = *(const uint64_t *)y; // from index
const void *member = (const char *)key->data + offset + key->offset;
- // Lookup by name
+ // Lookup by name (char *)
if (key->name != NULL) {
const char *name = member;
return strcmp(key->name, name);
- // Lookup by ID
+ // Lookup by ID (uint64_t)
} else if (key->id != NULL) {
const uint64_t *id = member;
if (*key->id < *id) {
}
}
+// search performs a binary search on an index, described by key and index.
uint64_t *search(const struct search_key *key, const void *index, uint64_t count) {
return bsearch(key, index, count, sizeof(uint64_t), bsearch_callback);
}
struct search_key {
- const char *name;
- const uint64_t *id;
+ const char *name; // if name != NULL search for a string
+ const uint64_t *id; // if name == NULL search for an id
+ // The actual data with all entries; this is where the full entry
+ // including name/id is located (the index holds an offset into data for
+ // each entry)
const void *data;
+ // Static offset to the search key (name/id) inside the entry; after it
+ // was located by using the index's offset into data
uint64_t offset;
};