]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/create_file.c
- Apply patch from Christopher Hull
[bacula/bacula] / bacula / src / findlib / create_file.c
1 /*
2  *  Create a file, and reset the modes
3  *
4  *    Kern Sibbald, November MM
5  *
6  *   Version $Id$
7  *
8  */
9 /*
10    Copyright (C) 2000-2006 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
20    the file LICENSE for additional details.
21
22  */
23
24 #include "bacula.h"
25 #include "find.h"
26
27 #ifndef S_IRWXUGO
28 #define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO)
29 #endif
30
31 #ifndef IS_CTG
32 #define IS_CTG(x) 0
33 #define O_CTG 0
34 #endif
35
36 static int separate_path_and_file(JCR *jcr, char *fname, char *ofile);
37 static int path_already_seen(JCR *jcr, char *path, int pnl);
38
39
40 /*
41  * Create the file, or the directory
42  *
43  *  fname is the original filename
44  *  ofile is the output filename (may be in a different directory)
45  *
46  * Returns:  CF_SKIP     if file should be skipped
47  *           CF_ERROR    on error
48  *           CF_EXTRACT  file created and data to restore
49  *           CF_CREATED  file created no data to restore
50  *
51  *   Note, we create the file here, except for special files,
52  *     we do not set the attributes because we want to first
53  *     write the file, then when the writing is done, set the
54  *     attributes.
55  *   So, we return with the file descriptor open for normal
56  *     files.
57  *
58  */
59 int create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
60 {
61    int new_mode, parent_mode, mode;
62    uid_t uid;
63    gid_t gid;
64    int pnl;
65    bool exists = false;
66    struct stat mstatp;
67
68    if (is_win32_stream(attr->data_stream)) {
69       set_win32_backup(bfd);
70    } else {
71       set_portable_backup(bfd);
72    }
73
74    new_mode = attr->statp.st_mode;
75    Dmsg3(200, "type=%d newmode=%x file=%s\n", attr->type, new_mode, attr->ofname);
76    parent_mode = S_IWUSR | S_IXUSR | new_mode;
77    gid = attr->statp.st_gid;
78    uid = attr->statp.st_uid;
79
80 #ifdef HAVE_WIN32
81    if (!bfd->use_backup_api) {
82       // eliminate invalid windows filename characters from foreign filenames
83       char *ch = (char *)attr->ofname;
84       if (ch[0] != 0 && ch[1] != 0) {
85          ch+=2;
86          while (*ch) {
87             switch (*ch) {
88             case ':':
89             case '<':
90             case '>':
91             case '*':
92             case '?':
93             case '|':
94                *ch = '_';
95                 break;
96             }
97             ch++;
98          }
99       }
100    }
101 #endif
102
103    Dmsg2(400, "Replace=%c %d\n", (char)replace, replace);
104    if (lstat(attr->ofname, &mstatp) == 0) {
105       exists = true;
106       switch (replace) {
107       case REPLACE_IFNEWER:
108          if (attr->statp.st_mtime <= mstatp.st_mtime) {
109             Qmsg(jcr, M_SKIPPED, 0, _("File skipped. Not newer: %s\n"), attr->ofname);
110             return CF_SKIP;
111          }
112          break;
113
114       case REPLACE_IFOLDER:
115          if (attr->statp.st_mtime >= mstatp.st_mtime) {
116             Qmsg(jcr, M_SKIPPED, 0, _("File skipped. Not older: %s\n"), attr->ofname);
117             return CF_SKIP;
118          }
119          break;
120
121       case REPLACE_NEVER:
122          Qmsg(jcr, M_SKIPPED, 0, _("File skipped. Already exists: %s\n"), attr->ofname);
123          return CF_SKIP;
124
125       case REPLACE_ALWAYS:
126          break;
127       }
128    }
129    switch (attr->type) {
130    case FT_RAW:                       /* raw device to be written */
131    case FT_FIFO:                      /* FIFO to be written to */
132    case FT_LNKSAVED:                  /* Hard linked, file already saved */
133    case FT_LNK:
134    case FT_SPEC:                      /* fifo, ... to be backed up */
135    case FT_REGE:                      /* empty file */
136    case FT_REG:                       /* regular file */
137       /* 
138        * Note, we do not delete FT_RAW because these are device files
139        *  or FIFOs that should already exist. If we blow it away,
140        *  we may blow away a FIFO that is being used to read the
141        *  restore data, or we may blow away a partition definition.
142        */
143       if (exists && attr->type != FT_RAW && attr->type != FT_FIFO) {
144          /* Get rid of old copy */
145          if (unlink(attr->ofname) == -1) {
146             berrno be;
147             Qmsg(jcr, M_ERROR, 0, _("File %s already exists and could not be replaced. ERR=%s.\n"),
148                attr->ofname, be.strerror());
149             /* Continue despite error */
150          }
151       }
152       /*
153        * Here we do some preliminary work for all the above
154        *   types to create the path to the file if it does
155        *   not already exist.  Below, we will split to
156        *   do the file type specific work
157        */
158       pnl = separate_path_and_file(jcr, attr->fname, attr->ofname);
159       if (pnl < 0) {
160          return CF_ERROR;
161       }
162
163       /*
164        * If path length is <= 0 we are making a file in the root
165        *  directory. Assume that the directory already exists.
166        */
167       if (pnl > 0) {
168          char savechr;
169          savechr = attr->ofname[pnl];
170          attr->ofname[pnl] = 0;                 /* terminate path */
171
172          if (!path_already_seen(jcr, attr->ofname, pnl)) {
173             Dmsg1(100, "Make path %s\n", attr->ofname);
174             /*
175              * If we need to make the directory, ensure that it is with
176              * execute bit set (i.e. parent_mode), and preserve what already
177              * exists. Normally, this should do nothing.
178              */
179             if (make_path(jcr, attr->ofname, parent_mode, parent_mode, uid, gid, 1, NULL) != 0) {
180                Dmsg1(10, "Could not make path. %s\n", attr->ofname);
181                attr->ofname[pnl] = savechr;     /* restore full name */
182                return CF_ERROR;
183             }
184          }
185          attr->ofname[pnl] = savechr;           /* restore full name */
186       }
187
188       /* Now we do the specific work for each file type */
189       switch(attr->type) {
190       case FT_REGE:
191       case FT_REG:
192          Dmsg1(100, "Create file %s\n", attr->ofname);
193          mode =  O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; /*  O_NOFOLLOW; */
194          if (IS_CTG(attr->statp.st_mode)) {
195             mode |= O_CTG;               /* set contiguous bit if needed */
196          }
197          Dmsg1(50, "Create file: %s\n", attr->ofname);
198          if (is_bopen(bfd)) {
199             Qmsg1(jcr, M_ERROR, 0, _("bpkt already open fid=%d\n"), bfd->fid);
200             bclose(bfd);
201          }
202       
203
204          if ((bopen(bfd, attr->ofname, mode, S_IRUSR | S_IWUSR)) < 0) {
205             berrno be;
206             be.set_errno(bfd->berrno);
207             Qmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"),
208                   attr->ofname, be.strerror());
209             return CF_ERROR;
210          }
211          return CF_EXTRACT;
212
213 #ifndef HAVE_WIN32  // none of these exists on MS Windows
214       case FT_RAW:                    /* Bacula raw device e.g. /dev/sda1 */
215       case FT_FIFO:                   /* Bacula fifo to save data */
216       case FT_SPEC:
217          if (S_ISFIFO(attr->statp.st_mode)) {
218             Dmsg1(200, "Restore fifo: %s\n", attr->ofname);
219             if (mkfifo(attr->ofname, attr->statp.st_mode) != 0 && errno != EEXIST) {
220                berrno be;
221                Qmsg2(jcr, M_ERROR, 0, _("Cannot make fifo %s: ERR=%s\n"),
222                      attr->ofname, be.strerror());
223                return CF_ERROR;
224             }
225          } else if(S_ISSOCK(attr->statp.st_mode)) {
226              Dmsg1(200, "Skipping restore of socket: %s\n", attr->ofname);
227          } else {
228             Dmsg1(200, "Restore node: %s\n", attr->ofname);
229             if (mknod(attr->ofname, attr->statp.st_mode, attr->statp.st_rdev) != 0 && errno != EEXIST) {
230                berrno be;
231                Qmsg2(jcr, M_ERROR, 0, _("Cannot make node %s: ERR=%s\n"),
232                      attr->ofname, be.strerror());
233                return CF_ERROR;
234             }
235          }
236          if (attr->type == FT_RAW || attr->type == FT_FIFO) {
237             btimer_t *tid;
238             Dmsg1(200, "FT_RAW|FT_FIFO %s\n", attr->ofname);
239             mode =  O_WRONLY | O_BINARY;
240             /* Timeout open() in 60 seconds */
241             if (attr->type == FT_FIFO) {
242                Dmsg0(200, "Set FIFO timer\n");
243                tid = start_thread_timer(pthread_self(), 60);
244             } else {
245                tid = NULL;
246             }
247             if (is_bopen(bfd)) {
248                Qmsg1(jcr, M_ERROR, 0, _("bpkt already open fid=%d\n"), bfd->fid);
249             }
250             Dmsg2(200, "open %s mode=0x%x\n", attr->ofname, mode);
251             if ((bopen(bfd, attr->ofname, mode, 0)) < 0) {
252                berrno be;
253                be.set_errno(bfd->berrno);
254                Qmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"),
255                      attr->ofname, be.strerror());
256                stop_thread_timer(tid);
257                return CF_ERROR;
258             }
259             stop_thread_timer(tid);
260             return CF_EXTRACT;
261          }
262          Dmsg1(200, "FT_SPEC %s\n", attr->ofname);
263          return CF_CREATED;
264
265       case FT_LNK:
266          Dmsg2(130, "FT_LNK should restore: %s -> %s\n", attr->ofname, attr->olname);
267          if (symlink(attr->olname, attr->ofname) != 0 && errno != EEXIST) {
268             berrno be;
269             Qmsg3(jcr, M_ERROR, 0, _("Could not symlink %s -> %s: ERR=%s\n"),
270                   attr->ofname, attr->olname, be.strerror());
271             return CF_ERROR;
272          }
273          return CF_CREATED;
274
275       case FT_LNKSAVED:                  /* Hard linked, file already saved */
276          Dmsg2(130, "Hard link %s => %s\n", attr->ofname, attr->olname);
277          if (link(attr->olname, attr->ofname) != 0) {
278             berrno be;
279             Qmsg3(jcr, M_ERROR, 0, _("Could not hard link %s -> %s: ERR=%s\n"),
280                   attr->ofname, attr->olname, be.strerror());
281             return CF_ERROR;
282          }
283          return CF_CREATED;
284 #endif
285       } /* End inner switch */
286
287    case FT_DIRBEGIN:
288    case FT_DIREND:
289       Dmsg2(200, "Make dir mode=%o dir=%s\n", new_mode, attr->ofname);
290       if (make_path(jcr, attr->ofname, new_mode, parent_mode, uid, gid, 0, NULL) != 0) {
291          return CF_ERROR;
292       }
293       /*
294        * If we are using the Win32 Backup API, we open the
295        *   directory so that the security info will be read
296        *   and saved.
297        */
298       if (!is_portable_backup(bfd)) {
299          if (is_bopen(bfd)) {
300             Qmsg1(jcr, M_ERROR, 0, _("bpkt already open fid=%d\n"), bfd->fid);
301          }
302          if ((bopen(bfd, attr->ofname, O_WRONLY|O_BINARY, 0)) < 0) {
303             berrno be;
304             be.set_errno(bfd->berrno);
305 #ifdef HAVE_WIN32
306             /* Check for trying to create a drive, if so, skip */
307             if (attr->ofname[1] == ':' && attr->ofname[2] == '/' && attr->ofname[3] == 0) {
308                return CF_SKIP;
309             }
310 #endif
311             Qmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"),
312                   attr->ofname, be.strerror());
313             return CF_ERROR;
314          }
315          return CF_EXTRACT;
316       } else {
317          return CF_CREATED;
318       }
319
320    /* The following should not occur */
321    case FT_NOACCESS:
322    case FT_NOFOLLOW:
323    case FT_NOSTAT:
324    case FT_DIRNOCHG:
325    case FT_NOCHG:
326    case FT_ISARCH:
327    case FT_NORECURSE:
328    case FT_NOFSCHG:
329    case FT_NOOPEN:
330       Qmsg2(jcr, M_ERROR, 0, _("Original file %s not saved: type=%d\n"), attr->fname, attr->type);
331       break;
332    default:
333       Qmsg2(jcr, M_ERROR, 0, _("Unknown file type %d; not restored: %s\n"), attr->type, attr->fname);
334       break;
335    }
336    return CF_ERROR;
337 }
338
339 /*
340  *  Returns: > 0 index into path where last path char is.
341  *           0  no path
342  *           -1 filename is zero length
343  */
344 static int separate_path_and_file(JCR *jcr, char *fname, char *ofile)
345 {
346    char *f, *p;
347    int fnl, pnl;
348
349    /* Separate pathname and filename */
350    for (p=f=ofile; *p; p++) {
351       if (*p == '/') {
352          f = p;                    /* possible filename */
353       }
354    }
355    if (*f == '/') {
356       f++;
357    }
358
359    fnl = p - f;
360    if (fnl == 0) {
361       /* The filename length must not be zero here because we
362        *  are dealing with a file (i.e. FT_REGE or FT_REG).
363        */
364       Qmsg1(jcr, M_ERROR, 0, _("Zero length filename: %s\n"), fname);
365       return -1;
366    }
367    pnl = f - ofile - 1;
368    return pnl;
369 }
370
371 /*
372  * Primitive caching of path to prevent recreating a pathname
373  *   each time as long as we remain in the same directory.
374  */
375 static int path_already_seen(JCR *jcr, char *path, int pnl)
376 {
377    if (!jcr->cached_path) {
378       jcr->cached_path = get_pool_memory(PM_FNAME);
379    }
380    if (jcr->cached_pnl == pnl && strcmp(path, jcr->cached_path) == 0) {
381       return 1;
382    }
383    pm_strcpy(&jcr->cached_path, path);
384    jcr->cached_pnl = pnl;
385    return 0;
386 }