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 | bool pvfs_has_wildcard(const char *str)
|
---|
30 | {
|
---|
31 | if (strpbrk(str, "*?<>\"")) {
|
---|
32 | return true;
|
---|
33 | }
|
---|
34 | return false;
|
---|
35 | }
|
---|
36 |
|
---|
37 | /*
|
---|
38 | map a unix errno to a NTSTATUS
|
---|
39 | */
|
---|
40 | NTSTATUS pvfs_map_errno(struct pvfs_state *pvfs, int unix_errno)
|
---|
41 | {
|
---|
42 | NTSTATUS status;
|
---|
43 | status = map_nt_error_from_unix(unix_errno);
|
---|
44 | DEBUG(10,(__location__ " mapped unix errno %d -> %s\n", unix_errno, nt_errstr(status)));
|
---|
45 | 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 | NTSTATUS pvfs_match_attrib(struct pvfs_state *pvfs, struct pvfs_filename *name,
|
---|
55 | uint32_t attrib, uint32_t must_attrib)
|
---|
56 | {
|
---|
57 | if ((name->dos.attrib & ~attrib) & FILE_ATTRIBUTE_DIRECTORY) {
|
---|
58 | return NT_STATUS_FILE_IS_A_DIRECTORY;
|
---|
59 | }
|
---|
60 | if ((name->dos.attrib & ~attrib) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
|
---|
61 | return NT_STATUS_NO_SUCH_FILE;
|
---|
62 | }
|
---|
63 | if (must_attrib & ~name->dos.attrib) {
|
---|
64 | return NT_STATUS_OBJECT_NAME_NOT_FOUND;
|
---|
65 | }
|
---|
66 | return NT_STATUS_OK;
|
---|
67 | }
|
---|
68 |
|
---|
69 |
|
---|
70 | /*
|
---|
71 | normalise a file attribute
|
---|
72 | */
|
---|
73 | uint32_t pvfs_attrib_normalise(uint32_t attrib, mode_t mode)
|
---|
74 | {
|
---|
75 | if (attrib != FILE_ATTRIBUTE_NORMAL) {
|
---|
76 | attrib &= ~FILE_ATTRIBUTE_NORMAL;
|
---|
77 | }
|
---|
78 | if (S_ISDIR(mode)) {
|
---|
79 | attrib |= FILE_ATTRIBUTE_DIRECTORY;
|
---|
80 | } else {
|
---|
81 | attrib &= ~FILE_ATTRIBUTE_DIRECTORY;
|
---|
82 | }
|
---|
83 | 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 | NTSTATUS pvfs_copy_file(struct pvfs_state *pvfs,
|
---|
92 | struct pvfs_filename *name1,
|
---|
93 | struct pvfs_filename *name2)
|
---|
94 | {
|
---|
95 | int fd1, fd2;
|
---|
96 | mode_t mode;
|
---|
97 | NTSTATUS status;
|
---|
98 | size_t buf_size = 0x10000;
|
---|
99 | uint8_t *buf = talloc_array(name2, uint8_t, buf_size);
|
---|
100 |
|
---|
101 | if (buf == NULL) {
|
---|
102 | return NT_STATUS_NO_MEMORY;
|
---|
103 | }
|
---|
104 |
|
---|
105 | fd1 = pvfs_sys_open(pvfs, name1->full_name, O_RDONLY, 0);
|
---|
106 | if (fd1 == -1) {
|
---|
107 | talloc_free(buf);
|
---|
108 | return pvfs_map_errno(pvfs, errno);
|
---|
109 | }
|
---|
110 |
|
---|
111 | fd2 = pvfs_sys_open(pvfs, name2->full_name, O_CREAT|O_EXCL|O_WRONLY, 0);
|
---|
112 | if (fd2 == -1) {
|
---|
113 | close(fd1);
|
---|
114 | talloc_free(buf);
|
---|
115 | return pvfs_map_errno(pvfs, errno);
|
---|
116 | }
|
---|
117 |
|
---|
118 | while (1) {
|
---|
119 | ssize_t ret2, ret = read(fd1, buf, buf_size);
|
---|
120 | if (ret == -1 &&
|
---|
121 | (errno == EINTR || errno == EAGAIN)) {
|
---|
122 | continue;
|
---|
123 | }
|
---|
124 | if (ret <= 0) break;
|
---|
125 |
|
---|
126 | ret2 = write(fd2, buf, ret);
|
---|
127 | if (ret2 == -1 &&
|
---|
128 | (errno == EINTR || errno == EAGAIN)) {
|
---|
129 | continue;
|
---|
130 | }
|
---|
131 |
|
---|
132 | if (ret2 != ret) {
|
---|
133 | close(fd1);
|
---|
134 | close(fd2);
|
---|
135 | talloc_free(buf);
|
---|
136 | pvfs_sys_unlink(pvfs, name2->full_name);
|
---|
137 | if (ret2 == -1) {
|
---|
138 | return pvfs_map_errno(pvfs, errno);
|
---|
139 | }
|
---|
140 | return NT_STATUS_DISK_FULL;
|
---|
141 | }
|
---|
142 | }
|
---|
143 |
|
---|
144 | talloc_free(buf);
|
---|
145 | close(fd1);
|
---|
146 |
|
---|
147 | mode = pvfs_fileperms(pvfs, name1->dos.attrib);
|
---|
148 | if (pvfs_sys_fchmod(pvfs, fd2, mode) == -1) {
|
---|
149 | status = pvfs_map_errno(pvfs, errno);
|
---|
150 | close(fd2);
|
---|
151 | pvfs_sys_unlink(pvfs, name2->full_name);
|
---|
152 | return status;
|
---|
153 | }
|
---|
154 |
|
---|
155 | name2->st.st_mode = mode;
|
---|
156 | name2->dos = name1->dos;
|
---|
157 |
|
---|
158 | status = pvfs_dosattrib_save(pvfs, name2, fd2);
|
---|
159 | if (!NT_STATUS_IS_OK(status)) {
|
---|
160 | close(fd2);
|
---|
161 | pvfs_sys_unlink(pvfs, name2->full_name);
|
---|
162 | return status;
|
---|
163 | }
|
---|
164 |
|
---|
165 | close(fd2);
|
---|
166 |
|
---|
167 | return NT_STATUS_OK;
|
---|
168 | }
|
---|
169 |
|
---|
170 |
|
---|
171 | /*
|
---|
172 | hash a string of the specified length. The string does not need to be
|
---|
173 | null terminated
|
---|
174 |
|
---|
175 | hash alghorithm changed to FNV1 by idra@samba.org (Simo Sorce).
|
---|
176 | see http://www.isthe.com/chongo/tech/comp/fnv/index.html for a
|
---|
177 | discussion on Fowler / Noll / Vo (FNV) Hash by one of it's authors
|
---|
178 | */
|
---|
179 | uint32_t pvfs_name_hash(const char *key, size_t length)
|
---|
180 | {
|
---|
181 | const uint32_t fnv1_prime = 0x01000193;
|
---|
182 | const uint32_t fnv1_init = 0xa6b93095;
|
---|
183 | uint32_t value = fnv1_init;
|
---|
184 |
|
---|
185 | while (*key && length--) {
|
---|
186 | size_t c_size;
|
---|
187 | codepoint_t c = next_codepoint(key, &c_size);
|
---|
188 | c = toupper_m(c);
|
---|
189 | value *= fnv1_prime;
|
---|
190 | value ^= (uint32_t)c;
|
---|
191 | key += c_size;
|
---|
192 | }
|
---|
193 |
|
---|
194 | return value;
|
---|
195 | }
|
---|
196 |
|
---|
197 |
|
---|
198 | /*
|
---|
199 | file allocation size rounding. This is required to pass ifstest
|
---|
200 | */
|
---|
201 | uint64_t pvfs_round_alloc_size(struct pvfs_state *pvfs, uint64_t size)
|
---|
202 | {
|
---|
203 | const uint32_t round_value = pvfs->alloc_size_rounding;
|
---|
204 | return round_value * ((size + round_value - 1)/round_value);
|
---|
205 | }
|
---|