~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/smbd/vfs.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

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 2 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, write to the Free Software
21
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
 
 
23
 
   This work was sponsored by Optifacio Software Services, Inc.
24
 
*/
25
 
 
26
 
#include "includes.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
 
        vfs_op_tuple *vfs_op_tuples;
36
 
        struct vfs_init_function_entry *prev, *next;
37
 
};
38
 
 
39
 
static struct vfs_init_function_entry *backends = NULL;
40
 
 
41
 
/****************************************************************************
42
 
    maintain the list of available backends
43
 
****************************************************************************/
44
 
 
45
 
static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
46
 
{
47
 
        struct vfs_init_function_entry *entry = backends;
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, 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**)&vfs->ops)[which] = op;
108
 
}
109
 
 
110
 
BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
111
 
{
112
 
        vfs_op_tuple *ops;
113
 
        char *module_name = NULL;
114
 
        char *module_param = NULL, *p;
115
 
        int i;
116
 
        vfs_handle_struct *handle;
117
 
        struct vfs_init_function_entry *entry;
118
 
        
119
 
        if (!conn||!vfs_object||!vfs_object[0]) {
120
 
                DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
121
 
                return False;
122
 
        }
123
 
 
124
 
        if(!backends) {
125
 
                static_init_vfs;
126
 
        }
127
 
 
128
 
        DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
129
 
 
130
 
        module_name = smb_xstrdup(vfs_object);
131
 
 
132
 
        p = strchr_m(module_name, ':');
133
 
 
134
 
        if (p) {
135
 
                *p = 0;
136
 
                module_param = p+1;
137
 
                trim_char(module_param, ' ', ' ');
138
 
        }
139
 
 
140
 
        trim_char(module_name, ' ', ' ');
141
 
 
142
 
        /* First, try to load the module with the new module system */
143
 
        if((entry = vfs_find_backend_entry(module_name)) || 
144
 
           (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) && 
145
 
                (entry = vfs_find_backend_entry(module_name)))) {
146
 
 
147
 
                DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
148
 
                
149
 
                if ((ops = entry->vfs_op_tuples) == NULL) {
150
 
                        DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
151
 
                        SAFE_FREE(module_name);
152
 
                        return False;
153
 
                }
154
 
        } else {
155
 
                DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
156
 
                SAFE_FREE(module_name);
157
 
                return False;
158
 
        }
159
 
 
160
 
        handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
161
 
        if (!handle) {
162
 
                DEBUG(0,("talloc_zero() failed!\n"));
163
 
                SAFE_FREE(module_name);
164
 
                return False;
165
 
        }
166
 
        memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
167
 
        handle->conn = conn;
168
 
        if (module_param) {
169
 
                handle->param = talloc_strdup(conn->mem_ctx, module_param);
170
 
        }
171
 
        DLIST_ADD(conn->vfs_handles, handle);
172
 
 
173
 
        for(i=0; ops[i].op != NULL; i++) {
174
 
                DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
175
 
                if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
176
 
                        /* If this operation was already made opaque by different module, it
177
 
                         * will be overridded here.
178
 
                         */
179
 
                        DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
180
 
                        vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
181
 
                }
182
 
                /* Change current VFS disposition*/
183
 
                DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
184
 
                vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
185
 
        }
186
 
 
187
 
        SAFE_FREE(module_name);
188
 
        return True;
189
 
}
190
 
 
191
 
/*****************************************************************
192
 
 Allow VFS modules to extend files_struct with VFS-specific state.
193
 
 This will be ok for small numbers of extensions, but might need to
194
 
 be refactored if it becomes more widely used.
195
 
******************************************************************/
196
 
 
197
 
#define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
198
 
 
199
 
void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
200
 
{
201
 
        struct vfs_fsp_data *ext;
202
 
        void * ext_data;
203
 
 
204
 
        /* Prevent VFS modules adding multiple extensions. */
205
 
        if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
206
 
                return ext_data;
207
 
        }
208
 
 
209
 
        ext = TALLOC_ZERO(handle->conn->mem_ctx,
210
 
                            sizeof(struct vfs_fsp_data) + ext_size);
211
 
        if (ext == NULL) {
212
 
                return NULL;
213
 
        }
