File: files.c

package info (click to toggle)
scalpel 1.60-6
  • links: PTS, VCS
  • area: main
  • in suites: buster, sid
  • size: 556 kB
  • sloc: ansic: 4,031; makefile: 61
file content (230 lines) | stat: -rw-r--r-- 6,143 bytes parent folder | download | duplicates (2)
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
// Scalpel Copyright (C) 2005-6 by Golden G. Richard III.
// Written by Golden G. Richard III.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
// 
// 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.  See the GNU
// General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301, USA.

// Scalpel is a complete rewrite of the foremost 0.69 file carver to
// increase speed and support execution on machines with minimal
// resources (e.g., < 256MB RAM).
//
// Thanks to Kris Kendall, Jesse Kornblum, et al for their work on
// foremost.

#include "scalpel.h"

// Returns TRUE if the directory exists and is empty. 
// If the directory does not exist, an attempt is made 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 occurred while trying to create %s - %s\n",
		   dir,strerror(errno));
	  return FALSE;
	}
	
	// try to open directory
	if ((temp = opendir(dir)) == NULL) {
	  fprintf (stderr,"An error occurred while trying to open %s - %s\n",
		   dir,strerror(errno));
	  return FALSE;
	}
      }
      else {
	fprintf (stderr,"An error occurred while trying to open %s - %s\n",
		 dir,strerror(errno));
	return FALSE;
      }
    }
    
    // verify directory is 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;
  }
  
  // open audit file
  int openAuditFile(struct scalpelState* state){
    time_t now = time(NULL);
    char* timestring = ctime(&now);
    char fn[MAX_STRING_LENGTH];
    
    if (!outputDirectoryOK(state->outputdirectory)) {
      return SCALPEL_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 SCALPEL_ERROR_FILE_OPEN;
    }
    
    fprintf (state->auditFile,
	     "\nScalpel version %s audit file\n"
	     "Started at %sCommand line:\n%s\n\n"
	     "Output directory: %s\n"
	     "Configuration file: %s\n",
	     SCALPEL_VERSION, timestring, state->invocation,
	     state->outputdirectory,state->conffile);
    
    return SCALPEL_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 SCALPEL_ERROR_FILE_CLOSE;
  }

  return SCALPEL_OK;
}


// helper function for measureOpenFile(), based on e2fsprogs utility 
// function valid_offset()

 static int valid_offset(int fd, off64_t offset) {
     char ch;
     if (lseek(fd, offset, SEEK_SET) < 0) {
       return 0;
     }
     if (read(fd, &ch, 1) < 1) {
       return 0;
     }
     return 1;
 }


// Return the remaining size, in bytes, of an open file stream. On
// error, return -1.  Handling raw device files is substantially more
// complicated than image files.  For Linux, an ioctl() is used.  For
// other operating systems, a "binary search" technique similar to
// that in e2fsprogs getsize.c is used.
 unsigned long long measureOpenFile(FILE *f, struct scalpelState* state) {

   unsigned long long total = 0, original = ftello(f);
   int descriptor = 0;
   struct stat *info;
   unsigned long long numsectors = 0;

   if ((fseeko(f,0,SEEK_END))) {
     if (state->modeVerbose) {
       fprintf(stdout, "fseeko() call failed on image file.\n");
       fprintf(stdout, "Diagnosis: %s\n", strerror(errno));
     }
     return -1;
   }
   total = ftello(f);

   // for block devices (e.g., raw disk devices), calculating size by 
   // seeking the end of the opened stream doesn't work.  For Linux, we use 
   // an ioctl() call.  For others (e.g., OS X), we use binary search.

  // is it a block device?
  descriptor = fileno(f);
  info = (struct stat*)malloc(sizeof(struct stat));
  fstat(descriptor,info);
  if (S_ISBLK(info->st_mode)) {

#if defined (__LINUX) 
    if (ioctl(descriptor, BLKGETSIZE, &numsectors) < 0) {
      if (state->modeVerbose) {
	fprintf(stdout, "Using ioctl() call to measure block device size.\n");
      }
#if defined(__DEBUG)
      perror("BLKGETSIZE failed");
#endif
    }
#else // non-Linux, use binary search

    {
      unsigned long long low, high, mid;

      fprintf(stdout, "Using binary search to measure block device size.\n");
      low = 0;
      for (high = 512; valid_offset(descriptor, high); high *= 2) {
	low = high;
      }
      
      while (low < high - 1)  {
	mid = (low + high) / 2;
	if (valid_offset(descriptor, mid)) {
	  low = mid;
	}
	else {
	  high = mid;
	}
      }
      numsectors = (low + 1) >> 9;
    }
#endif

    // assume device has 512 byte sectors
    total = numsectors * 512;
    
    free(info);
    
  }

  // restore file position

  if ((fseeko(f,original,SEEK_SET))) {
    if (state->modeVerbose) {
      fprintf(stdout, "fseeko() call to restore file position failed on image file.\n");
    }
    return -1;
  }
  
  return (total - original);
}