Example #1
0
MY_DIR	*my_dir(const char *path, myf MyFlags)
{
  char          *buffer;
  MY_DIR        *result= 0;
  FILEINFO      finfo;
  DYNAMIC_ARRAY *dir_entries_storage;
  MEM_ROOT      *names_storage;
#ifdef __BORLANDC__
  struct ffblk       find;
#else
  struct _finddata_t find;
#endif
  ushort	mode;
  char		tmp_path[FN_REFLEN],*tmp_file,attrib;
#ifdef _WIN64
  __int64       handle;
#else
  long		handle;
#endif
  DBUG_ENTER("my_dir");
  DBUG_PRINT("my",("path: '%s' stat: %d  MyFlags: %d",path,MyFlags));

  /* Put LIB-CHAR as last path-character if not there */
  tmp_file=tmp_path;
  if (!*path)
    *tmp_file++ ='.';				/* From current dir */
  tmp_file= strnmov(tmp_file, path, FN_REFLEN-5);
  if (tmp_file[-1] == FN_DEVCHAR)
    *tmp_file++= '.';				/* From current dev-dir */
  if (tmp_file[-1] != FN_LIBCHAR)
    *tmp_file++ =FN_LIBCHAR;
  tmp_file[0]='*';				/* Windows needs this !??? */
  tmp_file[1]='.';
  tmp_file[2]='*';
  tmp_file[3]='\0';

  if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) + 
                          ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
                          sizeof(MEM_ROOT), MyFlags)))
    goto error;

  dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR))); 
  names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
                             ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
  
  if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
                            ENTRIES_START_SIZE, ENTRIES_INCREMENT))
  {
    my_free(buffer);
    goto error;
  }
  init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
  
  /* MY_DIR structure is allocated and completly initialized at this point */
  result= (MY_DIR*)buffer;

#ifdef __BORLANDC__
  if ((handle= findfirst(tmp_path,&find,0)) == -1L)
#else
  if ((handle=_findfirst(tmp_path,&find)) == -1L)
#endif
  {
    DBUG_PRINT("info", ("findfirst returned error, errno: %d", errno));
    if  (errno != EINVAL)
      goto error;
    /*
      Could not read the directory, no read access.
      Probably because by "chmod -r".
      continue and return zero files in dir
    */
  }
  else
  {

    do
    {
#ifdef __BORLANDC__
      attrib= find.ff_attrib;
#else
      attrib= find.attrib;
      /*
        Do not show hidden and system files which Windows sometimes create.
        Note. Because Borland's findfirst() is called with the third
        argument = 0 hidden/system files are excluded from the search.
      */
      if (attrib & (_A_HIDDEN | _A_SYSTEM))
        continue;
#endif
#ifdef __BORLANDC__
      if (!(finfo.name= strdup_root(names_storage, find.ff_name)))
        goto error;
#else
      if (!(finfo.name= strdup_root(names_storage, find.name)))
        goto error;
#endif
      if (MyFlags & MY_WANT_STAT)
      {
        if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
                                                 sizeof(MY_STAT))))
          goto error;

        bzero(finfo.mystat, sizeof(MY_STAT));
#ifdef __BORLANDC__
        finfo.mystat->st_size=find.ff_fsize;
#else
        finfo.mystat->st_size=find.size;
#endif
        mode= MY_S_IREAD;
        if (!(attrib & _A_RDONLY))
          mode|= MY_S_IWRITE;
        if (attrib & _A_SUBDIR)
          mode|= MY_S_IFDIR;
        finfo.mystat->st_mode= mode;
#ifdef __BORLANDC__
        finfo.mystat->st_mtime= ((uint32) find.ff_ftime);
#else
        finfo.mystat->st_mtime= ((uint32) find.time_write);
#endif
      }
      else
        finfo.mystat= NULL;

      if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
        goto error;
    }
#ifdef __BORLANDC__
    while (findnext(&find) == 0);
