}
run_test 226c "call path2fid and fid2path under remote dir with subdir mount"
+test_226d () {
+ (( $CLIENT_VERSION >= $(version_code 2.15.57) )) ||
+ skip "Need client at least version 2.15.57"
+
+ # Define First test dataset
+ local testdirs_01=$DIR/$tdir
+ local testdata_01=$testdirs_01/${tdir}_01
+ local testresult_01=${tdir}_01
+ # Define Second test dataset
+ local testdirs_02=$DIR/$tdir/$tdir
+ local testdata_02=$testdirs_02/${tdir}_02
+ local testresult_02=${tdir}_02
+ # Define third test dataset (top level)
+ local testdata_03=$DIR/${tdir}_03
+ local testresult_03=${tdir}_03
+
+ # Create first test dataset
+ mkdir -p $testdirs_01 || error "cannot create dir $testdirs_01"
+ touch $testdata_01 || error "cannot create file $testdata_01"
+
+ # Create second test dataset
+ mkdir -p $testdirs_02 || error "cannot create dir $testdirs_02"
+ touch $testdata_02 || error "cannot create file $testdata_02"
+
+ # Create third test dataset
+ touch $testdata_03 || error "cannot create file $testdata_03"
+
+ local fid01=$($LFS getstripe -F "$testdata_01") ||
+ error "getstripe failed on $testdata_01"
+ local fid02=$($LFS getstripe -F "$testdata_02") ||
+ error "getstripe failed on $testdata_01"
+ local fid03=$($LFS getstripe -F "$testdata_03") ||
+ error "getstripe failed on $testdata_03"
+
+ # Verify only -n option
+ local out1=$($LFS fid2path -n $DIR $fid01) ||
+ error "fid2path failed on $fid01"
+ local out2=$($LFS fid2path -n $DIR $fid02) ||
+ error "fid2path failed on $fid02"
+ local out3=$($LFS fid2path -n $DIR $fid03) ||
+ error "fid2path failed on $fid03"
+
+ [[ "$out1" == "$testresult_01" ]] ||
+ error "fid2path failed: Expected $testresult_01 got $out1"
+ [[ "$out2" == "$testresult_02" ]] ||
+ error "fid2path failed: Expected $testresult_02 got $out2"
+ [[ "$out3" == "$testresult_03" ]] ||
+ error "fid2path failed: Expected $testresult_03 got $out3"
+
+ # Verify with option -fn together
+ out1=$($LFS fid2path -fn $DIR $fid01) ||
+ error "fid2path -fn failed on $fid01"
+ out2=$($LFS fid2path -fn $DIR $fid02) ||
+ error "fid2path -fn failed on $fid02"
+ out3=$($LFS fid2path -fn $DIR $fid03) ||
+ error "fid2path -fn failed on $fid03"
+
+ local tmpout=$(echo $out1 | cut -d" " -f2)
+ [[ "$tmpout" == "$testresult_01" ]] ||
+ error "fid2path -fn failed: Expected $testresult_01 got $out1"
+
+ tmpout=$(echo $out2 | cut -d" " -f2)
+ [[ "$tmpout" == "$testresult_02" ]] ||
+ error "fid2path -fn failed: Expected $testresult_02 got $out2"
+
+ tmpout=$(echo $out3 | cut -d" " -f2)
+ [[ "$tmpout" == "$testresult_03" ]] ||
+ error "fid2path -fn failed: Expected $testresult_03 got $out3"
+}
+run_test 226d "verify fid2path with -n and -fn option"
+
test_226e () {
(( $CLIENT_VERSION >= $(version_code 2.15.56) )) ||
skip "Need client at least version 2.15.56"
#include <linux/lnet/nidstr.h>
#include <lnetconfig/cyaml.h>
#include "lstddef.h"
+#include <uapi/linux/lustre/lustre_idl.h>
#ifndef NSEC_PER_SEC
# define NSEC_PER_SEC 1000000000UL
{"fid2path", lfs_fid2path, 0,
"Resolve the full path(s) for given FID(s). For a specific hardlink "
"specify link number <linkno>.\n"
- "usage: fid2path [--print-fid|-f] [--print-link|-c] [--link|-l <linkno>] "
- "[--print0|-0] <fsname|root> <fid>..."},
+ "usage: fid2path [--print0|-0] [--print-fid|-f] [--print-link|-c] "
+ "[--link|-l <linkno>] [--name|-n] <fsname|root> <fid>..."},
{"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
"usage: path2fid [--parents] <path> ..."},
{"rmfid", lfs_rmfid, 0, "Remove file(s) by FID(s)\n"
end[-1] = '\0';
}
+/* Helper function to lfs_fid2path. To print out only the file names and
+ * not the full path. Do not call OBD_IOC_FID2PATH for every file. Instead
+ * read the trusted.link xattr and loop over all the records to get all the
+ * file names.
+ */
+static int lfs_fid2path_prn_name(char *mnt_dir, char *path_buf,
+ bool print_linkno, bool print_fid, char *ptr,
+ const char *fid_str, int linktmp)
+{
+ char buf[65536]; /* BUFFER_SIZE 65536 */
+ char full_path[PATH_MAX * 2 + 2];
+ struct link_ea_header *leh;
+ struct link_ea_entry *lee;
+ ssize_t size;
+ int reclen, i, rc = 0;
+
+ /* Generate full_path */
+ snprintf(full_path, sizeof(full_path) - 1, "%s/%s", mnt_dir, path_buf);
+
+ size = getxattr(full_path, "trusted.link", buf, sizeof(buf));
+ if (size < 0) {
+ fprintf(stderr, "%s: failed to read %s xattr: %s\n", path_buf,
+ "trusted.link", strerror(errno));
+ rc = -errno;
+ goto fail;
+ }
+
+ leh = (struct link_ea_header *)buf;
+
+ if (leh->leh_magic == __swab32(LINK_EA_MAGIC))
+ leh->leh_reccount = __swab32(leh->leh_reccount);
+
+ lee = (struct link_ea_entry *)(leh + 1);
+
+ for (i = 0; i < leh->leh_reccount; i++) {
+ reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1];
+
+ /* handle -n -l case */
+ if (print_linkno) {
+ ptr = strrchr(path_buf, '/');
+ if (!ptr)
+ ptr = path_buf;
+ else
+ ptr = ptr + 1;
+
+ if (strcmp(ptr, lee->lee_name) == 0) {
+ if (print_fid)
+ printf("%s ", fid_str);
+
+ printf("%d ", linktmp);
+ printf("%s\n", lee->lee_name);
+ break;
+ }
+ } else {
+ if (print_fid)
+ printf("%s ", fid_str);
+ printf("%s\n", lee->lee_name);
+ }
+
+ /* Get next record */
+ lee = (struct link_ea_entry *)((char *)lee + reclen);
+ }
+fail:
+ return rc;
+}
+
static int lfs_fid2path(int argc, char **argv)
{
struct option long_opts[] = {
{ .val = 'c', .name = "print-link", .has_arg = no_argument },
{ .val = 'f', .name = "print-fid", .has_arg = no_argument },
{ .val = 'l', .name = "link", .has_arg = required_argument },
+ { .val = 'n', .name = "name", .has_arg = no_argument },
{ .name = NULL } };
- char short_opts[] = "0cfl:pr:";
+ char short_opts[] = "0cfl:pr:n";
+ bool print_only_fname = false;
+ bool print_linkno = false;
bool print_link = false;
bool print_fid = false;
bool print_mnt_dir;
int c;
int i;
- while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, short_opts,long_opts, NULL)) !=
+ -1) {
switch (c) {
case '0':
link_separator = '\0';
progname, optarg);
return CMD_HELP;
}
+ print_linkno = true;
+ break;
+ case 'n':
+ /* Bypass the full parent path if true
+ * only print the final filename */
+ print_only_fname = true;
break;
case 'r':
/* recno is something to do with changelogs
for (i = optind + 1; i < argc; i++) {
const char *fid_str = argv[i];
struct lu_fid fid;
+ char *ptr = NULL;
int rc2;
rc2 = llapi_fid_parse(fid_str, &fid, NULL);
}
int linktmp = (linkno >= 0) ? linkno : 0;
+
while (1) {
int oldtmp = linktmp;
long long rectmp = recno;
char path_buf[PATH_MAX];
- rc2 = llapi_fid2path_at(mnt_fd, &fid,
- path_buf, sizeof(path_buf), &rectmp, &linktmp);
+ rc2 = llapi_fid2path_at(mnt_fd, &fid, path_buf,
+ sizeof(path_buf), &rectmp,
+ &linktmp);
if (rc2 < 0) {
fprintf(stderr,
"%s fid2path: cannot find %s %s: %s\n",
break;
}
+ if (print_only_fname && !print_link) {
+ /* '-n' is passed as option here.
+ * For all other cases of -c fall back
+ * to default(else) path as to get the link
+ * count associated with the file name call
+ * to OBD_IOC_FID2PATH is required
+ */
+ rc = lfs_fid2path_prn_name(mnt_dir,
+ path_buf,
+ print_linkno,
+ print_fid, ptr,
+ fid_str, linktmp);
+ /* llapi_fid2path_at() is already called once
+ * in this case. No need to call it again.
+ * Break out as we have all the filenames.
+ */
+ break;
+ }
+
if (print_fid)
printf("%s ", fid_str);
*
* Note that llapi_fid2path() returns "" for the root
* FID. */
-
- printf("%s%s%s%c",
- print_mnt_dir ? mnt_dir : "",
- (print_mnt_dir || *path_buf == '\0') ?
- "/" : "", path_buf, link_separator);
+ if (!print_only_fname) {
+ printf("%s%s%s%c",
+ print_mnt_dir ? mnt_dir : "",
+ (print_mnt_dir || *path_buf == '\0') ?
+ "/" : "", path_buf, link_separator);
+ } else {
+ ptr = strrchr(path_buf, '/');
+ if (!ptr)
+ printf("%s\n", path_buf);
+ else
+ printf("%s\n", ptr + 1);
+ }
if (linkno >= 0)
/* specified linkno */
return rc < 0 ? -rc : rc;
}
-
-#ifdef _LUSTRE_IDL_H_
-/* Everything we need here should be included by lustreapi.h. */
-# error "lfs should not depend on lustre_idl.h"
-#endif /* _LUSTRE_IDL_H_ */