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