r4591: - converted the other _p talloc functions to not need _p
[jelmer/samba4-debian.git] / source / ntvfs / posix / pvfs_streams.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - alternate data streams
5
6    Copyright (C) Andrew Tridgell 2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "vfs_posix.h"
26 #include "librpc/gen_ndr/ndr_xattr.h"
27
28
29 /*
30   return the list of file streams for RAW_FILEINFO_STREAM_INFORMATION
31 */
32 NTSTATUS pvfs_stream_information(struct pvfs_state *pvfs, 
33                                  TALLOC_CTX *mem_ctx,
34                                  struct pvfs_filename *name, int fd, 
35                                  struct stream_information *info)
36 {
37         struct xattr_DosStreams *streams;
38         int i;
39         NTSTATUS status;
40
41         streams = talloc_p(mem_ctx, struct xattr_DosStreams);
42         if (streams == NULL) {
43                 return NT_STATUS_NO_MEMORY;
44         }
45
46         status = pvfs_streams_load(pvfs, name, fd, streams);
47         if (!NT_STATUS_IS_OK(status)) {
48                 ZERO_STRUCTP(streams);
49         }
50
51         info->num_streams = streams->num_streams+1;
52         info->streams = talloc_array_p(mem_ctx, struct stream_struct, info->num_streams);
53         if (!info->streams) {
54                 return NT_STATUS_NO_MEMORY;
55         }
56
57         info->streams[0].size          = name->st.st_size;
58         info->streams[0].alloc_size    = name->dos.alloc_size;
59         info->streams[0].stream_name.s = talloc_strdup(info->streams, "::$DATA");
60
61         for (i=0;i<streams->num_streams;i++) {
62                 info->streams[i+1].size          = streams->streams[i].size;
63                 info->streams[i+1].alloc_size    = streams->streams[i].alloc_size;
64                 info->streams[i+1].stream_name.s = talloc_asprintf(streams->streams, 
65                                                                    ":%s:$DATA",
66                                                                    streams->streams[i].name);
67         }
68
69         return NT_STATUS_OK;
70 }
71
72
73 /*
74   fill in the stream information for a name
75 */
76 NTSTATUS pvfs_stream_info(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
77 {
78         struct xattr_DosStreams *streams;
79         int i;
80         NTSTATUS status;
81
82         /* the NULL stream always exists */
83         if (name->stream_name == NULL) {
84                 name->stream_exists = True;
85                 return NT_STATUS_OK;
86         }
87
88         streams = talloc_p(name, struct xattr_DosStreams);
89         if (streams == NULL) {
90                 return NT_STATUS_NO_MEMORY;
91         }
92
93         status = pvfs_streams_load(pvfs, name, fd, streams);
94         if (!NT_STATUS_IS_OK(status)) {
95                 talloc_free(streams);
96                 return status;
97         }
98
99         for (i=0;i<streams->num_streams;i++) {
100                 struct xattr_DosStream *s = &streams->streams[i];
101                 if (StrCaseCmp(s->name, name->stream_name) == 0) {
102                         name->dos.alloc_size = pvfs_round_alloc_size(pvfs, s->alloc_size);
103                         name->st.st_size     = s->size;
104                         name->stream_exists = True;
105                         talloc_free(streams);
106                         return NT_STATUS_OK;
107                 }
108         }
109
110         talloc_free(streams);
111
112         name->dos.alloc_size = 0;
113         name->st.st_size     = 0;
114         name->stream_exists = False;
115
116         return NT_STATUS_OK;
117 }
118
119
120 /*
121   update size information for a stream
122 */
123 static NTSTATUS pvfs_stream_update_size(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
124                                         off_t size)
125 {
126         struct xattr_DosStreams *streams;
127         int i;
128         NTSTATUS status;
129
130         streams = talloc_p(name, struct xattr_DosStreams);
131         if (streams == NULL) {
132                 return NT_STATUS_NO_MEMORY;
133         }
134
135         status = pvfs_streams_load(pvfs, name, fd, streams);
136         if (!NT_STATUS_IS_OK(status)) {
137                 ZERO_STRUCTP(streams);
138         }
139
140         for (i=0;i<streams->num_streams;i++) {
141                 struct xattr_DosStream *s = &streams->streams[i];
142                 if (StrCaseCmp(s->name, name->stream_name) == 0) {
143                         s->size       = size;
144                         s->alloc_size = pvfs_round_alloc_size(pvfs, size);
145                         break;
146                 }
147         }
148
149         if (i == streams->num_streams) {
150                 struct xattr_DosStream *s;
151                 streams->streams = talloc_realloc_p(streams, streams->streams, 
152                                                     struct xattr_DosStream,
153                                                     streams->num_streams+1);
154                 if (streams->streams == NULL) {
155                         talloc_free(streams);
156                         return NT_STATUS_NO_MEMORY;
157                 }
158                 streams->num_streams++;
159                 s = &streams->streams[i];
160                 
161                 s->flags      = XATTR_STREAM_FLAG_INTERNAL;
162                 s->size       = size;
163                 s->alloc_size = pvfs_round_alloc_size(pvfs, size);
164                 s->name       = name->stream_name;
165         }
166
167         status = pvfs_streams_save(pvfs, name, fd, streams);
168         talloc_free(streams);
169
170         return status;
171 }
172
173
174 /*
175   create the xattr for a alternate data stream
176 */
177 NTSTATUS pvfs_stream_create(struct pvfs_state *pvfs, 
178                             struct pvfs_filename *name, 
179                             int fd)
180 {
181         NTSTATUS status;
182         status = pvfs_xattr_create(pvfs, name->full_name, fd, 
183                                    XATTR_DOSSTREAM_PREFIX, name->stream_name);
184         if (!NT_STATUS_IS_OK(status)) {
185                 return status;
186         }
187         return pvfs_stream_update_size(pvfs, name, fd, 0);
188 }
189
190 /*
191   delete the xattr for a alternate data stream
192 */
193 NTSTATUS pvfs_stream_delete(struct pvfs_state *pvfs, 
194                             struct pvfs_filename *name, 
195                             int fd)
196 {
197         NTSTATUS status;
198         struct xattr_DosStreams *streams;
199         int i;
200
201         status = pvfs_xattr_delete(pvfs, name->full_name, fd, 
202                                    XATTR_DOSSTREAM_PREFIX, name->stream_name);
203         if (!NT_STATUS_IS_OK(status)) {
204                 return status;
205         }
206
207         streams = talloc_p(name, struct xattr_DosStreams);
208         if (streams == NULL) {
209                 return NT_STATUS_NO_MEMORY;
210         }
211
212         status = pvfs_streams_load(pvfs, name, fd, streams);
213         if (!NT_STATUS_IS_OK(status)) {
214                 talloc_free(streams);
215                 return status;
216         }
217
218         for (i=0;i<streams->num_streams;i++) {
219                 struct xattr_DosStream *s = &streams->streams[i];
220                 if (StrCaseCmp(s->name, name->stream_name) == 0) {
221                         memmove(s, s+1, (streams->num_streams - (i+1)) * sizeof(*s));
222                         streams->num_streams--;
223                         break;
224                 }
225         }
226
227         status = pvfs_streams_save(pvfs, name, fd, streams);
228         talloc_free(streams);
229
230         return status;
231 }
232
233 /*
234   the equvalent of pread() on a stream
235 */
236 ssize_t pvfs_stream_read(struct pvfs_state *pvfs,
237                          struct pvfs_file_handle *h, void *data, size_t count, off_t offset)
238 {
239         NTSTATUS status;
240         DATA_BLOB blob;
241         if (count == 0) {
242                 return 0;
243         }
244         status = pvfs_xattr_load(pvfs, h, h->name->full_name, h->fd, XATTR_DOSSTREAM_PREFIX,
245                                  h->name->stream_name, offset+count, &blob);
246         if (!NT_STATUS_IS_OK(status)) {
247                 errno = EIO;
248                 return -1;
249         }
250         if (offset >= blob.length) {
251                 data_blob_free(&blob);
252                 return 0;
253         }
254         if (count > blob.length - offset) {
255                 count = blob.length - offset;
256         }
257         memcpy(data, blob.data + offset, count);
258         data_blob_free(&blob);
259         return count;
260 }
261
262
263 /*
264   the equvalent of pwrite() on a stream
265 */
266 ssize_t pvfs_stream_write(struct pvfs_state *pvfs,
267                           struct pvfs_file_handle *h, const void *data, size_t count, off_t offset)
268 {
269         NTSTATUS status;
270         DATA_BLOB blob;
271         if (count == 0) {
272                 return 0;
273         }
274         if (offset > XATTR_MAX_STREAM_SIZE) {
275                 errno = ENOSPC;
276                 return -1;
277         }
278
279         /* we have to load the existing stream, then modify, then save */
280         status = pvfs_xattr_load(pvfs, h, h->name->full_name, h->fd, XATTR_DOSSTREAM_PREFIX,
281                                  h->name->stream_name, offset+count, &blob);
282         if (!NT_STATUS_IS_OK(status)) {
283                 blob = data_blob(NULL, 0);
284         }
285         if (count+offset > blob.length) {
286                 blob.data = talloc_realloc(blob.data, blob.data, uint8_t, count+offset);
287                 if (blob.data == NULL) {
288                         errno = ENOMEM;
289                         return -1;
290                 }
291                 if (offset > blob.length) {
292                         memset(blob.data+blob.length, 0, offset - blob.length);
293                 }
294                 blob.length = count+offset;
295         }
296         memcpy(blob.data + offset, data, count);
297
298         status = pvfs_xattr_save(pvfs, h->name->full_name, h->fd, XATTR_DOSSTREAM_PREFIX,
299                                  h->name->stream_name, &blob);
300         if (!NT_STATUS_IS_OK(status)) {
301                 data_blob_free(&blob);
302                 /* getting this error mapping right is probably
303                    not worth it */
304                 errno = ENOSPC;
305                 return -1;
306         }
307
308         status = pvfs_stream_update_size(pvfs, h->name, h->fd, blob.length);
309
310         data_blob_free(&blob);
311
312         if (!NT_STATUS_IS_OK(status)) {
313                 errno = EIO;
314                 return -1;
315         }
316
317         return count;
318 }
319
320 /*
321   the equvalent of truncate() on a stream
322 */
323 NTSTATUS pvfs_stream_truncate(struct pvfs_state *pvfs,
324                               struct pvfs_filename *name, int fd, off_t length)
325 {
326         NTSTATUS status;
327         DATA_BLOB blob;
328
329         if (length > XATTR_MAX_STREAM_SIZE) {
330                 return NT_STATUS_DISK_FULL;
331         }
332
333         /* we have to load the existing stream, then modify, then save */
334         status = pvfs_xattr_load(pvfs, name, name->full_name, fd, XATTR_DOSSTREAM_PREFIX,
335                                  name->stream_name, length, &blob);
336         if (!NT_STATUS_IS_OK(status)) {
337                 return status;
338         }
339         if (length <= blob.length) {
340                 blob.length = length;
341         } else if (length > blob.length) {
342                 blob.data = talloc_realloc(blob.data, blob.data, uint8_t, length);
343                 if (blob.data == NULL) {
344                         return NT_STATUS_NO_MEMORY;
345                 }
346                 memset(blob.data+blob.length, 0, length - blob.length);
347                 blob.length = length;
348         }
349
350         status = pvfs_xattr_save(pvfs, name->full_name, fd, XATTR_DOSSTREAM_PREFIX,
351                                  name->stream_name, &blob);
352         data_blob_free(&blob);
353
354         if (NT_STATUS_IS_OK(status)) {
355                 status = pvfs_stream_update_size(pvfs, name, fd, blob.length);
356         }
357
358         return status;
359 }