d716834fed235fa6679169c6a1b40bc939102756
[jelmer/samba4-debian.git] / source / 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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 /*
21   utility functions for posix backend
22 */
23
24 #include "includes.h"
25 #include "vfs_posix.h"
26
27 /*
28   return True if a string contains one of the CIFS wildcard characters
29 */
30 BOOL pvfs_has_wildcard(const char *str)
31 {
32         if (strpbrk(str, "*?<>\"")) {
33                 return True;
34         }
35         return False;
36 }
37
38 /*
39   map a unix errno to a NTSTATUS
40 */
41 NTSTATUS pvfs_map_errno(struct pvfs_state *pvfs, int unix_errno)
42 {
43         return map_nt_error_from_unix(unix_errno);
44 }
45
46
47 /*
48   check if a filename has an attribute matching the given attribute search value
49   this is used by calls like unlink and search which take an attribute
50   and only include special files if they match the given attribute
51 */
52 NTSTATUS pvfs_match_attrib(struct pvfs_state *pvfs, struct pvfs_filename *name, 
53                            uint32_t attrib, uint32_t must_attrib)
54 {
55         if ((name->dos.attrib & ~attrib) & FILE_ATTRIBUTE_DIRECTORY) {
56                 return NT_STATUS_FILE_IS_A_DIRECTORY;
57         }
58         if ((name->dos.attrib & ~attrib) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
59                 return NT_STATUS_NO_SUCH_FILE;
60         }
61         if (must_attrib & ~name->dos.attrib) {
62                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
63         }
64         return NT_STATUS_OK;
65 }
66
67
68 /*
69   normalise a file attribute
70 */
71 uint32_t pvfs_attrib_normalise(uint32_t attrib, mode_t mode)
72 {
73         if (attrib != FILE_ATTRIBUTE_NORMAL) {
74                 attrib &= ~FILE_ATTRIBUTE_NORMAL;
75         }
76         if (S_ISDIR(mode)) {
77                 attrib |= FILE_ATTRIBUTE_DIRECTORY;
78         } else {
79                 attrib &= ~FILE_ATTRIBUTE_DIRECTORY;
80         }
81         return attrib;
82 }
83
84
85 /*
86   copy a file. Caller is supposed to have already ensured that the
87   operation is allowed. The destination file must not exist.
88 */
89 NTSTATUS pvfs_copy_file(struct pvfs_state *pvfs,
90                         struct pvfs_filename *name1, 
91                         struct pvfs_filename *name2)
92 {
93         int fd1, fd2;
94         mode_t mode;
95         NTSTATUS status;
96         size_t buf_size = 0x10000;
97         char *buf = talloc_size(name2, buf_size);
98
99         if (buf == NULL) {
100                 return NT_STATUS_NO_MEMORY;
101         }
102
103         fd1 = open(name1->full_name, O_RDONLY);
104         if (fd1 == -1) {
105                 talloc_free(buf);
106                 return pvfs_map_errno(pvfs, errno);
107         }
108
109         fd2 = open(name2->full_name, O_CREAT|O_EXCL|O_WRONLY, 0);
110         if (fd2 == -1) {
111                 close(fd1);
112                 talloc_free(buf);
113                 return pvfs_map_errno(pvfs, errno);
114         }
115
116         while (1) {
117                 ssize_t ret2, ret = read(fd1, buf, buf_size);
118                 if (ret == -1 && 
119                     (errno == EINTR || errno == EAGAIN)) {
120                         continue;
121                 }
122                 if (ret <= 0) break;
123
124                 ret2 = write(fd2, buf, ret);
125                 if (ret2 == -1 &&
126                     (errno == EINTR || errno == EAGAIN)) {
127                         continue;
128                 }
129                 
130                 if (ret2 != ret) {
131                         close(fd1);
132                         close(fd2);
133                         talloc_free(buf);
134                         unlink(name2->full_name);
135                         if (ret2 == -1) {
136                                 return pvfs_map_errno(pvfs, errno);
137                         }
138                         return NT_STATUS_DISK_FULL;
139                 }
140         }
141
142         talloc_free(buf);
143         close(fd1);
144
145         mode = pvfs_fileperms(pvfs, name1->dos.attrib);
146         if (fchmod(fd2, mode) == -1) {
147                 status = pvfs_map_errno(pvfs, errno);
148                 close(fd2);
149                 unlink(name2->full_name);
150                 return status;
151         }
152
153         name2->st.st_mode = mode;
154         name2->dos = name1->dos;
155
156         status = pvfs_dosattrib_save(pvfs, name2, fd2);
157         if (!NT_STATUS_IS_OK(status)) {
158                 close(fd2);
159                 unlink(name2->full_name);
160                 return status;
161         }
162
163         close(fd2);
164
165         return NT_STATUS_OK;
166 }
167
168
169 /* 
170    hash a string of the specified length. The string does not need to be
171    null terminated 
172
173    hash alghorithm changed to FNV1 by idra@samba.org (Simo Sorce).
174    see http://www.isthe.com/chongo/tech/comp/fnv/index.html for a
175    discussion on Fowler / Noll / Vo (FNV) Hash by one of it's authors
176 */
177 uint32_t pvfs_name_hash(const char *key, size_t length)
178 {
179         const uint32_t fnv1_prime = 0x01000193;
180         const uint32_t fnv1_init = 0xa6b93095;
181         uint32_t value = fnv1_init;
182
183         while (*key && length--) {
184                 size_t c_size;
185                 codepoint_t c = next_codepoint(key, &c_size);
186                 c = toupper_w(c);
187                 value *= fnv1_prime;
188                 value ^= (uint32_t)c;
189                 key += c_size;
190         }
191
192         return value;
193 }
194
195
196 /*
197   file allocation size rounding. This is required to pass ifstest
198 */
199 uint64_t pvfs_round_alloc_size(struct pvfs_state *pvfs, uint64_t size)
200 {
201         const uint64_t round_value = 511;
202         if (size == 0) return 0;
203         return (size + round_value) & ~round_value;
204 }