⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 storage.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 2 页
字号:
  UINT32   psize, pnsize, pnnsize;
  UINT32   pnid;

  if ((stobj == NULL) || (stobj->blocklist == NULL)) {
    return FALSE;
  }

  /* Scan block list until we find an empty block */
  p = IdToBlock (stobj, 0);
  if ((p == NULL) || (p->next == NULL))
    return FALSE;  /* Nothing further to be done */

  pn = p->next;
  if (pn->id == 0) {
    /* We have two adjacent blocks that are free, they must be joined. */
    /* This should never happen, but we take care of it just in case. */
    p->size += pn->size;
    PUTHEADER (stobj, p);
    p->next = pn->next;
    DEALLOC (&pn);
    return TRUE;
  }

  psize = p->size;
  pnsize = pn->size;
  pnid = pn->id;

  /* If the block following p->next is free, it has to be joined: */
  pnn = pn->next;
  pnnsize = 0;
  if ((pnn != NULL) && (pnn->id == 0))
    pnnsize = pnn->size;

  p->size += pnsize + pnnsize;
  /* For now, we mark the area of the two (or three) blocks as one big
   * empty block. The write operations to the store are carried out
   * in an order that will guarantee that the contents are always
   * consistent. */
  PUTHEADER(stobj, p);

  /* Move data part of allocated block */
  CopyData (stobj, p->pos + sizeof (BlockHeader),
            pn->pos + sizeof (BlockHeader),
            pnsize - sizeof (BlockHeader));

  /* Write header of the new empty block */
  pn->size = psize + pnnsize;
  pn->pos = p->pos + pnsize;
  pn->id = 0;
  PUTHEADER (stobj, pn);

  /* Write header of the new allocated block */
  p->size = pnsize;
  p->id = pnid;
  PUTHEADER (stobj, p);

  /* Remove the list node, in case we joined two free blocks */
  if (pnnsize > 0) {
    pn->next = pnn->next;
    DEALLOC (&pnn);
  }

  return TRUE;
}

/*
 * Allocate a new block of a size that will hold "len" bytes of data.
 * "id" must be different from NULL. If *id != 0, then that number
 * is used as the Id for the new block, unless it is alreaday in use,
 * in which case FALSE is returned. If *id == 0, then a new unique
 * id is allocated, larger than any other currently in use.
 * Returns FALSE in case of error, e.g., if there is not enough
 * memory left to add a block of the indicated size.
 */
BOOL
Storage_AllocateBlock (StorageObject *stobj, UINT32 len, UINT32 *id)
{
  ListNode *p, *tmp, *pnew;
  UINT32   newid;
  UINT32   sz;

  if ((stobj == NULL) || (stobj->blocklist == NULL)) {
    return FALSE;
  }

  /* Compute the size we will search for: add space for block header
   * and then round upward to nearest multiple of 8. */
  sz = len + sizeof (BlockHeader);
  sz = (sz + 7) & ~7;

  /* Search the block list for a block of size at least sz.
   * The search begins at the beginning of the block list. */
  for (p = stobj->blocklist; p; p = p->next) {
    if ((p->id == 0) && (p->size >= sz)) {
      break;
    }
  }
  /* If there was no block of sufficient size, return FALSE. */
  if (p == NULL) {
    return FALSE;
  }

  /* Get new ID */
  if (id == NULL)
    return FALSE;
  if (*id == 0) {
    /* Create a new unique ID */
    newid = AllocNewId (stobj);
    *id = newid;
  }
  else {
    /* Use the ID suggested by the caller, unless it is already in use. */
    newid = *id;
    for (tmp = stobj->blocklist; tmp; tmp = tmp->next)
      if (tmp->id == newid)
        return FALSE;
  }

  if (p->size >= sz + MINBLOCKSIZE) {
    /* If block is large enough, it can be split:
     *   write second header (size, id = 0)
     *   write first header (size, id = ID) */
    pnew = NEWARRAY (ListNode, 1);
    if (pnew == NULL)
      return FALSE;
    pnew->pos = p->pos + sz;
    pnew->size = p->size - sz;
    pnew->id = 0;
    PUTHEADER (stobj, pnew);

    p->size = sz;
    p->id = newid;
    PUTHEADER (stobj, p);

    pnew->next = p->next;
    p->next = pnew;
  }
  else /* No split, use the entire block. */ {
    /*   write header (size, id = ID) */
    p->id = newid;
    PUTHEADER (stobj, p);
  }
  stobj->bytesUsed += p->size;

  return TRUE;
}

/*
 * Fetch the contents of a block, or part of a block.
 * The retrieved data is copied to the location indicated by "recData".
 * Returns FALSE in case of error, e.g., if the specified block
 * does not exist.
 */
