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