LCOV - code coverage report
Current view: top level - source3/libsmb - libsmb_file.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 133 361 36.8 %
Date: 2024-04-21 15:09:00 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         484 : SMBC_open_ctx(SMBCCTX *context,
      37             :               const char *fname,
      38             :               int flags,
      39             :               mode_t mode)
      40             : {
      41         484 :         char *server = NULL;
      42         484 :         char *share = NULL;
      43         484 :         char *user = NULL;
      44         484 :         char *password = NULL;
      45         484 :         char *workgroup = NULL;
      46         484 :         char *path = NULL;
      47         484 :         char *targetpath = NULL;
      48         484 :         struct cli_state *targetcli = NULL;
      49         484 :         SMBCSRV *srv   = NULL;
      50         484 :         SMBCFILE *file = NULL;
      51           0 :         uint16_t fd;
      52         484 :         uint16_t port = 0;
      53         484 :         NTSTATUS status = NT_STATUS_OBJECT_PATH_INVALID;
      54         484 :         TALLOC_CTX *frame = talloc_stackframe();
      55             : 
      56         484 :         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         484 :         if (!fname) {
      63           0 :                 errno = EINVAL;
      64           0 :                 TALLOC_FREE(frame);
      65           0 :                 return NULL;
      66             :         }
      67             : 
      68         484 :         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         484 :         if (!user || user[0] == (char)0) {
      85          54 :                 user = talloc_strdup(frame, smbc_getUser(context));
      86          54 :                 if (!user) {
      87           0 :                         errno = ENOMEM;
      88           0 :                         TALLOC_FREE(frame);
      89           0 :                         return NULL;
      90             :                 }
      91             :         }
      92             : 
      93         484 :         srv = SMBC_server(frame, context, True,
      94             :                           server, port, share, &workgroup, &user, &password);
      95         484 :         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         484 :         if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
     104           0 :                 status = NT_STATUS_OBJECT_PATH_INVALID;
     105             :         } else {
     106         484 :                 struct cli_credentials *creds = NULL;
     107             : 
     108         484 :                 file = SMB_MALLOC_P(SMBCFILE);
     109         484 :                 if (!file) {
     110           0 :                         errno = ENOMEM;
     111           0 :                         TALLOC_FREE(frame);
     112           0 :                         return NULL;
     113             :                 }
     114             : 
     115         484 :                 ZERO_STRUCTP(file);
     116             : 
     117         484 :                 creds = context->internal->creds;
     118             :                 /*d_printf(">>>open: resolving %s\n", path);*/
     119         484 :                 status = cli_resolve_path(
     120             :                         frame, "",
     121             :                         creds,
     122             :                         srv->cli, path, &targetcli, &targetpath);
     123         484 :                 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         484 :                 status = cli_open(targetcli, targetpath, flags,
     133         484 :                                    context->internal->share_mode, &fd);
     134         484 :                 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         484 :                 file->cli_fd  = fd;
     147         484 :                 file->fname   = SMB_STRDUP(fname);
     148         484 :                 file->srv     = srv;
     149         484 :                 file->offset  = 0;
     150         484 :                 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         484 :                 file->targetcli = targetcli;
     159             : 
     160         484 :                 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         484 :                 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         484 :                 TALLOC_FREE(frame);
     194         484 :                 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         420 : SMBC_creat_ctx(SMBCCTX *context,
     219             :                const char *path,
     220             :                mode_t mode)
     221             : {
     222         420 :         if (!context || !context->internal->initialized) {
     223           0 :                 errno = EINVAL;
     224           0 :                 return NULL;
     225             :         }
     226             : 
     227         420 :         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         402 : SMBC_read_ctx(SMBCCTX *context,
     237             :               SMBCFILE *file,
     238             :               void *buf,
     239             :               size_t count)
     240             : {
     241           0 :         size_t ret;
     242         402 :         TALLOC_CTX *frame = talloc_stackframe();
     243           0 :         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           0 :         off_t offset;
     255             : 
     256         402 :         if (!context || !context->internal->initialized) {
     257           0 :                 errno = EINVAL;
     258           0 :                 TALLOC_FREE(frame);
     259           0 :                 return -1;
     260             :         }
     261             : 
     262         402 :         DEBUG(4, ("smbc_read(%p, %zu)\n", file, count));
     263             : 
     264         402 :         if (!SMBC_dlist_contains(context->internal->files, file)) {
     265           0 :                 errno = EBADF;
     266           0 :                 TALLOC_FREE(frame);
     267           0 :                 return -1;
     268             :         }
     269             : 
     270         402 :         offset = file->offset;
     271             : 
     272             :         /* Check that the buffer exists ... */
     273             : 
     274         402 :         if (buf == NULL) {
     275           0 :                 errno = EINVAL;
     276           0 :                 TALLOC_FREE(frame);
     277           0 :                 return -1;
     278             :         }
     279             : 
     280         402 :         status = cli_read(file->targetcli, file->cli_fd, (char *)buf, offset,
     281             :                           count, &ret);
     282         402 :         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         402 :         file->offset += ret;
     289             : 
     290         402 :         DEBUG(4, ("  --> %zu\n", ret));
     291             : 
     292         402 :         TALLOC_FREE(frame);
     293         402 :         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           0 :         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           0 :         off_t offset;
     354           0 :         TALLOC_CTX *frame = talloc_stackframe();
     355           0 :         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         486 : SMBC_close_ctx(SMBCCTX *context,
     401             :                SMBCFILE *file)
     402             : {
     403         486 :         TALLOC_CTX *frame = talloc_stackframe();
     404           0 :         NTSTATUS status;
     405             : 
     406         486 :         if (!context || !context->internal->initialized) {
     407           0 :                 errno = EINVAL;
     408           0 :                 TALLOC_FREE(frame);
     409           0 :                 return -1;
     410             :         }
     411             : 
     412         486 :         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         486 :         if (!file->file) {
     420           2 :                 TALLOC_FREE(frame);
     421           2 :                 return smbc_getFunctionClosedir(context)(context, file);
     422             :         }
     423             : 
     424         484 :         status = cli_close(file->targetcli, file->cli_fd);
     425         484 :         if (!NT_STATUS_IS_OK(status)) {
     426           0 :                 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         484 :         DLIST_REMOVE(context->internal->files, file);
     442         484 :         SAFE_FREE(file->fname);
     443         484 :         SAFE_FREE(file);
     444         484 :         TALLOC_FREE(frame);
     445         484 :         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          20 : SMBC_getatr(SMBCCTX * context,
     454             :             SMBCSRV *srv,
     455             :             const char *path,
     456             :             struct stat *sb)
     457             : {
     458          20 :         char *fixedpath = NULL;
     459          20 :         char *targetpath = NULL;
     460          20 :         struct cli_state *targetcli = NULL;
     461          20 :         uint32_t attr = 0;
     462          20 :         off_t size = 0;
     463          20 :         struct timespec create_time_ts = {0};
     464          20 :         struct timespec access_time_ts = {0};
     465          20 :         struct timespec write_time_ts = {0};
     466          20 :         struct timespec change_time_ts = {0};
     467          20 :         struct timespec w_time_ts = {0};
     468          20 :         time_t write_time = 0;
     469          20 :         SMB_INO_T ino = 0;
     470          20 :         mode_t mode = S_IFREG;
     471          20 :         struct cli_credentials *creds = NULL;
     472          20 :         TALLOC_CTX *frame = talloc_stackframe();
     473           0 :         NTSTATUS status;
     474             : 
     475          20 :         if (!context || !context->internal->initialized) {
     476           0 :                 TALLOC_FREE(frame);
     477           0 :                 return NT_STATUS_INVALID_PARAMETER;
     478             :         }
     479             : 
     480             :         /* path fixup for . and .. */
     481          20 :         if (ISDOT(path) || ISDOTDOT(path)) {
     482           0 :                 fixedpath = talloc_strdup(frame, "\\");
     483           0 :                 if (!fixedpath) {
     484           0 :                         TALLOC_FREE(frame);
     485           0 :                         return NT_STATUS_NO_MEMORY;
     486             :                 }
     487             :         } else {
     488          20 :                 fixedpath = talloc_strdup(frame, path);
     489          20 :                 if (!fixedpath) {
     490           0 :                         TALLOC_FREE(frame);
     491           0 :                         return NT_STATUS_NO_MEMORY;
     492             :                 }
     493          20 :                 trim_string(fixedpath, NULL, "\\..");
     494          20 :                 trim_string(fixedpath, NULL, "\\.");
     495             :         }
     496          20 :         DEBUG(4,("SMBC_getatr: sending qpathinfo\n"));
     497             : 
     498          20 :         creds = context->internal->creds;
     499             : 
     500          20 :         status = cli_resolve_path(frame, "",
     501             :                                   creds,
     502             :                                   srv->cli, fixedpath,
     503             :                                   &targetcli, &targetpath);
     504          20 :         if (!NT_STATUS_IS_OK(status)) {
     505           0 :                 d_printf("Couldn't resolve %s\n", path);
     506           0 :                 TALLOC_FREE(frame);
     507           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     508             :         }
     509             : 
     510          20 :         if (!srv->no_pathinfo2) {
     511          20 :                 bool not_supported_error = false;
     512          20 :                 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             :                                         &mode);
     522          20 :                 if (NT_STATUS_IS_OK(status)) {
     523          16 :                         goto setup_stat;
     524             :                 }
     525           4 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL) ||
     526           4 :                     NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
     527           0 :                         not_supported_error = true;
     528             :                 }
     529           4 :                 if (!not_supported_error) {
     530             :                         /* "Normal error". Just return it to caller. */
     531           4 :                         TALLOC_FREE(frame);
     532           4 :                         return status;
     533             :                 }
     534             :         }
     535             : 
     536           0 :         srv->no_pathinfo2 = True;
     537             : 
     538           0 :         if (!srv->no_pathinfo3) {
     539           0 :                 bool not_supported_error = false;
     540           0 :                 status = cli_qpathinfo3(targetcli,
     541             :                                         targetpath,
     542             :                                         &create_time_ts,
     543             :                                         &access_time_ts,
     544             :                                         &write_time_ts,
     545             :                                         &change_time_ts,
     546             :                                         &size,
     547             :                                         &attr,
     548             :                                         &ino);
     549           0 :                 if (NT_STATUS_IS_OK(status)) {
     550           0 :                         goto setup_stat;
     551             :                 }
     552           0 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL) ||
     553           0 :                     NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
     554           0 :                         not_supported_error = true;
     555             :                 }
     556           0 :                 if (!not_supported_error) {
     557             :                         /* "Normal error". Just return it to caller. */
     558           0 :                         TALLOC_FREE(frame);
     559           0 :                         return status;
     560             :                 }
     561             :         }
     562             : 
     563           0 :         srv->no_pathinfo3 = True;
     564             : 
     565             :         /* if this is NT then don't bother with the getatr */
     566           0 :         if (smb1cli_conn_capabilities(targetcli->conn) & CAP_NT_SMBS) {
     567           0 :                 goto all_failed;
     568             :         }
     569             : 
     570           0 :         status = cli_getatr(targetcli, targetpath, &attr, &size, &write_time);
     571           0 :         if (!NT_STATUS_IS_OK(status)) {
     572           0 :                 goto all_failed;
     573             :         }
     574           0 :         w_time_ts = convert_time_t_to_timespec(write_time);
     575           0 :         access_time_ts = change_time_ts = write_time_ts = w_time_ts;
     576             : 
     577          16 : setup_stat:
     578          16 :         setup_stat(sb,
     579             :                    path,
     580             :                    size,
     581             :                    attr,
     582             :                    ino,
     583             :                    srv->dev,
     584             :                    access_time_ts,
     585             :                    change_time_ts,
     586             :                    write_time_ts);
     587             : 
     588          16 :         if ((context->internal->posix_extensions) && (mode != S_IFREG)) {
     589           0 :                 sb->st_mode = (sb->st_mode & ~S_IFMT) | mode;
     590             :         }
     591             : 
     592          16 :         TALLOC_FREE(frame);
     593          16 :         return NT_STATUS_OK;
     594             : 
     595           0 : all_failed:
     596           0 :         srv->no_pathinfo2 = False;
     597           0 :         srv->no_pathinfo3 = False;
     598             : 
     599           0 :         TALLOC_FREE(frame);
     600           0 :         return status;
     601             : }
     602             : 
     603             : /*
     604             :  * Set file info on an SMB server.  Use setpathinfo call first.  If that
     605             :  * fails, use setattrE..
     606             :  *
     607             :  * Access and modification time parameters are always used and must be
     608             :  * provided.  Create time, if zero, will be determined from the actual create
     609             :  * time of the file.  If non-zero, the create time will be set as well.
     610             :  *
     611             :  * "attr" (attributes) parameter may be set to -1 if it is not to be set.
     612             :  */
     613             : bool
     614           4 : SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
     615             :             struct timespec create_time,
     616             :             struct timespec access_time,
     617             :             struct timespec write_time,
     618             :             struct timespec change_time,
     619             :             uint16_t attr)
     620             : {
     621           0 :         uint16_t fd;
     622           4 :         uint32_t lattr = (uint32_t)attr;
     623           0 :         NTSTATUS status;
     624           4 :         TALLOC_CTX *frame = talloc_stackframe();
     625             : 
     626           4 :         if (attr == (uint16_t)-1) {
     627             :                 /*
     628             :                  * External ABI only passes in
     629             :                  * 16-bits of attribute. Make
     630             :                  * sure we correctly map to
     631             :                  * (uint32_t)-1 meaning don't
     632             :                  * change attributes if attr was
     633             :                  * passed in as 16-bit -1.
     634             :                  */
     635           0 :                 lattr = (uint32_t)-1;
     636             :         }
     637             : 
     638             : 
     639             :         /*
     640             :          * First, try setpathinfo (if qpathinfo succeeded), for it is the
     641             :          * modern function for "new code" to be using, and it works given a
     642             :          * filename rather than requiring that the file be opened to have its
     643             :          * attributes manipulated.
     644             :          */
     645           4 :         if (srv->no_pathinfo ||
     646           4 :             !NT_STATUS_IS_OK(cli_setpathinfo_ext(srv->cli, path,
     647             :                                                  create_time,
     648             :                                                  access_time,
     649             :                                                  write_time,
     650             :                                                  change_time,
     651             :                                                  lattr))) {
     652             : 
     653             :                 /*
     654             :                  * setpathinfo is not supported; go to plan B.
     655             :                  *
     656             :                  * cli_setatr() does not work on win98, and it also doesn't
     657             :                  * support setting the access time (only the modification
     658             :                  * time), so in all cases, we open the specified file and use
     659             :                  * cli_setattrE() which should work on all OS versions, and
     660             :                  * supports both times.
     661             :                  */
     662             : 
     663             :                 /* Don't try {q,set}pathinfo() again, with this server */
     664           0 :                 srv->no_pathinfo = True;
     665             : 
     666             :                 /* Open the file */
     667           0 :                 status = cli_open(srv->cli, path, O_RDWR, DENY_NONE, &fd);
     668           0 :                 if (!NT_STATUS_IS_OK(status)) {
     669           0 :                         TALLOC_FREE(frame);
     670           0 :                         errno = cli_status_to_errno(status);
     671           0 :                         return False;
     672             :                 }
     673             : 
     674             :                 /* Set the new attributes */
     675           0 :                 status = cli_setattrE(
     676             :                         srv->cli,
     677             :                         fd,
     678             :                         change_time.tv_sec,
     679             :                         access_time.tv_sec,
     680             :                         write_time.tv_sec);
     681             : 
     682             :                 /* Close the file */
     683           0 :                 cli_close(srv->cli, fd);
     684             : 
     685             :                 /*
     686             :                  * Unfortunately, setattrE() doesn't have a provision for
     687             :                  * setting the access attr (attributes).  We'll have to try
     688             :                  * cli_setatr() for that, and with only this parameter, it
     689             :                  * seems to work on win98.
     690             :                  */
     691           0 :                 if (NT_STATUS_IS_OK(status) && attr != (uint16_t) -1) {
     692           0 :                         status = cli_setatr(srv->cli, path, (uint32_t)attr, 0);
     693             :                 }
     694             : 
     695           0 :                 if (!NT_STATUS_IS_OK(status)) {
     696           0 :                         TALLOC_FREE(frame);
     697           0 :                         errno = cli_status_to_errno(status);
     698           0 :                         return False;
     699             :                 }
     700             :         }
     701             : 
     702           4 :         TALLOC_FREE(frame);
     703           4 :         return True;
     704             : }
     705             : 
     706             : /*
     707             :  * A routine to lseek() a file
     708             :  */
     709             : 
     710             : off_t
     711           2 : SMBC_lseek_ctx(SMBCCTX *context,
     712             :                SMBCFILE *file,
     713             :                off_t offset,
     714             :                int whence)
     715             : {
     716           0 :         off_t size;
     717           2 :         TALLOC_CTX *frame = talloc_stackframe();
     718             : 
     719           2 :         if (!context || !context->internal->initialized) {
     720           0 :                 errno = EINVAL;
     721           0 :                 TALLOC_FREE(frame);
     722           0 :                 return -1;
     723             :         }
     724             : 
     725           2 :         if (!SMBC_dlist_contains(context->internal->files, file)) {
     726           0 :                 errno = EBADF;
     727           0 :                 TALLOC_FREE(frame);
     728           0 :                 return -1;
     729             :         }
     730             : 
     731           2 :         if (!file->file) {
     732           0 :                 errno = EINVAL;
     733           0 :                 TALLOC_FREE(frame);
     734           0 :                 return -1;      /* Can't lseek a dir ... */
     735             :         }
     736             : 
     737           2 :         switch (whence) {
     738           2 :         case SEEK_SET:
     739           2 :                 file->offset = offset;
     740           2 :                 break;
     741           0 :         case SEEK_CUR:
     742           0 :                 file->offset += offset;
     743           0 :                 break;
     744           0 :         case SEEK_END:
     745           0 :                 if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(
     746             :                                              file->targetcli, file->cli_fd, NULL,
     747             :                                              &size, NULL, NULL, NULL, NULL,
     748             :                                              NULL))) {
     749           0 :                         errno = EINVAL;
     750           0 :                         TALLOC_FREE(frame);
     751           0 :                         return -1;
     752             :                 }
     753           0 :                 file->offset = size + offset;
     754           0 :                 break;
     755           0 :         default:
     756           0 :                 errno = EINVAL;
     757           0 :                 break;
     758             :         }
     759             : 
     760           2 :         TALLOC_FREE(frame);
     761           2 :         return file->offset;
     762             : }
     763             : 
     764             : 
     765             : /*
     766             :  * Routine to truncate a file given by its file descriptor, to a specified size
     767             :  */
     768             : 
     769             : int
     770           0 : SMBC_ftruncate_ctx(SMBCCTX *context,
     771             :                    SMBCFILE *file,
     772             :                    off_t length)
     773             : {
     774           0 :         off_t size = length;
     775           0 :         TALLOC_CTX *frame = talloc_stackframe();
     776             : 
     777           0 :         if (!context || !context->internal->initialized) {
     778           0 :                 errno = EINVAL;
     779           0 :                 TALLOC_FREE(frame);
     780           0 :                 return -1;
     781             :         }
     782             : 
     783           0 :         if (!SMBC_dlist_contains(context->internal->files, file)) {
     784           0 :                 errno = EBADF;
     785           0 :                 TALLOC_FREE(frame);
     786           0 :                 return -1;
     787             :         }
     788             : 
     789           0 :         if (!file->file) {
     790           0 :                 errno = EINVAL;
     791           0 :                 TALLOC_FREE(frame);
     792           0 :                 return -1;
     793             :         }
     794             : 
     795           0 :         if (!NT_STATUS_IS_OK(cli_ftruncate(file->targetcli, file->cli_fd, (uint64_t)size))) {
     796           0 :                 errno = EINVAL;
     797           0 :                 TALLOC_FREE(frame);
     798           0 :                 return -1;
     799             :         }
     800             : 
     801           0 :         TALLOC_FREE(frame);
     802           0 :         return 0;
     803             : }

Generated by: LCOV version 1.14