<commit_before>/*
 * storage_backend_fs.c: storage backend for FS and directory handling
 *
 * Copyright (C) 2007-2014 Red Hat, Inc.
 * Copyright (C) 2007-2008 <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * Author: <NAME> <<EMAIL>>
 */

#include <config.h>

#include <sys/statvfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>

#if WITH_BLKID
# include <blkid/blkid.h>
#endif

#include "virerror.h"
#include "storage_backend_fs.h"
#include "storage_conf.h"
#include "virstoragefile.h"
#include "vircommand.h"
#include "viralloc.h"
#include "virxml.h"
#include "virfile.h"
#include "virlog.h"
#include "virstring.h"

#define VIR_FROM_THIS VIR_FROM_STORAGE

VIR_LOG_INIT("storage.storage_backend_fs");

#define VIR_STORAGE_VOL_FS_OPEN_FLAGS    (VIR_STORAGE_VOL_OPEN_DEFAULT | \
                                          VIR_STORAGE_VOL_OPEN_DIR)
#define VIR_STORAGE_VOL_FS_PROBE_FLAGS   (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \
                                          VIR_STORAGE_VOL_OPEN_NOERROR)

static int ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
virStorageBackendProbeTarget(virStorageSourcePtr target,
                             char **backingStore,
                             int *backingStoreFormat,
                             virStorageEncryptionPtr *encryption)
{
    int fd = -1;
    int ret = -1;
    virStorageSourcePtr meta = NULL;
    struct stat sb;
    char *header = NULL;
    ssize_t len = VIR_STORAGE_MAX_HEADER;

    *backingStore = NULL;
    *backingStoreFormat = VIR_STORAGE_FILE_AUTO;
    if (encryption)
        *encryption = NULL;

    if ((ret = virStorageBackendVolOpen(target->path, &sb,
                                        VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0)
        goto error; /* Take care to propagate ret, it is not always -1 */
    fd = ret;

    if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd,
                                                      &sb, true)) < 0) {
        goto error;
    }

    if (S_ISDIR(sb.st_mode)) {
        target->format = VIR_STORAGE_FILE_DIR;
    } else {
        if ((len = virFileReadHeaderFD(fd, len, &header)) < 0) {
            virReportSystemError(errno, _("cannot read header '%s'"),
                                 target->path);
            goto error;
        }

        if (!(meta = virStorageFileGetMetadataFromBuf(target->path,
                                                      header, len,
                                                      backingStore,
                                                      backingStoreFormat))) {
            ret = -1;
            goto error;
        }
    }

    VIR_FORCE_CLOSE(fd);

    if (meta && *backingStore &&
        *backingStoreFormat == VIR_STORAGE_FILE_AUTO &&
        virStorageIsFile(*backingStore)) {
        if ((ret = virStorageFileProbeFormat(*backingStore, -1, -1)) < 0) {
            /* If the backing file is currently unavailable, only log an error,
             * but continue. Returning -1 here would disable the whole storage
             * pool, making it unavailable for even maintenance. */
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot probe backing volume format: %s"),
                           *backingStore);
            ret = -3;
        } else {
            *backingStoreFormat = ret;
            ret = 0;
        }
    } else {
        ret = 0;
    }

    if (meta && meta->capacity)
        target->capacity = meta->capacity;

    if (encryption && meta && meta->encryption) {
        *encryption = meta->encryption;
        meta->encryption = NULL;

        switch (target->format) {
        case VIR_STORAGE_FILE_QCOW:
        case VIR_STORAGE_FILE_QCOW2:
            (*encryption)->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW;
            break;
        default:
            break;
        }

        /* XXX ideally we'd fill in secret UUID here
         * but we cannot guarantee 'conn' is non-NULL
         * at this point in time :-(  So we only fill
         * in secrets when someone first queries a vol
         */
    }

    virBitmapFree(target->features);
    if (meta) {
        target->features = meta->features;
        meta->features = NULL;
    }

    if (meta && meta->compat) {
        VIR_FREE(target->compat);
        target->compat = meta->compat;
        meta->compat = NULL;
    }

    goto cleanup;

 error:
    VIR_FORCE_CLOSE(fd);

 cleanup:
    virStorageSourceFree(meta);
    VIR_FREE(header);
    return ret;

}

#if WITH_STORAGE_FS

# include <mntent.h>

struct _virNetfsDiscoverState {<commit_msg>storage: fs: Drop-in replace use of virStorageFileGetMetadataFromBuf<commit_after>/*
 * storage_backend_fs.c: storage backend for FS and directory handling
 *
 * Copyright (C) 2007-2014 Red Hat, Inc.
 * Copyright (C) 2007-2008 <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * Author: <NAME> <<EMAIL>>
 */

#include <config.h>

#include <sys/statvfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>

#if WITH_BLKID
# include <blkid/blkid.h>
#endif

#include "virerror.h"
#include "storage_backend_fs.h"
#include "storage_conf.h"
#include "virstoragefile.h"
#include "vircommand.h"
#include "viralloc.h"
#include "virxml.h"
#include "virfile.h"
#include "virlog.h"
#include "virstring.h"

#define VIR_FROM_THIS VIR_FROM_STORAGE

VIR_LOG_INIT("storage.storage_backend_fs");

#define VIR_STORAGE_VOL_FS_OPEN_FLAGS    (VIR_STORAGE_VOL_OPEN_DEFAULT | \
                                          VIR_STORAGE_VOL_OPEN_DIR)
#define VIR_STORAGE_VOL_FS_PROBE_FLAGS   (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \
                                          VIR_STORAGE_VOL_OPEN_NOERROR)

static int ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
virStorageBackendProbeTarget(virStorageSourcePtr target,
                             char **backingStore,
                             int *backingStoreFormat,
                             virStorageEncryptionPtr *encryption)
{
    int fd = -1;
    int ret = -1;
    virStorageSourcePtr meta = NULL;
    struct stat sb;

    *backingStore = NULL;
    *backingStoreFormat = VIR_STORAGE_FILE_AUTO;
    if (encryption)
        *encryption = NULL;

    if ((ret = virStorageBackendVolOpen(target->path, &sb,
                                        VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0)
        goto error; /* Take care to propagate ret, it is not always -1 */
    fd = ret;

    if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd,
                                                      &sb, true)) < 0) {
        goto error;
    }

    ret = -1;

    if (S_ISDIR(sb.st_mode)) {
        target->format = VIR_STORAGE_FILE_DIR;
    } else {
        if (!(meta = virStorageFileGetMetadataFromFD(target->path,
                                                     fd,
                                                     VIR_STORAGE_FILE_AUTO,
                                                     backingStoreFormat)))
            goto error;

        if (VIR_STRDUP(*backingStore, meta->backingStoreRaw) < 0)
            goto error;
    }

    VIR_FORCE_CLOSE(fd);

    if (meta && *backingStore &&
        *backingStoreFormat == VIR_STORAGE_FILE_AUTO &&
        virStorageIsFile(*backingStore)) {
        if ((ret = virStorageFileProbeFormat(*backingStore, -1, -1)) < 0) {
            /* If the backing file is currently unavailable, only log an error,
             * but continue. Returning -1 here would disable the whole storage
             * pool, making it unavailable for even maintenance. */
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot probe backing volume format: %s"),
                           *backingStore);
            ret = -3;
        } else {
            *backingStoreFormat = ret;
            ret = 0;
        }
    } else {
        ret = 0;
    }

    if (meta && meta->capacity)
        target->capacity = meta->capacity;

    if (encryption && meta && meta->encryption) {
        *encryption = meta->encryption;
        meta->encryption = NULL;

        switch (target->format) {
        case VIR_STORAGE_FILE_QCOW:
        case VIR_STORAGE_FILE_QCOW2:
            (*encryption)->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW;
            break;
        default:
            break;
        }

        /* XXX ideally we'd fill in secret UUID here
         * but we cannot guarantee 'conn' is non-NULL
         * at this point in time :-(  So we only fill
         * in secrets when someone first queries a vol
         */
    }

    virBitmapFree(target->features);
    if (meta) {
        target->features = meta->features;
        meta->features = NULL;
    }

    if (meta && meta->compat) {
        VIR_FREE(target->compat);
        target->compat = meta->compat;
        meta->compat = NULL;
    }

    goto cleanup;

 error:
    VIR_FORCE_CLOSE(fd);

 cleanup:
    virStorageSourceFree(meta);
    return ret;

}

#if WITH_STORAGE_FS

# include <mntent.h>

struct _virNetfsDiscoverState {
{'fraction_non_alphanumeric': 0.0969628372005282, 'fraction_numerical': 0.006602527824938691, 'mean_word_length': 2.0876528829353522, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 85, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 8}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 29, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7227296', 'n_tokens_mistral': 3261, 'n_tokens_neox': 3169, 'n_words': 853}