コード例 #1
0
/*===========================================================================*
 *                             fs_rdlink                                     *
 *===========================================================================*/
int fs_rdlink()
{
  block_t b;                   /* block containing link text */
  struct buf *bp;              /* buffer containing link text */
  register struct inode *rip;  /* target inode */
  register int r;              /* return value */
  size_t copylen;
  
  copylen = min( (size_t) fs_m_in.REQ_MEM_SIZE, UMAX_FILE_POS);

  /* Temporarily open the file. */
  if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
	  return(EINVAL);

  if(!S_ISLNK(rip->i_mode))
	  r = EACCES;
  else if ((b = read_map(rip, (off_t) 0)) == NO_BLOCK)
	r = EIO;
  else {
	/* Passed all checks */
	/* We can safely cast to unsigned, because copylen is guaranteed to be
	   below max file size */
	copylen = min( copylen, (unsigned) rip->i_size);
	bp = get_block(rip->i_dev, b, NORMAL);
	r = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
			   (vir_bytes) 0, (vir_bytes) b_data(bp),
	  		   (size_t) copylen);
	put_block(bp, DIRECTORY_BLOCK);
	if (r == OK)
		fs_m_out.RES_NBYTES = copylen;
  }
  
  put_inode(rip);
  return(r);
}
コード例 #2
0
void parse_susp_rock_ridge_plcl(struct rrii_dir_record *dir, u32_t block) {
	struct inode *rep_inode;
	struct buf *bp;
	struct iso9660_dir_record *dir_rec;
	struct dir_extent extent;
	struct inode_dir_entry dummy_dir_entry;
	size_t dummy_offset = 0;

	/* Check if inode wasn't already parsed. */
	rep_inode = inode_cache_get(block);
	if (rep_inode != NULL) {
		rep_inode->i_refcount++;
		dir->reparented_inode = rep_inode;
		return;
	}

	/* Peek ahead to build extent for read_inode. */
	if (lmfs_get_block(&bp, fs_dev, block, NORMAL) != OK)
		return;

	dir_rec = (struct iso9660_dir_record*)b_data(bp);

	extent.location = block;
	extent.length = dir_rec->data_length_l / v_pri.logical_block_size_l;
	if (dir_rec->data_length_l % v_pri.logical_block_size_l)
		extent.length++;
	extent.next = NULL;
	lmfs_put_block(bp);

	memset(&dummy_dir_entry, 0, sizeof(struct inode_dir_entry));
	read_inode(&dummy_dir_entry, &extent, &dummy_offset);
	free(dummy_dir_entry.r_name);
	dir->reparented_inode = dummy_dir_entry.i_node;
}
コード例 #3
0
ファイル: channel.c プロジェクト: cloudant/haproxy
/* Inserts <str> followed by "\r\n" at position <pos> relative to channel <c>'s
 * input head. The <len> argument informs about the length of string <str> so
 * that we don't have to measure it. <str> must be a valid pointer and must not
 * include the trailing "\r\n".
 *
 * The number of bytes added is returned on success. 0 is returned on failure.
 */
int ci_insert_line2(struct channel *c, int pos, const char *str, int len)
{
	struct buffer *b = &c->buf;
	char *dst = c_ptr(c, pos);
	int delta;

	delta = len + 2;

	if (b_tail(b) + delta >= b_wrap(b))
		return 0;  /* no space left */

	if (b_data(b) &&
	    b_tail(b) + delta > b_head(b) &&
	    b_head(b) >= b_tail(b))
		return 0;  /* no space left before wrapping data */

	/* first, protect the end of the buffer */
	memmove(dst + delta, dst, b_tail(b) - dst);

	/* now, copy str over dst */
	memcpy(dst, str, len);
	dst[len] = '\r';
	dst[len + 1] = '\n';

	b_add(b, delta);
	return delta;
}
コード例 #4
0
ファイル: inode.c プロジェクト: Hooman3/minix
static struct buf* fetch_inode(struct dir_extent *extent, size_t *offset)
{
	struct iso9660_dir_record *dir_rec;
	struct buf *bp;

	/*
	 * Directory entries aren't allowed to cross a logical block boundary in
	 * ISO 9660, so we keep searching until we find something or reach the
	 * end of the extent.
	 */
	bp = read_extent_block(extent, *offset / v_pri.logical_block_size_l);
	while (bp != NULL) {
		dir_rec = (struct iso9660_dir_record*)(b_data(bp) + *offset %
		          v_pri.logical_block_size_l);
		if (dir_rec->length == 0) {
			*offset -= *offset % v_pri.logical_block_size_l;
			*offset += v_pri.logical_block_size_l;
		}
		else {
			break;
		}

		lmfs_put_block(bp, FULL_DATA_BLOCK);
		bp = read_extent_block(extent, *offset /
		    v_pri.logical_block_size_l);
	}

