libcli/util Rename common map_nt_error_from_unix to avoid duplicate symbol
[nivanova/samba-autobuild/.git] / source4 / ntvfs / posix / pvfs_util.c
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_common(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 }