Logo Search packages:      
Sourcecode: lfc-postgres version File versions  Download package

dpm_proclreq.c

/*
 * Copyright (C) 2004-2008 by CERN/IT/GD/CT
 * All rights reserved
 */

#ifndef lint
static char sccsid[] = "@(#)$RCSfile: dpm_proclreq.c,v $ $Revision: 1.44 $ $Date: 2008/10/30 06:04:01 $ CERN IT-GD/CT Jean-Philippe Baud";
#endif /* not lint */

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include "Cglobals.h"
#include "Cgrp.h"
#include "Cpool_api.h"
#include "Cthread_api.h"
#include "dpm.h"
#include "dpm_backend.h"
#ifdef DICOM
#include "dpm_dicom.h"
#endif
#include "dpm_server.h"
#include "dpm_util.h"
#include "dpns_api.h"
#include "rfio_api.h"
#include "serrno.h"

static struct dpm_srv_thread_info dpm_srv_thread_info[DPM_NBSTHREADS];
static int excl_mutex;
extern int being_shutdown;
extern char db_name[33];
extern char db_pwd[33];
extern char db_srvr[33];
extern char db_user[33];
extern gid_t dpm_gid;
extern uid_t dpm_uid;
extern int reqctr;
extern void *reqctr_lock;
extern gid_t *Cdecode_groups (char *, int *);
extern int Cgroupmatch (gid_t, int, gid_t *);
extern int dpm_rm_onereplica (struct Cns_fileid *, char *, u_signed64, int *, struct dpm_dbfd *dbfd, char *, int, u_signed64);

void *
msthread(arg)
void *arg;
{
      char func[16];
      int i;
      int ipool;
      int nb_active_threads;
      void *pooladdr;
      void *proclreq(void *);
      int thread_index;

      strcpy (func, "msthread");

      /* Create a pool of threads for slow operations */

      if ((ipool = Cpool_create_ext (DPM_NBSTHREADS, NULL, &pooladdr)) < 0) {
            dpmlogit (func, DP002, "Cpool_create", sstrerror(serrno));
            return (NULL);
      }
      for (i = 0; i < DPM_NBSTHREADS; i++) {
            dpm_srv_thread_info[i].s = -1;
            dpm_srv_thread_info[i].dbfd.idx = DPM_NBFTHREADS + i;
      }

      while (1) {
            if (being_shutdown)
                  break;

            /* Get index of a free thread */

            dpmlogit (func, "calling Cpool_next_index_timeout_ext\n");
            if ((thread_index =
                Cpool_next_index_timeout_ext (ipool, pooladdr, 10)) < 0) {
                  if (serrno != SETIMEDOUT)
                        dpmlogit (func, DP002, "Cpool_next_index",
                              sstrerror(serrno));
                  continue;
            }
            dpmlogit (func, "thread %d selected\n", thread_index);

            /* Wait for a request */

            dpmlogit (func, "calling Cthread_mutex_lock_ext\n");
            if (Cthread_mutex_lock_ext (reqctr_lock) < 0) {
                  dpmlogit (func, DP002, "Cthread_mutex_lock", sstrerror(serrno));
                  continue;
            }
            dpmlogit (func, "reqctr = %d\n", reqctr);
            while (reqctr == 0 && ! being_shutdown) {
                  if (Cthread_cond_timedwait_ext (reqctr_lock, 10) < 0) {
                        if (serrno != SETIMEDOUT)
                              dpmlogit (func, DP002, "Cthread_cond_timedwait",
                                    sstrerror(serrno));
                        continue;
                  }
            }
            if (being_shutdown) {
                  (void) Cthread_mutex_unlock_ext (reqctr_lock);
                  break;
            }
            dpm_srv_thread_info[thread_index].s = 0;
            dpmlogit (func, "calling Cpool_assign_ext\n");
            if (Cpool_assign_ext (ipool, pooladdr, &proclreq,
                &dpm_srv_thread_info[thread_index], 1) < 0) {
                  dpm_srv_thread_info[thread_index].s = -1;
                  dpmlogit (func, DP002, "Cpool_assign", sstrerror(serrno));
                  (void) Cthread_mutex_unlock_ext (reqctr_lock);
                  continue;
            }
            dpmlogit (func, "decrementing reqctr\n");
            reqctr--;
            (void) Cthread_mutex_unlock_ext (reqctr_lock);
      }

      /* Wait for the active threads to complete work */

      while (1) {
            nb_active_threads = 0;
            for (i = 0; i < DPM_NBSTHREADS; i++) {
                  if (dpm_srv_thread_info[i].s >= 0) {
                        nb_active_threads++;
                        continue;
                  }
                  if (dpm_srv_thread_info[i].db_open_done)
                        (void) dpm_closedb (&dpm_srv_thread_info[i].dbfd);
            }
            if (nb_active_threads == 0)
                  return (NULL);
      }
}