	return bp;
}
コード例 #5
0
ファイル: Support.cpp プロジェクト: dakcarto/PDAL
bool Support::compare_stage_data(pdal::Stage const& a, pdal::Stage const& b)
{
    pdal::Schema const& a_schema = a.getSchema();
    pdal::Schema const& b_schema = b.getSchema();
    if (a_schema != b_schema) return false;

    boost::uint64_t a_num_points64 = a.getNumPoints();
    boost::uint64_t b_num_points64 = b.getNumPoints();
    if (a_num_points64 > std::numeric_limits<boost::uint32_t>::max() ||
            b_num_points64 > std::numeric_limits<boost::uint32_t>::max())
        throw pdal::pdal_error("unable to do compare_stage_data for > 2^32 points");
    boost::uint32_t a_num_points = static_cast<boost::uint32_t>(a_num_points64);
    boost::uint32_t b_num_points = static_cast<boost::uint32_t>(b_num_points64);
    if (a_num_points != b_num_points) return false;


    // if we don't have any sizes here, we'll just use a small default
    if (a_num_points == 0) a_num_points = 1024;
    if (b_num_points == 0) b_num_points = 1024;

    pdal::PointBuffer a_data(a_schema, a_num_points);
    pdal::PointBuffer b_data(b_schema, b_num_points);

    pdal::StageSequentialIterator* a_itr = a.createSequentialIterator(a_data);
    pdal::StageSequentialIterator* b_itr = b.createSequentialIterator(b_data);

    if (!a_itr) throw pdal::pdal_error("unable to create sequential iterator for compare_stage_data for stage a");
    if (!b_itr) throw pdal::pdal_error("unable to create sequential iterator for compare_stage_data for stage b");



    {
        boost::uint32_t a_numRead = a_itr->read(a_data);
        boost::uint32_t b_numRead = b_itr->read(b_data);
        if (a_numRead != b_numRead) return false;

        boost::uint8_t const* a_bytes = a_data.getData(0);
        boost::uint8_t const* b_bytes = b_data.getData(0);

        boost::uint64_t a_length = a_data.getBufferByteLength();
        // boost::uint64_t b_length = b_data.getBufferByteLength();

        for (boost::uintmax_t i=0; i<a_length; i++)
        {
            if (*a_bytes != *b_bytes)
            {
                return false;
            }
            ++a_bytes;
            ++b_bytes;
        }

    }

    return true;

}
コード例 #6
0
ファイル: inode.c プロジェクト: Hooman3/minix
void read_inode_susp(struct inode *i, const struct iso9660_dir_record *dir_rec,
	struct buf *bp, size_t offset)
{
	int susp_offset, susp_size;
	struct rrii_dir_record rrii_data;

	susp_offset = 33 + dir_rec->length_file_id;
	/* Get rid of padding byte. */
	if(dir_rec->length_file_id % 2 == 0) {
		susp_offset++;
	}