#else
    while (_findnext(handle,&find) == 0);

    _findclose(handle);
#endif
  }

  result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
  result->number_off_files= dir_entries_storage->elements;

  if (!(MyFlags & MY_DONT_SORT))
    my_qsort((void *) result->dir_entry, result->number_off_files,
          sizeof(FILEINFO), (qsort_cmp) comp_names);
  DBUG_PRINT("exit", ("found %d files", result->number_off_files));
  DBUG_RETURN(result);
error:
  my_errno=errno;
#ifndef __BORLANDC__
  if (handle != -1)
      _findclose(handle);
#endif
  my_dirend(result);
  if (MyFlags & MY_FAE+MY_WME)
    my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
  DBUG_RETURN((MY_DIR *) NULL);
} /* my_dir */
Example #2
0
MY_DIR	*my_dir(const char *path, myf MyFlags)
{
  char          *buffer;
  MY_DIR        *result= 0;
  FILEINFO      finfo;
  DYNAMIC_ARRAY *dir_entries_storage;
  MEM_ROOT      *names_storage;
  DIR		*dirp;
  struct dirent *dp;
  char		tmp_path[FN_REFLEN+1],*tmp_file;
#ifdef THREAD
  char	dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
#endif
  DBUG_ENTER("my_dir");
  DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,MyFlags));

#if defined(THREAD) && !defined(HAVE_READDIR_R)
  mysql_mutex_lock(&THR_LOCK_open);
#endif

  dirp = opendir(directory_file_name(tmp_path,(char *) path));
#if defined(__amiga__)
  if ((dirp->dd_fd) < 0)			/* Directory doesn't exists */
    goto error;
#endif
  if (dirp == NULL || 
      ! (buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) + 
                           ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
                           sizeof(MEM_ROOT), MyFlags)))
    goto error;

  dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR))); 
  names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
                             ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
  
  if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
                            ENTRIES_START_SIZE, ENTRIES_INCREMENT))
  {
    my_free(buffer);
    goto error;
  }
  init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
  
  /* MY_DIR structure is allocated and completly initialized at this point */
  result= (MY_DIR*)buffer;

  tmp_file=strend(tmp_path);

#ifdef THREAD
  dp= (struct dirent*) dirent_tmp;
#else
  dp=0;
#endif
  
  while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
  {
    if (!(finfo.name= strdup_root(names_storage, dp->d_name)))
      goto error;
    
    if (MyFlags & MY_WANT_STAT)
    {
      if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage, 
                                               sizeof(MY_STAT))))
        goto error;
      
      bzero(finfo.mystat, sizeof(MY_STAT));
      (void) strmov(tmp_file,dp->d_name);
      (void) my_stat(tmp_path, finfo.mystat, MyFlags);
      if (!(finfo.mystat->st_mode & MY_S_IREAD))
        continue;
    }
    else
      finfo.mystat= NULL;

    if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
      goto error;
  }

  (void) closedir(dirp);
#if defined(THREAD) && !defined(HAVE_READDIR_R)
  mysql_mutex_unlock(&THR_LOCK_open);
#endif
  result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
  result->number_off_files= dir_entries_storage->elements;
  
  if (!(MyFlags & MY_DONT_SORT))
    my_qsort((void *) result->dir_entry, result->number_off_files,
          sizeof(FILEINFO), (qsort_cmp) comp_names);
  DBUG_RETURN(result);

 error:
#if defined(THREAD) && !defined(HAVE_READDIR_R)
  mysql_mutex_unlock(&THR_LOCK_open);
