LCOV - code coverage report
Current view: top level - source3/libsmb - libsmb_file.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 123 335 36.7 %
Date: 2021-09-23 10:06:22 Functions: 7 10 70.0 %

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

Generated by: LCOV version 1.13