Continued revamping of libsmbclient.
[samba.git] / source3 / libsmb / libsmb_file.c
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
10    
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.
15    
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.
20    
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/>.
23 */
24
25 #include "includes.h"
26 #include "libsmbclient.h"
27 #include "libsmb_internal.h"
28
29
30 /*
31  * Routine to open() a file ...
32  */
33
34 SMBCFILE *
35 SMBC_open_ctx(SMBCCTX *context,
36               const char *fname,
37               int flags,
38               mode_t mode)
39 {
40         char *server = NULL;
41         char *share = NULL;
42         char *user = NULL;
43         char *password = NULL;
44         char *workgroup = NULL;
45         char *path = NULL;
46         char *targetpath = NULL;
47         struct cli_state *targetcli = NULL;
48         SMBCSRV *srv   = NULL;
49         SMBCFILE *file = NULL;
50         int fd;
51         TALLOC_CTX *frame = talloc_stackframe();
52         
53         if (!context || !context->internal->initialized) {
54                 
55                 errno = EINVAL;  /* Best I can think of ... */
56                 TALLOC_FREE(frame);
57                 return NULL;
58                 
59         }
60         
61         if (!fname) {
62                 
63                 errno = EINVAL;
64                 TALLOC_FREE(frame);
65                 return NULL;
66                 
67         }
68         
69         if (SMBC_parse_path(frame,
70                             context,
71                             fname,
72                             &workgroup,
73                             &server,
74                             &share,
75                             &path,
76                             &user,
77                             &password,
78                             NULL)) {
79                 errno = EINVAL;
80                 TALLOC_FREE(frame);
81                 return NULL;
82         }
83         
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;
90                 }
91         }
92         
93         srv = SMBC_server(frame, context, True,
94                           server, share, &workgroup, &user, &password);
95         
96         if (!srv) {
97                 if (errno == EPERM) errno = EACCES;
98                 TALLOC_FREE(frame);
99                 return NULL;  /* SMBC_server sets errno */
100         }
101         
102         /* Hmmm, the test for a directory is suspect here ... FIXME */
103         
104         if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
105                 fd = -1;
106         } else {
107                 file = SMB_MALLOC_P(SMBCFILE);
108                 
109                 if (!file) {
110                         errno = ENOMEM;
111                         TALLOC_FREE(frame);
112                         return NULL;
113                 }
114                 
115                 ZERO_STRUCTP(file);
116                 
117                 /*d_printf(">>>open: resolving %s\n", path);*/
118                 if (!cli_resolve_path(frame, "", srv->cli, path,
119                                       &targetcli, &targetpath)) {
120                         d_printf("Could not resolve %s\n", path);
121                         SAFE_FREE(file);
122                         TALLOC_FREE(frame);
123                         return NULL;
124                 }
125                 /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/
126                 
127                 if ((fd = cli_open(targetcli, targetpath, flags,
128                                    context->internal->share_mode)) < 0) {
129                         
130                         /* Handle the error ... */
131                         
132                         SAFE_FREE(file);
133                         errno = SMBC_errno(context, targetcli);
134                         TALLOC_FREE(frame);
135                         return NULL;
136                         
137                 }
138                 
139                 /* Fill in file struct */
140                 
141                 file->cli_fd  = fd;
142                 file->fname   = SMB_STRDUP(fname);
143                 file->srv     = srv;
144                 file->offset  = 0;
145                 file->file    = True;
146                 
147                 DLIST_ADD(context->internal->files, file);
148                 
149                 /*
150                  * If the file was opened in O_APPEND mode, all write
151                  * operations should be appended to the file.  To do that,
152                  * though, using this protocol, would require a getattrE()
153                  * call for each and every write, to determine where the end
154                  * of the file is. (There does not appear to be an append flag
155                  * in the protocol.)  Rather than add all of that overhead of
156                  * retrieving the current end-of-file offset prior to each
157                  * write operation, we'll assume that most append operations
158                  * will continuously write, so we'll just set the offset to
159                  * the end of the file now and hope that's adequate.
160                  *
161                  * Note to self: If this proves inadequate, and O_APPEND
162                  * should, in some cases, be forced for each write, add a
163                  * field in the context options structure, for
164                  * "strict_append_mode" which would select between the current
165                  * behavior (if FALSE) or issuing a getattrE() prior to each
166                  * write and forcing the write to the end of the file (if
167                  * TRUE).  Adding that capability will likely require adding
168                  * an "append" flag into the _SMBCFILE structure to track
169                  * whether a file was opened in O_APPEND mode.  -- djl
170                  */
171                 if (flags & O_APPEND) {
172                         if (SMBC_lseek_ctx(context, file, 0, SEEK_END) < 0) {
173                                 (void) SMBC_close_ctx(context, file);
174                                 errno = ENXIO;
175                                 TALLOC_FREE(frame);
176                                 return NULL;
177                         }
178                 }
179                 
180                 TALLOC_FREE(frame);
181                 return file;
182                 
183         }
184         
185         /* Check if opendir needed ... */
186         
187         if (fd == -1) {
188                 int eno = 0;
189                 
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;
195                 
196         }
197         
198         errno = EINVAL; /* FIXME, correct errno ? */
199         TALLOC_FREE(frame);
200         return NULL;
201         
202 }
203
204 /*
205  * Routine to create a file 
206  */
207
208 SMBCFILE *
209 SMBC_creat_ctx(SMBCCTX *context,
210                const char *path,
211                mode_t mode)
212 {
213         
214         if (!context || !context->internal->initialized) {
215                 
216                 errno = EINVAL;
217                 return NULL;
218                 
219         }
220         
221         return SMBC_open_ctx(context, path,
222                              O_WRONLY | O_CREAT | O_TRUNC, mode);
223 }
224
225 /*
226  * Routine to read() a file ...
227  */
228
229 ssize_t
230 SMBC_read_ctx(SMBCCTX *context,
231               SMBCFILE *file,
232               void *buf,
233               size_t count)
234 {
235         int ret;
236         char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
237         char *path = NULL;
238         char *targetpath = NULL;
239         struct cli_state *targetcli = NULL;
240         TALLOC_CTX *frame = talloc_stackframe();
241         
242         /*
243          * offset:
244          *
245          * Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) --
246          * appears to pass file->offset (which is type off_t) differently than
247          * a local variable of type off_t.  Using local variable "offset" in
248          * the call to cli_read() instead of file->offset fixes a problem
249          * retrieving data at an offset greater than 4GB.
250          */
251         off_t offset;
252         
253         if (!context || !context->internal->initialized) {
254                 
255                 errno = EINVAL;
256                 TALLOC_FREE(frame);
257                 return -1;
258                 
259         }
260         
261         DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count));
262         
263         if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
264                 errno = EBADF;
265                 TALLOC_FREE(frame);
266                 return -1;
267                 
268         }
269         
270         offset = file->offset;
271         
272         /* Check that the buffer exists ... */
273         
274         if (buf == NULL) {
275                 errno = EINVAL;
276                 TALLOC_FREE(frame);
277                 return -1;
278                 
279         }
280         
281         /*d_printf(">>>read: parsing %s\n", file->fname);*/
282         if (SMBC_parse_path(frame,
283                             context,
284                             file->fname,
285                             NULL,
286                             &server,
287                             &share,
288                             &path,
289                             &user,
290                             &password,
291                             NULL)) {
292                 errno = EINVAL;
293                 TALLOC_FREE(frame);
294                 return -1;
295         }
296         
297         /*d_printf(">>>read: resolving %s\n", path);*/
298         if (!cli_resolve_path(frame, "", file->srv->cli, path,
299                               &targetcli, &targetpath)) {
300                 d_printf("Could not resolve %s\n", path);
301                 TALLOC_FREE(frame);
302                 return -1;
303         }
304         /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
305         
306         ret = cli_read(targetcli, file->cli_fd, (char *)buf, offset, count);
307         
308         if (ret < 0) {
309                 
310                 errno = SMBC_errno(context, targetcli);
311                 TALLOC_FREE(frame);
312                 return -1;
313                 
314         }
315         
316         file->offset += ret;
317         
318         DEBUG(4, ("  --> %d\n", ret));
319         
320         TALLOC_FREE(frame);
321         return ret;  /* Success, ret bytes of data ... */
322         
323 }
324
325 /*
326  * Routine to write() a file ...
327  */
328
329 ssize_t
330 SMBC_write_ctx(SMBCCTX *context,
331                SMBCFILE *file,
332                void *buf,
333                size_t count)
334 {
335         int ret;
336         off_t offset;
337         char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
338         char *path = NULL;
339         char *targetpath = NULL;
340         struct cli_state *targetcli = NULL;
341         TALLOC_CTX *frame = talloc_stackframe();
342         
343         /* First check all pointers before dereferencing them */
344         
345         if (!context || !context->internal->initialized) {
346                 
347                 errno = EINVAL;
348                 TALLOC_FREE(frame);
349                 return -1;
350                 
351         }
352         
353         if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
354                 errno = EBADF;
355                 TALLOC_FREE(frame);
356                 return -1;
357         }
358         
359         /* Check that the buffer exists ... */
360         
361         if (buf == NULL) {
362                 errno = EINVAL;
363                 TALLOC_FREE(frame);
364                 return -1;
365                 
366         }
367         
368         offset = file->offset; /* See "offset" comment in SMBC_read_ctx() */
369         
370         /*d_printf(">>>write: parsing %s\n", file->fname);*/
371         if (SMBC_parse_path(frame,
372                             context,
373                             file->fname,
374                             NULL,
375                             &server,
376                             &share,
377                             &path,
378                             &user,
379                             &password,
380                             NULL)) {
381                 errno = EINVAL;
382                 TALLOC_FREE(frame);
383                 return -1;
384         }
385         
386         /*d_printf(">>>write: resolving %s\n", path);*/
387         if (!cli_resolve_path(frame, "", file->srv->cli, path,
388                               &targetcli, &targetpath)) {
389                 d_printf("Could not resolve %s\n", path);
390                 TALLOC_FREE(frame);
391                 return -1;
392         }
393         /*d_printf(">>>write: resolved path as %s\n", targetpath);*/
394         
395         ret = cli_write(targetcli, file->cli_fd,
396                         0, (char *)buf, offset, count);
397         
398         if (ret <= 0) {
399                 errno = SMBC_errno(context, targetcli);
400                 TALLOC_FREE(frame);
401                 return -1;
402                 
403         }
404         
405         file->offset += ret;
406         
407         TALLOC_FREE(frame);
408         return ret;  /* Success, 0 bytes of data ... */
409 }
410
411 /*
412  * Routine to close() a file ...
413  */
414
415 int
416 SMBC_close_ctx(SMBCCTX *context,
417                SMBCFILE *file)
418 {
419         SMBCSRV *srv;
420         char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
421         char *path = NULL;
422         char *targetpath = NULL;
423         struct cli_state *targetcli = NULL;
424         TALLOC_CTX *frame = talloc_stackframe();
425         
426         if (!context || !context->internal->initialized) {
427                 
428                 errno = EINVAL;
429                 TALLOC_FREE(frame);
430                 return -1;
431         }
432         
433         if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
434                 errno = EBADF;
435                 TALLOC_FREE(frame);
436                 return -1;
437         }
438         
439         /* IS a dir ... */
440         if (!file->file) {
441                 TALLOC_FREE(frame);
442                 return smbc_getFunctionClosedir(context)(context, file);
443         }
444         
445         /*d_printf(">>>close: parsing %s\n", file->fname);*/
446         if (SMBC_parse_path(frame,
447                             context,
448                             file->fname,
449                             NULL,
450                             &server,
451                             &share,
452                             &path,
453                             &user,
454                             &password,
455                             NULL)) {
456                 errno = EINVAL;
457                 TALLOC_FREE(frame);
458                 return -1;
459         }
460         
461         /*d_printf(">>>close: resolving %s\n", path);*/
462         if (!cli_resolve_path(frame, "", file->srv->cli, path,
463                               &targetcli, &targetpath)) {
464                 d_printf("Could not resolve %s\n", path);
465                 TALLOC_FREE(frame);
466                 return -1;
467         }
468         /*d_printf(">>>close: resolved path as %s\n", targetpath);*/
469         
470         if (!cli_close(targetcli, file->cli_fd)) {
471                 
472                 DEBUG(3, ("cli_close failed on %s. purging server.\n", 
473                           file->fname));
474                 /* Deallocate slot and remove the server 
475                  * from the server cache if unused */
476                 errno = SMBC_errno(context, targetcli);
477                 srv = file->srv;
478                 DLIST_REMOVE(context->internal->files, file);
479                 SAFE_FREE(file->fname);
480                 SAFE_FREE(file);
481                 smbc_getFunctionRemoveUnusedServer(context)(context, srv);
482                 TALLOC_FREE(frame);
483                 return -1;
484                 
485         }
486         
487         DLIST_REMOVE(context->internal->files, file);
488         SAFE_FREE(file->fname);
489         SAFE_FREE(file);
490         TALLOC_FREE(frame);
491         
492         return 0;
493 }
494
495 /*
496  * Get info from an SMB server on a file. Use a qpathinfo call first
497  * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
498  */
499 bool
500 SMBC_getatr(SMBCCTX * context,
501             SMBCSRV *srv,
502             char *path,
503             uint16 *mode,
504             SMB_OFF_T *size,
505             struct timespec *create_time_ts,
506             struct timespec *access_time_ts,
507             struct timespec *write_time_ts,
508             struct timespec *change_time_ts,
509             SMB_INO_T *ino)
510 {
511         char *fixedpath = NULL;
512         char *targetpath = NULL;
513         struct cli_state *targetcli = NULL;
514         time_t write_time;
515         TALLOC_CTX *frame = talloc_stackframe();
516         
517         if (!context || !context->internal->initialized) {
518                 
519                 errno = EINVAL;
520                 TALLOC_FREE(frame);
521                 return -1;
522         }
523         
524         /* path fixup for . and .. */
525         if (strequal(path, ".") || strequal(path, "..")) {
526                 fixedpath = talloc_strdup(frame, "\\");
527                 if (!fixedpath) {
528                         errno = ENOMEM;
529                         TALLOC_FREE(frame);
530                         return -1;
531                 }
532         } else {
533                 fixedpath = talloc_strdup(frame, path);
534                 if (!fixedpath) {
535                         errno = ENOMEM;
536                         TALLOC_FREE(frame);
537                         return -1;
538                 }
539                 trim_string(fixedpath, NULL, "\\..");
540                 trim_string(fixedpath, NULL, "\\.");
541         }
542         DEBUG(4,("SMBC_getatr: sending qpathinfo\n"));
543         
544         if (!cli_resolve_path(frame, "", srv->cli, fixedpath,
545                               &targetcli, &targetpath)) {
546                 d_printf("Couldn't resolve %s\n", path);
547                 TALLOC_FREE(frame);
548                 return False;
549         }
550         
551         if (!srv->no_pathinfo2 &&
552             cli_qpathinfo2(targetcli, targetpath,
553                            create_time_ts,
554                            access_time_ts,
555                            write_time_ts,
556                            change_time_ts,
557                            size, mode, ino)) {
558                 TALLOC_FREE(frame);
559                 return True;
560         }
561         
562         /* if this is NT then don't bother with the getatr */
563         if (targetcli->capabilities & CAP_NT_SMBS) {
564                 errno = EPERM;
565                 TALLOC_FREE(frame);
566                 return False;
567         }
568         
569         if (cli_getatr(targetcli, targetpath, mode, size, &write_time)) {
570                 
571                 struct timespec w_time_ts;
572                 
573                 w_time_ts = convert_time_t_to_timespec(write_time);
574                 
575                 if (write_time_ts != NULL) {
576                         *write_time_ts = w_time_ts;
577                 }
578                 
579                 if (create_time_ts != NULL) {
580                         *create_time_ts = w_time_ts;
581                 }
582                 
583                 if (access_time_ts != NULL) {
584                         *access_time_ts = w_time_ts;
585                 }
586                 
587                 if (change_time_ts != NULL) {
588                         *change_time_ts = w_time_ts;
589                 }
590                 
591                 srv->no_pathinfo2 = True;
592                 TALLOC_FREE(frame);
593                 return True;
594         }
595         
596         errno = EPERM;
597         TALLOC_FREE(frame);
598         return False;
599         
600 }
601
602 /*
603  * Set file info on an SMB server.  Use setpathinfo call first.  If that
604  * fails, use setattrE..
605  *
606  * Access and modification time parameters are always used and must be
607  * provided.  Create time, if zero, will be determined from the actual create
608  * time of the file.  If non-zero, the create time will be set as well.
609  *
610  * "mode" (attributes) parameter may be set to -1 if it is not to be set.
611  */
612 bool
613 SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, 
614             time_t create_time,
615             time_t access_time,
616             time_t write_time,
617             time_t change_time,
618             uint16 mode)
619 {
620         int fd;
621         int ret;
622         TALLOC_CTX *frame = talloc_stackframe();
623         
624         /*
625          * First, try setpathinfo (if qpathinfo succeeded), for it is the
626          * modern function for "new code" to be using, and it works given a
627          * filename rather than requiring that the file be opened to have its
628          * attributes manipulated.
629          */
630         if (srv->no_pathinfo ||
631             ! cli_setpathinfo(srv->cli, path,
632                               create_time,
633                               access_time,
634                               write_time,
635                               change_time,
636                               mode)) {
637                 
638                 /*
639                  * setpathinfo is not supported; go to plan B. 
640                  *
641                  * cli_setatr() does not work on win98, and it also doesn't
642                  * support setting the access time (only the modification
643                  * time), so in all cases, we open the specified file and use
644                  * cli_setattrE() which should work on all OS versions, and
645                  * supports both times.
646                  */
647                 
648                 /* Don't try {q,set}pathinfo() again, with this server */
649                 srv->no_pathinfo = True;
650                 
651                 /* Open the file */
652                 if ((fd = cli_open(srv->cli, path, O_RDWR, DENY_NONE)) < 0) {
653                         
654                         errno = SMBC_errno(context, srv->cli);
655                         TALLOC_FREE(frame);
656                         return -1;
657                 }
658                 
659                 /* Set the new attributes */
660                 ret = cli_setattrE(srv->cli, fd,
661                                    change_time,
662                                    access_time,
663                                    write_time);
664                 
665                 /* Close the file */
666                 cli_close(srv->cli, fd);
667                 
668                 /*
669                  * Unfortunately, setattrE() doesn't have a provision for
670                  * setting the access mode (attributes).  We'll have to try
671                  * cli_setatr() for that, and with only this parameter, it
672                  * seems to work on win98.
673                  */
674                 if (ret && mode != (uint16) -1) {
675                         ret = cli_setatr(srv->cli, path, mode, 0);
676                 }
677                 
678                 if (! ret) {
679                         errno = SMBC_errno(context, srv->cli);
680                         TALLOC_FREE(frame);
681                         return False;
682                 }
683         }
684         
685         TALLOC_FREE(frame);
686         return True;
687 }
688
689 /*
690  * A routine to lseek() a file
691  */
692
693 off_t
694 SMBC_lseek_ctx(SMBCCTX *context,
695                SMBCFILE *file,
696                off_t offset,
697                int whence)
698 {
699         SMB_OFF_T size;
700         char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
701         char *path = NULL;
702         char *targetpath = NULL;
703         struct cli_state *targetcli = NULL;
704         TALLOC_CTX *frame = talloc_stackframe();
705         
706         if (!context || !context->internal->initialized) {
707                 
708                 errno = EINVAL;
709                 TALLOC_FREE(frame);
710                 return -1;
711         }
712         
713         if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
714                 
715                 errno = EBADF;
716                 TALLOC_FREE(frame);
717                 return -1;
718                 
719         }
720         
721         if (!file->file) {
722                 
723                 errno = EINVAL;
724                 TALLOC_FREE(frame);
725                 return -1;      /* Can't lseek a dir ... */
726                 
727         }
728         
729         switch (whence) {
730         case SEEK_SET:
731                 file->offset = offset;
732                 break;
733                 
734         case SEEK_CUR:
735                 file->offset += offset;
736                 break;
737                 
738         case SEEK_END:
739                 /*d_printf(">>>lseek: parsing %s\n", file->fname);*/
740                 if (SMBC_parse_path(frame,
741                                     context,
742                                     file->fname,
743                                     NULL,
744                                     &server,
745                                     &share,
746                                     &path,
747                                     &user,
748                                     &password,
749                                     NULL)) {
750                         errno = EINVAL;
751                         TALLOC_FREE(frame);
752                         return -1;
753                 }
754                 
755                 /*d_printf(">>>lseek: resolving %s\n", path);*/
756                 if (!cli_resolve_path(frame, "", file->srv->cli, path,
757                                       &targetcli, &targetpath)) {
758                         d_printf("Could not resolve %s\n", path);
759                         TALLOC_FREE(frame);
760                         return -1;
761                 }
762                 /*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/
763                 
764                 if (!cli_qfileinfo(targetcli, file->cli_fd, NULL,
765                                    &size, NULL, NULL, NULL, NULL, NULL))
766                 {
767                         SMB_OFF_T b_size = size;
768                         if (!cli_getattrE(targetcli, file->cli_fd,
769                                           NULL, &b_size, NULL, NULL, NULL))
770                         {
771                                 errno = EINVAL;
772                                 TALLOC_FREE(frame);
773                                 return -1;
774                         } else
775                                 size = b_size;
776                 }
777                 file->offset = size + offset;
778                 break;
779                 
780         default:
781                 errno = EINVAL;
782                 break;
783                 
784         }
785         
786         TALLOC_FREE(frame);
787         return file->offset;
788         
789 }
790
791
792 /*
793  * Routine to truncate a file given by its file descriptor, to a specified size
794  */
795
796 int
797 SMBC_ftruncate_ctx(SMBCCTX *context,
798                    SMBCFILE *file,
799                    off_t length)
800 {
801         SMB_OFF_T size = length;
802         char *server = NULL;
803         char *share = NULL;
804         char *user = NULL;
805         char *password = NULL;
806         char *path = NULL;
807         char *targetpath = NULL;
808         struct cli_state *targetcli = NULL;
809         TALLOC_CTX *frame = talloc_stackframe();
810         
811         if (!context || !context->internal->initialized) {
812                 
813                 errno = EINVAL;
814                 TALLOC_FREE(frame);
815                 return -1;
816         }
817         
818         if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
819                 errno = EBADF;
820                 TALLOC_FREE(frame);
821                 return -1;
822         }
823         
824         if (!file->file) {
825                 errno = EINVAL;
826                 TALLOC_FREE(frame);
827                 return -1;
828         }
829         
830         /*d_printf(">>>fstat: parsing %s\n", file->fname);*/
831         if (SMBC_parse_path(frame,
832                             context,
833                             file->fname,
834                             NULL,
835                             &server,
836                             &share,
837                             &path,
838                             &user,
839                             &password,
840                             NULL)) {
841                 errno = EINVAL;
842                 TALLOC_FREE(frame);
843                 return -1;
844         }
845         
846         /*d_printf(">>>fstat: resolving %s\n", path);*/
847         if (!cli_resolve_path(frame, "", file->srv->cli, path,
848                               &targetcli, &targetpath)) {
849                 d_printf("Could not resolve %s\n", path);
850                 TALLOC_FREE(frame);
851                 return -1;
852         }
853         /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
854         
855         if (!cli_ftruncate(targetcli, file->cli_fd, size)) {
856                 errno = EINVAL;
857                 TALLOC_FREE(frame);
858                 return -1;
859         }
860         
861         TALLOC_FREE(frame);
862         return 0;
863         
864 }