#endif
  my_errno=errno;
  if (dirp)
    (void) closedir(dirp);
  my_dirend(result);
  if (MyFlags & (MY_FAE | MY_WME))
    my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno);
  DBUG_RETURN((MY_DIR *) NULL);
} /* my_dir */
Example #3
0
MY_DIR	*my_dir(const char* path, myf MyFlags)
{
  char          *buffer;
  MY_DIR        *result= 0;
  FILEINFO      finfo;
  DYNAMIC_ARRAY *dir_entries_storage;
  MEM_ROOT      *names_storage;
  struct find_t find;
  ushort	mode;
  char		tmp_path[FN_REFLEN],*tmp_file,attrib;
  DBUG_ENTER("my_dir");
  DBUG_PRINT("my",("path: '%s' stat: %d  MyFlags: %d",path,MyFlags));

  /* Put LIB-CHAR as last path-character if not there */

  tmp_file=tmp_path;
  if (!*path)
    *tmp_file++ ='.';				/* From current dir */
  tmp_file= strmov(tmp_file,path);
  if (tmp_file[-1] == FN_DEVCHAR)
    *tmp_file++= '.';				/* From current dev-dir */
  if (tmp_file[-1] != FN_LIBCHAR)
    *tmp_file++ =FN_LIBCHAR;
  tmp_file[0]='*';				/* MSDOS needs this !??? */
  tmp_file[1]='.';
  tmp_file[2]='*';
  tmp_file[3]='\0';

  if (_dos_findfirst(tmp_path,_A_NORMAL | _A_SUBDIR, &find))
    goto error;

  if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) + 
                          ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
                          sizeof(MEM_ROOT), MyFlags)))
    goto error;

  dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR))); 
  names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
                             ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
  
  if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
                            ENTRIES_START_SIZE, ENTRIES_INCREMENT))
  {
    my_free((gptr) buffer,MYF(0));
    goto error;
  }
  init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
  
  /* MY_DIR structure is allocated and completly initialized at this point */
  result= (MY_DIR*)buffer;
 
  do
  {
    if (!(finfo.name= strdup_root(names_storage, find.name)))
      goto error;
    
    if (MyFlags & MY_WANT_STAT)
    {
      if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage, 
                                               sizeof(MY_STAT))))
        goto error;
      
      bzero(finfo.mystat, sizeof(MY_STAT));
      finfo.mystat->st_size= find.size;
      mode= MY_S_IREAD; attrib= find.attrib;
      if (!(attrib & _A_RDONLY))
	mode|= MY_S_IWRITE;
      if (attrib & _A_SUBDIR)
	mode|= MY_S_IFDIR;
      finfo.mystat->st_mode= mode;
      finfo.mystat->st_mtime= ((uint32) find.wr_date << 16) + find.wr_time;
    }
    else
      finfo.mystat= NULL;

    if (push_dynamic(dir_entries_storage, (gptr)&finfo))
      goto error;
  
  } while (_dos_findnext(&find) == 0);
  
  result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
  result->number_off_files= dir_entries_storage->elements;
  
  if (!(MyFlags & MY_DONT_SORT))
    my_qsort((void *) result->dir_entry, result->number_off_files,
          sizeof(FILEINFO), (qsort_cmp) comp_names);
  DBUG_RETURN(result);

