-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathzerofile.c
242 lines (206 loc) · 7.19 KB
/
zerofile.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#include <sys/param.h> // For system parameters
#include <sys/errno.h> // For system calls and error numbers
#include <unistd.h> // For getopt universal routines
#include <time.h> // For time functions
#include <stdio.h> // For standard io routines
#include <stdlib.h> // For standard library functions
#include <string.h> // For string functions
#include <signal.h> // For simplified software signal facilities
typedef enum {FALSE, TRUE} Bool;
#define minAmount 256
#define DEFAULT_TMP_FILENAME "0slask0.zro"
#define DEFAULT_BLKSIZE 4096
char *tmpFilename = DEFAULT_TMP_FILENAME;
size_t blockSize = DEFAULT_BLKSIZE; // Amount of zeroes to write at each pass
Bool quiet = FALSE; // No progress report during zeroing, a bit faster
FILE *fid;
//***********************************************************************
//
// showHelp
//
// Description:
// This procedure gives the correct syntax of the input command
//
// Parameters:
// ( char * ) program - This programs name, usually argv[ 0 ]
//
// Returns:
// ( void )
//***********************************************************************/
void showHelp( program )
char *program;
{
system( "clear" );
fprintf( stdout, "%s -q -b < blkdSize > [ tempFile ]\n\n", program );
fprintf( stdout, " Description: \n" );
fprintf( stdout, "\n" );
fprintf( stdout, " A simple command line tool that fills FREE space on a disk with zeroes by\n" );
fprintf( stdout, " filling a temporary file and then removing it.\n" );
fprintf( stdout, "\n" );
fprintf( stdout, " Algorithm: ( kindly taken from: https://github.com/nollan/zerofile with his permission )\n" );
fprintf( stdout, "\n" );
fprintf( stdout, " The file is filled 4096 bytes at the time ( blocksize ), and halves\n" );
fprintf( stdout, " it when disk space is to small for 4096 bytes. So next time it's 2048\n" );
fprintf( stdout, " and so on, until it's less than 256 when it will remove the tempfile and\n" );
fprintf( stdout, " exit. The reason for halving is to really fill up all the free space with\n" );
fprintf( stdout, " zeroes. If the selected block size is larger than the file system block\n" );
fprintf( stdout, " size the halving is not really usefull\n" );
fprintf( stdout, "\n" );
fprintf( stdout, " Note: CTRL-C kills and cleans up automatically\n" );
fprintf( stdout, "\n\n" );
fprintf( stdout, " %s recognizes the following options:\n\n", program );
fprintf( stdout, " -q => No progress report during zeroing, a bit faster\n" );
fprintf( stdout, " -b < blkSize > => Amount of zeroes to write at each pass. Default: %u\n", DEFAULT_BLKSIZE );
fprintf( stdout, " [ tempFilename ] => Temporary file used. Defaults to: %s\n", DEFAULT_TMP_FILENAME );
}
//****************************************************************************
//
// parseCommandLineOptions
//
// Description:
// This procedure takes all the command line options passed to main line.
//
// Parameters:
// ( int * ) argc - The number of command line arguments passed
// to this procedure.
// ( char** ) argv - List of command line options specified by the user.
//
// Updates Globals:
// ( Bool ) quiet - No progress report during zeroing, a bit faster.
// ( size_t ) blockSize - The amount of zeroes to write at each pass.
// ( char* ) tmpFilename - The Temporary file name to use.
//
// Returns:
// ( void )
//*************************************************************************/
void parseCommandLineOptions( int *argc, char *argv[ ] )
{
int opt;
extern char *optarg;
extern int optind;
// Check for options passed in
while ( ( opt = getopt( *argc, argv, "hqb:" ) ) != -1 )
{
switch ( opt )
{
case 'h':
showHelp( argv[ 0 ] );
exit( 0 );
case 'q':
quiet = TRUE;
break;
case 'b':
blockSize = strtoul( argv[ optind ], NULL, 10 ) ;
if ( errno == EINVAL )
{
fprintf( stderr, "Cannot convert %s to unsigned long. error: %d\n", argv[ optind ], errno );
exit( errno );
}
break;
case '?':
default:
showHelp( argv[ 0 ] );
fprintf( stderr, "Error: Unknown option given %c.\n", opt );
exit( 666 );
}
}
// Temp-file selection
if ( *argc > optind )
tmpFilename = argv[ optind ];
}
// Cleanup, remove tempfile
void cleanup( )
{
fprintf( stdout, "Removing temp-file ... " );
fclose( fid );
if ( unlink( tmpFilename ) != 0 )
{
fprintf( stderr, "error: %d\n", errno );
exit( errno );
}
fprintf( stdout, "Done\n" );
}
void intHandler( )
{
if ( ! quiet )
fprintf( stdout, "\n" );
fprintf( stdout, "Cleaning up" );
cleanup( );
exit( 1 );
}
//***********************************************************************
//
// main
//
// Description:
//
// Returns:
// 0 if successfull, otherwise errno.
//***********************************************************************/
int main( int argc, char *argv[ ] )
{
time_t startTime, endTime;
double diff_t;
char* bunchOfZeroes;
// Keep score of bytes written
long bytesWritten = 0;
long totalBytesWritten = 0;
// Keep score of when started
time( &startTime );
// Well, parse the flags! :)
parseCommandLineOptions( &argc, argv );
// Handle ctrl-c and kills
signal( SIGINT, intHandler );
signal( SIGTERM, intHandler );
// Make some zeroes
bunchOfZeroes = ( char * ) calloc( blockSize, sizeof( char * ) );
fid = fopen( tmpFilename, "w" );
if ( fid == NULL )
{
fprintf( stderr, "error: %d\n", errno );
exit ( errno );
}
fprintf( stdout, "Using tempfile: '%s'\n", tmpFilename );
// Amount to write at each pass
size_t amount = blockSize;
for ( ; ; )
{
// Write zeroes up to amount ( which is equal or less than blockSize )
size_t bytesWritten = fwrite( bunchOfZeroes, 1, amount, fid );
if ( bytesWritten != amount )
{
// Check for no more space left on device
if ( errno == ENOSPC )
{
// if not all of the amount is written, halve it and try again
// in case of very large blockSize.
if ( bytesWritten != amount )
amount /= 2;
// Limit of amount size, disk buffer size is normally larger
if ( amount < minAmount )
break;
} else
{
// Other error
cleanup( );
fprintf( stderr, "error: %d\n", errno );
exit( errno );
}
}
// Update stats
totalBytesWritten += bytesWritten;
// Keep quiet if wanted
if ( ! quiet )
fprintf( stdout, "Written: %zu bytes \r", totalBytesWritten );
}
// Print some stats
if ( ! quiet )
fprintf( stdout, "\n" );
time( &endTime );
diff_t = difftime( endTime, startTime );
fprintf( stdout, "Duration: %f ; Performance: %.3f bytes/sec\n",
diff_t,
totalBytesWritten / diff_t );
cleanup( );
exit( 0 );
}