]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
pluginlib: Metaplugin - add symbolic link support for external STAT command.
authorRadosław Korzeniewski <radoslaw@korzeniewski.net>
Thu, 4 Nov 2021 13:59:52 +0000 (14:59 +0100)
committerEric Bollengier <eric@baculasystems.com>
Thu, 14 Sep 2023 11:56:56 +0000 (13:56 +0200)
bacula/src/plugins/fd/pluginlib/metaplugin.cpp
bacula/src/plugins/fd/pluginlib/metaplugin_accurate.cpp
bacula/src/plugins/fd/pluginlib/metaplugin_accurate.h
bacula/src/plugins/fd/pluginlib/metaplugin_attributes.cpp
bacula/src/plugins/fd/pluginlib/metaplugin_attributes.h
bacula/src/plugins/fd/pluginlib/test_metaplugin_backend.c

index 12253ccdb7c2ed0000eb07a4b7f63488981a1874..46ebad105963495b1c742c1c436603bd3286f868 100644 (file)
@@ -897,13 +897,6 @@ bRC METAPLUGIN::send_startjob(bpContext *ctx, const char *command)
       return bRC_Error;
    }
 
-   // if (!backend.ctx->read_ack(ctx)){
-   //    strip_trailing_newline(cmd.c_str());
-   //    DMSG(ctx, DERROR, "Wrong backend response to %s command.\n", cmd.c_str());
-   //    JMSG(ctx, backend.ctx->jmsg_err_level(), "Wrong backend response to %s command.\n", cmd.c_str());
-   //    return bRC_Error;
-   // }
-
    int32_t status;
    while ((status = backend.ctx->read_command(ctx, cmd)) != 0)
    {
@@ -1765,13 +1758,13 @@ bRC METAPLUGIN::perform_read_metacommands(bpContext *ctx)
          if (scan_parameter_str(cmd, "CHECK:", fname))
          {
             /* got accurate check query */
-            metaplugin::accurate::perform_accurate_check(ctx, backend.ctx, fname, accurate_mode, accurate_mode_err);
+            metaplugin::accurate::perform_accurate_check(ctx, backend.ctx, fname, lname, accurate_mode, accurate_mode_err);
             continue;
          }
          if (scan_parameter_str(cmd, "CHECKGET:", fname))
          {
             /* got accurate get query */
-            metaplugin::accurate::perform_accurate_check_get(ctx, backend.ctx, fname, accurate_mode, accurate_mode_err);
+            metaplugin::accurate::perform_accurate_check_get(ctx, backend.ctx, fname, lname, accurate_mode, accurate_mode_err);
             continue;
          }
          if (scan_parameter_str(cmd, "ACCEPT:", fname))
@@ -1929,7 +1922,7 @@ bRC METAPLUGIN::perform_accept_file(bpContext *ctx)
    struct save_pkt sp;
    memset(&sp, 0, sizeof(sp));
 
-   metaplugin::attributes::Status status = metaplugin::attributes::read_attributes_command(ctx, backend.ctx, cmd, &sp);
+   metaplugin::attributes::Status status = metaplugin::attributes::read_attributes_command(ctx, backend.ctx, cmd, &sp, lname);
    switch(status)
    {
    case metaplugin::attributes::Invalid_File_Type:
@@ -2329,9 +2322,13 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp)
       while (backend.ctx->read_command(ctx, cmd) > 0)
       {
          DMSG(ctx, DINFO, "read_command(2): %s\n", cmd.c_str());
-         metaplugin::attributes::Status status = metaplugin::attributes::read_scan_stat_command(ctx, cmd, sp);
+
+         metaplugin::attributes::Status status = metaplugin::attributes::read_scan_stat_command(ctx, cmd, sp, lname);
          switch (status)
          {
+         case metaplugin::attributes::Status_Error:
+            return bRC_Error;
+
          case metaplugin::attributes::Invalid_File_Type:
             JMSG2(ctx, M_ERROR, "Invalid file type: %c for %s\n", sp->type, fname.c_str());
             return bRC_Error;
@@ -2345,12 +2342,15 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp)
                reqparams--;
             }
             continue;
+
          case metaplugin::attributes::Status_Handled:
             reqparams--;
             continue;
+
          default:
             break;
          }
+
          status = metaplugin::attributes::read_scan_tstamp_command(ctx, cmd, sp);
          switch (status)
          {
@@ -2359,12 +2359,15 @@ bRC METAPLUGIN::startBackupFile(bpContext *ctx, struct save_pkt *sp)
          default:
             break;
          }