void *
proclreq(arg)
void *arg;
{
      int alloced_gids = 0;
      time_t curtime;
      struct dpm_req dpm_req;
      char **fqan = NULL;
      gid_t *gids = NULL;
      int i;
      int nbgids;
      char *p;
      dpm_dbrec_addr rec_addr;
      struct dpm_srv_thread_info *thip = (struct dpm_srv_thread_info *) arg;
      char *voname = NULL;

      /* connect to the database if not done yet */

      if (! thip->db_open_done) {
            Cns_seterrbuf (thip->errbuf, sizeof(thip->errbuf));
            if (dpm_opendb (db_srvr, db_user, db_pwd, db_name, &thip->dbfd) < 0)
                  return;
            thip->db_open_done = 1;
            thip->last_db_use = time (0);
      } else {
            if ((curtime = time (0)) > thip->last_db_use + DPM_DBPINGI)
                  (void) dpm_pingdb (&thip->dbfd);
            thip->last_db_use = curtime;
      }

      /* Get next request and mark it "active" */

      (void) dpm_start_tr (thip->s, &thip->dbfd);
      if (dpm_get_next_req (&thip->dbfd, DPM_QUEUED, &dpm_req, 1, &rec_addr) < 0) {
            dpm_abort_tr (&thip->dbfd);
            if (serrno != ENOENT)
                  inc_reqctr ();    /* the request is still in the queue */
            thip->s = -1;
            return (NULL);
      }
      if (dpm_req.stime == 0)
            dpm_req.stime = time (0);
      dpm_req.status = DPM_ACTIVE;
      if (dpm_update_pending_entry (&thip->dbfd, &rec_addr, &dpm_req) < 0) {
            dpm_abort_tr (&thip->dbfd);
            inc_reqctr ();    /* the request is still in the queue */
            thip->s = -1;
            return (NULL);
      }
      dpm_end_tr (&thip->dbfd);
      nbgids = 1;
      gids = &dpm_req.r_gid;
#ifdef CSEC
      if (dpm_req.r_uid) {
            Cns_client_setAuthorizationId (dpm_req.r_uid, dpm_req.r_gid,
                "GSI", dpm_req.client_dn);
#ifdef VIRTUAL_ID
#ifdef USE_VOMS
            if ((gids = Cdecode_groups (dpm_req.groups, &nbgids)) == NULL)
                  goto free_voms_info;
            alloced_gids = 1;
            if ((fqan = calloc (nbgids, sizeof(char *))) == NULL)
                  goto free_voms_info;
            if (Cns_getgrpbygids (nbgids, gids, fqan) < 0)
                  goto free_voms_info;
            if ((voname = strdup (fqan[0])) == NULL)
                  goto free_voms_info;
            if ((p = strchr (voname, '/')))
                  *p = '\0';

            /* pass the VOMS auth data to the nameserver */
            Cns_client_setVOMS_data (voname, fqan, nbgids);
#endif
#endif
      } else
            Cns_client_resetAuthorizationId ();
#endif

      switch (dpm_req.r_type) {
      case 'B':
            dpm_srv_proc_bringonline (&dpm_req, thip, nbgids, gids);
            break;
      case 'G':
            dpm_srv_proc_get (&dpm_req, thip, nbgids, gids);
            break;
      case 'P':
            dpm_srv_proc_put (&dpm_req, thip, nbgids, gids);
            break;
      }
free_voms_info:
      free (voname);
      if (fqan) {
            for (i = 0; i < nbgids; i++)
                  free (fqan[i]);
            free (fqan);
      }
      if (alloced_gids)
            free (gids);
      thip->s = -1;
      return (NULL);
}

dpm_build_recall_request(struct dpm_dbfd *dbfd, struct dpm_req *dpm_req, struct dpm_get_filereq *gfr_entry, void *nearline_info, int backend_type, struct dpm_backend_req *backend_req)
{
      if (backend_req->nbreqfiles == 0) {
            backend_req->r_ordinal = dpm_req->r_ordinal;
            strcpy (backend_req->r_token, dpm_req->r_token);
            backend_req->r_uid = dpm_req->r_uid;
            backend_req->r_gid = dpm_req->r_gid;
            strcpy (backend_req->client_dn, dpm_req->client_dn);
            strcpy (backend_req->groups, dpm_req->groups);
            strcpy (backend_req->clienthost, dpm_req->clienthost);
            backend_req->retrytime = dpm_req->retrytime;
            backend_req->lifetime = gfr_entry->lifetime;
            strcpy (backend_req->s_token, gfr_entry->s_token);
            backend_req->ret_policy = gfr_entry->ret_policy;
            backend_req->f_type = gfr_entry->f_type;
            backend_req->ctime = time (0);
            backend_req->status = DPM_QUEUED;
      }
      backend_req->nbreqfiles++;

#ifdef DICOM
      if (backend_type == DPM_DICOM_RECALL) {
            struct dpm_dicom_filereq dfr_entry;

            memset (&dfr_entry, 0, sizeof(dfr_entry));
            strcpy (dfr_entry.r_token, gfr_entry->r_token);
            dfr_entry.f_ordinal = backend_req->nbreqfiles - 1;
            strcpy (dfr_entry.surl, gfr_entry->from_surl);
            strcpy (dfr_entry.dicom_fn, nearline_info + 8);
            dfr_entry.status = DPM_QUEUED;
            if (dpm_insert_dfr_entry (dbfd, &dfr_entry) < 0)
                  return (-1);
      } else
#endif
      {
            serrno = SEPROTONOTSUP;
            return (-1);
      }
      return (0);
}

dpm_write_recall_request(struct dpm_dbfd *dbfd, int backend_type, struct dpm_backend_req *backend_req)
{
#ifdef DICOM
      if (backend_type == DPM_DICOM_RECALL) {
            if (dpm_insert_dicomreq_entry (dbfd, backend_req) < 0)
                  return (-1);
            dpm_end_tr (dbfd);
            dicomcopy_inc_reqctr ();
      } else
#endif
      {
            serrno = SEPROTONOTSUP;
            return (-1);
      }
      return (0);
}

dpm_check_replica_online(char *sfn, char *s_token, char *server, char *pfn)
{
      int i;
      int j = 0;
      int nbreplicas = 0;
      struct Cns_filereplica *rep_entries = NULL;
      int status;

      if (Cns_getreplica (sfn, NULL, NULL, &nbreplicas, &rep_entries) < 0)
            return (-1);
      if (nbreplicas == 0) {
            serrno = ENOENT;
            return (-1);
      }
      for (i = 0; i < nbreplicas; i++) {
            if ((rep_entries + i)->status == '-' &&
                dpm_get_fs_status ((rep_entries + i)->host, (rep_entries + i)->fs, &status) == 0 &&
                !(status & FS_DISABLED)) j++;
      }
      if (j == 0) {     /* no valid online replica, check for nearline replica */
            for (i = 0; i < nbreplicas; i++)
                  if ((rep_entries + i)->status == 'N') break;
            if (i < nbreplicas) {
                  strcpy (pfn, (rep_entries + i)->sfn);
                  strcpy (server, (rep_entries + i)->host);
                  free (rep_entries);
                  if (strncmp (pfn, "dicom://", 8) == 0)
                        return (DPM_DICOM_RECALL);
                  serrno = SEINTERNAL;
                  return (-1);
            }
      }
      free (rep_entries);
      if (j == 0) {     /* no valid replica */
            serrno = ENOENT;
            return (-1);
      }
      return (0);
}

dpm_getbestreplica(char *sfn, char *clienthost, char *server, char *pfn)
{
      static int dpm_rand_key = -1;
      unsigned int *dpm_rand_val;
      int i;
      int j = 0;
      int k = 0;
      int nbreplicas = 0;
      char *p1, *p2;
      struct Cns_filereplica *rep_entries = NULL;
      int status;
      int *valid_entries;
      int *valid_entries1;

      if (Cns_getreplica (sfn, NULL, NULL, &nbreplicas, &rep_entries) < 0)
            return (-1);
      if (nbreplicas == 0) {
            serrno = ENOENT;
            return (-1);
      }
      if ((valid_entries = calloc (nbreplicas, sizeof(int))) == NULL) {
            free (rep_entries);
            serrno = ENOMEM;
            return (-1);
      }
      for (i = 0; i < nbreplicas; i++) {
            if ((rep_entries + i)->status == '-' &&
                dpm_get_fs_status ((rep_entries + i)->host, (rep_entries + i)->fs, &status) == 0 &&
                !(status & FS_DISABLED)) valid_entries[j++] = i;
      }
      if (j == 0) {     /* no valid online replica, check for nearline replica */
            for (i = 0; i < nbreplicas; i++)
                  if ((rep_entries + i)->status == 'N') break;
            if (i < nbreplicas) {
                  strcpy (pfn, (rep_entries + i)->sfn);
                  strcpy (server, (rep_entries + i)->host);
                  free (rep_entries);
                  free (valid_entries);
                  if (strncmp (pfn, "dicom://", 8) == 0)
                        return (DPM_DICOM_RECALL);
                  serrno = SEINTERNAL;
                  return (-1);
            }
      }
      if (j == 0) {     /* no valid replica */
            free (rep_entries);
            free (valid_entries);
            serrno = ENOENT;
            return (-1);
      }
      if (j == 1) {
            strcpy (pfn, (rep_entries + valid_entries[0])->sfn);
            strcpy (server, (rep_entries + valid_entries[0])->host);
            free (rep_entries);
            free (valid_entries);
            return (0);
      }

      /* Look for replicas on same domain as client */

      if ((valid_entries1 = calloc (j, sizeof(int))) == NULL) {
            free (rep_entries);
            free (valid_entries);
            serrno = ENOMEM;
            return (-1);
      }
      p1 = strchr (clienthost, '.') + 1;
      for (i = 0; i < j; i++) {
            p2 = strchr ((rep_entries + valid_entries[i])->host, '.') + 1;
            if (strcmp (p1, p2) == 0)
                  valid_entries1[k++] = valid_entries[i];
      }
      if (k) {
            free (valid_entries);
            valid_entries = valid_entries1;
            j = k;
      } else
            free (valid_entries1);

      /* Take random replica */

      Cglobals_get (&dpm_rand_key, (void **) &dpm_rand_val, sizeof(int));
      if (dpm_rand_val == NULL) {
            free (rep_entries);
            free (valid_entries);
            serrno = ENOMEM;
            return (-1);
      }
      j = ((float) j * rand_r (dpm_rand_val)) / (RAND_MAX + 1.0);
      strcpy (pfn, (rep_entries + valid_entries[j])->sfn);
      strcpy (server, (rep_entries + valid_entries[j])->host);
      free (rep_entries);
      free (valid_entries);
      return (0);
}

dpm_makedirp (char *sfn, uid_t uid, gid_t gid)
{
      int c;
      char *lastslash = NULL;
      char *p;
      char *q;

      p = strrchr (sfn, '/');
      while (p) {
            if (lastslash == NULL) lastslash = p;
            if (*(p - 1) == ':') break;
            *p = '\0';
            c = Cns_access (sfn, F_OK);
            if (c == 0) {
                  *p = '/';
                  break;
            }
            if (serrno != ENOENT) {
                  *p = '/';
                  return (c);
            }
            q = strrchr (sfn, '/');
            *p = '/';
            p = q;
      }
      while (c == 0 && p < lastslash && (p = strchr (p + 1, '/'))) {
            *p = '\0';
            c = Cns_mkdir (sfn, 0775);
            if (c && serrno == EEXIST) c = 0;
            if (c == 0)
                  c = Cns_chown (sfn, uid, gid);
            *p = '/';
      }
      return (c);
}