BOOL
Storage_Get (StorageObject *stobj, UINT32 id,
             UINT32 start, UINT32 len, VOID *recData)
{
  ListNode *p;

  if ((stobj == NULL) || (stobj->blocklist == NULL)) {
    return FALSE;
  }

  p = IdToBlock (stobj, id);
  if (p == NULL)
    return FALSE;

  if (start + len + sizeof (BlockHeader) > p->size)
    return FALSE;

  stobj->readStorage (p->pos + sizeof (BlockHeader) + start,
                      len, recData);

  return TRUE;
}

/*
 * Write the contents of an existing block, or part of a block.
 * The data written to the block is read from the location
 * indicated by "recData".
 * Returns FALSE in case of error, e.g., if the specified block
 * does not exist, or if the indicated start position and data length
 * adds up to a position beyond the current end of the block.
 */
BOOL
Storage_Put (StorageObject *stobj, UINT32 id,
             UINT32 start, UINT32 len, VOID *recData)
{
  ListNode *p;

  if ((stobj == NULL) || (stobj->blocklist == NULL)) {
    return FALSE;
  }

  p = IdToBlock (stobj, id);
  if (p == NULL)
    return FALSE;

  if (start + len + sizeof (BlockHeader) > p->size)
    return FALSE;

  stobj->writeStorage (p->pos + sizeof (BlockHeader) + start,
                       len, recData);

  return TRUE;
}

/*
 * Delete the block with given block ID.
 * Returns FALSE in case of error, e.g., if the indicated block
 * does not exist.
 */
BOOL
Storage_DeleteBlock (StorageObject *stobj, UINT32 id)
{
  ListNode *p, *pred, *succ;

  if ((stobj == NULL) || (stobj->blocklist == NULL) || (id == 0)) {
    return FALSE;
  }

  for (pred = NULL, p = stobj->blocklist; p; pred = p, p = p->next) {
    if (p->id == id)
      break;
  }

  if (p == NULL)
    return FALSE;
  succ = p->next;
  stobj->bytesUsed -= p->size;

  /* Set to 'free' */
  p->id = 0;
  PUTHEADER (stobj, p);

  /* Merge with previous record? */
  if (pred && (pred->id == 0)) {
    pred->size += p->size;
    PUTHEADER (stobj, pred);
    pred->next = p->next;
    DEALLOC (&p);
    p = pred;
  }

  /* Merge with next record? */
  if (succ && (succ->id == 0)) {
    p->size += succ->size;
    PUTHEADER (stobj, p);
    p->next = succ->next;
    DEALLOC (&succ);
  }

  return TRUE;
}


/*
 * Return the size of the indicated block.
 * Returns 0 in case of error.
 */
UINT32
Storage_GetBlockSize (StorageObject *stobj, UINT32 id)
{
  ListNode *p;

  if ((stobj == NULL) || (stobj->blocklist == NULL)) {
    return 0;
  }

  p = IdToBlock (stobj, id);
  if (p == NULL)
    return 0;

  return p->size - sizeof (BlockHeader);
}


/*
 * Get the IDs of all blocks in the storage area.
 * Sets "*idarr" to point to an array of UINT32 values,
 * and "*len" to the number of elements in the array.
 * Returns FALSE in case of error.
 * NOTE: it is the caller's responsibility to deallocate the array.
 */
BOOL
Storage_GetAllBlockIds (StorageObject *stobj,
                        UINT32 **idarr, UINT16 *len)
{
  UINT16   i = 0;
  ListNode *p;

  if ((stobj == NULL) || (stobj->blocklist == NULL) ||
      (idarr == NULL) || (len == NULL))
    return FALSE;

  *idarr = NULL;
  *len = 0;

  /* Count the number of allocated blocks */
  for (p = stobj->blocklist; p; p = p->next) {
    if (p->id != 0)
      i++;
  }
  if (i == 0) {
    return TRUE;
  }

  *idarr = NEWARRAY (UINT32, i);
  if (*idarr == NULL)
    return FALSE;
  *len = i;

  i = 0;
  for (p = stobj->blocklist; p; p = p->next) {
    if (p->id != 0)
      (*idarr)[i++] = p->id;
  }

  return TRUE;
}

/*
 * Return the size of the largest block that could be allocated
 * if the storage area were completely compacted.
 * Returns 0 in case of error.
 */
UINT32
Storage_NumBytesFree (StorageObject *stobj)
{
  INT32 nf;

  if ((stobj == NULL) || (stobj->blocklist == NULL)) {
    return 0;
  }
  nf = stobj->size - stobj->bytesUsed - 4 - sizeof (BlockHeader);
  if (nf < 0)
    return 0;

  return (UINT32)(nf & ~0x7);
}


/*
 * Return the number of bytes currently used in the allocated blocks.
 */
UINT32
Storage_BytesUsed (StorageObject *stobj)
{
  if ((stobj == NULL) || (stobj->blocklist == NULL)) {
    return 0;
  }
  return stobj->bytesUsed + 4;
}
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -