"Fossies" - the Fresh Open Source Software Archive

Member "srm-1.2.15/src/sunlink.c" (26 Feb 2015, 27479 Bytes) of package /linux/privat/srm-1.2.15.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sunlink.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.2.14_vs_1.2.15.

    1 /* this file is part of srm http://srm.sourceforge.net/
    2    It is licensed under the MIT/X11 license */
    3 
    4 #include "config.h"
    5 
    6 #ifdef _MSC_VER
    7 #include "AltStreams.h"
    8 #endif
    9 
   10 #include <errno.h>
   11 #include <fcntl.h>
   12 #include <stdarg.h>
   13 #include <stdio.h>
   14 #include <stdlib.h>
   15 #include <string.h>
   16 #include <sys/stat.h>
   17 #include <sys/types.h>
   18 #include <time.h>
   19 #include <unistd.h>
   20 
   21 #if defined(__unix__)
   22 #include <sys/ioctl.h>
   23 #include <stdint.h>
   24 #endif
   25 
   26 #ifdef HAVE_SYS_VFS_H
   27 #include <sys/vfs.h>
   28 #endif
   29 
   30 #if defined(__APPLE__)
   31 #include <sys/disk.h>
   32 #include <sys/paths.h>
   33 #endif
   34 
   35 #if defined(HAVE_SYS_PARAM_H) && defined(HAVE_SYS_MOUNT_H)
   36 #include <sys/param.h>
   37 #include <sys/mount.h>
   38 #endif
   39 
   40 #if defined(HAVE_LINUX_EXT3_FS_H)
   41 #include <linux/fs.h>
   42 #include <linux/ext3_fs.h>
   43 
   44 #define EXT2_IOC_GETFLAGS EXT3_IOC_GETFLAGS
   45 #define EXT2_UNRM_FL EXT3_UNRM_FL
   46 #define EXT2_IMMUTABLE_FL EXT3_IMMUTABLE_FL
   47 #define EXT2_APPEND_FL EXT3_APPEND_FL
   48 #define EXT2_IOC_SETFLAGS EXT3_IOC_SETFLAGS
   49 #define EXT2_SECRM_FL EXT3_SECRM_FL
   50 #define EXT2_IOC_SETFLAGS EXT3_IOC_SETFLAGS
   51 #ifndef EXT2_SUPER_MAGIC
   52 #define EXT2_SUPER_MAGIC EXT3_SUPER_MAGIC
   53 #endif
   54 
   55 #elif defined(HAVE_LINUX_EXT2_FS_H)
   56 #include <linux/fs.h>
   57 #include <linux/ext2_fs.h>
   58 #endif
   59 
   60 #if defined(HAVE_ATTR_XATTR_H)
   61 #include <attr/xattr.h>
   62 #undef HAVE_SYS_XATTR_H
   63 #undef HAVE_SYS_EXTATTR_H
   64 #elif defined(HAVE_SYS_XATTR_H)
   65 #include <sys/xattr.h>
   66 #undef HAVE_SYS_EXTATTR_H
   67 #elif defined(HAVE_SYS_EXTATTR_H)
   68 #include <sys/extattr.h>
   69 #include <libutil.h>
   70 #endif
   71 
   72 #include "srm.h"
   73 #include "impl.h"
   74 
   75 #ifndef O_SYNC
   76 #define O_SYNC 0
   77 #endif
   78 #ifndef _O_BINARY
   79 #define _O_BINARY 0
   80 #endif
   81 
   82 #define KiB 1024
   83 #define MiB (KiB*KiB)
   84 #define GiB (KiB*KiB*KiB)
   85 
   86 #ifdef _MSC_VER
   87 typedef long long my_off_t;
   88 #else
   89 typedef off_t my_off_t;
   90 #endif
   91 
   92 struct srm_target
   93 {
   94   int fd;
   95   const char* file_name;
   96   my_off_t file_size;
   97   unsigned char *buffer;
   98   unsigned buffer_size;
   99   int options;
  100 };
  101 
  102 static volatile int SIGINT_received = 0;
  103 #if defined(__unix__)
  104 #include <signal.h>
  105 #if defined(__linux__) && !defined(__USE_GNU)
  106 typedef __sighandler_t sighandler_t;
  107 #endif
  108 #if defined(__FreeBSD__) || defined(__OpenBSD__)
  109 typedef sig_t sighandler_t;
  110 #endif
  111 
  112 static void sigint_handler(int signo)
  113 {
  114   SIGINT_received = signo;
  115 }
  116 int sunlink_impl(const char *path, const int options);
  117 
  118 int sunlink(const char *path, const int options)
  119 {
  120 #ifdef SIGUSR2
  121   sighandler_t usr2=signal(SIGUSR2, sigint_handler);
  122 #endif
  123 #ifdef SIGINFO
  124   sighandler_t info=signal(SIGINFO, sigint_handler);
  125 #endif
  126 #ifdef SIGPIPE
  127   sighandler_t pipe=signal(SIGPIPE, SIG_IGN);
  128 #endif
  129 
  130   int ret=sunlink_impl(path, options);
  131 
  132 #ifdef SIGPIPE
  133   signal(SIGPIPE, pipe);
  134 #endif
  135 #ifdef SIGINFO
  136   signal(SIGINFO, info);
  137 #endif
  138 #ifdef SIGUSR2
  139   signal(SIGUSR2, usr2);
  140 #endif
  141   return ret;
  142 }
  143 
  144 #else /* __unix__ */
  145 #define sunlink_impl sunlink
  146 #endif
  147 
  148 /**
  149    writes a buffer to a file descriptor. Ensures that the complete
  150    buffer is written.
  151 
  152    ripped from Advanced Programming in the Unix Environment by Richard Stevens
  153 
  154    @param fd file descriptor
  155    @param buf pointer to a buffer
  156    @param count size of buf in bytes
  157 
  158    @return upon success the number of bytes written, upon error the negative return code from write() (see the errno variable for details)
  159 */
  160 static ssize_t writen(const int fd, const void* buf, const size_t count)
  161 {
  162   const char *ptr=(const char*)buf;
  163   size_t nleft=count;
  164 
  165   if(fd<0 || !buf) return -1;
  166 
  167   while(nleft > 0)
  168     {
  169       ssize_t nwritten;
  170       if( (nwritten=write(fd, ptr, nleft)) < 0)
  171     return nwritten;
  172       nleft -= nwritten;
  173       ptr   += nwritten;
  174     }
  175 
  176   return count;
  177 }
  178 
  179 static void flush(int fd)
  180 {
  181   /* force buffered writes to be flushed to disk */
  182 #if defined F_FULLFSYNC
  183   /* F_FULLFSYNC is equivalent to fsync plus device flush to media */
  184   if (fcntl(fd, F_FULLFSYNC, NULL) != 0) {
  185     /* we're not on a fs that supports this; fall back to plain fsync */
  186     fsync(fd);
  187   }
  188 #elif HAVE_FDATASYNC
  189   fdatasync(fd);
  190 #else
  191   fsync(fd);
  192 #endif
  193 }
  194 
  195 #if defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H) || defined(HAVE_SYS_EXTATTR_H)
  196 static int extattr_overwrite(struct srm_target *srm, const int pass, const int attrnamespace)
  197 {
  198   char *list = NULL;
  199   unsigned char *value = NULL;
  200   size_t list_size = 256, value_size = 0, key_len = 0;
  201   ssize_t len = 0, i = 0;
  202   /* get list of atrributes */
  203   for(;;) {
  204     list = alloca(list_size);
  205     if (! list) {
  206       errno = ENOMEM;
  207       return -1;
  208     }
  209     errno = 0;
  210 #if defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H)
  211 #if defined(HAVE_ATTR_XATTR_H)
  212     len = flistxattr(srm->fd, list, list_size);
  213 #elif defined(HAVE_SYS_XATTR_H) && defined(__APPLE__)
  214     len = flistxattr(srm->fd, list, list_size, 0);
  215 #endif
  216     if (len < 0 && errno == ERANGE) {
  217       list_size *= 2;
  218       if (list_size > 1024*1024) {
  219     error("file has very large extended attribute list, giving up.");
  220     break;
  221       }
  222       continue;
  223     }
  224 #elif defined(HAVE_SYS_EXTATTR_H)
  225     len = extattr_list_fd(srm->fd, attrnamespace, NULL, 0);
  226     if (len > list_size) {
  227       list_size = len;
  228       continue;
  229     }
  230     len = extattr_list_fd(srm->fd, attrnamespace, list, list_size);
  231 #endif
  232     if (len < 0) {
  233       break;
  234     }
  235     break;
  236   }
  237 
  238   /* iterate list of attributes */
  239   for(i = 0; i < len; i += key_len + 1) {
  240     int ret = 0;
  241     ssize_t val_len = 0;
  242     char *key = NULL;
  243 #if defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H)
  244     key = list + i;
  245     key_len = strlen(key);
  246 #if defined(HAVE_ATTR_XATTR_H)
  247     val_len = fgetxattr(srm->fd, key, NULL, 0);
  248 #elif defined(HAVE_SYS_XATTR_H) && defined(__APPLE__)
  249     val_len = fgetxattr(srm->fd, key, NULL, 0, 0, 0);
  250 #endif
  251 #elif defined(HAVE_SYS_EXTATTR_H)
  252     char keybuf[257];
  253     key_len = *((unsigned char*)(list + i));
  254     memcpy(keybuf, list+i+1, key_len);
  255     keybuf[key_len] = 0;
  256     key = keybuf;
  257     val_len = extattr_get_fd(srm->fd, attrnamespace, key, NULL, 0);
  258 #endif
  259     if ( ((srm->options & SRM_OPT_V) > 1) && pass == 1) {
  260       char *name_space="";
  261 #if defined(HAVE_SYS_EXTATTR_H)
  262       extattr_namespace_to_string(attrnamespace, &namespace);
  263 #endif
  264       error("found extended attribute %s %s of %i bytes", name_space, key, (int)val_len);
  265     }
  266     if (val_len > (ssize_t)value_size) {
  267       value_size = val_len;
  268       value = alloca(value_size);
  269       if (! value) {
  270     errno = ENOMEM;
  271     return -1;
  272       }
  273       fill(value, value_size, srm->buffer, srm->buffer_size);
  274     }
  275 #if defined(HAVE_ATTR_XATTR_H)
  276     ret = fsetxattr(srm->fd, key, value, val_len, XATTR_REPLACE);
  277 #elif defined(HAVE_SYS_XATTR_H) && defined(__APPLE__)
  278     ret = fsetxattr(srm->fd, key, value, val_len, 0, XATTR_REPLACE);
  279 #elif defined(HAVE_SYS_EXTATTR_H)
  280     ret = extattr_set_fd(srm->fd, attrnamespace, key, value, val_len);
  281 #endif
  282     if (ret < 0) {
  283       errorp("could not overwrite extended attribute %s", key);
  284     }
  285   }
  286 
  287   (void)attrnamespace;
  288   return 0;
  289 }
  290 #endif
  291 
  292 static int overwrite(struct srm_target *srm, const int pass)
  293 {
  294   unsigned last_val = ~0u;
  295   my_off_t i = 0;
  296   ssize_t w;
  297 
  298   if(!srm) return -1;
  299   if(!srm->buffer) return -1;
  300   if(srm->buffer_size < 1) return -1;
  301 
  302   /* check for extended attributes */
  303 #if defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H)
  304   if (extattr_overwrite(srm, pass, 0) < 0) {
  305     return -1;
  306   }
  307 #elif defined(HAVE_SYS_EXTATTR_H)
  308   if (extattr_overwrite(srm, pass, EXTATTR_NAMESPACE_USER) < 0) {
  309     return -1;
  310   }
  311   if (extattr_overwrite(srm, pass, EXTATTR_NAMESPACE_SYSTEM) < 0) {
  312     return -1;
  313   }
  314 #endif
  315 
  316   if(lseek(srm->fd, 0, SEEK_SET) != 0)
  317     {
  318       perror("could not seek");
  319       return -1;
  320     }
  321 
  322   if(srm->file_size < (my_off_t)(srm->buffer_size))
  323     {
  324       w=writen(srm->fd, srm->buffer, srm->file_size);
  325       if(w != srm->file_size)
  326     return -1;
  327     }
  328   else
  329     {
  330       while (i < srm->file_size - (my_off_t)srm->buffer_size)
  331     {
  332       w=writen(srm->fd, srm->buffer, srm->buffer_size);
  333       if(w != (ssize_t)(srm->buffer_size))
  334         return -1;
  335       i += w;
  336 
  337       if ((srm->options & SRM_OPT_V) > 1 || SIGINT_received) {
  338           unsigned val = 0, file_size = 0;
  339           char c = '.';
  340           if (srm->file_size < MiB) {
  341           val = i / KiB;
  342           file_size = (unsigned)(srm->file_size/KiB);
  343           c = 'K';
  344           } else if(srm->file_size < GiB) {
  345           val = i / MiB;
  346           file_size = (unsigned)(srm->file_size/MiB);
  347           c = 'M';
  348           } else {
  349           val = i / GiB;
  350           file_size = (unsigned)(srm->file_size/GiB);
  351           c = 'G';
  352           }
  353           if (val != last_val) {
  354           printf("\rpass %i %u%ciB/%u%ciB     ", pass, val, c, file_size, c);
  355           fflush(stdout);
  356           last_val = val;
  357           }
  358 
  359           if(SIGINT_received)
  360         {
  361           if(srm->file_name)
  362             printf("%s\n", srm->file_name);
  363           else
  364             putchar('\n');
  365           SIGINT_received=0;
  366           fflush(stdout);
  367         }
  368         }
  369     }
  370       w=writen(srm->fd, srm->buffer, srm->file_size - i);
  371       if(w != srm->file_size-i)
  372     return -1;
  373     }
  374 
  375   if((srm->options & SRM_OPT_V) > 1)
  376     {
  377       printf("\rpass %i sync                        ", pass);
  378       fflush(stdout);
  379     }
  380 
  381   flush(srm->fd);
  382 
  383   if(lseek(srm->fd, 0, SEEK_SET) != 0)
  384     {
  385       perror("could not seek");
  386       return -1;
  387     }
  388 
  389   return 0;
  390 }
  391 
  392 static int overwrite_random(struct srm_target *srm, const int pass, const int num_passes)
  393 {
  394   int i;
  395 
  396   if(!srm) return -1;
  397   if(!srm->buffer) return -1;
  398   if(srm->buffer_size < 1) return -1;
  399 
  400   for (i = 0; i < num_passes; i++)
  401     {
  402       randomize_buffer(srm->buffer, srm->buffer_size);
  403       if(overwrite(srm, pass+i) < 0)
  404     return -1;
  405     }
  406 
  407   return 0;
  408 }
  409 
  410 static int overwrite_byte(struct srm_target *srm, const int pass, const int byte)
  411 {
  412   if(!srm) return -1;
  413   if(!srm->buffer) return -1;
  414   if(srm->buffer_size < 1) return -1;
  415   memset(srm->buffer, byte, srm->buffer_size);
  416   return overwrite(srm, pass);
  417 }
  418 
  419 static int overwrite_bytes(struct srm_target *srm, const int pass, const unsigned char byte1, const unsigned char byte2, const unsigned char byte3)
  420 {
  421   unsigned char buf[3];
  422 
  423   if(!srm) return -1;
  424   if(!srm->buffer) return -1;
  425   if(srm->buffer_size < 1) return -1;
  426 
  427   buf[0] = byte1;
  428   buf[1] = byte2;
  429   buf[2] = byte3;
  430   fill(srm->buffer, srm->buffer_size, buf, sizeof(buf));
  431   return overwrite(srm, pass);
  432 }
  433 
  434 static int overwrite_string(struct srm_target *srm, const int pass, const char *str)
  435 {
  436   if(!srm) return -1;
  437   if(!srm->buffer) return -1;
  438   if(srm->buffer_size < 1) return -1;
  439   if (!str) return -1;
  440 
  441   fill(srm->buffer, srm->buffer_size, (const unsigned char*)str, strlen(str));
  442   return overwrite(srm, pass);
  443 }
  444 
  445 static int overwrite_selector(struct srm_target *srm)
  446 {
  447   if(!srm) return -1;
  448 
  449 #if defined(F_NOCACHE)
  450   /* before performing file I/O, set F_NOCACHE to prevent caching */
  451   (void)fcntl(srm->fd, F_NOCACHE, 1);
  452 #endif
  453 
  454   if( (srm->buffer = (unsigned char *)alloca(srm->buffer_size)) == NULL )
  455     {
  456       errno = ENOMEM;
  457       return -1;
  458     }
  459 
  460   if(srm->options & SRM_MODE_DOD)
  461     {
  462       if((srm->options&SRM_OPT_V) > 1)
  463     error("US DoD mode");
  464       if(overwrite_byte(srm, 1, 0xF6) < 0) return -1;
  465       if(overwrite_byte(srm, 2, 0x00) < 0) return -1;
  466       if(overwrite_byte(srm, 3, 0xFF) < 0) return -1;
  467       if(overwrite_random(srm, 4, 1) < 0) return -1;
  468       if(overwrite_byte(srm, 5, 0x00) < 0) return -1;
  469       if(overwrite_byte(srm, 6, 0xFF) < 0) return -1;
  470       if(overwrite_random(srm, 7, 1) < 0) return -1;
  471     }
  472   else if(srm->options & SRM_MODE_DOE)
  473     {
  474       if((srm->options&SRM_OPT_V) > 1)
  475     error("US DoE mode");
  476       if(overwrite_random(srm, 1, 2) < 0) return -1;
  477       if(overwrite_bytes(srm, 3, 'D', 'o', 'E') < 0) return -1;
  478     }
  479   else if(srm->options & SRM_MODE_OPENBSD)
  480     {
  481       if((srm->options&SRM_OPT_V) > 1)
  482     error("OpenBSD mode");
  483       if(overwrite_byte(srm, 1, 0xFF) < 0) return -1;
  484       if(overwrite_byte(srm, 2, 0x00) < 0) return -1;
  485       if(overwrite_byte(srm, 3, 0xFF) < 0) return -1;
  486     }
  487   else if(srm->options & SRM_MODE_SIMPLE)
  488     {
  489       if((srm->options&SRM_OPT_V) > 1)
  490     error("Simple mode");
  491       if(overwrite_byte(srm, 1, 0x00) < 0) return -1;
  492     }
  493   else if(srm->options & SRM_MODE_RCMP)
  494     {
  495       if((srm->options&SRM_OPT_V) > 1)
  496     error("RCMP mode");
  497       if(overwrite_byte(srm, 1, 0x00) < 0) return -1;
  498       if(overwrite_byte(srm, 2, 0xFF) < 0) return -1;
  499       if(overwrite_string(srm, 3, "RCMP") < 0) return -1;
  500     }
  501   else
  502     {
  503       if(! (srm->options & SRM_MODE_35))
  504     error("something is strange, did not have mode_35 bit");
  505       if((srm->options&SRM_OPT_V) > 1)
  506     error("Full 35-pass mode (Gutmann method)");
  507       if(overwrite_random(srm, 1, 4) < 0) return -1;
  508       if(overwrite_byte(srm, 5, 0x55) < 0) return -1;
  509       if(overwrite_byte(srm, 6, 0xAA) < 0) return -1;
  510       if(overwrite_bytes(srm, 7, 0x92, 0x49, 0x24) < 0) return -1;
  511       if(overwrite_bytes(srm, 8, 0x49, 0x24, 0x92) < 0) return -1;
  512       if(overwrite_bytes(srm, 9, 0x24, 0x92, 0x49) < 0) return -1;
  513       if(overwrite_byte(srm, 10, 0x00) < 0) return -1;
  514       if(overwrite_byte(srm, 11, 0x11) < 0) return -1;
  515       if(overwrite_byte(srm, 12, 0x22) < 0) return -1;
  516       if(overwrite_byte(srm, 13, 0x33) < 0) return -1;
  517       if(overwrite_byte(srm, 14, 0x44) < 0) return -1;
  518       if(overwrite_byte(srm, 15, 0x55) < 0) return -1;
  519       if(overwrite_byte(srm, 16, 0x66) < 0) return -1;
  520       if(overwrite_byte(srm, 17, 0x77) < 0) return -1;
  521       if(overwrite_byte(srm, 18, 0x88) < 0) return -1;
  522       if(overwrite_byte(srm, 19, 0x99) < 0) return -1;
  523       if(overwrite_byte(srm, 20, 0xAA) < 0) return -1;
  524       if(overwrite_byte(srm, 21, 0xBB) < 0) return -1;
  525       if(overwrite_byte(srm, 22, 0xCC) < 0) return -1;
  526       if(overwrite_byte(srm, 23, 0xDD) < 0) return -1;
  527       if(overwrite_byte(srm, 24, 0xEE) < 0) return -1;
  528       if(overwrite_byte(srm, 25, 0xFF) < 0) return -1;
  529       if(overwrite_bytes(srm, 26, 0x92, 0x49, 0x24) < 0) return -1;
  530       if(overwrite_bytes(srm, 27, 0x49, 0x24, 0x92) < 0) return -1;
  531       if(overwrite_bytes(srm, 28, 0x24, 0x92, 0x49) < 0) return -1;
  532       if(overwrite_bytes(srm, 29, 0x6D, 0xB6, 0xDB) < 0) return -1;
  533       if(overwrite_bytes(srm, 30, 0xB6, 0xDB, 0x6D) < 0) return -1;
  534       if(overwrite_bytes(srm, 31, 0xDB, 0x6D, 0xB6) < 0) return -1;
  535       if(overwrite_random(srm, 32, 4) < 0) return -1;
  536       /* if you want to backup your partition or shrink your vmware image having the file zero-ed gives best compression results. */
  537       if(overwrite_byte(srm, 36, 0x00) < 0) return -1;
  538     }
  539 #if 0
  540   if((srm->options & SRM_OPT_V) > 1)
  541     printf("\n");
  542 #endif
  543   return 0;
  544 }
  545 
  546 #ifdef _MSC_VER
  547 static my_off_t getFileSize(WCHAR *fn)
  548 {
  549     /* it's a pain, but it seems that the only way to get the size of an alternate data stream is to read it once. */
  550 #if 1
  551     my_off_t size = 0, r;
  552     int fd = _wopen(fn, O_RDONLY);
  553     if (fd < 0) return 0;
  554     do {
  555         char buf[4096];
  556     r = read(fd, buf, sizeof(buf));
  557     if (r > 0) size += r;
  558     } while(r > 0);
  559     close(fd);
  560     return size;
  561 #else
  562     WCHAR fn2[32767];
  563     WIN32_FILE_ATTRIBUTE_DATA w32_fad;
  564 
  565     wcscpy(fn2, L"\\\\?\\");
  566     wcscat(fn2, fn);
  567     if (! GetFileAttributesEx((char*)fn2, GetFileExInfoStandard, &w32_fad)) {
  568     error("could not get file attributes of %S", fn2);
  569     return 0;
  570     }
  571     return (((long long)w32_fad.nFileSizeHigh) << 32) | ((long long)w32_fad.nFileSizeLow);
  572 #endif
  573 }
  574 
  575 int ntfsHardLinks(const char *fn)
  576 {
  577     int ret = -1;
  578     BY_HANDLE_FILE_INFORMATION hfi;
  579     HANDLE hFile = CreateFile(fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  580     if (hFile == INVALID_HANDLE_VALUE) {
  581     return ret;
  582     }
  583 
  584     if (GetFileInformationByHandle(hFile, &hfi)) {
  585     ret = hfi.nNumberOfLinks;
  586     }
  587 
  588     CloseHandle(hFile);
  589     return ret;
  590 }
  591 #endif
  592 
  593 int sunlink_impl(const char *path, const int options)
  594 {
  595   const int oflags = O_WRONLY|O_SYNC|_O_BINARY;
  596   struct srm_target srm;
  597 #if defined(_MSC_VER)
  598   struct __stat64 statbuf;
  599 #else
  600   struct stat statbuf;
  601 #endif
  602 #if defined(__unix__) || defined(__APPLE__)
  603   struct flock flock;
  604 #endif
  605 
  606   /* check function arguments */
  607   if(!path) return -1;
  608 
  609   memset(&srm, 0, sizeof(srm));
  610   srm.file_name = path;
  611   srm.options = options;
  612 
  613   /* check if path exists */
  614 #if defined(_MSC_VER)
  615   if (_stat64(path, &statbuf) < 0) {
  616     return -1;
  617   }
  618 #else
  619   if (lstat(path, &statbuf) < 0) {
  620     return -1;
  621   }
  622 #endif
  623 
  624   srm.file_size = statbuf.st_size;
  625   if (srm.file_size < 0) {
  626     error("%s : file size: %lli, can not work with negative values", path, (long long)srm.file_size);
  627     return -1;
  628   }
  629 #ifdef _MSC_VER
  630   srm.buffer_size = 4096;
  631 #else
  632   srm.buffer_size = statbuf.st_blksize;
  633 #endif
  634   if(srm.buffer_size < 16)
  635     srm.buffer_size = 512;
  636   if((srm.options & SRM_OPT_V) > 2)
  637     error("file size: %lli, buffer_size=%u", (long long)srm.file_size, srm.buffer_size);
  638 
  639 #if defined(__linux__)
  640   if(S_ISBLK(statbuf.st_mode))
  641     {
  642       int secsize=512;
  643       long blocks=0;
  644       uint64_t u=0, u_;
  645 
  646       if( (srm.fd = open(srm.file_name, O_WRONLY)) < 0)
  647     return -1;
  648 
  649       if(ioctl(srm.fd, BLKSSZGET, &secsize) < 0)
  650     {
  651       perror("could not ioctl(BLKSSZGET)");
  652       return -1;
  653     }
  654       if((options&SRM_OPT_V) > 2)
  655     error("sector size %i bytes", secsize);
  656 
  657       if(ioctl(srm.fd, BLKGETSIZE, &blocks) < 0)
  658     {
  659       perror("could not ioctl(BLKGETSIZE)");
  660       return -1;
  661     }
  662       if((options&SRM_OPT_V) > 2)
  663     error("BLKGETSIZE %i blocks", (int)blocks);
  664 
  665       if(ioctl(srm.fd, BLKGETSIZE64, &u) < 0)
  666     {
  667       perror("could not ioctl(BLKGETSIZE64)");
  668       return -1;
  669     }
  670       if((options&SRM_OPT_V) > 2)
  671     error("BLKGETSIZE64 %llu bytes", (unsigned long long)u);
  672 
  673       u_=((uint64_t)blocks)*secsize;
  674       if(u_ != u)
  675       error("!Warning! sectorsize*blocks:%llu != bytes:%llu", (long long unsigned) u_, (long long unsigned) u);
  676 
  677       srm.file_size = u;
  678       srm.buffer_size = secsize;
  679 
  680       if(srm.file_size == 0)
  681     {
  682       close(srm.fd);
  683       if (srm.options & SRM_OPT_V)
  684         error("could not determine block device %s filesize", srm.file_name);
  685       errno = EIO;
  686       return -1;
  687     }
  688 
  689       if((options&SRM_OPT_V) > 1)
  690     error("block device %s size: %llu bytes", srm.file_name, (unsigned long long)u);
  691 
  692       if(overwrite_selector(&srm) < 0)
  693     {
  694       int e=errno;
  695       if (srm.options & SRM_OPT_V)
  696         errorp("could not overwrite device %s", srm.file_name);
  697       close(srm.fd);
  698       errno=e;
  699       return -1;
  700     }
  701       close(srm.fd);
  702       return 0;
  703     }
  704 #endif
  705 
  706     if (!S_ISREG(statbuf.st_mode)) {
  707     return rename_unlink(srm.file_name);
  708     }
  709 
  710 #if defined(_MSC_VER)
  711   /* check for alternate NTFS data streams */
  712   /* code taken from http://www.flexhex.com/docs/articles/alternate-streams.phtml */
  713   {
  714     static NTQUERYINFORMATIONFILE NtQueryInformationFile = 0;
  715     char InfoBlock[64 * 1024];
  716     PFILE_STREAM_INFORMATION pStreamInfo = (PFILE_STREAM_INFORMATION)InfoBlock;
  717 
  718     if (! NtQueryInformationFile) {
  719     NtQueryInformationFile = (NTQUERYINFORMATIONFILE) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryInformationFile");
  720     }
  721 
  722     /* get information on current file */
  723     if (NtQueryInformationFile) {
  724     IO_STATUS_BLOCK ioStatus;
  725     HANDLE hFile = CreateFile(srm.file_name, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  726     NtQueryInformationFile(hFile, &ioStatus, InfoBlock, sizeof(InfoBlock), FileStreamInformation);
  727     CloseHandle(hFile);
  728 
  729     /* iterate over information looking from streams */
  730     for (;;) {
  731     WCHAR wszStreamName[MAX_PATH];
  732     int i;
  733     char ads_fn[MAX_PATH], buf[MAX_PATH];
  734     WCHAR ads_fn_w[MAX_PATH];
  735     struct srm_target ads = srm;
  736 
  737     /* Check if stream info block is empty (directory may have no stream) */
  738     if (pStreamInfo->StreamNameLength == 0) break;
  739 
  740     /* Get null-terminated stream name */
  741     memcpy(wszStreamName, pStreamInfo->StreamName, pStreamInfo->StreamNameLength);
  742     wszStreamName[pStreamInfo->StreamNameLength / sizeof(WCHAR)] = L'\0';
  743 
  744     /* skip the default data stream */
  745     if (wcscmp(wszStreamName, L"::$DATA") == 0) {
  746         goto next_ads;
  747     }
  748 
  749     i = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wszStreamName, -1, buf, sizeof(buf)-1, NULL, NULL);
  750     if (i > 0) {
  751         buf[i] = 0;
  752         snprintf(ads_fn, sizeof(ads_fn), "%s%s", srm.file_name, buf);
  753         ads.file_name = ads_fn;
  754     }
  755 
  756     i = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, srm.file_name, -1, ads_fn_w, MAX_PATH);
  757     if (i <= 0) {
  758         error("could not convert %S to multi byte string", wszStreamName);
  759         goto next_ads;
  760     }
  761     ads_fn_w[i] = 0;
  762     wcscat(ads_fn_w, wszStreamName);
  763 
  764     ads.file_size = getFileSize(ads_fn_w);
  765     if (ads.file_size == 0) {
  766         if ((srm.options & SRM_OPT_V) > 1) {
  767         error("skipping alternate data stream %S of %lli bytes %i %i", ads_fn_w, ads.file_size);
  768         }
  769         goto next_ads;
  770     }
  771 
  772     ads.fd = _wopen(ads_fn_w, oflags);
  773     if (ads.fd < 0) {
  774         errorp("could not open alternate data stream %S", wszStreamName);
  775         goto next_ads;
  776     }
  777 
  778     if (srm.options & SRM_OPT_V) {
  779         error("removing alternate data stream %S of %lli bytes", ads_fn_w, ads.file_size);
  780     }
  781     if (ads.file_size > 0) {
  782         if(overwrite_selector(&ads) < 0)
  783         {
  784         if (ads.options & SRM_OPT_V)
  785             errorp("could not overwrite alternate data stream %S", ads_fn_w);
  786         }
  787         ftruncate(ads.fd, 0);
  788     }
  789     close(ads.fd);
  790 
  791 next_ads:
  792     if (pStreamInfo->NextEntryOffset == 0) break;
  793     pStreamInfo = (PFILE_STREAM_INFORMATION) ((LPBYTE)pStreamInfo + pStreamInfo->NextEntryOffset);
  794     }
  795     }
  796   }
  797 #endif
  798 
  799 #ifdef _MSC_VER
  800   if (ntfsHardLinks(srm.file_name) > 1)
  801 #else
  802   if (statbuf.st_nlink > 1)
  803 #endif
  804   {
  805     rename_unlink(srm.file_name);
  806     errno = EMLINK;
  807     return -1;
  808   }
  809 
  810   if (srm.file_size==0) {
  811     return rename_unlink(srm.file_name);
  812   }
  813 
  814   if ( (srm.fd = open(srm.file_name, oflags)) < 0)
  815     return -1;
  816 
  817 #if defined(__unix__) || defined(__APPLE__)
  818   flock.l_type = F_WRLCK;
  819   flock.l_whence = SEEK_SET;
  820   flock.l_start = 0;
  821   flock.l_len = 0;
  822   if (fcntl(srm.fd, F_SETLK, &flock) < 0) {
  823     int e=errno;
  824     flock.l_type = F_WRLCK;
  825     flock.l_whence = SEEK_SET;
  826     flock.l_start = 0;
  827     flock.l_len = 0;
  828     flock.l_pid = 0;
  829     if (fcntl(srm.fd, F_GETLK, &flock) == 0 && flock.l_pid > 0) {
  830       error("can't unlink %s, locked by process %i", srm.file_name, flock.l_pid);
  831     }
  832     close(srm.fd);
  833     errno=e;
  834     return -1;
  835   }
  836 #endif
  837 
  838 #if defined(HAVE_SYS_VFS_H) || (defined(HAVE_SYS_PARAM_H) && defined(HAVE_SYS_MOUNT_H))
  839   {
  840     struct statfs fs_stats;
  841     if (fstatfs(srm.fd, &fs_stats) < 0 && errno != ENOSYS)
  842       {
  843     int e=errno;
  844     close(srm.fd);
  845     errno=e;
  846     return -1;
  847       }
  848 
  849 #if defined(__linux__)
  850     srm.buffer_size = fs_stats.f_bsize;
  851 #elif defined(__FreeBSD__) || defined(__APPLE__)
  852     srm.buffer_size = fs_stats.f_iosize;
  853 #else
  854 #error Please define your platform.
  855 #endif
  856     if((srm.options & SRM_OPT_V) > 2)
  857       error("buffer_size=%u", srm.buffer_size);
  858 
  859 #if defined(HAVE_LINUX_EXT2_FS_H) || defined(HAVE_LINUX_EXT3_FS_H)
  860     if (fs_stats.f_type == EXT2_SUPER_MAGIC ) /* EXT2_SUPER_MAGIC and EXT3_SUPER_MAGIC are the same */
  861       {
  862     int flags = 0;
  863 
  864       if (ioctl(srm.fd, EXT2_IOC_GETFLAGS, &flags) < 0)
  865         {
  866           int e=errno;
  867           close(srm.fd);
  868           errno=e;
  869           return -1;
  870         }
  871 
  872       if ( (flags & EXT2_UNRM_FL) ||
  873            (flags & EXT2_IMMUTABLE_FL) ||
  874            (flags & EXT2_APPEND_FL) )
  875         {
  876               if((srm.options & SRM_OPT_V) > 2) {
  877                   error("%s has ext2 undelete, immutable or append-only flag", srm.file_name);
  878               }
  879           close(srm.fd);
  880           errno = EPERM;
  881           return -1;
  882         }
  883 
  884 #ifdef HAVE_LINUX_EXT3_FS_H
  885       /* if we have the required capabilities we can disable data journaling on ext3 */
  886       if(fs_stats.f_type == EXT3_SUPER_MAGIC) /* superflous check again, just to make it clear again */
  887         {
  888           flags &= ~EXT3_JOURNAL_DATA_FL;
  889           if (ioctl(srm.fd, EXT3_IOC_SETFLAGS, flags) < 0) {
  890                   if (srm.options & SRM_OPT_V)
  891                       errorp("could not clear journal data flag for ext3 on %s", srm.file_name);
  892           }
  893         }
  894 #endif
  895     }
  896 #endif /* HAVE_LINUX_EXT2_FS_H */
  897   }
  898 #endif /* HAVE_SYS_VFS_H */
  899 
  900 /* chflags(2) turns out to be a different system call in every BSD
  901    derivative. The important thing is to make sure we'll be able to
  902    unlink it after we're through messing around. Unlinking it first
  903    would remove the need for any of these checks, but would leave the
  904    user with no way to overwrite the file if the process was
  905    interupted during the overwriting. So, instead we assume that the
  906    open() above will fail on immutable and append-only files and try
  907    and catch only platforms supporting NOUNLINK here.
  908 
  909    OpenBSD - doesn't support nounlink (As of 3.1)
  910    FreeBSD - supports nounlink (from 4.4 on?)
  911    Tru64   - unknown
  912    MacOS X - doesn't support NOUNLINK (as of 10.3.5)
  913 */
  914 
  915 #if defined(HAVE_CHFLAGS) && defined(__FreeBSD__)
  916   if ((statbuf.st_flags & UF_IMMUTABLE) ||
  917       (statbuf.st_flags & UF_APPEND) ||
  918       (statbuf.st_flags & UF_NOUNLINK) ||
  919       (statbuf.st_flags & SF_IMMUTABLE) ||
  920       (statbuf.st_flags & SF_APPEND) ||
  921       (statbuf.st_flags & SF_NOUNLINK))
  922     {
  923       if((srm.options & SRM_OPT_V) > 2) {
  924           error("%s has ext2 nounlink, immutable or append-only flag", srm.file_name);
  925       }
  926       close(srm.fd);
  927       errno = EPERM;
  928       return -1;
  929     }
  930 #endif /* HAVE_CHFLAGS */
  931 
  932   /* check that the srm struct contains useful values */
  933   if (srm.file_name == 0) {
  934     error("internal error: srm.file_name is NULL");
  935     close(srm.fd);
  936     errno = ENOSYS;
  937     return -1;
  938   }
  939   if (srm.file_size == 0) {
  940     error("internal error: srm.file_size is 0");
  941     close(srm.fd);
  942     errno = ENOSYS;
  943     return -1;
  944   }
  945   if (srm.buffer_size == 0) {
  946     error("internal error: srm.buffer_size is 0");
  947     close(srm.fd);
  948     errno = ENOSYS;
  949     return -1;
  950   }
  951 
  952   if(overwrite_selector(&srm) < 0)
  953     {
  954       int e=errno;
  955       if (srm.options & SRM_OPT_V)
  956     errorp("could not overwrite file %s", srm.file_name);
  957       close(srm.fd);
  958       errno=e;
  959       return -1;
  960     }
  961 
  962 #if defined(HAVE_LINUX_EXT2_FS_H) || defined(HAVE_LINUX_EXT3_FS_H)
  963   ioctl(srm.fd, EXT2_IOC_SETFLAGS, EXT2_SECRM_FL);
  964 #endif
  965 
  966   if (ftruncate(srm.fd, 0) < 0) {
  967     int e=errno;
  968     close(srm.fd);
  969     errno=e;
  970     return -1;
  971   }
  972 
  973   close(srm.fd);
  974   srm.fd = -1;
  975 
  976 #ifdef __APPLE__
  977   /* Also overwrite the file's resource fork, if present. */
  978   {
  979     struct srm_target rsrc = srm;
  980     rsrc.file_name = (char *)alloca(strlen(srm.file_name) + sizeof(_PATH_RSRCFORKSPEC) + 1);
  981     if (rsrc.file_name == NULL)
  982       {
  983     errno = ENOMEM;
  984     goto rsrc_fork_failed;
  985       }
  986 
  987     if (snprintf((char*)rsrc.file_name, MAXPATHLEN, "%s" _PATH_RSRCFORKSPEC, srm.file_name) > MAXPATHLEN - 1)
  988       {
  989     errno = ENAMETOOLONG;
  990     goto rsrc_fork_failed;
  991       }
  992 
  993     if (lstat(rsrc.file_name, &statbuf) != 0)
  994       {
  995     if (errno == ENOENT || errno == ENOTDIR) {
  996       rsrc.file_size = 0;
  997     } else {
  998       goto rsrc_fork_failed;
  999     }
 1000       }
 1001     else
 1002       {
 1003     rsrc.file_size = statbuf.st_size;
 1004       }
 1005 
 1006     if (rsrc.file_size > 0)
 1007       {
 1008     if ((rsrc.fd = open(rsrc.file_name, oflags)) < 0) {
 1009       goto rsrc_fork_failed;
 1010     }
 1011 
 1012     flock.l_type = F_WRLCK;
 1013     flock.l_whence = SEEK_SET;
 1014     flock.l_start = 0;
 1015     flock.l_len = 0;
 1016     if (fcntl(rsrc.fd, F_SETLK, &flock) == -1)
 1017       {
 1018         close(rsrc.fd);
 1019         goto rsrc_fork_failed;
 1020       }
 1021 
 1022     if (rsrc.options & SRM_OPT_V) {
 1023       error("removing %s", rsrc.file_name);
 1024     }
 1025 
 1026     if(overwrite_selector(&rsrc) < 0)
 1027       {
 1028         if (rsrc.options & SRM_OPT_V) {
 1029           errorp("could not overwrite resource fork %s", rsrc.file_name);
 1030         }
 1031       }
 1032 
 1033     ftruncate(rsrc.fd, 0);
 1034     close(rsrc.fd);
 1035       }
 1036     goto rsrc_fork_done;
 1037 
 1038   rsrc_fork_failed:
 1039     if (rsrc.options & SRM_OPT_V) {
 1040       errorp("could not access resource fork %s", srm.file_name);
 1041     }
 1042 
 1043   rsrc_fork_done: ;
 1044   }
 1045 #endif /* __APPLE__ */
 1046 
 1047   return rename_unlink(srm.file_name);
 1048 }