dpm_srv_proc_bringonline(dpm_req, thip, nbgids, gids)
struct dpm_req *dpm_req;
struct dpm_srv_thread_info *thip;
int nbgids;
gid_t *gids;
{
      struct dpm_backend_req backend_req;
      int c;
      char errbuf[256];
      struct Cns_fileid file_uniqueid;
      char func[25];
      struct dpm_get_filereq gfr_entry;
      int i;
      int nb_file_err = 0;
      int nb_files_to_recall = 0;
      struct dpm_get_filereq old_gfr_entry;
      char pfn[CA_MAXSFNLEN+1];
      dpm_dbrec_addr rec_addr;
      dpm_dbrec_addr rec_addrf;
      char server[CA_MAXHOSTNAMELEN+1];
      char *sfn;
      struct Cns_filestat st;

      strcpy (func, "dpm_srv_proc_bringonline");
      dpmlogit (func, "processing request %s from %s\n", dpm_req->r_token,
          dpm_req->client_dn);
      for (i = 0; i < dpm_req->nbreqfiles; i++) {

            /* Get File Request */

            (void) dpm_start_tr (thip->s, &thip->dbfd);
            if (dpm_get_gfr_by_fullid (&thip->dbfd, dpm_req->r_token, i,
                &gfr_entry, 1, &rec_addrf) < 0) {
                  dpm_abort_tr (&thip->dbfd);
                  continue;
            }
            if (gfr_entry.status != DPM_QUEUED) {     /* No need to process */
                  dpm_abort_tr (&thip->dbfd);
                  continue;
            }

            /* Mark the file request as active */

            gfr_entry.status = DPM_ACTIVE;
            (void) dpm_update_gfr_entry (&thip->dbfd, &rec_addrf, &gfr_entry);
            (void) dpm_end_tr (&thip->dbfd);

            if (strncmp (gfr_entry.from_surl, "srm://", 6) == 0) {
                  if ((sfn = sfnfromsurl (gfr_entry.from_surl)) == NULL) {
                        gfr_entry.status = DPM_FAILED | EINVAL;
                        strcpy (gfr_entry.errstring, "Bad SURL syntax");
                        goto upd_bof;
                  }
            } else
                  sfn = gfr_entry.from_surl;

            /* Check if the file exists */

            memset ((void *) &file_uniqueid, 0, sizeof(struct Cns_fileid));
            if (Cns_statx (sfn, &file_uniqueid, &st) < 0) {
                  gfr_entry.status = DPM_FAILED | serrno;
                  goto upd_bof;
            }
            if (st.filemode & S_IFDIR) {
                  gfr_entry.status = DPM_FAILED | EISDIR;
                  goto upd_bof;
            }

            if ((c = dpm_check_replica_online (sfn, gfr_entry.s_token,
                server, pfn)) < 0) {
                  gfr_entry.status = DPM_FAILED | serrno;
                  goto upd_bof;
            }
            if (c > 0) {      /* must bring replica online */
                  gfr_entry.status = c;
                  if (dpm_build_recall_request (&thip->dbfd, dpm_req, &gfr_entry,
                      pfn, c, &backend_req) < 0) {
                        gfr_entry.status = DPM_FAILED | serrno;
                        goto upd_bof;
                  }
                  dpmlogit (func, "%s: to be recalled\n", gfr_entry.from_surl);
                  nb_files_to_recall++;
                  goto upd_bof;
            }

            /* Update filesize/status in gfr_entry */

            gfr_entry.actual_size = st.filesize;
            gfr_entry.status = DPM_SUCCESS;
upd_bof:
            (void) dpm_start_tr (thip->s, &thip->dbfd);
            if (dpm_get_gfr_by_fullid (&thip->dbfd, dpm_req->r_token, i,
                &old_gfr_entry, 1, &rec_addrf) < 0) {
                  dpm_abort_tr (&thip->dbfd);
                  continue;
            }
            if (old_gfr_entry.status == DPM_ACTIVE)
                  (void) dpm_update_gfr_entry (&thip->dbfd, &rec_addrf,
                      &gfr_entry);
            (void) dpm_end_tr (&thip->dbfd);
            if (gfr_entry.status != DPM_SUCCESS &&
                (gfr_entry.status & 0xF000) != DPM_TO_BE_RECALLED) {
                  dpmlogit (func, "%s: %s\n", gfr_entry.from_surl,
                      *gfr_entry.errstring ? gfr_entry.errstring :
                      status2str (gfr_entry.status, errbuf));
                  nb_file_err++;
            }
      }

      if (nb_files_to_recall) {
            if (dpm_write_recall_request (&thip->dbfd, DPM_DICOM_RECALL, &backend_req) < 0)
                  RETURN (serrno);
            RETURNS (0, DPM_ACTIVE);
      }

      /* Move the request to the non-pending queue */

      (void) dpm_start_tr (thip->s, &thip->dbfd);
      if ((c = dpm_get_pending_req_by_token (&thip->dbfd, dpm_req->r_token,
          dpm_req, 1, &rec_addr)) < 0 && serrno != ENOENT)
            RETURN (serrno);
      if (c)
            RETURN (0);
      if (dpm_delete_pending_entry (&thip->dbfd, &rec_addr) < 0)
            RETURN (serrno);
      dpm_req->etime = time (0);
      if (nb_file_err == 0)
            dpm_req->status = DPM_SUCCESS;
      else if (nb_file_err != dpm_req->nbreqfiles)
            dpm_req->status = DPM_DONE;
      else {
            if (dpm_req->nbreqfiles == 1)
                  dpm_req->status = gfr_entry.status;
            else
                  dpm_req->status = DPM_FAILED | EINVAL;
            strcpy (dpm_req->errstring, "Failed for all SURLs");
      }
      if (dpm_insert_xferreq_entry (&thip->dbfd, dpm_req) < 0)
            RETURN (serrno);
      RETURNS (0, dpm_req->status);
}