error:
  my_dirend(result);
  if (MyFlags & MY_FAE+MY_WME)
    my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
  DBUG_RETURN((MY_DIR *) NULL);
} /* my_dir */
Example #4
0
my_bool _ma_fetch_keypage(MARIA_PAGE *page, MARIA_HA *info,
                          const MARIA_KEYDEF *keyinfo,
                          my_off_t pos, enum pagecache_page_lock lock,
                          int level, uchar *buff,
                          my_bool return_buffer __attribute__ ((unused)))
{
  uchar *tmp;
  MARIA_PINNED_PAGE page_link;
  MARIA_SHARE *share= info->s;
  uint block_size= share->block_size;
  DBUG_ENTER("_ma_fetch_keypage");
  DBUG_PRINT("enter",("page: %lu", (ulong) (pos / block_size)));

  tmp= pagecache_read(share->pagecache, &share->kfile,
                      (pgcache_page_no_t) (pos / block_size), level, buff,
                      share->page_type, lock, &page_link.link);

  if (lock != PAGECACHE_LOCK_LEFT_UNLOCKED)
  {
    DBUG_ASSERT(lock == PAGECACHE_LOCK_WRITE || PAGECACHE_LOCK_READ);
    page_link.unlock= (lock == PAGECACHE_LOCK_WRITE ?
                       PAGECACHE_LOCK_WRITE_UNLOCK :
                       PAGECACHE_LOCK_READ_UNLOCK);
    page_link.changed= 0;
    push_dynamic(&info->pinned_pages, (void*) &page_link);
    page->link_offset= info->pinned_pages.elements-1;
  }

  if (tmp == info->buff)
    info->keyread_buff_used=1;
  else if (!tmp)
  {
    DBUG_PRINT("error",("Got errno: %d from pagecache_read",my_errno));
    info->last_keypage=HA_OFFSET_ERROR;
    _ma_set_fatal_error(share, HA_ERR_CRASHED);
    DBUG_RETURN(1);
  }
  info->last_keypage= pos;

  /*
    Setup page structure to make pages easy to use
    This is same as page_fill_info, but here inlined as this si used
    so often.
  */
  page->info=    info;
  page->keyinfo= keyinfo;
  page->buff=    tmp;
  page->pos=     pos;
  page->size=    _ma_get_page_used(share, tmp);
  page->org_size= page->size;                    /* For debugging */
  page->flag=    _ma_get_keypage_flag(share, tmp);
  page->node=   ((page->flag & KEYPAGE_FLAG_ISNOD) ?
                 share->base.key_reflength : 0);

#ifdef EXTRA_DEBUG
  {
    uint page_size= page->size;
    if (page_size < 4 || page_size > share->max_index_block_size ||
        _ma_get_keynr(share, tmp) != keyinfo->key_nr)
    {
      DBUG_PRINT("error",("page %lu had wrong page length: %u  keynr: %u",
                          (ulong) (pos / block_size), page_size,
                          _ma_get_keynr(share, tmp)));
      DBUG_DUMP("page", tmp, page_size);
      info->last_keypage = HA_OFFSET_ERROR;
      _ma_set_fatal_error(share, HA_ERR_CRASHED);
      DBUG_RETURN(1);
    }
  }
#endif
  DBUG_RETURN(0);
} /* _ma_fetch_keypage */
Example #5
0
my_off_t _ma_new(register MARIA_HA *info, int level,
                 MARIA_PINNED_PAGE **page_link)

