Skip to content

Commit bd7c42a

Browse files
committed
miscellaneous fixes
fix parallel_cpr path checking lustre_plugin depend on install_dependencies wrap gufi_dirfd error check with #ifdef __APPLE__ gufi_dir2index test update try_skip_lstat with DT_UNKNOWN test blobop unit test updates
1 parent 30bef1b commit bd7c42a

File tree

9 files changed

+187
-49
lines changed

9 files changed

+187
-49
lines changed

contrib/plugins/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,6 @@ find_path(LUSTRE_PLUGIN "lustre/lustreapi.h")
6565
# If so, build the lustre example plugin:
6666
if (LUSTRE_PLUGIN)
6767
add_library(lustre_plugin SHARED lustre_plugin.c)
68+
add_dependencies(lustre_plugin install_dependencies)
6869
target_link_libraries(lustre_plugin lustreapi)
6970
endif()

src/parallel_cpr.c

Lines changed: 81 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,69 @@ static int cpr_dir(QPTPool_ctx_t *ctx, void *data) {
278278
return rc;
279279
}
280280

281+
/*
282+
* check if lhs contains rhs
283+
*
284+
* lhs and rhs should be absolute paths
285+
*
286+
* lhs and rhs are modified but should exit this function with their original values
287+
* flip changes the order of the paths printed
288+
*
289+
* returns -1 on error
290+
* 0 on lhs does not contain rhs
291+
* 1 on lhs containes rhs
292+
*/
293+
static int check_contains(char *lhs, char *rhs, const int flip) {
294+
struct stat lhs_st;
295+
if (stat(lhs, &lhs_st) != 0) {
296+
const int err = errno;
297+
fprintf(stderr, "Error: Cannot stat \"%s\": %s (%d)\n",
298+
lhs, strerror(err), err);
299+
return -1;
300+
}
301+
302+
/* last path segment is not followed by a slash, so have to handle separately */
303+
struct stat rhs_st;
304+
if (stat(rhs, &rhs_st) != 0) {
305+
const int err = errno;
306+
fprintf(stderr, "Error: Cannot stat \"%s\": %s (%d)\n",
307+
rhs, strerror(err), err);
308+
return -1;
309+
}
310+
311+
if (lhs_st.st_ino == rhs_st.st_ino) {
312+
fprintf(stderr, "Error: Not copying into itself: \"%s\" -> \"%s\"\n",
313+
flip?rhs:lhs, flip?lhs:rhs);
314+
return 1;
315+
}
316+
317+
size_t len = trailing_match_index(rhs, strlen(rhs) - 1, "/", 1);
318+
while (len > 1) {
319+
rhs[len - 1] = '\0';
320+
321+
struct stat rhs_st;
322+
const int stat_rc = stat(rhs, &rhs_st);
323+
rhs[len - 1] = '/';
324+
325+
if (stat_rc != 0) {
326+
const int err = errno;
327+
fprintf(stderr, "Error: Cannot stat \"%s\": %s (%d)\n",
328+
rhs, strerror(err), err); /* rhs is the full path, not the stat-ed path */
329+
return -1;
330+
}
331+
332+
if (lhs_st.st_ino == rhs_st.st_ino) {
333+
fprintf(stderr, "Error: Not copying into itself: \"%s\" -> \"%s\"\n",
334+
flip?rhs:lhs, flip?lhs:rhs);
335+
return 1;
336+
}
337+
338+
len = trailing_match_index(rhs, len - 1, "/", 1);
339+
}
340+
341+
return 0;
342+
}
343+
281344
static int setup(const str_t *dst) {
282345
const mode_t old_umask = umask(0);
283346
umask(old_umask); /* reset umask */
@@ -315,13 +378,12 @@ int main(int argc, char * argv[]) {
315378
return EXIT_FAILURE;
316379
}
317380

318-
/* get realpath after set up to ensure the path exists */
319-
const char *dst = pa.dst.data;
320-
const char *real_dst = realpath(dst, NULL);
381+
/* get realpath after set up to ensure the destination path exists */
382+
char *real_dst = realpath(pa.dst.data, NULL);
321383
if (!real_dst) {
322384
const int err = errno;
323385
fprintf(stderr, "Error: Cannot get realpath of \"%s\": %s (%d)\n",
324-
dst, strerror(err), err);
386+
pa.dst.data, strerror(err), err);
325387
input_fini(&pa.in);
326388
return EXIT_FAILURE;
327389
}
@@ -330,7 +392,7 @@ int main(int argc, char * argv[]) {
330392
if (QPTPool_start(ctx) != 0) {
331393
fprintf(stderr, "Error: Failed to start thread pool\n");
332394
QPTPool_destroy(ctx);
333-
free((char *) real_dst);
395+
free(real_dst);
334396
input_fini(&pa.in);
335397
return EXIT_FAILURE;
336398
}
@@ -359,13 +421,20 @@ int main(int argc, char * argv[]) {
359421
work->root_parent.len = dirname_len(path, work->name_len);
360422

361423
if (S_ISDIR(st.st_mode)) {
362-
const char *real_path = realpath(path, NULL);
363-
const int match = !strncmp(real_dst, real_path, strlen(real_path));
364-
free((char *) real_path);
365-
if (match) {
366-
fprintf(stderr, "Not copying into itself: \"%s\" -> \"%s\"\n",
367-
path, dst);
424+
char *real_path = realpath(path, NULL);
425+
426+
/*
427+
* check if current source is under the destination
428+
* or if the destination is under the current source
429+
*/
430+
const int contains = (check_contains(real_path, real_dst, 0) ||
431+
check_contains(real_dst, real_path, 1));
432+
433+
free(real_path);
434+
435+
if (contains) {
368436
rc = 1;
437+
free(work);
369438
continue;
370439
}
371440

@@ -419,7 +488,7 @@ int main(int argc, char * argv[]) {
419488
const uint64_t threads_completed = QPTPool_threads_completed(ctx);
420489
QPTPool_destroy(ctx);
421490

422-
free((char *) real_dst);
491+
free(real_dst);
423492

424493
input_fini(&pa.in);
425494

src/utils.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,7 @@ ssize_t read_size(const int fd, void *buf, const size_t size) {
829829
*/
830830
int gufi_dirfd(DIR *d) {
831831
int d_fd = dirfd(d);
832+
#ifdef __APPLE__
832833
if (d_fd < 0) {
833834
/*
834835
* We should never get here. glibc's dirfd(3) never return errors, and
@@ -838,7 +839,7 @@ int gufi_dirfd(DIR *d) {
838839
fprintf(stderr, "BUG: dirfd(3) failed: errno = %d\n", errno);
839840
exit(1);
840841
}
841-
842+
#endif
842843
return d_fd;
843844
}
844845

test/regression/gufi_dir2index.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,10 @@ Could not stat source directory "": No such file or directory (2)
376376
Total Dirs: 0
377377
Total Non-Dirs: 0
378378

379+
# desintation path contains a file in a path segment
380+
$ gufi_dir2index -n 2 "prefix" "prefix/1KB/search"
381+
Could not create prefix/1KB/search
382+
379383
# skip file
380384
$ gufi_dir2index -n 2 --skip-file "skip" "prefix" "search"
381385
"search" Already exists!

test/regression/gufi_dir2index.sh.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ run_no_sort "${GUFI_DIR2INDEX} -n ${THREADS} \"${SRCDIR}/1KB\" \"${SEARCH}\"" |
218218
echo "# empty source path"
219219
run_no_sort "${GUFI_DIR2INDEX} -n ${THREADS} \"\" \"${TRACE}\""
220220

221+
echo "# desintation path contains a file in a path segment"
222+
run_no_sort "${GUFI_DIR2INDEX} -n ${THREADS} \"${SRCDIR}\" \"${SRCDIR}/1KB/${SEARCH}\""
223+
221224
echo "# skip file"
222225
run_no_sort "${GUFI_DIR2INDEX} -n ${THREADS} --skip-file \"${SKIP}\" \"${SRCDIR}\" \"${SEARCH}\""
223226

test/regression/parallel_cpr.expected

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ $ compare xattrs of "prefix/old_file"
8484
$ compare xattrs of "prefix/repeat_name"
8585
$ compare xattrs of "prefix/unusual#? directory ,"
8686
$ compare xattrs of "prefix/unusual#? directory ,/unusual, name?#"
87+
# Copy to similar name
88+
$ parallel_cpr "prefix" "prefix2"
89+
8790
$ rm -rf "copy"
8891

8992
$ parallel_cpr "prefix/leaf_directory/leaf_file1" "copy"
@@ -111,23 +114,27 @@ prefix/1KB
111114

112115
$ rm -rf "copy"
113116

114-
$ parallel_cpr "prefix" "copy"
117+
# copy to existing directory
118+
$ parallel_cpr "prefix" "copy"
115119

116120
$ rm -rf "copy"
117121

118-
$ parallel_cpr "prefix" "prefix"
119-
Not copying into itself: "prefix" -> "prefix"
122+
$ parallel_cpr "prefix" "prefix"
123+
Error: Not copying into itself: "prefix" -> "prefix"
124+
125+
$ parallel_cpr "prefix" "prefix/directory"
126+
Error: Not copying into itself: "prefix" -> "prefix/directory"
120127

121-
$ parallel_cpr "prefix" "prefix/directory"
122-
Not copying into itself: "prefix" -> "prefix/directory"
128+
$ parallel_cpr "prefix/directory" "prefix"
129+
Error: Not copying into itself: "prefix/directory" -> "prefix"
123130

124131
$ parallel_cpr "badtrace" "copy"
125132
Error: Cannot lstat "badtrace": No such file or directory (2)
126133

127-
$ parallel_cpr /dev/null "copy"
134+
$ parallel_cpr /dev/null "copy"
128135
Not copying "/dev/null"
129136

130-
$ parallel_cpr "prefix" "prefix/old_file"
137+
$ parallel_cpr "prefix" "prefix/old_file"
131138
Error: Cannot copy to "prefix/old_file": File exists (17)
132139

133140
$ parallel_cpr -n 18446744073709551615 "prefix" "copy"

test/regression/parallel_cpr.sh.in

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,10 @@ set -e
6767
OUTPUT="parallel_cpr.out"
6868

6969
CPR_ROOT="copy"
70+
CPR_ROOT2="${SRCDIR}2"
7071

7172
cleanup() {
72-
rm -rf "${CPR_ROOT}"
73+
rm -rf "${CPR_ROOT}" "${CPR_ROOT2}"
7374
}
7475

7576
cleanup_exit() {
@@ -114,6 +115,9 @@ do
114115
done
115116
set -e
116117

118+
echo "# Copy to similar name"
119+
run_no_sort "${PARALLEL_CPR} \"${SRCDIR}\" \"${CPR_ROOT2}\""
120+
117121
# copy single files/links
118122

119123
run_no_sort "rm -rf \"${CPR_ROOT}\""
@@ -128,26 +132,27 @@ run_no_sort "readlink \"${CPR_ROOT}/file_symlink\""
128132

129133
run_no_sort "rm -rf \"${CPR_ROOT}\""
130134

131-
# copy to existing directory
135+
echo "# copy to existing directory"
132136
mkdir "${CPR_ROOT}"
133-
run_no_sort "${PARALLEL_CPR} \"${SRCDIR}\" \"${CPR_ROOT}\""
137+
run_no_sort "${PARALLEL_CPR} \"${SRCDIR}\" \"${CPR_ROOT}\""
134138

135139
# errors
136140

137141
run_no_sort "rm -rf \"${CPR_ROOT}\""
138142

139143
# copy into self
140-
run_no_sort "${PARALLEL_CPR} \"${SRCDIR}\" \"${SRCDIR}\""
141-
run_no_sort "${PARALLEL_CPR} \"${SRCDIR}\" \"${SRCDIR}/directory\""
144+
run_no_sort "${PARALLEL_CPR} \"${SRCDIR}\" \"${SRCDIR}\""
145+
run_no_sort "${PARALLEL_CPR} \"${SRCDIR}\" \"${SRCDIR}/directory\""
146+
run_no_sort "${PARALLEL_CPR} \"${SRCDIR}/directory\" \"${SRCDIR}\""
142147

143148
# non-existant source
144149
run_no_sort "${PARALLEL_CPR} \"${BADTRACE}\" \"${CPR_ROOT}\""
145150

146151
# non-directory/link/file source
147-
run_no_sort "${PARALLEL_CPR} /dev/null \"${CPR_ROOT}\""
152+
run_no_sort "${PARALLEL_CPR} /dev/null \"${CPR_ROOT}\""
148153

149154
# directory to file
150-
run_no_sort "${PARALLEL_CPR} \"${SRCDIR}\" \"${SRCDIR}/old_file\""
155+
run_no_sort "${PARALLEL_CPR} \"${SRCDIR}\" \"${SRCDIR}/old_file\""
151156

152157
# bad thread count
153158
run_no_sort "${PARALLEL_CPR} -n 18446744073709551615 \"${SRCDIR}\" \"${CPR_ROOT}\""

test/unit/googletest/addqueryfuncs.cpp

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ OF SUCH DAMAGE.
6464

6565
#include <cmath>
6666
#include <ctime>
67+
#include <fstream>
6768
#include <grp.h>
6869
#include <pwd.h>
6970
#include <stdlib.h>
@@ -533,38 +534,72 @@ static int copy_blob_column_callback(void *args, int count, char **data, char **
533534
}
534535

535536
TEST(addqueryfuncs, blobop) {
536-
const char data[] = "abc def\n\x00\x01\x02 \x03\x04\x05\nghi jkl";
537-
const std::size_t len = sizeof(data) - 1;
538-
539537
// sqlite3 does not like binary in SQL statements, so write contents to temp file first
540538
char temp[] = "XXXXXX";
541-
int fd = mkstemp(temp);
542-
ASSERT_GT(fd, -1);
543-
ASSERT_EQ(write(fd, data, len), (ssize_t) len);
544-
close(fd);
539+
{
540+
const int fd = mkstemp(temp);
541+
ASSERT_GT(fd, -1);
542+
close(fd);
543+
}
545544

546545
sqlite3 *db = nullptr;
547546
ASSERT_EQ(sqlite3_open(SQLITE_MEMORY, &db), SQLITE_OK);
548547
ASSERT_NE(db, nullptr);
549-
550548
ASSERT_EQ(addqueryfuncs(db), 0);
551549

552-
// have to insert into table to get length later without opening file twice
553550
char cmd[1024];
554-
snprintf(cmd, sizeof(cmd), "CREATE TABLE data(col BLOB); INSERT INTO data SELECT blobop('cat %s');", temp);
555-
ASSERT_EQ(sqlite3_exec(db, cmd, nullptr, nullptr, nullptr), SQLITE_OK);
556-
557551
str_t output;
552+
memset(&output, 0, sizeof(output));
558553
char *err = nullptr;
559-
ASSERT_EQ(sqlite3_exec(db, "SELECT length(col), col FROM data;",
560-
copy_blob_column_callback, &output, &err), SQLITE_OK);
561-
EXPECT_EQ(err, nullptr);
562-
EXPECT_EQ(output.len, len);
563-
ASSERT_NE(output.data, nullptr);
564-
EXPECT_EQ(memcmp(output.data, data, len), 0);
565-
str_free_existing(&output);
566-
sqlite3_free(err);
567-
err = nullptr;
554+
555+
// have to insert into table to get length later without opening file twice
556+
557+
// empty file
558+
{
559+
snprintf(cmd, sizeof(cmd), "CREATE TABLE data(col BLOB); INSERT INTO data SELECT blobop('cat %s');", temp);
560+
ASSERT_EQ(sqlite3_exec(db, cmd, nullptr, nullptr, nullptr), SQLITE_OK);
561+
562+
ASSERT_EQ(sqlite3_exec(db, "SELECT length(col), col FROM data; DROP TABLE data;",
563+
copy_blob_column_callback, &output, &err), SQLITE_OK);
564+
EXPECT_EQ(err, nullptr);
565+
EXPECT_EQ(output.len, (std::size_t) 0);
566+
ASSERT_NE(output.data, nullptr);
567+
str_free_existing(&output);
568+
}
569+
570+
// short result
571+
{
572+
const char data[] = "abc def\n\x00\x01\x02 \x03\x04\x05\nghi jkl";
573+
const std::size_t len = sizeof(data) - 1;
574+
std::ofstream(temp).write(data, len);
575+
snprintf(cmd, sizeof(cmd), "CREATE TABLE data(col BLOB); INSERT INTO data SELECT blobop('cat %s');", temp);
576+
ASSERT_EQ(sqlite3_exec(db, cmd, nullptr, nullptr, nullptr), SQLITE_OK);
577+
578+
ASSERT_EQ(sqlite3_exec(db, "SELECT length(col), col FROM data; DROP TABLE data;",
579+
copy_blob_column_callback, &output, &err), SQLITE_OK);
580+
EXPECT_EQ(err, nullptr);
581+
EXPECT_EQ(output.len, len);
582+
ASSERT_NE(output.data, nullptr);
583+
EXPECT_EQ(memcmp(output.data, data, len), 0);
584+
str_free_existing(&output);
585+
}
586+
587+
// "long" result (force a reallocation)
588+
{
589+
const std::size_t len = 256;
590+
const std::string A(len, 'a');
591+
std::ofstream(temp) << A;
592+
snprintf(cmd, sizeof(cmd), "CREATE TABLE data(col BLOB); INSERT INTO data SELECT blobop('cat %s');", temp);
593+
ASSERT_EQ(sqlite3_exec(db, cmd, NULL, NULL, NULL), SQLITE_OK);
594+
595+
ASSERT_EQ(sqlite3_exec(db, "SELECT length(col), col FROM data; DROP TABLE data;",
596+
copy_blob_column_callback, &output, &err), SQLITE_OK);
597+
EXPECT_EQ(err, nullptr);
598+
EXPECT_EQ(output.len, len);
599+
ASSERT_NE(output.data, nullptr);
600+
EXPECT_EQ(memcmp(output.data, A.c_str(), len), 0);
601+
str_free_existing(&output);
602+
}
568603

569604
// not enough file descriptors
570605
{
@@ -575,7 +610,8 @@ TEST(addqueryfuncs, blobop) {
575610
fewer_fds.rlim_cur = 3;
576611
ASSERT_EQ(setrlimit(RLIMIT_NOFILE, &fewer_fds), 0);
577612

578-
ASSERT_EQ(sqlite3_exec(db, "SELECT blobop('echo blob');", copy_columns_callback, &output, &err), SQLITE_ERROR);
613+
ASSERT_EQ(sqlite3_exec(db, "SELECT blobop('echo blob');",
614+
copy_columns_callback, &output, &err), SQLITE_ERROR);
579615
EXPECT_NE(err, nullptr);
580616
sqlite3_free(err);
581617
err = nullptr;

0 commit comments

Comments
 (0)