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