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