|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "prio.h" |
|
7 #include "prmem.h" |
|
8 #include "prprf.h" |
|
9 #include "prinit.h" |
|
10 #include "prerror.h" |
|
11 #include "prthread.h" |
|
12 |
|
13 #include "plerror.h" |
|
14 #include "plgetopt.h" |
|
15 |
|
16 #define DEFAULT_COUNT 10 |
|
17 #define DEFAULT_FILESIZE 1 |
|
18 #define BUFFER_SIZE 1000000 |
|
19 |
|
20 typedef enum {v_silent, v_whisper, v_shout} Verbosity; |
|
21 static void Verbose(Verbosity, const char*, const char*, PRIntn); |
|
22 |
|
23 #define VERBOSE(_l, _m) Verbose(_l, _m, __FILE__, __LINE__) |
|
24 |
|
25 static PRIntn test_result = 2; |
|
26 static PRFileDesc *output = NULL; |
|
27 static PRIntn verbose = v_silent; |
|
28 static PRIntn filesize = DEFAULT_FILESIZE; |
|
29 |
|
30 static PRIntn Usage(void) |
|
31 { |
|
32 PR_fprintf(output, "Bigfile test usage:\n"); |
|
33 PR_fprintf(output, ">bigfile [-G] [-d] [-v[*v]] [-s <n>] <filename>\n"); |
|
34 PR_fprintf(output, "\td\tdebug mode (equivalent to -vvv)\t(false)\n"); |
|
35 PR_fprintf(output, "\tv\tAdditional levels of output\t(none)\n"); |
|
36 PR_fprintf(output, "\tk\tKeep data file after exit\t(false)\n"); |
|
37 PR_fprintf(output, "\ts <n>\tFile size in megabytes\t\t(1 megabyte)\n"); |
|
38 PR_fprintf(output, "\t<filename>\tName of test file\t(none)\n"); |
|
39 return 2; /* nothing happened */ |
|
40 } /* Usage */ |
|
41 |
|
42 static PRStatus DeleteIfFound(const char *filename) |
|
43 { |
|
44 PRStatus rv; |
|
45 VERBOSE(v_shout, "Checking for existing file"); |
|
46 rv = PR_Access(filename, PR_ACCESS_WRITE_OK); |
|
47 if (PR_SUCCESS == rv) |
|
48 { |
|
49 VERBOSE(v_shout, "Deleting existing file"); |
|
50 rv = PR_Delete(filename); |
|
51 if (PR_FAILURE == rv) VERBOSE(v_shout, "Cannot delete big file"); |
|
52 } |
|
53 else if (PR_FILE_NOT_FOUND_ERROR != PR_GetError()) |
|
54 VERBOSE(v_shout, "Cannot access big file"); |
|
55 else rv = PR_SUCCESS; |
|
56 return rv; |
|
57 } /* DeleteIfFound */ |
|
58 |
|
59 static PRIntn Error(const char *msg, const char *filename) |
|
60 { |
|
61 PRInt32 error = PR_GetError(); |
|
62 if (NULL != msg) |
|
63 { |
|
64 if (0 == error) PR_fprintf(output, msg); |
|
65 else PL_FPrintError(output, msg); |
|
66 } |
|
67 (void)DeleteIfFound(filename); |
|
68 if (v_shout == verbose) PR_Abort(); |
|
69 return 1; |
|
70 } /* Error */ |
|
71 |
|
72 static void Verbose( |
|
73 Verbosity level, const char *msg, const char *file, PRIntn line) |
|
74 { |
|
75 if (level <= verbose) |
|
76 PR_fprintf(output, "[%s : %d]: %s\n", file, line, msg); |
|
77 } /* Verbose */ |
|
78 |
|
79 static void PrintInfo(PRFileInfo64 *info, const char *filename) |
|
80 { |
|
81 PRExplodedTime tm; |
|
82 char ctime[40], mtime[40]; |
|
83 static const char *types[] = {"FILE", "DIRECTORY", "OTHER"}; |
|
84 PR_fprintf( |
|
85 output, "[%s : %d]: File info for %s\n", |
|
86 __FILE__, __LINE__, filename); |
|
87 PR_fprintf( |
|
88 output, " type: %s, size: %llu bytes,\n", |
|
89 types[info->type - 1], info->size); |
|
90 |
|
91 PR_ExplodeTime(info->creationTime, PR_GMTParameters, &tm); |
|
92 (void)PR_FormatTime(ctime, sizeof(ctime), "%c GMT", &tm); |
|
93 PR_ExplodeTime(info->modifyTime, PR_GMTParameters, &tm); |
|
94 (void)PR_FormatTime(mtime, sizeof(mtime), "%c GMT", &tm); |
|
95 |
|
96 PR_fprintf( |
|
97 output, " creation: %s,\n modify: %s\n", ctime, mtime); |
|
98 } /* PrintInfo */ |
|
99 |
|
100 int main(int argc, char **argv) |
|
101 { |
|
102 PRStatus rv; |
|
103 char *buffer; |
|
104 PLOptStatus os; |
|
105 PRInt32 loop, bytes; |
|
106 PRFileInfo small_info; |
|
107 PRFileInfo64 big_info; |
|
108 PRBool keep = PR_FALSE; |
|
109 PRFileDesc *file = NULL; |
|
110 const char *filename = NULL; |
|
111 PRIntn count = DEFAULT_COUNT; |
|
112 PRInt64 filesize64, big_answer, big_size, one_meg, zero_meg, big_fragment; |
|
113 PRInt64 sevenFox = LL_INIT(0,0x7fffffff); |
|
114 |
|
115 PLOptState *opt = PL_CreateOptState(argc, argv, "dtvhs:"); |
|
116 |
|
117 output = PR_GetSpecialFD(PR_StandardError); |
|
118 PR_STDIO_INIT(); |
|
119 |
|
120 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) |
|
121 { |
|
122 if (PL_OPT_BAD == os) continue; |
|
123 switch (opt->option) |
|
124 { |
|
125 case 0: |
|
126 filename = opt->value; |
|
127 break; |
|
128 case 'd': /* debug mode */ |
|
129 verbose = v_shout; |
|
130 break; |
|
131 case 'k': /* keep file */ |
|
132 keep = PR_TRUE; |
|
133 break; |
|
134 case 'v': /* verbosity */ |
|
135 if (v_shout > verbose) verbose += 1; |
|
136 break; |
|
137 case 'c': /* loop counter */ |
|
138 count = atoi(opt->value); |
|
139 break; |
|
140 case 's': /* filesize */ |
|
141 filesize = atoi(opt->value); |
|
142 break; |
|
143 case 'h': /* confused */ |
|
144 default: |
|
145 return Usage(); |
|
146 } |
|
147 } |
|
148 PL_DestroyOptState(opt); |
|
149 |
|
150 if (0 == count) count = DEFAULT_COUNT; |
|
151 if (0 == filesize) filesize = DEFAULT_FILESIZE; |
|
152 if (NULL == filename) |
|
153 { |
|
154 #ifdef SYMBIAN |
|
155 #define FILE_NAME "c:\\data\\bigfile.dat" |
|
156 #else |
|
157 #define FILE_NAME "bigfile.dat" |
|
158 #endif |
|
159 if (DEFAULT_FILESIZE != filesize) return Usage(); |
|
160 else filename = FILE_NAME; |
|
161 } |
|
162 |
|
163 if (PR_FAILURE == DeleteIfFound(filename)) return 1; |
|
164 |
|
165 test_result = 0; |
|
166 |
|
167 LL_I2L(zero_meg, 0); |
|
168 LL_I2L(one_meg, 1000000); |
|
169 LL_I2L(filesize64, filesize); |
|
170 buffer = (char*)PR_MALLOC(BUFFER_SIZE); |
|
171 LL_I2L(big_fragment, BUFFER_SIZE); |
|
172 LL_MUL(filesize64, filesize64, one_meg); |
|
173 |
|
174 for (loop = 0; loop < BUFFER_SIZE; ++loop) buffer[loop] = (char)loop; |
|
175 |
|
176 VERBOSE(v_whisper, "Creating big file"); |
|
177 file = PR_Open(filename, PR_CREATE_FILE | PR_WRONLY, 0666); |
|
178 if (NULL == file) return Error("PR_Open()", filename); |
|
179 |
|
180 VERBOSE(v_whisper, "Testing available space in empty file"); |
|
181 big_answer = file->methods->available64(file); |
|
182 if (!LL_IS_ZERO(big_answer)) return Error("empty available64()", filename); |
|
183 |
|
184 LL_SUB(big_size, filesize64, one_meg); |
|
185 VERBOSE(v_whisper, "Creating sparse big file by seeking to end"); |
|
186 big_answer = file->methods->seek64(file, big_size, PR_SEEK_SET); |
|
187 if (!LL_EQ(big_answer, big_size)) return Error("seek", filename); |
|
188 |
|
189 VERBOSE(v_whisper, "Writing block at end of sparse file"); |
|
190 bytes = file->methods->write(file, buffer, BUFFER_SIZE); |
|
191 if (bytes != BUFFER_SIZE) return Error("write", filename); |
|
192 |
|
193 VERBOSE(v_whisper, "Testing available space at end of sparse file"); |
|
194 big_answer = file->methods->available64(file); |
|
195 if (!LL_IS_ZERO(big_answer)) return Error("eof available64()", filename); |
|
196 |
|
197 VERBOSE(v_whisper, "Getting big info on sparse big file"); |
|
198 rv = file->methods->fileInfo64(file, &big_info); |
|
199 if (PR_FAILURE == rv) return Error("fileInfo64()", filename); |
|
200 if (v_shout <= verbose) PrintInfo(&big_info, filename); |
|
201 |
|
202 VERBOSE(v_whisper, "Getting small info on sparse big file"); |
|
203 rv = file->methods->fileInfo(file, &small_info); |
|
204 if (LL_CMP(sevenFox, <, filesize64) && (PR_SUCCESS == rv)) |
|
205 { |
|
206 VERBOSE(v_whisper, "Should have failed and didn't"); |
|
207 return Error("fileInfo()", filename); |
|
208 } |
|
209 else if (LL_CMP(sevenFox, >, filesize64) && (PR_FAILURE == rv)) |
|
210 { |
|
211 VERBOSE(v_whisper, "Should have succeeded and didn't"); |
|
212 return Error("fileInfo()", filename); |
|
213 } |
|
214 |
|
215 VERBOSE(v_whisper, "Rewinding big file"); |
|
216 big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET); |
|
217 if (!LL_IS_ZERO(big_answer)) return Error("rewind seek64()", filename); |
|
218 |
|
219 VERBOSE(v_whisper, "Establishing available space in rewound file"); |
|
220 big_answer = file->methods->available64(file); |
|
221 if (LL_NE(filesize64, big_answer)) |
|
222 return Error("bof available64()", filename); |
|
223 |
|
224 VERBOSE(v_whisper, "Closing big file"); |
|
225 rv = file->methods->close(file); |
|
226 if (PR_FAILURE == rv) return Error("close()", filename); |
|
227 |
|
228 VERBOSE(v_whisper, "Reopening big file"); |
|
229 file = PR_Open(filename, PR_RDWR, 0666); |
|
230 if (NULL == file) return Error("open failed", filename); |
|
231 |
|
232 VERBOSE(v_whisper, "Checking available data in reopened file"); |
|
233 big_answer = file->methods->available64(file); |
|
234 if (LL_NE(filesize64, big_answer)) |
|
235 return Error("reopened available64()", filename); |
|
236 |
|
237 big_answer = zero_meg; |
|
238 VERBOSE(v_whisper, "Rewriting every byte of big file data"); |
|
239 do |
|
240 { |
|
241 bytes = file->methods->write(file, buffer, BUFFER_SIZE); |
|
242 if (bytes != BUFFER_SIZE) |
|
243 return Error("write", filename); |
|
244 LL_ADD(big_answer, big_answer, big_fragment); |
|
245 } while (LL_CMP(big_answer, <, filesize64)); |
|
246 |
|
247 VERBOSE(v_whisper, "Checking position at eof"); |
|
248 big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_CUR); |
|
249 if (LL_NE(big_answer, filesize64)) |
|
250 return Error("file size error", filename); |
|
251 |
|
252 VERBOSE(v_whisper, "Testing available space at eof"); |
|
253 big_answer = file->methods->available64(file); |
|
254 if (!LL_IS_ZERO(big_answer)) |
|
255 return Error("eof available64()", filename); |
|
256 |
|
257 VERBOSE(v_whisper, "Rewinding full file"); |
|
258 big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET); |
|
259 if (!LL_IS_ZERO(big_answer)) return Error("bof seek64()", filename); |
|
260 |
|
261 VERBOSE(v_whisper, "Testing available space in rewound file"); |
|
262 big_answer = file->methods->available64(file); |
|
263 if (LL_NE(big_answer, filesize64)) return Error("bof available64()", filename); |
|
264 |
|
265 VERBOSE(v_whisper, "Seeking to end of big file"); |
|
266 big_answer = file->methods->seek64(file, filesize64, PR_SEEK_SET); |
|
267 if (LL_NE(big_answer, filesize64)) return Error("eof seek64()", filename); |
|
268 |
|
269 VERBOSE(v_whisper, "Getting info on big file while it's open"); |
|
270 rv = file->methods->fileInfo64(file, &big_info); |
|
271 if (PR_FAILURE == rv) return Error("fileInfo64()", filename); |
|
272 if (v_shout <= verbose) PrintInfo(&big_info, filename); |
|
273 |
|
274 VERBOSE(v_whisper, "Closing big file"); |
|
275 rv = file->methods->close(file); |
|
276 if (PR_FAILURE == rv) return Error("close()", filename); |
|
277 |
|
278 VERBOSE(v_whisper, "Getting info on big file after it's closed"); |
|
279 rv = PR_GetFileInfo64(filename, &big_info); |
|
280 if (PR_FAILURE == rv) return Error("fileInfo64()", filename); |
|
281 if (v_shout <= verbose) PrintInfo(&big_info, filename); |
|
282 |
|
283 VERBOSE(v_whisper, "Deleting big file"); |
|
284 rv = PR_Delete(filename); |
|
285 if (PR_FAILURE == rv) return Error("PR_Delete()", filename); |
|
286 |
|
287 PR_DELETE(buffer); |
|
288 return test_result; |
|
289 } /* main */ |
|
290 |
|
291 /* bigfile.c */ |