summaryrefslogtreecommitdiffstats
path: root/source4/ntvfs/posix/pvfs_util.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source4/ntvfs/posix/pvfs_util.c
parentInitial commit. (diff)
downloadsamba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz
samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source4/ntvfs/posix/pvfs_util.c')
-rw-r--r--source4/ntvfs/posix/pvfs_util.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/source4/ntvfs/posix/pvfs_util.c b/source4/ntvfs/posix/pvfs_util.c
new file mode 100644
index 0000000..2975e04
--- /dev/null
+++ b/source4/ntvfs/posix/pvfs_util.c
@@ -0,0 +1,206 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ utility functions for posix backend
+*/
+
+#include "includes.h"
+#include "vfs_posix.h"
+
+/*
+ return true if a string contains one of the CIFS wildcard characters
+*/
+bool pvfs_has_wildcard(const char *str)
+{
+ if (strpbrk(str, "*?<>\"")) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ map a unix errno to a NTSTATUS
+*/
+NTSTATUS pvfs_map_errno(struct pvfs_state *pvfs, int unix_errno)
+{
+ NTSTATUS status;
+ status = map_nt_error_from_unix_common(unix_errno);
+ DEBUG(10,(__location__ " mapped unix errno %d -> %s\n", unix_errno, nt_errstr(status)));
+ return status;
+}
+
+
+/*
+ check if a filename has an attribute matching the given attribute search value
+ this is used by calls like unlink and search which take an attribute
+ and only include special files if they match the given attribute
+*/
+NTSTATUS pvfs_match_attrib(struct pvfs_state *pvfs, struct pvfs_filename *name,
+ uint32_t attrib, uint32_t must_attrib)
+{
+ if ((name->dos.attrib & ~attrib) & FILE_ATTRIBUTE_DIRECTORY) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ }
+ if ((name->dos.attrib & ~attrib) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+ if (must_attrib & ~name->dos.attrib) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ return NT_STATUS_OK;
+}
+
+
+/*
+ normalise a file attribute
+*/
+uint32_t pvfs_attrib_normalise(uint32_t attrib, mode_t mode)
+{
+ if (attrib != FILE_ATTRIBUTE_NORMAL) {
+ attrib &= ~FILE_ATTRIBUTE_NORMAL;
+ }
+ if (S_ISDIR(mode)) {
+ attrib |= FILE_ATTRIBUTE_DIRECTORY;
+ } else {
+ attrib &= ~FILE_ATTRIBUTE_DIRECTORY;
+ }
+ return attrib;
+}
+
+
+/*
+ copy a file. Caller is supposed to have already ensured that the
+ operation is allowed. The destination file must not exist.
+*/
+NTSTATUS pvfs_copy_file(struct pvfs_state *pvfs,
+ struct pvfs_filename *name1,
+ struct pvfs_filename *name2,
+ bool allow_override)
+{
+ int fd1, fd2;
+ mode_t mode;
+ NTSTATUS status;
+ size_t buf_size = 0x10000;
+ uint8_t *buf = talloc_array(name2, uint8_t, buf_size);
+
+ if (buf == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ fd1 = pvfs_sys_open(pvfs, name1->full_name, O_RDONLY, 0, allow_override);
+ if (fd1 == -1) {
+ talloc_free(buf);
+ return pvfs_map_errno(pvfs, errno);
+ }
+
+ fd2 = pvfs_sys_open(pvfs, name2->full_name, O_CREAT|O_EXCL|O_WRONLY, 0, allow_override);
+ if (fd2 == -1) {
+ close(fd1);
+ talloc_free(buf);
+ return pvfs_map_errno(pvfs, errno);
+ }
+
+ while (1) {
+ ssize_t ret2, ret = read(fd1, buf, buf_size);
+ if (ret == -1 &&
+ (errno == EINTR || errno == EAGAIN)) {
+ continue;
+ }
+ if (ret <= 0) break;
+
+ ret2 = write(fd2, buf, ret);
+ if (ret2 == -1 &&
+ (errno == EINTR || errno == EAGAIN)) {
+ continue;
+ }
+
+ if (ret2 != ret) {
+ close(fd1);
+ close(fd2);
+ talloc_free(buf);
+ pvfs_sys_unlink(pvfs, name2->full_name, allow_override);
+ if (ret2 == -1) {
+ return pvfs_map_errno(pvfs, errno);
+ }
+ return NT_STATUS_DISK_FULL;
+ }
+ }
+
+ talloc_free(buf);
+ close(fd1);
+
+ mode = pvfs_fileperms(pvfs, name1->dos.attrib);
+ if (pvfs_sys_fchmod(pvfs, fd2, mode, allow_override) == -1) {
+ status = pvfs_map_errno(pvfs, errno);
+ close(fd2);
+ pvfs_sys_unlink(pvfs, name2->full_name, allow_override);
+ return status;
+ }
+
+ name2->st.st_mode = mode;
+ name2->dos = name1->dos;
+
+ status = pvfs_dosattrib_save(pvfs, name2, fd2);
+ if (!NT_STATUS_IS_OK(status)) {
+ close(fd2);
+ pvfs_sys_unlink(pvfs, name2->full_name, allow_override);
+ return status;
+ }
+
+ close(fd2);
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ hash a string of the specified length. The string does not need to be
+ null terminated
+
+ hash algorithm changed to FNV1 by idra@samba.org (Simo Sorce).
+ see http://www.isthe.com/chongo/tech/comp/fnv/index.html for a
+ discussion on Fowler / Noll / Vo (FNV) Hash by one of it's authors
+*/
+uint32_t pvfs_name_hash(const char *key, size_t length)
+{
+ const uint32_t fnv1_prime = 0x01000193;
+ const uint32_t fnv1_init = 0xa6b93095;
+ uint32_t value = fnv1_init;
+
+ while (*key && length--) {
+ size_t c_size;
+ codepoint_t c = next_codepoint(key, &c_size);
+ c = toupper_m(c);
+ value *= fnv1_prime;
+ value ^= (uint32_t)c;
+ key += c_size;
+ }
+
+ return value;
+}
+
+
+/*
+ file allocation size rounding. This is required to pass ifstest
+*/
+uint64_t pvfs_round_alloc_size(struct pvfs_state *pvfs, uint64_t size)
+{
+ const uint32_t round_value = pvfs->alloc_size_rounding;
+ return round_value * ((size + round_value - 1)/round_value);
+}