214
 
 
215
 
        ext->owner = handle;
216
 
        ext->next = fsp->vfs_extension;
217
 
        fsp->vfs_extension = ext;
218
 
        return EXT_DATA_AREA(ext);
219
 
}
220
 
 
221
 
void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
222
 
{
223
 
        struct vfs_fsp_data *curr;
224
 
        struct vfs_fsp_data *prev;
225
 
 
226
 
        for (curr = fsp->vfs_extension, prev = NULL;
227
 
             curr;
228
 
             prev = curr, curr = curr->next) {
229
 
                if (curr->owner == handle) {
230
 
                    if (prev) {
231
 
                            prev->next = curr->next;
232
 
                    } else {
233
 
                            fsp->vfs_extension = curr->next;
234
 
                    }
235
 
                    TALLOC_FREE(curr);
236
 
                    return;
237
 
                }
238
 
        }
239
 
}
240
 
 
241
 
void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
242
 
{
243
 
        struct vfs_fsp_data *head;
244
 
 
245
 
        for (head = fsp->vfs_extension; head; head = head->next) {
246
 
                if (head->owner == handle) {
247
 
                        return EXT_DATA_AREA(head);
248
 
                }
249
 
        }
250
 
 
251
 
        return NULL;
252
 
}
253
 
 
254
 
#undef EXT_DATA_AREA
255
 
 
256
 
/*****************************************************************
257
 
 Generic VFS init.
258
 
******************************************************************/
259
 
 
260
 
BOOL smbd_vfs_init(connection_struct *conn)
261
 
{
262
 
        const char **vfs_objects;
263
 
        unsigned int i = 0;
264
 
        int j = 0;
265
 
        
266
 
        /* Normal share - initialise with disk access functions */
267
 
        vfs_init_default(conn);
268
 
        vfs_objects = lp_vfs_objects(SNUM(conn));
269
 
 
270
 
        /* Override VFS functions if 'vfs object' was not specified*/
271
 
        if (!vfs_objects || !vfs_objects[0])
272
 
                return True;
273
 
        
274
 
        for (i=0; vfs_objects[i] ;) {
275
 
                i++;
276
 
        }
277
 
 
278
 
        for (j=i-1; j >= 0; j--) {
279
 
                if (!vfs_init_custom(conn, vfs_objects[j])) {
280
 
                        DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
281
 
                        return False;
282
 
                }
283
 
        }
284
 
        return True;
285
 
}
286
 
 
287
 
/*******************************************************************
288
 
 Check if directory exists.
289
 
********************************************************************/
290
 
 
291
 
BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
292
 
{
293
 
        SMB_STRUCT_STAT st2;
294
 
        BOOL ret;
295
 
 
296
 
        if (!st)
297
 
                st = &st2;
298
 
 
299
 
        if (SMB_VFS_STAT(conn,dname,st) != 0)
300
 
                return(False);
301
 
 
302
 
        ret = S_ISDIR(st->st_mode);
303
 
        if(!ret)
304
 
                errno = ENOTDIR;
305
 
 
306
 
        return ret;
307
 
}
308
 
 
309
 
/*******************************************************************
310
 
 vfs mkdir wrapper 
311
 
********************************************************************/
312
 
 
313
 
int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
314
 
{
315
 
        int ret;
316
 
        SMB_STRUCT_STAT sbuf;
317
 
 
318
 
        if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
319
 
 
320
 
                inherit_access_acl(conn, name, mode);
321
 
 
322
 
                /*
323
 
                 * Check if high bits should have been set,
324
 
                 * then (if bits are missing): add them.
325
 
                 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
326
 
                 */
327
 
                if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
328
 
                                !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
329
 
                        SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
330
 
        }
331
 
        return ret;
332
 
}
333
 
 
334
 
/*******************************************************************
335
 
 Check if an object exists in the vfs.
336
 
********************************************************************/
337
 
 
338
 
BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
339
 
{
340
 
        SMB_STRUCT_STAT st;
341
 
 
342
 
        if (!sbuf)
343
 
                sbuf = &st;
344
 
 
345
 
        ZERO_STRUCTP(sbuf);
346
 
 
347
 
        if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
348
 
                return(False);
349
 
        return True;
350
 
}
351
 
 
352
 
