]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_create.c
ebl fix nasty runscript configuration parsing bug
[bacula/bacula] / bacula / src / cats / sql_create.c
1 /*
2  * Bacula Catalog Database Create record interface routines
3  *
4  *    Kern Sibbald, March 2000
5  *
6  *    Version $Id$
7  */
8 /*
9    Bacula® - The Network Backup Solution
10
11    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
12
13    The main author of Bacula is Kern Sibbald, with contributions from
14    many others, a complete list can be found in the file AUTHORS.
15    This program is Free Software; you can redistribute it and/or
16    modify it under the terms of version two of the GNU General Public
17    License as published by the Free Software Foundation plus additions
18    that are listed in the file LICENSE.
19
20    This program is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23    General Public License for more details.
24
25    You should have received a copy of the GNU General Public License
26    along with this program; if not, write to the Free Software
27    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28    02110-1301, USA.
29
30    Bacula® is a registered trademark of John Walker.
31    The licensor of Bacula is the Free Software Foundation Europe
32    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
33    Switzerland, email:ftf@fsfeurope.org.
34 */
35
36 /* The following is necessary so that we do not include
37  * the dummy external definition of DB.
38  */
39 #define __SQL_C                       /* indicate that this is sql.c */
40
41 #include "bacula.h"
42 #include "cats.h"
43
44 static const int dbglevel = 500;
45
46 #if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL
47
48 /* -----------------------------------------------------------------------
49  *
50  *   Generic Routines (or almost generic)
51  *
52  * -----------------------------------------------------------------------
53  */
54
55 /* Forward referenced subroutines */
56 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
57 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
58 static int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
59
60
61 /* Create a new record for the Job
62  * Returns: false on failure
63  *          true  on success
64  */
65 bool
66 db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
67 {
68    char dt[MAX_TIME_LENGTH];
69    time_t stime;
70    struct tm tm;
71    bool ok;
72    utime_t JobTDate;
73    char ed1[30];
74
75    db_lock(mdb);
76
77    stime = jr->SchedTime;
78    ASSERT(stime != 0);
79
80    (void)localtime_r(&stime, &tm);
81    strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
82    JobTDate = (utime_t)stime;
83
84    /* Must create it */
85    Mmsg(mdb->cmd,
86 "INSERT INTO Job (Job,Name,Type,Level,JobStatus,SchedTime,JobTDate) VALUES "
87 "('%s','%s','%c','%c','%c','%s',%s)",
88            jr->Job, jr->Name, (char)(jr->JobType), (char)(jr->JobLevel),
89            (char)(jr->JobStatus), dt, edit_uint64(JobTDate, ed1));
90
91    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
92       Mmsg2(&mdb->errmsg, _("Create DB Job record %s failed. ERR=%s\n"),
93             mdb->cmd, sql_strerror(mdb));
94       jr->JobId = 0;
95       ok = false;
96    } else {
97       jr->JobId = sql_insert_id(mdb, NT_("Job"));
98       ok = true;
99    }
100    db_unlock(mdb);
101    return ok;
102 }
103
104
105 /* Create a JobMedia record for medium used this job
106  * Returns: false on failure
107  *          true  on success
108  */
109 bool
110 db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm)
111 {
112    bool ok = true;;
113    int count;
114    char ed1[50], ed2[50];
115
116    db_lock(mdb);
117
118    /* Now get count for VolIndex */
119    Mmsg(mdb->cmd, "SELECT count(*) from JobMedia WHERE JobId=%s",
120         edit_int64(jm->JobId, ed1));
121    count = get_sql_record_max(jcr, mdb);
122    if (count < 0) {
123       count = 0;
124    }
125    count++;
126
127    /* Note, jm->Strip is not used and is not likely to be used
128     * in the near future, so I have removed it from the insert
129     * to save space in the DB. KES June 2006.
130     */
131    Mmsg(mdb->cmd,
132         "INSERT INTO JobMedia (JobId,MediaId,FirstIndex,LastIndex,"
133         "StartFile,EndFile,StartBlock,EndBlock,VolIndex,Copy) "
134         "VALUES (%s,%s,%u,%u,%u,%u,%u,%u,%u,%u)",
135         edit_int64(jm->JobId, ed1),
136         edit_int64(jm->MediaId, ed2),
137         jm->FirstIndex, jm->LastIndex,
138         jm->StartFile, jm->EndFile, jm->StartBlock, jm->EndBlock,count,
139         jm->Copy);
140
141    Dmsg0(300, mdb->cmd);
142    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
143       Mmsg2(&mdb->errmsg, _("Create JobMedia record %s failed: ERR=%s\n"), mdb->cmd,
144          sql_strerror(mdb));
145       ok = false;
146    } else {
147       /* Worked, now update the Media record with the EndFile and EndBlock */
148       Mmsg(mdb->cmd,
149            "UPDATE Media SET EndFile=%u, EndBlock=%u WHERE MediaId=%u",
150            jm->EndFile, jm->EndBlock, jm->MediaId);
151       if (!UPDATE_DB(jcr, mdb, mdb->cmd)) {
152          Mmsg2(&mdb->errmsg, _("Update Media record %s failed: ERR=%s\n"), mdb->cmd,
153               sql_strerror(mdb));
154          ok = false;
155       }
156    }
157    db_unlock(mdb);
158    Dmsg0(300, "Return from JobMedia\n");
159    return ok;
160 }
161
162
163
164 /* Create Unique Pool record
165  * Returns: false on failure
166  *          true  on success
167  */
168 bool
169 db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
170 {
171    bool stat;        
172    char ed1[30], ed2[30], ed3[50];
173
174    Dmsg0(200, "In create pool\n");
175    db_lock(mdb);
176    Mmsg(mdb->cmd, "SELECT PoolId,Name FROM Pool WHERE Name='%s'", pr->Name);
177    Dmsg1(200, "selectpool: %s\n", mdb->cmd);
178
179    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
180       mdb->num_rows = sql_num_rows(mdb);
181       if (mdb->num_rows > 0) {
182          Mmsg1(&mdb->errmsg, _("pool record %s already exists\n"), pr->Name);
183          sql_free_result(mdb);
184          db_unlock(mdb);
185          return false;
186       }
187       sql_free_result(mdb);
188    }
189
190    /* Must create it */
191    Mmsg(mdb->cmd,
192 "INSERT INTO Pool (Name,NumVols,MaxVols,UseOnce,UseCatalog,"
193 "AcceptAnyVolume,AutoPrune,Recycle,VolRetention,VolUseDuration,"
194 "MaxVolJobs,MaxVolFiles,MaxVolBytes,PoolType,LabelType,LabelFormat) "
195 "VALUES ('%s',%u,%u,%d,%d,%d,%d,%d,%s,%s,%u,%u,%s,'%s',%d,'%s')",
196                   pr->Name,
197                   pr->NumVols, pr->MaxVols,
198                   pr->UseOnce, pr->UseCatalog,
199                   pr->AcceptAnyVolume,
200                   pr->AutoPrune, pr->Recycle,
201                   edit_uint64(pr->VolRetention, ed1),
202                   edit_uint64(pr->VolUseDuration, ed2),
203                   pr->MaxVolJobs, pr->MaxVolFiles,
204                   edit_uint64(pr->MaxVolBytes, ed3),
205                   pr->PoolType, pr->LabelType, pr->LabelFormat);
206    Dmsg1(200, "Create Pool: %s\n", mdb->cmd);
207    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
208       Mmsg2(&mdb->errmsg, _("Create db Pool record %s failed: ERR=%s\n"),
209             mdb->cmd, sql_strerror(mdb));
210       pr->PoolId = 0;
211       stat = false;
212    } else {
213       pr->PoolId = sql_insert_id(mdb, NT_("Pool"));
214       stat = true;
215    }
216    db_unlock(mdb);
217    return stat;
218 }
219
220 /*
221  * Create Unique Device record
222  * Returns: false on failure
223  *          true  on success
224  */
225 bool
226 db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr)
227 {
228    bool ok;
229    char ed1[30], ed2[30];
230
231    Dmsg0(200, "In create Device\n");
232    db_lock(mdb);
233    Mmsg(mdb->cmd, "SELECT DeviceId,Name FROM Device WHERE Name='%s'", dr->Name);
234    Dmsg1(200, "selectdevice: %s\n", mdb->cmd);
235
236    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
237       mdb->num_rows = sql_num_rows(mdb);
238       if (mdb->num_rows > 0) {
239          Mmsg1(&mdb->errmsg, _("Device record %s already exists\n"), dr->Name);
240          sql_free_result(mdb);
241          db_unlock(mdb);
242          return false;
243       }
244       sql_free_result(mdb);
245    }
246
247    /* Must create it */
248    Mmsg(mdb->cmd,
249 "INSERT INTO Device (Name,MediaTypeId,StorageId) VALUES ('%s',%s,%s)",
250                   dr->Name,
251                   edit_uint64(dr->MediaTypeId, ed1),
252                   edit_int64(dr->StorageId, ed2));
253    Dmsg1(200, "Create Device: %s\n", mdb->cmd);
254    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
255       Mmsg2(&mdb->errmsg, _("Create db Device record %s failed: ERR=%s\n"),
256             mdb->cmd, sql_strerror(mdb));
257       dr->DeviceId = 0;
258       ok = false;
259    } else {
260       dr->DeviceId = sql_insert_id(mdb, NT_("Device"));
261       ok = true;
262    }
263    db_unlock(mdb);
264    return ok;
265 }
266
267
268
269 /*
270  * Create a Unique record for Storage -- no duplicates
271  * Returns: false on failure
272  *          true  on success with id in sr->StorageId
273  */
274 bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
275 {
276    SQL_ROW row;
277    bool ok;
278
279    db_lock(mdb);
280    Mmsg(mdb->cmd, "SELECT StorageId,AutoChanger FROM Storage WHERE Name='%s'", sr->Name);
281
282    sr->StorageId = 0;
283    sr->created = false;
284    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
285       mdb->num_rows = sql_num_rows(mdb);
286       /* If more than one, report error, but return first row */
287       if (mdb->num_rows > 1) {
288          Mmsg1(&mdb->errmsg, _("More than one Storage record!: %d\n"), (int)(mdb->num_rows));
289          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
290       }
291       if (mdb->num_rows >= 1) {
292          if ((row = sql_fetch_row(mdb)) == NULL) {
293             Mmsg1(&mdb->errmsg, _("error fetching Storage row: %s\n"), sql_strerror(mdb));
294             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
295             sql_free_result(mdb);
296             db_unlock(mdb);
297             return false;
298          }
299          sr->StorageId = str_to_int64(row[0]);
300          sr->AutoChanger = atoi(row[1]);   /* bool */
301          sql_free_result(mdb);
302          db_unlock(mdb);
303          return true;
304       }
305       sql_free_result(mdb);
306    }
307
308    /* Must create it */
309    Mmsg(mdb->cmd, "INSERT INTO Storage (Name,AutoChanger)"
310         " VALUES ('%s',%d)", sr->Name, sr->AutoChanger);
311
312    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
313       Mmsg2(&mdb->errmsg, _("Create DB Storage record %s failed. ERR=%s\n"),
314             mdb->cmd, sql_strerror(mdb));
315       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
316       ok = false;
317    } else {
318       sr->StorageId = sql_insert_id(mdb, NT_("Storage"));
319       sr->created = true;
320       ok = true;
321    }
322    db_unlock(mdb);
323    return ok;
324 }
325
326
327 /*
328  * Create Unique MediaType record
329  * Returns: false on failure
330  *          true  on success
331  */
332 bool
333 db_create_mediatype_record(JCR *jcr, B_DB *mdb, MEDIATYPE_DBR *mr)
334 {
335    bool stat;        
336
337    Dmsg0(200, "In create mediatype\n");
338    db_lock(mdb);
339    Mmsg(mdb->cmd, "SELECT MediaTypeId,MediaType FROM MediaType WHERE MediaType='%s'", mr->MediaType);
340    Dmsg1(200, "selectmediatype: %s\n", mdb->cmd);
341
342    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
343       mdb->num_rows = sql_num_rows(mdb);
344       if (mdb->num_rows > 0) {
345          Mmsg1(&mdb->errmsg, _("mediatype record %s already exists\n"), mr->MediaType);
346          sql_free_result(mdb);
347          db_unlock(mdb);
348          return false;
349       }
350       sql_free_result(mdb);
351    }
352
353    /* Must create it */
354    Mmsg(mdb->cmd,
355 "INSERT INTO MediaType (MediaType,ReadOnly) "
356 "VALUES ('%s',%d)",
357                   mr->MediaType,
358                   mr->ReadOnly);
359    Dmsg1(200, "Create mediatype: %s\n", mdb->cmd);
360    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
361       Mmsg2(&mdb->errmsg, _("Create db mediatype record %s failed: ERR=%s\n"),
362             mdb->cmd, sql_strerror(mdb));
363       mr->MediaTypeId = 0;
364       stat = false;
365    } else {
366       mr->MediaTypeId = sql_insert_id(mdb, NT_("MediaType"));
367       stat = true;
368    }
369    db_unlock(mdb);
370    return stat;
371 }
372
373
374 /*
375  * Create Media record. VolumeName and non-zero Slot must be unique
376  *
377  * Returns: 0 on failure
378  *          1 on success
379  */
380 int
381 db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
382 {
383    int stat;
384    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
385    char ed9[50], ed10[50], ed11[50], ed12[50];
386    struct tm tm;
387
388    db_lock(mdb);
389    Mmsg(mdb->cmd, "SELECT MediaId FROM Media WHERE VolumeName='%s'",
390            mr->VolumeName);
391    Dmsg1(500, "selectpool: %s\n", mdb->cmd);
392
393    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
394       mdb->num_rows = sql_num_rows(mdb);
395       if (mdb->num_rows > 0) {
396          Mmsg1(&mdb->errmsg, _("Volume \"%s\" already exists.\n"), mr->VolumeName);
397          sql_free_result(mdb);
398          db_unlock(mdb);
399          return 0;
400       }
401       sql_free_result(mdb);
402    }
403
404    /* Must create it */
405    Mmsg(mdb->cmd,
406 "INSERT INTO Media (VolumeName,MediaType,MediaTypeId,PoolId,MaxVolBytes,"
407 "VolCapacityBytes,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
408 "VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,VolParts,"
409 "EndFile,EndBlock,LabelType,StorageId,DeviceId,LocationId,"
410 "ScratchPoolId,RecyclePoolId,Enabled)"
411 "VALUES ('%s','%s',0,%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,0,0,%d,%s,"
412 "%s,%s,%s,%s,%d)",
413           mr->VolumeName,
414           mr->MediaType, mr->PoolId,
415           edit_uint64(mr->MaxVolBytes,ed1),
416           edit_uint64(mr->VolCapacityBytes, ed2),
417           mr->Recycle,
418           edit_uint64(mr->VolRetention, ed3),
419           edit_uint64(mr->VolUseDuration, ed4),
420           mr->MaxVolJobs,
421           mr->MaxVolFiles,
422           mr->VolStatus,
423           mr->Slot,
424           edit_uint64(mr->VolBytes, ed5),
425           mr->InChanger,
426           edit_uint64(mr->VolReadTime, ed6),
427           edit_uint64(mr->VolWriteTime, ed7),
428           mr->VolParts,
429           mr->LabelType,
430           edit_int64(mr->StorageId, ed8), 
431           edit_int64(mr->DeviceId, ed9), 
432           edit_int64(mr->LocationId, ed10), 
433           edit_int64(mr->ScratchPoolId, ed11), 
434           edit_int64(mr->RecyclePoolId, ed12), 
435           mr->Enabled
436           );
437
438
439    Dmsg1(500, "Create Volume: %s\n", mdb->cmd);
440    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
441       Mmsg2(&mdb->errmsg, _("Create DB Media record %s failed. ERR=%s\n"),
442             mdb->cmd, sql_strerror(mdb));
443       stat = 0;
444    } else {
445       mr->MediaId = sql_insert_id(mdb, NT_("Media"));
446       stat = 1;
447       if (mr->set_label_date) {
448          char dt[MAX_TIME_LENGTH];
449          if (mr->LabelDate == 0) {
450             mr->LabelDate = time(NULL);
451          }
452          (void)localtime_r(&mr->LabelDate, &tm);
453          strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
454          Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
455               "WHERE MediaId=%d", dt, mr->MediaId);
456          stat = UPDATE_DB(jcr, mdb, mdb->cmd);
457       }
458    }
459
460    /*
461     * Make sure that if InChanger is non-zero any other identical slot
462     *   has InChanger zero.
463     */
464    db_make_inchanger_unique(jcr, mdb, mr);
465
466    db_unlock(mdb);
467    return stat;
468 }
469
470 /*
471  * Create a Unique record for the client -- no duplicates
472  * Returns: 0 on failure
473  *          1 on success with id in cr->ClientId
474  */
475 int db_create_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
476 {
477    SQL_ROW row;
478    int stat;
479    char ed1[50], ed2[50];
480
481    db_lock(mdb);
482    Mmsg(mdb->cmd, "SELECT ClientId,Uname FROM Client WHERE Name='%s'", cr->Name);
483
484    cr->ClientId = 0;
485    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
486       mdb->num_rows = sql_num_rows(mdb);
487       /* If more than one, report error, but return first row */
488       if (mdb->num_rows > 1) {
489          Mmsg1(&mdb->errmsg, _("More than one Client!: %d\n"), (int)(mdb->num_rows));
490          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
491       }
492       if (mdb->num_rows >= 1) {
493          if ((row = sql_fetch_row(mdb)) == NULL) {
494             Mmsg1(&mdb->errmsg, _("error fetching Client row: %s\n"), sql_strerror(mdb));
495             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
496             sql_free_result(mdb);
497             db_unlock(mdb);
498             return 0;
499          }
500          cr->ClientId = str_to_int64(row[0]);
501          if (row[1]) {
502             bstrncpy(cr->Uname, row[1], sizeof(cr->Uname));
503          } else {
504             cr->Uname[0] = 0;         /* no name */
505          }
506          sql_free_result(mdb);
507          db_unlock(mdb);
508          return 1;
509       }
510       sql_free_result(mdb);
511    }
512
513    /* Must create it */
514    Mmsg(mdb->cmd, "INSERT INTO Client (Name,Uname,AutoPrune,"
515 "FileRetention,JobRetention) VALUES "
516 "('%s','%s',%d,%s,%s)", cr->Name, cr->Uname, cr->AutoPrune,
517       edit_uint64(cr->FileRetention, ed1),
518       edit_uint64(cr->JobRetention, ed2));
519
520    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
521       Mmsg2(&mdb->errmsg, _("Create DB Client record %s failed. ERR=%s\n"),
522             mdb->cmd, sql_strerror(mdb));
523       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
524       cr->ClientId = 0;
525       stat = 0;
526    } else {
527       cr->ClientId = sql_insert_id(mdb, NT_("Client"));
528       stat = 1;
529    }
530    db_unlock(mdb);
531    return stat;
532 }
533
534
535
536
537
538 /*
539  * Create a Unique record for the counter -- no duplicates
540  * Returns: 0 on failure
541  *          1 on success with counter filled in
542  */
543 int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
544 {
545    COUNTER_DBR mcr;
546    int stat;
547
548    db_lock(mdb);
549    memset(&mcr, 0, sizeof(mcr));
550    bstrncpy(mcr.Counter, cr->Counter, sizeof(mcr.Counter));
551    if (db_get_counter_record(jcr, mdb, &mcr)) {
552       memcpy(cr, &mcr, sizeof(COUNTER_DBR));
553       db_unlock(mdb);
554       return 1;
555    }
556
557    /* Must create it */
558    Mmsg(mdb->cmd, "INSERT INTO Counters (Counter,MinValue,MaxValue,CurrentValue,"
559       "WrapCounter) VALUES ('%s','%d','%d','%d','%s')",
560       cr->Counter, cr->MinValue, cr->MaxValue, cr->CurrentValue,
561       cr->WrapCounter);
562
563    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
564       Mmsg2(&mdb->errmsg, _("Create DB Counters record %s failed. ERR=%s\n"),
565             mdb->cmd, sql_strerror(mdb));
566       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
567       stat = 0;
568    } else {
569       stat = 1;
570    }
571    db_unlock(mdb);
572    return stat;
573 }
574
575
576 /*
577  * Create a FileSet record. This record is unique in the
578  *  name and the MD5 signature of the include/exclude sets.
579  *  Returns: 0 on failure
580  *           1 on success with FileSetId in record
581  */
582 bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
583 {
584    SQL_ROW row;
585    bool stat;
586    struct tm tm;
587
588    db_lock(mdb);
589    fsr->created = false;
590    Mmsg(mdb->cmd, "SELECT FileSetId,CreateTime FROM FileSet WHERE "
591 "FileSet='%s' AND MD5='%s'", fsr->FileSet, fsr->MD5);
592
593    fsr->FileSetId = 0;
594    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
595       mdb->num_rows = sql_num_rows(mdb);
596       if (mdb->num_rows > 1) {
597          Mmsg1(&mdb->errmsg, _("More than one FileSet!: %d\n"), (int)(mdb->num_rows));
598          Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
599       }
600       if (mdb->num_rows >= 1) {
601          if ((row = sql_fetch_row(mdb)) == NULL) {
602             Mmsg1(&mdb->errmsg, _("error fetching FileSet row: ERR=%s\n"), sql_strerror(mdb));
603             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
604             sql_free_result(mdb);
605             db_unlock(mdb);
606             return false;
607          }
608          fsr->FileSetId = str_to_int64(row[0]);
609          if (row[1] == NULL) {
610             fsr->cCreateTime[0] = 0;
611          } else {
612             bstrncpy(fsr->cCreateTime, row[1], sizeof(fsr->cCreateTime));
613          }
614          sql_free_result(mdb);
615          db_unlock(mdb);
616          return true;
617       }
618       sql_free_result(mdb);
619    }
620
621    if (fsr->CreateTime == 0 && fsr->cCreateTime[0] == 0) {
622       fsr->CreateTime = time(NULL);
623    }
624    (void)localtime_r(&fsr->CreateTime, &tm);
625    strftime(fsr->cCreateTime, sizeof(fsr->cCreateTime), "%Y-%m-%d %H:%M:%S", &tm);
626
627    /* Must create it */
628       Mmsg(mdb->cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) "
629 "VALUES ('%s','%s','%s')", fsr->FileSet, fsr->MD5, fsr->cCreateTime);
630
631    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
632       Mmsg2(&mdb->errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"),
633             mdb->cmd, sql_strerror(mdb));
634       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
635       fsr->FileSetId = 0;
636       stat = false;
637    } else {
638       fsr->FileSetId = sql_insert_id(mdb, NT_("FileSet"));
639       fsr->created = true;
640       stat = true;
641    }
642
643    db_unlock(mdb);
644    return stat;
645 }
646
647
648 /*
649  *  struct stat
650  *  {
651  *      dev_t         st_dev;       * device *
652  *      ino_t         st_ino;       * inode *
653  *      mode_t        st_mode;      * protection *
654  *      nlink_t       st_nlink;     * number of hard links *
655  *      uid_t         st_uid;       * user ID of owner *
656  *      gid_t         st_gid;       * group ID of owner *
657  *      dev_t         st_rdev;      * device type (if inode device) *
658  *      off_t         st_size;      * total size, in bytes *
659  *      unsigned long st_blksize;   * blocksize for filesystem I/O *
660  *      unsigned long st_blocks;    * number of blocks allocated *
661  *      time_t        st_atime;     * time of last access *
662  *      time_t        st_mtime;     * time of last modification *
663  *      time_t        st_ctime;     * time of last inode change *
664  *  };
665  */
666
667
668
669 /*
670  * Create File record in B_DB
671  *
672  *  In order to reduce database size, we store the File attributes,
673  *  the FileName, and the Path separately.  In principle, there
674  *  is a single FileName record and a single Path record, no matter
675  *  how many times it occurs.  This is this subroutine, we separate
676  *  the file and the path and create three database records.
677  */
678 int db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
679 {
680
681    db_lock(mdb);
682    Dmsg1(dbglevel, "Fname=%s\n", ar->fname);
683    Dmsg0(dbglevel, "put_file_into_catalog\n");
684    /*
685     * Make sure we have an acceptable attributes record.
686     */
687    if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
688          ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
689       Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
690          ar->Stream);
691       Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
692       goto bail_out;
693    }
694
695
696    split_path_and_file(jcr, mdb, ar->fname);
697
698    if (!db_create_filename_record(jcr, mdb, ar)) {
699       goto bail_out;
700    }
701    Dmsg1(dbglevel, "db_create_filename_record: %s\n", mdb->esc_name);
702
703
704    if (!db_create_path_record(jcr, mdb, ar)) {
705       goto bail_out;
706    }
707    Dmsg1(dbglevel, "db_create_path_record: %s\n", mdb->esc_name);
708
709    /* Now create master File record */
710    if (!db_create_file_record(jcr, mdb, ar)) {
711       goto bail_out;
712    }
713    Dmsg0(dbglevel, "db_create_file_record OK\n");
714
715    Dmsg3(dbglevel, "CreateAttributes Path=%s File=%s FilenameId=%d\n", mdb->path, mdb->fname, ar->FilenameId);
716    db_unlock(mdb);
717    return 1;
718
719 bail_out:
720    db_unlock(mdb);
721    return 0;
722 }
723
724 /*
725  * This is the master File entry containing the attributes.
726  *  The filename and path records have already been created.
727  */
728 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
729 {
730    int stat;
731    static char *no_digest = "0";
732    char *digest;
733
734    ASSERT(ar->JobId);
735    ASSERT(ar->PathId);
736    ASSERT(ar->FilenameId);
737
738    if (ar->Digest == NULL || ar->Digest[0] == 0) {
739       digest = no_digest;
740    } else {
741       digest = ar->Digest;
742    }
743
744    /* Must create it */
745    Mmsg(mdb->cmd,
746         "INSERT INTO File (FileIndex,JobId,PathId,FilenameId,"
747         "LStat,MD5) VALUES (%u,%u,%u,%u,'%s','%s')",
748         ar->FileIndex, ar->JobId, ar->PathId, ar->FilenameId,
749         ar->attr, digest);
750
751    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
752       Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"),
753          mdb->cmd, sql_strerror(mdb));
754       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
755       ar->FileId = 0;
756       stat = 0;
757    } else {
758       ar->FileId = sql_insert_id(mdb, NT_("File"));
759       stat = 1;
760    }
761    return stat;
762 }
763
764 /* Create a Unique record for the Path -- no duplicates */
765 static int db_create_path_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
766 {
767    SQL_ROW row;
768    int stat;
769
770    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->pnl+2);
771    db_escape_string(mdb->esc_name, mdb->path, mdb->pnl);
772
773    if (mdb->cached_path_id != 0 && mdb->cached_path_len == mdb->pnl &&
774        strcmp(mdb->cached_path, mdb->path) == 0) {
775       ar->PathId = mdb->cached_path_id;
776       return 1;
777    }
778
779    Mmsg(mdb->cmd, "SELECT PathId FROM Path WHERE Path='%s'", mdb->esc_name);
780
781    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
782       mdb->num_rows = sql_num_rows(mdb);
783       if (mdb->num_rows > 1) {
784          char ed1[30];
785          Mmsg2(&mdb->errmsg, _("More than one Path!: %s for path: %s\n"),
786             edit_uint64(mdb->num_rows, ed1), mdb->path);
787          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
788       }
789       /* Even if there are multiple paths, take the first one */
790       if (mdb->num_rows >= 1) {
791          if ((row = sql_fetch_row(mdb)) == NULL) {
792             Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
793             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
794             sql_free_result(mdb);
795             ar->PathId = 0;
796             ASSERT(ar->PathId);
797             return 0;
798          }
799          ar->PathId = str_to_int64(row[0]);
800          sql_free_result(mdb);
801          /* Cache path */
802          if (ar->PathId != mdb->cached_path_id) {
803             mdb->cached_path_id = ar->PathId;
804             mdb->cached_path_len = mdb->pnl;
805             pm_strcpy(mdb->cached_path, mdb->path);
806          }
807          ASSERT(ar->PathId);
808          return 1;
809       }
810       sql_free_result(mdb);
811    }
812
813    Mmsg(mdb->cmd, "INSERT INTO Path (Path) VALUES ('%s')", mdb->esc_name);
814
815    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
816       Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"),
817          mdb->cmd, sql_strerror(mdb));
818       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
819       ar->PathId = 0;
820       stat = 0;
821    } else {
822       ar->PathId = sql_insert_id(mdb, NT_("Path"));
823       stat = 1;
824    }
825
826    /* Cache path */
827    if (stat && ar->PathId != mdb->cached_path_id) {
828       mdb->cached_path_id = ar->PathId;
829       mdb->cached_path_len = mdb->pnl;
830       pm_strcpy(mdb->cached_path, mdb->path);
831    }
832    return stat;
833 }
834
835 /* Create a Unique record for the filename -- no duplicates */
836 static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
837 {
838    SQL_ROW row;
839
840    mdb->esc_name = check_pool_memory_size(mdb->esc_name, 2*mdb->fnl+2);
841    db_escape_string(mdb->esc_name, mdb->fname, mdb->fnl);
842
843    Mmsg(mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name='%s'", mdb->esc_name);
844
845    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
846       mdb->num_rows = sql_num_rows(mdb);
847       if (mdb->num_rows > 1) {
848          char ed1[30];
849          Mmsg2(&mdb->errmsg, _("More than one Filename! %s for file: %s\n"),
850             edit_uint64(mdb->num_rows, ed1), mdb->fname);
851          Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
852       }
853       if (mdb->num_rows >= 1) {
854          if ((row = sql_fetch_row(mdb)) == NULL) {
855             Mmsg2(&mdb->errmsg, _("Error fetching row for file=%s: ERR=%s\n"),
856                 mdb->fname, sql_strerror(mdb));
857             Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
858             ar->FilenameId = 0;
859          } else {
860             ar->FilenameId = str_to_int64(row[0]);
861          }
862          sql_free_result(mdb);
863          return ar->FilenameId > 0;
864       }
865       sql_free_result(mdb);
866    }
867
868    Mmsg(mdb->cmd, "INSERT INTO Filename (Name) VALUES ('%s')", mdb->esc_name);
869
870    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
871       Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"),
872             mdb->cmd, sql_strerror(mdb));
873       Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
874       ar->FilenameId = 0;
875    } else {
876       ar->FilenameId = sql_insert_id(mdb, NT_("Filename"));
877    }
878    return ar->FilenameId > 0;
879 }
880
881 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL */