LCOV - code coverage report
Current view: top level - source3/libsmb - libsmb_file.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 0 345 0.0 %
Date: 2024-06-13 04:01:37 Functions: 0 10 0.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           0 : SMBC_open_ctx(SMBCCTX *context,
      37             :               const char *fname,
      38             :               int flags,
      39             :               mode_t mode)
      40             : {
      41           0 :         char *server = NULL;
      42           0 :         char *share = NULL;
      43           0 :         char *user = NULL;
      44           0 :         char *password = NULL;
      45           0 :         char *workgroup = NULL;
      46           0 :         char *path = NULL;
      47           0 :         char *targetpath = NULL;
      48           0 :         struct cli_state *targetcli = NULL;
      49           0 :         SMBCSRV *srv   = NULL;
      50           0 :         SMBCFILE *file = NULL;
      51             :         uint16_t fd;
      52           0 :         uint16_t port = 0;
      53           0 :         NTSTATUS status = NT_STATUS_OBJECT_PATH_INVALID;
      54           0 :         TALLOC_CTX *frame = talloc_stackframe();
      55             : 
      56           0 :         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           0 :         if (!fname) {
      63           0 :                 errno = EINVAL;
      64           0 :                 TALLOC_FREE(frame);
      65           0 :                 return NULL;
      66             :         }
      67             : 
      68           0 :         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           0 :         if (!user || user[0] == (char)0) {
      85           0 :                 user = talloc_strdup(frame, smbc_getUser(context));
      86           0 :                 if (!user) {
      87           0 :                         errno = ENOMEM;
      88           0 :                         TALLOC_FREE(frame);
      89           0 :                         return NULL;
      90             :                 }
      91             :         }
      92             : 
      93           0 :         srv = SMBC_server(frame, context, True,
      94             :                           server, port, share, &workgroup, &user, &password);
      95           0 :         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           0 :         if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
     104           0 :                 status = NT_STATUS_OBJECT_PATH_INVALID;
     105             :         } else {
     106           0 :                 struct cli_credentials *creds = NULL;
     107             : 
     108           0 :                 file = SMB_MALLOC_P(SMBCFILE);
     109           0 :                 if (!file) {
     110           0 :                         errno = ENOMEM;
     111           0 :                         TALLOC_FREE(frame);
     112           0 :                         return NULL;
     113             :                 }
     114             : 
     115           0 :                 ZERO_STRUCTP(file);
     116             : 
     117           0 :                 creds = context->internal->creds;
     118             :                 /*d_printf(">>>open: resolving %s\n", path);*/
     119           0 :                 status = cli_resolve_path(
     120             :                         frame, "",
     121             :                         creds,
     122             :                         srv->cli, path, &targetcli, &targetpath);
     123           0 :                 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           0 :                 status = cli_open(targetcli, targetpath, flags,
     133           0 :                                    context->internal->share_mode, &fd);
     134           0 :                 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           0 :                 file->cli_fd  = fd;
     147           0 :                 file->fname   = SMB_STRDUP(fname);
     148           0 :                 file->srv     = srv;
     149           0 :                 file->offset  = 0;
     150           0 :                 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           0 :                 file->targetcli = targetcli;
     159             : 
     160           0 :                 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           0 :                 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           0 :                 TALLOC_FREE(frame);
     194           0 :                 return file;
     195             :         }
     196             : 
     197             :         /* Check if opendir needed ... */
     198             : 
     199           0 :         if (!NT_STATUS_IS_OK(status)) {
     200           0 :                 file = smbc_getFunctionOpendir(context)(context, fname);
     201           0 :                 TALLOC_FREE(frame);
     202           0 :                 if (file == NULL) {
     203           0 :                         errno = cli_status_to_errno(status);
     204             :                 }
     205           0 :                 return file;
     206             :         }
     207             : 
     208           0 :         errno = EINVAL; /* FIXME, correct errno ? */
     209           0 :         TALLOC_FREE(frame);
     210           0 :         return NULL;
     211             : }
     212             : 
     213             : /*
     214             :  * Routine to create a file
     215             :  */
     216             : 
     217             : SMBCFILE *
     218           0 : SMBC_creat_ctx(SMBCCTX *context,
     219             :                const char *path,
     220             :                mode_t mode)
     221             : {
     222           0 :         if (!context || !context->internal->initialized) {
     223           0 :                 errno = EINVAL;
     224           0 :                 return NULL;
     225             :         }
     226             : 
     227           0 :         return SMBC_open_ctx(context, path,
     228             :                              O_WRONLY | O_CREAT | O_TRUNC, mode);
     229             : }
     230             : 
     231             : /*
     232             :  * Routine to read() a file ...
     233             :  */
     234             : 
     235             : ssize_t
     236           0 : SMBC_read_ctx(SMBCCTX *context,
     237             :               SMBCFILE *file,
     238             :               void *buf,
     239             :               size_t count)
     240             : {
     241             :         size_t ret;
     242           0 :         TALLOC_CTX *frame = talloc_stackframe();
     243             :         NTSTATUS status;
     244             : 
     245             :         /*
     246             :          * offset:
     247             :          *
     248             :          * Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) --
     249             :          * appears to pass file->offset (which is type off_t) differently than
     250             :          * a local variable of type off_t.  Using local variable "offset" in
     251             :          * the call to cli_read() instead of file->offset fixes a problem
     252             :          * retrieving data at an offset greater than 4GB.
     253             :          */
     254             :         off_t offset;
     255             : 
     256           0 :         if (!context || !context->internal->initialized) {
     257           0 :                 errno = EINVAL;
     258           0 :                 TALLOC_FREE(frame);
     259           0 :                 return -1;
     260             :         }
     261             : 
     262           0 :         DEBUG(4, ("smbc_read(%p, %zu)\n", file, count));
     263             : 
     264           0 :         if (!SMBC_dlist_contains(context->internal->files, file)) {
     265           0 :                 errno = EBADF;
     266           0 :                 TALLOC_FREE(frame);
     267           0 :                 return -1;
     268             :         }
     269             : 
     270           0 :         offset = file->offset;
     271             : 
     272             :         /* Check that the buffer exists ... */
     273             : 
     274           0 :         if (buf == NULL) {
     275           0 :                 errno = EINVAL;
     276           0 :                 TALLOC_FREE(frame);
     277           0 :                 return -1;
     278             :         }
     279             : 
     280           0 :         status = cli_read(file->targetcli, file->cli_fd, (char *)buf, offset,
     281             :                           count, &ret);
     282           0 :         if (!NT_STATUS_IS_OK(status)) {
     283           0 :                 TALLOC_FREE(frame);
     284           0 :                 errno = cli_status_to_errno(status);
     285           0 :                 return -1;
     286             :         }
     287             : 
     288           0 :         file->offset += ret;
     289             : 
     290           0 :         DEBUG(4, ("  --> %zu\n", ret));
     291             : 
     292           0 :         TALLOC_FREE(frame);
     293           0 :         return ret;  /* Success, ret bytes of data ... */
     294             : }
     295             : 
     296             : off_t
     297           0 : SMBC_splice_ctx(SMBCCTX *context,
     298             :                 SMBCFILE *srcfile,
     299             :                 SMBCFILE *dstfile,
     300             :                 off_t count,
     301             :                 int (*splice_cb)(off_t n, void *priv),
     302             :                 void *priv)
     303             : {
     304           0 :         off_t written = 0;
     305           0 :         TALLOC_CTX *frame = talloc_stackframe();
     306             :         NTSTATUS status;
     307             : 
     308           0 :         if (!context || !context->internal->initialized) {
     309           0 :                 errno = EINVAL;
     310           0 :                 TALLOC_FREE(frame);
     311           0 :                 return -1;
     312             :         }
     313             : 
     314           0 :         if (!SMBC_dlist_contains(context->internal->files, srcfile)) {
     315           0 :                 errno = EBADF;
     316           0 :                 TALLOC_FREE(frame);
     317           0 :                 return -1;
     318             :         }
     319             : 
     320           0 :         if (!SMBC_dlist_contains(context->internal->files, dstfile)) {
     321           0 :                 errno = EBADF;
     322           0 :                 TALLOC_FREE(frame);
     323           0 :                 return -1;
     324             :         }
     325             : 
     326           0 :         status = cli_splice(srcfile->targetcli, dstfile->targetcli,
     327           0 :                             srcfile->cli_fd, dstfile->cli_fd,
     328             :                             count, srcfile->offset, dstfile->offset, &written,
     329             :                             splice_cb, priv);
     330           0 :         if (!NT_STATUS_IS_OK(status)) {
     331           0 :                 TALLOC_FREE(frame);
     332           0 :                 errno = cli_status_to_errno(status);
     333           0 :                 return -1;
     334             :         }
     335             : 
     336           0 :         srcfile->offset += written;
     337           0 :         dstfile->offset += written;
     338             : 
     339           0 :         TALLOC_FREE(frame);
     340           0 :         return written;
     341             : }
     342             : 
     343             : /*
     344             :  * Routine to write() a file ...
     345             :  */
     346             : 
     347             : ssize_t
     348           0 : SMBC_write_ctx(SMBCCTX *context,
     349             :                SMBCFILE *file,
     350             :                const void *buf,
     351             :                size_t count)
     352             : {
     353             :         off_t offset;
     354           0 :         TALLOC_CTX *frame = talloc_stackframe();
     355             :         NTSTATUS status;
     356             : 
     357             :         /* First check all pointers before dereferencing them */
     358             : 
     359           0 :         if (!context || !context->internal->initialized) {
     360           0 :                 errno = EINVAL;
     361           0 :                 TALLOC_FREE(frame);
     362           0 :                 return -1;
     363             :         }
     364             : 
     365           0 :         if (!SMBC_dlist_contains(context->internal->files, file)) {
     366           0 :                 errno = EBADF;
     367           0 :                 TALLOC_FREE(frame);
     368           0 :                 return -1;
     369             :         }
     370             : 
     371             :         /* Check that the buffer exists ... */
     372             : 
     373           0 :         if (buf == NULL) {
     374           0 :                 errno = EINVAL;
     375           0 :                 TALLOC_FREE(frame);
     376           0 :                 return -1;
     377             :         }
     378             : 
     379           0 :         offset = file->offset; /* See "offset" comment in SMBC_read_ctx() */
     380             : 
     381           0 :         status = cli_writeall(file->targetcli, file->cli_fd,
     382             :                               0, (const uint8_t *)buf, offset, count, NULL);
     383           0 :         if (!NT_STATUS_IS_OK(status)) {
     384           0 :                 errno = map_errno_from_nt_status(status);
     385           0 :                 TALLOC_FREE(frame);
     386           0 :                 return -1;
     387             :         }
     388             : 
     389           0 :         file->offset += count;
     390             : 
     391           0 :         TALLOC_FREE(frame);
     392           0 :         return count;  /* Success, 0 bytes of data ... */
     393             : }
     394             : 
     395             : /*
     396             :  * Routine to close() a file ...
     397             :  */
     398             : 
     399             : int
     400           0 : SMBC_close_ctx(SMBCCTX *context,
     401             :                SMBCFILE *file)
     402             : {
     403           0 :         TALLOC_CTX *frame = talloc_stackframe();
     404             :         NTSTATUS status;
     405             : 
     406           0 :         if (!context || !context->internal->initialized) {
     407           0 :                 errno = EINVAL;
     408           0 :                 TALLOC_FREE(frame);
     409           0 :                 return -1;
     410             :         }
     411             : 
     412           0 :         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           0 :         if (!file->file) {
     420           0 :                 TALLOC_FREE(frame);
     421           0 :                 return smbc_getFunctionClosedir(context)(context, file);
     422             :         }
     423             : 
     424           0 :         status = cli_close(file->targetcli, file->cli_fd);
     425           0 :         if (!NT_STATUS_IS_OK(status)) {
     426             :                 SMBCSRV *srv;
     427           0 :                 DEBUG(3, ("cli_close failed on %s. purging server.\n",
     428             :                           file->fname));
     429             :                 /* Deallocate slot and remove the server
     430             :                  * from the server cache if unused */
     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 :                 errno = cli_status_to_errno(status);
     438           0 :                 return -1;
     439             :         }
     440             : 
     441           0 :         DLIST_REMOVE(context->internal->files, file);
     442           0 :         SAFE_FREE(file->fname);
     443           0 :         SAFE_FREE(file);
     444           0 :         TALLOC_FREE(frame);
     445           0 :         return 0;
     446             : }
     447             : 
     448             : /*
     449             :  * Get info from an SMB server on a file. Use a qpathinfo call first
     450             :  * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
     451             :  */
     452             : NTSTATUS
     453           0 : SMBC_getatr(SMBCCTX * context,
     454             :             SMBCSRV *srv,
     455             :             const char *path,
     456             :             struct stat *sb)
     457             : {
     458           0 :         char *fixedpath = NULL;
     459           0 :         char *targetpath = NULL;
     460           0 :         struct cli_state *targetcli = NULL;
     461           0 :         uint32_t attr = 0;
     462           0 :         off_t size = 0;
     463           0 :         struct timespec create_time_ts = {0};
     464           0 :         struct timespec access_time_ts = {0};
     465           0 :         struct timespec write_time_ts = {0};
     466           0 :         struct timespec change_time_ts = {0};
     467           0 :         struct timespec w_time_ts = {0};
     468           0 :         time_t write_time = 0;
     469           0 :         SMB_INO_T ino = 0;
     470           0 :         struct cli_credentials *creds = NULL;
     471           0 :         TALLOC_CTX *frame = talloc_stackframe();
     472             :         NTSTATUS status;
     473             : 
     474           0 :         if (!context || !context->internal->initialized) {
     475           0 :                 TALLOC_FREE(frame);
     476           0 :                 return NT_STATUS_INVALID_PARAMETER;
     477             :         }
     478             : 
     479             :         /* path fixup for . and .. */
     480           0 :         if (ISDOT(path) || ISDOTDOT(path)) {
     481           0 :                 fixedpath = talloc_strdup(frame, "\\");
     482           0 :                 if (!fixedpath) {
     483           0 :                         TALLOC_FREE(frame);
     484           0 :                         return NT_STATUS_NO_MEMORY;
     485             :                 }
     486             :         } else {
     487           0 :                 fixedpath = talloc_strdup(frame, path);
     488           0 :                 if (!fixedpath) {
     489           0 :                         TALLOC_FREE(frame);
     490           0 :                         return NT_STATUS_NO_MEMORY;
     491             :                 }
     492           0 :                 trim_string(fixedpath, NULL, "\\..");
     493           0 :                 trim_string(fixedpath, NULL, "\\.");
     494             :         }
     495           0 :         DEBUG(4,("SMBC_getatr: sending qpathinfo\n"));
     496             : 
     497           0 :         creds = context->internal->creds;
     498             : 
     499           0 :         status = cli_resolve_path(frame, "",
     500             :                                   creds,
     501             :                                   srv->cli, fixedpath,
     502             :                                   &targetcli, &targetpath);
     503           0 :         if (!NT_STATUS_IS_OK(status)) {
     504           0 :                 d_printf("Couldn't resolve %s\n", path);
     505           0 :                 TALLOC_FREE(frame);
     506           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     507             :         }
     508             : 
     509           0 :         if (!srv->no_pathinfo2) {
     510           0 :                 bool not_supported_error = false;
     511           0 :                 status = cli_qpathinfo2(targetcli,
     512             :                                         targetpath,
     513             :                                         &create_time_ts,
     514             :                                         &access_time_ts,
     515             :                                         &write_time_ts,
     516             :                                         &change_time_ts,
     517             :                                         &size,
     518             :                                         &attr,
     519             :                                         &ino);
     520           0 :                 if (NT_STATUS_IS_OK(status)) {
     521           0 :                         goto setup_stat;
     522             :                 }
     523           0 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL) ||
     524           0 :                     NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
     525           0 :                         not_supported_error = true;
     526             :                 }
     527           0 :                 if (!not_supported_error) {
     528             :                         /* "Normal error". Just return it to caller. */
     529           0 :                         TALLOC_FREE(frame);
     530           0 :                         return status;
     531             :                 }
     532             :         }
     533             : 
     534           0 :         srv->no_pathinfo2 = True;
     535             : 
     536           0 :         if (!srv->no_pathinfo3) {
     537           0 :                 bool not_supported_error = false;
     538           0 :                 status = cli_qpathinfo3(targetcli,
     539             :                                         targetpath,
     540             :                                         &create_time_ts,
     541             :                                         &access_time_ts,
     542             :                                         &write_time_ts,
     543             :                                         &change_time_ts,
     544             :                                         &size,
     545             :                                         &attr,
     546             :                                         &ino);
     547           0 :                 if (NT_STATUS_IS_OK(status)) {
     548           0 :                         goto setup_stat;
     549             :                 }
     550           0 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL) ||
     551           0 :                     NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
     552           0 :                         not_supported_error = true;
     553             :                 }
     554           0 :                 if (!not_supported_error) {
     555             :                         /* "Normal error". Just return it to caller. */
     556           0 :                         TALLOC_FREE(frame);
     557           0 :                         return status;
     558             :                 }
     559             :         }
     560             : 
     561           0 :         srv->no_pathinfo3 = True;
     562             : 
     563             :         /* if this is NT then don't bother with the getatr */
     564           0 :         if (smb1cli_conn_capabilities(targetcli->conn) & CAP_NT_SMBS) {
     565           0 :                 goto all_failed;
     566             :         }
     567             : 
     568           0 :         status = cli_getatr(targetcli, targetpath, &attr, &size, &write_time);
     569           0 :         if (!NT_STATUS_IS_OK(status)) {
     570           0 :                 goto all_failed;
     571             :         }
     572           0 :         w_time_ts = convert_time_t_to_timespec(write_time);
     573           0 :         access_time_ts = change_time_ts = write_time_ts = w_time_ts;
     574             : 
     575           0 : setup_stat:
     576           0 :         setup_stat(sb,
     577             :                    path,
     578             :                    size,
     579             :                    attr,
     580             :                    ino,
     581             :                    srv->dev,
     582             :                    access_time_ts,
     583             :                    change_time_ts,
     584             :                    write_time_ts);
     585             : 
     586           0 :         TALLOC_FREE(frame);
     587           0 :         return NT_STATUS_OK;
     588             : 
     589           0 : all_failed:
     590           0 :         srv->no_pathinfo2 = False;
     591           0 :         srv->no_pathinfo3 = False;
     592             : 
     593           0 :         TALLOC_FREE(frame);
     594           0 :         return status;
     595             : }
     596             : 
     597             : /*
     598             :  * Set file info on an SMB server.  Use setpathinfo call first.  If that
     599             :  * fails, use setattrE..
     600             :  *
     601             :  * Access and modification time parameters are always used and must be
     602             :  * provided.  Create time, if zero, will be determined from the actual create
     603             :  * time of the file.  If non-zero, the create time will be set as well.
     604             :  *
     605             :  * "attr" (attributes) parameter may be set to -1 if it is not to be set.
     606             :  */
     607             : bool
     608           0 : SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
     609             :             struct timespec create_time,
     610             :             struct timespec access_time,
     611             :             struct timespec write_time,
     612             :             struct timespec change_time,
     613             :             uint16_t attr)
     614             : {
     615             :         uint16_t fd;
     616           0 :         uint32_t lattr = (uint32_t)attr;
     617             :         NTSTATUS status;
     618           0 :         TALLOC_CTX *frame = talloc_stackframe();
     619             : 
     620           0 :         if (attr == (uint16_t)-1) {
     621             :                 /*
     622             :                  * External ABI only passes in
     623             :                  * 16-bits of attribute. Make
     624             :                  * sure we correctly map to
     625             :                  * (uint32_t)-1 meaning don't
     626             :                  * change attributes if attr was
     627             :                  * passed in as 16-bit -1.
     628             :                  */
     629           0 :                 lattr = (uint32_t)-1;
     630             :         }
     631             : 
     632             : 
     633             :         /*
     634             :          * First, try setpathinfo (if qpathinfo succeeded), for it is the
     635             :          * modern function for "new code" to be using, and it works given a
     636             :          * filename rather than requiring that the file be opened to have its
     637             :          * attributes manipulated.
     638             :          */
     639           0 :         if (srv->no_pathinfo ||
     640           0 :             !NT_STATUS_IS_OK(cli_setpathinfo_ext(srv->cli, path,
     641             :                                                  create_time,
     642             :                                                  access_time,
     643             :                                                  write_time,
     644             :                                                  change_time,
     645             :                                                  lattr))) {
     646             : 
     647             :                 /*
     648             :                  * setpathinfo is not supported; go to plan B.
     649             :                  *
     650             :                  * cli_setatr() does not work on win98, and it also doesn't
     651             :                  * support setting the access time (only the modification
     652             :                  * time), so in all cases, we open the specified file and use
     653             :                  * cli_setattrE() which should work on all OS versions, and
     654             :                  * supports both times.
     655             :                  */
     656             : 
     657             :                 /* Don't try {q,set}pathinfo() again, with this server */
     658           0 :                 srv->no_pathinfo = True;
     659             : 
     660             :                 /* Open the file */
     661           0 :                 status = cli_open(srv->cli, path, O_RDWR, DENY_NONE, &fd);
     662           0 :                 if (!NT_STATUS_IS_OK(status)) {
     663           0 :                         TALLOC_FREE(frame);
     664           0 :                         errno = cli_status_to_errno(status);
     665           0 :                         return False;
     666             :                 }
     667             : 
     668             :                 /* Set the new attributes */
     669           0 :                 status = cli_setattrE(
     670             :                         srv->cli,
     671             :                         fd,
     672             :                         change_time.tv_sec,
     673             :                         access_time.tv_sec,
     674             :                         write_time.tv_sec);
     675             : 
     676             :                 /* Close the file */
     677           0 :                 cli_close(srv->cli, fd);
     678             : 
     679             :                 /*
     680             :                  * Unfortunately, setattrE() doesn't have a provision for
     681             :                  * setting the access attr (attributes).  We'll have to try
     682             :                  * cli_setatr() for that, and with only this parameter, it
     683             :                  * seems to work on win98.
     684             :                  */
     685           0 :                 if (NT_STATUS_IS_OK(status) && attr != (uint16_t) -1) {
     686           0 :                         status = cli_setatr(srv->cli, path, (uint32_t)attr, 0);
     687             :                 }
     688             : 
     689           0 :                 if (!NT_STATUS_IS_OK(status)) {
     690           0 :                         TALLOC_FREE(frame);
     691           0 :                         errno = cli_status_to_errno(status);
     692           0 :                         return False;
     693             :                 }
     694             :         }
     695             : 
     696           0 :         TALLOC_FREE(frame);
     697           0 :         return True;
     698             : }
     699             : 
     700             : /*
     701             :  * A routine to lseek() a file
     702             :  */
     703             : 
     704             : off_t
     705           0 : SMBC_lseek_ctx(SMBCCTX *context,
     706             :                SMBCFILE *file,
     707             :                off_t offset,
     708             :                int whence)
     709             : {
     710             :         off_t size;
     711           0 :         TALLOC_CTX *frame = talloc_stackframe();
     712             : 
     713           0 :         if (!context || !context->internal->initialized) {
     714           0 :                 errno = EINVAL;
     715           0 :                 TALLOC_FREE(frame);
     716           0 :                 return -1;
     717             :         }
     718             : 
     719           0 :         if (!SMBC_dlist_contains(context->internal->files, file)) {
     720           0 :                 errno = EBADF;
     721           0 :                 TALLOC_FREE(frame);
     722           0 :                 return -1;
     723             :         }
     724             : 
     725           0 :         if (!file->file) {
     726           0 :                 errno = EINVAL;
     727           0 :                 TALLOC_FREE(frame);
     728           0 :                 return -1;      /* Can't lseek a dir ... */
     729             :         }
     730             : 
     731           0 :         switch (whence) {
     732           0 :         case SEEK_SET:
     733           0 :                 file->offset = offset;
     734           0 :                 break;
     735           0 :         case SEEK_CUR:
     736           0 :                 file->offset += offset;
     737           0 :                 break;
     738           0 :         case SEEK_END:
     739           0 :                 if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(
     740             :                                              file->targetcli, file->cli_fd, NULL,
     741             :                                              &size, NULL, NULL, NULL, NULL,
     742             :                                              NULL))) {
     743           0 :                         errno = EINVAL;
     744           0 :                         TALLOC_FREE(frame);
     745           0 :                         return -1;
     746             :                 }
     747           0 :                 file->offset = size + offset;
     748           0 :                 break;
     749           0 :         default:
     750           0 :                 errno = EINVAL;
     751           0 :                 break;
     752             :         }
     753             : 
     754           0 :         TALLOC_FREE(frame);
     755           0 :         return file->offset;
     756             : }
     757             : 
     758             : 
     759             : /*
     760             :  * Routine to truncate a file given by its file descriptor, to a specified size
     761             :  */
     762             : 
     763             : int
     764           0 : SMBC_ftruncate_ctx(SMBCCTX *context,
     765             :                    SMBCFILE *file,
     766             :                    off_t length)
     767             : {
     768           0 :         off_t size = length;
     769           0 :         TALLOC_CTX *frame = talloc_stackframe();
     770             : 
     771           0 :         if (!context || !context->internal->initialized) {
     772           0 :                 errno = EINVAL;
     773           0 :                 TALLOC_FREE(frame);
     774           0 :                 return -1;
     775             :         }
     776             : 
     777           0 :         if (!SMBC_dlist_contains(context->internal->files, file)) {
     778           0 :                 errno = EBADF;
     779           0 :                 TALLOC_FREE(frame);
     780           0 :                 return -1;
     781             :         }
     782             : 
     783           0 :         if (!file->file) {
     784           0 :                 errno = EINVAL;
     785           0 :                 TALLOC_FREE(frame);
     786           0 :                 return -1;
     787             :         }
     788             : 
     789           0 :         if (!NT_STATUS_IS_OK(cli_ftruncate(file->targetcli, file->cli_fd, (uint64_t)size))) {
     790           0 :                 errno = EINVAL;
     791           0 :                 TALLOC_FREE(frame);
     792           0 :                 return -1;
     793             :         }
     794             : 
     795           0 :         TALLOC_FREE(frame);
     796           0 :         return 0;
     797             : }

Generated by: LCOV version 1.13