	if(dir_rec->length - susp_offset >= 4) {
		susp_size = dir_rec->length - susp_offset;

		/* Initialize record with known, sane data. */
		memcpy(rrii_data.mtime, dir_rec->rec_date, ISO9660_SIZE_DATE7);
		memcpy(rrii_data.atime, dir_rec->rec_date, ISO9660_SIZE_DATE7);
		memcpy(rrii_data.ctime, dir_rec->rec_date, ISO9660_SIZE_DATE7);
		memcpy(rrii_data.birthtime, dir_rec->rec_date,
		    ISO9660_SIZE_DATE7);

		rrii_data.d_mode = i->i_stat.st_mode;
		rrii_data.uid    = 0;
		rrii_data.gid    = 0;
		rrii_data.rdev   = NO_DEV;
		rrii_data.file_id_rrip[0] = '\0';
		rrii_data.slink_rrip[0]   = '\0';

		parse_susp_buffer(&rrii_data, b_data(bp)+offset+susp_offset,
		    susp_size);

		/* Copy back data from rrii_dir_record structure. */
		i->i_stat.st_atime = date7_to_time_t(rrii_data.atime);
		i->i_stat.st_ctime = date7_to_time_t(rrii_data.ctime);
		i->i_stat.st_mtime = date7_to_time_t(rrii_data.mtime);
		i->i_stat.st_birthtime = date7_to_time_t(rrii_data.birthtime);

		i->i_stat.st_mode = rrii_data.d_mode;
		i->i_stat.st_uid  = rrii_data.uid;
		i->i_stat.st_gid  = rrii_data.gid;
		i->i_stat.st_rdev = rrii_data.rdev;

		if (rrii_data.file_id_rrip[0] != '\0')
			strlcpy(i->i_name, rrii_data.file_id_rrip,
			   sizeof(i->i_name));
		if (rrii_data.slink_rrip[0] != '\0')
			strlcpy(i->s_link, rrii_data.slink_rrip,
			   sizeof(i->s_link));
	}
}
コード例 #7
0
ファイル: dti_process.hpp プロジェクト: YounesN/DSI-Studio
    virtual void init(Voxel& voxel)
    {
        voxel.fib_fa.clear();
        voxel.fib_fa.resize(voxel.dim.size());
        voxel.fib_dir.clear();
        voxel.fib_dir.resize(voxel.dim.size()*3);

        md.clear();
        md.resize(voxel.dim.size());
        d0.clear();
        d0.resize(voxel.dim.size());
        d1.clear();
        d1.resize(voxel.dim.size());

        b_count = voxel.bvalues.size()-1;
        std::vector<image::vector<3> > b_data(b_count);
        //skip null
        std::copy(voxel.bvectors.begin()+1,voxel.bvectors.end(),b_data.begin());
        for(unsigned int index = 0; index < b_count; ++index)
            b_data[index] *= std::sqrt(voxel.bvalues[index+1]);

        Kt.resize(6*b_count);
        {
            unsigned int qmap[6]		= {0  ,4  ,8  ,1  ,2  ,5  };
            double qweighting[6]= {1.0,1.0,1.0,2.0,2.0,2.0};
            //					  bxx,byy,bzz,bxy,bxz,byz
            for (unsigned int i = 0,k = 0; i < b_data.size(); ++i,k+=6)
            {
                //qq = q qT
                std::vector<float> qq(3*3);
                image::matrix::product_transpose(b_data[i].begin(),b_data[i].begin(),qq.begin(),
                                                 image::dyndim(3,1),image::dyndim(3,1));

                /*
                      q11 q15 q19 2*q12 2*q13 2*q16
                      q21 q25 q29 2*q22 2*q23 2*q26
                K  = | ...                         |
                */
                for (unsigned int col = 0,index = i; col < 6; ++col,index+=b_count)
                    Kt[index] = qq[qmap[col]]*qweighting[col];
            }
        }
        iKtK.resize(6*6);
        iKtK_pivot.resize(6);
        image::matrix::product_transpose(Kt.begin(),Kt.begin(),iKtK.begin(),
                                         image::dyndim(6,b_count),image::dyndim(6,b_count));
        image::matrix::lu_decomposition(iKtK.begin(),iKtK_pivot.begin(),image::dyndim(6,6));
    }
コード例 #8
0
ファイル: link.c プロジェクト: anuragpeshne/minix
/*===========================================================================*
 *                             fs_rdlink                                     *
 *===========================================================================*/
int fs_rdlink()
{
  struct buf *bp = NULL;       /* buffer containing link text */
  char* link_text;             /* either bp->b_data or rip->i_block */
  register struct inode *rip;  /* target inode */
  register int r;              /* return value */
  size_t copylen;

  copylen = min( (size_t) fs_m_in.REQ_MEM_SIZE, UMAX_FILE_POS);

  /* Temporarily open the file. */
  if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
	  return(EINVAL);

  if (rip->i_size >= MAX_FAST_SYMLINK_LENGTH) {
  /* normal symlink */
       	if(!(bp = get_block_map(rip, 0))) {
		r = EIO;
	} else {
		link_text = b_data(bp);
		r = OK;
	}
  } else {
        /* fast symlink, stored in inode */
        link_text = (char*) rip->i_block;
	r = OK;
  }
  if (r == OK) {
  /* Passed all checks */
  /* We can safely cast to unsigned, because copylen is guaranteed to be
     below max file size */
	copylen = min( copylen, (unsigned) rip->i_size);
	r = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
	                   (vir_bytes) 0, (vir_bytes) link_text,
			   (size_t) copylen);
	put_block(bp, DIRECTORY_BLOCK);
	if (r == OK)
		fs_m_out.RES_NBYTES = copylen;
  }

  put_inode(rip);
  return(r);
}
コード例 #9
0
ファイル: inode.c プロジェクト: Hooman3/minix
int read_inode(struct inode *i_node, struct dir_extent *extent, size_t offset,
	size_t *new_offset)
{
	struct iso9660_dir_record *dir_rec;
	struct buf *bp;

	/* Find inode. */
	bp = fetch_inode(extent, &offset);
	if (bp == NULL)
		return EOF;

	dir_rec = (struct iso9660_dir_record*)(b_data(bp) + offset %
	          v_pri.logical_block_size_l);

	/* Parse basic ISO 9660 specs. */
	if (check_dir_record(dir_rec,
	    offset % v_pri.logical_block_size_l) != OK) {
		lmfs_put_block(bp, FULL_DATA_BLOCK);
		return EINVAL;
	}

	memset(&i_node->i_stat, 0, sizeof(struct stat));

	i_node->i_stat.st_ino = get_extent_absolute_block_id(extent,
	    offset / v_pri.logical_block_size_l) * v_pri.logical_block_size_l +
	    offset % v_pri.logical_block_size_l;

	read_inode_iso9660(i_node, dir_rec);

	/* Parse extensions. */
	read_inode_susp(i_node, dir_rec, bp,
	    offset % v_pri.logical_block_size_l);

	offset += dir_rec->length;
	read_inode_extents(i_node, dir_rec, extent, &offset);

	lmfs_put_block(bp, FULL_DATA_BLOCK);
	if (new_offset != NULL)
		*new_offset = offset;
	return OK;
}
コード例 #10
0
ファイル: link.c プロジェクト: jungle0755/minix
/*===========================================================================*
 *                             fs_rdlink                                     *
 *===========================================================================*/
ssize_t fs_rdlink(ino_t ino_nr, struct fsdriver_data *data, size_t bytes)
{
    struct buf *bp = NULL;       /* buffer containing link text */
    char* link_text;             /* either bp->b_data or rip->i_block */
    register struct inode *rip;  /* target inode */
    register int r;              /* return value */

    /* Temporarily open the file. */
    if( (rip = get_inode(fs_dev, ino_nr)) == NULL)
        return(EINVAL);

    if (rip->i_size >= MAX_FAST_SYMLINK_LENGTH) {
        /* normal symlink */
        if(!(bp = get_block_map(rip, 0))) {
            r = EIO;
        } else {
            link_text = b_data(bp);
            r = OK;
        }
    } else {
        /* fast symlink, stored in inode */
        link_text = (char*) rip->i_block;
        r = OK;
    }
    if (r == OK) {
        /* Passed all checks */
        if (bytes > rip->i_size)
            bytes = rip->i_size;
        r = fsdriver_copyout(data, 0, link_text, bytes);
        put_block(bp, DIRECTORY_BLOCK);
        if (r == OK)
            r = bytes;
    }

    put_inode(rip);
    return(r);
}
コード例 #11
0
ファイル: read.c プロジェクト: Hooman3/minix
ssize_t fs_read(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
	off_t pos, int __unused call)
{
	size_t off, chunk, block_size, cum_io;
	off_t f_size;
	struct inode *i_node;
	struct buf *bp;
	int r;

	/* Try to get inode according to its index. */
	if ((i_node = find_inode(ino_nr)) == NULL)
		return EINVAL; /* No inode found. */

	f_size = i_node->i_stat.st_size;
	if (pos >= f_size)
		return 0; /* EOF */

	/* Limit the request to the remainder of the file size. */
	if ((off_t)bytes > f_size - pos)
		bytes = (size_t)(f_size - pos);

	block_size = v_pri.logical_block_size_l;
	cum_io = 0;

	lmfs_reset_rdwt_err();
	r = OK;

	/* Split the transfer into chunks that don't span two blocks. */
	while (bytes > 0) {
		off = pos % block_size;

		chunk = block_size - off;
		if (chunk > bytes)
			chunk = bytes;

		/* Read 'chunk' bytes. */
		bp = read_extent_block(i_node->extent, pos / block_size);
		if (bp == NULL)
			panic("bp not valid in rw_chunk; this can't happen");

		r = fsdriver_copyout(data, cum_io, b_data(bp)+off, chunk);

		lmfs_put_block(bp, FULL_DATA_BLOCK);

		if (r != OK)
			break;  /* EOF reached. */
		if (lmfs_rdwt_err() < 0)
			break;

		/* Update counters and pointers. */
		bytes -= chunk;		/* Bytes yet to be read. */
		cum_io += chunk;	/* Bytes read so far. */
		pos += chunk;		/* Position within the file. */
	}

	if (lmfs_rdwt_err() != OK)
		r = lmfs_rdwt_err();	/* Check for disk error. */
	if (lmfs_rdwt_err() == END_OF_FILE)
		r = OK;

	return (r == OK) ? cum_io : r;
}
コード例 #12
0
ファイル: open.c プロジェクト: bdeepak77/minix3
/*===========================================================================*
 *                             fs_slink 				     *
 *===========================================================================*/