dpm_srv_proc_get(dpm_req, thip, nbgids, gids)
struct dpm_req *dpm_req;
struct dpm_srv_thread_info *thip;
int nbgids;
gid_t *gids;
{
      struct dpm_backend_req backend_req;
      int c;
      time_t current_time;
      char errbuf[256];
      struct Cns_fileid file_uniqueid;
      char func[17];
      struct dpm_get_filereq gfr_entry;
      int i;
      int maxpintime;
      int nb_file_err = 0;
      int nb_files_to_recall = 0;
      struct dpm_get_filereq old_gfr_entry;
      char pfn[CA_MAXSFNLEN+1];
      dpm_dbrec_addr rec_addr;
      dpm_dbrec_addr rec_addrf;
      char server[CA_MAXHOSTNAMELEN+1];
      char *sfn;
      struct Cns_filestat st;
      time_t t1;

      strcpy (func, "dpm_srv_proc_get");
      dpmlogit (func, "processing request %s from %s\n", dpm_req->r_token,
          dpm_req->client_dn);
      memset (&backend_req, 0, sizeof(backend_req));

      for (i = 0; i < dpm_req->nbreqfiles; i++) {

            /* Get File Request */

            (void) dpm_start_tr (thip->s, &thip->dbfd);
            if (dpm_get_gfr_by_fullid (&thip->dbfd, dpm_req->r_token, i,
                &gfr_entry, 1, &rec_addrf) < 0) {
                  dpm_abort_tr (&thip->dbfd);
                  continue;
            }
            if (gfr_entry.status != DPM_QUEUED) {     /* No need to process */
                  dpm_abort_tr (&thip->dbfd);
                  continue;
            }

            /* Mark the file request as active */

            gfr_entry.status = DPM_ACTIVE;
            (void) dpm_update_gfr_entry (&thip->dbfd, &rec_addrf, &gfr_entry);
            (void) dpm_end_tr (&thip->dbfd);

            if (strncmp (gfr_entry.from_surl, "srm://", 6) == 0) {
                  if ((sfn = sfnfromsurl (gfr_entry.from_surl)) == NULL) {
                        gfr_entry.status = DPM_FAILED | EINVAL;
                        strcpy (gfr_entry.errstring, "Bad SURL syntax");
                        goto upd_gfr;
                  }
            } else
                  sfn = gfr_entry.from_surl;

            /* Check if the file exists */

            memset ((void *) &file_uniqueid, 0, sizeof(struct Cns_fileid));
            if (Cns_statx (sfn, &file_uniqueid, &st) < 0) {
                  gfr_entry.status = DPM_FAILED | serrno;
                  goto upd_gfr;
            }
            if (st.filemode & S_IFDIR) {
                  gfr_entry.status = DPM_FAILED | EISDIR;
                  goto upd_gfr;
            }

            /* Get best replica */

            if ((c = dpm_getbestreplica (sfn, dpm_req->clienthost, server, pfn)) < 0) {
                  gfr_entry.status = DPM_FAILED | serrno;
                  goto upd_gfr;
            }
            if (c > 0) {      /* must bring replica online */
                  gfr_entry.status = c;
                  if (dpm_build_recall_request (&thip->dbfd, dpm_req, &gfr_entry,
                      pfn, c, &backend_req) < 0) {
                        gfr_entry.status = DPM_FAILED | serrno;
                        goto upd_gfr;
                  }
                  dpmlogit (func, "%s: to be recalled\n", gfr_entry.from_surl);
                  nb_files_to_recall++;
                  goto upd_gfr;
            }

            /* Update last access date/nb accesses in replica entry */

            (void) Cns_setratime (pfn);

            /* Update last access date in DPM file catalog master table */

            if (Cns_setatime (sfn, &file_uniqueid) < 0) {
                  gfr_entry.status = DPM_FAILED | serrno;
                  goto upd_gfr;
            }

            /* Update lifetime/server/pfn/filesize/status in gfr_entry */

            current_time = time (0);
            if (! gfr_entry.lifetime)
                  gfr_entry.lifetime = dpm_get_defpintime (pfn);
            if (gfr_entry.lifetime != 0x7FFFFFFF)
                  gfr_entry.lifetime += current_time;
            maxpintime = dpm_get_maxpintime (pfn);
            if (maxpintime != 0x7FFFFFFF)
                  maxpintime += current_time;
            if (gfr_entry.lifetime > maxpintime)
                  gfr_entry.lifetime = maxpintime;
            if (dpm_get_max_get_lifetime (&thip->dbfd, pfn, &t1) < 0)
                  t1 = 0;
            if (gfr_entry.lifetime > t1)
                  t1 = gfr_entry.lifetime;
            if (Cns_setptime (pfn, t1) < 0) {
                  gfr_entry.status = DPM_FAILED | serrno;
                  goto upd_gfr;
            }
            strcpy (gfr_entry.server, server);
            strcpy (gfr_entry.pfn, pfn);
            gfr_entry.actual_size = st.filesize;
            gfr_entry.status = DPM_READY;
upd_gfr:
            (void) dpm_start_tr (thip->s, &thip->dbfd);
            if (dpm_get_gfr_by_fullid (&thip->dbfd, dpm_req->r_token, i,
                &old_gfr_entry, 1, &rec_addrf) < 0) {
                  dpm_abort_tr (&thip->dbfd);
                  continue;
            }
            if (old_gfr_entry.status == DPM_ACTIVE)
                  (void) dpm_update_gfr_entry (&thip->dbfd, &rec_addrf,
                      &gfr_entry);
            (void) dpm_end_tr (&thip->dbfd);
            if (gfr_entry.status != DPM_READY &&
                (gfr_entry.status & 0xF000) != DPM_TO_BE_RECALLED) {
                  dpmlogit (func, "%s: %s\n", gfr_entry.from_surl,
                      *gfr_entry.errstring ? gfr_entry.errstring :
                      status2str (gfr_entry.status, errbuf));
                  nb_file_err++;
            }
      }

      if (nb_files_to_recall) {
            if (dpm_write_recall_request (&thip->dbfd, DPM_DICOM_RECALL, &backend_req) < 0)
                  RETURN (serrno);
            RETURNS (0, DPM_ACTIVE);
      }

      /* Move the request to the non-pending queue */

      (void) dpm_start_tr (thip->s, &thip->dbfd);
      if ((c = dpm_get_pending_req_by_token (&thip->dbfd, dpm_req->r_token,
          dpm_req, 1, &rec_addr)) < 0 && serrno != ENOENT)
            RETURN (serrno);
      if (c)
            RETURN (0);
      if (dpm_delete_pending_entry (&thip->dbfd, &rec_addr) < 0)
            RETURN (serrno);
      dpm_req->etime = time (0);
      if (nb_file_err == 0)
            dpm_req->status = DPM_SUCCESS;
      else if (nb_file_err != dpm_req->nbreqfiles)
            dpm_req->status = DPM_DONE;
      else {
            if (dpm_req->nbreqfiles == 1)
                  dpm_req->status = gfr_entry.status;
            else
                  dpm_req->status = DPM_FAILED | EINVAL;
            strcpy (dpm_req->errstring, "Failed for all SURLs");
      }
      if (dpm_insert_xferreq_entry (&thip->dbfd, dpm_req) < 0)
            RETURN (serrno);
      RETURNS (0, dpm_req->status);
}

dpm_srv_proc_put(dpm_req, thip, nbgids, gids)
struct dpm_req *dpm_req;
struct dpm_srv_thread_info *thip;
int nbgids;
gid_t *gids;
{
      int c;
      int cns_in_trans;
      time_t current_time;
      int defpintime;
      struct dpm_space_reserv dpm_spcmd;
      char errbuf[256];
      char errstring[256];
      char **excl_fs = NULL;
      char **excl_host = NULL;
      int excl_mutex_taken = 0;
      int file_created;
      struct Cns_fileid file_uniqueid;
      char fs[80];
      char func[17];
      char gid_str[256];
      struct group *gr;
      int i;
      int j;
      int maxpintime;
      int nb_file_err = 0;
      int nb_s_gids;
      int nbreplicas = 0;
      struct dpm_put_filereq old_pfr_entry;
      int old_status;
      char *p;
      char pfn[CA_MAXSFNLEN+1];
      struct dpm_put_filereq pfr_entry;
      char poolname[CA_MAXPOOLNAMELEN+1];
      gid_t r_gid;
      dpm_dbrec_addr rec_addr;
      dpm_dbrec_addr rec_addrf;
      dpm_dbrec_addr rec_addrs;
      struct Cns_filereplicax *rep_entries = NULL;
      int replica_added;
      u_signed64 reqsize;
      gid_t sav_rgid = -1;
      gid_t *s_gids;
      char server[CA_MAXHOSTNAMELEN+1];
      char *sfn;
      struct Cns_filestat st;
      struct stat statbuf;
      int status;
      char timestr[11];
      struct tm *tm;
      char tmpbuf[12];
      char tmpbuf0[21];
      char tmpbuf1[21];
#if defined(_REENTRANT) || defined(_THREAD_SAFE)
      struct tm tmstruc;
#endif
      int u_space_updated;

      strcpy (func, "dpm_srv_proc_put");
      dpmlogit (func, "processing request %s from %s\n", dpm_req->r_token,
          dpm_req->client_dn);
#if (defined(_REENTRANT) || defined(_THREAD_SAFE)) && !defined(_WIN32)
      (void) localtime_r (&dpm_req->stime, &tmstruc);
      tm = &tmstruc;
#else
      tm = localtime (&dpm_req->stime);
#endif
      strftime (timestr, 11, "%F", tm);
      if (dpm_req->r_uid || dpm_req->flags != 4) {
            r_gid = dpm_req->r_gid;
#ifdef VIRTUAL_ID
            if (r_gid == 0)
                  strcpy (gid_str, "root");
            else if (Cns_getgrpbygid (r_gid, gid_str) == 0) {
                  if ((p = strchr (gid_str, '/'))) *p = '\0';
            }
#else
            if ((gr = Cgetgrgid (r_gid)))
                  strcpy (gid_str, gr->gr_name);
#endif
            else
                  sprintf (gid_str, "%d", r_gid);
      }
                
      errstring[0] = '\0';
      for (i = 0; i < dpm_req->nbreqfiles; i++) {

            /* Get File Request */

            (void) dpm_start_tr (thip->s, &thip->dbfd);
            if (dpm_get_pfr_by_fullid (&thip->dbfd, dpm_req->r_token, i,
                &pfr_entry, 1, &rec_addrf) < 0) {
                  dpm_abort_tr (&thip->dbfd);
                  continue;
            }
            if (pfr_entry.status != DPM_QUEUED) {     /* No need to process */
                  dpm_abort_tr (&thip->dbfd);
                  continue;
            }

            /* Mark the file request as active */

            pfr_entry.status = DPM_ACTIVE;
            (void) dpm_update_pfr_entry (&thip->dbfd, &rec_addrf, &pfr_entry);
            (void) dpm_end_tr (&thip->dbfd);

            cns_in_trans = 0;
            file_created = 0;
            nbreplicas = 0;
            pfn[0] = '\0';
            poolname[0] = '\0';
            replica_added = 0;
            rep_entries = NULL;
            u_space_updated = 0;
            if (strncmp (pfr_entry.to_surl, "srm://", 6) == 0) {
                  if ((sfn = sfnfromsurl (pfr_entry.to_surl)) == NULL) {
                        pfr_entry.status = DPM_FAILED | EINVAL;
                        strcpy (pfr_entry.errstring, "Bad SURL syntax");
                        goto upd_pfr;
                  }
            } else
                  sfn = pfr_entry.to_surl;

            /* Check if the file exists */

            dpmlogit (func, "calling Cns_stat\n");
            memset (&file_uniqueid, 0, sizeof(file_uniqueid));
            if ((c = Cns_statx (sfn, &file_uniqueid, &st)) < 0 &&
                (serrno != ENOENT || dpm_req->flags == 4)) {
                  pfr_entry.status = DPM_FAILED | serrno;
                  goto upd_pfr;
            }
            if (dpm_req->flags == 4) {    /* for replication */
                  if (Cthread_mutex_lock (&excl_mutex) < 0) {
                        pfr_entry.status = DPM_FAILED | serrno;
                        goto upd_pfr;
                  }
                  excl_mutex_taken = 1;
                  excl_fs = NULL;
                  excl_host = NULL;
                  if (Cns_getreplicax (sfn, NULL, NULL, &nbreplicas, &rep_entries) < 0) {
                        pfr_entry.status = DPM_FAILED | serrno;
                        goto upd_pfr;
                  }
                  if (nbreplicas == 0) {
                        pfr_entry.status = DPM_FAILED | ENOENT;
                        goto upd_pfr;
                  }
                  if ((excl_fs = malloc ((nbreplicas + 1) * sizeof(char *))) == NULL ||
                      (excl_host = malloc ((nbreplicas + 1) * sizeof(char *))) == NULL) {
                        pfr_entry.status = DPM_FAILED | ENOMEM;
                        goto upd_pfr;
                  }
                  for (j = 0; j < nbreplicas; j++) {
                        excl_fs[j] = (rep_entries + j)->fs;
                        excl_host[j] = (rep_entries + j)->host;
                  }
                  excl_fs[nbreplicas] = NULL;
                  excl_host[nbreplicas] = NULL;
                  pfr_entry.requested_size = st.filesize;
                  if (dpm_req->r_uid == 0) {
                        r_gid = st.gid;
                        if (r_gid != sav_rgid) {
#ifdef VIRTUAL_ID
                              if (r_gid == 0)
                                    strcpy (gid_str, "root");
                              else if (Cns_getgrpbygid (r_gid, gid_str) == 0) {
                                    if ((p = strchr (gid_str, '/'))) *p = '\0';
                              }
#else
                              if ((gr = Cgetgrgid (r_gid)))
                                    strcpy (gid_str, gr->gr_name);
#endif
                              else
                                    sprintf (gid_str, "%d", r_gid);
                              sav_rgid = r_gid;
                        }
                  }
            } else {
                  if (c == 0) {           /* file exists */
                        if (! dpm_req->flags) { /* overwrite option not set */
                              pfr_entry.status = DPM_FAILED | EEXIST;
                              goto upd_pfr;
                        }

                        /* delete existing disk replicas */

                        status = 0;
                        if (Cns_getreplicax (sfn, NULL, NULL,
                            &nbreplicas, &rep_entries) < 0) {
                              pfr_entry.status = DPM_FAILED | serrno;
                              goto upd_pfr;
                        }
                        for (j = 0; j < nbreplicas; j++) {
                              file_uniqueid.fileid = (rep_entries + i)->fileid;
                              reqsize = 0;
                              if ((rep_entries + i)->status == 'P') {
                                    (void) dpm_start_tr (thip->s, &thip->dbfd);
                                    if (dpm_get_pfr_by_pfn (&thip->dbfd,
                                        (rep_entries + i)->sfn, &old_pfr_entry,
                                        1, &rec_addr) == 0) {
                                          old_status = old_pfr_entry.status;
                                          old_pfr_entry.status = DPM_ABORTED;
                                          if (nbreplicas == 1 &&
                                              old_pfr_entry.actual_size)
                                                file_created = 1;
                                          dpm_update_pfr_entry (&thip->dbfd,
                                              &rec_addr, &old_pfr_entry);
                                          (void) dpm_end_tr (&thip->dbfd);
                                          if (old_status == DPM_READY || old_status == DPM_RUNNING)
                                                reqsize = old_pfr_entry.requested_size;
                                    }
                              }
                              dpm_rm_onereplica (&file_uniqueid,
                                  (rep_entries + i)->sfn, reqsize, &status,
                                  &thip->dbfd, (rep_entries + i)->setname, 0, -1);
                        }
                        free (rep_entries);
                  }

                  /* Start name server transaction */

                  if (Cns_starttrans (NULL, NULL) < 0) {
                        pfr_entry.status = DPM_FAILED | serrno;
                        goto upd_pfr;
                  }
                  cns_in_trans = 1;

                  /* Create an entry in the DPM file catalog master table */

                  dpmlogit (func, "calling Cns_creatx\n");
                  if (Cns_creatx (sfn, 0664, &file_uniqueid) < 0) {
                        if (serrno != ENOENT) {
                              pfr_entry.status = DPM_FAILED | serrno;
                              goto upd_pfr;
                        }
                        (void) Cns_aborttrans ();
                        cns_in_trans = 0;
                        sprintf (tmpbuf, "%d", dpm_req->r_ordinal);
                        if (strcmp (dpm_req->r_token, tmpbuf)) {
                              pfr_entry.status = DPM_FAILED | ENOENT;
                              goto upd_pfr;
                        }
                        /* SRM v1 request, try to create the missing directories on the fly */
                        if (dpm_makedirp (sfn, dpm_req->r_uid, dpm_req->r_gid) < 0) {
                              pfr_entry.status = DPM_FAILED | serrno;
                              goto upd_pfr;
                        }
                        if (Cns_starttrans (NULL, NULL) < 0) {
                              pfr_entry.status = DPM_FAILED | serrno;
                              goto upd_pfr;
                        }
                        cns_in_trans = 1;
                        if (Cns_creatx (sfn, 0664, &file_uniqueid) < 0) {
                              pfr_entry.status = DPM_FAILED | serrno;
                              goto upd_pfr;
                        }
                  }
                  if (c < 0)              /* file did not exist */
                        file_created = 1; /* but has now been successfully created */
            }

            /* Allocate space */

            if (*pfr_entry.s_token) {
                  (void) dpm_start_tr (thip->s, &thip->dbfd);
                  if (dpm_get_spcmd_by_token (&thip->dbfd, pfr_entry.s_token,
                      &dpm_spcmd, 1, &rec_addrs) < 0) {
                        if (serrno == ENOENT) {
                              pfr_entry.status = DPM_FAILED | EINVAL;
                              strcpy (pfr_entry.errstring, "Unknown space token");
                        } else
                              pfr_entry.status = DPM_FAILED | serrno;
                        goto upd_pfr;
                  }
                  if (dpm_req->r_uid && dpm_spcmd.s_gid) {
                        if ((s_gids = Cdecode_groups (dpm_spcmd.groups, &nb_s_gids)) == NULL) {
                              pfr_entry.status = DPM_FAILED | ENOMEM;
                              goto upd_pfr;
                        }
                        for (j = 0; j < nb_s_gids; j++) {
                              if (Cgroupmatch (s_gids[j], nbgids, gids)) break;
                        }
                        free (s_gids);
                        if (j >= nb_s_gids) {
                              pfr_entry.status = DPM_FAILED | EACCES;
                              goto upd_pfr;
                        }
                  }
                  if (dpm_req->r_uid && dpm_spcmd.s_uid && dpm_req->r_uid != dpm_spcmd.s_uid) {
                        pfr_entry.status = DPM_FAILED | EACCES;
                        goto upd_pfr;
                  }
                  if (dpm_spcmd.expire_time < time (0)) {
                        pfr_entry.status = DPM_FAILED | EINVAL;
                        strcpy (pfr_entry.errstring, "Space lifetime expired");
                        strcpy (errstring, pfr_entry.errstring);
                        goto upd_pfr;
                  }
                  strcpy (poolname, dpm_spcmd.poolname);
            }
             
            dpmlogit (func, "calling dpm_selectfs\n");
            if (dpm_selectfs (r_gid, pfr_entry.f_type,
                pfr_entry.ret_policy, pfr_entry.ac_latency, excl_host, excl_fs,
                &pfr_entry.requested_size, server, pfn, poolname, &defpintime) < 0) {
                  pfr_entry.status = DPM_FAILED | ENOSPC;
                  goto upd_pfr;
            }
            if (excl_mutex_taken)
                  (void) Cthread_mutex_unlock (&excl_mutex);

            if (*pfr_entry.s_token) {
                  if (dpm_spcmd.u_space < 0 ||
                      pfr_entry.requested_size > dpm_spcmd.u_space) {
                        pfr_entry.status = DPM_FAILED | ENOSPC;
                        strcpy (pfr_entry.errstring,
                            "Insufficient space left associated with token");
                        strcpy (errstring, pfr_entry.errstring);
                        goto upd_pfr;
                  }
                  dpm_spcmd.u_space -= pfr_entry.requested_size;
                  if (dpm_update_spcmd_entry (&thip->dbfd, &rec_addrs, &dpm_spcmd) < 0) {
                        pfr_entry.status = DPM_FAILED | serrno;
                        dpm_abort_tr (&thip->dbfd);
                        goto upd_pfr;
                  }
                  (void) dpm_end_tr (&thip->dbfd);
                  dpmlogit (func, "Updated space token %s: incr=%s, u_space=%s\n",
                      pfr_entry.s_token, i64tostr (-pfr_entry.requested_size, tmpbuf0, 0),
                      i64tostr (dpm_spcmd.u_space, tmpbuf1, 0));
                  u_space_updated++;
            }

            p = strchr (pfn, ':') + 1;
            strcpy (fs, p);

            /* Build directory name: fs/group/date and make sure the directory exists */

            sprintf (pfn + strlen (pfn), "/%s/%s", gid_str, timestr);
            rfio_errno = 0;
            if (rfio_stat (pfn, &statbuf) < 0) {
                  c = rfio_serrno();
                  if (c != ENOENT) {
                        dpmlogit (func, "error accessing %s: %s\n", pfn,
                            rfio_serror());
                        /* Should also disable the filesystem */
                        pfr_entry.status = DPM_FAILED | c;
                        goto upd_pfr;
                  }
                  p = strrchr (pfn, '/');
                  *p = '\0';
                  rfio_errno = 0;
                  if (rfio_stat (pfn, &statbuf) < 0) {
                        c = rfio_serrno();
                        if (c != ENOENT) {
                              dpmlogit (func, "error accessing %s: %s\n", pfn,
                                  rfio_serror());
                              /* Should also disable the filesystem */
                              pfr_entry.status = DPM_FAILED | c;
                              goto upd_pfr;
                        }
                        if (rfio_mkdir (pfn, 0770) < 0) {   /* create vo directory */
                              c = rfio_serrno();
                              if (c != EEXIST) {
                                    dpmlogit (func, "error creating %s: %s\n",
                                        pfn, rfio_serror());
                                    /* Should also disable the filesystem */
                                    pfr_entry.status = DPM_FAILED | c;
                                    goto upd_pfr;
                              }
                        }
                        if (rfio_chown (pfn, dpm_uid, dpm_gid) < 0) {
                              dpmlogit (func, "error chowning %s: %s\n",
                                  pfn, rfio_serror());
                              /* Should also disable the filesystem */
                              pfr_entry.status = DPM_FAILED | rfio_serrno();
                              goto upd_pfr;
                        }
                  }
                  *p = '/';
                  if (rfio_mkdir (pfn, 0770) < 0) {   /* create date directory */
                        c = rfio_serrno();
                        if (c != EEXIST) {
                              dpmlogit (func, "error creating %s: %s\n",
                                  pfn, rfio_serror());
                              /* Should also disable the filesystem */
                              pfr_entry.status = DPM_FAILED | c;
                              goto upd_pfr;
                        }
                  }
                  if (rfio_chown (pfn, dpm_uid, dpm_gid) < 0) {
                        dpmlogit (func, "error chowning %s: %s\n",
                            pfn, rfio_serror());
                        /* Should also disable the filesystem */
                        pfr_entry.status = DPM_FAILED | rfio_serrno();
                        goto upd_pfr;
                  }
            }

            /* Build complete pfn: fs/group/date/basename.r_ordinal.f_ordinal */

            sprintf (pfn + strlen (pfn), "/%.235s.%d.%d",
                strrchr (pfr_entry.to_surl, '/') + 1,
                dpm_req->r_ordinal, pfr_entry.f_ordinal);

            /* Add replica entry */

            if (Cns_addreplicax (NULL, &file_uniqueid, server, pfn, 'P',
                pfr_entry.f_type, poolname, fs,
                (dpm_req->flags == 4) ? 'S' : 'P', pfr_entry.s_token) < 0) {
                  pfr_entry.status = DPM_FAILED | serrno;
                  goto upd_pfr;
            }
            replica_added = 1;

            /* Update server/pfn/status in pfr_entry */

            current_time = time (0);
            if (! pfr_entry.lifetime)
                  pfr_entry.lifetime = defpintime;
            if (pfr_entry.lifetime != 0x7FFFFFFF)
                  pfr_entry.lifetime += current_time;
            if (* pfr_entry.s_token)
                  maxpintime = dpm_spcmd.expire_time;
            else {
                  maxpintime = dpm_get_maxpintime (pfn);
                  if (maxpintime != 0x7FFFFFFF)
                        maxpintime += current_time;
            }
            if (pfr_entry.lifetime > maxpintime)
                  pfr_entry.lifetime = maxpintime;
            strcpy (pfr_entry.server, server);
            strcpy (pfr_entry.pfn, pfn);
            if (file_created)
                  pfr_entry.actual_size = -1;
            pfr_entry.status = DPM_READY;
upd_pfr:
            if (dpm_req->flags == 4) {    /* for replication */
                  if (excl_mutex_taken)
                        (void) Cthread_mutex_unlock (&excl_mutex);
                  free (excl_fs);
                  free (excl_host);
                  free (rep_entries);
            }
            (void) dpm_start_tr (thip->s, &thip->dbfd);
            if (dpm_get_pfr_by_fullid (&thip->dbfd, dpm_req->r_token, i,
                &old_pfr_entry, 1, &rec_addrf) < 0) {
                  pfr_entry.status = DPM_FAILED | serrno;
                  dpm_abort_tr (&thip->dbfd);
            } else {
                  if (old_pfr_entry.status == DPM_ACTIVE) {
                        (void) dpm_update_pfr_entry (&thip->dbfd, &rec_addrf,
                            &pfr_entry);
                        if (pfr_entry.status == DPM_READY && cns_in_trans) {
                              (void) Cns_endtrans ();
                              cns_in_trans = 0;
                        }
                  } else {
                        if ((pfr_entry.status & 0xF000) != DPM_FAILED)
                              pfr_entry.status = DPM_FAILED | SEINTERNAL;
                  }
                  (void) dpm_end_tr (&thip->dbfd);
            }
            if ((pfr_entry.status & 0xF000) == DPM_FAILED) {
                        if (*pfn) {
                        if (u_space_updated)
                              (void) dpm_upd_u_space (&thip->dbfd, pfr_entry.s_token,
                                  pfr_entry.requested_size);
                        dpm_updfreespace (pfn, pfr_entry.requested_size, pfr_entry.s_token, 0);
                  }
                  if (replica_added)
                        (void) Cns_delreplica (NULL, &file_uniqueid, pfn);
                  if (file_created)
                        (void) Cns_unlink (sfn);
            }
            if (cns_in_trans)
                  (void) Cns_endtrans ();
            if (pfr_entry.status != DPM_READY) {
                  dpmlogit (func, "%s: %s\n", pfr_entry.to_surl,
                      *pfr_entry.errstring ? pfr_entry.errstring :
                      status2str (pfr_entry.status, errbuf));
                  nb_file_err++;
            }
      }

      /* Move the request to the non-pending queue */

      (void) dpm_start_tr (thip->s, &thip->dbfd);
      if ((c = dpm_get_pending_req_by_token (&thip->dbfd, dpm_req->r_token,
          dpm_req, 1, &rec_addr)) < 0 && serrno != ENOENT)
            RETURN (serrno);
      if (c)
            RETURN (0);
      if (dpm_delete_pending_entry (&thip->dbfd, &rec_addr) < 0)
            RETURN (serrno);
      dpm_req->etime = time (0);
      if (nb_file_err == 0)
            dpm_req->status = DPM_SUCCESS;
      else if (nb_file_err != dpm_req->nbreqfiles)
            dpm_req->status = DPM_DONE;
      else {
            if (dpm_req->nbreqfiles == 1)
                  dpm_req->status = pfr_entry.status;
            else
                  dpm_req->status = DPM_FAILED | EINVAL;
            strcpy (dpm_req->errstring, "Failed for all SURLs");
      }
      if (*errstring)
            strcpy (dpm_req->errstring, errstring);
      if (dpm_insert_xferreq_entry (&thip->dbfd, dpm_req) < 0)
            RETURN (serrno);
      RETURNS (0, dpm_req->status);
}

Generated by  Doxygen 1.6.0   Back to index