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