int fs_slink()
{
  phys_bytes len;
  struct inode *sip;           /* inode containing symbolic link */
  struct inode *ldirp;         /* directory containing link */
  register int r;              /* error code */
  char string[NAME_MAX];       /* last component of the new dir's path name */
  char* link_target_buf = NULL;       /* either sip->i_block or bp->b_data */
  struct buf *bp = NULL;    /* disk buffer for link */

  caller_uid = (uid_t) fs_m_in.REQ_UID;
  caller_gid = (gid_t) fs_m_in.REQ_GID;

  /* Copy the link name's last component */
  len = fs_m_in.REQ_PATH_LEN;
  if (len > NAME_MAX || len > EXT2_NAME_MAX)
	return(ENAMETOOLONG);

  r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
		       (vir_bytes) 0, (vir_bytes) string, (size_t) len);
  if (r != OK) return(r);
  NUL(string, len, sizeof(string));

  /* Temporarily open the dir. */
  if( (ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
	  return(EINVAL);

  /* Create the inode for the symlink. */
  sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES),
		   (block_t) 0);

  /* If we can then create fast symlink (store it in inode),
   * Otherwise allocate a disk block for the contents of the symlink and
   * copy contents of symlink (the name pointed to) into first disk block. */
  if( (r = err_code) == OK) {
	if ( (fs_m_in.REQ_MEM_SIZE + 1) > sip->i_sp->s_block_size) {
		r = ENAMETOOLONG;
	} else if ((fs_m_in.REQ_MEM_SIZE + 1) <= MAX_FAST_SYMLINK_LENGTH) {
		r = sys_safecopyfrom(VFS_PROC_NR,
				     (cp_grant_id_t) fs_m_in.REQ_GRANT3,
				     (vir_bytes) 0, (vir_bytes) sip->i_block,
                                     (vir_bytes) fs_m_in.REQ_MEM_SIZE);
		sip->i_dirt = IN_DIRTY;
		link_target_buf = (char*) sip->i_block;
        } else {
		if ((bp = new_block(sip, (off_t) 0)) != NULL) {
			sys_safecopyfrom(VFS_PROC_NR,
					 (cp_grant_id_t) fs_m_in.REQ_GRANT3,
					 (vir_bytes) 0, (vir_bytes) b_data(bp),
					 (vir_bytes) fs_m_in.REQ_MEM_SIZE);
			lmfs_markdirty(bp);
			link_target_buf = b_data(bp);
		} else {
			r = err_code;
		}
	}
	if (r == OK) {
		assert(link_target_buf);
		link_target_buf[fs_m_in.REQ_MEM_SIZE] = '\0';
		sip->i_size = (off_t) strlen(link_target_buf);
		if (sip->i_size != fs_m_in.REQ_MEM_SIZE) {
			  /* This can happen if the user provides a buffer
			   * with a \0 in it. This can cause a lot of trouble
			   * when the symlink is used later. We could just use
			   * the strlen() value, but we want to let the user
			   * know he did something wrong. ENAMETOOLONG doesn't
			   * exactly describe the error, but there is no
			   * ENAMETOOWRONG.
			   */
			  r = ENAMETOOLONG;
		  }
	}

	put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NULL. */

	if(r != OK) {
		sip->i_links_count = NO_LINK;
		if (search_dir(ldirp, string, NULL, DELETE, IGN_PERM, 0) != OK)
			panic("Symbolic link vanished");
	}
  }

  /* put_inode() accepts NULL as a noop, so the below are safe. */
  put_inode(sip);
  put_inode(ldirp);

  return(r);
}
コード例 #13
0
ファイル: inode.c プロジェクト: Hooman3/minix
void read_inode_extents(struct inode *i,
	const struct iso9660_dir_record *dir_rec,
	struct dir_extent *extent, size_t *offset)
{
	struct buf *bp;
	struct iso9660_dir_record *extent_rec;
	struct dir_extent *cur_extent = i->extent;
	int done = FALSE;

