~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/smbd/vfs.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Unix SMB/Netbios implementation.
 
3
   Version 1.9.
 
4
   VFS initialisation and support functions
 
5
   Copyright (C) Tim Potter 1999
 
6
   Copyright (C) Alexander Bokovoy 2002
 
7
   Copyright (C) James Peach 2006
 
8
 
 
9
   This program is free software; you can redistribute it and/or modify
 
10
   it under the terms of the GNU General Public License as published by
 
11
   the Free Software Foundation; either version 3 of the License, or
 
12
   (at your option) any later version.
 
13
 
 
14
   This program is distributed in the hope that it will be useful,
 
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
   GNU General Public License for more details.
 
18
 
 
19
   You should have received a copy of the GNU General Public License
 
20
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
 
 
22
   This work was sponsored by Optifacio Software Services, Inc.
 
23
*/
 
24
 
 
25
#include "includes.h"
 
26
#include "smbd/globals.h"
 
27
 
 
28
#undef DBGC_CLASS
 
29
#define DBGC_CLASS DBGC_VFS
 
30
 
 
31
static_decl_vfs;
 
32
 
 
33
struct vfs_init_function_entry {
 
34
        char *name;
 
35
        const vfs_op_tuple *vfs_op_tuples;
 
36
        struct vfs_init_function_entry *prev, *next;
 
37
};
 
38
 
 
39
/****************************************************************************
 
40
    maintain the list of available backends
 
41
****************************************************************************/
 
42
 
 
43
static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
 
44
{
 
45
        struct vfs_init_function_entry *entry = backends;
 
46
 
 
47
        DEBUG(10, ("vfs_find_backend_entry called for %s\n", name));
 
48
 
 
49
        while(entry) {
 
50
                if (strcmp(entry->name, name)==0) return entry;
 
51
                entry = entry->next;
 
52
        }
 
53
 
 
54
        return NULL;
 
55
}
 
56
 
 
57
NTSTATUS smb_register_vfs(int version, const char *name, const vfs_op_tuple *vfs_op_tuples)
 
58
{
 
59
        struct vfs_init_function_entry *entry = backends;
 
60
 
 
61
        if ((version != SMB_VFS_INTERFACE_VERSION)) {
 
62
                DEBUG(0, ("Failed to register vfs module.\n"
 
63
                          "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
 
64
                          "current SMB_VFS_INTERFACE_VERSION is %d.\n"
 
65
                          "Please recompile against the current Samba Version!\n",  
 
66
                          version, SMB_VFS_INTERFACE_VERSION));
 
67
                return NT_STATUS_OBJECT_TYPE_MISMATCH;
 
68
        }
 
69
 
 
70
        if (!name || !name[0] || !vfs_op_tuples) {
 
71
                DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
 
72
                return NT_STATUS_INVALID_PARAMETER;
 
73
        }
 
74
 
 
75
        if (vfs_find_backend_entry(name)) {
 
76
                DEBUG(0,("VFS module %s already loaded!\n", name));
 
77
                return NT_STATUS_OBJECT_NAME_COLLISION;
 
78
        }
 
79
 
 
80
        entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
 
81
        entry->name = smb_xstrdup(name);
 
82
        entry->vfs_op_tuples = vfs_op_tuples;
 
83
 
 
84
        DLIST_ADD(backends, entry);
 
85
        DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
 
86
        return NT_STATUS_OK;
 
87
}
 
88
 
 
89
/****************************************************************************
 
90
  initialise default vfs hooks
 
91
****************************************************************************/
 
92
 
 
93
static void vfs_init_default(connection_struct *conn)
 
94
{
 
95
        DEBUG(3, ("Initialising default vfs hooks\n"));
 
96
        vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
 
97
}
 
98
 
 
99
/****************************************************************************
 
100
  initialise custom vfs hooks
 
101
 ****************************************************************************/
 
102
 
 
103
static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which,
 
104
                                struct vfs_handle_struct * handle, void * op)
 
105
{
 
106
        ((struct vfs_handle_struct **)&vfs->handles)[which] = handle;
 
107
        ((void **)(void *)&vfs->ops)[which] = op;
 
108
}
 
109
 
 
110
bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
 
111
{
 
112
        const vfs_op_tuple *ops;
 
113
        char *module_path = NULL;
 
114
        char *module_name = NULL;
 
115
        char *module_param = NULL, *p;
 
116
        int i;
 
117
        vfs_handle_struct *handle;
 
118
        const struct vfs_init_function_entry *entry;
 
119
        
 
120
        if (!conn||!vfs_object||!vfs_object[0]) {
 
121
                DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
 
122
                return False;
 
123
        }
 
124
 
 
125
        if(!backends) {
 
126
                static_init_vfs;
 
127
        }
 
128
 
 
129
        DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
 
130
 
 
131
        module_path = smb_xstrdup(vfs_object);
 
132
 
 
133
        p = strchr_m(module_path, ':');
 
134
 
 
135
        if (p) {
 
136
                *p = 0;
 
137
                module_param = p+1;
 
138
                trim_char(module_param, ' ', ' ');
 
139
        }
 
140
 
 
141
        trim_char(module_path, ' ', ' ');
 
142
 
 
143
        module_name = smb_xstrdup(module_path);
 
144
 
 
145
        if ((module_name[0] == '/') &&
 
146
            (strcmp(module_path, DEFAULT_VFS_MODULE_NAME) != 0)) {
 
147
 
 
148
                /*
 
149
                 * Extract the module name from the path. Just use the base
 
150
                 * name of the last path component.
 
151
                 */
 
152
 
 
153
                SAFE_FREE(module_name);
 
154
                module_name = smb_xstrdup(strrchr_m(module_path, '/')+1);
 
155
 
 
156
                p = strchr_m(module_name, '.');
 
157
 
 
158
                if (p != NULL) {
 
159
                        *p = '\0';
 
160
                }
 
161
        }
 
162
 
 
163
        /* First, try to load the module with the new module system */
 
164
        if((entry = vfs_find_backend_entry(module_name)) || 
 
165
           (NT_STATUS_IS_OK(smb_probe_module("vfs", module_path)) &&
 
166
                (entry = vfs_find_backend_entry(module_name)))) {
 
167
 
 
168
                DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
 
169
                
 
170
                if ((ops = entry->vfs_op_tuples) == NULL) {
 
171
                        DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
 
172
                        goto fail;
 
173
                }
 
174
        } else {
 
175
                DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
 
176
                goto fail;
 
177
        }
 
178
 
 
179
        handle = TALLOC_ZERO_P(conn, vfs_handle_struct);
 
180
        if (!handle) {
 
181
                DEBUG(0,("TALLOC_ZERO() failed!\n"));
 
182
                goto fail;
 
183
        }
 
184
        memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
 
185
        handle->conn = conn;
 
186
        if (module_param) {
 
187
                handle->param = talloc_strdup(conn, module_param);
 
188
        }
 
189
        DLIST_ADD(conn->vfs_handles, handle);
 
190
 
 
191
        for(i=0; ops[i].op != NULL; i++) {
 
192
                DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
 
193
                if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
 
194
                        /* If this operation was already made opaque by different module, it
 
195
                         * will be overridden here.
 
196
                         */
 
197
                        DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
 
198
                        vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
 
199
                }
 
200
                /* Change current VFS disposition*/
 
201
                DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
 
202
                vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
 
203
        }
 
204
 
 
205
        SAFE_FREE(module_path);
 
206
        SAFE_FREE(module_name);
 
207
        return True;
 
208
 
 
209
 fail:
 
210
        SAFE_FREE(module_path);
 
211
        SAFE_FREE(module_name);
 
212
        return False;
 
213
}
 
214
 
 
215
/*****************************************************************
 
216
 Allow VFS modules to extend files_struct with VFS-specific state.
 
217
 This will be ok for small numbers of extensions, but might need to
 
218
 be refactored if it becomes more widely used.
 
219
******************************************************************/
 
220
 
 
221
#define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
 
222
 
 
223
void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle,
 
224
                                   files_struct *fsp, size_t ext_size,
 
225
                                   void (*destroy_fn)(void *p_data))
 
226
{
 
227
        struct vfs_fsp_data *ext;
 
228
        void * ext_data;
 
229
 
 
230
        /* Prevent VFS modules adding multiple extensions. */
 
231
        if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
 
232
                return ext_data;
 
233
        }
 
