mirror of https://gitee.com/openkylin/libvirt.git
storage: Add storage file API to read file headers
Add storage driver based functions to access headers of storage files for metadata extraction. Along with this patch a local filesystem and gluster via libgfapi implementation is provided. The gluster implementation is based on code of the saferead_lim function.
This commit is contained in:
parent
ae26731e1f
commit
81271a9261
|
@ -190,6 +190,12 @@ typedef int
|
|||
(*virStorageFileBackendStat)(virStorageSourcePtr src,
|
||||
struct stat *st);
|
||||
|
||||
typedef ssize_t
|
||||
(*virStorageFileBackendReadHeader)(virStorageSourcePtr src,
|
||||
ssize_t max_len,
|
||||
char **buf);
|
||||
|
||||
|
||||
virStorageFileBackendPtr virStorageFileBackendForType(int type, int protocol);
|
||||
|
||||
|
||||
|
@ -204,6 +210,7 @@ struct _virStorageFileBackend {
|
|||
* error on failure. */
|
||||
virStorageFileBackendInit backendInit;
|
||||
virStorageFileBackendDeinit backendDeinit;
|
||||
virStorageFileBackendReadHeader storageFileReadHeader;
|
||||
|
||||
/* The following group of callbacks is expected to set errno
|
||||
* and return -1 on error. No libvirt error shall be reported */
|
||||
|
|
|
@ -1375,6 +1375,34 @@ virStorageFileBackendFileStat(virStorageSourcePtr src,
|
|||
}
|
||||
|
||||
|
||||
static ssize_t
|
||||
virStorageFileBackendFileReadHeader(virStorageSourcePtr src,
|
||||
ssize_t max_len,
|
||||
char **buf)
|
||||
{
|
||||
int fd = -1;
|
||||
ssize_t ret = -1;
|
||||
|
||||
if ((fd = virFileOpenAs(src->path, O_RDONLY, 0,
|
||||
src->drv->uid, src->drv->gid, 0)) < 0) {
|
||||
virReportSystemError(-fd, _("Failed to open file '%s'"),
|
||||
src->path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ret = virFileReadHeaderFD(fd, max_len, buf)) < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("cannot read header '%s'"), src->path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
VIR_FORCE_CLOSE(fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
virStorageFileBackend virStorageFileBackendFile = {
|
||||
.type = VIR_STORAGE_TYPE_FILE,
|
||||
|
||||
|
@ -1383,6 +1411,7 @@ virStorageFileBackend virStorageFileBackendFile = {
|
|||
|
||||
.storageFileUnlink = virStorageFileBackendFileUnlink,
|
||||
.storageFileStat = virStorageFileBackendFileStat,
|
||||
.storageFileReadHeader = virStorageFileBackendFileReadHeader,
|
||||
};
|
||||
|
||||
|
||||
|
@ -1393,6 +1422,7 @@ virStorageFileBackend virStorageFileBackendBlock = {
|
|||
.backendDeinit = virStorageFileBackendFileDeinit,
|
||||
|
||||
.storageFileStat = virStorageFileBackendFileStat,
|
||||
.storageFileReadHeader = virStorageFileBackendFileReadHeader,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -638,6 +638,71 @@ virStorageFileBackendGlusterStat(virStorageSourcePtr src,
|
|||
}
|
||||
|
||||
|
||||
static ssize_t
|
||||
virStorageFileBackendGlusterReadHeader(virStorageSourcePtr src,
|
||||
ssize_t max_len,
|
||||
char **buf)
|
||||
{
|
||||
virStorageFileBackendGlusterPrivPtr priv = src->drv->priv;
|
||||
glfs_fd_t *fd = NULL;
|
||||
size_t alloc = 0;
|
||||
size_t size = 0;
|
||||
int save_errno;
|
||||
ssize_t ret = -1;
|
||||
|
||||
*buf = NULL;
|
||||
|
||||
if (!(fd = glfs_open(priv->vol, src->path, O_RDONLY))) {
|
||||
virReportSystemError(errno, _("Failed to open file '%s'"),
|
||||
src->path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* code below is shamelessly stolen from saferead_lim */
|
||||
for (;;) {
|
||||
int count;
|
||||
int requested;
|
||||
|
||||
if (size + BUFSIZ + 1 > alloc) {
|
||||
alloc += alloc / 2;
|
||||
if (alloc < size + BUFSIZ + 1)
|
||||
alloc = size + BUFSIZ + 1;
|
||||
|
||||
if (VIR_REALLOC_N(*buf, alloc) < 0) {
|
||||
save_errno = errno;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure that (size + requested <= max_len); */
|
||||
requested = MIN(size < max_len ? max_len - size : 0,
|
||||
alloc - size - 1);
|
||||
count = glfs_read(fd, *buf + size, requested, 0);
|
||||
size += count;
|
||||
|
||||
if (count != requested || requested == 0) {
|
||||
save_errno = errno;
|
||||
if (count < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("cannot read header '%s'"), src->path);
|
||||
break;
|
||||
}
|
||||
ret = size;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
VIR_FREE(*buf);
|
||||
errno = save_errno;
|
||||
|
||||
cleanup:
|
||||
if (fd)
|
||||
glfs_close(fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
virStorageFileBackend virStorageFileBackendGluster = {
|
||||
.type = VIR_STORAGE_TYPE_NETWORK,
|
||||
.protocol = VIR_STORAGE_NET_PROTOCOL_GLUSTER,
|
||||
|
@ -647,4 +712,5 @@ virStorageFileBackend virStorageFileBackendGluster = {
|
|||
|
||||
.storageFileUnlink = virStorageFileBackendGlusterUnlink,
|
||||
.storageFileStat = virStorageFileBackendGlusterStat,
|
||||
.storageFileReadHeader = virStorageFileBackendGlusterReadHeader,
|
||||
};
|
||||
|
|
|
@ -2947,3 +2947,43 @@ virStorageFileStat(virStorageSourcePtr src,
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* virStorageFileReadHeader: read the beginning bytes of a file into a buffer
|
||||
*
|
||||
* @src: file structure pointing to the file
|
||||
* @max_len: maximum number of bytes read from the storage file
|
||||
* @buf: buffer to read the data into. buffer shall be freed by caller)
|
||||
*
|
||||
* Returns the count of bytes read on success and -1 on failure, -2 if the
|
||||
* function isn't supported by the backend. Libvirt error is reported on failure.
|
||||
*/
|
||||
ssize_t
|
||||
virStorageFileReadHeader(virStorageSourcePtr src,
|
||||
ssize_t max_len,
|
||||
char **buf)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
if (!virStorageFileIsInitialized(src)) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("storage file backend not initialized"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!src->drv->backend->storageFileReadHeader) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("storage file header reading is not supported for "
|
||||
"storage type %s (protocol: %s)'"),
|
||||
virStorageTypeToString(src->type),
|
||||
virStorageNetProtocolTypeToString(src->protocol));
|
||||
return -2;
|
||||
}
|
||||
|
||||
ret = src->drv->backend->storageFileReadHeader(src, max_len, buf);
|
||||
|
||||
VIR_DEBUG("read of storage header %p: ret=%zd", src, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,9 @@ int virStorageFileCreate(virStorageSourcePtr src);
|
|||
int virStorageFileUnlink(virStorageSourcePtr src);
|
||||
int virStorageFileStat(virStorageSourcePtr src,
|
||||
struct stat *stat);
|
||||
ssize_t virStorageFileReadHeader(virStorageSourcePtr src,
|
||||
ssize_t max_len,
|
||||
char **buf);
|
||||
|
||||
int storageRegister(void);
|
||||
|
||||
|
|
Loading…
Reference in New Issue