Skip to content

Commit 45ca77f

Browse files
committed
btrfs-progs: add basename wrappers for unified semantics
What basename(3) does with the argument depends on _GNU_SOURCE and inclusion of libgen.h. This is problematic on Musl (1.2.5) as reported. We want the GNU semantics that does not modify the argument. Common way to make it portable is to add own helper. This is now implemented in path_basename() that does not use the libc provided basename but preserves the semantics. The path_dirname() is just for parity, otherwise same as dirname(). Sources: - https://bugs.gentoo.org/926288 - https://git.musl-libc.org/cgit/musl/commit/?id=725e17ed6dff4d0cd22487bb64470881e86a92e7 Issue: #778 Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 4d1fc48 commit 45ca77f

File tree

4 files changed

+45
-15
lines changed

4 files changed

+45
-15
lines changed

cmds/subvolume.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include <string.h>
2525
#include <unistd.h>
2626
#include <errno.h>
27-
#include <libgen.h>
2827
#include <getopt.h>
2928
#include <dirent.h>
3029
#include <stdbool.h>
@@ -149,7 +148,7 @@ static int create_one_subvolume(const char *dst, struct btrfs_qgroup_inherit *in
149148
int fddst = -1;
150149
char *dupname = NULL;
151150
char *dupdir = NULL;
152-
char *newname;
151+
const char *newname;
153152
char *dstdir;
154153

155154
ret = path_is_dir(dst);
@@ -170,15 +169,15 @@ static int create_one_subvolume(const char *dst, struct btrfs_qgroup_inherit *in
170169
ret = -ENOMEM;
171170
goto out;
172171
}
173-
newname = basename(dupname);
172+
newname = path_basename(dupname);
174173

175174
dupdir = strdup(dst);
176175
if (!dupdir) {
177176
error_msg(ERROR_MSG_MEMORY, "duplicating %s", dst);
178177
ret = -ENOMEM;
179178
goto out;
180179
}
181-
dstdir = dirname(dupdir);
180+
dstdir = path_dirname(dupdir);
182181

183182
if (!test_issubvolname(newname)) {
184183
error("invalid subvolume name: %s", newname);
@@ -364,7 +363,8 @@ static int cmd_subvolume_delete(const struct cmd_struct *cmd, int argc, char **a
364363
int res, ret = 0;
365364
int cnt;
366365
int fd = -1;
367-
char *dname, *vname, *cpath;
366+
char *dname, *cpath;
367+
const char *vname;
368368
char *dupdname = NULL;
369369
char *dupvname = NULL;
370370
char *path = NULL;
@@ -482,9 +482,9 @@ static int cmd_subvolume_delete(const struct cmd_struct *cmd, int argc, char **a
482482
goto out;
483483
}
484484
dupdname = strdup(cpath);
485-
dname = dirname(dupdname);
485+
dname = path_dirname(dupdname);
486486
dupvname = strdup(cpath);
487-
vname = basename(dupvname);
487+
vname = path_basename(dupvname);
488488
free(cpath);
489489

490490
/* When subvolid is passed, <path> will point to the mount point */
@@ -670,7 +670,7 @@ static int cmd_subvolume_snapshot(const struct cmd_struct *cmd, int argc, char *
670670
bool readonly = false;
671671
char *dupname = NULL;
672672
char *dupdir = NULL;
673-
char *newname;
673+
const char *newname;
674674
char *dstdir;
675675
enum btrfs_util_error err;
676676
struct btrfs_ioctl_vol_args_v2 args;
@@ -727,13 +727,13 @@ static int cmd_subvolume_snapshot(const struct cmd_struct *cmd, int argc, char *
727727

728728
if (res > 0) {
729729
dupname = strdup(subvol);
730-
newname = basename(dupname);
730+
newname = path_basename(dupname);
731731
dstdir = dst;
732732
} else {
733733
dupname = strdup(dst);
734-
newname = basename(dupname);
734+
newname = path_basename(dupname);
735735
dupdir = strdup(dst);
736-
dstdir = dirname(dupdir);
736+
dstdir = path_dirname(dupdir);
737737
}
738738

739739
if (!test_issubvolname(newname)) {
@@ -1557,7 +1557,7 @@ static int cmd_subvolume_show(const struct cmd_struct *cmd, int argc, char **arg
15571557
struct btrfs_util_subvolume_iterator *iter;
15581558
struct btrfs_util_subvolume_info subvol;
15591559
char *subvol_path = NULL;
1560-
char *subvol_name = NULL;
1560+
const char *subvol_name = NULL;
15611561
enum btrfs_util_error err;
15621562
struct btrfs_qgroup_stats stats;
15631563
unsigned int unit_mode;
@@ -1669,7 +1669,7 @@ static int cmd_subvolume_show(const struct cmd_struct *cmd, int argc, char **arg
16691669
subvol_path = strdup("/");
16701670
subvol_name = "<FS_TREE>";
16711671
} else {
1672-
subvol_name = basename(subvol_path);
1672+
subvol_name = path_basename(subvol_path);
16731673
}
16741674

16751675
if (bconf.output_format == CMD_FORMAT_JSON) {

common/device-utils.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,14 +343,14 @@ static u64 device_get_partition_size_sysfs(const char *dev)
343343
char path[PATH_MAX] = {};
344344
char sysfs[PATH_MAX] = {};
345345
char sizebuf[128] = {};
346-
char *name = NULL;
346+
const char *name = NULL;
347347
int sysfd;
348348
unsigned long long size = 0;
349349

350350
name = realpath(dev, path);
351351
if (!name)
352352
return 0;
353-
name = basename(path);
353+
name = path_basename(path);
354354

355355
ret = path_cat3_out(sysfs, "/sys/class/block", name, "size");
356356
if (ret < 0)

common/path-utils.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
#include <string.h>
2929
#include <errno.h>
3030
#include <ctype.h>
31+
/*
32+
* For dirname() and basename(), but never use basename directly, there's
33+
* path_basename() with unified GNU behaviour regardless of the includes and
34+
* conditional defines. See basename(3) for more.
35+
*/
3136
#include <libgen.h>
3237
#include <limits.h>
3338
#include "common/path-utils.h"
@@ -482,3 +487,26 @@ int test_issubvolname(const char *name)
482487
strcmp(name, ".") && strcmp(name, "..");
483488
}
484489

490+
/*
491+
* Unified GNU semantics basename helper, never changing the argument. Always
492+
* use this instead of basename().
493+
*/
494+
const char *path_basename(const char *path)
495+
{
496+
const char *tmp = strrchr(path, '/');
497+
498+
/* Special case when the whole path is just "/". */
499+
if (path[0] == '/' && path[1] == 0)
500+
return path;
501+
502+
return tmp ? tmp + 1 : path;
503+
}
504+
505+
/*
506+
* Return dirname component of path, may change the argument.
507+
* Own helper for parity with path_basename().
508+
*/
509+
char *path_dirname(char *path)
510+
{
511+
return dirname(path);
512+
}

common/path-utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ int path_is_dir(const char *path);
3939
int is_same_loop_file(const char *a, const char *b);
4040
int path_is_reg_or_block_device(const char *filename);
4141
int path_is_in_dir(const char *parent, const char *path);
42+
const char *path_basename(const char *path);
43+
char *path_dirname(char *path);
4244

4345
int test_issubvolname(const char *name);
4446

0 commit comments

Comments
 (0)