234
 
 
235
        ext = (struct vfs_fsp_data *)TALLOC_ZERO(
 
236
                handle->conn, sizeof(struct vfs_fsp_data) + ext_size);
 
237
        if (ext == NULL) {
 
238
                return NULL;
 
239
        }
 
240
 
 
241
        ext->owner = handle;
 
242
        ext->next = fsp->vfs_extension;
 
243
        ext->destroy = destroy_fn;
 
244
        fsp->vfs_extension = ext;
 
245
        return EXT_DATA_AREA(ext);
 
246
}
 
247
 
 
248
void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
 
249
{
 
250
        struct vfs_fsp_data *curr;
 
251
        struct vfs_fsp_data *prev;
 
252
 
 
253
        for (curr = fsp->vfs_extension, prev = NULL;
 
254
             curr;
 
255
             prev = curr, curr = curr->next) {
 
256
                if (curr->owner == handle) {
 
257
                    if (prev) {
 
258
                            prev->next = curr->next;
 
259
                    } else {
 
260
                            fsp->vfs_extension = curr->next;
 
261
                    }
 
262
                    if (curr->destroy) {
 
263
                            curr->destroy(EXT_DATA_AREA(curr));
 
264
                    }
 
265
                    TALLOC_FREE(curr);
 
266
                    return;
 
267
                }
 
268
        }
 
269
}
 
270
 
 
271
void *vfs_memctx_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
 
272
{
 
273
        struct vfs_fsp_data *head;
 
274
 
 
275
        for (head = fsp->vfs_extension; head; head = head->next) {
 
276
                if (head->owner == handle) {
 
277
                        return head;
 
278
                }
 
279
        }
 
280
 
 
281
        return NULL;
 
282
}
 
283
 
 
284
void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
 
285
{
 
286
        struct vfs_fsp_data *head;
 
287
 
 
288
        head = (struct vfs_fsp_data *)vfs_memctx_fsp_extension(handle, fsp);
 
289
        if (head != NULL) {
 
290
                return EXT_DATA_AREA(head);
 
291
        }
 
292
 
 
293
        return NULL;
 
294
}
 
295
 
 
296
#undef EXT_DATA_AREA
 
297
 
 
298
/*****************************************************************
 
299
 Generic VFS init.
 
300
******************************************************************/
 
301
 
 
302
bool smbd_vfs_init(connection_struct *conn)
 
303
{
 
304
        const char **vfs_objects;
 
305
        unsigned int i = 0;
 
306
        int j = 0;
 
307
        
 
308
        /* Normal share - initialise with disk access functions */
 
309
        vfs_init_default(conn);
 
310
        vfs_objects = lp_vfs_objects(SNUM(conn));
 
311
 
 
312
        /* Override VFS functions if 'vfs object' was not specified*/
 
313
        if (!vfs_objects || !vfs_objects[0])
 
314
                return True;
 
315
        
 
316
        for (i=0; vfs_objects[i] ;) {
 
317
                i++;
 
318
        }
 
319
 
 
320
        for (j=i-1; j >= 0; j--) {
 
321
                if (!vfs_init_custom(conn, vfs_objects[j])) {
 
322
                        DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
 
323
                        return False;
 
324
                }
 
325
        }
 
326
        return True;
 
327
}
 
328
 
 
329
/*******************************************************************
 
330
 Check if directory exists.
 
331
********************************************************************/
 
332
 
 
333
bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
 
334
{
 
335
        SMB_STRUCT_STAT st2;
 
336
        bool ret;
 
337
 
 
338
        if (!st)
 
339
                st = &st2;
 
340
 
 
341
        if (SMB_VFS_STAT(conn,dname,st) != 0)
 
342
                return(False);
 
343
 
 
344
        ret = S_ISDIR(st->st_mode);
 
345
        if(!ret)
 
346
                errno = ENOTDIR;
 
347
 
 
348
        return ret;
 
349
}
 
350
 
 
351
/*******************************************************************
 
352
 Check if an object exists in the vfs.
 
353
********************************************************************/
 
354
 
 
355
bool vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
 
356
{
 
357
        SMB_STRUCT_STAT st;
 
358
 
 
359
        if (!sbuf)
 
360
                sbuf = &st;
 
361
 
 
362
        ZERO_STRUCTP(sbuf);
 
363
 
 
364
        if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
 
365
                return(False);
 
366
        return True;
 
367
}
 