	/*
	 * No need to search extents if file is empty or has final directory
	 * record flag set.
	 */
	if (cur_extent == NULL ||
	    ((dir_rec->file_flags & D_NOT_LAST_EXTENT) == 0))
		return;

	while (!done) {
		bp = fetch_inode(extent, offset);
		if (bp == NULL)
			return;

		bp = read_extent_block(extent,
		    *offset / v_pri.logical_block_size_l);
		extent_rec = (struct iso9660_dir_record*)(b_data(bp) +
		    *offset % v_pri.logical_block_size_l);

		if (check_dir_record(dir_rec,
		    *offset % v_pri.logical_block_size_l) != OK) {
			lmfs_put_block(bp, FULL_DATA_BLOCK);
			return;
		}

		/* Extent entries should share the same name. */
		if ((dir_rec->length_file_id == extent_rec->length_file_id) &&
		    (memcmp(dir_rec->file_id, extent_rec->file_id,
		    dir_rec->length_file_id) == 0)) {
			/* Add the extent at the end of the linked list. */
			assert(cur_extent->next == NULL);
			cur_extent->next = alloc_extent();
			cur_extent->next->location = dir_rec->loc_extent_l +
			    dir_rec->ext_attr_rec_length;
			cur_extent->next->length = dir_rec->data_length_l /
			    v_pri.logical_block_size_l;
			if (dir_rec->data_length_l % v_pri.logical_block_size_l)
				cur_extent->next->length++;

			i->i_stat.st_size += dir_rec->data_length_l;
			i->i_stat.st_blocks += cur_extent->next->length;

			cur_extent = cur_extent->next;
			*offset += extent_rec->length;
		}
		else
			done = TRUE;

		/* Check if not last extent bit is not set. */
		if ((dir_rec->file_flags & D_NOT_LAST_EXTENT) == 0)
			done = TRUE;

		lmfs_put_block(bp, FULL_DATA_BLOCK);
	}
}
コード例 #14
0
ファイル: susp.c プロジェクト: Hooman3/minix
int parse_susp(struct rrii_dir_record *dir, char *buffer)
{
	/* Parse fundamental SUSP entries */
	char susp_signature[2];
	u8_t susp_length;
	u8_t susp_version;

	u32_t ca_block_nr;
	u32_t ca_offset;
	u32_t ca_length;
	struct buf *ca_bp;

	susp_signature[0] = buffer[0];
	susp_signature[1] = buffer[1];
	susp_length = *((u8_t*)buffer + 2);
	susp_version = *((u8_t*)buffer + 3);

	if ((susp_signature[0] == 'C') && (susp_signature[1] == 'E') &&
	    (susp_length >= 28) && (susp_version >= 1)) {
		/*
		 * Continuation area, perform a recursion.
		 *
		 * FIXME: Currently we're parsing only first logical block of a
		 * continuation area, and infinite recursion is not checked.
		 */

		ca_block_nr = *((u32_t*)(buffer + 4));
		ca_offset = *((u32_t*)(buffer + 12));
		ca_length = *((u32_t*)(buffer + 20));

		/* Truncate continuation area to fit one logical block. */
		if (ca_offset >= v_pri.logical_block_size_l) {
			return EINVAL;
		}
		if (ca_offset + ca_length > v_pri.logical_block_size_l) {
			ca_length = v_pri.logical_block_size_l - ca_offset;
		}

		ca_bp = lmfs_get_block(fs_dev, ca_block_nr, NORMAL);
		if (ca_bp == NULL) {
			return EINVAL;
		}

		parse_susp_buffer(dir, b_data(ca_bp) + ca_offset, ca_length);
		lmfs_put_block(ca_bp, FULL_DATA_BLOCK);

		return OK;
	}
	else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'D')) {
		/* Padding, skip. */
		return OK;
	}
	else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'P')) {
		/* Ignored, skip. */
		return OK;
	}
	else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'T')) {
		/* Terminator entry, stop processing. */
		return(ECANCELED);
	}
	else if ((susp_signature[0] == 'E') && (susp_signature[1] == 'R')) {
		/* Ignored, skip. */
		return OK;
	}
	else if ((susp_signature[0] == 'E') && (susp_signature[1] == 'S')) {
		/* Ignored, skip. */
		return OK;
	}

	/* Not a SUSP fundamental entry. */
	return EINVAL;
}