diff options
Diffstat (limited to 'lib/libc')
-rw-r--r-- | lib/libc/db/hash/hash.c | 18 | ||||
-rw-r--r-- | lib/libc/db/man/dbm.3 | 5 | ||||
-rw-r--r-- | lib/libc/db/man/dbopen.3 | 5 | ||||
-rw-r--r-- | lib/libc/string/memchr.3 | 6 | ||||
-rw-r--r-- | lib/libc/tests/db/Makefile | 3 | ||||
-rw-r--r-- | lib/libc/tests/db/dbm_open_test.c | 52 | ||||
-rw-r--r-- | lib/libc/tests/db/dbm_perm_test.c | 98 |
7 files changed, 169 insertions, 18 deletions
diff --git a/lib/libc/db/hash/hash.c b/lib/libc/db/hash/hash.c index 7a66f5443d94..1eb01ee0f0c5 100644 --- a/lib/libc/db/hash/hash.c +++ b/lib/libc/db/hash/hash.c @@ -99,11 +99,6 @@ __hash_open(const char *file, int flags, int mode, DB *dbp; int bpages, hdrsize, new_table, nsegs, save_errno; - if ((flags & O_ACCMODE) == O_WRONLY) { - errno = EINVAL; - return (NULL); - } - if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB)))) return (NULL); hashp->fp = -1; @@ -115,12 +110,17 @@ __hash_open(const char *file, int flags, int mode, * we can check accesses. */ hashp->flags = flags; + if ((flags & O_ACCMODE) == O_WRONLY) { + flags &= ~O_WRONLY; + flags |= O_RDWR; + } if (file) { if ((hashp->fp = _open(file, flags | O_CLOEXEC, mode)) == -1) RETURN_ERROR(errno, error0); new_table = _fstat(hashp->fp, &statbuf) == 0 && - statbuf.st_size == 0 && (flags & O_ACCMODE) != O_RDONLY; + statbuf.st_size == 0 && + ((flags & O_ACCMODE) != O_RDONLY || (flags & O_CREAT) != 0); } else new_table = 1; @@ -179,7 +179,7 @@ __hash_open(const char *file, int flags, int mode, __buf_init(hashp, DEF_BUFSIZE); hashp->new_file = new_table; - hashp->save_file = file && (hashp->flags & O_RDWR); + hashp->save_file = file && (flags & O_RDWR); hashp->cbucket = -1; if (!(dbp = (DB *)malloc(sizeof(DB)))) { save_errno = errno; @@ -523,6 +523,10 @@ hash_get(const DB *dbp, const DBT *key, DBT *data, u_int32_t flag) hashp->error = errno = EINVAL; return (ERROR); } + if ((hashp->flags & O_ACCMODE) == O_WRONLY) { + hashp->error = errno = EPERM; + return (ERROR); + } return (hash_access(hashp, HASH_GET, (DBT *)key, data)); } diff --git a/lib/libc/db/man/dbm.3 b/lib/libc/db/man/dbm.3 index c5a83c7acef4..30787600ad2d 100644 --- a/lib/libc/db/man/dbm.3 +++ b/lib/libc/db/man/dbm.3 @@ -13,7 +13,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 2, 2022 +.Dd July 25, 2025 .Dt DBM 3 .Os .Sh NAME @@ -99,9 +99,6 @@ is a typical value for .Li 0660 is a typical value for .Fa mode . -.Dv O_WRONLY -is not allowed in -.Fa flags . The pointer returned by .Fn dbm_open identifies the database and is the diff --git a/lib/libc/db/man/dbopen.3 b/lib/libc/db/man/dbopen.3 index 64cef88506d8..7fe515f17849 100644 --- a/lib/libc/db/man/dbopen.3 +++ b/lib/libc/db/man/dbopen.3 @@ -76,13 +76,10 @@ are as specified to the .Xr open 2 routine, however, only the .Dv O_CREAT , O_EXCL , O_EXLOCK , O_NOFOLLOW , O_NONBLOCK , -.Dv O_RDONLY , O_RDWR , O_SHLOCK , O_SYNC +.Dv O_RDONLY , O_RDWR , O_SHLOCK , O_SYNC, O_WRONLY, and .Dv O_TRUNC flags are meaningful. -(Note, opening a database file -.Dv O_WRONLY -is not possible.) .\"Three additional options may be specified by .\".Em or Ns 'ing .\"them into the diff --git a/lib/libc/string/memchr.3 b/lib/libc/string/memchr.3 index 65617a117371..c50e932d3382 100644 --- a/lib/libc/string/memchr.3 +++ b/lib/libc/string/memchr.3 @@ -34,7 +34,7 @@ .Os .Sh NAME .Nm memchr -.Nd locate byte in byte string +.Nd locate byte in memory object .Sh LIBRARY .Lb libc .Sh SYNOPSIS @@ -51,7 +51,7 @@ locates the first occurrence of .Fa c (converted to an .Vt "unsigned char" ) -in string +in object .Fa b , limited to at most .Fa len @@ -63,7 +63,7 @@ function behaves like .Fn memchr , except that it locates the last occurrence of .Fa c -in string +in object .Fa b , limited to the first .Fa len diff --git a/lib/libc/tests/db/Makefile b/lib/libc/tests/db/Makefile index f1f33bd2bafc..cc181cc81160 100644 --- a/lib/libc/tests/db/Makefile +++ b/lib/libc/tests/db/Makefile @@ -7,6 +7,9 @@ PROGS+= h_lfsr ${PACKAGE}FILES+= README +ATF_TESTS_C+= dbm_open_test +ATF_TESTS_C+= dbm_perm_test + NETBSD_ATF_TESTS_C+= db_hash_seq_test NETBSD_ATF_TESTS_SH+= db_test ATF_TESTS_SH_SED_db_test= -e 's,/bin/csh,/bin/cat,g' diff --git a/lib/libc/tests/db/dbm_open_test.c b/lib/libc/tests/db/dbm_open_test.c new file mode 100644 index 000000000000..8a3e888bf72c --- /dev/null +++ b/lib/libc/tests/db/dbm_open_test.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <fcntl.h> +#include <ndbm.h> +#include <stdio.h> + +#include <atf-c.h> + +static const char *path = "tmp"; +static const char *dbname = "tmp.db"; + +ATF_TC(dbm_open_missing_test); +ATF_TC_HEAD(dbm_open_missing_test, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test dbm_open when creating a new database"); +} + +ATF_TC_BODY(dbm_open_missing_test, tc) +{ + + /* + * POSIX.1 specifies that a missing database file should + * always get created if O_CREAT is present, except when + * O_EXCL is specified as well. + */ + ATF_CHECK(dbm_open(path, O_RDONLY, 0755) == NULL); + ATF_REQUIRE(!atf_utils_file_exists(dbname)); + ATF_CHECK(dbm_open(path, O_RDONLY | O_CREAT, 0755) != NULL); + ATF_REQUIRE(atf_utils_file_exists(dbname)); + ATF_CHECK(dbm_open(path, O_RDONLY | O_CREAT | O_EXCL, 0755) == NULL); +} + +ATF_TC_WITHOUT_HEAD(dbm_open_wronly_test); +ATF_TC_BODY(dbm_open_wronly_test, tc) +{ + ATF_CHECK(dbm_open(path, O_WRONLY, 0755) == NULL); + ATF_REQUIRE(!atf_utils_file_exists(dbname)); + ATF_CHECK(dbm_open(path, O_WRONLY | O_CREAT, 0755) != NULL); + ATF_REQUIRE(atf_utils_file_exists(dbname)); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, dbm_open_missing_test); + ATF_TP_ADD_TC(tp, dbm_open_wronly_test); + return (atf_no_error()); +} diff --git a/lib/libc/tests/db/dbm_perm_test.c b/lib/libc/tests/db/dbm_perm_test.c new file mode 100644 index 000000000000..c07210292014 --- /dev/null +++ b/lib/libc/tests/db/dbm_perm_test.c @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <errno.h> +#include <fcntl.h> +#include <ndbm.h> +#include <stdio.h> + +#include <atf-c.h> + +static const char *path = "tmp"; +static const char *dbname = "tmp.db"; + +static void +create_db(void) +{ + DB *db; + datum data, key; + + data.dptr = "bar"; + data.dsize = strlen("bar"); + key.dptr = "foo"; + key.dsize = strlen("foo"); + + db = dbm_open(path, O_RDWR | O_CREAT, 0755); + ATF_CHECK(db != NULL); + ATF_REQUIRE(atf_utils_file_exists(dbname)); + ATF_REQUIRE(dbm_store(db, key, data, DBM_INSERT) != -1); + dbm_close(db); +} + +ATF_TC_WITHOUT_HEAD(dbm_rdonly_test); +ATF_TC_BODY(dbm_rdonly_test, tc) +{ + DB *db; + datum data, key; + + bzero(&data, sizeof(data)); + key.dptr = "foo"; + key.dsize = strlen("foo"); + create_db(); + + db = dbm_open(path, O_RDONLY, 0755); + data = dbm_fetch(db, key); + ATF_REQUIRE(data.dptr != NULL); + ATF_REQUIRE(strncmp((const char*)data.dptr, "bar", data.dsize) == 0); + ATF_REQUIRE(dbm_store(db, key, data, DBM_REPLACE) == -1); + ATF_REQUIRE(errno == EPERM); +} + +ATF_TC_WITHOUT_HEAD(dbm_wronly_test); +ATF_TC_BODY(dbm_wronly_test, tc) +{ + DB *db; + datum data, key; + + key.dptr = "foo"; + key.dsize = strlen("foo"); + data.dptr = "baz"; + data.dsize = strlen("baz"); + create_db(); + + db = dbm_open(path, O_WRONLY, 0755); + data = dbm_fetch(db, key); + ATF_REQUIRE(data.dptr == NULL); + ATF_REQUIRE(errno == EPERM); + ATF_REQUIRE(dbm_store(db, key, data, DBM_REPLACE) != -1); +} + +ATF_TC_WITHOUT_HEAD(dbm_rdwr_test); +ATF_TC_BODY(dbm_rdwr_test, tc) +{ + DB *db; + datum data, key; + + key.dptr = "foo"; + key.dsize = strlen("foo"); + create_db(); + + db = dbm_open(path, O_RDWR, 0755); + data = dbm_fetch(db, key); + ATF_REQUIRE(data.dptr != NULL); + data.dptr = "baz"; + data.dsize = strlen("baz"); + ATF_REQUIRE(dbm_store(db, key, data, DBM_REPLACE) != -1); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, dbm_rdonly_test); + ATF_TP_ADD_TC(tp, dbm_wronly_test); + ATF_TP_ADD_TC(tp, dbm_rdwr_test); + + return (atf_no_error()); +} |