368
 
 
369
/*******************************************************************
 
370
 Check if a file exists in the vfs.
 
371
********************************************************************/
 
372
 
 
373
bool vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
 
374
{
 
375
        SMB_STRUCT_STAT st;
 
376
 
 
377
        if (!sbuf)
 
378
                sbuf = &st;
 
379
 
 
380
        ZERO_STRUCTP(sbuf);
 
381
 
 
382
        if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
 
383
                return False;
 
384
        return(S_ISREG(sbuf->st_mode));
 
385
}
 
386
 
 
387
/****************************************************************************
 
388
 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
 
389
****************************************************************************/
 
390
 
 
391
ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
 
392
{
 
393
        size_t total=0;
 
394
 
 
395
        while (total < byte_count)
 
396
        {
 
397
                ssize_t ret = SMB_VFS_READ(fsp, buf + total,
 
398
                                           byte_count - total);
 
399
 
 
400
                if (ret == 0) return total;
 
401
                if (ret == -1) {
 
402
                        if (errno == EINTR)
 
403
                                continue;
 
404
                        else
 
405
                                return -1;
 
406
                }
 
407
                total += ret;
 
408
        }
 
409
        return (ssize_t)total;
 
410
}
 
411
 
 
412
ssize_t vfs_pread_data(files_struct *fsp, char *buf,
 
413
                size_t byte_count, SMB_OFF_T offset)
 
414
{
 
415
        size_t total=0;
 
416
 
 
417
        while (total < byte_count)
 
418
        {
 
419
                ssize_t ret = SMB_VFS_PREAD(fsp, buf + total,
 
420
                                        byte_count - total, offset + total);
 
421
 
 
422
                if (ret == 0) return total;
 
423
                if (ret == -1) {
 
424
                        if (errno == EINTR)
 
425
                                continue;
 
426
                        else
 
427
                                return -1;
 
428
                }
 
429
                total += ret;
 
430
        }
 
431
        return (ssize_t)total;
 
432
}
 
433
 
 
434
/****************************************************************************
 
435
 Write data to a fd on the vfs.
 
436
****************************************************************************/
 
437
 
 
438
ssize_t vfs_write_data(struct smb_request *req,
 
439
                        files_struct *fsp,
 
440
                        const char *buffer,
 
441
                        size_t N)
 
442
{
 
443
        size_t total=0;
 
444
        ssize_t ret;
 
445
 
 
446
        if (req && req->unread_bytes) {
 
447
                SMB_ASSERT(req->unread_bytes == N);
 
448
                /* VFS_RECVFILE must drain the socket
 
449
                 * before returning. */
 
450
                req->unread_bytes = 0;
 
451
                return SMB_VFS_RECVFILE(smbd_server_fd(),
 
452
                                        fsp,
 
453
                                        (SMB_OFF_T)-1,
 
454
                                        N);
 
455
        }
 
456
 
 
457
        while (total < N) {
 
458
                ret = SMB_VFS_WRITE(fsp, buffer + total, N - total);
 
459
 
 
460
                if (ret == -1)
 
461
                        return -1;
 
462
                if (ret == 0)
 
463
                        return total;
 
464
 
 
465
                total += ret;
 
466
        }
 
467
        return (ssize_t)total;
 
468
}
 
469
 
 
470
ssize_t vfs_pwrite_data(struct smb_request *req,
 
471
                        files_struct *fsp,
 
472
                        const char *buffer,
 
473
                        size_t N,
 
474
                        SMB_OFF_T offset)
 
475
{
 
476
        size_t total=0;
 
477
        ssize_t ret;
 
478
 
 
479
        if (req && req->unread_bytes) {
 
480
                SMB_ASSERT(req->unread_bytes == N);
 
481
                /* VFS_RECVFILE must drain the socket
 
482
                 * before returning. */
 
483
                req->unread_bytes = 0;
 
484
                return SMB_VFS_RECVFILE(smbd_server_fd(),
 
485
                                        fsp,
 
486
                                        offset,
 
487
                                        N);
 
488
        }
 
489
 
 
490
        while (total < N) {
 
491
                ret = SMB_VFS_PWRITE(fsp, buffer + total, N - total,
 
492
                                     offset + total);
 
493
 
 
494
                if (ret == -1)
 
495
                        return -1;
 
496
                if (ret == 0)
 
497
                        return total;
 
498
 
 
499
                total += ret;
 
500
        }
 
501
        return (ssize_t)total;
 
502
}
 
