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