swrap: Properly cache the handle also in LIBC_SO case.
[Samba.git] / source3 / libsmb / libsmb_file.c
blob8fb7a2e67eca800763d92fc32a14575d977935df
1 /*
2 Unix SMB/Netbios implementation.
3 SMB client library implementation
4 Copyright (C) Andrew Tridgell 1998
5 Copyright (C) Richard Sharpe 2000, 2002
6 Copyright (C) John Terpstra 2000
7 Copyright (C) Tom Jansen (Ninja ISD) 2002
8 Copyright (C) Derrell Lipman 2003-2008
9 Copyright (C) Jeremy Allison 2007, 2008
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "libsmb/libsmb.h"
27 #include "libsmbclient.h"
28 #include "libsmb_internal.h"
29 #include "../libcli/smb/smbXcli_base.h"
32 * Routine to open() a file ...
35 SMBCFILE *
36 SMBC_open_ctx(SMBCCTX *context,
37 const char *fname,
38 int flags,
39 mode_t mode)
41 char *server = NULL;
42 char *share = NULL;
43 char *user = NULL;
44 char *password = NULL;
45 char *workgroup = NULL;
46 char *path = NULL;
47 char *targetpath = NULL;
48 struct cli_state *targetcli = NULL;
49 SMBCSRV *srv = NULL;
50 SMBCFILE *file = NULL;
51 uint16_t fd;
52 uint16_t port = 0;
53 NTSTATUS status = NT_STATUS_OBJECT_PATH_INVALID;
54 TALLOC_CTX *frame = talloc_stackframe();
56 if (!context || !context->internal->initialized) {
57 errno = EINVAL; /* Best I can think of ... */
58 TALLOC_FREE(frame);
59 return NULL;
62 if (!fname) {
63 errno = EINVAL;
64 TALLOC_FREE(frame);
65 return NULL;
68 if (SMBC_parse_path(frame,
69 context,
70 fname,
71 &workgroup,
72 &server,
73 &port,
74 &share,
75 &path,
76 &user,
77 &password,
78 NULL)) {
79 errno = EINVAL;
80 TALLOC_FREE(frame);
81 return NULL;
84 if (!user || user[0] == (char)0) {
85 user = talloc_strdup(frame, smbc_getUser(context));
86 if (!user) {
87 errno = ENOMEM;
88 TALLOC_FREE(frame);
89 return NULL;
93 srv = SMBC_server(frame, context, True,
94 server, port, share, &workgroup, &user, &password);
95 if (!srv) {
96 if (errno == EPERM) errno = EACCES;
97 TALLOC_FREE(frame);
98 return NULL; /* SMBC_server sets errno */
101 /* Hmmm, the test for a directory is suspect here ... FIXME */
103 if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
104 status = NT_STATUS_OBJECT_PATH_INVALID;
105 } else {
106 file = SMB_MALLOC_P(SMBCFILE);
107 if (!file) {
108 errno = ENOMEM;
109 TALLOC_FREE(frame);
110 return NULL;
113 ZERO_STRUCTP(file);
115 /*d_printf(">>>open: resolving %s\n", path);*/
116 status = cli_resolve_path(
117 frame, "", context->internal->auth_info,
118 srv->cli, path, &targetcli, &targetpath);
119 if (!NT_STATUS_IS_OK(status)) {
120 d_printf("Could not resolve %s\n", path);
121 errno = ENOENT;
122 SAFE_FREE(file);
123 TALLOC_FREE(frame);
124 return NULL;
126 /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/
128 status = cli_open(targetcli, targetpath, flags,
129 context->internal->share_mode, &fd);
130 if (!NT_STATUS_IS_OK(status)) {
132 /* Handle the error ... */
134 SAFE_FREE(file);
135 errno = SMBC_errno(context, targetcli);
136 TALLOC_FREE(frame);
137 return NULL;
140 /* Fill in file struct */
142 file->cli_fd = fd;
143 file->fname = SMB_STRDUP(fname);
144 file->srv = srv;
145 file->offset = 0;
146 file->file = True;
148 DLIST_ADD(context->internal->files, file);
151 * If the file was opened in O_APPEND mode, all write
152 * operations should be appended to the file. To do that,
153 * though, using this protocol, would require a getattrE()
154 * call for each and every write, to determine where the end
155 * of the file is. (There does not appear to be an append flag
156 * in the protocol.) Rather than add all of that overhead of
157 * retrieving the current end-of-file offset prior to each
158 * write operation, we'll assume that most append operations
159 * will continuously write, so we'll just set the offset to
160 * the end of the file now and hope that's adequate.
162 * Note to self: If this proves inadequate, and O_APPEND
163 * should, in some cases, be forced for each write, add a
164 * field in the context options structure, for
165 * "strict_append_mode" which would select between the current
166 * behavior (if FALSE) or issuing a getattrE() prior to each
167 * write and forcing the write to the end of the file (if
168 * TRUE). Adding that capability will likely require adding
169 * an "append" flag into the _SMBCFILE structure to track
170 * whether a file was opened in O_APPEND mode. -- djl
172 if (flags & O_APPEND) {
173 if (SMBC_lseek_ctx(context, file, 0, SEEK_END) < 0) {
174 (void) SMBC_close_ctx(context, file);
175 errno = ENXIO;
176 TALLOC_FREE(frame);
177 return NULL;
181 TALLOC_FREE(frame);
182 return file;
185 /* Check if opendir needed ... */
187 if (!NT_STATUS_IS_OK(status)) {
188 int eno = 0;
190 eno = SMBC_errno(context, srv->cli);
191 file = smbc_getFunctionOpendir(context)(context, fname);
192 if (!file) errno = eno;
193 TALLOC_FREE(frame);
194 return file;
197 errno = EINVAL; /* FIXME, correct errno ? */
198 TALLOC_FREE(frame);
199 return NULL;
203 * Routine to create a file
206 SMBCFILE *
207 SMBC_creat_ctx(SMBCCTX *context,
208 const char *path,
209 mode_t mode)
211 if (!context || !context->internal->initialized) {
212 errno = EINVAL;
213 return NULL;
216 return SMBC_open_ctx(context, path,
217 O_WRONLY | O_CREAT | O_TRUNC, mode);
221 * Routine to read() a file ...
224 ssize_t
225 SMBC_read_ctx(SMBCCTX *context,
226 SMBCFILE *file,
227 void *buf,
228 size_t count)
230 size_t ret;
231 char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
232 char *path = NULL;
233 char *targetpath = NULL;
234 struct cli_state *targetcli = NULL;
235 uint16_t port = 0;
236 TALLOC_CTX *frame = talloc_stackframe();
237 NTSTATUS status;
240 * offset:
242 * Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) --
243 * appears to pass file->offset (which is type off_t) differently than
244 * a local variable of type off_t. Using local variable "offset" in
245 * the call to cli_read() instead of file->offset fixes a problem
246 * retrieving data at an offset greater than 4GB.
248 off_t offset;
250 if (!context || !context->internal->initialized) {
251 errno = EINVAL;
252 TALLOC_FREE(frame);
253 return -1;
256 DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count));
258 if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
259 errno = EBADF;
260 TALLOC_FREE(frame);
261 return -1;
264 offset = file->offset;
266 /* Check that the buffer exists ... */
268 if (buf == NULL) {
269 errno = EINVAL;
270 TALLOC_FREE(frame);
271 return -1;
274 /*d_printf(">>>read: parsing %s\n", file->fname);*/
275 if (SMBC_parse_path(frame,
276 context,
277 file->fname,
278 NULL,
279 &server,
280 &port,
281 &share,
282 &path,
283 &user,
284 &password,
285 NULL)) {
286 errno = EINVAL;
287 TALLOC_FREE(frame);
288 return -1;
291 /*d_printf(">>>read: resolving %s\n", path);*/
292 status = cli_resolve_path(frame, "", context->internal->auth_info,
293 file->srv->cli, path,
294 &targetcli, &targetpath);
295 if (!NT_STATUS_IS_OK(status)) {
296 d_printf("Could not resolve %s\n", path);
297 errno = ENOENT;
298 TALLOC_FREE(frame);
299 return -1;
301 /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
303 status = cli_read(targetcli, file->cli_fd, (char *)buf, offset,
304 count, &ret);
305 if (!NT_STATUS_IS_OK(status)) {
306 errno = SMBC_errno(context, targetcli);
307 TALLOC_FREE(frame);
308 return -1;
311 file->offset += ret;
313 DEBUG(4, (" --> %ld\n", (unsigned long)ret));
315 TALLOC_FREE(frame);
316 return ret; /* Success, ret bytes of data ... */
320 * Routine to write() a file ...
323 ssize_t
324 SMBC_write_ctx(SMBCCTX *context,
325 SMBCFILE *file,
326 const void *buf,
327 size_t count)
329 off_t offset;
330 char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
331 char *path = NULL;
332 char *targetpath = NULL;
333 struct cli_state *targetcli = NULL;
334 uint16_t port = 0;
335 TALLOC_CTX *frame = talloc_stackframe();
336 NTSTATUS status;
338 /* First check all pointers before dereferencing them */
340 if (!context || !context->internal->initialized) {
341 errno = EINVAL;
342 TALLOC_FREE(frame);
343 return -1;
346 if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
347 errno = EBADF;
348 TALLOC_FREE(frame);
349 return -1;
352 /* Check that the buffer exists ... */
354 if (buf == NULL) {
355 errno = EINVAL;
356 TALLOC_FREE(frame);
357 return -1;
360 offset = file->offset; /* See "offset" comment in SMBC_read_ctx() */
362 /*d_printf(">>>write: parsing %s\n", file->fname);*/
363 if (SMBC_parse_path(frame,
364 context,
365 file->fname,
366 NULL,
367 &server,
368 &port,
369 &share,
370 &path,
371 &user,
372 &password,
373 NULL)) {
374 errno = EINVAL;
375 TALLOC_FREE(frame);
376 return -1;
379 /*d_printf(">>>write: resolving %s\n", path);*/
380 status = cli_resolve_path(frame, "", context->internal->auth_info,
381 file->srv->cli, path,
382 &targetcli, &targetpath);
383 if (!NT_STATUS_IS_OK(status)) {
384 d_printf("Could not resolve %s\n", path);
385 errno = ENOENT;
386 TALLOC_FREE(frame);
387 return -1;
389 /*d_printf(">>>write: resolved path as %s\n", targetpath);*/
391 status = cli_writeall(targetcli, file->cli_fd,
392 0, (const uint8_t *)buf, offset, count, NULL);
393 if (!NT_STATUS_IS_OK(status)) {
394 errno = map_errno_from_nt_status(status);
395 TALLOC_FREE(frame);
396 return -1;
399 file->offset += count;
401 TALLOC_FREE(frame);
402 return count; /* Success, 0 bytes of data ... */
406 * Routine to close() a file ...
410 SMBC_close_ctx(SMBCCTX *context,
411 SMBCFILE *file)
413 SMBCSRV *srv;
414 char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
415 char *path = NULL;
416 char *targetpath = NULL;
417 uint16_t port = 0;
418 struct cli_state *targetcli = NULL;
419 TALLOC_CTX *frame = talloc_stackframe();
420 NTSTATUS status;
422 if (!context || !context->internal->initialized) {
423 errno = EINVAL;
424 TALLOC_FREE(frame);
425 return -1;
428 if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
429 errno = EBADF;
430 TALLOC_FREE(frame);
431 return -1;
434 /* IS a dir ... */
435 if (!file->file) {
436 TALLOC_FREE(frame);
437 return smbc_getFunctionClosedir(context)(context, file);
440 /*d_printf(">>>close: parsing %s\n", file->fname);*/
441 if (SMBC_parse_path(frame,
442 context,
443 file->fname,
444 NULL,
445 &server,
446 &port,
447 &share,
448 &path,
449 &user,
450 &password,
451 NULL)) {
452 errno = EINVAL;
453 TALLOC_FREE(frame);
454 return -1;
457 /*d_printf(">>>close: resolving %s\n", path);*/
458 status = cli_resolve_path(frame, "", context->internal->auth_info,
459 file->srv->cli, path,
460 &targetcli, &targetpath);
461 if (!NT_STATUS_IS_OK(status)) {
462 d_printf("Could not resolve %s\n", path);
463 errno = ENOENT;
464 TALLOC_FREE(frame);
465 return -1;
467 /*d_printf(">>>close: resolved path as %s\n", targetpath);*/
469 if (!NT_STATUS_IS_OK(cli_close(targetcli, file->cli_fd))) {
470 DEBUG(3, ("cli_close failed on %s. purging server.\n",
471 file->fname));
472 /* Deallocate slot and remove the server
473 * from the server cache if unused */
474 errno = SMBC_errno(context, targetcli);
475 srv = file->srv;
476 DLIST_REMOVE(context->internal->files, file);
477 SAFE_FREE(file->fname);
478 SAFE_FREE(file);
479 smbc_getFunctionRemoveUnusedServer(context)(context, srv);
480 TALLOC_FREE(frame);
481 return -1;
484 DLIST_REMOVE(context->internal->files, file);
485 SAFE_FREE(file->fname);
486 SAFE_FREE(file);
487 TALLOC_FREE(frame);
488 return 0;
492 * Get info from an SMB server on a file. Use a qpathinfo call first
493 * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
495 bool
496 SMBC_getatr(SMBCCTX * context,
497 SMBCSRV *srv,
498 const char *path,
499 uint16 *mode,
500 off_t *size,
501 struct timespec *create_time_ts,
502 struct timespec *access_time_ts,
503 struct timespec *write_time_ts,
504 struct timespec *change_time_ts,
505 SMB_INO_T *ino)
507 char *fixedpath = NULL;
508 char *targetpath = NULL;
509 struct cli_state *targetcli = NULL;
510 time_t write_time;
511 TALLOC_CTX *frame = talloc_stackframe();
512 NTSTATUS status;
514 if (!context || !context->internal->initialized) {
515 errno = EINVAL;
516 TALLOC_FREE(frame);
517 return False;
520 /* path fixup for . and .. */
521 if (strequal(path, ".") || strequal(path, "..")) {
522 fixedpath = talloc_strdup(frame, "\\");
523 if (!fixedpath) {
524 errno = ENOMEM;
525 TALLOC_FREE(frame);
526 return False;
528 } else {
529 fixedpath = talloc_strdup(frame, path);
530 if (!fixedpath) {
531 errno = ENOMEM;
532 TALLOC_FREE(frame);
533 return False;
535 trim_string(fixedpath, NULL, "\\..");
536 trim_string(fixedpath, NULL, "\\.");
538 DEBUG(4,("SMBC_getatr: sending qpathinfo\n"));
540 status = cli_resolve_path(frame, "", context->internal->auth_info,
541 srv->cli, fixedpath,
542 &targetcli, &targetpath);
543 if (!NT_STATUS_IS_OK(status)) {
544 d_printf("Couldn't resolve %s\n", path);
545 errno = ENOENT;
546 TALLOC_FREE(frame);
547 return False;
550 if (!srv->no_pathinfo2 &&
551 NT_STATUS_IS_OK(cli_qpathinfo2(targetcli, targetpath,
552 create_time_ts,
553 access_time_ts,
554 write_time_ts,
555 change_time_ts,
556 size, mode, ino))) {
557 TALLOC_FREE(frame);
558 return True;
561 srv->no_pathinfo2 = True;
563 if (!srv->no_pathinfo3 &&
564 NT_STATUS_IS_OK(cli_qpathinfo3(targetcli, targetpath,
565 create_time_ts,
566 access_time_ts,
567 write_time_ts,
568 change_time_ts,
569 size, mode, ino))) {
570 TALLOC_FREE(frame);
571 return True;
574 srv->no_pathinfo3 = True;
576 /* if this is NT then don't bother with the getatr */
577 if (smb1cli_conn_capabilities(targetcli->conn) & CAP_NT_SMBS) {
578 goto all_failed;
581 if (NT_STATUS_IS_OK(cli_getatr(targetcli, targetpath, mode, size, &write_time))) {
582 struct timespec w_time_ts;
584 w_time_ts = convert_time_t_to_timespec(write_time);
585 if (write_time_ts != NULL) {
586 *write_time_ts = w_time_ts;
588 if (create_time_ts != NULL) {
589 *create_time_ts = w_time_ts;
591 if (access_time_ts != NULL) {
592 *access_time_ts = w_time_ts;
594 if (change_time_ts != NULL) {
595 *change_time_ts = w_time_ts;
597 if (ino) {
598 *ino = 0;
600 TALLOC_FREE(frame);
601 return True;
604 all_failed:
605 srv->no_pathinfo2 = False;
606 srv->no_pathinfo3 = False;
608 errno = EPERM;
609 TALLOC_FREE(frame);
610 return False;
614 * Set file info on an SMB server. Use setpathinfo call first. If that
615 * fails, use setattrE..
617 * Access and modification time parameters are always used and must be
618 * provided. Create time, if zero, will be determined from the actual create
619 * time of the file. If non-zero, the create time will be set as well.
621 * "mode" (attributes) parameter may be set to -1 if it is not to be set.
623 bool
624 SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
625 time_t create_time,
626 time_t access_time,
627 time_t write_time,
628 time_t change_time,
629 uint16 mode)
631 uint16_t fd;
632 int ret;
633 TALLOC_CTX *frame = talloc_stackframe();
636 * First, try setpathinfo (if qpathinfo succeeded), for it is the
637 * modern function for "new code" to be using, and it works given a
638 * filename rather than requiring that the file be opened to have its
639 * attributes manipulated.
641 if (srv->no_pathinfo ||
642 !NT_STATUS_IS_OK(cli_setpathinfo_basic(srv->cli, path,
643 create_time,
644 access_time,
645 write_time,
646 change_time,
647 mode))) {
650 * setpathinfo is not supported; go to plan B.
652 * cli_setatr() does not work on win98, and it also doesn't
653 * support setting the access time (only the modification
654 * time), so in all cases, we open the specified file and use
655 * cli_setattrE() which should work on all OS versions, and
656 * supports both times.
659 /* Don't try {q,set}pathinfo() again, with this server */
660 srv->no_pathinfo = True;
662 /* Open the file */
663 if (!NT_STATUS_IS_OK(cli_open(srv->cli, path, O_RDWR, DENY_NONE, &fd))) {
664 errno = SMBC_errno(context, srv->cli);
665 TALLOC_FREE(frame);
666 return -1;
669 /* Set the new attributes */
670 ret = NT_STATUS_IS_OK(cli_setattrE(srv->cli, fd,
671 change_time,
672 access_time,
673 write_time));
675 /* Close the file */
676 cli_close(srv->cli, fd);
679 * Unfortunately, setattrE() doesn't have a provision for
680 * setting the access mode (attributes). We'll have to try
681 * cli_setatr() for that, and with only this parameter, it
682 * seems to work on win98.
684 if (ret && mode != (uint16) -1) {
685 ret = NT_STATUS_IS_OK(cli_setatr(srv->cli, path, mode, 0));
688 if (! ret) {
689 errno = SMBC_errno(context, srv->cli);
690 TALLOC_FREE(frame);
691 return False;
695 TALLOC_FREE(frame);
696 return True;
700 * A routine to lseek() a file
703 off_t
704 SMBC_lseek_ctx(SMBCCTX *context,
705 SMBCFILE *file,
706 off_t offset,
707 int whence)
709 off_t size;
710 char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
711 char *path = NULL;
712 char *targetpath = NULL;
713 struct cli_state *targetcli = NULL;
714 uint16_t port = 0;
715 TALLOC_CTX *frame = talloc_stackframe();
716 NTSTATUS status;
718 if (!context || !context->internal->initialized) {
719 errno = EINVAL;
720 TALLOC_FREE(frame);
721 return -1;
724 if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
725 errno = EBADF;
726 TALLOC_FREE(frame);
727 return -1;
730 if (!file->file) {
731 errno = EINVAL;
732 TALLOC_FREE(frame);
733 return -1; /* Can't lseek a dir ... */
736 switch (whence) {
737 case SEEK_SET:
738 file->offset = offset;
739 break;
740 case SEEK_CUR:
741 file->offset += offset;
742 break;
743 case SEEK_END:
744 /*d_printf(">>>lseek: parsing %s\n", file->fname);*/
745 if (SMBC_parse_path(frame,
746 context,
747 file->fname,
748 NULL,
749 &server,
750 &port,
751 &share,
752 &path,
753 &user,
754 &password,
755 NULL)) {
756 errno = EINVAL;
757 TALLOC_FREE(frame);
758 return -1;
761 /*d_printf(">>>lseek: resolving %s\n", path);*/
762 status = cli_resolve_path(
763 frame, "", context->internal->auth_info,
764 file->srv->cli, path, &targetcli, &targetpath);
765 if (!NT_STATUS_IS_OK(status)) {
766 d_printf("Could not resolve %s\n", path);
767 errno = ENOENT;
768 TALLOC_FREE(frame);
769 return -1;
772 /*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/
773 if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(
774 targetcli, file->cli_fd, NULL,
775 &size, NULL, NULL, NULL, NULL,
776 NULL))) {
777 off_t b_size = size;
778 if (!NT_STATUS_IS_OK(cli_getattrE(targetcli, file->cli_fd,
779 NULL, &b_size, NULL, NULL, NULL))) {
780 errno = EINVAL;
781 TALLOC_FREE(frame);
782 return -1;
783 } else
784 size = b_size;
786 file->offset = size + offset;
787 break;
788 default:
789 errno = EINVAL;
790 break;
793 TALLOC_FREE(frame);
794 return file->offset;
799 * Routine to truncate a file given by its file descriptor, to a specified size
803 SMBC_ftruncate_ctx(SMBCCTX *context,
804 SMBCFILE *file,
805 off_t length)
807 off_t size = length;
808 char *server = NULL;
809 char *share = NULL;
810 char *user = NULL;
811 char *password = NULL;
812 char *path = NULL;
813 char *targetpath = NULL;
814 uint16_t port = 0;
815 struct cli_state *targetcli = NULL;
816 TALLOC_CTX *frame = talloc_stackframe();
817 NTSTATUS status;
819 if (!context || !context->internal->initialized) {
820 errno = EINVAL;
821 TALLOC_FREE(frame);
822 return -1;
825 if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
826 errno = EBADF;
827 TALLOC_FREE(frame);
828 return -1;
831 if (!file->file) {
832 errno = EINVAL;
833 TALLOC_FREE(frame);
834 return -1;
837 /*d_printf(">>>fstat: parsing %s\n", file->fname);*/
838 if (SMBC_parse_path(frame,
839 context,
840 file->fname,
841 NULL,
842 &server,
843 &port,
844 &share,
845 &path,
846 &user,
847 &password,
848 NULL)) {
849 errno = EINVAL;
850 TALLOC_FREE(frame);
851 return -1;
854 /*d_printf(">>>fstat: resolving %s\n", path);*/
855 status = cli_resolve_path(frame, "", context->internal->auth_info,
856 file->srv->cli, path,
857 &targetcli, &targetpath);
858 if (!NT_STATUS_IS_OK(status)) {
859 d_printf("Could not resolve %s\n", path);
860 errno = ENOENT;
861 TALLOC_FREE(frame);
862 return -1;
864 /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
866 if (!NT_STATUS_IS_OK(cli_ftruncate(targetcli, file->cli_fd, (uint64_t)size))) {
867 errno = EINVAL;
868 TALLOC_FREE(frame);
869 return -1;
872 TALLOC_FREE(frame);
873 return 0;