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