LCOV - code coverage report
Current view: top level - source3/modules - vfs_preopen.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 7 309 2.3 %
Date: 2021-09-23 10:06:22 Functions: 1 14 7.1 %

          Line data    Source code
       1             : /*
       2             :  * Force a readahead of files by opening them and reading the first bytes
       3             :  *
       4             :  * Copyright (C) Volker Lendecke 2008
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 2 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, write to the Free Software
      18             :  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
      19             :  */
      20             : 
      21             : #include "includes.h"
      22             : #include "system/filesys.h"
      23             : #include "smbd/smbd.h"
      24             : #include "lib/util/sys_rw.h"
      25             : #include "lib/util/sys_rw_data.h"
      26             : #include "lib/util/smb_strtox.h"
      27             : #include "lib/util_matching.h"
      28             : #include "lib/global_contexts.h"
      29             : 
      30             : static int vfs_preopen_debug_level = DBGC_VFS;
      31             : 
      32             : #undef DBGC_CLASS
      33             : #define DBGC_CLASS vfs_preopen_debug_level
      34             : 
      35             : #define PREOPEN_MAX_DIGITS 19
      36             : #define PREOPEN_MAX_NUMBER (uint64_t)9999999999999999999ULL
      37             : 
      38             : struct preopen_state;
      39             : 
      40             : struct preopen_helper {
      41             :         struct preopen_state *state;
      42             :         struct tevent_fd *fde;
      43             :         pid_t pid;
      44             :         int fd;
      45             :         bool busy;
      46             : };
      47             : 
      48             : struct preopen_state {
      49             :         int num_helpers;
      50             :         struct preopen_helper *helpers;
      51             : 
      52             :         size_t to_read;         /* How many bytes to read in children? */
      53             :         int queue_max;
      54             : 
      55             :         int queue_dbglvl;       /* DBGLVL_DEBUG by default */
      56             :         int nomatch_dbglvl;     /* DBGLVL_INFO by default */
      57             :         int match_dbglvl;       /* DBGLVL_INFO by default */
      58             :         int reset_dbglvl;       /* DBGLVL_INFO by default */
      59             :         int nodigits_dbglvl;    /* DBGLVL_WARNING by default */
      60             :         int founddigits_dbglvl; /* DBGLVL_NOTICE by default */
      61             :         int push_dbglvl;        /* DBGLVL_NOTICE by default */
      62             : 
      63             :         char *template_fname;   /* Filename to be sent to children */
      64             :         size_t number_start;    /* start offset into "template_fname" */
      65             :         int num_digits;         /* How many digits is the number long? */
      66             : 
      67             :         uint64_t fnum_sent;     /* last fname sent to children */
      68             : 
      69             :         uint64_t fnum_queue_end;/* last fname to be sent, based on
      70             :                                  * last open call + preopen:queuelen
      71             :                                  */
      72             : 
      73             :         struct samba_path_matching *preopen_names;
      74             :         ssize_t last_match_idx; /* remember the last match */
      75             : };
      76             : 
      77           0 : static void preopen_helper_destroy(struct preopen_helper *c)
      78             : {
      79             :         int status;
      80           0 :         TALLOC_FREE(c->fde);
      81           0 :         close(c->fd);
      82           0 :         c->fd = -1;
      83           0 :         kill(c->pid, SIGKILL);
      84           0 :         waitpid(c->pid, &status, 0);
      85           0 :         c->busy = true;
      86           0 : }
      87             : 
      88           0 : static void preopen_queue_run(struct preopen_state *state)
      89             : {
      90             :         char *pdelimiter;
      91             :         char delimiter;
      92             : 
      93           0 :         DBG_PREFIX(state->queue_dbglvl, ("START: "
      94             :                    "last_fname[%s] start_offset=%zu num_digits=%d "
      95             :                    "last_pushed_num=%"PRIu64" queue_end_num=%"PRIu64" num_helpers=%d\n",
      96             :                    state->template_fname,
      97             :                    state->number_start,
      98             :                    state->num_digits,
      99             :                    state->fnum_sent,
     100             :                    state->fnum_queue_end,
     101             :                    state->num_helpers));
     102             : 
     103           0 :         pdelimiter = state->template_fname + state->number_start
     104           0 :                 + state->num_digits;
     105           0 :         delimiter = *pdelimiter;
     106             : 
     107           0 :         while (state->fnum_sent < state->fnum_queue_end) {
     108             : 
     109             :                 ssize_t written;
     110             :                 size_t to_write;
     111             :                 int helper;
     112             : 
     113           0 :                 for (helper=0; helper<state->num_helpers; helper++) {
     114           0 :                         if (state->helpers[helper].busy) {
     115           0 :                                 continue;
     116             :                         }
     117           0 :                         break;
     118             :                 }
     119           0 :                 if (helper == state->num_helpers) {
     120             :                         /* everyone is busy */
     121           0 :                         DBG_PREFIX(state->queue_dbglvl, ("BUSY: "
     122             :                                    "template_fname[%s] start_offset=%zu num_digits=%d "
     123             :                                    "last_pushed_num=%"PRIu64" queue_end_num=%"PRIu64"\n",
     124             :                                    state->template_fname,
     125             :                                    state->number_start,
     126             :                                    state->num_digits,
     127             :                                    state->fnum_sent,
     128             :                                    state->fnum_queue_end));
     129           0 :                         return;
     130             :                 }
     131             : 
     132           0 :                 snprintf(state->template_fname + state->number_start,
     133           0 :                          state->num_digits + 1,
     134             :                          "%.*llu", state->num_digits,
     135           0 :                          (long long unsigned int)(state->fnum_sent + 1));
     136           0 :                 *pdelimiter = delimiter;
     137             : 
     138           0 :                 DBG_PREFIX(state->push_dbglvl, (
     139             :                            "PUSH: fullpath[%s] to helper(idx=%d)\n",
     140             :                            state->template_fname, helper));
     141             : 
     142           0 :                 to_write = talloc_get_size(state->template_fname);
     143           0 :                 written = write_data(state->helpers[helper].fd,
     144           0 :                                      state->template_fname, to_write);
     145           0 :                 state->helpers[helper].busy = true;
     146             : 
     147           0 :                 if (written != to_write) {
     148           0 :                         preopen_helper_destroy(&state->helpers[helper]);
     149             :                 }
     150           0 :                 state->fnum_sent += 1;
     151             :         }
     152           0 :         DBG_PREFIX(state->queue_dbglvl, ("END: "
     153             :                    "template_fname[%s] start_offset=%zu num_digits=%d "
     154             :                    "last_pushed_num=%"PRIu64" queue_end_num=%"PRIu64"\n",
     155             :                    state->template_fname,
     156             :                    state->number_start,
     157             :                    state->num_digits,
     158             :                    state->fnum_sent,
     159             :                    state->fnum_queue_end));
     160             : }
     161             : 
     162           0 : static void preopen_helper_readable(struct tevent_context *ev,
     163             :                                     struct tevent_fd *fde, uint16_t flags,
     164             :                                     void *priv)
     165             : {
     166           0 :         struct preopen_helper *helper = (struct preopen_helper *)priv;
     167           0 :         struct preopen_state *state = helper->state;
     168             :         ssize_t nread;
     169             :         char c;
     170             : 
     171           0 :         if ((flags & TEVENT_FD_READ) == 0) {
     172           0 :                 return;
     173             :         }
     174             : 
     175           0 :         nread = read(helper->fd, &c, 1);
     176           0 :         if (nread <= 0) {
     177           0 :                 preopen_helper_destroy(helper);
     178           0 :                 return;
     179             :         }
     180             : 
     181           0 :         helper->busy = false;
     182             : 
     183           0 :         DBG_PREFIX(state->queue_dbglvl, ("BEFORE: preopen_queue_run\n"));
     184           0 :         preopen_queue_run(state);
     185           0 :         DBG_PREFIX(state->queue_dbglvl, ("AFTER: preopen_queue_run\n"));
     186             : }
     187             : 
     188           0 : static int preopen_helpers_destructor(struct preopen_state *c)
     189             : {
     190             :         int i;
     191             : 
     192           0 :         for (i=0; i<c->num_helpers; i++) {
     193           0 :                 if (c->helpers[i].fd == -1) {
     194           0 :                         continue;
     195             :                 }
     196           0 :                 preopen_helper_destroy(&c->helpers[i]);
     197             :         }
     198             : 
     199           0 :         return 0;
     200             : }
     201             : 
     202           0 : static bool preopen_helper_open_one(int sock_fd, char **pnamebuf,
     203             :                                     size_t to_read, void *filebuf)
     204             : {
     205           0 :         char *namebuf = *pnamebuf;
     206             :         ssize_t nread;
     207           0 :         char c = 0;
     208             :         int fd;
     209             : 
     210           0 :         nread = 0;
     211             : 
     212             :         do {
     213             :                 ssize_t thistime;
     214             : 
     215           0 :                 thistime = read(sock_fd, namebuf + nread,
     216           0 :                                 talloc_get_size(namebuf) - nread);
     217           0 :                 if (thistime <= 0) {
     218           0 :                         return false;
     219             :                 }
     220             : 
     221           0 :                 nread += thistime;
     222             : 
     223           0 :                 if (nread == talloc_get_size(namebuf)) {
     224           0 :                         namebuf = talloc_realloc(
     225             :                                 NULL, namebuf, char,
     226             :                                 talloc_get_size(namebuf) * 2);
     227           0 :                         if (namebuf == NULL) {
     228           0 :                                 return false;
     229             :                         }
     230           0 :                         *pnamebuf = namebuf;
     231             :                 }
     232           0 :         } while (namebuf[nread - 1] != '\0');
     233             : 
     234           0 :         fd = open(namebuf, O_RDONLY);
     235           0 :         if (fd == -1) {
     236           0 :                 goto done;
     237             :         }
     238           0 :         nread = read(fd, filebuf, to_read);
     239           0 :         close(fd);
     240             : 
     241           0 :  done:
     242           0 :         sys_write_v(sock_fd, &c, 1);
     243           0 :         return true;
     244             : }
     245             : 
     246           0 : static bool preopen_helper(int fd, size_t to_read)
     247             : {
     248             :         char *namebuf;
     249             :         void *readbuf;
     250             : 
     251           0 :         namebuf = talloc_array(NULL, char, 1024);
     252           0 :         if (namebuf == NULL) {
     253           0 :                 return false;
     254             :         }
     255             : 
     256           0 :         readbuf = talloc_size(NULL, to_read);
     257           0 :         if (readbuf == NULL) {
     258           0 :                 TALLOC_FREE(namebuf);
     259           0 :                 return false;
     260             :         }
     261             : 
     262           0 :         while (preopen_helper_open_one(fd, &namebuf, to_read, readbuf)) {
     263             :                 ;
     264             :         }
     265             : 
     266           0 :         TALLOC_FREE(readbuf);
     267           0 :         TALLOC_FREE(namebuf);
     268           0 :         return false;
     269             : }
     270             : 
     271           0 : static NTSTATUS preopen_init_helper(struct preopen_helper *h)
     272             : {
     273             :         int fdpair[2];
     274             :         NTSTATUS status;
     275             : 
     276           0 :         if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1) {
     277           0 :                 status = map_nt_error_from_unix(errno);
     278           0 :                 DEBUG(10, ("socketpair() failed: %s\n", strerror(errno)));
     279           0 :                 return status;
     280             :         }
     281             : 
     282           0 :         h->pid = fork();
     283             : 
     284           0 :         if (h->pid == -1) {
     285           0 :                 return map_nt_error_from_unix(errno);
     286             :         }
     287             : 
     288           0 :         if (h->pid == 0) {
     289           0 :                 close(fdpair[0]);
     290           0 :                 preopen_helper(fdpair[1], h->state->to_read);
     291           0 :                 exit(0);
     292             :         }
     293           0 :         close(fdpair[1]);
     294           0 :         h->fd = fdpair[0];
     295           0 :         h->fde = tevent_add_fd(global_event_context(), h->state, h->fd,
     296             :                               TEVENT_FD_READ, preopen_helper_readable, h);
     297           0 :         if (h->fde == NULL) {
     298           0 :                 close(h->fd);
     299           0 :                 h->fd = -1;
     300           0 :                 return NT_STATUS_NO_MEMORY;
     301             :         }
     302           0 :         h->busy = false;
     303           0 :         return NT_STATUS_OK;
     304             : }
     305             : 
     306           0 : static NTSTATUS preopen_init_helpers(TALLOC_CTX *mem_ctx, size_t to_read,
     307             :                                      int num_helpers, int queue_max,
     308             :                                      struct preopen_state **presult)
     309             : {
     310             :         struct preopen_state *result;
     311             :         int i;
     312             : 
     313           0 :         result = talloc(mem_ctx, struct preopen_state);
     314           0 :         if (result == NULL) {
     315           0 :                 return NT_STATUS_NO_MEMORY;
     316             :         }
     317             : 
     318           0 :         result->num_helpers = num_helpers;
     319           0 :         result->helpers = talloc_array(result, struct preopen_helper,
     320             :                                        num_helpers);
     321           0 :         if (result->helpers == NULL) {
     322           0 :                 TALLOC_FREE(result);
     323           0 :                 return NT_STATUS_NO_MEMORY;
     324             :         }
     325             : 
     326           0 :         result->to_read = to_read;
     327           0 :         result->queue_max = queue_max;
     328           0 :         result->template_fname = NULL;
     329           0 :         result->fnum_sent = 0;
     330           0 :         result->fnum_queue_end = 0;
     331             : 
     332           0 :         for (i=0; i<num_helpers; i++) {
     333           0 :                 result->helpers[i].state = result;
     334           0 :                 result->helpers[i].fd = -1;
     335             :         }
     336             : 
     337           0 :         talloc_set_destructor(result, preopen_helpers_destructor);
     338             : 
     339           0 :         for (i=0; i<num_helpers; i++) {
     340           0 :                 preopen_init_helper(&result->helpers[i]);
     341             :         }
     342             : 
     343           0 :         *presult = result;
     344           0 :         return NT_STATUS_OK;
     345             : }
     346             : 
     347           0 : static void preopen_free_helpers(void **ptr)
     348             : {
     349           0 :         TALLOC_FREE(*ptr);
     350           0 : }
     351             : 
     352           0 : static struct preopen_state *preopen_state_get(vfs_handle_struct *handle)
     353             : {
     354             :         struct preopen_state *state;
     355             :         NTSTATUS status;
     356             :         const char *namelist;
     357             : 
     358           0 :         if (SMB_VFS_HANDLE_TEST_DATA(handle)) {
     359           0 :                 SMB_VFS_HANDLE_GET_DATA(handle, state, struct preopen_state,
     360             :                                         return NULL);
     361           0 :                 return state;
     362             :         }
     363             : 
     364           0 :         namelist = lp_parm_const_string(SNUM(handle->conn), "preopen", "names",
     365             :                                         NULL);
     366             : 
     367           0 :         if (namelist == NULL) {
     368           0 :                 return NULL;
     369             :         }
     370             : 
     371           0 :         status = preopen_init_helpers(
     372             :                 NULL,
     373           0 :                 lp_parm_int(SNUM(handle->conn), "preopen", "num_bytes", 1),
     374           0 :                 lp_parm_int(SNUM(handle->conn), "preopen", "helpers", 1),
     375           0 :                 lp_parm_int(SNUM(handle->conn), "preopen", "queuelen", 10),
     376             :                 &state);
     377           0 :         if (!NT_STATUS_IS_OK(status)) {
     378           0 :                 return NULL;
     379             :         }
     380             : 
     381           0 :         state->queue_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "queue_log_level", DBGLVL_DEBUG);
     382           0 :         state->nomatch_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "nomatch_log_level", DBGLVL_INFO);
     383           0 :         state->match_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "match_log_level", DBGLVL_INFO);
     384           0 :         state->reset_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "reset_log_level", DBGLVL_INFO);
     385           0 :         state->nodigits_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "nodigits_log_level", DBGLVL_WARNING);
     386           0 :         state->founddigits_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "founddigits_log_level", DBGLVL_NOTICE);
     387           0 :         state->push_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "push_log_level", DBGLVL_NOTICE);
     388             : 
     389           0 :         if (lp_parm_bool(SNUM(handle->conn), "preopen", "posix-basic-regex", false)) {
     390           0 :                 status = samba_path_matching_regex_sub1_create(state,
     391             :                                                                namelist,
     392           0 :                                                                &state->preopen_names);
     393             :         } else {
     394           0 :                 status = samba_path_matching_mswild_create(state,
     395             :                                                            true, /* case_sensitive */
     396             :                                                            namelist,
     397           0 :                                                            &state->preopen_names);
     398             :         }
     399           0 :         if (!NT_STATUS_IS_OK(status)) {
     400           0 :                 TALLOC_FREE(state);
     401           0 :                 return NULL;
     402             :         }
     403           0 :         state->last_match_idx = -1;
     404             : 
     405           0 :         if (!SMB_VFS_HANDLE_TEST_DATA(handle)) {
     406           0 :                 SMB_VFS_HANDLE_SET_DATA(handle, state, preopen_free_helpers,
     407             :                                         struct preopen_state, return NULL);
     408             :         }
     409             : 
     410           0 :         return state;
     411             : }
     412             : 
     413           0 : static bool preopen_parse_fname(const char *fname, uint64_t *pnum,
     414             :                                 size_t *pstart_idx, int *pnum_digits)
     415             : {
     416           0 :         char digits[PREOPEN_MAX_DIGITS+1] = { 0, };
     417             :         const char *p;
     418           0 :         char *q = NULL;
     419             :         unsigned long long num;
     420           0 :         size_t start_idx = 0;
     421           0 :         int num_digits = -1;
     422           0 :         int error = 0;
     423             : 
     424           0 :         if (*pstart_idx > 0 && *pnum_digits > 0) {
     425             :                 /*
     426             :                  * If the caller knowns
     427             :                  * how many digits are expected
     428             :                  * and on what position,
     429             :                  * we should copy the exact
     430             :                  * subset before we start
     431             :                  * parsing the string into a number
     432             :                  */
     433             : 
     434           0 :                 if (*pnum_digits < 1) {
     435             :                         /*
     436             :                          * We need at least one digit
     437             :                          */
     438           0 :                         return false;
     439             :                 }
     440           0 :                 if (*pnum_digits > PREOPEN_MAX_DIGITS) {
     441             :                         /*
     442             :                          * a string with as much digits as
     443             :                          * PREOPEN_MAX_DIGITS is the longest
     444             :                          * string that would make any sense for us.
     445             :                          *
     446             :                          * The rest will be checked via
     447             :                          * smb_strtoull().
     448             :                          */
     449           0 :                         return false;
     450             :                 }
     451           0 :                 p = fname + *pstart_idx;
     452           0 :                 memcpy(digits, p, *pnum_digits);
     453           0 :                 p = digits;
     454           0 :                 start_idx = *pstart_idx;
     455           0 :                 goto parse;
     456             :         }
     457             : 
     458           0 :         p = strrchr_m(fname, '/');
     459           0 :         if (p == NULL) {
     460           0 :                 p = fname;
     461             :         }
     462             : 
     463           0 :         p += 1;
     464           0 :         while (p[0] != '\0') {
     465           0 :                 if (isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2])) {
     466           0 :                         break;
     467             :                 }
     468           0 :                 p += 1;
     469             :         }
     470           0 :         if (*p == '\0') {
     471             :                 /* no digits around */
     472           0 :                 return false;
     473             :         }
     474             : 
     475           0 :         start_idx = (p - fname);
     476             : 
     477           0 : parse:
     478           0 :         num = smb_strtoull(p, (char **)&q, 10, &error, SMB_STR_STANDARD);
     479           0 :         if (error != 0) {
     480           0 :                 return false;
     481             :         }
     482             : 
     483           0 :         if (num >= PREOPEN_MAX_NUMBER) {
     484             :                 /* overflow */
     485           0 :                 return false;
     486             :         }
     487             : 
     488           0 :         num_digits = (q - p);
     489             : 
     490           0 :         if (*pnum_digits != -1 && *pnum_digits != num_digits) {
     491             :                 /*
     492             :                  * If the caller knowns how many digits
     493             :                  * it expects we should fail if we got something
     494             :                  * different.
     495             :                  */
     496           0 :                 return false;
     497             :         }
     498             : 
     499           0 :         *pnum = num;
     500           0 :         *pstart_idx = start_idx;
     501           0 :         *pnum_digits = num_digits;
     502           0 :         return true;
     503             : }
     504             : 
     505           0 : static uint64_t num_digits_max_value(int num_digits)
     506             : {
     507           0 :         uint64_t num_max = 1;
     508             :         int i;
     509             : 
     510           0 :         if (num_digits < 1) {
     511           0 :                 return 0;
     512             :         }
     513           0 :         if (num_digits >= PREOPEN_MAX_DIGITS) {
     514           0 :                 return PREOPEN_MAX_NUMBER;
     515             :         }
     516             : 
     517           0 :         for (i = 0; i < num_digits; i++) {
     518           0 :                 num_max *= 10;
     519             :         }
     520             : 
     521             :         /*
     522             :          * We actually want
     523             :          * 9   instead of 10
     524             :          * 99  instead of 100
     525             :          * 999 instead of 1000
     526             :          */
     527           0 :         return num_max - 1;
     528             : }
     529             : 
     530           0 : static int preopen_openat(struct vfs_handle_struct *handle,
     531             :                           const struct files_struct *dirfsp,
     532             :                           const struct smb_filename *smb_fname,
     533             :                           struct files_struct *fsp,
     534             :                           int flags,
     535             :                           mode_t mode)
     536             : {
     537           0 :         const char *dirname = dirfsp->fsp_name->base_name;
     538             :         struct preopen_state *state;
     539             :         int res;
     540             :         uint64_t num;
     541             :         uint64_t num_max;
     542             :         NTSTATUS status;
     543           0 :         char *new_template = NULL;
     544           0 :         size_t new_start = 0;
     545           0 :         int new_digits = -1;
     546           0 :         size_t new_end = 0;
     547           0 :         ssize_t match_idx = -1;
     548           0 :         ssize_t replace_start = -1;
     549           0 :         ssize_t replace_end = -1;
     550           0 :         bool need_reset = false;
     551             : 
     552           0 :         DBG_DEBUG("called on %s\n", smb_fname_str_dbg(smb_fname));
     553             : 
     554           0 :         state = preopen_state_get(handle);
     555           0 :         if (state == NULL) {
     556           0 :                 return SMB_VFS_NEXT_OPENAT(handle,
     557             :                                            dirfsp,
     558             :                                            smb_fname,
     559             :                                            fsp,
     560             :                                            flags,
     561             :                                            mode);
     562             :         }
     563             : 
     564           0 :         res = SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, flags, mode);
     565           0 :         if (res == -1) {
     566           0 :                 return -1;
     567             :         }
     568             : 
     569           0 :         if ((flags & O_ACCMODE) != O_RDONLY) {
     570           0 :                 return res;
     571             :         }
     572             : 
     573             :         /*
     574             :          * Make sure we can later contruct an absolute pathname
     575             :          */
     576           0 :         if (dirname[0] != '/') {
     577           0 :                 return res;
     578             :         }
     579             :         /*
     580             :          * There's no point in preopen the directory itself.
     581             :          */
     582           0 :         if (ISDOT(smb_fname->base_name)) {
     583           0 :                 return res;
     584             :         }
     585             :         /*
     586             :          * If we got an absolute path in
     587             :          * smb_fname it's most likely the
     588             :          * reopen via /proc/self/fd/$fd
     589             :          */
     590           0 :         if (smb_fname->base_name[0] == '/') {
     591           0 :                 return res;
     592             :         }
     593             : 
     594           0 :         status = samba_path_matching_check_last_component(state->preopen_names,
     595           0 :                                                           smb_fname->base_name,
     596             :                                                           &match_idx,
     597             :                                                           &replace_start,
     598             :                                                           &replace_end);
     599           0 :         if (!NT_STATUS_IS_OK(status)) {
     600           0 :                 match_idx = -1;
     601             :         }
     602           0 :         if (match_idx < 0) {
     603           0 :                 DBG_PREFIX(state->nomatch_dbglvl, (
     604             :                            "No match with the preopen:names list by name[%s]\n",
     605             :                            smb_fname_str_dbg(smb_fname)));
     606           0 :                 return res;
     607             :         }
     608             : 
     609           0 :         if (replace_start != -1 && replace_end != -1) {
     610           0 :                 DBG_PREFIX(state->match_dbglvl, (
     611             :                            "Pattern(idx=%zd) from preopen:names list matched name[%s] hints(start=%zd,end=%zd)\n",
     612             :                            match_idx, smb_fname_str_dbg(smb_fname), replace_start, replace_end));
     613             :         } else {
     614           0 :                 DBG_PREFIX(state->match_dbglvl, (
     615             :                            "Pattern(idx=%zd) from preopen:names list matched name[%s]\n",
     616             :                            match_idx, smb_fname_str_dbg(smb_fname)));
     617             :         }
     618             : 
     619           0 :         new_template = talloc_asprintf(
     620             :                 state, "%s/%s",
     621             :                 dirname, smb_fname->base_name);
     622           0 :         if (new_template == NULL) {
     623           0 :                 DBG_ERR("talloc_asprintf(%s/%s) failed\n",
     624             :                         dirname, smb_fname_str_dbg(smb_fname));
     625           0 :                 return res;
     626             :         }
     627             : 
     628           0 :         if (replace_start != -1 && replace_end != -1) {
     629           0 :                 size_t dirofs = strlen(dirname) + 1;
     630           0 :                 new_start = dirofs + replace_start;
     631           0 :                 new_digits = replace_end - replace_start;
     632             :         }
     633             : 
     634           0 :         if (!preopen_parse_fname(new_template, &num,
     635             :                                  &new_start, &new_digits)) {
     636           0 :                 DBG_PREFIX(state->nodigits_dbglvl, (
     637             :                            "Pattern(idx=%zd) no valid digits found on fullpath[%s]\n",
     638             :                            match_idx, new_template));
     639           0 :                 TALLOC_FREE(new_template);
     640           0 :                 return res;
     641             :         }
     642           0 :         new_end = new_start + new_digits;
     643             : 
     644           0 :         DBG_PREFIX(state->founddigits_dbglvl, (
     645             :                    "Pattern(idx=%zd) found num_digits[%d] start_offset[%zd] parsed_num[%lu] fullpath[%s]\n",
     646             :                    match_idx, new_digits, new_start, num, new_template));
     647             : 
     648           0 :         if (state->last_match_idx != match_idx) {
     649             :                 /*
     650             :                  * If a different pattern caused the match
     651             :                  * we better reset the queue
     652             :                  */
     653           0 :                 if (state->last_match_idx != -1) {
     654           0 :                         DBG_PREFIX(state->reset_dbglvl, ("RESET: "
     655             :                                    "pattern changed from idx=%zd to idx=%zd by fullpath[%s]\n",
     656             :                                    state->last_match_idx, match_idx, new_template));
     657             :                 }
     658           0 :                 need_reset = true;
     659           0 :         } else if (state->number_start != new_start) {
     660             :                 /*
     661             :                  * If the digits started at a different possition
     662             :                  * we better reset the queue
     663             :                  */
     664           0 :                 DBG_PREFIX(state->reset_dbglvl, ("RESET: "
     665             :                            "start_offset changed from byte=%zd to byte=%zd by fullpath[%s]\n",
     666             :                            state->number_start, new_start, new_template));
     667           0 :                 need_reset = true;
     668           0 :         } else if (state->num_digits != new_digits) {
     669             :                 /*
     670             :                  * If number of digits changed
     671             :                  * we better reset the queue
     672             :                  */
     673           0 :                 DBG_PREFIX(state->reset_dbglvl, ("RESET: "
     674             :                            "num_digits changed %d to %d by fullpath[%s]\n",
     675             :                            state->num_digits, new_digits, new_template));
     676           0 :                 need_reset = true;
     677           0 :         } else if (strncmp(state->template_fname, new_template, new_start) != 0) {
     678             :                 /*
     679             :                  * If name before the digits changed
     680             :                  * we better reset the queue
     681             :                  */
     682           0 :                 DBG_PREFIX(state->reset_dbglvl, ("RESET: "
     683             :                            "leading pathprefix[%.*s] changed by fullpath[%s]\n",
     684             :                            (int)state->number_start, state->template_fname, new_template));
     685           0 :                 need_reset = true;
     686           0 :         } else if (strcmp(state->template_fname + new_end, new_template + new_end) != 0) {
     687             :                 /*
     688             :                  * If name after the digits changed
     689             :                  * we better reset the queue
     690             :                  */
     691           0 :                 DBG_PREFIX(state->reset_dbglvl, ("RESET: "
     692             :                            "trailing suffix[%s] changed by fullpath[%s]\n",
     693             :                            state->template_fname + new_end, new_template));
     694           0 :                 need_reset = true;
     695             :         }
     696             : 
     697           0 :         if (need_reset) {
     698             :                 /*
     699             :                  * Reset the queue
     700             :                  */
     701           0 :                 state->fnum_sent = 0;
     702           0 :                 state->fnum_queue_end = 0;
     703           0 :                 state->last_match_idx = match_idx;
     704             :         }
     705             : 
     706           0 :         TALLOC_FREE(state->template_fname);
     707           0 :         state->template_fname = new_template;
     708           0 :         state->number_start = new_start;
     709           0 :         state->num_digits = new_digits;
     710             : 
     711           0 :         if (num > state->fnum_sent) {
     712             :                 /*
     713             :                  * Helpers were too slow, there's no point in reading
     714             :                  * files in helpers that we already read in the
     715             :                  * parent.
     716             :                  */
     717           0 :                 state->fnum_sent = num;
     718             :         }
     719             : 
     720           0 :         if ((state->fnum_queue_end != 0) /* Something was started earlier */
     721           0 :             && (num < (state->fnum_queue_end - state->queue_max))) {
     722             :                 /*
     723             :                  * "num" is before the queue we announced. This means
     724             :                  * a new run is started.
     725             :                  */
     726           0 :                 state->fnum_sent = num;
     727             :         }
     728             : 
     729           0 :         num_max = num_digits_max_value(state->num_digits);
     730           0 :         state->fnum_queue_end = MIN(num_max, num + state->queue_max);
     731             : 
     732           0 :         DBG_PREFIX(state->queue_dbglvl, ("BEFORE: preopen_queue_run\n"));
     733           0 :         preopen_queue_run(state);
     734           0 :         DBG_PREFIX(state->queue_dbglvl, ("AFTER: preopen_queue_run\n"));
     735             : 
     736           0 :         return res;
     737             : }
     738             : 
     739             : static struct vfs_fn_pointers vfs_preopen_fns = {
     740             :         .openat_fn = preopen_openat,
     741             : };
     742             : 
     743             : static_decl_vfs;
     744          20 : NTSTATUS vfs_preopen_init(TALLOC_CTX *ctx)
     745             : {
     746             :         NTSTATUS status;
     747             : 
     748          20 :         status = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
     749             :                                   "preopen",
     750             :                                   &vfs_preopen_fns);
     751          20 :         if (!NT_STATUS_IS_OK(status)) {
     752           0 :                 return status;
     753             :         }
     754             : 
     755          20 :         vfs_preopen_debug_level = debug_add_class("preopen");
     756          20 :         if (vfs_preopen_debug_level == -1) {
     757           0 :                 vfs_preopen_debug_level = DBGC_VFS;
     758           0 :                 DBG_ERR("Couldn't register custom debugging class!\n");
     759             :         } else {
     760          20 :                 DBG_DEBUG("Debug class number of 'preopen': %d\n",
     761             :                           vfs_preopen_debug_level);
     762             :         }
     763             : 
     764          20 :         return NT_STATUS_OK;
     765             : }

Generated by: LCOV version 1.13