File: files.c

package info (click to toggle)
foremost 0.69-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 148 kB
  • ctags: 153
  • sloc: ansic: 1,297; makefile: 108
file content (300 lines) | stat: -rwxr-xr-x 8,454 bytes parent folder | download
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);
}