/[winpt]/trunk/PTD/wptWipeFile.cpp
ViewVC logotype

Diff of /trunk/PTD/wptWipeFile.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 45 by twoaday, Fri Sep 30 10:10:16 2005 UTC revision 46 by werner, Fri Oct 28 12:57:05 2005 UTC
# Line 1  Line 1 
1  /* wptWipeFile.cpp - Secure file removal  /* wptWipeFile.cpp - Secure file removal
2   *      Copyright (C) 2001-2005 Timo Schulz   *      Copyright (C) 2001-2005 Timo Schulz
3   *      Copyright (C) 2000 Matt Gauthier   *      Copyright (C) 2000 Matt Gauthier
4   *   *
5   * WinPT software; you can redistribute it and/or modify   * WinPT software; you can redistribute it and/or modify
6   * it under the terms of the GNU General Public License as published by   * it under the terms of the GNU General Public License as published by
7   * the Free Software Foundation; either version 2 of the License, or   * the Free Software Foundation; either version 2 of the License, or
8   * (at your option) any later version.   * (at your option) any later version.
9   *   *
10   * WinPT is distributed in the hope that it will be useful,   * WinPT is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.   * GNU General Public License for more details.
14   *   *
15   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
16   * along with WinPT; if not, write to the Free Software   * along with WinPT; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18   *   *
19   **************************************************************************   **************************************************************************
20   * This code based on the sunlink.c file from the SRM project, but        *   * This code based on the sunlink.c file from the SRM project, but        *
21   * it was heavily modified to work with W32 and with added GCRYPT         *   * it was heavily modified to work with W32 and with added GCRYPT         *
22   * support for gathering random bytes.                                    *   * support for gathering random bytes.                                    *
23   *                                                                        *   *                                                                        *
24   * The original code was placed under the GNU Lesser Public License,      *   * The original code was placed under the GNU Lesser Public License,      *
25   * even so I decide to put this file under the GNU General Public License.*   * even so I decide to put this file under the GNU General Public License.*
26   **************************************************************************   **************************************************************************
27   */   */
28    
29  #include <windows.h>  #ifdef HAVE_CONFIG_H
30  #include <stdio.h>  #include <config.h>
31  #include <stdlib.h>  #endif
32  #include <sys/stat.h>  
33  #include <string.h>  #include <windows.h>
34  #include <ctype.h>  #include <windows.h>
35  #include <direct.h>  #include <stdio.h>
36    #include <stdlib.h>
37  #include "openpgp.h"  #include <sys/stat.h>
38  #include "wptW32API.h"  #include <string.h>
39  #include "wptErrors.h"  #include <ctype.h>
40  #include "wptTypes.h"  #include <direct.h>
41    
42    #include "openpgp.h"
43  typedef unsigned __int64 DDWORD;  #include "wptW32API.h"
44    #include "wptErrors.h"
45  typedef struct {  #include "wptTypes.h"
46      HANDLE fd;  #include "wptCrypto.h"
47      DDWORD filesize;  
48      DDWORD offset;  typedef unsigned __int64 DDWORD;
49      BYTE  *buffer;  
50      DWORD  buffsize;  typedef struct {
51      const char *name;      HANDLE fd;
52      int    n_passes;      DDWORD filesize;
53  } wipe_context_s;      DDWORD offset;
54        BYTE  *buffer;
55        DWORD  buffsize;
56  void (*progress_cb) (void *, DDWORD, DDWORD);      const char *name;
57  static void *progress_cb_value = NULL;      int    n_passes;
58    } wipe_context_s;
59  void (*unlink_cb)(void *, const char *, int, int, int) = NULL;  
60  static void *unlink_cb_value = NULL;  
61    void (*progress_cb) (void *, DDWORD, DDWORD);
62  /* Use the file handle in the context to overwrite a file  static void *progress_cb_value = NULL;
63     with prepared buffer contents. */  
64  static void  void (*unlink_cb)(void *, const char *, int, int, int) = NULL;
65  overwrite (wipe_context_s *ctx)  static void *unlink_cb_value = NULL;
66  {  
67      DDWORD blocks = 0, mod = 0;  /* Use the file handle in the context to overwrite a file
68      DWORD nwritten = 0;     with prepared buffer contents. */
69      LONG size_high = 0;  static void
70    overwrite (wipe_context_s *ctx)
71      blocks = ctx->filesize / ctx->buffsize;  {
72      mod = ctx->filesize % ctx->buffsize;      DDWORD blocks = 0, mod = 0;
73      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);      DWORD nwritten = 0;
74      while (blocks--) {      LONG size_high = 0;
75          if (!WriteFile (ctx->fd, ctx->buffer, ctx->buffsize, &nwritten, NULL))  
76              break;      blocks = ctx->filesize / ctx->buffsize;
77          ctx->offset += nwritten;      mod = ctx->filesize % ctx->buffsize;
78          if (unlink_cb)      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
79              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,      while (blocks--) {
80                         (unsigned)ctx->filesize*ctx->n_passes);          if (!WriteFile (ctx->fd, ctx->buffer, ctx->buffsize, &nwritten, NULL))
81      }              break;
82      if (mod) {          ctx->offset += nwritten;
83          WriteFile (ctx->fd, ctx->buffer, (DWORD)mod, &nwritten, NULL);          if (unlink_cb)
84          ctx->offset += nwritten;              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
85          if (unlink_cb)                         (unsigned)ctx->filesize*ctx->n_passes);
86              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,      }
87                         (unsigned)ctx->filesize*ctx->n_passes);      if (mod) {
88      }          WriteFile (ctx->fd, ctx->buffer, (DWORD)mod, &nwritten, NULL);
89      FlushFileBuffers (ctx->fd);          ctx->offset += nwritten;
90      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);          if (unlink_cb)
91  }              unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
92                           (unsigned)ctx->filesize*ctx->n_passes);
93        }
94  /* fill the buffer with random of the given level. */      FlushFileBuffers (ctx->fd);
95  static void      SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
96  randomize_buffer (byte *buf, size_t bufsize, int level)  }
97  {  
98      const int blocksize = 512;  
99      int blocks = bufsize / blocksize;  /* fill the buffer with random of the given level. */
100      int mod = bufsize % blocksize;  static void
101        randomize_buffer (byte *buf, size_t bufsize, int level)
102      while (blocks--) {  {
103          gpg_randomize (buf, blocksize, level);      const int blocksize = 512;
104          buf += blocksize;      int blocks = bufsize / blocksize;
105      }      int mod = bufsize % blocksize;
106      if (mod)      
107          gpg_randomize (buf, mod, level);      while (blocks--) {
108  }          gpg_randomize (buf, blocksize, level);
109            buf += blocksize;
110        }
111  /* performs a random overwrite. */      if (mod)
112  static void          gpg_randomize (buf, mod, level);
113  overwrite_random (int npasses, wipe_context_s * ctx)  }
114  {        
115      int i;  
116        /* performs a random overwrite. */
117      for (i = 0; i < npasses; i++) {  static void
118          randomize_buffer (ctx->buffer, ctx->buffsize, 0);  overwrite_random (int npasses, wipe_context_s * ctx)
119          overwrite (ctx);  {      
120      }      int i;
121  }      
122        for (i = 0; i < npasses; i++) {
123            randomize_buffer (ctx->buffer, ctx->buffsize, 0);
124  /* perform an overwrite with a specific byte (like 0x00). */          overwrite (ctx);
125  static void      }
126  overwrite_byte (int byte, wipe_context_s * ctx)  }
127  {  
128      memset (ctx->buffer, byte, ctx->buffsize);  
129      overwrite (ctx);  /* perform an overwrite with a specific byte (like 0x00). */
130  } /* overwrite_byte */  static void
131    overwrite_byte (int byte, wipe_context_s * ctx)
132    {
133  /* perform an overwrite with a specific byte triple (like 0x00, 0xFF, 0xAA). */      memset (ctx->buffer, byte, ctx->buffsize);
134  static void      overwrite (ctx);
135  overwrite_bytes (int byte1, int byte2, int byte3, wipe_context_s * ctx)  } /* overwrite_byte */
136  {  
137      DWORD i;  
138    /* perform an overwrite with a specific byte triple (like 0x00, 0xFF, 0xAA). */
139      memset (ctx->buffer, byte1, ctx->buffsize);  static void
140      for (i = 1; i < ctx->buffsize; i += 3) {  overwrite_bytes (int byte1, int byte2, int byte3, wipe_context_s * ctx)
141          ctx->buffer[i] = byte2;  {
142          ctx->buffer[i+1] = byte3;      DWORD i;
143      }  
144      overwrite (ctx);      memset (ctx->buffer, byte1, ctx->buffsize);
145  } /* overwrite_bytes */      for (i = 1; i < ctx->buffsize; i += 3) {
146            ctx->buffer[i] = byte2;
147            ctx->buffer[i+1] = byte3;
148  /* For the case the file is not a regular file (this is true for      }
149     devices or directories) this function tries to rename the file      overwrite (ctx);
150     to random pattern and then it will be delete (without random!). */  } /* overwrite_bytes */
151  int  
152  rename_unlink (const char *path)  
153  {  /* For the case the file is not a regular file (this is true for
154      struct stat statbuf;     devices or directories) this function tries to rename the file
155      char *new_name = NULL, *p = NULL, c;       to random pattern and then it will be delete (without random!). */
156      int i = 0, rc = 0;  extern "C" int
157      int is_dir = 0;  rename_unlink (const char *path)
158    {
159      if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)      struct stat statbuf;
160          is_dir = 1;      char *new_name = NULL, *p = NULL, c;  
161            int i = 0, rc = 0;
162      new_name = new char[strlen (path)+15];      int is_dir = 0;
163      if (!new_name)  
164          BUG (0);      if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
165                is_dir = 1;
166      strcpy (new_name, path);      
167      p = strrchr (new_name, '\\');      new_name = new char[strlen (path)+15];
168      if (p != NULL) {      if (!new_name)
169          p++;          BUG (0);
170          *p = '\0';      
171      }      strcpy (new_name, path);
172      else      p = strrchr (new_name, '\\');
173          p = new_name;      if (p != NULL) {
174      do {          p++;
175          while (i < 14) {          *p = '\0';
176              c = gpg_random_char (1);      }
177              *p = c;      else
178              p++;          p = new_name;
179              i++;      do {
180          }          while (i < 14) {
181          *p = '\0';              c = gpg_random_char (1);
182      } while (stat (new_name, &statbuf) == 0);              *p = c;
183                    p++;
184      if (rename (path, new_name) == -1) {              i++;
185          rc = WPTERR_FILE_READ;          }
186          goto leave;          *p = '\0';
187      }      } while (stat (new_name, &statbuf) == 0);
188      if (is_dir && RemoveDirectory (new_name) == FALSE)      
189          rc = WPTERR_FILE_REMOVE;      if (rename (path, new_name) == -1) {
190      else if (!DeleteFile (new_name))          rc = WPTERR_FILE_READ;
191          rc = WPTERR_FILE_REMOVE;          goto leave;
192            }
193  leave:      if (is_dir && RemoveDirectory (new_name) == FALSE)
194      free_if_alloc (new_name);          rc = WPTERR_FILE_REMOVE;
195      return rc;      else if (!DeleteFile (new_name))
196  }          rc = WPTERR_FILE_REMOVE;
197        
198    leave:
199  /* return the filesize as an 64-bit integer. */      free_if_alloc (new_name);
200  static __int64      return rc;
201  GetFileSize64 (const char * path)  }
202  {  
203      FILE *fp = fopen (path, "r");  
204      if (fp) {  /* return the filesize as an 64-bit integer. */
205          struct _stati64 statbuf;  static __int64
206          if (_fstati64 (fileno (fp), &statbuf) == -1)  GetFileSize64 (const char * path)
207              return -1;  {
208          fclose (fp);      FILE *fp = fopen (path, "r");
209          return statbuf.st_size;      if (fp) {
210      }          struct _stati64 statbuf;
211      return -1;          if (_fstati64 (fileno (fp), &statbuf) == -1)
212  }              return -1;
213            fclose (fp);
214            return statbuf.st_size;
215  static int      }
216  _secure_unlink (const char * path, int mode, HANDLE *r_fd)      return -1;
217  {  }
218      wipe_context_s ctx;  
219      LONG size_high = 0;  
220        static int
221      if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)  _secure_unlink (const char * path, int mode, HANDLE *r_fd)
222          return rename_unlink (path);  {
223            wipe_context_s ctx;
224      memset (&ctx, 0, sizeof (ctx));      LONG size_high = 0;
225      ctx.name = path;      
226      ctx.buffsize = 16384;      if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
227      ctx.buffer = new byte[ctx.buffsize];          return rename_unlink (path);
228      if (!ctx.buffer)      
229          BUG (0);      memset (&ctx, 0, sizeof (ctx));
230            ctx.name = path;
231      ctx.filesize = GetFileSize64 (path);      ctx.buffsize = 16384;
232      if (!ctx.filesize) {      ctx.buffer = new byte[ctx.buffsize];
233          free_if_alloc (ctx.buffer);      if (!ctx.buffer)
234          unlink (path);          BUG (0);
235          return 0;      
236      }      ctx.filesize = GetFileSize64 (path);
237        if (!ctx.filesize) {
238      ctx.fd = CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,          free_if_alloc (ctx.buffer);
239                           OPEN_ALWAYS, 0, NULL);          unlink (path);
240      if (ctx.fd == INVALID_HANDLE_VALUE) {          return 0;
241          free_if_alloc (ctx.buffer);      }
242          return WPTERR_FILE_OPEN;  
243      }      ctx.fd = CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
244      else if (r_fd)                           OPEN_ALWAYS, 0, NULL);
245          *r_fd = ctx.fd;      if (ctx.fd == INVALID_HANDLE_VALUE) {
246                free_if_alloc (ctx.buffer);
247      gpg_quick_random_gen (1);          return WPTERR_FILE_OPEN;
248      if (unlink_cb)      }
249          unlink_cb (unlink_cb_value, ctx.name, 0, 0, 0);      else if (r_fd)
250            *r_fd = ctx.fd;
251      switch (mode) {      
252      case WIPE_MODE_FAST:      gpg_quick_random_gen (1);
253          ctx.n_passes = 1;      if (unlink_cb)
254          overwrite_random (1, &ctx);          unlink_cb (unlink_cb_value, ctx.name, 0, 0, 0);
255          break;  
256        switch (mode) {
257      case WIPE_MODE_SIMPLE:      case WIPE_MODE_FAST:
258          ctx.n_passes = 2;          ctx.n_passes = 1;
259          overwrite_random (2, &ctx);          overwrite_random (1, &ctx);
260          break;          break;
261            
262      case WIPE_MODE_DOD:      case WIPE_MODE_SIMPLE:
263          ctx.n_passes = 5;          ctx.n_passes = 2;
264          overwrite_random (1, &ctx);          overwrite_random (2, &ctx);
265          overwrite_byte ((~1) & 0xFF, &ctx);          break;
266          overwrite_random (1, &ctx);          
267          overwrite_byte ((~4) & 0xFF, &ctx);      case WIPE_MODE_DOD:
268          overwrite_random (1, &ctx);          ctx.n_passes = 5;
269          break;          overwrite_random (1, &ctx);
270                    overwrite_byte ((~1) & 0xFF, &ctx);
271      case WIPE_MODE_GUTMANN:          overwrite_random (1, &ctx);
272          ctx.n_passes = 39;          overwrite_byte ((~4) & 0xFF, &ctx);
273          overwrite_random (4, &ctx);          overwrite_random (1, &ctx);
274          overwrite_byte( 0x55, &ctx );          break;
275          overwrite_byte ( 0xAA, &ctx );          
276          overwrite_bytes( 0x92, 0x49, 0x24, &ctx );      case WIPE_MODE_GUTMANN:
277          overwrite_bytes( 0x49, 0x24, 0x92, &ctx );          ctx.n_passes = 39;
278          overwrite_bytes( 0x24, 0x92, 0x49, &ctx );          overwrite_random (4, &ctx);
279          overwrite_byte( 0x00, &ctx );          overwrite_byte( 0x55, &ctx );
280          overwrite_byte( 0x11, &ctx );          overwrite_byte ( 0xAA, &ctx );
281          overwrite_byte( 0x22, &ctx );          overwrite_bytes( 0x92, 0x49, 0x24, &ctx );
282          overwrite_byte( 0x33, &ctx );          overwrite_bytes( 0x49, 0x24, 0x92, &ctx );
283          overwrite_byte( 0x44, &ctx );          overwrite_bytes( 0x24, 0x92, 0x49, &ctx );
284          overwrite_byte( 0x55, &ctx );          overwrite_byte( 0x00, &ctx );
285          overwrite_byte( 0x66, &ctx );          overwrite_byte( 0x11, &ctx );
286          overwrite_byte( 0x77, &ctx );          overwrite_byte( 0x22, &ctx );
287          overwrite_byte( 0x88, &ctx );          overwrite_byte( 0x33, &ctx );
288          overwrite_byte( 0x99, &ctx );          overwrite_byte( 0x44, &ctx );
289          overwrite_byte( 0xAA, &ctx );          overwrite_byte( 0x55, &ctx );
290          overwrite_byte( 0xBB, &ctx );          overwrite_byte( 0x66, &ctx );
291          overwrite_byte( 0xCC, &ctx );          overwrite_byte( 0x77, &ctx );
292          overwrite_byte( 0xDD, &ctx );          overwrite_byte( 0x88, &ctx );
293          overwrite_byte( 0xEE, &ctx );          overwrite_byte( 0x99, &ctx );
294          overwrite_byte( 0xFF, &ctx );          overwrite_byte( 0xAA, &ctx );
295          overwrite_bytes( 0x92, 0x49, 0x24, &ctx );          overwrite_byte( 0xBB, &ctx );
296          overwrite_bytes( 0x49, 0x24, 0x92, &ctx );          overwrite_byte( 0xCC, &ctx );
297          overwrite_bytes( 0x24, 0x92, 0x49, &ctx );          overwrite_byte( 0xDD, &ctx );
298          overwrite_bytes( 0x6D, 0xB6, 0xDB, &ctx );          overwrite_byte( 0xEE, &ctx );
299          overwrite_bytes( 0xB6, 0xDB, 0x6D, &ctx );          overwrite_byte( 0xFF, &ctx );
300          overwrite_bytes( 0xDB, 0x6D, 0xB6, &ctx );          overwrite_bytes( 0x92, 0x49, 0x24, &ctx );
301          overwrite_random( 4, &ctx );          overwrite_bytes( 0x49, 0x24, 0x92, &ctx );
302          break;          overwrite_bytes( 0x24, 0x92, 0x49, &ctx );
303      }          overwrite_bytes( 0x6D, 0xB6, 0xDB, &ctx );
304                    overwrite_bytes( 0xB6, 0xDB, 0x6D, &ctx );
305      /* Set file length to zero so allocated clusters cannot be trailed */                overwrite_bytes( 0xDB, 0x6D, 0xB6, &ctx );
306      SetFilePointer (ctx.fd, 0, &size_high, FILE_BEGIN);          overwrite_random( 4, &ctx );
307      SetEndOfFile (ctx.fd);          break;
308      CloseHandle (ctx.fd);      }
309                
310      memset (ctx.buffer, 0, ctx.buffsize); /* burn the last evidence */        /* Set file length to zero so allocated clusters cannot be trailed */      
311      free_if_alloc (ctx.buffer);      SetFilePointer (ctx.fd, 0, &size_high, FILE_BEGIN);
312        SetEndOfFile (ctx.fd);
313      return rename_unlink (path);      CloseHandle (ctx.fd);
314  }      
315        memset (ctx.buffer, 0, ctx.buffsize); /* burn the last evidence */  
316        free_if_alloc (ctx.buffer);
317  /* Delete a file in a secure way with the given mode. */  
318  int      return rename_unlink (path);
319  secure_unlink (const char *path, int mode)  }
320  {  
321      return _secure_unlink (path, mode, NULL);  
322  }  /* Delete a file in a secure way with the given mode. */
323    extern "C" int
324    secure_unlink (const char *path, int mode)
325  /* Set the callback @cb for the wipe function. The callback is call every time  {
326     the wipe function writes data to the file. */      return _secure_unlink (path, mode, NULL);
327  void  }
328  secure_unlink_set_cb (void (*cb)(void *, const char *, int, int, int),  
329                        void *cb_value)  
330  {  /* Set the callback @cb for the wipe function. The callback is call every time
331      unlink_cb = cb;     the wipe function writes data to the file. */
332      unlink_cb_value = cb_value;  extern "C" void
333  }  secure_unlink_set_cb (void (*cb)(void *, const char *, int, int, int),
334                          void *cb_value)
335    {
336  /* wipe all free space of the given drive by creating a temp file      unlink_cb = cb;
337     which has the size of the free space. This file will be then      unlink_cb_value = cb_value;
338     overwritten with random and static pattern. */  }
339  int  
340  wipe_freespace (const char * drive, HANDLE *r_fd,  
341                  void (*cb)(void *, DDWORD, DDWORD), void * cb_value)  /* wipe all free space of the given drive by creating a temp file
342  {     which has the size of the free space. This file will be then
343      ULARGE_INTEGER caller, total, frees;     overwritten with random and static pattern. */
344      LONG hpart=0;  extern "C" int
345      HANDLE fd;  wipe_freespace (const char * drive, HANDLE *r_fd,
346      int disktyp = GetDriveType (drive);                  void (*cb)(void *, DDWORD, DDWORD), void * cb_value)
347      int rc;  {
348      char * file;      ULARGE_INTEGER caller, total, frees;
349        LONG hpart=0;
350      if (disktyp != DRIVE_FIXED && disktyp != DRIVE_REMOVABLE)      HANDLE fd;
351          return -1;      int disktyp = GetDriveType (drive);
352      if (!GetDiskFreeSpaceEx (drive, &caller, &total, &frees))      int rc;
353          return -1;        char * file;
354    
355      /* disk is full */      if (disktyp != DRIVE_FIXED && disktyp != DRIVE_REMOVABLE)
356      if (!frees.LowPart)          return -1;
357          return 0;      if (!GetDiskFreeSpaceEx (drive, &caller, &total, &frees))
358      file = new char[strlen (drive)+8];          return -1;  
359      if (!file)  
360          BUG (0);      /* disk is full */
361      sprintf (file, "%stemp_winpt.tmp", drive);      if (!frees.LowPart)
362      fd = CreateFile (file,          return 0;
363                      GENERIC_READ|GENERIC_WRITE,      file = new char[strlen (drive)+8];
364                      FILE_SHARE_READ|FILE_SHARE_WRITE,      if (!file)
365                      NULL, CREATE_ALWAYS, 0, NULL);          BUG (0);
366      if (fd == INVALID_HANDLE_VALUE) {      sprintf (file, "%stemp_winpt.tmp", drive);
367          free_if_alloc (file);      fd = CreateFile (file,
368          return WPTERR_FILE_OPEN;                      GENERIC_READ|GENERIC_WRITE,
369      }                      FILE_SHARE_READ|FILE_SHARE_WRITE,
370      hpart = frees.HighPart;                      NULL, CREATE_ALWAYS, 0, NULL);
371      SetFilePointer (fd, frees.LowPart, &hpart, FILE_BEGIN);      if (fd == INVALID_HANDLE_VALUE) {
372      SetEndOfFile (fd);          free_if_alloc (file);
373      CloseHandle (fd);          return WPTERR_FILE_OPEN;
374        }
375      if (cb && cb_value) {      hpart = frees.HighPart;
376          progress_cb = cb;      SetFilePointer (fd, frees.LowPart, &hpart, FILE_BEGIN);
377          progress_cb_value = cb_value;      SetEndOfFile (fd);
378      }      CloseHandle (fd);
379      rc = _secure_unlink (file, WIPE_MODE_FAST, r_fd);  
380      free_if_alloc (file);      if (cb && cb_value) {
381      return rc;          progress_cb = cb;
382  }          progress_cb_value = cb_value;
383        }
384        rc = _secure_unlink (file, WIPE_MODE_FAST, r_fd);
385        free_if_alloc (file);
386        return rc;
387    }

Legend:
Removed from v.45  
changed lines
  Added in v.46

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26