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