Since directories can be used for <filesystem> passthrough, they are
basically storage volumes.
v2:
Skip ., .., lost+found dirs
v3:
Use gnulib last_component
v4:
Use gnulib "dirname.h", not system <dirname.h>
Don't skip lost+found
Signed-off-by: Cole Robinson <crobinso(a)redhat.com>
---
src/storage/storage_backend.c | 44 +++++++++++++++++++++++++++++++------
src/storage/storage_backend.h | 7 +++++-
src/storage/storage_backend_fs.c | 14 ++++++++---
src/util/storage_file.c | 30 +++++++++++++++++++++++++-
4 files changed, 82 insertions(+), 13 deletions(-)
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index 02e455f..d269e4c 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -36,6 +36,7 @@
#include <sys/stat.h>
#include <sys/param.h>
#include <dirent.h>
+#include "dirname.h"
#ifdef __linux__
# include <sys/ioctl.h>
# include <linux/fs.h>
@@ -994,6 +995,7 @@ virStorageBackendVolOpenCheckMode(const char *path, unsigned int
flags)
{
int fd, mode = 0;
struct stat sb;
+ char *base = last_component(path);
if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_NOCTTY)) < 0) {
if ((errno == ENOENT || errno == ELOOP) &&
@@ -1022,9 +1024,20 @@ virStorageBackendVolOpenCheckMode(const char *path, unsigned int
flags)
mode = VIR_STORAGE_VOL_OPEN_CHAR;
else if (S_ISBLK(sb.st_mode))
mode = VIR_STORAGE_VOL_OPEN_BLOCK;
+ else if (S_ISDIR(sb.st_mode)) {
+ mode = VIR_STORAGE_VOL_OPEN_DIR;
+
+ if (STREQ(base, ".") ||
+ STREQ(base, "..")) {
+ VIR_FORCE_CLOSE(fd);
+ VIR_INFO("Skipping special dir '%s'", base);
+ return -2;
+ }
+ }
if (!(mode & flags)) {
VIR_FORCE_CLOSE(fd);
+ VIR_INFO("Skipping volume '%s'", path);
if (mode & VIR_STORAGE_VOL_OPEN_ERROR) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1047,11 +1060,13 @@ int virStorageBackendVolOpen(const char *path)
int
virStorageBackendUpdateVolTargetInfo(virStorageVolTargetPtr target,
unsigned long long *allocation,
- unsigned long long *capacity)
+ unsigned long long *capacity,
+ unsigned int openflags)
{
int ret, fd;
- if ((ret = virStorageBackendVolOpen(target->path)) < 0)
+ if ((ret = virStorageBackendVolOpenCheckMode(target->path,
+ openflags)) < 0)
return ret;
fd = ret;
@@ -1066,24 +1081,34 @@ virStorageBackendUpdateVolTargetInfo(virStorageVolTargetPtr
target,
}
int
-virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
- int withCapacity)
+virStorageBackendUpdateVolInfoFlags(virStorageVolDefPtr vol,
+ int withCapacity,
+ unsigned int openflags)
{
int ret;
if ((ret = virStorageBackendUpdateVolTargetInfo(&vol->target,
- &vol->allocation,
- withCapacity ? &vol->capacity
: NULL)) < 0)
+ &vol->allocation,
+ withCapacity ? &vol->capacity : NULL,
+ openflags)) < 0)
return ret;
if (vol->backingStore.path &&
(ret = virStorageBackendUpdateVolTargetInfo(&vol->backingStore,
- NULL, NULL)) < 0)
+ NULL, NULL,
+ VIR_STORAGE_VOL_OPEN_DEFAULT)) < 0)
return ret;
return 0;
}
+int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
+ int withCapacity)
+{
+ return virStorageBackendUpdateVolInfoFlags(vol, withCapacity,
+ VIR_STORAGE_VOL_OPEN_DEFAULT);
+}
+
/*
* virStorageBackendUpdateVolTargetInfoFD:
* @conn: connection to report errors on
@@ -1125,6 +1150,11 @@ virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr
target,
*/
if (capacity)
*capacity = sb.st_size;
+ } else if (S_ISDIR(sb.st_mode)) {
+ *allocation = 0;
+ if (capacity)
+ *capacity = 0;
+
} else {
off_t end;
/* XXX this is POSIX compliant, but doesn't work for CHAR files,
diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h
index fcfbed0..67ac32c 100644
--- a/src/storage/storage_backend.h
+++ b/src/storage/storage_backend.h
@@ -93,6 +93,7 @@ enum {
VIR_STORAGE_VOL_OPEN_REG = 1 << 1, /* regular files okay */
VIR_STORAGE_VOL_OPEN_BLOCK = 1 << 2, /* block files okay */
VIR_STORAGE_VOL_OPEN_CHAR = 1 << 3, /* char files okay */
+ VIR_STORAGE_VOL_OPEN_DIR = 1 << 4, /* directories okay */
};
# define VIR_STORAGE_VOL_OPEN_DEFAULT (VIR_STORAGE_VOL_OPEN_ERROR |\
@@ -107,9 +108,13 @@ ATTRIBUTE_NONNULL(1);
int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
int withCapacity);
+int virStorageBackendUpdateVolInfoFlags(virStorageVolDefPtr vol,
+ int withCapacity,
+ unsigned int openflags);
int virStorageBackendUpdateVolTargetInfo(virStorageVolTargetPtr target,
unsigned long long *allocation,
- unsigned long long *capacity);
+ unsigned long long *capacity,
+ unsigned int openflags);
int virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target,
int fd,
unsigned long long *allocation,
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index b8d4d63..3f4d978 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -48,6 +48,11 @@
#define VIR_FROM_THIS VIR_FROM_STORAGE
+#define VIR_STORAGE_VOL_FS_OPEN_FLAGS (VIR_STORAGE_VOL_OPEN_DEFAULT |\
+ VIR_STORAGE_VOL_OPEN_DIR)
+#define VIR_STORAGE_VOL_FS_REFRESH_FLAGS (VIR_STORAGE_VOL_FS_OPEN_FLAGS &\
+ ~VIR_STORAGE_VOL_OPEN_ERROR)
+
static int ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
virStorageBackendProbeTarget(virStorageVolTargetPtr target,
char **backingStore,
@@ -65,7 +70,7 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
*encryption = NULL;
if ((ret = virStorageBackendVolOpenCheckMode(target->path,
- (VIR_STORAGE_VOL_OPEN_DEFAULT &
~VIR_STORAGE_VOL_OPEN_ERROR))) < 0)
+ VIR_STORAGE_VOL_FS_REFRESH_FLAGS)) < 0)
return ret; /* Take care to propagate ret, it is not always -1 */
fd = ret;
@@ -676,8 +681,8 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn
ATTRIBUTE_UNUSED,
vol->backingStore.format = backingStoreFormat;
if (virStorageBackendUpdateVolTargetInfo(&vol->backingStore,
- NULL,
- NULL) < 0) {
+ NULL, NULL,
+ VIR_STORAGE_VOL_OPEN_DEFAULT) < 0) {
/* The backing file is currently unavailable, the capacity,
* allocation, owner, group and mode are unknown. Just log the
* error an continue.
@@ -941,7 +946,8 @@ virStorageBackendFileSystemVolRefresh(virConnectPtr conn,
int ret;
/* Refresh allocation / permissions info in case its changed */
- ret = virStorageBackendUpdateVolInfo(vol, 0);
+ ret = virStorageBackendUpdateVolInfoFlags(vol, 0,
+ VIR_STORAGE_VOL_FS_OPEN_FLAGS);
if (ret < 0)
return ret;
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
index ede79fa..8dbd933 100644
--- a/src/util/storage_file.c
+++ b/src/util/storage_file.c
@@ -24,6 +24,7 @@
#include <config.h>
#include "storage_file.h"
+#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef __linux__
@@ -736,6 +737,19 @@ virStorageFileProbeFormatFromFD(const char *path, int fd)
unsigned char *head;
ssize_t len = STORAGE_MAX_HEAD;
int ret = -1;
+ struct stat sb;
+
+ if (fstat(fd, &sb) < 0) {
+ virReportSystemError(errno,
+ _("cannot stat file '%s'"),
+ path);
+ return -1;
+ }
+
+ /* No header to probe for directories */
+ if (S_ISDIR(sb.st_mode)) {
+ return VIR_STORAGE_FILE_DIR;
+ }
if (VIR_ALLOC_N(head, len) < 0) {
virReportOOMError();
@@ -812,9 +826,10 @@ virStorageFileGetMetadataFromFD(const char *path,
int format,
virStorageFileMetadata *meta)
{
- unsigned char *head;
+ unsigned char *head = NULL;
ssize_t len = STORAGE_MAX_HEAD;
int ret = -1;
+ struct stat sb;
if (VIR_ALLOC_N(head, len) < 0) {
virReportOOMError();
@@ -823,6 +838,19 @@ virStorageFileGetMetadataFromFD(const char *path,
memset(meta, 0, sizeof (*meta));
+ if (fstat(fd, &sb) < 0) {
+ virReportSystemError(errno,
+ _("cannot stat file '%s'"),
+ path);
+ return -1;
+ }
+
+ /* No header to probe for directories */
+ if (S_ISDIR(sb.st_mode)) {
+ ret = 0;
+ goto cleanup;
+ }
+
if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
virReportSystemError(errno, _("cannot seek to start of '%s'"),
path);
goto cleanup;
--
1.7.4.4