mirror of
https://github.com/kdave/btrfs-progs
synced 2025-05-04 00:47:56 +00:00
btrfs-progs: utils: split path related utils to own file
Group helpers that return some status of a given path to own file so we debloat utils.c a bit. Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
bb1b07848e
commit
f83e81c61b
2
Makefile
2
Makefile
@ -134,7 +134,7 @@ objects = ctree.o disk-io.o kernel-lib/radix-tree.o extent-tree.o print-tree.o \
|
||||
common/task-utils.o \
|
||||
inode.o file.o find-root.o free-space-tree.o common/help.o send-dump.o \
|
||||
common/fsfeatures.o kernel-lib/tables.o kernel-lib/raid56.o transaction.o \
|
||||
delayed-ref.o common/format-output.o
|
||||
delayed-ref.o common/format-output.o common/path-utils.o
|
||||
cmds_objects = cmds/subvolume.o cmds/filesystem.o cmds/device.o cmds/scrub.o \
|
||||
cmds/inspect.o cmds/balance.o cmds/send.o cmds/receive.o \
|
||||
cmds/quota.o cmds/qgroup.o cmds/replace.o check/main.o \
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include "cmds/commands.h"
|
||||
#include "common/help.h"
|
||||
#include "common/path-utils.h"
|
||||
#include "mkfs/common.h"
|
||||
|
||||
static const char * const device_cmd_group_usage[] = {
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "disk-io.h"
|
||||
#include "common/help.h"
|
||||
#include "common/fsfeatures.h"
|
||||
#include "common/path-utils.h"
|
||||
|
||||
/*
|
||||
* for btrfs fi show, we maintain a hash of fsids we've already printed.
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "send-utils.h"
|
||||
#include "send-dump.h"
|
||||
#include "common/help.h"
|
||||
#include "common/path-utils.h"
|
||||
|
||||
/*
|
||||
* Default is 1 for historical reasons, changing may break scripts that expect
|
||||
|
@ -38,6 +38,7 @@
|
||||
|
||||
#include "cmds/commands.h"
|
||||
#include "common/help.h"
|
||||
#include "common/path-utils.h"
|
||||
#include "mkfs/common.h"
|
||||
|
||||
static int print_replace_status(int fd, const char *path, int once);
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "send.h"
|
||||
#include "send-utils.h"
|
||||
#include "common/help.h"
|
||||
#include "common/path-utils.h"
|
||||
|
||||
#define SEND_BUFFER_SIZE SZ_64K
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "common/utils.h"
|
||||
#include "btrfs-list.h"
|
||||
#include "common/help.h"
|
||||
#include "common/path-utils.h"
|
||||
|
||||
static int wait_for_subvolume_cleaning(int fd, size_t count, uint64_t *ids,
|
||||
int sleep_interval)
|
||||
|
406
common/path-utils.c
Normal file
406
common/path-utils.c
Normal file
@ -0,0 +1,406 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License v2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 021110-1307, USA.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/loop.h>
|
||||
#include <linux/limits.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <mntent.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include "common/path-utils.h"
|
||||
|
||||
/*
|
||||
* checks if a path is a block device node
|
||||
* Returns negative errno on failure, otherwise
|
||||
* returns 1 for blockdev, 0 for not-blockdev
|
||||
*/
|
||||
int is_block_device(const char *path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat(path, &statbuf) < 0)
|
||||
return -errno;
|
||||
|
||||
return !!S_ISBLK(statbuf.st_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* check if given path is a mount point
|
||||
* return 1 if yes. 0 if no. -1 for error
|
||||
*/
|
||||
int is_mount_point(const char *path)
|
||||
{
|
||||
FILE *f;
|
||||
struct mntent *mnt;
|
||||
int ret = 0;
|
||||
|
||||
f = setmntent("/proc/self/mounts", "r");
|
||||
if (f == NULL)
|
||||
return -1;
|
||||
|
||||
while ((mnt = getmntent(f)) != NULL) {
|
||||
if (strcmp(mnt->mnt_dir, path))
|
||||
continue;
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
endmntent(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int is_reg_file(const char *path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat(path, &statbuf) < 0)
|
||||
return -errno;
|
||||
return S_ISREG(statbuf.st_mode);
|
||||
}
|
||||
|
||||
int is_path_exist(const char *path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
int ret;
|
||||
|
||||
ret = stat(path, &statbuf);
|
||||
if (ret < 0) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* checks if a device is a loop device */
|
||||
static int is_loop_device(const char *device)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if(stat(device, &statbuf) < 0)
|
||||
return -errno;
|
||||
|
||||
return (S_ISBLK(statbuf.st_mode) &&
|
||||
MAJOR(statbuf.st_rdev) == LOOP_MAJOR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Takes a loop device path (e.g. /dev/loop0) and returns
|
||||
* the associated file (e.g. /images/my_btrfs.img) using
|
||||
* loopdev API
|
||||
*/
|
||||
static int resolve_loop_device_with_loopdev(const char* loop_dev, char* loop_file)
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
struct loop_info64 lo64;
|
||||
|
||||
fd = open(loop_dev, O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
ret = ioctl(fd, LOOP_GET_STATUS64, &lo64);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(loop_file, lo64.lo_file_name, sizeof(lo64.lo_file_name));
|
||||
loop_file[sizeof(lo64.lo_file_name)] = 0;
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Takes a loop device path (e.g. /dev/loop0) and returns
|
||||
* the associated file (e.g. /images/my_btrfs.img)
|
||||
*/
|
||||
static int resolve_loop_device(const char* loop_dev, char* loop_file,
|
||||
int max_len)
|
||||
{
|
||||
int ret;
|
||||
FILE *f;
|
||||
char fmt[20];
|
||||
char p[PATH_MAX];
|
||||
char real_loop_dev[PATH_MAX];
|
||||
|
||||
if (!realpath(loop_dev, real_loop_dev))
|
||||
return -errno;
|
||||
snprintf(p, PATH_MAX, "/sys/block/%s/loop/backing_file", strrchr(real_loop_dev, '/'));
|
||||
if (!(f = fopen(p, "r"))) {
|
||||
if (errno == ENOENT)
|
||||
/*
|
||||
* It's possibly a partitioned loop device, which is
|
||||
* resolvable with loopdev API.
|
||||
*/
|
||||
return resolve_loop_device_with_loopdev(loop_dev, loop_file);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
snprintf(fmt, 20, "%%%i[^\n]", max_len - 1);
|
||||
ret = fscanf(f, fmt, loop_file);
|
||||
fclose(f);
|
||||
if (ret == EOF)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks whether a and b are identical or device
|
||||
* files associated with the same block device
|
||||
*/
|
||||
static int is_same_blk_file(const char* a, const char* b)
|
||||
{
|
||||
struct stat st_buf_a, st_buf_b;
|
||||
char real_a[PATH_MAX];
|
||||
char real_b[PATH_MAX];
|
||||
|
||||
if (!realpath(a, real_a))
|
||||
strncpy_null(real_a, a);
|
||||
|
||||
if (!realpath(b, real_b))
|
||||
strncpy_null(real_b, b);
|
||||
|
||||
/* Identical path? */
|
||||
if (strcmp(real_a, real_b) == 0)
|
||||
return 1;
|
||||
|
||||
if (stat(a, &st_buf_a) < 0 || stat(b, &st_buf_b) < 0) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Same blockdevice? */
|
||||
if (S_ISBLK(st_buf_a.st_mode) && S_ISBLK(st_buf_b.st_mode) &&
|
||||
st_buf_a.st_rdev == st_buf_b.st_rdev) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Hardlink? */
|
||||
if (st_buf_a.st_dev == st_buf_b.st_dev &&
|
||||
st_buf_a.st_ino == st_buf_b.st_ino) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if a and b are identical or device files associated with the same
|
||||
* block device or if one file is a loop device that uses the other file.
|
||||
*/
|
||||
int is_same_loop_file(const char *a, const char *b)
|
||||
{
|
||||
char res_a[PATH_MAX];
|
||||
char res_b[PATH_MAX];
|
||||
const char* final_a = NULL;
|
||||
const char* final_b = NULL;
|
||||
int ret;
|
||||
|
||||
/* Resolve a if it is a loop device */
|
||||
if ((ret = is_loop_device(a)) < 0) {
|
||||
if (ret == -ENOENT)
|
||||
return 0;
|
||||
return ret;
|
||||
} else if (ret) {
|
||||
ret = resolve_loop_device(a, res_a, sizeof(res_a));
|
||||
if (ret < 0) {
|
||||
if (errno != EPERM)
|
||||
return ret;
|
||||
} else {
|
||||
final_a = res_a;
|
||||
}
|
||||
} else {
|
||||
final_a = a;
|
||||
}
|
||||
|
||||
/* Resolve b if it is a loop device */
|
||||
if ((ret = is_loop_device(b)) < 0) {
|
||||
if (ret == -ENOENT)
|
||||
return 0;
|
||||
return ret;
|
||||
} else if (ret) {
|
||||
ret = resolve_loop_device(b, res_b, sizeof(res_b));
|
||||
if (ret < 0) {
|
||||
if (errno != EPERM)
|
||||
return ret;
|
||||
} else {
|
||||
final_b = res_b;
|
||||
}
|
||||
} else {
|
||||
final_b = b;
|
||||
}
|
||||
|
||||
return is_same_blk_file(final_a, final_b);
|
||||
}
|
||||
|
||||
/* Checks if a file exists and is a block or regular file*/
|
||||
int is_existing_blk_or_reg_file(const char *filename)
|
||||
{
|
||||
struct stat st_buf;
|
||||
|
||||
if (stat(filename, &st_buf) < 0) {
|
||||
if(errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return (S_ISBLK(st_buf.st_mode) || S_ISREG(st_buf.st_mode));
|
||||
}
|
||||
|
||||
/*
|
||||
* Resolve a pathname to a device mapper node to /dev/mapper/<name>
|
||||
* Returns NULL on invalid input or malloc failure; Other failures
|
||||
* will be handled by the caller using the input pathname.
|
||||
*/
|
||||
char *canonicalize_dm_name(const char *ptname)
|
||||
{
|
||||
FILE *f;
|
||||
size_t sz;
|
||||
char path[PATH_MAX], name[PATH_MAX], *res = NULL;
|
||||
|
||||
if (!ptname || !*ptname)
|
||||
return NULL;
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname);
|
||||
if (!(f = fopen(path, "r")))
|
||||
return NULL;
|
||||
|
||||
/* read <name>\n from sysfs */
|
||||
if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) {
|
||||
name[sz - 1] = '\0';
|
||||
snprintf(path, sizeof(path), "/dev/mapper/%s", name);
|
||||
|
||||
if (access(path, F_OK) == 0)
|
||||
res = strdup(path);
|
||||
}
|
||||
fclose(f);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resolve a pathname to a canonical device node, e.g. /dev/sda1 or
|
||||
* to a device mapper pathname.
|
||||
* Returns NULL on invalid input or malloc failure; Other failures
|
||||
* will be handled by the caller using the input pathname.
|
||||
*/
|
||||
char *canonicalize_path(const char *path)
|
||||
{
|
||||
char *canonical, *p;
|
||||
|
||||
if (!path || !*path)
|
||||
return NULL;
|
||||
|
||||
canonical = realpath(path, NULL);
|
||||
if (!canonical)
|
||||
return strdup(path);
|
||||
p = strrchr(canonical, '/');
|
||||
if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) {
|
||||
char *dm = canonicalize_dm_name(p + 1);
|
||||
|
||||
if (dm) {
|
||||
free(canonical);
|
||||
return dm;
|
||||
}
|
||||
}
|
||||
return canonical;
|
||||
}
|
||||
|
||||
/*
|
||||
* __strncpy_null - strncpy with null termination
|
||||
* @dest: the target array
|
||||
* @src: the source string
|
||||
* @n: maximum bytes to copy (size of *dest)
|
||||
*
|
||||
* Like strncpy, but ensures destination is null-terminated.
|
||||
*
|
||||
* Copies the string pointed to by src, including the terminating null
|
||||
* byte ('\0'), to the buffer pointed to by dest, up to a maximum
|
||||
* of n bytes. Then ensure that dest is null-terminated.
|
||||
*/
|
||||
char *__strncpy_null(char *dest, const char *src, size_t n)
|
||||
{
|
||||
strncpy(dest, src, n);
|
||||
if (n > 0)
|
||||
dest[n - 1] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if path is a directory
|
||||
* Returns:
|
||||
* 0 - path exists but it is not a directory
|
||||
* 1 - path exists and it is a directory
|
||||
* < 0 - error
|
||||
*/
|
||||
int test_isdir(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
int ret;
|
||||
|
||||
ret = stat(path, &st);
|
||||
if (ret < 0)
|
||||
return -errno;
|
||||
|
||||
return !!S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a path argument from SRC to DEST and check the SRC length if it's at
|
||||
* most PATH_MAX and fits into DEST. DESTLEN is supposed to be exact size of
|
||||
* the buffer.
|
||||
* The destination buffer is zero terminated.
|
||||
* Return < 0 for error, 0 otherwise.
|
||||
*/
|
||||
int arg_copy_path(char *dest, const char *src, int destlen)
|
||||
{
|
||||
size_t len = strlen(src);
|
||||
|
||||
if (len >= PATH_MAX || len >= destlen)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
__strncpy_null(dest, src, destlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Subvolume helper functions */
|
||||
/*
|
||||
* test if name is a correct subvolume name
|
||||
* this function return
|
||||
* 0-> name is not a correct subvolume name
|
||||
* 1-> name is a correct subvolume name
|
||||
*/
|
||||
int test_issubvolname(const char *name)
|
||||
{
|
||||
return name[0] != '\0' && !strchr(name, '/') &&
|
||||
strcmp(name, ".") && strcmp(name, "..");
|
||||
}
|
||||
|
41
common/path-utils.h
Normal file
41
common/path-utils.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License v2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 021110-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __BTRFS_PATH_UTILS_H__
|
||||
#define __BTRFS_PATH_UTILS_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
char *canonicalize_dm_name(const char *ptname);
|
||||
char *canonicalize_path(const char *path);
|
||||
|
||||
int arg_copy_path(char *dest, const char *src, int destlen);
|
||||
|
||||
char *__strncpy_null(char *dest, const char *src, size_t n);
|
||||
/* Helper to always get proper size of the destination string */
|
||||
#define strncpy_null(dest, src) __strncpy_null(dest, src, sizeof(dest))
|
||||
|
||||
int is_block_device(const char *file);
|
||||
int is_mount_point(const char *file);
|
||||
int is_path_exist(const char *file);
|
||||
int is_reg_file(const char *path);
|
||||
int is_same_loop_file(const char *a, const char *b);
|
||||
int is_existing_blk_or_reg_file(const char *filename);
|
||||
|
||||
int test_issubvolname(const char *name);
|
||||
int test_isdir(const char *path);
|
||||
|
||||
#endif
|
372
common/utils.c
372
common/utils.c
@ -49,6 +49,7 @@
|
||||
#include "transaction.h"
|
||||
#include "kernel-lib/crc32c.h"
|
||||
#include "common/utils.h"
|
||||
#include "common/path-utils.h"
|
||||
#include "volumes.h"
|
||||
#include "ioctl.h"
|
||||
#include "cmds/commands.h"
|
||||
@ -411,69 +412,6 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* checks if a path is a block device node
|
||||
* Returns negative errno on failure, otherwise
|
||||
* returns 1 for blockdev, 0 for not-blockdev
|
||||
*/
|
||||
int is_block_device(const char *path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat(path, &statbuf) < 0)
|
||||
return -errno;
|
||||
|
||||
return !!S_ISBLK(statbuf.st_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* check if given path is a mount point
|
||||
* return 1 if yes. 0 if no. -1 for error
|
||||
*/
|
||||
int is_mount_point(const char *path)
|
||||
{
|
||||
FILE *f;
|
||||
struct mntent *mnt;
|
||||
int ret = 0;
|
||||
|
||||
f = setmntent("/proc/self/mounts", "r");
|
||||
if (f == NULL)
|
||||
return -1;
|
||||
|
||||
while ((mnt = getmntent(f)) != NULL) {
|
||||
if (strcmp(mnt->mnt_dir, path))
|
||||
continue;
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
endmntent(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int is_reg_file(const char *path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat(path, &statbuf) < 0)
|
||||
return -errno;
|
||||
return S_ISREG(statbuf.st_mode);
|
||||
}
|
||||
|
||||
int is_path_exist(const char *path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
int ret;
|
||||
|
||||
ret = stat(path, &statbuf);
|
||||
if (ret < 0) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks if the given input parameter is
|
||||
* an uuid or a path
|
||||
@ -636,185 +574,6 @@ int btrfs_open_file_or_dir(const char *path, DIR **dirstream, int verbose)
|
||||
return btrfs_open(path, dirstream, verbose, 0);
|
||||
}
|
||||
|
||||
/* checks if a device is a loop device */
|
||||
static int is_loop_device (const char* device) {
|
||||
struct stat statbuf;
|
||||
|
||||
if(stat(device, &statbuf) < 0)
|
||||
return -errno;
|
||||
|
||||
return (S_ISBLK(statbuf.st_mode) &&
|
||||
MAJOR(statbuf.st_rdev) == LOOP_MAJOR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Takes a loop device path (e.g. /dev/loop0) and returns
|
||||
* the associated file (e.g. /images/my_btrfs.img) using
|
||||
* loopdev API
|
||||
*/
|
||||
static int resolve_loop_device_with_loopdev(const char* loop_dev, char* loop_file)
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
struct loop_info64 lo64;
|
||||
|
||||
fd = open(loop_dev, O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
ret = ioctl(fd, LOOP_GET_STATUS64, &lo64);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(loop_file, lo64.lo_file_name, sizeof(lo64.lo_file_name));
|
||||
loop_file[sizeof(lo64.lo_file_name)] = 0;
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Takes a loop device path (e.g. /dev/loop0) and returns
|
||||
* the associated file (e.g. /images/my_btrfs.img) */
|
||||
static int resolve_loop_device(const char* loop_dev, char* loop_file,
|
||||
int max_len)
|
||||
{
|
||||
int ret;
|
||||
FILE *f;
|
||||
char fmt[20];
|
||||
char p[PATH_MAX];
|
||||
char real_loop_dev[PATH_MAX];
|
||||
|
||||
if (!realpath(loop_dev, real_loop_dev))
|
||||
return -errno;
|
||||
snprintf(p, PATH_MAX, "/sys/block/%s/loop/backing_file", strrchr(real_loop_dev, '/'));
|
||||
if (!(f = fopen(p, "r"))) {
|
||||
if (errno == ENOENT)
|
||||
/*
|
||||
* It's possibly a partitioned loop device, which is
|
||||
* resolvable with loopdev API.
|
||||
*/
|
||||
return resolve_loop_device_with_loopdev(loop_dev, loop_file);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
snprintf(fmt, 20, "%%%i[^\n]", max_len-1);
|
||||
ret = fscanf(f, fmt, loop_file);
|
||||
fclose(f);
|
||||
if (ret == EOF)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks whether a and b are identical or device
|
||||
* files associated with the same block device
|
||||
*/
|
||||
static int is_same_blk_file(const char* a, const char* b)
|
||||
{
|
||||
struct stat st_buf_a, st_buf_b;
|
||||
char real_a[PATH_MAX];
|
||||
char real_b[PATH_MAX];
|
||||
|
||||
if (!realpath(a, real_a))
|
||||
strncpy_null(real_a, a);
|
||||
|
||||
if (!realpath(b, real_b))
|
||||
strncpy_null(real_b, b);
|
||||
|
||||
/* Identical path? */
|
||||
if (strcmp(real_a, real_b) == 0)
|
||||
return 1;
|
||||
|
||||
if (stat(a, &st_buf_a) < 0 || stat(b, &st_buf_b) < 0) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Same blockdevice? */
|
||||
if (S_ISBLK(st_buf_a.st_mode) && S_ISBLK(st_buf_b.st_mode) &&
|
||||
st_buf_a.st_rdev == st_buf_b.st_rdev) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Hardlink? */
|
||||
if (st_buf_a.st_dev == st_buf_b.st_dev &&
|
||||
st_buf_a.st_ino == st_buf_b.st_ino) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* checks if a and b are identical or device
|
||||
* files associated with the same block device or
|
||||
* if one file is a loop device that uses the other
|
||||
* file.
|
||||
*/
|
||||
static int is_same_loop_file(const char* a, const char* b)
|
||||
{
|
||||
char res_a[PATH_MAX];
|
||||
char res_b[PATH_MAX];
|
||||
const char* final_a = NULL;
|
||||
const char* final_b = NULL;
|
||||
int ret;
|
||||
|
||||
/* Resolve a if it is a loop device */
|
||||
if((ret = is_loop_device(a)) < 0) {
|
||||
if (ret == -ENOENT)
|
||||
return 0;
|
||||
return ret;
|
||||
} else if (ret) {
|
||||
ret = resolve_loop_device(a, res_a, sizeof(res_a));
|
||||
if (ret < 0) {
|
||||
if (errno != EPERM)
|
||||
return ret;
|
||||
} else {
|
||||
final_a = res_a;
|
||||
}
|
||||
} else {
|
||||
final_a = a;
|
||||
}
|
||||
|
||||
/* Resolve b if it is a loop device */
|
||||
if ((ret = is_loop_device(b)) < 0) {
|
||||
if (ret == -ENOENT)
|
||||
return 0;
|
||||
return ret;
|
||||
} else if (ret) {
|
||||
ret = resolve_loop_device(b, res_b, sizeof(res_b));
|
||||
if (ret < 0) {
|
||||
if (errno != EPERM)
|
||||
return ret;
|
||||
} else {
|
||||
final_b = res_b;
|
||||
}
|
||||
} else {
|
||||
final_b = b;
|
||||
}
|
||||
|
||||
return is_same_blk_file(final_a, final_b);
|
||||
}
|
||||
|
||||
/* Checks if a file exists and is a block or regular file*/
|
||||
static int is_existing_blk_or_reg_file(const char* filename)
|
||||
{
|
||||
struct stat st_buf;
|
||||
|
||||
if(stat(filename, &st_buf) < 0) {
|
||||
if(errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return (S_ISBLK(st_buf.st_mode) || S_ISREG(st_buf.st_mode));
|
||||
}
|
||||
|
||||
/* Checks if a file is used (directly or indirectly via a loop device)
|
||||
* by a device in fs_devices
|
||||
*/
|
||||
@ -832,64 +591,6 @@ static int blk_file_in_dev_list(struct btrfs_fs_devices* fs_devices,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resolve a pathname to a device mapper node to /dev/mapper/<name>
|
||||
* Returns NULL on invalid input or malloc failure; Other failures
|
||||
* will be handled by the caller using the input pathname.
|
||||
*/
|
||||
char *canonicalize_dm_name(const char *ptname)
|
||||
{
|
||||
FILE *f;
|
||||
size_t sz;
|
||||
char path[PATH_MAX], name[PATH_MAX], *res = NULL;
|
||||
|
||||
if (!ptname || !*ptname)
|
||||
return NULL;
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname);
|
||||
if (!(f = fopen(path, "r")))
|
||||
return NULL;
|
||||
|
||||
/* read <name>\n from sysfs */
|
||||
if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) {
|
||||
name[sz - 1] = '\0';
|
||||
snprintf(path, sizeof(path), "/dev/mapper/%s", name);
|
||||
|
||||
if (access(path, F_OK) == 0)
|
||||
res = strdup(path);
|
||||
}
|
||||
fclose(f);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resolve a pathname to a canonical device node, e.g. /dev/sda1 or
|
||||
* to a device mapper pathname.
|
||||
* Returns NULL on invalid input or malloc failure; Other failures
|
||||
* will be handled by the caller using the input pathname.
|
||||
*/
|
||||
char *canonicalize_path(const char *path)
|
||||
{
|
||||
char *canonical, *p;
|
||||
|
||||
if (!path || !*path)
|
||||
return NULL;
|
||||
|
||||
canonical = realpath(path, NULL);
|
||||
if (!canonical)
|
||||
return strdup(path);
|
||||
p = strrchr(canonical, '/');
|
||||
if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) {
|
||||
char *dm = canonicalize_dm_name(p + 1);
|
||||
|
||||
if (dm) {
|
||||
free(canonical);
|
||||
return dm;
|
||||
}
|
||||
}
|
||||
return canonical;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns 1 if the device was mounted, < 0 on error or 0 if everything
|
||||
* is safe to continue.
|
||||
@ -1197,26 +898,6 @@ int pretty_size_snprintf(u64 size, char *str, size_t str_size, unsigned unit_mod
|
||||
return snprintf(str, str_size, "%.2f%s", fraction, suffix[num_divs]);
|
||||
}
|
||||
|
||||
/*
|
||||
* __strncpy_null - strncpy with null termination
|
||||
* @dest: the target array
|
||||
* @src: the source string
|
||||
* @n: maximum bytes to copy (size of *dest)
|
||||
*
|
||||
* Like strncpy, but ensures destination is null-terminated.
|
||||
*
|
||||
* Copies the string pointed to by src, including the terminating null
|
||||
* byte ('\0'), to the buffer pointed to by dest, up to a maximum
|
||||
* of n bytes. Then ensure that dest is null-terminated.
|
||||
*/
|
||||
char *__strncpy_null(char *dest, const char *src, size_t n)
|
||||
{
|
||||
strncpy(dest, src, n);
|
||||
if (n > 0)
|
||||
dest[n - 1] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks to make sure that the label matches our requirements.
|
||||
* Returns:
|
||||
@ -2160,25 +1841,6 @@ int find_mount_root(const char *path, char **mount_root)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if path is a directory
|
||||
* Returns:
|
||||
* 0 - path exists but it is not a directory
|
||||
* 1 - path exists and it is a directory
|
||||
* < 0 - error
|
||||
*/
|
||||
int test_isdir(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
int ret;
|
||||
|
||||
ret = stat(path, &st);
|
||||
if (ret < 0)
|
||||
return -errno;
|
||||
|
||||
return !!S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
void units_set_mode(unsigned *units, unsigned mode)
|
||||
{
|
||||
unsigned base = *units & UNITS_MODE_MASK;
|
||||
@ -2320,25 +1982,6 @@ int btrfs_tree_search2_ioctl_supported(int fd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a path argument from SRC to DEST and check the SRC length if it's at
|
||||
* most PATH_MAX and fits into DEST. DESTLEN is supposed to be exact size of
|
||||
* the buffer.
|
||||
* The destination buffer is zero terminated.
|
||||
* Return < 0 for error, 0 otherwise.
|
||||
*/
|
||||
int arg_copy_path(char *dest, const char *src, int destlen)
|
||||
{
|
||||
size_t len = strlen(src);
|
||||
|
||||
if (len >= PATH_MAX || len >= destlen)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
__strncpy_null(dest, src, destlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int get_unit_mode_from_arg(int *argc, char *argv[], int df_mode)
|
||||
{
|
||||
unsigned int unit_mode = UNITS_DEFAULT;
|
||||
@ -2492,19 +2135,6 @@ int prefixcmp(const char *str, const char *prefix)
|
||||
return (unsigned char)*prefix - (unsigned char)*str;
|
||||
}
|
||||
|
||||
/* Subvolume helper functions */
|
||||
/*
|
||||
* test if name is a correct subvolume name
|
||||
* this function return
|
||||
* 0-> name is not a correct subvolume name
|
||||
* 1-> name is a correct subvolume name
|
||||
*/
|
||||
int test_issubvolname(const char *name)
|
||||
{
|
||||
return name[0] != '\0' && !strchr(name, '/') &&
|
||||
strcmp(name, ".") && strcmp(name, "..");
|
||||
}
|
||||
|
||||
const char *subvol_strip_mountpoint(const char *mnt, const char *full_path)
|
||||
{
|
||||
int len = strlen(mnt);
|
||||
|
@ -89,8 +89,6 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans,
|
||||
int btrfs_scan_for_fsid(int run_ioctls);
|
||||
int btrfs_register_one_device(const char *fname);
|
||||
int btrfs_register_all_devices(void);
|
||||
char *canonicalize_dm_name(const char *ptname);
|
||||
char *canonicalize_path(const char *path);
|
||||
int check_mounted(const char *devicename);
|
||||
int check_mounted_where(int fd, const char *file, char *where, int size,
|
||||
struct btrfs_fs_devices **fs_devices_mnt, unsigned sbflags);
|
||||
@ -104,7 +102,6 @@ const char *pretty_size_mode(u64 size, unsigned mode);
|
||||
u64 parse_size(char *s);
|
||||
u64 parse_qgroupid(const char *p);
|
||||
u64 arg_strtou64(const char *str);
|
||||
int arg_copy_path(char *dest, const char *src, int destlen);
|
||||
int open_file_or_dir(const char *fname, DIR **dirstream);
|
||||
int open_file_or_dir3(const char *fname, DIR **dirstream, int open_flags);
|
||||
void close_file_or_dir(int fd, DIR *dirstream);
|
||||
@ -120,19 +117,12 @@ void free_seen_fsid(struct seen_fsid *seen_fsid_hash[]);
|
||||
int get_label(const char *btrfs_dev, char *label);
|
||||
int set_label(const char *btrfs_dev, const char *label);
|
||||
|
||||
char *__strncpy_null(char *dest, const char *src, size_t n);
|
||||
int is_block_device(const char *file);
|
||||
int is_mount_point(const char *file);
|
||||
int is_path_exist(const char *file);
|
||||
int is_reg_file(const char *path);
|
||||
int check_arg_type(const char *input);
|
||||
int open_path_or_dev_mnt(const char *path, DIR **dirstream, int verbose);
|
||||
int btrfs_open(const char *path, DIR **dirstream, int verbose, int dir_only);
|
||||
int btrfs_open_dir(const char *path, DIR **dirstream, int verbose);
|
||||
int btrfs_open_file_or_dir(const char *path, DIR **dirstream, int verbose);
|
||||
u64 btrfs_device_size(int fd, struct stat *st);
|
||||
/* Helper to always get proper size of the destination string */
|
||||
#define strncpy_null(dest, src) __strncpy_null(dest, src, sizeof(dest))
|
||||
int get_label_mounted(const char *mount_path, char *labelp);
|
||||
int get_label_unmounted(const char *dev, char *label);
|
||||
int group_profile_max_safe_loss(u64 flags);
|
||||
@ -150,9 +140,6 @@ int test_uuid_unique(char *fs_uuid);
|
||||
u64 disk_size(const char *path);
|
||||
u64 get_partition_size(const char *dev);
|
||||
|
||||
int test_issubvolname(const char *name);
|
||||
int test_isdir(const char *path);
|
||||
|
||||
const char *subvol_strip_mountpoint(const char *mnt, const char *full_path);
|
||||
int find_next_key(struct btrfs_path *path, struct btrfs_key *key);
|
||||
const char* btrfs_group_type_str(u64 flag);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "disk-io.h"
|
||||
#include "volumes.h"
|
||||
#include "common/utils.h"
|
||||
#include "common/path-utils.h"
|
||||
#include "mkfs/common.h"
|
||||
#include "convert/common.h"
|
||||
|
||||
|
@ -97,6 +97,7 @@
|
||||
#include "transaction.h"
|
||||
#include "common/utils.h"
|
||||
#include "common/task-utils.h"
|
||||
#include "common/path-utils.h"
|
||||
#include "common/help.h"
|
||||
#include "mkfs/common.h"
|
||||
#include "convert/common.h"
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "disk-io.h"
|
||||
#include "volumes.h"
|
||||
#include "common/utils.h"
|
||||
#include "common/path-utils.h"
|
||||
#include "mkfs/common.h"
|
||||
|
||||
static u64 reference_root_table[] = {
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "volumes.h"
|
||||
#include "transaction.h"
|
||||
#include "common/utils.h"
|
||||
#include "common/path-utils.h"
|
||||
#include "kernel-lib/list_sort.h"
|
||||
#include "common/help.h"
|
||||
#include "common/rbtree-utils.h"
|
||||
|
Loading…
Reference in New Issue
Block a user