-         if (scan_parameter_str(cmd, "LSTAT:", lname) == 1) {
+
+         if (scan_parameter_str(cmd, "LSTAT:", lname) == 1)
+         {
             sp->link = lname.c_str();
             reqparams--;
             DMSG(ctx, DINFO, "LSTAT:%s\n", lname.c_str());
             continue;
          }
+
          POOL_MEM tmp(PM_FNAME);
          if (scan_parameter_str(cmd, "PIPE:", tmp)) {
             /* handle PIPE command */
index 2b7e008df1ef89616614fcbe1cdd83d79a273b20..bf44aa7053ce5f76541c83eeb040701805a249af 100644 (file)
@@ -53,7 +53,7 @@ namespace accurate
     * @param accurate_mode_err when accurate mode error handled
     * @return bRC bRC_OK when success, bRC_Error if not
     */
-   bRC perform_accurate_check(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, bool accurate_mode, bool &accurate_mode_err)
+   bRC perform_accurate_check(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, POOL_MEM &lname, bool accurate_mode, bool &accurate_mode_err)
    {
       if (strlen(fname.c_str()) == 0){
          // input variable is not valid
@@ -72,7 +72,7 @@ namespace accurate
          return bRC_Error;
       }
 
-      metaplugin::attributes::Status status = metaplugin::attributes::read_scan_stat_command(ctx, cmd, &sp);
+      metaplugin::attributes::Status status = metaplugin::attributes::read_scan_stat_command(ctx, cmd, &sp, lname);
       if (status == metaplugin::attributes::Status_OK) {
          if (ptcomm->read_command(ctx, cmd) < 0) {
             // error
@@ -137,7 +137,7 @@ namespace accurate
     * @param accurate_mode_err when accurate mode error handled
     * @return bRC bRC_OK when success, bRC_Error if not
     */
-   bRC perform_accurate_check_get(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, bool accurate_mode, bool &accurate_mode_err)
+   bRC perform_accurate_check_get(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, POOL_MEM &lname, bool accurate_mode, bool &accurate_mode_err)
    {
       POOL_MEM cmd(PM_FNAME);
 
index 6399db0c49fd1fee3f2619a8ea2006a6ab00024e..81187698cf33049201d90a64013207b43cacef20 100644 (file)
@@ -37,8 +37,8 @@ namespace metaplugin
 {
 namespace accurate
 {
-   bRC perform_accurate_check(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, bool accurate_mode, bool &accurate_mode_err);
-   bRC perform_accurate_check_get(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, bool accurate_mode, bool &accurate_mode_err);
+   bRC perform_accurate_check(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, POOL_MEM &lname, bool accurate_mode, bool &accurate_mode_err);
+   bRC perform_accurate_check_get(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &fname, POOL_MEM &lname, bool accurate_mode, bool &accurate_mode_err);
 
 }  // namespace accurate
 }  // namespace metaplugin
index a5e4579cbd572f642e1167e7bd7c49a3fb7f56da..d19c495444da73418d078df5ff57f5c76d8f2964 100644 (file)
@@ -51,7 +51,7 @@ namespace attributes
     *                Status_Handled when data managed and TSTAMP command is not required
     *                Not_Command when it was not this command
     */
-   Status read_scan_stat_command(bpContext *ctx, POOL_MEM &cmd, struct save_pkt *sp)
+   Status read_scan_stat_command(bpContext *ctx, POOL_MEM &cmd, struct save_pkt *sp, POOL_MEM &lname)
    {
       char type;
       size_t size;
@@ -67,7 +67,7 @@ namespace attributes
          // handle stat(2) for this file
          scan_parameter_str(cmd, "STAT:", param);
          DMSG1(ctx, DDEBUG, "read_scan_stat_command():stat:%s\n", param.c_str());
-         int rc = stat(param.c_str(), &sp->statp);
+         int rc = lstat(param.c_str(), &sp->statp);
          if (rc < 0)
          {
             // error
@@ -85,6 +85,23 @@ namespace attributes
          case S_IFREG:
             sp->type = FT_REG;
             break;
+         case S_IFLNK:
+            {
+               sp->type = FT_LNK;
+               ssize_t rc = readlink(param.c_str(), lname.c_str(), lname.size());
+               if (rc < 0)
+               {
+                  berrno be;
+                  // error reading link value
+                  DMSG2(ctx, DERROR, "Error reading link value. Err=%s (%d)", be.bstrerror(), be.code());
+                  JMSG3(ctx, M_ERROR, "Error reading link value: %s, Err=%s (%d)", param.c_str(), be.bstrerror(), be.code());
+                  return Status_Error;
+               }
+               lname.c_str()[rc] = '\0';
+               sp->link = lname.c_str();
+               DMSG1(ctx, DDEBUG, "read_scan_stat_command():readlink:%s\n", sp->link);
+            }
+            break;
          default:
             DMSG1(ctx, DERROR, "Unsupported file type: %o\n", sp->statp.st_mode & S_IFMT);
             return Invalid_Stat_Packet;
@@ -246,7 +263,7 @@ namespace attributes
     * @param sp save packet to fill when file attributes handled
     * @return Status Status_OK when file attributes commands handled, Status_Error on any error, other depends on enum.
     */
-   Status read_attributes_command(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &cmd, struct save_pkt *sp)
+   Status read_attributes_command(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &cmd, struct save_pkt *sp, POOL_MEM &lname)
    {
       DMSG0(ctx, DDEBUG, "read_attributes_command()\n");
 
@@ -256,7 +273,7 @@ namespace attributes
          return Status_Error;
       }
 
-      Status status = read_scan_stat_command(ctx, cmd, sp);
+      Status status = read_scan_stat_command(ctx, cmd, sp, lname);
       switch(status)
       {
       case Status_OK:
index a2fc77038b559410378444061b8d58b552aefddb..93de0a1d5fbf69ac8fef737a920d62ac9c856912 100644 (file)
@@ -47,11 +47,11 @@ namespace attributes
       Status_Error,
    } Status;
 
-   Status read_scan_stat_command(bpContext *ctx, POOL_MEM &cmd, struct save_pkt *sp);
+   Status read_scan_stat_command(bpContext *ctx, POOL_MEM &cmd, struct save_pkt *sp, POOL_MEM &lname);
    Status make_stat_command(bpContext *ctx, POOL_MEM &cmd, const restore_pkt *rp);
    Status read_scan_tstamp_command(bpContext *ctx, POOL_MEM &cmd, struct save_pkt *sp);
    Status make_tstamp_command(bpContext *ctx, POOL_MEM &cmd, const restore_pkt *rp);
-   Status read_attributes_command(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &cmd, struct save_pkt *sp);
+   Status read_attributes_command(bpContext *ctx, PTCOMM *ptcomm, POOL_MEM &cmd, struct save_pkt *sp, POOL_MEM &lname);
 }  // attributes
 }  // metaplugin
 
index 31ebf58d165fe61365df2ff1ec45fbe728693fce..a888e150c603dbdfdd24adbea8494aef571d842d 100644 (file)
@@ -54,8 +54,9 @@ extern const char *PLUGINNAME;
 
 int logfd;
 pid_t mypid;
-char * buf;
-char * buflog;
+char *buf;
+char *buflog;
+char symlink_fname[32];
 
 bool regress_error_plugin_params = false;
 bool regress_error_start_job = false;
@@ -1183,6 +1184,27 @@ void perform_backup()
    signal_eod();
    write_plugin('I', "TEST18Data");
 
+   // now test `STAT:/path/to/file` using symbolic link
+   snprintf(symlink_fname, 32, "/tmp/passwd.%d", mypid);
+   symlink("/etc/passwd", symlink_fname);
+
+   // the file with external stat(2) packet
+   snprintf(buf, BIGBUFLEN, "FNAME:%s/java/%d/stat.symlink\n", PLUGINPREFIX, mypid);
+   write_plugin('C', buf);
+   snprintf(buf, BIGBUFLEN, "STAT:%s\n", symlink_fname);
+   write_plugin('C', buf);
+   write_plugin('I', "TEST18S");
+   signal_eod();
+   // here comes a file data contents
+   write_plugin('C', "DATA\n");
+   write_plugin('D', "/* here comes a file data contents */");
+   write_plugin('D', "/* here comes another file line    */");
+   write_plugin('D', "/* here comes another file line    */");
+   write_plugin('D', "/* here comes another file line    */");
+   write_plugin('D', "/* here comes another file line    */");
+   signal_eod();
+   write_plugin('I', "TEST18S_Data");
+
    // this plugin object should be the latest item to backup
    if (regress_backup_plugin_objects)
    {
@@ -1771,6 +1793,8 @@ int main(int argc, char** argv) {
 
 Term:
    signal_term();
+   // LOG("#> Unlink symlink_fname.");
+   // unlink(symlink_fname);
    LOG("#> Terminating backend.");
    close(logfd);
    free(buf);