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