503
/****************************************************************************
 
504
 An allocate file space call using the vfs interface.
 
505
 Allocates space for a file from a filedescriptor.
 
506
 Returns 0 on success, -1 on failure.
 
507
****************************************************************************/
 
508
 
 
509
int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
 
510
{
 
511
        int ret;
 
512
        SMB_STRUCT_STAT st;
 
513
        connection_struct *conn = fsp->conn;
 
514
        uint64_t space_avail;
 
515
        uint64_t bsize,dfree,dsize;
 
516
 
 
517
        /*
 
518
         * Actually try and commit the space on disk....
 
519
         */
 
520
 
 
521
        DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
 
522
 
 
523
        if (((SMB_OFF_T)len) < 0) {
 
524
                DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
 
525
                errno = EINVAL;
 
526
                return -1;
 
527
        }
 
528
 
 
529
        ret = SMB_VFS_FSTAT(fsp, &st);
 
530
        if (ret == -1)
 
531
                return ret;
 
532
 
 
533
        if (len == (uint64_t)st.st_size)
 
534
                return 0;
 
535
 
 
536
        if (len < (uint64_t)st.st_size) {
 
537
                /* Shrink - use ftruncate. */
 
538
 
 
539
                DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
 
540
                                fsp->fsp_name, (double)st.st_size ));
 
541
 
 
542
                contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
 
543
 
 
544
                flush_write_cache(fsp, SIZECHANGE_FLUSH);
 
545
                if ((ret = SMB_VFS_FTRUNCATE(fsp, (SMB_OFF_T)len)) != -1) {
 
546
                        set_filelen_write_cache(fsp, len);
 
547
                }
 
548
 
 
549
                contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
 
550
 
 
551
                return ret;
 
552
        }
 
553
 
 
554
        /* Grow - we need to test if we have enough space. */
 
555
 
 
556
        contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_GROW);
 
557
        contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_GROW);
 
558
 
 
559
        if (!lp_strict_allocate(SNUM(fsp->conn)))
 
560
                return 0;
 
561
 
 
562
        len -= st.st_size;
 
563
        len /= 1024; /* Len is now number of 1k blocks needed. */
 
564
        space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
 
565
        if (space_avail == (uint64_t)-1) {
 
566
                return -1;
 
567
        }
 
568
 
 
569
        DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
 
570
                        fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
 
571
 
 
572
        if (len > space_avail) {
 
573
                errno = ENOSPC;
 
574
                return -1;
 
575
        }
 
576
 
 
577
        return 0;
 
578
}
 
579
 
 
580
/****************************************************************************
 
581
 A vfs set_filelen call.
 
582
 set the length of a file from a filedescriptor.
 
583
 Returns 0 on success, -1 on failure.
 
584
****************************************************************************/
 
585
 
 
586
int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
 
587
{
 
588
        int ret;
 
589
 
 
590
        contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
 
591
 
 
592
        DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
 
593
        flush_write_cache(fsp, SIZECHANGE_FLUSH);
 
594
        if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) {
 
595
                set_filelen_write_cache(fsp, len);
 
596
                notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
 
597
                             FILE_NOTIFY_CHANGE_SIZE
 
598
                             | FILE_NOTIFY_CHANGE_ATTRIBUTES,
 
599
                             fsp->fsp_name);
 
600
        }
 
601
 
 
602
        contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_SET_FILE_LEN);
 
603
 
 
604
        return ret;
 
605
}
 
606
 
 
607
/****************************************************************************
 
608
 A vfs fill sparse call.
 
609
 Writes zeros from the end of file to len, if len is greater than EOF.
 
610
 Used only by strict_sync.
 
611
 Returns 0 on success, -1 on failure.
 
612
****************************************************************************/
 
613
 
 
614
#define SPARSE_BUF_WRITE_SIZE (32*1024)
 
615
 
 
616
int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
 
617
{
 
618
        int ret;
 
619
        SMB_STRUCT_STAT st;
 
620
        SMB_OFF_T offset;
 
621
        size_t total;
 
622
        size_t num_to_write;
 
623
        ssize_t pwrite_ret;
 
624
 
 
625
        ret = SMB_VFS_FSTAT(fsp, &st);
 
626
        if (ret == -1) {
 
627
                return ret;
 
628
        }
 
629
 
 
630
        if (len <= st.st_size) {
 
631
                return 0;
 
632
        }
 
633
 
 
634
        DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
 
635
                fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
 
636
 
 
637
        contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE);
 
638
 
 
639
        flush_write_cache(fsp, SIZECHANGE_FLUSH);
 
640
 
 
641
        if (!sparse_buf) {
 
642
                sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
 
643
                if (!sparse_buf) {
 
644
                        errno = ENOMEM;
 
645
                        ret = -1;
 
646
                        goto out;
 
647
                }
 
648
        }
 
649
 
 
650
        offset = st.st_size;
 
651
        num_to_write = len - st.st_size;
 
652
        total = 0;
 
653
 
 
654
        while (total < num_to_write) {
 
655
                size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
 
656
 
 
657
                pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total);
 
658
                if (pwrite_ret == -1) {
 
659
                        DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
 
660
                                fsp->fsp_name, strerror(errno) ));
 
661
                        ret = -1;
 
662
                        goto out;
 
663
                }
 
664
                if (pwrite_ret == 0) {
 
665
                        ret = 0;
 
666
                        goto out;
 
667
                }
 
668
 
 
669
                total += pwrite_ret;
 
670
        }
 
671
 
 
672
        set_filelen_write_cache(fsp, len);
 
673
 
 
674
        ret = 0;
 
675
 out:
 
676
        contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_FILL_SPARSE);
 
677
        return ret;
 
678
}
 
679
 
 
680
/****************************************************************************
 
681
 Transfer some data (n bytes) between two file_struct's.
 
682
****************************************************************************/
 
683
 
 
684
static ssize_t vfs_read_fn(void *file, void *buf, size_t len)
 
685
{
 
686
        struct files_struct *fsp = (struct files_struct *)file;
 
687
 
 
688
        return SMB_VFS_READ(fsp, buf, len);
 
689
}
 
690
 
 
691
static ssize_t vfs_write_fn(void *file, const void *buf, size_t len)
 
692
{
 
693
        struct files_struct *fsp = (struct files_struct *)file;
 
694
 
 
695
        return SMB_VFS_WRITE(fsp, buf, len);
 
696
}
 
697
 
 
698
SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
 
699
{
 
700
        return transfer_file_internal((void *)in, (void *)out, n,
 
701
                                      vfs_read_fn, vfs_write_fn);
 
702
}
 
703
 
 
704
/*******************************************************************
 
705
 A vfs_readdir wrapper which just returns the file name.
 
706
********************************************************************/
 
707
 
 
708
char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf)
 
709
{
 
710
        SMB_STRUCT_DIRENT *ptr= NULL;
 
711
        char *dname;
 
712
 
 
713
        if (!p)
 
714
                return(NULL);
 
715
 
 
716
        ptr = SMB_VFS_READDIR(conn, (DIR *)p, sbuf);
 
717
        if (!ptr)
 
718
                return(NULL);
 
719
 
 
720
        dname = ptr->d_name;
 
721
 
 
722
#ifdef NEXT2
 
723
        if (telldir(p) < 0)
 
724
                return(NULL);
 
725
#endif
 
726
 
 
727
#ifdef HAVE_BROKEN_READDIR_NAME
 
728
        /* using /usr/ucb/cc is BAD */
 
729
        dname = dname - 2;
 
730
#endif
 
731
 
 
732
        return(dname);
 
733
}
 
734
 
 
735
/*******************************************************************
 
736
 A wrapper for vfs_chdir().
 
737
********************************************************************/
 
738
 
 
739
int vfs_ChDir(connection_struct *conn, const char *path)
 
740
{
 
741
        int res;
 
742
 
 
743
        if (!LastDir) {
 
744
                LastDir = SMB_STRDUP("");
 
745
        }
 
746
 
 
747
        if (strcsequal(path,"."))
 
748
                return(0);
 
749
 
 
750
        if (*path == '/' && strcsequal(LastDir,path))
 
751
                return(0);
 
752
 
 
753
        DEBUG(4,("vfs_ChDir to %s\n",path));
 
754
 
 
755
        res = SMB_VFS_CHDIR(conn,path);
 
756
        if (!res) {
 
757
                SAFE_FREE(LastDir);
 
758
                LastDir = SMB_STRDUP(path);
 
759
        }
 
760
        return(res);
 
761
}
 
762
 
 
763
/*******************************************************************
 
764
 Return the absolute current directory path - given a UNIX pathname.
 
765
 Note that this path is returned in DOS format, not UNIX
 
766
 format. Note this can be called with conn == NULL.
 
767
********************************************************************/
 
768
 
 
769
char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
 
770
{
 
771
        char s[PATH_MAX+1];
 
772
        SMB_STRUCT_STAT st, st2;
 
773
        char *result;
 
774
        DATA_BLOB cache_value;
 
775
        struct file_id key;
 
776
 
 
777
        *s = 0;
 
778
 
 
779
        if (!lp_getwd_cache()) {
 
780
                goto nocache;
 
781
        }
 
782
 
 
783
        SET_STAT_INVALID(st);
 
784
 
 
785
        if (SMB_VFS_STAT(conn, ".",&st) == -1) {
 
786
                /*
 
787
                 * Known to fail for root: the directory may be NFS-mounted
 
788
                 * and exported with root_squash (so has no root access).
 
789
                 */
 
790
                DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s "
 
791
                         "(NFS problem ?)\n", strerror(errno) ));
 
792
                goto nocache;
 
793
        }
 
794
 
 
795
        key = vfs_file_id_from_sbuf(conn, &st);
 
796
 
 
797
        if (!memcache_lookup(smbd_memcache(), GETWD_CACHE,
 
798
                             data_blob_const(&key, sizeof(key)),
 
799
                             &cache_value)) {
 
800
                goto nocache;
 
801
        }
 
802
 
 
803
        SMB_ASSERT((cache_value.length > 0)
 
804
                   && (cache_value.data[cache_value.length-1] == '\0'));
 
805
 
 
806
        if ((SMB_VFS_STAT(conn, (char *)cache_value.data, &st2) == 0)
 
807
            && (st.st_dev == st2.st_dev) && (st.st_ino == st2.st_ino)
 
808
            && (S_ISDIR(st.st_mode))) {
 
809
                /*
 
810
                 * Ok, we're done
 
811
                 */
 
812
                result = talloc_strdup(ctx, (char *)cache_value.data);
 
813
                if (result == NULL) {
 
814
                        errno = ENOMEM;
 
815
                }
 
816
                return result;
 
817
        }
 
818
 
 
819
 nocache:
 
820
 
 
821
        /*
 
822
         * We don't have the information to hand so rely on traditional
 
823
         * methods. The very slow getcwd, which spawns a process on some
 
824
         * systems, or the not quite so bad getwd.
 
825
         */
 
826
 
 
827
        if (!SMB_VFS_GETWD(conn,s)) {
 
828
                DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n",
 
829
                          strerror(errno)));
 
830
                return NULL;
 
831
        }
 
832
 
 
833
        if (lp_getwd_cache() && VALID_STAT(st)) {
 
834
                key = vfs_file_id_from_sbuf(conn, &st);
 
835
 
 
836
                memcache_add(smbd_memcache(), GETWD_CACHE,
 
837
                             data_blob_const(&key, sizeof(key)),
 
838
                             data_blob_const(s, strlen(s)+1));
 
839
        }
 
840
 
 
841
        result = talloc_strdup(ctx, s);
 
842
        if (result == NULL) {
 
843
                errno = ENOMEM;
 
844
        }
 
845
        return result;
 
846
}
 
847
 
 
848
/*******************************************************************
 
849
 Reduce a file name, removing .. elements and checking that
 
850
 it is below dir in the heirachy. This uses realpath.
 
851
********************************************************************/
 
852
 
 
853
NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
 
854
{
 
855
#ifdef REALPATH_TAKES_NULL
 
856
        bool free_resolved_name = True;
 
857
#else
 
858
        char resolved_name_buf[PATH_MAX+1];
 
859
        bool free_resolved_name = False;
 
860
#endif
 
861
        char *resolved_name = NULL;
 
862
        size_t con_path_len = strlen(conn->connectpath);
 
863
        char *p = NULL;
 
864
 
 
865
        DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
 
866
 
 
867
#ifdef REALPATH_TAKES_NULL
 
868
        resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
 
869
#else
 
870
        resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
 
871
#endif
 
872
 
 
873
        if (!resolved_name) {
 
874
                switch (errno) {
 
875
                        case ENOTDIR:
 
876
                                DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
 
877
                                return map_nt_error_from_unix(errno);
 
878
                        case ENOENT:
 
879
                        {
 
880
                                TALLOC_CTX *ctx = talloc_tos();
 
881
                                char *tmp_fname = NULL;
 
882
                                char *last_component = NULL;
 
883
                                /* Last component didn't exist. Remove it and try and canonicalise the directory. */
 
884
 
 
885
                                tmp_fname = talloc_strdup(ctx, fname);
 
886
                                if (!tmp_fname) {
 
887
                                        return NT_STATUS_NO_MEMORY;
 
888
                                }
 
889
                                p = strrchr_m(tmp_fname, '/');
 
890
                                if (p) {
 
891
                                        *p++ = '\0';
 
892
                                        last_component = p;
 
893
                                } else {
 
894
                                        last_component = tmp_fname;
 
895
                                        tmp_fname = talloc_strdup(ctx,
 
896
                                                        ".");
 
897
                                        if (!tmp_fname) {
 
898
                                                return NT_STATUS_NO_MEMORY;
 
899
                                        }
 
900
                                }
 
901
 
 
902
#ifdef REALPATH_TAKES_NULL
 
903
                                resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
 
904
#else
 
905
                                resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
 
906
#endif
 
907
                                if (!resolved_name) {
 
908
                                        DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
 
909
                                        return map_nt_error_from_unix(errno);
 
910
                                }
 
911
                                tmp_fname = talloc_asprintf(ctx,
 
912
                                                "%s/%s",
 
913
                                                resolved_name,
 
914
                                                last_component);
 
915
                                if (!tmp_fname) {
 
916
                                        return NT_STATUS_NO_MEMORY;
 
917
                                }
 
918
#ifdef REALPATH_TAKES_NULL
 
919
                                SAFE_FREE(resolved_name);
 
920
                                resolved_name = SMB_STRDUP(tmp_fname);
 
921
                                if (!resolved_name) {
 
922
                                        DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
 
923
                                        return NT_STATUS_NO_MEMORY;
 
924
                                }
 
925
#else
 
926
                                safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
 
927
                                resolved_name = resolved_name_buf;
 
928
#endif
 
929
                                break;
 
930
                        }
 
931
                        default:
 
932
                                DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
 
933
                                return map_nt_error_from_unix(errno);
 
934
                }
 
935
        }
 
936
 
 
937
        DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
 
938
 
 
939
        if (*resolved_name != '/') {
 
940
                DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
 
941
                if (free_resolved_name) {
 
942
                        SAFE_FREE(resolved_name);
 
943
                }
 
944
                return NT_STATUS_OBJECT_NAME_INVALID;
 
945
        }
 
946
 
 
947
        /* Check for widelinks allowed. */
 
948
        if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
 
949
                DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path\n", fname));
 
950
                if (free_resolved_name) {
 
951
                        SAFE_FREE(resolved_name);
 
952
                }
 
953
                return NT_STATUS_ACCESS_DENIED;
 
954
        }
 
955
 
 
956
        /* Check if we are allowing users to follow symlinks */
 
957
        /* Patch from David Clerc <David.Clerc@cui.unige.ch>
 
958
                University of Geneva */
 
959
 
 
960
#ifdef S_ISLNK
 
961
        if (!lp_symlinks(SNUM(conn))) {
 
962
                SMB_STRUCT_STAT statbuf;
 
963
                if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
 
964
                                (S_ISLNK(statbuf.st_mode)) ) {
 
965
                        if (free_resolved_name) {
 
966
                                SAFE_FREE(resolved_name);
 
967
                        }
 
968
                        DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
 
969
                        return NT_STATUS_ACCESS_DENIED;
 
970
                }
 
971
        }
 
972
#endif
 
973
 
 
974
        DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
 
975
        if (free_resolved_name) {
 
976
                SAFE_FREE(resolved_name);
 
977
        }
 
978
        return NT_STATUS_OK;
 
979
}