Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Andrew Tridgell 2004
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 : /*
20 : utility functions for posix backend
21 : */
22 :
23 : #include "includes.h"
24 : #include "vfs_posix.h"
25 :
26 : /*
27 : return true if a string contains one of the CIFS wildcard characters
28 : */
29 0 : bool pvfs_has_wildcard(const char *str)
30 : {
31 0 : if (strpbrk(str, "*?<>\"")) {
32 0 : return true;
33 : }
34 0 : return false;
35 : }
36 :
37 : /*
38 : map a unix errno to a NTSTATUS
39 : */
40 34 : NTSTATUS pvfs_map_errno(struct pvfs_state *pvfs, int unix_errno)
41 : {
42 0 : NTSTATUS status;
43 34 : status = map_nt_error_from_unix_common(unix_errno);
44 34 : DEBUG(10,(__location__ " mapped unix errno %d -> %s\n", unix_errno, nt_errstr(status)));
45 34 : return status;
46 : }
47 :
48 :
49 : /*
50 : check if a filename has an attribute matching the given attribute search value
51 : this is used by calls like unlink and search which take an attribute
52 : and only include special files if they match the given attribute
53 : */
54 160471 : NTSTATUS pvfs_match_attrib(struct pvfs_state *pvfs, struct pvfs_filename *name,
55 : uint32_t attrib, uint32_t must_attrib)
56 : {
57 160471 : if ((name->dos.attrib & ~attrib) & FILE_ATTRIBUTE_DIRECTORY) {
58 2494 : return NT_STATUS_FILE_IS_A_DIRECTORY;
59 : }
60 157977 : if ((name->dos.attrib & ~attrib) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
61 4 : return NT_STATUS_NO_SUCH_FILE;
62 : }
63 157973 : if (must_attrib & ~name->dos.attrib) {
64 4004 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
65 : }
66 153969 : return NT_STATUS_OK;
67 : }
68 :
69 :
70 : /*
71 : normalise a file attribute
72 : */
73 442624 : uint32_t pvfs_attrib_normalise(uint32_t attrib, mode_t mode)
74 : {
75 442624 : if (attrib != FILE_ATTRIBUTE_NORMAL) {
76 442171 : attrib &= ~FILE_ATTRIBUTE_NORMAL;
77 : }
78 442624 : if (S_ISDIR(mode)) {
79 194 : attrib |= FILE_ATTRIBUTE_DIRECTORY;
80 : } else {
81 442430 : attrib &= ~FILE_ATTRIBUTE_DIRECTORY;
82 : }
83 442624 : return attrib;
84 : }
85 :
86 :
87 : /*
88 : copy a file. Caller is supposed to have already ensured that the
89 : operation is allowed. The destination file must not exist.
90 : */
91 2 : NTSTATUS pvfs_copy_file(struct pvfs_state *pvfs,
92 : struct pvfs_filename *name1,
93 : struct pvfs_filename *name2,
94 : bool allow_override)
95 : {
96 0 : int fd1, fd2;
97 0 : mode_t mode;
98 0 : NTSTATUS status;
99 2 : size_t buf_size = 0x10000;
100 2 : uint8_t *buf = talloc_array(name2, uint8_t, buf_size);
101 :
102 2 : if (buf == NULL) {
103 0 : return NT_STATUS_NO_MEMORY;
104 : }
105 :
106 2 : fd1 = pvfs_sys_open(pvfs, name1->full_name, O_RDONLY, 0, allow_override);
107 2 : if (fd1 == -1) {
108 0 : talloc_free(buf);
109 0 : return pvfs_map_errno(pvfs, errno);
110 : }
111 :
112 2 : fd2 = pvfs_sys_open(pvfs, name2->full_name, O_CREAT|O_EXCL|O_WRONLY, 0, allow_override);
113 2 : if (fd2 == -1) {
114 0 : close(fd1);
115 0 : talloc_free(buf);
116 0 : return pvfs_map_errno(pvfs, errno);
117 : }
118 :
119 2 : while (1) {
120 4 : ssize_t ret2, ret = read(fd1, buf, buf_size);
121 4 : if (ret == -1 &&
122 0 : (errno == EINTR || errno == EAGAIN)) {
123 0 : continue;
124 : }
125 4 : if (ret <= 0) break;
126 :
127 2 : ret2 = write(fd2, buf, ret);
128 2 : if (ret2 == -1 &&
129 0 : (errno == EINTR || errno == EAGAIN)) {
130 0 : continue;
131 : }
132 :
133 2 : if (ret2 != ret) {
134 0 : close(fd1);
135 0 : close(fd2);
136 0 : talloc_free(buf);
137 0 : pvfs_sys_unlink(pvfs, name2->full_name, allow_override);
138 0 : if (ret2 == -1) {
139 0 : return pvfs_map_errno(pvfs, errno);
140 : }
141 0 : return NT_STATUS_DISK_FULL;
142 : }
143 : }
144 :
145 2 : talloc_free(buf);
146 2 : close(fd1);
147 :
148 2 : mode = pvfs_fileperms(pvfs, name1->dos.attrib);
149 2 : if (pvfs_sys_fchmod(pvfs, fd2, mode, allow_override) == -1) {
150 0 : status = pvfs_map_errno(pvfs, errno);
151 0 : close(fd2);
152 0 : pvfs_sys_unlink(pvfs, name2->full_name, allow_override);
153 0 : return status;
154 : }
155 :
156 2 : name2->st.st_mode = mode;
157 2 : name2->dos = name1->dos;
158 :
159 2 : status = pvfs_dosattrib_save(pvfs, name2, fd2);
160 2 : if (!NT_STATUS_IS_OK(status)) {
161 0 : close(fd2);
162 0 : pvfs_sys_unlink(pvfs, name2->full_name, allow_override);
163 0 : return status;
164 : }
165 :
166 2 : close(fd2);
167 :
168 2 : return NT_STATUS_OK;
169 : }
170 :
171 :
172 : /*
173 : hash a string of the specified length. The string does not need to be
174 : null terminated
175 :
176 : hash algorithm changed to FNV1 by idra@samba.org (Simo Sorce).
177 : see http://www.isthe.com/chongo/tech/comp/fnv/index.html for a
178 : discussion on Fowler / Noll / Vo (FNV) Hash by one of it's authors
179 : */
180 362223 : uint32_t pvfs_name_hash(const char *key, size_t length)
181 : {
182 362223 : const uint32_t fnv1_prime = 0x01000193;
183 362223 : const uint32_t fnv1_init = 0xa6b93095;
184 362223 : uint32_t value = fnv1_init;
185 :
186 4113140 : while (*key && length--) {
187 0 : size_t c_size;
188 3750917 : codepoint_t c = next_codepoint(key, &c_size);
189 3750917 : c = toupper_m(c);
190 3750917 : value *= fnv1_prime;
191 3750917 : value ^= (uint32_t)c;
192 3750917 : key += c_size;
193 : }
194 :
195 362223 : return value;
196 : }
197 :
198 :
199 : /*
200 : file allocation size rounding. This is required to pass ifstest
201 : */
202 1106460 : uint64_t pvfs_round_alloc_size(struct pvfs_state *pvfs, uint64_t size)
203 : {
204 1106460 : const uint32_t round_value = pvfs->alloc_size_rounding;
205 1106460 : return round_value * ((size + round_value - 1)/round_value);
206 : }
|