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__) || defined(__DragonFly__)
109 typedef sig_t sighandler_t;
110 #endif
111
sigint_handler(int signo)112 static void sigint_handler(int signo)
113 {
114 SIGINT_received = signo;
115 }
116 int sunlink_impl(const char *path, const int options);
117
sunlink(const char * path,const int options)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 */
writen(const int fd,const void * buf,const size_t count)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
flush(int fd)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)
extattr_overwrite(struct srm_target * srm,const int pass,const int attrnamespace)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
overwrite(struct srm_target * srm,const int pass)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
overwrite_random(struct srm_target * srm,const int pass,const int num_passes)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
overwrite_byte(struct srm_target * srm,const int pass,const int byte)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
overwrite_bytes(struct srm_target * srm,const int pass,const unsigned char byte1,const unsigned char byte2,const unsigned char byte3)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
overwrite_string(struct srm_target * srm,const int pass,const char * str)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
overwrite_selector(struct srm_target * srm)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
getFileSize(WCHAR * fn)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
ntfsHardLinks(const char * fn)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
sunlink_impl(const char * path,const int options)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(__DragonFly__) || 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 }
1049