{
  my_off_t pos;
  MARIA_SHARE *share= info->s;
  uint block_size= share->block_size;
  DBUG_ENTER("_ma_new");

  if (_ma_lock_key_del(info, 1))
  {
    mysql_mutex_lock(&share->intern_lock);
    pos= share->state.state.key_file_length;
    if (pos >= share->base.max_key_file_length - block_size)
    {
      my_errno=HA_ERR_INDEX_FILE_FULL;
      mysql_mutex_unlock(&share->intern_lock);
      DBUG_RETURN(HA_OFFSET_ERROR);
    }
    share->state.state.key_file_length+= block_size;
    /* Following is for not transactional tables */
    info->state->key_file_length= share->state.state.key_file_length;
    mysql_mutex_unlock(&share->intern_lock);
    (*page_link)->changed= 0;
    (*page_link)->write_lock= PAGECACHE_LOCK_WRITE;
  }
  else
  {
    uchar *buff;
    pos= share->key_del_current;                /* Protected */
    DBUG_ASSERT(share->pagecache->block_size == block_size);
    if (!(buff= pagecache_read(share->pagecache,
                               &share->kfile,
                               (pgcache_page_no_t) (pos / block_size), level,
                               0, share->page_type,
                               PAGECACHE_LOCK_WRITE, &(*page_link)->link)))
      pos= HA_OFFSET_ERROR;
    else
    {
      /*
        Next deleted page's number is in the header of the present page
        (single linked list):
      */
#ifndef DBUG_OFF
      my_off_t key_del_current;
#endif
      share->key_del_current= mi_sizekorr(buff+share->keypage_header);
#ifndef DBUG_OFF
      key_del_current= share->key_del_current;
      DBUG_ASSERT((key_del_current != 0) &&
                  ((key_del_current == HA_OFFSET_ERROR) ||
                   (key_del_current <=
                    (share->state.state.key_file_length - block_size))));
#endif
    }

    (*page_link)->unlock=     PAGECACHE_LOCK_WRITE_UNLOCK;
    (*page_link)->write_lock= PAGECACHE_LOCK_WRITE;
    /*
      We have to mark it changed as _ma_flush_pending_blocks() uses
      'changed' to know if we used the page cache or not
    */
    (*page_link)->changed= 1;
    push_dynamic(&info->pinned_pages, (void*) *page_link);
    *page_link= dynamic_element(&info->pinned_pages,
                                info->pinned_pages.elements-1,
                                MARIA_PINNED_PAGE *);
  }
  share->state.changed|= STATE_NOT_SORTED_PAGES;
  DBUG_PRINT("exit",("Pos: %ld",(long) pos));
  DBUG_RETURN(pos);
} /* _ma_new */
Example #6
0
int _ma_dispose(register MARIA_HA *info, my_off_t pos, my_bool page_not_read)
{
  my_off_t old_link;
  uchar buff[MAX_KEYPAGE_HEADER_SIZE+ 8 + 2];
  ulonglong page_no;
  MARIA_SHARE *share= info->s;
  MARIA_PINNED_PAGE page_link;
  uint block_size= share->block_size;
  int result= 0;
  enum pagecache_page_lock lock_method;
  enum pagecache_page_pin pin_method;
  DBUG_ENTER("_ma_dispose");
  DBUG_PRINT("enter",("page: %lu", (ulong) (pos / block_size)));
  DBUG_ASSERT(pos % block_size == 0);

  (void) _ma_lock_key_del(info, 0);

  old_link= share->key_del_current;
  share->key_del_current= pos;
  page_no= pos / block_size;
  bzero(buff, share->keypage_header);
  _ma_store_keynr(share, buff, (uchar) MARIA_DELETE_KEY_NR);
  _ma_store_page_used(share, buff, share->keypage_header + 8);
  mi_sizestore(buff + share->keypage_header, old_link);
  share->state.changed|= STATE_NOT_SORTED_PAGES;

  if (share->now_transactional)
  {
    LSN lsn;
    uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2];
    LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
    my_off_t page;

    /* Store address of deleted page */
    page_store(log_data + FILEID_STORE_SIZE, page_no);

    /* Store link to next unused page (the link that is written to page) */
    page= (old_link == HA_OFFSET_ERROR ? IMPOSSIBLE_PAGE_NO :
           old_link / block_size);
    page_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE, page);

    log_array[TRANSLOG_INTERNAL_PARTS + 0].str=    log_data;
    log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);

    if (translog_write_record(&lsn, LOGREC_REDO_INDEX_FREE_PAGE,
                              info->trn, info,
                              (translog_size_t) sizeof(log_data),
                              TRANSLOG_INTERNAL_PARTS + 1, log_array,
                              log_data, NULL))
      result= 1;
  }

  if (page_not_read)
  {
    lock_method= PAGECACHE_LOCK_WRITE;
    pin_method= PAGECACHE_PIN;
  }
  else
  {
    lock_method= PAGECACHE_LOCK_LEFT_WRITELOCKED;
    pin_method= PAGECACHE_PIN_LEFT_PINNED;
  }

  if (pagecache_write_part(share->pagecache,
                           &share->kfile, (pgcache_page_no_t) page_no,
                           PAGECACHE_PRIORITY_LOW, buff,
                           share->page_type,
                           lock_method, pin_method,
                           PAGECACHE_WRITE_DELAY, &page_link.link,
			   LSN_IMPOSSIBLE,
                           0, share->keypage_header + 8))
    result= 1;

#ifdef IDENTICAL_PAGES_AFTER_RECOVERY
  {
    uchar *page_buff= pagecache_block_link_to_buffer(page_link.link);
    bzero(page_buff + share->keypage_header + 8,
          block_size - share->keypage_header - 8 - KEYPAGE_CHECKSUM_SIZE);
  }
#endif

  if (page_not_read)
  {
    /* It was not locked before, we have to unlock it when we unpin pages */
    page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
    page_link.changed= 1;
    push_dynamic(&info->pinned_pages, (void*) &page_link);
  }

  DBUG_RETURN(result);
} /* _ma_dispose */
Example #7
0
my_bool _ma_write_keypage(MARIA_PAGE *page, enum pagecache_page_lock lock,
                          int level)
{
  MARIA_SHARE *share= page->info->s;
  uint block_size= share->block_size;
  uchar *buff= page->buff;
  my_bool res;
  MARIA_PINNED_PAGE page_link;
  DBUG_ENTER("_ma_write_keypage");

  /*
    The following ensures that for transactional tables we have logged
    all changes that changes the page size (as the logging code sets
    page->org_size)
  */
  DBUG_ASSERT(!share->now_transactional || page->size == page->org_size);

#ifdef EXTRA_DEBUG				/* Safety check */
  {
    uint page_length, nod_flag;
    page_length= _ma_get_page_used(share, buff);
    nod_flag=    _ma_test_if_nod(share, buff);

    DBUG_ASSERT(page->size == page_length);
    DBUG_ASSERT(page->size <= share->max_index_block_size);
    DBUG_ASSERT(page->flag == _ma_get_keypage_flag(share, buff));

    if (page->pos < share->base.keystart ||
        page->pos+block_size > share->state.state.key_file_length ||
        (page->pos & (maria_block_size-1)))
    {
      DBUG_PRINT("error",("Trying to write inside key status region: "
                          "key_start: %lu  length: %lu  page_pos: %lu",
                          (long) share->base.keystart,
                          (long) share->state.state.key_file_length,
                          (long) page->pos));
      my_errno=EINVAL;
      DBUG_ASSERT(0);
      DBUG_RETURN(1);
    }
    DBUG_PRINT("page",("write page at: %lu",(ulong) (page->pos / block_size)));
    DBUG_DUMP("buff", buff, page_length);
    DBUG_ASSERT(page_length >= share->keypage_header + nod_flag +
                page->keyinfo->minlength || maria_in_recovery);
  }
#endif

  /* Verify that keynr is correct */
  DBUG_ASSERT(_ma_get_keynr(share, buff) == page->keyinfo->key_nr);

#if defined(EXTRA_DEBUG) && defined(HAVE_valgrind) && defined(NOT_ANYMORE)
  {
    /* This is here to catch uninitialized bytes */
    uint length= page->size;
    ulong crc= my_checksum(0, buff, length);
    int4store(buff + block_size - KEYPAGE_CHECKSUM_SIZE, crc);
  }
#endif

  page_cleanup(share, page);
  res= pagecache_write(share->pagecache,
                       &share->kfile,
                       (pgcache_page_no_t) (page->pos / block_size),
                       level, buff, share->page_type,
                       lock,
                       lock == PAGECACHE_LOCK_LEFT_WRITELOCKED ?
                       PAGECACHE_PIN_LEFT_PINNED :
                       (lock == PAGECACHE_LOCK_WRITE_UNLOCK ?
                        PAGECACHE_UNPIN : PAGECACHE_PIN),
                       PAGECACHE_WRITE_DELAY, &page_link.link,
		       LSN_IMPOSSIBLE);

  if (lock == PAGECACHE_LOCK_WRITE)
  {
    /* It was not locked before, we have to unlock it when we unpin pages */
    page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
    page_link.changed= 1;
    push_dynamic(&page->info->pinned_pages, (void*) &page_link);
  }
  DBUG_RETURN(res);
}