/*******************************************************************
353
 
 Check if a file exists in the vfs.
354
 
********************************************************************/
355
 
 
356
 
BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
357
 
{
358
 
        SMB_STRUCT_STAT st;
359
 
 
360
 
        if (!sbuf)
361
 
                sbuf = &st;
362
 
 
363
 
        ZERO_STRUCTP(sbuf);
364
 
 
365
 
        if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
366
 
                return False;
367
 
        return(S_ISREG(sbuf->st_mode));
368
 
}
369
 
 
370
 
/****************************************************************************
371
 
 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
372
 
****************************************************************************/
373
 
 
374
 
ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
375
 
{
376
 
        size_t total=0;
377
 
 
378
 
        while (total < byte_count)
379
 
        {
380
 
                ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
381
 
                                        byte_count - total);
382
 
 
383
 
                if (ret == 0) return total;
384
 
                if (ret == -1) {
385
 
                        if (errno == EINTR)
386
 
                                continue;
387
 
                        else
388
 
                                return -1;
389
 
                }
390
 
                total += ret;
391
 
        }
392
 
        return (ssize_t)total;
393
 
}
394
 
 
395
 
ssize_t vfs_pread_data(files_struct *fsp, char *buf,
396
 
                size_t byte_count, SMB_OFF_T offset)
397
 
{
398
 
        size_t total=0;
399
 
 
400
 
        while (total < byte_count)
401
 
        {
402
 
                ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
403
 
                                        byte_count - total, offset + total);
404
 
 
405
 
                if (ret == 0) return total;
406
 
                if (ret == -1) {
407
 
                        if (errno == EINTR)
408
 
                                continue;
409
 
                        else
410
 
                                return -1;
411
 
                }
412
 
                total += ret;
413
 
        }
414
 
        return (ssize_t)total;
415
 
}
416
 
 
417
 
/****************************************************************************
418
 
 Write data to a fd on the vfs.
419
 
****************************************************************************/
420
 
 
421
 
ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
422
 
{
423
 
        size_t total=0;
424
 
        ssize_t ret;
425
 
 
426
 
        while (total < N) {
427
 
                ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
428
 
 
429
 
                if (ret == -1)
430
 
                        return -1;
431
 
                if (ret == 0)
432
 
                        return total;
433
 
 
434
 
                total += ret;
435
 
        }
436
 
        return (ssize_t)total;
437
 
}
438
 
 
439
 
ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
440
 
                size_t N, SMB_OFF_T offset)
441
 
{
442
 
        size_t total=0;
443
 
        ssize_t ret;
444
 
 
445
 
        while (total < N) {
446
 
                ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
447
 
                                N - total, offset + total);
448
 
 
449
 
                if (ret == -1)
450
 
                        return -1;
451
 
                if (ret == 0)
452
 
                        return total;
453
 
 
454
 
                total += ret;
455
 
        }
456
 
        return (ssize_t)total;
457
 
}
458
 
/****************************************************************************
459
 
 An allocate file space call using the vfs interface.
460
 
 Allocates space for a file from a filedescriptor.
461
 
 Returns 0 on success, -1 on failure.
462
 
****************************************************************************/
463
 
 
464
 
int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
465
 
{
466
 
        int ret;
467
 
        SMB_STRUCT_STAT st;
468
 
        connection_struct *conn = fsp->conn;
469
 
        SMB_BIG_UINT space_avail;
470
 
        SMB_BIG_UINT bsize,dfree,dsize;
471
 
 
472
 
        release_level_2_oplocks_on_change(fsp);
473
 
 
474
 
        /*
475
 
         * Actually try and commit the space on disk....
476
 
         */
477
 
 
478
 
        DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
479
 
 
480
 
        if (((SMB_OFF_T)len) < 0) {
481
 
                DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
482
 
                return -1;
483
 
        }
484
 
 
485
 
        ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
486
 
        if (ret == -1)
487
 
                return ret;
488
 
 
489
 
        if (len == (SMB_BIG_UINT)st.st_size)
490
 
                return 0;
491
 
 
492
 
        if (len < (SMB_BIG_UINT)st.st_size) {
493
 
                /* Shrink - use ftruncate. */
494
 
 
495
 
                DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
496
 
                                fsp->fsp_name, (double)st.st_size ));
497
 
 
498
 
                flush_write_cache(fsp, SIZECHANGE_FLUSH);
499
 
                if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
500
 
                        set_filelen_write_cache(fsp, len);
501
 
                }
502
 
                return ret;
503
 
        }
504
 
 
505
 
        /* Grow - we need to test if we have enough space. */
506
 
 
507
 
        if (!lp_strict_allocate(SNUM(fsp->conn)))
508
 
                return 0;
509
 
 
510
 
        len -= st.st_size;
511
 
        len /= 1024; /* Len is now number of 1k blocks needed. */
512
 
        space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
513
 
        if (space_avail == (SMB_BIG_UINT)-1) {
514
 
                return -1;
515
 
        }
516
 
 
517
 
        DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
518
 
                        fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
519
 
 
520
 
        if (len > space_avail) {
521
 
                errno = ENOSPC;
522
 
                return -1;
523
 
        }
524
 
 
525
 
        return 0;
526
 
}
527
 
 
528
 
/****************************************************************************
529
 
 A vfs set_filelen call.
530
 
 set the length of a file from a filedescriptor.
531
 
 Returns 0 on success, -1 on failure.
532
 
****************************************************************************/
533
 
 
534
 
int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
535
 
{
536
 
        int ret;
537
 
 
538
 
        release_level_2_oplocks_on_change(fsp);
539
 
        DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
540
 
        flush_write_cache(fsp, SIZECHANGE_FLUSH);
541
 
        if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1)
542
 
                set_filelen_write_cache(fsp, len);
543
 
 
544
 
        return ret;
545
 
}
546
 
 
547
 
/****************************************************************************
548
 
 A vfs fill sparse call.
549
 
 Writes zeros from the end of file to len, if len is greater than EOF.
550
 
 Used only by strict_sync.
551
 
 Returns 0 on success, -1 on failure.
552
 
****************************************************************************/
553
 
 
554
 
static char *sparse_buf;
555
 
#define SPARSE_BUF_WRITE_SIZE (32*1024)
556
 
 
557
 
int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
558
 
{
559
 
        int ret;
560
 
        SMB_STRUCT_STAT st;
561
 
        SMB_OFF_T offset;
562
 
        size_t total;
563
 
        size_t num_to_write;
564
 
        ssize_t pwrite_ret;
565
 
 
566
 
        release_level_2_oplocks_on_change(fsp);
567
 
        ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
568
 
        if (ret == -1) {
569
 
                return ret;
570
 
        }
571
 
 
572
 
        if (len <= st.st_size) {
573
 
                return 0;
574
 
        }
575
 
 
576
 
        DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
577
 
                fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
578
 
 
579
 
        flush_write_cache(fsp, SIZECHANGE_FLUSH);
580
 
 
581
 
        if (!sparse_buf) {
582
 
                sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
583
 
                if (!sparse_buf) {
584
 
                        errno = ENOMEM;
585
 
                        return -1;
586
 
                }
587
 
        }
588
 
 
589
 
        offset = st.st_size;
590
 
        num_to_write = len - st.st_size;
591
 
        total = 0;
592
 
 
593
 
        while (total < num_to_write) {
594
 
                size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
595
 
 
596
 
                pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
597
 
                if (pwrite_ret == -1) {
598
 
                        DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
599
 
                                fsp->fsp_name, strerror(errno) ));
600
 
                        return -1;
601
 
                }
602
 
                if (pwrite_ret == 0) {
603
 
                        return 0;
604
 
                }
605
 
 
606
 
                total += pwrite_ret;
607
 
        }
608
 
 
609
 
        set_filelen_write_cache(fsp, len);
610
 
        return 0;
611
 
}
612
 
 
613
 
/****************************************************************************
614
 
 Transfer some data (n bytes) between two file_struct's.
615
 
****************************************************************************/
616
 
 
617
 
static files_struct *in_fsp;
618
 
static files_struct *out_fsp;
619
 
 
620
 
static ssize_t read_fn(int fd, void *buf, size_t len)
621
 
{
622
 
        return SMB_VFS_READ(in_fsp, fd, buf, len);
623
 
}
624
 
 
625
 
static ssize_t write_fn(int fd, const void *buf, size_t len)
626
 
{
627
 
        return SMB_VFS_WRITE(out_fsp, fd, buf, len);
628
 
}
629
 
 
630
 
SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
631
 
{
632
 
        in_fsp = in;
633
 
        out_fsp = out;
634
 
 
635
 
        return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
636
 
}
637
 
 
638
 
/*******************************************************************
639
 
 A vfs_readdir wrapper which just returns the file name.
640
 
********************************************************************/
641
 
 
642
 
char *vfs_readdirname(connection_struct *conn, void *p)
643
 
{
644
 
        SMB_STRUCT_DIRENT *ptr= NULL;
645
 
        char *dname;
646
 
 
647
 
        if (!p)
648
 
                return(NULL);
649
 
 
650
 
        ptr = SMB_VFS_READDIR(conn,p);
651
 
        if (!ptr)
652
 
                return(NULL);
653
 
 
654
 
        dname = ptr->d_name;
655
 
 
656
 
#ifdef NEXT2
657
 
        if (telldir(p) < 0)
658
 
                return(NULL);
659
 
#endif
660
 
 
661
 
#ifdef HAVE_BROKEN_READDIR_NAME
662
 
        /* using /usr/ucb/cc is BAD */
663
 
        dname = dname - 2;
664
 
#endif
665
 
 
666
 
        return(dname);
667
 
}
668
 
 
669
 
/*******************************************************************
670
 
 A wrapper for vfs_chdir().
671
 
********************************************************************/
672
 
 
673
 
int vfs_ChDir(connection_struct *conn, const char *path)
674
 
{
675
 
        int res;
676
 
        static pstring LastDir="";
677
 
 
678
 
        if (strcsequal(path,"."))
679
 
                return(0);
680
 
 
681
 
        if (*path == '/' && strcsequal(LastDir,path))
682
 
                return(0);
683
 
 
684
 
        DEBUG(4,("vfs_ChDir to %s\n",path));
685
 
 
686
 
        res = SMB_VFS_CHDIR(conn,path);
687
 
        if (!res)
688
 
                pstrcpy(LastDir,path);
689
 
        return(res);
690
 
}
691
 
 
692
 
/* number of list structures for a caching GetWd function. */
693
 
#define MAX_GETWDCACHE (50)
694
 
 
695
 
static struct {
696
 
        SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
697
 
        SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
698
 
        char *dos_path; /* The pathname in DOS format. */
699
 
        BOOL valid;
700
 
} ino_list[MAX_GETWDCACHE];
701
 
 
702
 
extern BOOL use_getwd_cache;
703
 
 
704
 
/****************************************************************************
705
 
 Prompte a ptr (to make it recently used)
706
 
****************************************************************************/
707
 
 
708
 
static void array_promote(char *array,int elsize,int element)
709
 
{
710
 
        char *p;
711
 
        if (element == 0)
712
 
                return;
713
 
 
714
 
        p = (char *)SMB_MALLOC(elsize);
715
 
 
716
 
        if (!p) {
717
 
                DEBUG(5,("array_promote: malloc fail\n"));
718
 
                return;
719
 
        }
720
 
 
721
 
        memcpy(p,array + element * elsize, elsize);
722
 
        memmove(array + elsize,array,elsize*element);
723
 
        memcpy(array,p,elsize);
724
 
        SAFE_FREE(p);
725
 
}
726
 
 
727
 
/*******************************************************************
728
 
 Return the absolute current directory path - given a UNIX pathname.
729
 
 Note that this path is returned in DOS format, not UNIX
730
 
 format. Note this can be called with conn == NULL.
731
 
********************************************************************/
732
 
 
733
 
char *vfs_GetWd(connection_struct *conn, char *path)
734
 
{
735
 
        pstring s;
736
 
        static BOOL getwd_cache_init = False;
737
 
        SMB_STRUCT_STAT st, st2;
738
 
        int i;
739
 
 
740
 
        *s = 0;
741
 
 
742
 
        if (!use_getwd_cache)
743
 
                return(SMB_VFS_GETWD(conn,path));
744
 
 
745
 
        /* init the cache */
746
 
        if (!getwd_cache_init) {
747
 
                getwd_cache_init = True;
748
 
                for (i=0;i<MAX_GETWDCACHE;i++) {
749
 
                        string_set(&ino_list[i].dos_path,"");
750
 
                        ino_list[i].valid = False;
751
 
                }
752
 
        }
753
 
 
754
 
        /*  Get the inode of the current directory, if this doesn't work we're
755
 
                in trouble :-) */
756
 
 
757
 
        if (SMB_VFS_STAT(conn, ".",&st) == -1) {
758
 
                /* Known to fail for root: the directory may be
759
 
                 * NFS-mounted and exported with root_squash (so has no root access). */
760
 
                DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
761
 
                return(SMB_VFS_GETWD(conn,path));
762
 
        }
763
 
 
764
 
 
765
 
        for (i=0; i<MAX_GETWDCACHE; i++) {
766
 
                if (ino_list[i].valid) {
767
 
 
768
 
                        /*  If we have found an entry with a matching inode and dev number
769
 
                                then find the inode number for the directory in the cached string.
770
 
                                If this agrees with that returned by the stat for the current
771
 
                                directory then all is o.k. (but make sure it is a directory all
772
 
                                the same...) */
773
 
 
774
 
                        if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
775
 
                                if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
776
 
                                        if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
777
 
                                                        (st2.st_mode & S_IFMT) == S_IFDIR) {
778
 
                                                pstrcpy (path, ino_list[i].dos_path);
779
 
 
780
 
                                                /* promote it for future use */
781
 
                                                array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
782
 
                                                return (path);
783
 
                                        } else {
784
 
                                                /*  If the inode is different then something's changed,
785
 
                                                        scrub the entry and start from scratch. */
786
 
                                                ino_list[i].valid = False;
787
 
                                        }
788
 
                                }
789
 
                        }
790
 
                }
791
 
        }
792
 
 
793
 
        /*  We don't have the information to hand so rely on traditional methods.
794
 
                The very slow getcwd, which spawns a process on some systems, or the
795
 
                not quite so bad getwd. */
796
 
 
797
 
        if (!SMB_VFS_GETWD(conn,s)) {
798
 
                DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
799
 
                return (NULL);
800
 
        }
801
 
 
802
 
        pstrcpy(path,s);
803
 
 
804
 
        DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
805
 
 
806
 
        /* add it to the cache */
807
 
        i = MAX_GETWDCACHE - 1;
808
 
        string_set(&ino_list[i].dos_path,s);
809
 
        ino_list[i].dev = st.st_dev;
810
 
        ino_list[i].inode = st.st_ino;
811
 
        ino_list[i].valid = True;
812
 
 
813
 
        /* put it at the top of the list */
814
 
        array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
815
 
 
816
 
        return (path);
817
 
}
818
 
 
819
 
BOOL canonicalize_path(connection_struct *conn, pstring path)
820
 
{
821
 
#ifdef REALPATH_TAKES_NULL
822
 
        char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
823
 
        if (!resolved_name) {
824
 
                return False;
825
 
        }
826
 
        pstrcpy(path, resolved_name);
827
 
        SAFE_FREE(resolved_name);
828
 
        return True;
829
 
#else
830
 
#ifdef PATH_MAX
831
 
        char resolved_name_buf[PATH_MAX+1];
832
 
#else
833
 
        pstring resolved_name_buf;
834
 
#endif
835
 
        char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
836
 
        if (!resolved_name) {
837
 
                return False;
838
 
        }
839
 
        pstrcpy(path, resolved_name);
840
 
        return True;
841
 
#endif /* REALPATH_TAKES_NULL */
842
 
}
843
 
 
844
 
/*******************************************************************
845
 
 Reduce a file name, removing .. elements and checking that
846
 
 it is below dir in the heirachy. This uses realpath.
847
 
********************************************************************/
848
 
 
849
 
BOOL reduce_name(connection_struct *conn, const pstring fname)
850
 
{
851
 
#ifdef REALPATH_TAKES_NULL
852
 
        BOOL free_resolved_name = True;
853
 
#else
854
 
#ifdef PATH_MAX
855
 
        char resolved_name_buf[PATH_MAX+1];
856
 
#else
857
 
        pstring resolved_name_buf;
858
 
#endif
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
 
        int saved_errno = errno;
865
 
 
866
 
        DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
867
 
 
868
 
#ifdef REALPATH_TAKES_NULL
869
 
        resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
870
 
#else
871
 
        resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
872
 
#endif
873
 
 
874
 
        if (!resolved_name) {
875
 
                switch (errno) {
876
 
                        case ENOTDIR:
877
 
                                DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
878
 
                                errno = saved_errno;
879
 
                                return False;
880
 
                        case ENOENT:
881
 
                        {
882
 
                                pstring tmp_fname;
883
 
                                fstring last_component;
884
 
                                /* Last component didn't exist. Remove it and try and canonicalise the directory. */
885
 
 
886
 
                                pstrcpy(tmp_fname, fname);
887
 
                                p = strrchr_m(tmp_fname, '/');
888
 
                                if (p) {
889
 
                                        *p++ = '\0';
890
 
                                        fstrcpy(last_component, p);
891
 
                                } else {
892
 
                                        fstrcpy(last_component, tmp_fname);
893
 
                                        pstrcpy(tmp_fname, ".");
894
 
                                }
895
 
 
896
 
#ifdef REALPATH_TAKES_NULL
897
 
                                resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
898
 
#else
899
 
                                resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
900
 
#endif
901
 
                                if (!resolved_name) {
902
 
                                        DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
903
 
                                        errno = saved_errno;
904
 
                                        return False;
905
 
                                }
906
 
                                pstrcpy(tmp_fname, resolved_name);
907
 
                                pstrcat(tmp_fname, "/");
908
 
                                pstrcat(tmp_fname, last_component);
909
 
#ifdef REALPATH_TAKES_NULL
910
 
                                SAFE_FREE(resolved_name);
911
 
                                resolved_name = SMB_STRDUP(tmp_fname);
912
 
                                if (!resolved_name) {
913
 
                                        DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
914
 
                                        errno = saved_errno;
915
 
                                        return False;
916
 
                                }
917
 
#else
918
 
#ifdef PATH_MAX
919
 
                                safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
920
 
#else
921
 
                                pstrcpy(resolved_name_buf, tmp_fname);
922
 
#endif
923
 
                                resolved_name = resolved_name_buf;
924
 
#endif
925
 
                                break;
926
 
                        }
927
 
                        default:
928
 
                                DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
929
 
                                /* Don't restore the saved errno. We need to return the error that
930
 
                                   realpath caused here as it was not one of the cases we handle. JRA. */
931
 
                                return False;
932
 
                }
933
 
        }
934
 
 
935
 
        DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
936
 
 
937
 
        if (*resolved_name != '/') {
938
 
                DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
939
 
                if (free_resolved_name)
940
 
                        SAFE_FREE(resolved_name);
941
 
                errno = saved_errno;
942
 
                return False;
943
 
        }
944
 
 
945
 
        /* Check for widelinks allowed. */
946
 
        if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
947
 
                DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
948
 
                if (free_resolved_name)
949
 
                        SAFE_FREE(resolved_name);
950
 
                errno = EACCES;
951
 
                return False;
952
 
        }
953
 
 
954
 
        /* Check if we are allowing users to follow symlinks */
955
 
        /* Patch from David Clerc <David.Clerc@cui.unige.ch>
956
 
                University of Geneva */
957
 
                                                                                                                                                    
958
 
#ifdef S_ISLNK
959
 
        if (!lp_symlinks(SNUM(conn))) {
960
 
                SMB_STRUCT_STAT statbuf;
961
 
                if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
962
 
                                (S_ISLNK(statbuf.st_mode)) ) {
963
 
                        if (free_resolved_name)
964
 
                                SAFE_FREE(resolved_name);
965
 
                        DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
966
 
                        errno = EACCES;
967
 
                        return False;
968
 
                }
969
 
        }
970
 
#endif
971
 
 
972
 
        DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
973
 
        if (free_resolved_name)
974
 
                SAFE_FREE(resolved_name);
975
 
        errno = saved_errno;
976
 
        return(True);
977
 
}