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 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
|
/* files.c
*
* This is a work of the US Government. In accordance with 17 USC 105,
* copyright protection is not available for any work of the US Government.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#include "foremost.h"
/* Audit File
The audit file is opened before we do the digging.
This file will be closed either at the end of the program,
or by a signal_handler if the user sends a SIGINT or SIGTERM...
*/
/* Returns TRUE if the directory exists and is empty.
If the directory does not exist, we attempt to create it.
On error, returns FALSE */
int outputDirectoryOK(char *dir) {
DIR *temp;
struct dirent *entry;
int i;
mode_t newDirectoryMode;
if ((temp = opendir(dir)) == NULL) {
/* If the directory doesn't exist (ENOENT), we will create it */
if (errno == ENOENT) {
/* The directory mode values come from the chmod(2) man page */
#ifdef __MINGW32__
newDirectoryMode = 0;
if(mkdir(dir)){
#else
newDirectoryMode = (S_IRUSR | S_IWUSR | S_IXUSR |
S_IRGRP | S_IWGRP | S_IXGRP |
S_IROTH | S_IWOTH);
if (mkdir(dir,newDirectoryMode)) {
#endif
fprintf (stderr,"An error occured while trying to create %s - %s\n",
dir,strerror(errno));
return FALSE;
}
/* So now that we've created the directory we should
be able to open it. Let's try again */
if ((temp = opendir(dir)) == NULL) {
fprintf (stderr,"An error occured while trying to open %s - %s\n",
dir,strerror(errno));
return FALSE;
}
}
/* This is going back to the first time we tried to open the directory
and failed for a reason other than "file does not exist." */
else {
fprintf (stderr,"An error occured while trying to open %s - %s\n",
dir,strerror(errno));
return FALSE;
}
}
/* The directory is open. Let's verify that it's empty. There should
be only two entries "." and ".." */
i=0;
while((entry = readdir(temp))) {
if(i>1){
fprintf (stderr, NONEMPTYDIR_ERROR_MSG);
return FALSE;
}
i++;
}
closedir(temp);
return TRUE;
}
int openAuditFile(struct foremostState* state){
time_t now = time(NULL);
char* timestring = ctime(&now);
char fn[MAX_STRING_LENGTH];
if (!outputDirectoryOK(state->outputdirectory))
return FOREMOST_ERROR_FILE_OPEN;
snprintf(fn,MAX_STRING_LENGTH,"%s/audit.txt",
state->outputdirectory);
if(!(state->auditFile = fopen(fn,"w"))) {
fprintf(stderr,"Couldn't open %s -- %s\n",fn,strerror(errno));
return FOREMOST_ERROR_FILE_OPEN;
}
fprintf (state->auditFile,
"\nForemost version %s audit file\n"
"Started at %sCommand line:\n%s\n\n"
"Output directory: %s\n"
"Configuration file: %s\n",
FOREMOST_VERSION, timestring, state->invocation,
state->outputdirectory,state->conffile);
if (state->modeQuick){
fprintf(state->auditFile,"Quick mode enabled.\n");
}
return FOREMOST_OK;
}
int closeFile(FILE* f){
time_t now = time(NULL);
char* timestring = ctime(&now);
fprintf (f, "\n\nCompleted at %s", timestring);
if(fclose(f)){
return FOREMOST_ERROR_FILE_CLOSE;
}
return FOREMOST_OK;
}
/* writeToDisk(char* suffix of file to be written,
struct foremostState* program state
struct CharBucket* text to be written)
unsigned long long offset in the image file
from we should start writing
Writes text, a file of format suffix, to the disk, in order.
Returns FOREMOST_OK on success. */
int writeToDisk(char* suffix,
int length,
struct foremostState* state,
struct CharBucket* text,
unsigned long long offset){
char fn[MAX_STRING_LENGTH], sectorHeader, chopped;
FILE* f;
long byteswritten = 0;
int noSuffixThisTime = FALSE;
/* RBF - This is a kludgy way to check if we have to ignore
RBF - the suffix. This MUST be fixed. */
if (state->modeNoSuffix || suffix[0] == FOREMOST_NOEXTENSION) {
noSuffixThisTime = TRUE;
snprintf(fn,MAX_STRING_LENGTH,"%s/%08d",
state->outputdirectory,state->fileswritten);
} else {
snprintf(fn,MAX_STRING_LENGTH,"%s/%08d.%s",
state->outputdirectory,state->fileswritten,suffix);
}
if (offset % FOREMOST_BLOCK_SIZE != 0)
sectorHeader = 'X';
else
sectorHeader = ' ';
/* RBF - The CHOP field must be documented! */
if(text->length == length)
chopped = 'X';
else
chopped = ' ';
/* Originally we wrote the full path to the audit file, but that leads
to problems when the path is long. Because the path is printed at
the top of the audit file, we don't have to repeat it every time. (JK) */
if (noSuffixThisTime) {
fprintf(state->auditFile,
"%08d %14Ld %c %c %7ld %s\n",
state->fileswritten,
offset,sectorHeader,chopped,
text->length,basename(state->imagefile));
}else{
fprintf(state->auditFile,"%08d.%s ",state->fileswritten,suffix);
fprintf(state->auditFile,"%13Ld ",offset);
fprintf(state->auditFile,"%c ",sectorHeader);
fprintf(state->auditFile,"%c ",chopped);
fprintf(state->auditFile,"%7ld ",text->length);
fprintf(state->auditFile,"%s\n",basename(state->imagefile));
}
if(!(f = fopen(fn,"w"))){
fprintf (stderr, "Error opening file: %s -- %s\n",
fn, strerror(errno));
fprintf (state->auditFile, "Error opening file: %s -- %s\n",
fn, strerror(errno));
return FOREMOST_ERROR_FILE_OPEN;
}
if ((byteswritten = fwrite(text->str,
sizeof(char),
text->length,f)) != text->length) {
fprintf(stderr,"Error writing to file: %s -- %s\n",
fn, strerror(ferror(f)));
fprintf(state->auditFile,"Error writing to file: %s -- %s\n",
fn, strerror(ferror(f)));
return FOREMOST_ERROR_FILE_WRITE;
}
if(fclose(f)){
fprintf(stderr, "Error closing file: %s -- %s\n\n",
fn,strerror(ferror(f)));
fprintf(state->auditFile, "Error closing file: %s -- %s\n\n",
fn,strerror(ferror(f)));
return FOREMOST_ERROR_FILE_WRITE;
}
if (state->modeVerbose) {
fprintf (stdout,"Wrote file %s -- Success\n", basename(fn));
}
/* We only say that we wrote the file if we were successful. This
statement was originally immediately after the snprintf for the
filename. Because we use the variable fileswritten elsewhere in
this function I've moved it down here. (JK) */
state->fileswritten++;
return FOREMOST_OK;
}
/* Return the size, in bytes of an open file stream. On error, return -1 */
unsigned long long measureOpenFile(FILE *f){
/* If numsectors and total are not initialized, you will get wildly
innacurate results at run time */
unsigned long long total = 0, original = ftello(f);
#ifdef __LINUX
int descriptor = 0;
struct stat *info;
unsigned long long numsectors = 0;
#endif
if ((fseeko(f,0,SEEK_END)))
return -1;
total = ftello(f);
if ((fseeko(f,original,SEEK_SET)))
return -1;
#ifdef __LINUX
/* Block devices, like /dev/hda, don't return a normal filesize.
If we are working with a block device, we have to ask the operating
system to tell us the true size of the device.
The following only works on Linux as far as I know. If you know
how to port this code to another operating system, please contact
the current maintainer of this program! */
descriptor = fileno(f);
info = (struct stat*)malloc(sizeof(struct stat));
/* I'd prefer not to use fstat as it will follow symbolic links. We don't
follow symbolic links. That being said, all symbolic links *should*
have been caught before we got here. */
fstat(descriptor,info);
if (S_ISBLK(info->st_mode)) {
if (ioctl(descriptor, BLKGETSIZE, &numsectors)){
#if defined(__DEBUG)
perror("BLKGETSIZE failed");
#endif
} else {
/* We're going to assume that this device has 512 byte sectors.
Eventually we should add a way to get the real number of sectors
from the device. */
total = numsectors * 512;
}
}
free(info);
#endif /* #ifdef __LINUX */
return (total - original);
}
|