LCOV - code coverage report
Current view: top level - src/server/protocol2 - dpth.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 141 154 91.6 %
Date: 2017-10-31 Functions: 15 15 100.0 %

          Line data    Source code
       1             : #include "../../burp.h"
       2             : #include "../../alloc.h"
       3             : #include "../../cmd.h"
       4             : #include "../../fsops.h"
       5             : #include "../../hexmap.h"
       6             : #include "../../iobuf.h"
       7             : #include "../../lock.h"
       8             : #include "../../log.h"
       9             : #include "../../prepend.h"
      10             : #include "../../protocol2/blk.h"
      11             : #include "dpth.h"
      12             : 
      13          15 : static int get_data_lock(struct lock *lock, const char *path)
      14             : {
      15          15 :         int ret=-1;
      16          15 :         char *lockfile=NULL;
      17             :         // Use just the first three components, excluding sig number.
      18          15 :         if(!(lockfile=prepend(path, ".lock")))
      19             :                 goto end;
      20          15 :         if(lock_init(lock, lockfile)
      21          15 :           || build_path_w(lock->path))
      22             :                 goto end;
      23          15 :         lock_get_quick(lock);
      24          15 :         ret=0;
      25             : end:
      26          15 :         free_w(&lockfile);
      27          15 :         return ret;
      28             : }
      29             : 
      30             : static char *dpth_mk_prim(struct dpth *dpth)
      31             : {
      32             :         static char path[8];
      33          39 :         snprintf(path, sizeof(path), "%04X", dpth->comp[0]);
      34             :         return path;
      35             : }
      36             : 
      37             : static char *dpth_mk_seco(struct dpth *dpth)
      38             : {
      39             :         static char path[16];
      40          39 :         snprintf(path, sizeof(path), "%04X/%04X", dpth->comp[0], dpth->comp[1]);
      41             :         return path;
      42             : }
      43             : 
      44          11 : static struct dpth_lock *dpth_lock_alloc(const char *save_path)
      45             : {
      46             :         struct dpth_lock *dpth_lock;
      47          11 :         if(!(dpth_lock=(struct dpth_lock *)
      48             :                 calloc_w(1, sizeof(struct dpth_lock), __func__)))
      49             :                         return NULL;
      50          11 :         snprintf(dpth_lock->save_path, sizeof(dpth_lock->save_path),
      51             :                 "%s", save_path);
      52          11 :         return dpth_lock;
      53             : }
      54             : 
      55          11 : static int add_lock_to_list(struct dpth *dpth,
      56             :         struct lock *lock, const char *save_path)
      57             : {
      58             :         struct dpth_lock *dlnew;
      59          11 :         if(!(dlnew=dpth_lock_alloc(save_path))) return -1;
      60          11 :         dlnew->lock=lock;
      61             : 
      62             :         // Add to the end of the list.
      63          11 :         if(dpth->tail) dpth->tail->next=dlnew;
      64           8 :         else if(!dpth->head) dpth->head=dlnew;
      65          11 :         dpth->tail=dlnew;
      66             :         return 0;
      67             : }
      68             : 
      69        8538 : char *dpth_protocol2_get_save_path(struct dpth *dpth)
      70             : {
      71             :         static char save_path[32];
      72       34152 :         snprintf(save_path, sizeof(save_path), "%04X/%04X/%04X/%04X",
      73       34152 :                 dpth->comp[0], dpth->comp[1], dpth->comp[2], dpth->comp[3]);
      74        8538 :         return save_path;
      75             : }
      76             : 
      77        8527 : char *dpth_protocol2_mk(struct dpth *dpth)
      78             : {
      79        8527 :         char *p=NULL;
      80             :         static char *save_path=NULL;
      81             :         static struct lock *lock=NULL;
      82             :         struct stat statp;
      83             : 
      84             :         while(1)
      85             :         {
      86        8531 :                 free_w(&p);
      87        8531 :                 save_path=dpth_protocol2_get_save_path(dpth);
      88        8531 :                 if(!dpth->need_data_lock)
      89             :                         return save_path;
      90             : 
      91          15 :                 if(!lock && !(lock=lock_alloc()))
      92             :                         goto error;
      93             : 
      94             :                 // Use just the first three components, excluding sig number.
      95          15 :                 if(!(p=prepend_slash(dpth->base_path, save_path, 14)))
      96             :                         goto error;
      97             : 
      98          15 :                 if(get_data_lock(lock, p))
      99             :                         goto error;
     100             : 
     101          15 :                 switch(lock->status)
     102             :                 {
     103             :                         case GET_LOCK_GOT:
     104          28 :                                 if(lstat(p, &statp))
     105             :                                 {
     106             :                                         // File does not exist yet, and we
     107             :                                         // have the lock. All good.
     108             :                                         break;
     109             :                                 }
     110             :                                 // The file that we want to write already
     111             :                                 // exists.
     112           3 :                                 if(lock_release(lock))
     113             :                                         goto error;
     114           3 :                                 lock_free(&lock);
     115             :                                 // Fall through and try again.
     116             :                         case GET_LOCK_NOT_GOT:
     117             :                                 // Increment and try again.
     118           4 :                                 if(dpth_incr(dpth))
     119             :                                         goto error;
     120           4 :                                 continue;
     121             :                         case GET_LOCK_ERROR:
     122             :                         default:
     123             :                                 goto error;
     124             :                 }
     125             : 
     126          11 :                 dpth->need_data_lock=0; // Got it.
     127          11 :                 if(add_lock_to_list(dpth, lock, save_path))
     128             :                         goto error;
     129          11 :                 lock=NULL;
     130          11 :                 free_w(&p);
     131          11 :                 return save_path;
     132           4 :         }
     133             : error:
     134           0 :         free_w(&p);
     135           0 :         lock_free(&lock);
     136           0 :         return NULL;
     137             : }
     138             : 
     139             : // Returns 0 on OK, -1 on error. *max gets set to the next entry.
     140         153 : int get_highest_entry(const char *path, int *max, size_t len)
     141             : {
     142         153 :         int ent=0;
     143         153 :         int ret=0;
     144         153 :         DIR *d=NULL;
     145         153 :         struct dirent *dp=NULL;
     146             : 
     147         153 :         *max=-1;
     148         153 :         if(!(d=opendir(path))) goto end;
     149         229 :         while((dp=readdir(d)))
     150             :         {
     151         174 :                 if(!dp->d_ino
     152         174 :                   || strlen(dp->d_name)!=len)
     153         150 :                         continue;
     154          24 :                 ent=strtol(dp->d_name, NULL, 16);
     155          24 :                 if(ent>*max) *max=ent;
     156             :         }
     157             : 
     158             : end:
     159         153 :         if(d) closedir(d);
     160         153 :         return ret;
     161             : }
     162             : 
     163       16725 : int dpth_protocol2_incr_sig(struct dpth *dpth)
     164             : {
     165       16725 :         if(++dpth->comp[3]<DATA_FILE_SIG_MAX) return 0;
     166           9 :         dpth->comp[3]=0;
     167           9 :         dpth->need_data_lock=1;
     168           9 :         return dpth_incr(dpth);
     169             : }
     170             : 
     171          39 : static int open_cfile_fzp(struct dpth *dpth,
     172             :         const char *cname, const char *cfiles)
     173             : {
     174             :         int fd;
     175          39 :         int ret=-1;
     176          39 :         char *fname=NULL;
     177          39 :         char *fullpath=NULL;
     178             : 
     179          39 :         if(!(fname=prepend(cname, "XXXXXX")))
     180             :                 goto end;
     181          39 :         if(!(fullpath=prepend_s(cfiles, fname)))
     182             :                 goto end;
     183          39 :         errno=0;
     184          39 :         if(build_path_w(fullpath) && errno!=EEXIST)
     185             :                 goto end;
     186          39 :         if((fd=mkstemp(fullpath))<0)
     187             :         {
     188           0 :                 logp("Could not mkstemp from template %s: %s\n",
     189             :                         fullpath, strerror(errno));
     190             :                 goto end;
     191             :         }
     192          39 :         if(!(dpth->cfile_fzp=fzp_dopen(fd, "wb")))
     193             :                 goto end;
     194             : 
     195          39 :         ret=0;
     196             : end:
     197          39 :         free_w(&fname);
     198          39 :         free_w(&fullpath);
     199          39 :         return ret;
     200             : }
     201             : 
     202         117 : int dpth_protocol2_init(struct dpth *dpth, const char *base_path,
     203             :         const char *cname, const char *cfiles, int max_storage_subdirs)
     204             : {
     205             :         int max;
     206          39 :         int ret=0;
     207          39 :         char *tmp=NULL;
     208             : 
     209          39 :         if(!base_path)
     210             :         {
     211           0 :                 logp("No base_path supplied in %s()\n", __func__);
     212           0 :                 goto error;
     213             :         }
     214             : 
     215          39 :         if(open_cfile_fzp(dpth, cname, cfiles)) goto error;
     216             : 
     217          39 :         dpth->max_storage_subdirs=max_storage_subdirs;
     218             : 
     219          39 :         free_w(&dpth->base_path);
     220          39 :         if(!(dpth->base_path=strdup_w(base_path, __func__)))
     221             :                 goto error;
     222             : 
     223          39 :         dpth->savepath=0;
     224          39 :         dpth->need_data_lock=1;
     225             : 
     226          39 :         if(get_highest_entry(dpth->base_path, &max, 4))
     227             :                 goto error;
     228          39 :         if(max<0) max=0;
     229          39 :         dpth->comp[0]=max;
     230          78 :         tmp=dpth_mk_prim(dpth);
     231          39 :         if(!(tmp=prepend_s(dpth->base_path, tmp)))
     232             :                 goto error;
     233             : 
     234          39 :         if(get_highest_entry(tmp, &max, 4))
     235             :                 goto error;
     236          39 :         if(max<0) max=0;
     237          39 :         dpth->comp[1]=max;
     238          39 :         free_w(&tmp);
     239         117 :         tmp=dpth_mk_seco(dpth);
     240          39 :         if(!(tmp=prepend_s(dpth->base_path, tmp)))
     241             :                 goto error;
     242             : 
     243          39 :         if(get_highest_entry(tmp, &max, 4))
     244             :                 goto error;
     245          39 :         if(max<0)
     246             :         {
     247          31 :                 dpth->comp[2]=0;
     248             :         }
     249             :         else
     250             :         {
     251           8 :                 dpth->comp[2]=max;
     252           8 :                 if(dpth_incr(dpth)) goto error;
     253             :         }
     254             : 
     255             :         goto end;
     256             : error:
     257             :         ret=-1;
     258             : end:
     259          39 :         free_w(&tmp);
     260          39 :         return ret;
     261             : }
     262             : 
     263       16713 : static int fprint_tag(struct fzp *fzp, enum cmd cmd, unsigned int s)
     264             : {
     265       16713 :         if(fzp_printf(fzp, "%c%04X", cmd, s)!=5)
     266             :         {
     267           0 :                 logp("Short fprintf\n");
     268           0 :                 return -1;
     269             :         }
     270             :         return 0;
     271             : }
     272             : 
     273       16713 : static int fwrite_buf(enum cmd cmd,
     274             :         const char *buf, unsigned int s, struct fzp *fzp)
     275             : {
     276             :         static size_t bytes;
     277       16713 :         if(fprint_tag(fzp, cmd, s)) return -1;
     278       16713 :         if((bytes=fzp_write(fzp, buf, s))!=s)
     279             :         {
     280           0 :                 logp("Short write: %d\n", (int)bytes);
     281           0 :                 return -1;
     282             :         }
     283             :         return 0;
     284             : }
     285             : 
     286           9 : static struct fzp *file_open_w(const char *path)
     287             : {
     288           9 :         if(build_path_w(path)) return NULL;
     289           9 :         return fzp_open(path, "wb");
     290             : }
     291             : 
     292           9 : static int write_to_cfile(struct dpth *dpth, struct blk *blk)
     293             : {
     294             :         struct iobuf wbuf;
     295           9 :         blk_to_iobuf_savepath(blk, &wbuf);
     296           9 :         if(iobuf_send_msg_fzp(&wbuf, dpth->cfile_fzp))
     297             :                 return -1;
     298           9 :         if(fzp_flush(dpth->cfile_fzp))
     299             :                 return -1;
     300           9 :         if(fsync(fzp_fileno(dpth->cfile_fzp)))
     301             :         {
     302           0 :                 logp("fsync on cfile_fzp failed: %s\n", strerror(errno));
     303             :                 return -1;
     304             :         }
     305             :         return 0;
     306             : }
     307             : 
     308           9 : static struct fzp *open_data_file_for_write(struct dpth *dpth, struct blk *blk)
     309             : {
     310           9 :         char *path=NULL;
     311           9 :         struct fzp *fzp=NULL;
     312           9 :         char *savepathstr=NULL;
     313           9 :         struct dpth_lock *head=dpth->head;
     314             : 
     315           9 :         savepathstr=uint64_to_savepathstr(blk->savepath);
     316             : 
     317             :         // Sanity check. They should be coming through from the client
     318             :         // in the same order in which we locked them.
     319             :         // Remember that the save_path on the lock list is shorter than the
     320             :         // full save_path on the blk.
     321           9 :         if(!head
     322           9 :           || strncmp(head->save_path,
     323             :                 //FIX THIS
     324             :                 savepathstr, sizeof(head->save_path)-1))
     325             :         {
     326           0 :                 logp("lock and block save_path mismatch: %s %s\n",
     327             :                         head?head->save_path:"(null)", savepathstr);
     328           0 :                 goto end;
     329             :         }
     330             : 
     331           9 :         if(!(path=prepend_slash(dpth->base_path, savepathstr, 14)))
     332             :                 goto end;
     333           9 :         if(write_to_cfile(dpth, blk))
     334             :                 goto end;
     335           9 :         fzp=file_open_w(path);
     336             : end:
     337           9 :         free_w(&path);
     338           9 :         return fzp;
     339             : }
     340             : 
     341       16713 : int dpth_protocol2_fwrite(struct dpth *dpth,
     342             :         struct iobuf *iobuf, struct blk *blk)
     343             : {
     344             :         // Remember that the save_path on the lock list is shorter than the
     345             :         // full save_path on the blk.
     346       16713 :         if(dpth->fzp
     347       16705 :           && strncmp(dpth->head->save_path,
     348             :                 uint64_to_savepathstr(blk->savepath),
     349             :                 sizeof(dpth->head->save_path)-1)
     350           1 :           && dpth_release_and_move_to_next_in_list(dpth))
     351             :                 return -1;
     352             : 
     353             :         // Open the current list head if we have no fzp.
     354       16713 :         if(!dpth->fzp
     355           9 :           && !(dpth->fzp=open_data_file_for_write(dpth, blk))) return -1;
     356             : 
     357       16713 :         return fwrite_buf(CMD_DATA, iobuf->buf, iobuf->len, dpth->fzp);
     358             : }

Generated by: LCOV version 1.10