/** Add a lock to an object (primitive). * Set the lock type on thing to boolexp. * This is a primitive routine, to be called by other routines. * It will go somewhat wonky if given a NULL boolexp. * It will allocate memory if called with a string that is not already * in the lock table. * \param player the enactor, for permission checking. * \param thing object on which to set the lock. * \param type type of lock to set. * \param key lock boolexp pointer (should not be NULL!). * \param flags lock flags. * \retval 0 failure. * \retval 1 success. */ int add_lock(dbref player, dbref thing, lock_type type, boolexp key, int flags) { lock_list *ll, **t; lock_type real_type = type; if (!GoodObject(thing)) { return 0; } ll = getlockstruct_noparent(thing, type); if (ll) { if (!can_write_lock(player, thing, ll)) { free_boolexp(key); return 0; } /* We're replacing an existing lock. */ free_boolexp(ll->key); ll->key = key; ll->creator = player; if (flags != -1) ll->flags = flags; } else { ll = next_free_lock(); if (!ll) { /* Oh, this sucks */ do_log(LT_ERR, 0, 0, "Unable to malloc memory for lock_list!"); } else { real_type = st_insert(type, &lock_names); ll->type = real_type; ll->key = key; ll->creator = player; if (flags == -1) { const lock_list *l2 = get_lockproto(real_type); if (l2) ll->flags = l2->flags; else ll->flags = 0; } else { ll->flags = flags; } if (!can_write_lock(player, thing, ll)) { st_delete(real_type, &lock_names); free_boolexp(key); return 0; } t = &Locks(thing); while (*t && strcasecmp(L_TYPE(*t), L_TYPE(ll)) < 0) t = &L_NEXT(*t); L_NEXT(ll) = *t; *t = ll; } } return 1; }
static void ct_generic(dbref player, dbref i, warn_type flags) { if ((flags & W_LOCK_PROBS)) { lock_list *ll; for (ll = Locks(i); ll; ll = L_NEXT(ll)) { check_lock(player, i, L_TYPE(ll), L_KEY(ll)); } } }
void purge_locks(void) { dbref thing; for (thing = 0; thing < db_top; thing++) { lock_list *ll; for (ll = Locks(thing); ll; ll = L_NEXT(ll)) L_KEY(ll) = cleanup_boolexp(L_KEY(ll)); } }
/** Add a lock to an object on db load. * Set the lock type on thing to boolexp. * Used only on db load, when we can't safely test the player's * permissions because they're not loaded yet. * This is a primitive routine, to be called by other routines. * It will go somewhat wonky if given a NULL boolexp. * It will allocate memory if called with a string that is not already * in the lock table. * \param player lock creator. * \param thing object on which to set the lock. * \param type type of lock to set. * \param key lock boolexp pointer (should not be NULL!). * \param flags lock flags. * \retval 0 failure. */ int add_lock_raw(dbref player, dbref thing, lock_type type, boolexp key, privbits flags) { lock_list *ll, **t; lock_type real_type = type; if (!GoodObject(thing)) { return 0; } ll = next_free_lock(Locks(thing)); if (!ll) { /* Oh, this sucks */ do_log(LT_ERR, 0, 0, "Unable to malloc memory for lock_list!"); } else { real_type = st_insert(type, &lock_names); ll->type = real_type; ll->key = key; ll->creator = player; if (flags == LF_DEFAULT) { const lock_list *l2 = get_lockproto(real_type); if (l2) ll->flags = l2->flags; else ll->flags = 0; } else { ll->flags = flags; } t = &Locks(thing); while (*t && strcasecmp(L_TYPE(*t), L_TYPE(ll)) < 0) t = &L_NEXT(*t); L_NEXT(ll) = *t; *t = ll; } return 1; }
/** Migrate some number of chunks. * The requested amount is only a guideline; the actual amount * migrated will be more or less due to always migrating all the * attributes, locks, and mail on any given object together. * \param amount the suggested number of attributes to migrate. */ static void migrate_stuff(int amount) { static int start_obj = 0; static chunk_reference_t **refs = NULL; static int refs_size = 0; int end_obj; int actual; ATTR *aptr; lock_list *lptr; MAIL *mp; if (db_top == 0) return; end_obj = start_obj; actual = 0; do { for (aptr = List(end_obj); aptr; aptr = AL_NEXT(aptr)) if (aptr->data != NULL_CHUNK_REFERENCE) actual++; for (lptr = Locks(end_obj); lptr; lptr = L_NEXT(lptr)) if (L_KEY(lptr) != NULL_CHUNK_REFERENCE) actual++; if (IsPlayer(end_obj)) { for (mp = find_exact_starting_point(end_obj); mp; mp = mp->next) if (mp->msgid != NULL_CHUNK_REFERENCE) actual++; } end_obj = (end_obj + 1) % db_top; } while (actual < amount && end_obj != start_obj); if (actual == 0) return; if (!refs || actual > refs_size) { if (refs) mush_free(refs, "migration reference array"); refs = mush_calloc(actual, sizeof(chunk_reference_t *), "migration reference array"); refs_size = actual; if (!refs) mush_panic("Could not allocate migration reference array"); } #ifdef DEBUG_MIGRATE do_rawlog(LT_TRACE, "Migrate asked %d, actual objects #%d to #%d for %d", amount, start_obj, (end_obj + db_top - 1) % db_top, actual); #endif actual = 0; do { for (aptr = List(start_obj); aptr; aptr = AL_NEXT(aptr)) if (aptr->data != NULL_CHUNK_REFERENCE) { refs[actual] = &(aptr->data); actual++; } for (lptr = Locks(start_obj); lptr; lptr = L_NEXT(lptr)) if (L_KEY(lptr) != NULL_CHUNK_REFERENCE) { refs[actual] = &(lptr->key); actual++; } if (IsPlayer(start_obj)) { for (mp = find_exact_starting_point(start_obj); mp; mp = mp->next) if (mp->msgid != NULL_CHUNK_REFERENCE) { refs[actual] = &(mp->msgid); actual++; } } start_obj = (start_obj + 1) % db_top; } while (start_obj != end_obj); chunk_migration(actual, refs); }