📄 cde40.c
字号:
/* Copyright (C) 2001-2005 by Hans Reiser, licensing governed by reiser4progs/COPYING. cde40.c -- reiser4 directory entry plugin. */#include "cde40.h"#include "cde40_repair.h"reiser4_core_t *cde40_core = NULL;inline uint32_t cde40_key_pol(reiser4_place_t *place) { return plugcall(place->key.plug, bodysize);}/* Returns pointer to entry */inline void *cde40_entry(reiser4_place_t *place, uint32_t pos) { return cde_get_entry(place, pos, cde40_key_pol(place));}/* Returns pointer to the objectid entry component. */inline void *cde40_objid(reiser4_place_t *place, uint32_t pos) { return (place->body + en_get_offset(cde40_entry(place, pos), cde40_key_pol(place)));}/* Returns pointer to entry offset */static inline void *cde40_hash(reiser4_place_t *place, uint32_t pos) { return cde40_entry(place, pos);}/* Returns statdata key of the object entry points to */static void cde40_get_obj(reiser4_place_t *place, uint32_t pos, reiser4_key_t *key){ aal_memset(key, 0, sizeof(*key)); key->plug = place->key.plug; aal_memcpy(key->body, cde40_objid(place, pos), ob_size(cde40_key_pol(place)));}/* Stores entry offset (hash) to passed @key */errno_t cde40_get_hash(reiser4_place_t *place, uint32_t pos, reiser4_key_t *key){ void *hash; uint32_t pol; uint64_t locality; pol = cde40_key_pol(place); hash = cde40_hash(place, pos); /* Getting item key params */ locality = objcall(&place->key, get_locality); /* Building the full key from entry at @place */ plugcall(place->key.plug, build_generic, key, KEY_FILENAME_TYPE, locality, ha_get_ordering(hash, pol), ha_get_objectid(hash, pol), ha_get_offset(hash, pol)); return 0;}#ifndef ENABLE_MINIMAL/* Set the key for the entry->offset. It is needed for fixing entry keys if repair code detects it is wrong. */errno_t cde40_set_hash(reiser4_place_t *place, uint32_t pos, reiser4_key_t *key){ void *hash; uint32_t pol; uint64_t offset; uint64_t objectid; uint64_t ordering; pol = cde40_key_pol(place); hash = cde40_hash(place, pos); ordering = objcall(&place->key, get_ordering); objectid = objcall(&place->key, get_fobjectid); offset = objcall(&place->key, get_offset); ha_set_ordering(hash, ordering, pol); ha_set_objectid(hash, objectid, pol); ha_set_offset(hash, offset, pol); return 0;}#endif/* Extracts entry name from the passed @entry to passed @buff */char *cde40_get_name(reiser4_place_t *place, uint32_t pos, char *buff, uint32_t len){ reiser4_key_t key; cde40_get_hash(place, pos, &key); /* If name is long, we just copy it from the area after objectid. Otherwise we extract it from the entry hash. */ if (objcall(&key, hashed)) { char *ptr = (char *)(cde40_objid(place, pos) + ob_size(cde40_key_pol(place))); aal_strncpy(buff, ptr, len); } else { objcall(&key, get_name, buff); } return buff;}#ifndef ENABLE_MINIMAL/* Calculates entry length. This function is widely used in shift code and modification code. */static uint32_t cde40_get_len(reiser4_place_t *place, uint32_t pos) { uint32_t len; uint32_t pol; reiser4_key_t key; /* Counting objid size */ pol = cde40_key_pol(place); len = ob_size(pol); /* Getting entry key */ cde40_get_hash(place, pos, &key); /* If entry contains long name it is stored just after objectid. Otherwise, entry name is stored in objectid and offset of the entry. This trick saves a lot of space in directories, because the average name is shorter than 15 symbols. */ if (objcall(&key, hashed)) { len += aal_strlen((char *)(cde40_objid(place, pos) + ob_size(pol))) + 1; } return len;}/* Updates entry offset. It is needed for fixing entry keys if repair code detects it is wrong. */errno_t cde40_update_key(reiser4_place_t *place, reiser4_key_t *key) { aal_assert("vpf-1228", key != NULL); aal_assert("vpf-1229", place != NULL); aal_assert("vpf-1230", place->body != NULL); return cde40_set_hash(place, place->pos.unit, key);}#endif/* Builds full key by entry components. It is needed for updating keys after shift, insert, etc. Also library requires unit keys sometims. */errno_t cde40_fetch_key(reiser4_place_t *place, reiser4_key_t *key) { aal_assert("umka-1606", key != NULL); aal_assert("umka-1607", place != NULL); aal_assert("umka-1605", place->body != NULL); return cde40_get_hash(place, place->pos.unit, key);}/* Returns the number of units. */uint32_t cde40_units(reiser4_place_t *place) { aal_assert("umka-865", place != NULL); return cde_get_units(place);}/* Fetches some number of cde items to passed @hint. */static int64_t cde40_fetch_units(reiser4_place_t *place, trans_hint_t *hint) { uint32_t i, pos; entry_hint_t *entry; aal_assert("umka-1418", hint != NULL); aal_assert("umka-866", place != NULL); pos = place->pos.unit; entry = (entry_hint_t *)hint->specific; for (i = pos; i < pos + hint->count; i++, entry++) { /* Get object stat data key. */ cde40_get_obj(place, i, &entry->object); /* Get entry key (hash). */ cde40_get_hash(place, i, &entry->offset); /* Extract entry name. */ cde40_get_name(place, i, entry->name, sizeof(entry->name)); } return hint->count;}#ifndef ENABLE_MINIMALuint16_t cde40_overhead() { return sizeof(cde40_t);}/* Returns 1 if items are mergeable, 0 -- otherwise. That is if they belong to the same directory. This function is used in shift code from the node plugin in order to determine are two items may be merged or not. */static int cde40_mergeable(reiser4_place_t *place1, reiser4_place_t *place2) { aal_assert("umka-1581", place1 != NULL); aal_assert("umka-1582", place2 != NULL); /* Items mergeable if their short keys match. */ return !objcall(&place1->key, compshort, &place2->key);}/* Calculates the size of @count units (entries) in passed @place at passed @pos. */uint32_t cde40_regsize(reiser4_place_t *place, uint32_t pos, uint32_t count) { uint32_t pol; uint32_t size; void *entry_end; void *entry_start; if (count == 0) return 0; pol = cde40_key_pol(place); entry_start = cde40_entry(place, pos); if (pos + count < cde_get_units(place)) { size = 0; entry_end = cde40_entry(place, pos + count); } else { entry_end = cde40_entry(place, pos + count - 1); size = cde40_get_len(place, pos + count - 1); } size += (en_get_offset(entry_end, pol) - en_get_offset(entry_start, pol)); return size;}/* Makes copy of @count amount of units from @src_item to @dst_one */errno_t cde40_copy(reiser4_place_t *dst, uint32_t dst_pos, reiser4_place_t *src, uint32_t src_pos, uint32_t count){ uint32_t i; void *entry; uint32_t pol; uint32_t size; uint32_t offset; uint32_t headers; void *dstp, *srcp; uint32_t dst_units; aal_assert("umka-2069", dst != NULL); aal_assert("umka-2070", src != NULL); pol = cde40_key_pol(dst); dst_units = cde40_units(dst); aal_assert("umka-2077", dst_pos <= dst_units); /* Getting offset of body in dst place. Do not just call regsize because in the case of expanding dst_pos offset points to the wrong place. */ offset = dst_pos ? cde40_regsize(dst, 0, dst_pos - 1) + cde40_get_len(dst, dst_pos - 1) : 0; /* Copying entry headers */ srcp = src->body + sizeof(cde40_t) + (src_pos * en_size(pol)); dstp = dst->body + sizeof(cde40_t) + (dst_pos * en_size(pol)); headers = count * en_size(pol); aal_memcpy(dstp, srcp, headers); /* Copying entry bodies */ srcp = src->body + en_get_offset(srcp, pol); dstp = dst->body + sizeof(cde40_t) + (dst_units * en_size(pol)) + headers + offset; size = cde40_regsize(src, src_pos, count); aal_memcpy(dstp, srcp, size); /* Updating offset of dst cde */ entry = cde40_entry(dst, dst_pos); offset += sizeof(cde40_t) + (dst_units * en_size(pol)) + headers; for (i = 0; i < count; i++) { en_set_offset(entry, offset, pol); offset += cde40_get_len(src, src_pos + i); entry += en_size(pol); } /* Updating cde units */ cde_inc_units(dst, count); /* Updating item key by unit key if the first unit waqs changed. It is needed for correct updating left delimiting keys. */ if (dst_pos == 0) { cde40_get_hash(dst, 0, &dst->key); } place_mkdirty(dst); return 0;}/* Shrinks cde item in order to delete some entries */static uint32_t cde40_shrink(reiser4_place_t *place, uint32_t pos, uint32_t count){ uint32_t units, len, pol; void *entry; aal_assert("vpf-1561", place != NULL); pol = cde40_key_pol(place); units = cde_get_units(place); aal_assert("vpf-1562", pos < units); if (pos + count > units) count = units - pos; if (count == 0) return 0; /* Get the length of the item on the basis of the last unit. */ entry = cde40_entry(place, units - 1); len = en_get_offset(entry, pol) + cde40_get_len(place, units - 1); return cde40_cut(place, pos, count, len);}/* Cuts some units from cde item without analyzing the unit content, namely without calling cde40_get_len. @len is the length of the item. */uint32_t cde40_cut(reiser4_place_t *place, uint32_t pos, uint32_t count, uint32_t len){ void *entry; uint32_t pol; uint32_t i, units; uint32_t first, second; uint32_t headers, remove; aal_assert("umka-1959", place != NULL); pol = cde40_key_pol(place); units = cde_get_units(place); aal_assert("umka-1681", pos < units); if (pos + count > units) count = units - pos; if (count == 0) return 0; headers = count * en_size(pol); /* Getting how many bytes should be moved before passed @pos */ first = (units - (pos + count)) * en_size(pol); first += cde40_regsize(place, 0, pos); /* Getting how many bytes should be moved after passed @pos */ entry = cde40_entry(place, pos + count); second = (pos + count == units) ? 0 : len - en_get_offset(entry, pol); /* Getting how many bytes should be removed */ entry = cde40_entry(place, pos); remove = (pos + count == units) ? len - en_get_offset(entry, pol) : cde40_regsize(place, pos, count); /* Moving headers and first part of bodies (before passed @pos) */ entry = cde40_entry(place, pos); aal_memmove(entry, entry + (en_size(pol) * count), first); /* Setting up the entry offsets */ entry = cde40_entry(place, 0); for (i = 0; i < pos; i++) { en_dec_offset(entry, headers, pol); entry += en_size(pol); } /* We also move the rest of the data (after insert point) if needed. */ if (second > 0) { void *src, *dst; entry = cde40_entry(place, pos); src = place->body + en_get_offset(entry, pol); dst = src - (headers + remove); aal_memmove(dst, src, second); /* Setting up entry offsets */ for (i = pos; i < units - count; i++) { entry = cde40_entry(place, i); en_dec_offset(entry, (headers + remove), pol); } } cde_dec_units(place, count); place_mkdirty(place); return remove + headers;}/* Prepares cde40 for insert new entries */uint32_t cde40_expand(reiser4_place_t *place, uint32_t pos, uint32_t count, uint32_t len){ void *entry; uint32_t pol; uint32_t first; void *src, *dst; uint32_t second; uint32_t offset; uint32_t headers; uint32_t i, units; aal_assert("umka-1724", len > 0); aal_assert("umka-1724", count > 0); aal_assert("umka-1723", place != NULL); pol = cde40_key_pol(place); units = cde_get_units(place); headers = (count * en_size(pol)); aal_assert("umka-1722", pos <= units); /* Getting the offset of the current place. */ if (units > 0) { if (pos < units) { entry = cde40_entry(place, pos); offset = en_get_offset(entry, pol); } else { entry = cde40_entry(place, units - 1); offset = en_get_offset(entry, pol) + cde40_get_len(place, units - 1); } } else { offset = sizeof(cde40_t); } /* Calculating length bytes to be moved before insert point. */ first = (units - pos) * en_size(pol); first += cde40_regsize(place, 0, pos); /* Calculating length bytes to be moved after insert point. */ second = cde40_regsize(place, pos, units - pos); /* Updating offset of entries which lie before insert point. */ entry = cde40_entry(place, 0); for (i = 0; i < pos; i++) { en_inc_offset(entry, headers, pol); entry += en_size(pol); } /* Updating offset of entries which lie after insert point. */ entry = cde40_entry(place, pos); for (i = pos; i < units; i++) { en_inc_offset(entry, len, pol); entry += en_size(pol); } /* Moving entry bodies if it is needed. */ if (pos < units) { src = place->body + offset; dst = src + len; aal_memmove(dst, src, second); } /* Moving unit headers if it is needed. */ if (first > 0) { src = cde40_entry(place, pos); dst = src + headers; aal_memmove(dst, src, first); } place_mkdirty(place); return offset + headers;}/* Predicts how many entries and bytes can be shifted from the @src_place to @dst_place. The behavior of the function depends on the passed @hint. */static errno_t cde40_prep_shift(reiser4_place_t *src_place, reiser4_place_t *dst_place, shift_hint_t *hint){ int check; uint32_t pol; uint32_t curr; uint32_t flags; uint32_t src_units; uint32_t dst_units; uint32_t space, len; aal_assert("umka-1592", hint != NULL); aal_assert("umka-1591", src_place != NULL); hint->units_number = 0; space = hint->units_bytes; pol = cde40_key_pol(src_place); src_units = cde40_units(src_place); dst_units = dst_place ? cde40_units(dst_place) : 0; /* If hint's create flag is present, we need to create new cde item, so we should count its overhead. */ if (hint->create) { if (space < sizeof(cde40_t)) return 0; /* There is only space for header. Getting us out. */ if (!(space -= sizeof(cde40_t))) return 0; } flags = hint->control; /* Getting start item header needed inside loop. */ curr = (hint->control & SF_ALLOW_LEFT ? 0 : src_units - 1); /* If we need to check insert point. */ check = (src_place->pos.item == hint->pos.item && hint->pos.unit != MAX_UINT32); while (!(hint->result & SF_MOVE_POINT) && curr < cde40_units(src_place)) { /* Check if we have already moved everything possible and are on edge of item and will be moved to neighbour item. */ if (check && (flags & SF_UPDATE_POINT)) { if (!(flags & SF_MOVE_POINT)) { if (flags & SF_ALLOW_LEFT) { if (hint->pos.unit == 0) break; } else { if (hint->pos.unit == src_units) break; } } } /* Check is we have enough free space for shifting one more unit
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -