2 Unix SMB/CIFS implementation.
4 simple NTVFS filesystem backend
6 Copyright (C) Andrew Tridgell 2003
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.
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.
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.
23 this implements a very simple NTVFS filesystem backend.
25 this backend largely ignores the POSIX -> CIFS mappings, just doing absolutely
26 minimal work to give a working backend.
30 #include "system/dir.h"
31 #include "system/filesys.h"
33 #include "system/time.h"
34 #include "dlinklist.h"
35 #include "ntvfs/ntvfs.h"
36 #include "ntvfs/simple/proto.h"
42 #define CHECK_READ_ONLY(req) do { if (lp_readonly(ntvfs->ctx->config.snum)) return NT_STATUS_ACCESS_DENIED; } while (0)
45 connect to a share - used when a tree_connect operation comes
46 in. For a disk based backend we needs to ensure that the base
47 directory exists (tho it doesn't need to be accessible by the user,
50 static NTSTATUS
svfs_connect(struct ntvfs_module_context
*ntvfs
,
51 struct ntvfs_request
*req
, const char *sharename
)
54 struct svfs_private
*private;
55 int snum
= ntvfs
->ctx
->config
.snum
;
57 private = talloc(ntvfs
, struct svfs_private
);
59 private->next_search_handle
= 0;
60 private->connectpath
= talloc_strdup(private, lp_pathname(snum
));
61 private->open_files
= NULL
;
62 private->search
= NULL
;
64 /* the directory must exist */
65 if (stat(private->connectpath
, &st
) != 0 || !S_ISDIR(st
.st_mode
)) {
66 DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n",
67 private->connectpath
, sharename
));
68 return NT_STATUS_BAD_NETWORK_NAME
;
71 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
72 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->fs_type
);
73 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
74 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->dev_type
);
76 ntvfs
->private_data
= private;
78 DEBUG(0,("WARNING: ntvfs simple: connect to share [%s] with ROOT privileges!!!\n",sharename
));
84 disconnect from a share
86 static NTSTATUS
svfs_disconnect(struct ntvfs_module_context
*ntvfs
)
92 find open file handle given fd
94 static struct svfs_file
*find_fd(struct svfs_private
*private, int fd
)
97 for (f
=private->open_files
;f
;f
=f
->next
) {
106 delete a file - the dirtype specifies the file types to include in the search.
107 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
109 static NTSTATUS
svfs_unlink(struct ntvfs_module_context
*ntvfs
,
110 struct ntvfs_request
*req
,
111 union smb_unlink
*unl
)
115 CHECK_READ_ONLY(req
);
117 unix_path
= svfs_unix_path(ntvfs
, req
, unl
->unlink
.in
.pattern
);
119 /* ignoring wildcards ... */
120 if (unlink(unix_path
) == -1) {
121 return map_nt_error_from_unix(errno
);
129 ioctl interface - we don't do any
131 static NTSTATUS
svfs_ioctl(struct ntvfs_module_context
*ntvfs
,
132 struct ntvfs_request
*req
, union smb_ioctl
*io
)
134 return NT_STATUS_INVALID_PARAMETER
;
138 check if a directory exists
140 static NTSTATUS
svfs_chkpath(struct ntvfs_module_context
*ntvfs
,
141 struct ntvfs_request
*req
,
142 union smb_chkpath
*cp
)
147 unix_path
= svfs_unix_path(ntvfs
, req
, cp
->chkpath
.in
.path
);
149 if (stat(unix_path
, &st
) == -1) {
150 return map_nt_error_from_unix(errno
);
153 if (!S_ISDIR(st
.st_mode
)) {
154 return NT_STATUS_NOT_A_DIRECTORY
;
161 build a file_id from a stat struct
163 static uint64_t svfs_file_id(struct stat
*st
)
165 uint64_t ret
= st
->st_ino
;
172 approximately map a struct stat to a generic fileinfo struct
174 static NTSTATUS
svfs_map_fileinfo(struct ntvfs_module_context
*ntvfs
,
175 struct ntvfs_request
*req
, union smb_fileinfo
*info
,
176 struct stat
*st
, const char *unix_path
)
178 struct svfs_dir
*dir
= NULL
;
179 char *pattern
= NULL
;
181 const char *s
, *short_name
;
183 s
= strrchr(unix_path
, '/');
190 asprintf(&pattern
, "%s:*", unix_path
);
193 dir
= svfs_list_unix(req
, req
, pattern
);
196 unix_to_nt_time(&info
->generic
.out
.create_time
, st
->st_ctime
);
197 unix_to_nt_time(&info
->generic
.out
.access_time
, st
->st_atime
);
198 unix_to_nt_time(&info
->generic
.out
.write_time
, st
->st_mtime
);
199 unix_to_nt_time(&info
->generic
.out
.change_time
, st
->st_mtime
);
200 info
->generic
.out
.alloc_size
= st
->st_size
;
201 info
->generic
.out
.size
= st
->st_size
;
202 info
->generic
.out
.attrib
= svfs_unix_to_dos_attrib(st
->st_mode
);
203 info
->generic
.out
.alloc_size
= st
->st_blksize
* st
->st_blocks
;
204 info
->generic
.out
.nlink
= st
->st_nlink
;
205 info
->generic
.out
.directory
= S_ISDIR(st
->st_mode
) ? 1 : 0;
206 info
->generic
.out
.file_id
= svfs_file_id(st
);
207 /* REWRITE: TODO stuff in here */
208 info
->generic
.out
.delete_pending
= 0;
209 info
->generic
.out
.ea_size
= 0;
210 info
->generic
.out
.num_eas
= 0;
211 info
->generic
.out
.fname
.s
= talloc_strdup(req
, short_name
);
212 info
->generic
.out
.alt_fname
.s
= talloc_strdup(req
, short_name
);
213 info
->generic
.out
.compressed_size
= 0;
214 info
->generic
.out
.format
= 0;
215 info
->generic
.out
.unit_shift
= 0;
216 info
->generic
.out
.chunk_shift
= 0;
217 info
->generic
.out
.cluster_shift
= 0;
219 info
->generic
.out
.access_flags
= 0;
220 info
->generic
.out
.position
= 0;
221 info
->generic
.out
.mode
= 0;
222 info
->generic
.out
.alignment_requirement
= 0;
223 info
->generic
.out
.reparse_tag
= 0;
224 info
->generic
.out
.num_streams
= 0;
225 /* setup a single data stream */
226 info
->generic
.out
.num_streams
= 1 + (dir
?dir
->count
:0);
227 info
->generic
.out
.streams
= talloc_array(req
,
228 struct stream_struct
,
229 info
->generic
.out
.num_streams
);
230 if (!info
->generic
.out
.streams
) {
231 return NT_STATUS_NO_MEMORY
;
233 info
->generic
.out
.streams
[0].size
= st
->st_size
;
234 info
->generic
.out
.streams
[0].alloc_size
= st
->st_size
;
235 info
->generic
.out
.streams
[0].stream_name
.s
= talloc_strdup(req
,"::$DATA");
237 for (i
=0;dir
&& i
<dir
->count
;i
++) {
238 s
= strchr(dir
->files
[i
].name
, ':');
239 info
->generic
.out
.streams
[1+i
].size
= dir
->files
[i
].st
.st_size
;
240 info
->generic
.out
.streams
[1+i
].alloc_size
= dir
->files
[i
].st
.st_size
;
241 info
->generic
.out
.streams
[1+i
].stream_name
.s
= s
?s
:dir
->files
[i
].name
;
248 return info on a pathname
250 static NTSTATUS
svfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
251 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
256 DEBUG(19,("svfs_qpathinfo: file %s level 0x%x\n", info
->generic
.in
.file
.path
, info
->generic
.level
));
257 if (info
->generic
.level
!= RAW_FILEINFO_GENERIC
) {
258 return ntvfs_map_qpathinfo(ntvfs
, req
, info
);
261 unix_path
= svfs_unix_path(ntvfs
, req
, info
->generic
.in
.file
.path
);
262 DEBUG(19,("svfs_qpathinfo: file %s\n", unix_path
));
263 if (stat(unix_path
, &st
) == -1) {
264 DEBUG(19,("svfs_qpathinfo: file %s errno=%d\n", unix_path
, errno
));
265 return map_nt_error_from_unix(errno
);
267 DEBUG(19,("svfs_qpathinfo: file %s, stat done\n", unix_path
));
268 return svfs_map_fileinfo(ntvfs
, req
, info
, &st
, unix_path
);
272 query info on a open file
274 static NTSTATUS
svfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
275 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
277 struct svfs_private
*private = ntvfs
->private_data
;
281 if (info
->generic
.level
!= RAW_FILEINFO_GENERIC
) {
282 return ntvfs_map_qfileinfo(ntvfs
, req
, info
);
285 f
= find_fd(private, info
->generic
.in
.file
.fnum
);
287 return NT_STATUS_INVALID_HANDLE
;
290 if (fstat(info
->generic
.in
.file
.fnum
, &st
) == -1) {
291 return map_nt_error_from_unix(errno
);
294 return svfs_map_fileinfo(ntvfs
, req
,info
, &st
, f
->name
);
301 static NTSTATUS
svfs_open(struct ntvfs_module_context
*ntvfs
,
302 struct ntvfs_request
*req
, union smb_open
*io
)
304 struct svfs_private
*private = ntvfs
->private_data
;
309 int create_flags
, rdwr_flags
;
312 if (io
->generic
.level
!= RAW_OPEN_GENERIC
) {
313 return ntvfs_map_open(ntvfs
, req
, io
);
316 readonly
= lp_readonly(ntvfs
->ctx
->config
.snum
);
319 rdwr_flags
= O_RDONLY
;
321 create_flags
= O_CREAT
;
325 unix_path
= svfs_unix_path(ntvfs
, req
, io
->ntcreatex
.in
.fname
);
327 switch (io
->generic
.in
.open_disposition
) {
328 case NTCREATEX_DISP_SUPERSEDE
:
329 case NTCREATEX_DISP_OVERWRITE_IF
:
330 flags
= create_flags
| O_TRUNC
;
332 case NTCREATEX_DISP_OPEN
:
333 case NTCREATEX_DISP_OVERWRITE
:
336 case NTCREATEX_DISP_CREATE
:
337 flags
= create_flags
| O_EXCL
;
339 case NTCREATEX_DISP_OPEN_IF
:
340 flags
= create_flags
;
349 if (io
->generic
.in
.create_options
& NTCREATEX_OPTIONS_DIRECTORY
) {
350 flags
= O_RDONLY
| O_DIRECTORY
;
354 switch (io
->generic
.in
.open_disposition
) {
355 case NTCREATEX_DISP_CREATE
:
356 if (mkdir(unix_path
, 0755) == -1) {
357 DEBUG(9,("svfs_open: mkdir %s errno=%d\n", unix_path
, errno
));
358 return map_nt_error_from_unix(errno
);
361 case NTCREATEX_DISP_OPEN_IF
:
362 if (mkdir(unix_path
, 0755) == -1 && errno
!= EEXIST
) {
363 DEBUG(9,("svfs_open: mkdir %s errno=%d\n", unix_path
, errno
));
364 return map_nt_error_from_unix(errno
);
371 fd
= open(unix_path
, flags
, 0644);
373 return map_nt_error_from_unix(errno
);
376 if (fstat(fd
, &st
) == -1) {
377 DEBUG(9,("svfs_open: fstat errno=%d\n", errno
));
379 return map_nt_error_from_unix(errno
);
382 f
= talloc(ntvfs
, struct svfs_file
);
383 NT_STATUS_HAVE_NO_MEMORY(f
);
385 f
->name
= talloc_strdup(f
, unix_path
);
386 NT_STATUS_HAVE_NO_MEMORY(f
->name
);
388 DLIST_ADD(private->open_files
, f
);
390 ZERO_STRUCT(io
->generic
.out
);
392 unix_to_nt_time(&io
->generic
.out
.create_time
, st
.st_ctime
);
393 unix_to_nt_time(&io
->generic
.out
.access_time
, st
.st_atime
);
394 unix_to_nt_time(&io
->generic
.out
.write_time
, st
.st_mtime
);
395 unix_to_nt_time(&io
->generic
.out
.change_time
, st
.st_mtime
);
396 io
->generic
.out
.file
.fnum
= fd
;
397 io
->generic
.out
.alloc_size
= st
.st_size
;
398 io
->generic
.out
.size
= st
.st_size
;
399 io
->generic
.out
.attrib
= svfs_unix_to_dos_attrib(st
.st_mode
);
400 io
->generic
.out
.is_directory
= S_ISDIR(st
.st_mode
) ? 1 : 0;
408 static NTSTATUS
svfs_mkdir(struct ntvfs_module_context
*ntvfs
,
409 struct ntvfs_request
*req
, union smb_mkdir
*md
)
413 CHECK_READ_ONLY(req
);
415 if (md
->generic
.level
!= RAW_MKDIR_MKDIR
) {
416 return NT_STATUS_INVALID_LEVEL
;
419 unix_path
= svfs_unix_path(ntvfs
, req
, md
->mkdir
.in
.path
);
421 if (mkdir(unix_path
, 0777) == -1) {
422 return map_nt_error_from_unix(errno
);
431 static NTSTATUS
svfs_rmdir(struct ntvfs_module_context
*ntvfs
,
432 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
436 CHECK_READ_ONLY(req
);
438 unix_path
= svfs_unix_path(ntvfs
, req
, rd
->in
.path
);
440 if (rmdir(unix_path
) == -1) {
441 return map_nt_error_from_unix(errno
);
448 rename a set of files
450 static NTSTATUS
svfs_rename(struct ntvfs_module_context
*ntvfs
,
451 struct ntvfs_request
*req
, union smb_rename
*ren
)
453 char *unix_path1
, *unix_path2
;
455 CHECK_READ_ONLY(req
);
457 if (ren
->generic
.level
!= RAW_RENAME_RENAME
) {
458 return NT_STATUS_INVALID_LEVEL
;
461 unix_path1
= svfs_unix_path(ntvfs
, req
, ren
->rename
.in
.pattern1
);
462 unix_path2
= svfs_unix_path(ntvfs
, req
, ren
->rename
.in
.pattern2
);
464 if (rename(unix_path1
, unix_path2
) == -1) {
465 return map_nt_error_from_unix(errno
);
474 static NTSTATUS
svfs_copy(struct ntvfs_module_context
*ntvfs
,
475 struct ntvfs_request
*req
, struct smb_copy
*cp
)
477 return NT_STATUS_NOT_SUPPORTED
;
483 static NTSTATUS
svfs_read(struct ntvfs_module_context
*ntvfs
,
484 struct ntvfs_request
*req
, union smb_read
*rd
)
488 if (rd
->generic
.level
!= RAW_READ_READX
) {
489 return NT_STATUS_NOT_SUPPORTED
;
492 ret
= pread(rd
->readx
.in
.file
.fnum
,
495 rd
->readx
.in
.offset
);
497 return map_nt_error_from_unix(errno
);
500 rd
->readx
.out
.nread
= ret
;
501 rd
->readx
.out
.remaining
= 0; /* should fill this in? */
502 rd
->readx
.out
.compaction_mode
= 0;
510 static NTSTATUS
svfs_write(struct ntvfs_module_context
*ntvfs
,
511 struct ntvfs_request
*req
, union smb_write
*wr
)
515 if (wr
->generic
.level
!= RAW_WRITE_WRITEX
) {
516 return ntvfs_map_write(ntvfs
, req
, wr
);
519 CHECK_READ_ONLY(req
);
521 ret
= pwrite(wr
->writex
.in
.file
.fnum
,
524 wr
->writex
.in
.offset
);
526 return map_nt_error_from_unix(errno
);
529 wr
->writex
.out
.nwritten
= ret
;
530 wr
->writex
.out
.remaining
= 0; /* should fill this in? */
538 static NTSTATUS
svfs_seek(struct ntvfs_module_context
*ntvfs
,
539 struct ntvfs_request
*req
,
542 return NT_STATUS_NOT_SUPPORTED
;
548 static NTSTATUS
svfs_flush(struct ntvfs_module_context
*ntvfs
,
549 struct ntvfs_request
*req
,
552 fsync(io
->flush
.in
.file
.fnum
);
559 static NTSTATUS
svfs_close(struct ntvfs_module_context
*ntvfs
,
560 struct ntvfs_request
*req
,
563 struct svfs_private
*private = ntvfs
->private_data
;
566 if (io
->generic
.level
!= RAW_CLOSE_CLOSE
) {
567 /* we need a mapping function */
568 return NT_STATUS_INVALID_LEVEL
;
571 f
= find_fd(private, io
->close
.in
.file
.fnum
);
573 return NT_STATUS_INVALID_HANDLE
;
576 if (close(io
->close
.in
.file
.fnum
) == -1) {
577 return map_nt_error_from_unix(errno
);
580 DLIST_REMOVE(private->open_files
, f
);
581 talloc_free(f
->name
);
590 static NTSTATUS
svfs_exit(struct ntvfs_module_context
*ntvfs
,
591 struct ntvfs_request
*req
)
593 return NT_STATUS_NOT_SUPPORTED
;
597 logoff - closing files
599 static NTSTATUS
svfs_logoff(struct ntvfs_module_context
*ntvfs
,
600 struct ntvfs_request
*req
)
602 return NT_STATUS_NOT_SUPPORTED
;
606 setup for an async call
608 static NTSTATUS
svfs_async_setup(struct ntvfs_module_context
*ntvfs
,
609 struct ntvfs_request
*req
,
618 static NTSTATUS
svfs_cancel(struct ntvfs_module_context
*ntvfs
, struct ntvfs_request
*req
)
620 return NT_STATUS_UNSUCCESSFUL
;
626 static NTSTATUS
svfs_lock(struct ntvfs_module_context
*ntvfs
,
627 struct ntvfs_request
*req
, union smb_lock
*lck
)
629 DEBUG(0,("REWRITE: not doing byte range locking!\n"));
634 set info on a pathname
636 static NTSTATUS
svfs_setpathinfo(struct ntvfs_module_context
*ntvfs
,
637 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
639 CHECK_READ_ONLY(req
);
641 return NT_STATUS_NOT_SUPPORTED
;
645 set info on a open file
647 static NTSTATUS
svfs_setfileinfo(struct ntvfs_module_context
*ntvfs
,
648 struct ntvfs_request
*req
,
649 union smb_setfileinfo
*info
)
651 struct utimbuf unix_times
;
654 CHECK_READ_ONLY(req
);
656 switch (info
->generic
.level
) {
657 case RAW_SFILEINFO_END_OF_FILE_INFO
:
658 case RAW_SFILEINFO_END_OF_FILE_INFORMATION
:
659 if (ftruncate(info
->end_of_file_info
.in
.file
.fnum
,
660 info
->end_of_file_info
.in
.size
) == -1) {
661 return map_nt_error_from_unix(errno
);
664 case RAW_SFILEINFO_SETATTRE
:
665 unix_times
.actime
= info
->setattre
.in
.access_time
;
666 unix_times
.modtime
= info
->setattre
.in
.write_time
;
667 fd
= info
->setattre
.in
.file
.fnum
;
669 if (unix_times
.actime
== 0 && unix_times
.modtime
== 0) {
673 /* set modify time = to access time if modify time was 0 */
674 if (unix_times
.actime
!= 0 && unix_times
.modtime
== 0) {
675 unix_times
.modtime
= unix_times
.actime
;
678 /* Set the date on this file */
679 if (svfs_file_utime(fd
, &unix_times
) != 0) {
680 return NT_STATUS_ACCESS_DENIED
;
684 DEBUG(2,("svfs_setfileinfo: level %d not implemented\n",
685 info
->generic
.level
));
686 return NT_STATUS_NOT_IMPLEMENTED
;
693 return filesystem space info
695 static NTSTATUS
svfs_fsinfo(struct ntvfs_module_context
*ntvfs
,
696 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
698 struct svfs_private
*private = ntvfs
->private_data
;
701 if (fs
->generic
.level
!= RAW_QFS_GENERIC
) {
702 return ntvfs_map_fsinfo(ntvfs
, req
, fs
);
705 if (sys_fsusage(private->connectpath
,
706 &fs
->generic
.out
.blocks_free
,
707 &fs
->generic
.out
.blocks_total
) == -1) {
708 return map_nt_error_from_unix(errno
);
711 fs
->generic
.out
.block_size
= 512;
713 if (stat(private->connectpath
, &st
) != 0) {
714 return NT_STATUS_DISK_CORRUPT_ERROR
;
717 fs
->generic
.out
.fs_id
= st
.st_ino
;
718 unix_to_nt_time(&fs
->generic
.out
.create_time
, st
.st_ctime
);
719 fs
->generic
.out
.serial_number
= st
.st_ino
;
720 fs
->generic
.out
.fs_attr
= 0;
721 fs
->generic
.out
.max_file_component_length
= 255;
722 fs
->generic
.out
.device_type
= 0;
723 fs
->generic
.out
.device_characteristics
= 0;
724 fs
->generic
.out
.quota_soft
= 0;
725 fs
->generic
.out
.quota_hard
= 0;
726 fs
->generic
.out
.quota_flags
= 0;
727 fs
->generic
.out
.volume_name
= talloc_strdup(req
, lp_servicename(ntvfs
->ctx
->config
.snum
));
728 fs
->generic
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
735 return filesystem attribute info
737 static NTSTATUS
svfs_fsattr(struct ntvfs_module_context
*ntvfs
,
738 struct ntvfs_request
*req
, union smb_fsattr
*fs
)
741 struct svfs_private
*private = ntvfs
->private_data
;
743 if (fs
->generic
.level
!= RAW_FSATTR_GENERIC
) {
744 return ntvfs_map_fsattr(ntvfs
, req
, fs
);
747 if (stat(private->connectpath
, &st
) == -1) {
748 return map_nt_error_from_unix(errno
);
751 unix_to_nt_time(&fs
->generic
.out
.create_time
, st
.st_ctime
);
752 fs
->generic
.out
.fs_attr
=
753 FILE_CASE_PRESERVED_NAMES
|
754 FILE_CASE_SENSITIVE_SEARCH
|
755 FILE_PERSISTENT_ACLS
;
756 fs
->generic
.out
.max_file_component_length
= 255;
757 fs
->generic
.out
.serial_number
= 1;
758 fs
->generic
.out
.fs_type
= talloc_strdup(req
, "NTFS");
759 fs
->generic
.out
.volume_name
= talloc_strdup(req
,
760 lp_servicename(req
->tcon
->service
));
767 return print queue info
769 static NTSTATUS
svfs_lpq(struct ntvfs_module_context
*ntvfs
,
770 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
772 return NT_STATUS_NOT_SUPPORTED
;
776 list files in a directory matching a wildcard pattern
778 static NTSTATUS
svfs_search_first(struct ntvfs_module_context
*ntvfs
,
779 struct ntvfs_request
*req
, union smb_search_first
*io
,
780 void *search_private
,
781 BOOL (*callback
)(void *, union smb_search_data
*))
783 struct svfs_dir
*dir
;
785 struct svfs_private
*private = ntvfs
->private_data
;
786 struct search_state
*search
;
787 union smb_search_data file
;
790 if (io
->generic
.level
!= RAW_SEARCH_BOTH_DIRECTORY_INFO
) {
791 return NT_STATUS_NOT_SUPPORTED
;
794 search
= talloc_zero(private, struct search_state
);
796 return NT_STATUS_NO_MEMORY
;
799 max_count
= io
->t2ffirst
.in
.max_count
;
801 dir
= svfs_list(ntvfs
, req
, io
->t2ffirst
.in
.pattern
);
803 return NT_STATUS_FOOBAR
;
806 search
->handle
= private->next_search_handle
;
809 if (dir
->count
< max_count
) {
810 max_count
= dir
->count
;
813 for (i
=0; i
< max_count
;i
++) {
815 unix_to_nt_time(&file
.both_directory_info
.create_time
, dir
->files
[i
].st
.st_ctime
);
816 unix_to_nt_time(&file
.both_directory_info
.access_time
, dir
->files
[i
].st
.st_atime
);
817 unix_to_nt_time(&file
.both_directory_info
.write_time
, dir
->files
[i
].st
.st_mtime
);
818 unix_to_nt_time(&file
.both_directory_info
.change_time
, dir
->files
[i
].st
.st_mtime
);
819 file
.both_directory_info
.name
.s
= dir
->files
[i
].name
;
820 file
.both_directory_info
.short_name
.s
= dir
->files
[i
].name
;
821 file
.both_directory_info
.size
= dir
->files
[i
].st
.st_size
;
822 file
.both_directory_info
.attrib
= svfs_unix_to_dos_attrib(dir
->files
[i
].st
.st_mode
);
824 if (!callback(search_private
, &file
)) {
829 search
->current_index
= i
;
831 io
->t2ffirst
.out
.count
= i
;
832 io
->t2ffirst
.out
.handle
= search
->handle
;
833 io
->t2ffirst
.out
.end_of_search
= (i
== dir
->count
) ? 1 : 0;
835 /* work out if we are going to keep the search state */
836 if ((io
->t2ffirst
.in
.flags
& FLAG_TRANS2_FIND_CLOSE
) ||
837 ((io
->t2ffirst
.in
.flags
& FLAG_TRANS2_FIND_CLOSE_IF_END
) && (i
== dir
->count
))) {
840 private->next_search_handle
++;
841 DLIST_ADD(private->search
, search
);
847 /* continue a search */
848 static NTSTATUS
svfs_search_next(struct ntvfs_module_context
*ntvfs
,
849 struct ntvfs_request
*req
, union smb_search_next
*io
,
850 void *search_private
,
851 BOOL (*callback
)(void *, union smb_search_data
*))
853 struct svfs_dir
*dir
;
855 struct svfs_private
*private = ntvfs
->private_data
;
856 struct search_state
*search
;
857 union smb_search_data file
;
860 if (io
->generic
.level
!= RAW_SEARCH_BOTH_DIRECTORY_INFO
) {
861 return NT_STATUS_NOT_SUPPORTED
;
864 for (search
=private->search
; search
; search
= search
->next
) {
865 if (search
->handle
== io
->t2fnext
.in
.handle
) break;
869 /* we didn't find the search handle */
870 return NT_STATUS_FOOBAR
;
875 /* the client might be asking for something other than just continuing
877 if (!(io
->t2fnext
.in
.flags
& FLAG_TRANS2_FIND_CONTINUE
) &&
878 (io
->t2fnext
.in
.flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) &&
879 io
->t2fnext
.in
.last_name
&& *io
->t2fnext
.in
.last_name
) {
880 /* look backwards first */
881 for (i
=search
->current_index
; i
> 0; i
--) {
882 if (strcmp(io
->t2fnext
.in
.last_name
, dir
->files
[i
-1].name
) == 0) {
883 search
->current_index
= i
;
888 /* then look forwards */
889 for (i
=search
->current_index
+1; i
<= dir
->count
; i
++) {
890 if (strcmp(io
->t2fnext
.in
.last_name
, dir
->files
[i
-1].name
) == 0) {
891 search
->current_index
= i
;
898 max_count
= search
->current_index
+ io
->t2fnext
.in
.max_count
;
900 if (max_count
> dir
->count
) {
901 max_count
= dir
->count
;
904 for (i
= search
->current_index
; i
< max_count
;i
++) {
906 unix_to_nt_time(&file
.both_directory_info
.create_time
, dir
->files
[i
].st
.st_ctime
);
907 unix_to_nt_time(&file
.both_directory_info
.access_time
, dir
->files
[i
].st
.st_atime
);
908 unix_to_nt_time(&file
.both_directory_info
.write_time
, dir
->files
[i
].st
.st_mtime
);
909 unix_to_nt_time(&file
.both_directory_info
.change_time
, dir
->files
[i
].st
.st_mtime
);
910 file
.both_directory_info
.name
.s
= dir
->files
[i
].name
;
911 file
.both_directory_info
.short_name
.s
= dir
->files
[i
].name
;
912 file
.both_directory_info
.size
= dir
->files
[i
].st
.st_size
;
913 file
.both_directory_info
.attrib
= svfs_unix_to_dos_attrib(dir
->files
[i
].st
.st_mode
);
915 if (!callback(search_private
, &file
)) {
920 io
->t2fnext
.out
.count
= i
- search
->current_index
;
921 io
->t2fnext
.out
.end_of_search
= (i
== dir
->count
) ? 1 : 0;
923 search
->current_index
= i
;
925 /* work out if we are going to keep the search state */
926 if ((io
->t2fnext
.in
.flags
& FLAG_TRANS2_FIND_CLOSE
) ||
927 ((io
->t2fnext
.in
.flags
& FLAG_TRANS2_FIND_CLOSE_IF_END
) && (i
== dir
->count
))) {
928 DLIST_REMOVE(private->search
, search
);
936 static NTSTATUS
svfs_search_close(struct ntvfs_module_context
*ntvfs
,
937 struct ntvfs_request
*req
, union smb_search_close
*io
)
939 struct svfs_private
*private = ntvfs
->private_data
;
940 struct search_state
*search
;
942 for (search
=private->search
; search
; search
= search
->next
) {
943 if (search
->handle
== io
->findclose
.in
.handle
) break;
947 /* we didn't find the search handle */
948 return NT_STATUS_FOOBAR
;
951 DLIST_REMOVE(private->search
, search
);
957 /* SMBtrans - not used on file shares */
958 static NTSTATUS
svfs_trans(struct ntvfs_module_context
*ntvfs
,
959 struct ntvfs_request
*req
, struct smb_trans2
*trans2
)
961 return NT_STATUS_ACCESS_DENIED
;
966 initialialise the POSIX disk backend, registering ourselves with the ntvfs subsystem
968 NTSTATUS
ntvfs_simple_init(void)
971 struct ntvfs_ops ops
;
972 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
976 /* fill in all the operations */
977 ops
.connect
= svfs_connect
;
978 ops
.disconnect
= svfs_disconnect
;
979 ops
.unlink
= svfs_unlink
;
980 ops
.chkpath
= svfs_chkpath
;
981 ops
.qpathinfo
= svfs_qpathinfo
;
982 ops
.setpathinfo
= svfs_setpathinfo
;
983 ops
.open
= svfs_open
;
984 ops
.mkdir
= svfs_mkdir
;
985 ops
.rmdir
= svfs_rmdir
;
986 ops
.rename
= svfs_rename
;
987 ops
.copy
= svfs_copy
;
988 ops
.ioctl
= svfs_ioctl
;
989 ops
.read
= svfs_read
;
990 ops
.write
= svfs_write
;
991 ops
.seek
= svfs_seek
;
992 ops
.flush
= svfs_flush
;
993 ops
.close
= svfs_close
;
994 ops
.exit
= svfs_exit
;
995 ops
.lock
= svfs_lock
;
996 ops
.setfileinfo
= svfs_setfileinfo
;
997 ops
.qfileinfo
= svfs_qfileinfo
;
998 ops
.fsinfo
= svfs_fsinfo
;
1000 ops
.search_first
= svfs_search_first
;
1001 ops
.search_next
= svfs_search_next
;
1002 ops
.search_close
= svfs_search_close
;
1003 ops
.trans
= svfs_trans
;
1004 ops
.logoff
= svfs_logoff
;
1005 ops
.async_setup
= svfs_async_setup
;
1006 ops
.cancel
= svfs_cancel
;
1008 /* register ourselves with the NTVFS subsystem. We register
1009 under names 'simple'
1012 ops
.type
= NTVFS_DISK
;
1013 ops
.name
= "simple";
1014 ret
= ntvfs_register(&ops
, &vers
);
1016 if (!NT_STATUS_IS_OK(ret
)) {
1017 DEBUG(0,("Failed to register simple backend with name: %s!\n",