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