LCOV - code coverage report
Current view: top level - src - fsops.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 181 226 80.1 %
Date: 2017-10-31 Functions: 28 30 93.3 %

          Line data    Source code
       1             : #include "burp.h"
       2             : #include "alloc.h"
       3             : #include "fsops.h"
       4             : #include "fzp.h"
       5             : #include "log.h"
       6             : #include "pathcmp.h"
       7             : #include "prepend.h"
       8             : 
       9             : #ifndef HAVE_WIN32
      10             : #include <sys/un.h>
      11             : #endif
      12             : 
      13             : uint32_t fs_name_max=0;
      14             : uint32_t fs_full_path_max=0;
      15             : static uint32_t fs_path_max=0;
      16             : 
      17         365 : void close_fd(int *fd)
      18             : {
      19         730 :         if(!fd || *fd<0) return;
      20             :         //logp("closing %d\n", *fd);
      21         365 :         close(*fd);
      22         365 :         *fd=-1;
      23             : }
      24             : 
      25           4 : int is_dir_lstat(const char *path)
      26             : {
      27             :         struct stat buf;
      28           4 :         if(lstat(path, &buf))
      29             :                 return -1;
      30           4 :         return S_ISDIR(buf.st_mode);
      31             : }
      32             : 
      33          81 : int is_reg_lstat(const char *path)
      34             : {
      35             :         struct stat buf;
      36          81 :         if(lstat(path, &buf))
      37             :                 return -1;
      38           5 :         return S_ISREG(buf.st_mode);
      39             : }
      40             : 
      41        5440 : int is_dir(const char *path, struct dirent *d)
      42             : {
      43             : #ifdef _DIRENT_HAVE_D_TYPE
      44             :         // Faster evaluation on most systems.
      45        5440 :         switch(d->d_type)
      46             :         {
      47             :                 case DT_DIR:
      48             :                         return 1;
      49             :                 case DT_UNKNOWN:
      50             :                         break;
      51             :                 default:
      52        2746 :                         return 0;
      53             :         }
      54             : #endif
      55           0 :         return is_dir_lstat(path);
      56             : }
      57             : 
      58        5065 : int mkpath(char **rpath, const char *limit)
      59             : {
      60        5065 :         int ret=-1;
      61        5065 :         char *cp=NULL;
      62             :         struct stat buf;
      63             : #ifdef HAVE_WIN32
      64             :         int windows_stupidity=0;
      65             : #endif
      66        5065 :         if((cp=strrchr(*rpath, '/')))
      67             :         {
      68        4119 :                 *cp='\0';
      69             : #ifdef HAVE_WIN32
      70             :                 if(strlen(*rpath)==2 && (*rpath)[1]==':')
      71             :                 {
      72             :                         (*rpath)[1]='\0';
      73             :                         windows_stupidity++;
      74             :                 }
      75             : #endif
      76        4119 :                 if(!**rpath)
      77             :                 {
      78             :                         // We are down to the root, which is OK.
      79             :                 }
      80        8238 :                 else if(lstat(*rpath, &buf))
      81             :                 {
      82             :                         // does not exist - recurse further down, then come
      83             :                         // back and try to mkdir it.
      84        2169 :                         if(mkpath(rpath, limit)) goto end;
      85             : 
      86             :                         // Require that the user has set up the required paths
      87             :                         // on the server correctly. I have seen problems with
      88             :                         // part of the path being a temporary symlink that
      89             :                         // gets replaced by burp with a proper directory.
      90             :                         // Allow it to create the actual directory specified,
      91             :                         // though.
      92             : 
      93             :                         // That is, if limit is:
      94             :                         // /var/spool/burp
      95             :                         // and /var/spool exists, the directory will be
      96             :                         // created.
      97             :                         // If only /var exists, the directory will not be
      98             :                         // created.
      99             : 
     100             :                         // Caller can give limit=NULL to create the whole
     101             :                         // path with no limit, as in a restore.
     102        2166 :                         if(limit && pathcmp(*rpath, limit)<0)
     103             :                         {
     104           1 :                                 logp("will not mkdir %s\n", *rpath);
     105           1 :                                 goto end;
     106             :                         }
     107        2165 :                         if(mkdir(*rpath, 0777))
     108             :                         {
     109           0 :                                 logp("could not mkdir %s: %s\n", *rpath, strerror(errno));
     110           0 :                                 goto end;
     111             :                         }
     112             :                 }
     113        1950 :                 else if(S_ISDIR(buf.st_mode))
     114             :                 {
     115             :                         // Is a directory - can put the slash back and return.
     116             :                 }
     117          39 :                 else if(S_ISLNK(buf.st_mode))
     118             :                 {
     119             :                         // to help with the 'current' symlink
     120             :                 }
     121             :                 else
     122             :                 {
     123             :                         // something funny going on
     124           0 :                         logp("warning: wanted '%s' to be a directory\n",
     125             :                                 *rpath);
     126             :                 }
     127             :         }
     128             : 
     129             :         ret=0;
     130             : end:
     131             : #ifdef HAVE_WIN32
     132             :         if(windows_stupidity) (*rpath)[1]=':';
     133             : #endif
     134        5065 :         if(cp) *cp='/';
     135        5065 :         return ret;
     136             : }
     137             : 
     138        2791 : int build_path(const char *datadir, const char *fname, char **rpath, const char *limit)
     139             : {
     140             :         //logp("build path: '%s/%s'\n", datadir, fname);
     141        2791 :         if(!(*rpath=prepend_s(datadir, fname))) return -1;
     142        2791 :         if(mkpath(rpath, limit))
     143             :         {
     144           0 :                 free_w(rpath);
     145           0 :                 return -1;
     146             :         }
     147             :         return 0;
     148             : }
     149             : 
     150         328 : int do_rename(const char *oldpath, const char *newpath)
     151             : {
     152             :         // Be careful, this is not actually atomic. Everything that uses this
     153             :         // needs to deal with the consequences.
     154         328 :         if(rename(oldpath, newpath))
     155             :         {
     156           0 :                 logp("could not rename '%s' to '%s': %s\n",
     157           0 :                         oldpath, newpath, strerror(errno)); 
     158           0 :                 return -1; 
     159             :         }
     160             :         return 0;
     161             : }
     162             : 
     163        2763 : int build_path_w(const char *path)
     164             : {
     165             :         int ret;
     166        2763 :         char *rpath=NULL;
     167        2763 :         ret=build_path(path, "", &rpath, NULL);
     168        2763 :         free_w(&rpath);
     169        2763 :         return ret;
     170             : }
     171             : 
     172             : #define RECDEL_ERROR                    -1
     173             : #define RECDEL_OK                       0
     174             : #define RECDEL_ENTRIES_REMAINING        1
     175             : 
     176        2309 : static void get_max(int32_t *max, int32_t default_max)
     177             : {
     178        2309 :         *max = pathconf(".", default_max);
     179        2309 :         if(*max < 1024) *max = 1024;
     180             :         // Add for EOS.
     181        2309 :         (*max)++;
     182        2309 : }
     183             : 
     184        4935 : static int do_recursive_delete(const char *d, const char *file,
     185             :         uint8_t delfiles, int32_t name_max,
     186             :         uint8_t ignore_not_empty_errors)
     187             : {
     188        4935 :         int ret=RECDEL_ERROR;
     189        4935 :         DIR *dirp=NULL;
     190        4935 :         struct dirent *entry=NULL;
     191             :         struct stat statp;
     192        4935 :         char *directory=NULL;
     193        4935 :         char *fullpath=NULL;
     194             : 
     195        4935 :         if(!file)
     196             :         {
     197        2309 :                 if(!(directory=prepend_s(d, "")))
     198             :                         goto end;
     199             :         }
     200        2626 :         else if(!(directory=prepend_s(d, file)))
     201             :         {
     202           0 :                 log_out_of_memory(__func__);
     203           0 :                 goto end;
     204             :         }
     205             : 
     206        9870 :         if(lstat(directory, &statp))
     207             :         {
     208             :                 // path does not exist.
     209             :                 ret=RECDEL_OK;
     210             :                 goto end;
     211             :         }
     212             : 
     213        3447 :         if(!(dirp=opendir(directory)))
     214             :         {
     215           0 :                 logp("opendir %s in %s: %s\n",
     216           0 :                         directory, __func__, strerror(errno));
     217           0 :                 goto end;
     218             :         }
     219             : 
     220             :         while(1)
     221             :         {
     222       15673 :                 errno=0;
     223       15673 :                 if(!(entry=readdir(dirp)))
     224             :                 {
     225        3447 :                         if(errno)
     226             :                         {
     227           0 :                                 logp("error in readdir in %s: %s\n",
     228             :                                         __func__, strerror(errno));
     229           0 :                                 goto end;
     230             :                         }
     231             :                         // Got to the end of the directory.
     232        3447 :                         ret=RECDEL_OK;
     233             :                         break;
     234             :                 }
     235             : 
     236       12226 :                 if(!filter_dot(entry))
     237        6894 :                         continue;
     238        5332 :                 free_w(&fullpath);
     239        5332 :                 if(!(fullpath=prepend_s(directory, entry->d_name)))
     240             :                         goto end;
     241             : 
     242        5332 :                 if(is_dir(fullpath, entry)>0)
     243             :                 {
     244             :                         int r;
     245        2626 :                         if((r=do_recursive_delete(directory, entry->d_name,
     246             :                                 delfiles, name_max,
     247             :                                 ignore_not_empty_errors))==RECDEL_ERROR)
     248             :                                         goto end;
     249             :                         // do not overwrite ret with OK if it previously
     250             :                         // had ENTRIES_REMAINING
     251        2626 :                         if(r==RECDEL_ENTRIES_REMAINING) ret=r;
     252             :                 }
     253        2706 :                 else if(delfiles)
     254             :                 {
     255        2706 :                         if(unlink(fullpath))
     256             :                         {
     257           0 :                                 logp("unlink %s: %s\n",
     258             :                                         fullpath, strerror(errno));
     259           0 :                                 ret=RECDEL_ENTRIES_REMAINING;
     260             :                         }
     261             :                 }
     262             :                 else
     263             :                 {
     264             :                         ret=RECDEL_ENTRIES_REMAINING;
     265             :                 }
     266             :         }
     267             : 
     268        3447 :         if(ret==RECDEL_OK && rmdir(directory))
     269             :         {
     270           0 :                 if(errno!=ENOTEMPTY || !ignore_not_empty_errors)
     271             :                 {
     272           0 :                         logp("rmdir %s: %s\n", directory, strerror(errno));
     273           0 :                         ret=RECDEL_ERROR;
     274             :                 }
     275             :         }
     276             : end:
     277        4935 :         if(dirp) closedir(dirp);
     278        4935 :         free_w(&fullpath);
     279        4935 :         free_w(&directory);
     280        4935 :         return ret;
     281             : }
     282             : 
     283        2309 : static int do_recursive_delete_w(const char *path, uint8_t delfiles,
     284             :         uint8_t ignore_not_empty_errors)
     285             : {
     286             :         int32_t name_max;
     287        2309 :         get_max(&name_max, _PC_NAME_MAX);
     288        2309 :         return do_recursive_delete(path,
     289             :                 NULL, delfiles, name_max, ignore_not_empty_errors);
     290             : }
     291             : 
     292        2303 : int recursive_delete(const char *path)
     293             : {
     294             :         struct stat statp;
     295             :         // We might have been given a file entry, instead of a directory.
     296        2303 :         if(!lstat(path, &statp) && !S_ISDIR(statp.st_mode))
     297             :         {
     298         156 :                 if(unlink(path))
     299             :                 {
     300           0 :                         logp("unlink %s: %s\n", path, strerror(errno));
     301           0 :                         return RECDEL_ENTRIES_REMAINING;
     302             :                 }
     303             :         }
     304        2303 :         return do_recursive_delete_w(path, 1, 0/*ignore_not_empty_errors*/);
     305             : }
     306             : 
     307           2 : int recursive_delete_dirs_only(const char *path)
     308             : {
     309           2 :         return do_recursive_delete_w(path, 0, 0/*ignore_not_empty_errors*/);
     310             : }
     311             : 
     312           4 : int recursive_delete_dirs_only_no_warnings(const char *path)
     313             : {
     314           4 :         return do_recursive_delete_w(path, 0, 1/*ignore_not_empty_errors*/);
     315             : }
     316             : 
     317           0 : int unlink_w(const char *path, const char *func)
     318             : {
     319           0 :         if(unlink(path))
     320             :         {
     321           0 :                 logp("unlink(%s) called from %s(): %s\n",
     322           0 :                         path, func, strerror(errno));
     323           0 :                 return -1;
     324             :         }
     325             :         return 0;
     326             : }
     327             : 
     328             : static void init_max(const char *path,
     329             :         uint32_t *max, int what, uint32_t default_max)
     330             : {
     331          14 :         *max=pathconf(path?path:".", what);
     332          14 :         if(*max<default_max) *max=default_max;
     333             : }
     334             : 
     335           7 : int init_fs_max(const char *path)
     336             : {
     337             :         struct stat statp;
     338           7 :         if(stat(path, &statp))
     339             :         {
     340           0 :                 logp("Path %s does not exist in %s\n", path, __func__);
     341           0 :                 return -1;
     342             :         }
     343             :         // Get system path and filename maximum lengths.
     344             :         init_max(path, &fs_path_max, _PC_PATH_MAX, 1024);
     345             :         init_max(path, &fs_name_max, _PC_NAME_MAX, 255);
     346           7 :         fs_full_path_max=fs_path_max+fs_name_max;
     347           7 :         return 0;
     348             : }
     349             : 
     350         109 : int looks_like_tmp_or_hidden_file(const char *filename)
     351             : {
     352         109 :         if(!filename) return 0;
     353         109 :         if(filename[0]=='.' // Also avoids '.' and '..'.
     354             :           // I am told that emacs tmp files end with '~'.
     355         108 :           || filename[strlen(filename)-1]=='~')
     356             :                 return 1;
     357         107 :         return 0;
     358             : }
     359             : 
     360          24 : static int do_get_entries_in_directory(DIR *directory, char ***nl,
     361             :         int *count, int (*compar)(const void *, const void *))
     362             : {
     363          24 :         int allocated=0;
     364          24 :         char **ntmp=NULL;
     365          24 :         struct dirent *result=NULL;
     366             : 
     367          24 :         *count=0;
     368             : 
     369             :         // This here is doing a funky kind of scandir/alphasort
     370             :         // that can also run on Windows.
     371             :         while(1)
     372             :         {
     373         135 :                 errno=0;
     374         135 :                 if(!(result=readdir(directory)))
     375             :                 {
     376          24 :                         if(errno)
     377             :                         {
     378           0 :                                 logp("error in readdir: %s\n",
     379             :                                         strerror(errno));
     380           0 :                                 goto error;
     381             :                         }
     382             :                         break;
     383             :                 }
     384             : 
     385         111 :                 if(!filter_dot(result))
     386          48 :                         continue;
     387             : 
     388          63 :                 if(*count==allocated)
     389             :                 {
     390          18 :                         if(!allocated) allocated=10;
     391           0 :                         else allocated*=2;
     392             : 
     393          18 :                         if(!(ntmp=(char **)
     394          18 :                           realloc_w(*nl, allocated*sizeof(**nl), __func__)))
     395             :                                 goto error;
     396          18 :                         *nl=ntmp;
     397             :                 }
     398          63 :                 if(!((*nl)[(*count)++]=strdup_w(result->d_name, __func__)))
     399             :                         goto error;
     400             :         }
     401          24 :         if(*nl && compar)
     402          18 :                 qsort(*nl, *count, sizeof(**nl), compar);
     403             :         return 0;
     404             : error:
     405           0 :         if(*nl)
     406             :         {
     407             :                 int i;
     408           0 :                 for(i=0; i<*count; i++)
     409           0 :                         free_w(&((*nl)[i]));
     410           0 :                 free_v((void **)nl);
     411             :         }
     412             :         return -1;
     413             : }
     414             : 
     415          24 : static int entries_in_directory(const char *path, char ***nl,
     416             :         int *count, int atime,
     417             :         int (*compar)(const char **, const char **))
     418             : {
     419          24 :         int ret=0;
     420          24 :         DIR *directory=NULL;
     421             : 
     422          24 :         if(!fs_name_max)
     423             :         {
     424             :                 // Get system path and filename maximum lengths.
     425             :                 // FIX THIS: maybe this should be done every time a file system
     426             :                 // is crossed?
     427           2 :                 if(init_fs_max(path)) return -1;
     428             :         }
     429             : #if defined(O_DIRECTORY) && defined(O_NOATIME)
     430          24 :         int dfd=-1;
     431          24 :         if((dfd=open(path, O_RDONLY|O_DIRECTORY|atime?0:O_NOATIME))<0
     432          24 :           || !(directory=fdopendir(dfd)))
     433             : #else
     434             : // Mac OS X appears to have no O_NOATIME and no fdopendir(), so it should
     435             : // end up using opendir() here.
     436             :         if(!(directory=opendir(path)))
     437             : #endif
     438             :         {
     439             : #if defined(O_DIRECTORY) && defined(O_NOATIME)
     440             :                 close_fd(&dfd);
     441             : #endif
     442             :                 ret=1;
     443             :         }
     444             :         else
     445             :         {
     446          24 :                 if(do_get_entries_in_directory(directory, nl, count,
     447             :                         (int (*)(const void *, const void *))compar))
     448           0 :                                 ret=-1;
     449             :         }
     450          24 :         if(directory) closedir(directory);
     451             :         return ret;
     452             : }
     453             : 
     454       14752 : int filter_dot(const struct dirent *d)
     455             : {
     456       14752 :         if(!d->d_name
     457       14752 :           || !strcmp(d->d_name, ".")
     458       10924 :           || !strcmp(d->d_name, ".."))
     459             :                 return 0;
     460        7096 :         return 1;
     461             : }
     462             : 
     463          81 : static int my_alphasort(const char **a, const char **b)
     464             : {
     465          81 :         return pathcmp(*a, *b);
     466             : }
     467             : 
     468          24 : int entries_in_directory_alphasort(const char *path, char ***nl,
     469             :         int *count, int atime)
     470             : {
     471          24 :         return entries_in_directory(path, nl, count, atime, my_alphasort);
     472             : }
     473             : 
     474             : #define FULL_CHUNK      4096
     475             : 
     476          13 : int files_equal(const char *opath, const char *npath, int compressed)
     477             : {
     478          13 :         int ret=0;
     479             :         size_t ogot;
     480             :         size_t ngot;
     481          13 :         unsigned int i=0;
     482          13 :         struct fzp *ofp=NULL;
     483          13 :         struct fzp *nfp=NULL;
     484             :         static char obuf[FULL_CHUNK];
     485             :         static char nbuf[FULL_CHUNK];
     486             : 
     487          13 :         if(compressed)
     488             :         {
     489           5 :                 ofp=fzp_gzopen(opath, "rb");
     490           5 :                 nfp=fzp_gzopen(npath, "rb");
     491             :         }
     492             :         else
     493             :         {
     494           8 :                 ofp=fzp_open(opath, "rb");
     495           8 :                 nfp=fzp_open(npath, "rb");
     496             :         }
     497             : 
     498          13 :         if(!ofp && !nfp)
     499             :         {
     500             :                 ret=1;
     501             :                 goto end;
     502             :         }
     503          13 :         if(!ofp && nfp)
     504             :                 goto end;
     505          13 :         if(!nfp && ofp)
     506             :                 goto end;
     507             : 
     508             :         while(1)
     509             :         {
     510          13 :                 ogot=fzp_read(ofp, obuf, FULL_CHUNK);
     511          13 :                 ngot=fzp_read(nfp, nbuf, FULL_CHUNK);
     512          13 :                 if(ogot!=ngot)
     513             :                         goto end;
     514        9241 :                 for(i=0; i<ogot; i++)
     515             :                 {
     516        9241 :                         if(obuf[i]!=nbuf[i])
     517             :                                 goto end;
     518             :                 }
     519          13 :                 if(ogot<FULL_CHUNK)
     520             :                         break;
     521             :         }
     522             :         ret=1;
     523             : end:
     524          13 :         fzp_close(&ofp);
     525          13 :         fzp_close(&nfp);
     526          13 :         return ret;
     527             : }
     528             : 
     529             : #ifndef HAVE_WIN32
     530           1 : int mksock(const char *path)
     531             : {
     532           1 :         int fd=-1;
     533           1 :         int ret=-1;
     534             :         struct sockaddr_un addr;
     535             :         memset(&addr, 0, sizeof(addr));
     536           1 :         addr.sun_family=AF_UNIX;
     537             :         strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
     538           1 :         if((fd=socket(addr.sun_family, SOCK_STREAM, 0))<0
     539           1 :           || (bind(fd, (struct sockaddr *)&addr, sizeof(addr)))<0)
     540             :                 goto end;
     541           1 :         ret=0;
     542             : end:
     543           1 :         if(fd>=0) close(fd);
     544           1 :         return ret;
     545             : }
     546             : 
     547          63 : int is_lnk_lstat(const char *path)
     548             : {
     549             :         struct stat buf;
     550          63 :         if(lstat(path, &buf))
     551             :                 return -1;
     552           0 :         return S_ISLNK(buf.st_mode);
     553             : }
     554             : 
     555           0 : int is_lnk_valid(const char *path)
     556             : {
     557             :         struct stat buf;
     558           0 :         if(stat(path, &buf))
     559             :                 return 0;
     560           0 :         return 1;
     561             : }
     562             : 
     563           6 : int do_symlink(const char *oldpath, const char *newpath)
     564             : {
     565           6 :         if(!symlink(oldpath, newpath))
     566             :                 return 0;
     567           0 :         logp("could not symlink '%s' to '%s': %s\n",
     568           0 :                 newpath, oldpath, strerror(errno));
     569           0 :         return -1;
     570             : }
     571             : 
     572         309 : static int do_readlink(const char *path, char buf[], size_t buflen)
     573             : {
     574             :         ssize_t len;
     575         618 :         if((len=readlink(path, buf, buflen-1))<0)
     576             :                 return -1;
     577         309 :         buf[len]='\0';
     578         309 :         return 0;
     579             : }
     580             : 
     581         881 : int readlink_w(const char *path, char buf[], size_t buflen)
     582             : {
     583             :         struct stat statp;
     584         881 :         if(lstat(path, &statp))
     585             :                 return -1;
     586         309 :         if(S_ISLNK(statp.st_mode))
     587         309 :                 return do_readlink(path, buf, buflen);
     588             :         return -1;
     589             : }
     590             : 
     591         872 : int readlink_w_in_dir(const char *dir, const char *lnk,
     592             :         char buf[], size_t buflen)
     593             : {
     594         872 :         char *tmp=NULL;
     595         872 :         if(!(tmp=prepend_s(dir, lnk)))
     596             :                 return -1;
     597         872 :         readlink_w(tmp, buf, buflen);
     598         872 :         free_w(&tmp);
     599         872 :         return 0;
     600             : }
     601             : 
     602             : #endif

Generated by: LCOV version 1.10