1 /******************************* LICENCE **************************************
2 * Any code in this file may be redistributed or modified under the terms of
3 * the GNU General Public Licence as published by the Free Software
4 * Foundation; version 2 of the licence.
5 ****************************** END LICENCE ***********************************/
6
7 /******************************************************************************
8 * Author:
9 * Andrew Smith, http://littlesvr.ca/misc/contactandrew.php
10 *
11 * Contributors:
12 *
13 ******************************************************************************/
14
15 #include <dirent.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <stdio.h>
21
22 #include "bk.h"
23 #include "bkPath.h"
24 #include "bkAdd.h"
25 #include "bkError.h"
26 #include "bkGet.h"
27 #include "bkMangle.h"
28 #include "bkLink.h"
29 #include "bkMisc.h"
30 #include "bkSet.h"
31 #include "bkIoWrappers.h"
32
add(VolInfo * volInfo,const char * srcPathAndName,BkDir * destDir,const char * nameToUse)33 int add(VolInfo* volInfo, const char* srcPathAndName, BkDir* destDir,
34 const char* nameToUse)
35 {
36 int rc;
37 char lastName[NCHARS_FILE_ID_MAX_STORE];
38 BkFileBase* oldHead; /* of the children list */
39 BkStatStruct statStruct;
40
41 if(volInfo->stopOperation)
42 return BKERROR_OPER_CANCELED_BY_USER;
43
44 maybeUpdateProgress(volInfo);
45
46 if(nameToUse == NULL)
47 {
48 rc = getLastNameFromPath(srcPathAndName, lastName);
49 if(rc <= 0)
50 return rc;
51 }
52 else
53 {
54 if(strlen(nameToUse) > NCHARS_FILE_ID_MAX_STORE - 1)
55 return BKERROR_MAX_NAME_LENGTH_EXCEEDED;
56 strcpy(lastName, nameToUse);
57 }
58
59 if(strcmp(lastName, ".") == 0 || strcmp(lastName, "..") == 0)
60 return BKERROR_NAME_INVALID;
61
62 if( !nameIsValid(lastName) )
63 return BKERROR_NAME_INVALID_CHAR;
64
65 oldHead = destDir->children;
66
67 /* windows doesn't have symbolic links */
68 if(volInfo->followSymLinks)
69 rc = bkStat(srcPathAndName, &statStruct);
70 else
71 rc = lstat(srcPathAndName, &statStruct);
72 if(rc == -1)
73 return BKERROR_STAT_FAILED;
74
75 if( IS_DIR(statStruct.st_mode) )
76 {
77 BkDir* newDir;
78
79 newDir = malloc(sizeof(BkDir));
80 if(newDir == NULL)
81 return BKERROR_OUT_OF_MEMORY;
82
83 memset(newDir, 0, sizeof(BkDir));
84
85 strcpy(BK_BASE_PTR(newDir)->name, lastName);
86
87 BK_BASE_PTR(newDir)->posixFileMode = statStruct.st_mode;
88
89 BK_BASE_PTR(newDir)->next = oldHead;
90
91 newDir->children = NULL;
92
93 /* ADD dir contents */
94 rc = addDirContents(volInfo, srcPathAndName, newDir);
95 if(rc < 0)
96 {
97 free(newDir);
98 return rc;
99 }
100 /* END ADD dir contents */
101
102 destDir->children = BK_BASE_PTR(newDir);
103 }
104 else if( IS_REG_FILE(statStruct.st_mode) )
105 {
106 BkFile* newFile;
107
108 if(statStruct.st_size > 0xFFFFFFFF)
109 /* size won't fit in a 32bit variable on the iso */
110 return BKERROR_ADD_FILE_TOO_BIG;
111
112 newFile = malloc(sizeof(BkFile));
113 if(newFile == NULL)
114 return BKERROR_OUT_OF_MEMORY;
115
116 memset(newFile, 0, sizeof(BkFile));
117
118 strcpy(BK_BASE_PTR(newFile)->name, lastName);
119
120 BK_BASE_PTR(newFile)->posixFileMode = statStruct.st_mode;
121
122 BK_BASE_PTR(newFile)->next = oldHead;
123
124 newFile->size = statStruct.st_size;
125
126 newFile->onImage = false;
127
128 newFile->position = 0;
129
130 newFile->pathAndName = malloc(strlen(srcPathAndName) + 1);
131 strcpy(newFile->pathAndName, srcPathAndName);
132
133 if( volInfo->scanForDuplicateFiles)
134 {
135 BkHardLink* newLink;
136
137 rc = findInHardLinkTable(volInfo, 0, newFile->pathAndName,
138 statStruct.st_size, false, &newLink);
139 if(rc < 0)
140 {
141 free(newFile);
142 return rc;
143 }
144
145 if(newLink == NULL)
146 /* not found */
147 {
148 rc = addToHardLinkTable(volInfo, 0, newFile->pathAndName,
149 statStruct.st_size, false, &newLink);
150 if(rc < 0)
151 {
152 free(newFile);
153 return rc;
154 }
155 }
156
157 newFile->location = newLink;
158 }
159
160 destDir->children = BK_BASE_PTR(newFile);
161 }
162 else if( IS_SYMLINK(statStruct.st_mode) )
163 {
164 BkSymLink* newSymLink;
165 ssize_t numChars;
166
167 newSymLink = malloc(sizeof(BkSymLink));
168 if(newSymLink == NULL)
169 return BKERROR_OUT_OF_MEMORY;
170
171 memset(newSymLink, 0, sizeof(BkSymLink));
172
173 strcpy(BK_BASE_PTR(newSymLink)->name, lastName);
174
175 BK_BASE_PTR(newSymLink)->posixFileMode = statStruct.st_mode;
176
177 BK_BASE_PTR(newSymLink)->next = oldHead;
178
179 numChars = readlink(srcPathAndName, newSymLink->target,
180 NCHARS_SYMLINK_TARGET_MAX - 1);
181 if(numChars == -1)
182 {
183 free(newSymLink);
184 return BKERROR_OPEN_READ_FAILED;
185 }
186 newSymLink->target[numChars] = '\0';
187
188 destDir->children = BK_BASE_PTR(newSymLink);
189 }
190 else
191 return BKERROR_NO_SPECIAL_FILES;
192
193 return 1;
194 }
195
addDirContents(VolInfo * volInfo,const char * srcPath,BkDir * destDir)196 int addDirContents(VolInfo* volInfo, const char* srcPath, BkDir* destDir)
197 {
198 int rc;
199 int srcPathLen;
200 char* newSrcPathAndName;
201
202 /* vars to read contents of a dir on fs */
203 DIR* srcDir;
204 struct dirent* dirEnt;
205
206 srcPathLen = strlen(srcPath);
207
208 /* including the new name and the possibly needed trailing '/' */
209 newSrcPathAndName = malloc(srcPathLen + NCHARS_FILE_ID_MAX_STORE + 2);
210 if(newSrcPathAndName == NULL)
211 return BKERROR_OUT_OF_MEMORY;
212
213 strcpy(newSrcPathAndName, srcPath);
214
215 if(srcPath[srcPathLen - 1] != '/')
216 {
217 strcat(newSrcPathAndName, "/");
218 srcPathLen++;
219 }
220
221 srcDir = opendir(srcPath);
222 if(srcDir == NULL)
223 {
224 free(newSrcPathAndName);
225 return BKERROR_OPENDIR_FAILED;
226 }
227
228 /* it may be possible but in any case very unlikely that readdir() will fail
229 * if it does, it returns NULL (same as end of dir) */
230 while( (dirEnt = readdir(srcDir)) != NULL )
231 {
232 if( strcmp(dirEnt->d_name, ".") == 0 || strcmp(dirEnt->d_name, "..") == 0 )
233 /* ignore "." and ".." */
234 continue;
235
236 if(strlen(dirEnt->d_name) > NCHARS_FILE_ID_MAX_STORE - 1)
237 {
238 closedir(srcDir);
239 free(newSrcPathAndName);
240
241 return BKERROR_MAX_NAME_LENGTH_EXCEEDED;
242 }
243
244 /* append file/dir name */
245 strcpy(newSrcPathAndName + srcPathLen, dirEnt->d_name);
246
247 rc = add(volInfo, newSrcPathAndName, destDir, NULL);
248 if(rc <= 0 && rc != BKWARNING_OPER_PARTLY_FAILED)
249 {
250 bool goOn;
251
252 if(volInfo->warningCbk != NULL && !volInfo->stopOperation)
253 /* perhaps the user wants to ignore this failure */
254 {
255 snprintf(volInfo->warningMessage, BK_WARNING_MAX_LEN,
256 "Failed to add item '%s': '%s'",
257 dirEnt->d_name,
258 bk_get_error_string(rc));
259 goOn = volInfo->warningCbk(volInfo->warningMessage);
260 rc = BKWARNING_OPER_PARTLY_FAILED;
261 }
262 else
263 goOn = false;
264
265 if(goOn)
266 continue;
267 else
268 {
269 volInfo->stopOperation = true;
270 closedir(srcDir);
271 free(newSrcPathAndName);
272 return rc;
273 }
274 }
275 }
276
277 free(newSrcPathAndName);
278
279 rc = closedir(srcDir);
280 if(rc != 0)
281 /* exotic error */
282 return BKERROR_EXOTIC;
283
284 return 1;
285 }
286
bk_add(VolInfo * volInfo,const char * srcPathAndName,const char * destPathStr,void (* progressFunction)(VolInfo *))287 int bk_add(VolInfo* volInfo, const char* srcPathAndName,
288 const char* destPathStr, void(*progressFunction)(VolInfo*))
289 {
290 return bk_add_as(volInfo, srcPathAndName, destPathStr, NULL,
291 progressFunction);
292 }
293
bk_add_as(VolInfo * volInfo,const char * srcPathAndName,const char * destPathStr,const char * nameToUse,void (* progressFunction)(VolInfo *))294 int bk_add_as(VolInfo* volInfo, const char* srcPathAndName,
295 const char* destPathStr, const char* nameToUse,
296 void(*progressFunction)(VolInfo*))
297 {
298 int rc;
299 NewPath destPath;
300 char lastName[NCHARS_FILE_ID_MAX_STORE];
301
302 /* vars to find the dir in the tree */
303 BkDir* destDirInTree;
304 bool dirFound;
305
306 volInfo->progressFunction = progressFunction;
307
308 rc = makeNewPathFromString(destPathStr, &destPath);
309 if(rc <= 0)
310 {
311 freePathContents(&destPath);
312 return rc;
313 }
314
315 rc = getLastNameFromPath(srcPathAndName, lastName);
316 if(rc <= 0)
317 {
318 freePathContents(&destPath);
319 return rc;
320 }
321
322 dirFound = findDirByNewPath(&destPath, &(volInfo->dirTree), &destDirInTree);
323 if(!dirFound)
324 {
325 freePathContents(&destPath);
326 return BKERROR_DIR_NOT_FOUND_ON_IMAGE;
327 }
328
329 freePathContents(&destPath);
330
331 if(itemIsInDir(lastName, destDirInTree))
332 return BKERROR_DUPLICATE_ADD;
333
334 volInfo->stopOperation = false;
335
336 rc = add(volInfo, srcPathAndName, destDirInTree, nameToUse);
337 if(rc <= 0)
338 return rc;
339
340 return 1;
341 }
342
343 /*******************************************************************************
344 * bk_add_boot_record()
345 * Source boot file must be exactly the right size if floppy emulation requested.
346 * */
bk_add_boot_record(VolInfo * volInfo,const char * srcPathAndName,int bootMediaType)347 int bk_add_boot_record(VolInfo* volInfo, const char* srcPathAndName,
348 int bootMediaType)
349 {
350 BkStatStruct statStruct;
351 int rc;
352
353 if(bootMediaType != BOOT_MEDIA_NO_EMULATION &&
354 bootMediaType != BOOT_MEDIA_1_2_FLOPPY &&
355 bootMediaType != BOOT_MEDIA_1_44_FLOPPY &&
356 bootMediaType != BOOT_MEDIA_2_88_FLOPPY)
357 {
358 return BKERROR_ADD_UNKNOWN_BOOT_MEDIA;
359 }
360
361 rc = bkStat(srcPathAndName, &statStruct);
362 if(rc == -1)
363 return BKERROR_STAT_FAILED;
364
365 if(statStruct.st_size > 0xFFFFFFFF)
366 /* size won't fit in a 32bit variable on the iso */
367 return BKERROR_ADD_FILE_TOO_BIG;
368
369 if( (bootMediaType == BOOT_MEDIA_1_2_FLOPPY &&
370 statStruct.st_size != 1228800) ||
371 (bootMediaType == BOOT_MEDIA_1_44_FLOPPY &&
372 statStruct.st_size != 1474560) ||
373 (bootMediaType == BOOT_MEDIA_2_88_FLOPPY &&
374 statStruct.st_size != 2949120) )
375 {
376 return BKERROR_ADD_BOOT_RECORD_WRONG_SIZE;
377 }
378
379 volInfo->bootMediaType = bootMediaType;
380
381 volInfo->bootRecordSize = statStruct.st_size;
382
383 volInfo->bootRecordIsOnImage = false;
384
385 /* make copy of the source path and name */
386 if(volInfo->bootRecordPathAndName != NULL)
387 free(volInfo->bootRecordPathAndName);
388 volInfo->bootRecordPathAndName = malloc(strlen(srcPathAndName) + 1);
389 if(volInfo->bootRecordPathAndName == NULL)
390 {
391 volInfo->bootMediaType = BOOT_MEDIA_NONE;
392 return BKERROR_OUT_OF_MEMORY;
393 }
394 strcpy(volInfo->bootRecordPathAndName, srcPathAndName);
395
396 /* this is the wrong function to use if you want a visible one */
397 volInfo->bootRecordIsVisible = false;
398
399 return 1;
400 }
401
402 /*******************************************************************************
403 * bk_create_dir()
404 *
405 * */
bk_create_dir(VolInfo * volInfo,const char * destPathStr,const char * newDirName)406 int bk_create_dir(VolInfo* volInfo, const char* destPathStr,
407 const char* newDirName)
408 {
409 size_t nameLen;
410 BkDir* destDir;
411 int rc;
412 BkFileBase* oldHead;
413 BkDir* newDir;
414
415 nameLen = strlen(newDirName);
416 if(nameLen > NCHARS_FILE_ID_MAX_STORE - 1)
417 return BKERROR_MAX_NAME_LENGTH_EXCEEDED;
418 if(nameLen == 0)
419 return BKERROR_BLANK_NAME;
420
421 if(strcmp(newDirName, ".") == 0 || strcmp(newDirName, "..") == 0)
422 return BKERROR_NAME_INVALID;
423
424 if( !nameIsValid(newDirName) )
425 return BKERROR_NAME_INVALID_CHAR;
426
427 rc = getDirFromString(&(volInfo->dirTree), destPathStr, &destDir);
428 if(rc <= 0)
429 return rc;
430
431 if(itemIsInDir(newDirName, destDir))
432 return BKERROR_DUPLICATE_CREATE_DIR;
433
434 oldHead = destDir->children;
435
436 newDir = malloc(sizeof(BkDir));
437 if(newDir == NULL)
438 return BKERROR_OUT_OF_MEMORY;
439
440 strcpy(BK_BASE_PTR(newDir)->name, newDirName);
441
442 BK_BASE_PTR(newDir)->posixFileMode = volInfo->posixDirDefaults;
443
444 BK_BASE_PTR(newDir)->next = oldHead;
445
446 newDir->children = NULL;
447
448 destDir->children = BK_BASE_PTR(newDir);
449
450 return 1;
451 }
452