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

dpm_procreq.c

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

#ifndef lint
static char sccsid[] = "@(#)$RCSfile: dpm_procreq.c,v $ $Revision: 1.57 $ $Date: 2009/09/16 16:10:14 $ CERN IT-GD/CT Jean-Philippe Baud";
#endif /* not lint */

#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#if defined(_WIN32)
#include <winsock2.h>
#else
#include <netinet/in.h>
#endif
#include <uuid/uuid.h>
#include "Cpwd.h"
#ifdef CSEC
#include "Csec_api.h"
#endif
#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 "marshall.h"
#include "patchlevel.h"
#include "rfio_api.h"
#include "serrno.h"
#include "u64subr.h"

extern int being_shutdown;
extern char dpnshost[CA_MAXHOSTNAMELEN+1];
extern char localdomain[CA_MAXHOSTNAMELEN+1];
extern int nb_supported_protocols;
extern char **supported_protocols;
gid_t *Cdecode_groups (char *, int *);
char *Cencode_groups (int, gid_t *, char *);
int Cgroupmatch (gid_t, int, gid_t *);
int dpm_rm_onereplica (struct Cns_fileid *, char *, u_signed64, int *, struct dpm_dbfd *dbfd, char *, int, u_signed64);

/*    dpm_logreq - log a request */

/*    Split the message into lines so they don't exceed LOGBUFSZ-1 characters
 *    A backslash is appended to a line to be continued
 *    A continuation line is prefixed by '+ '
 */
void
dpm_logreq(func, logbuf)
char *func;
char *logbuf;
{
      int n1, n2;
      char *p;
      char savechrs1[2];
      char savechrs2[2];

      n1 = LOGBUFSZ - strlen (func) - 36;
      n2 = strlen (logbuf);
      p = logbuf;
      while (n2 > n1) {
            savechrs1[0] = *(p + n1);
            savechrs1[1] = *(p + n1 + 1);
            *(p + n1) = '\\';
            *(p + n1 + 1) = '\0';
            dpmlogit (func, DP098, p);
            if (p != logbuf) {
                  *p = savechrs2[0];
                  *(p + 1) = savechrs2[1];
            }
            p += n1 - 2;
            savechrs2[0] = *p;
            savechrs2[1] = *(p + 1);
            *p = '+';
            *(p + 1) = ' ';
            *(p + 2) = savechrs1[0];
            *(p + 3) = savechrs1[1];
            n2 -= n1;
      }
      dpmlogit (func, DP098, p);
      if (p != logbuf) {
            *p = savechrs2[0];
            *(p + 1) = savechrs2[1];
      }
}

dpm_reallocate_space (dbfd)
struct dpm_dbfd *dbfd;
{
      int bol = 1;
      int c;
      DBLISTPTR dblistptr;
      struct dpm_space_reserv dpm_spcmd;
      char func[21];
      struct dpm_put_filereq pfr_entry;
      struct stat64 statbuf;

      strcpy (func, "dpm_reallocate_space");
      dpmlogit (func, "Reallocating the space needed by reservespace requests\n");
      while ((c = dpm_list_spcmd_entry (dbfd, bol, &dpm_spcmd, 0, &dblistptr)) == 0) {
            bol = 0;
            dpm_updpoolfreespace (dpm_spcmd.poolname, -dpm_spcmd.u_space);
      }
      (void) dpm_list_spcmd_entry (dbfd, bol, &dpm_spcmd, 1, &dblistptr);
      if (c < 0)
            return (c);

      bol = 1;
      dpmlogit (func, "Reallocating the space needed by pending requests\n");
      while ((c = dpm_list_rr_puts (dbfd, bol, &pfr_entry, 0, &dblistptr)) == 0) {
            bol = 0;
            if (rfio_stat64 (pfr_entry.pfn, &statbuf) != 0)
                  statbuf.st_size = 0;
            dpm_updfreespace (pfr_entry.pfn, statbuf.st_size -
                pfr_entry.requested_size, pfr_entry.s_token, 0);
      }
      (void) dpm_list_rr_puts (dbfd, bol, &pfr_entry, 1, &dblistptr);   /* free res */
      return (c < 0 ? -1 : 0);
}

dpm_recover_queue (dbfd)
struct dpm_dbfd *dbfd;
{
      int bof;
      int bol = 1;
      int c;
      DBLISTPTR dblistptr;
      DBLISTPTR dblistptrf;
      struct dpm_req dpm_req;
      int errflag = 0;
      char func[18];
      struct dpm_put_filereq pfr_entry;
      dpm_dbrec_addr rec_addr;
      dpm_dbrec_addr rec_addrf;
      struct stat64 statbuf;

      strcpy (func, "dpm_recover_queue");
      dpmlogit (func, "Recovering the queue of pending requests\n");
      (void) dpm_start_tr (0, dbfd);
      while ((c = dpm_list_pending_req (dbfd, bol, &dpm_req, 1, &rec_addr, 0,
          &dblistptr)) == 0) {
            bol = 0;
            inc_reqctr ();
            if (dpm_req.status != DPM_ACTIVE) continue;
            bof = 1;
            if (dpm_req.r_type != 'P') continue;
            while ((c = dpm_list_pfr_entry (dbfd, bof, dpm_req.r_token,
                &pfr_entry, 1, &rec_addrf, 0, &dblistptrf)) == 0) {
                  bof = 0;
                  switch (pfr_entry.status) {
                  case DPM_ACTIVE:
                        pfr_entry.status = DPM_QUEUED;
                        if (dpm_update_pfr_entry (dbfd, &rec_addrf, &pfr_entry) < 0)
                              errflag++;
                        break;
                  default:
                        break;
                  }
            }
            (void) dpm_list_pfr_entry (dbfd, bof, dpm_req.r_token,
                &pfr_entry, 1, &rec_addrf, 1, &dblistptrf); /* free res */
            if (c < 0)
                  errflag++;
            else {
                  dpm_req.status = DPM_QUEUED;
                  if (dpm_update_pending_entry (dbfd, &rec_addr, &dpm_req) < 0)
                        errflag++;
            }
      }
      (void) dpm_list_pending_req (dbfd, bol, &dpm_req, 1, &rec_addr, 1,
          &dblistptr);  /* free res */
      (void) dpm_end_tr (dbfd);
      return ((c < 0 || errflag) ? -1 : 0);
}

get_client_actual_id (thip, uid, gid, nbgids, gids, user)
struct dpm_srv_thread_info *thip;
uid_t *uid;
gid_t *gid;
int *nbgids;
gid_t **gids;
char **user;
{
#ifdef CSEC
      *uid = thip->Csec_uid;
#ifdef VIRTUAL_ID
      *gid = *thip->Csec_gids;
      *nbgids = thip->Csec_nbgids;
      *gids = thip->Csec_gids;
#else
      *gid = thip->Csec_gid;
      *nbgids = 1;
      *gids = gid;
#endif
      *user = thip->Csec_auth_id;
#else
      struct passwd *pw;

      *nbgids = 1;
      *gids = gid;
      if ((pw = Cgetpwuid (*uid)) == NULL)
            *user = "UNKNOWN";
      else
            *user = pw->pw_name;
#endif
      return (0);
}

marshall_CPR (sbpp, cpr_entry)
char **sbpp;
struct dpm_copy_filereq *cpr_entry;
{
      int n;
      char *sbp;

      if (! sbpp) {
            n = strlen (cpr_entry->from_surl) + 1;
            n += strlen (cpr_entry->to_surl) + 1;
            n += HYPERSIZE;
            n += LONGSIZE;
            n += strlen (cpr_entry->errstring) + 1;
            n += TIME_TSIZE;
            return (n);
      }
      sbp = *sbpp;
      marshall_STRING (sbp, cpr_entry->from_surl);
      marshall_STRING (sbp, cpr_entry->to_surl);
      marshall_HYPER (sbp, cpr_entry->actual_size);
      marshall_LONG (sbp, cpr_entry->status);
      marshall_STRING (sbp, cpr_entry->errstring);
      marshall_TIME_T (sbp, cpr_entry->f_lifetime);
      *sbpp = sbp;
      return (0);
}

marshall_GFR (sbpp, gfr_entry)
char **sbpp;
struct dpm_get_filereq *gfr_entry;
{
      int n;
      char *p;
      char *sbp;
      char turl[CA_MAXSFNLEN+1];

      if (*gfr_entry->pfn) {
            if (strcmp (gfr_entry->protocol, "rfio") == 0)
                  p = strchr (gfr_entry->pfn, ':') + 1;
            else
                  p = gfr_entry->pfn;
            sprintf (turl, "%s://%s/%s", gfr_entry->protocol, gfr_entry->server, p);
      } else
            *turl = '\0';
      if (! sbpp) {
            n = strlen (gfr_entry->from_surl) + 1;
            n += strlen (turl) + 1;
            n += HYPERSIZE;
            n += LONGSIZE;
            n += strlen (gfr_entry->errstring) + 1;
            n += TIME_TSIZE;
            return (n);
      }
      sbp = *sbpp;
      marshall_STRING (sbp, gfr_entry->from_surl);
      marshall_STRING (sbp, turl);
      marshall_HYPER (sbp, gfr_entry->actual_size);
      marshall_LONG (sbp, gfr_entry->status);
      marshall_STRING (sbp, gfr_entry->errstring);
      marshall_TIME_T (sbp, gfr_entry->lifetime);
      *sbpp = sbp;
      return (0);
}

marshall_PFR (sbpp, magic, pfr_entry)
char **sbpp;
int magic;
struct dpm_put_filereq *pfr_entry;
{
      int n;
      char *p;
      char *sbp;
      char turl[CA_MAXSFNLEN+1];

      if (*pfr_entry->pfn) {
            if (strcmp (pfr_entry->protocol, "rfio") == 0)
                  p = strchr (pfr_entry->pfn, ':') + 1;
            else
                  p = pfr_entry->pfn;
            sprintf (turl, "%s://%s/%s", pfr_entry->protocol, pfr_entry->server, p);
      } else
            *turl = '\0';
      if (! sbpp) {
            n = strlen (pfr_entry->to_surl) + 1;
            n += strlen (turl) + 1;
            n += HYPERSIZE;
            n += LONGSIZE;
            n += strlen (pfr_entry->errstring) + 1;
            n += TIME_TSIZE;
            if (magic >= DPM_MAGIC2)
                  n += TIME_TSIZE;
            return (n);
      }
      sbp = *sbpp;
      marshall_STRING (sbp, pfr_entry->to_surl);
      marshall_STRING (sbp, turl);
      marshall_HYPER (sbp, ((pfr_entry->actual_size & INT64_NEG) ? 0 : pfr_entry->actual_size));
      marshall_LONG (sbp, pfr_entry->status);
      marshall_STRING (sbp, pfr_entry->errstring);
      marshall_TIME_T (sbp, pfr_entry->lifetime);
      if (magic >= DPM_MAGIC2)
            marshall_TIME_T (sbp, pfr_entry->f_lifetime);
      *sbpp = sbp;
      return (0);
}

/*    dpm_srv_abortfiles - abort a set of file requests */

dpm_abort_backend_filereq(dbfd, backend_type, r_token, surl)
struct dpm_dbfd *dbfd;
int backend_type;
char *r_token;
char *surl;
{
      dpm_dbrec_addr rec_addrf;

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

            if (dpm_get_dfr_by_surl (dbfd, r_token, surl, &dfr_entry,
                1, &rec_addrf) < 0)
                  return (-1);
            dfr_entry.status = DPM_ABORTED;
            if (dpm_update_dfr_entry (dbfd, &rec_addrf, &dfr_entry) < 0)
                  return (-1);
      } else
#endif
      {
            serrno = SEPROTONOTSUP;
            return (-1);
      }
      return (0);
}

dpm_abort_onefile (thip, r_token, r_type, surl, status)
struct dpm_srv_thread_info *thip;
char *r_token;
char r_type;
char *surl;
int *status;
{
      struct dpm_copy_filereq cpr_entry;
      int file_created = 0;
      struct dpm_get_filereq gfr_entry;
      int old_status;
      char *pfn;
      struct dpm_put_filereq pfr_entry;
      dpm_dbrec_addr rec_addr;
      u_signed64 reqsize;
      time_t t1;

      /* start transaction */

      (void) dpm_start_tr (thip->s, &thip->dbfd);

      switch (r_type) {
      case 'C':
            if (dpm_get_cpr_by_surl (&thip->dbfd, r_token, surl, &cpr_entry,
                1, &rec_addr) < 0) {
                  *status = DPM_FAILED | serrno;
                  (void) dpm_abort_tr (&thip->dbfd);
                  return (-1);
            }
            cpr_entry.status = DPM_ABORTED;
            if (dpm_update_cpr_entry (&thip->dbfd, &rec_addr, &cpr_entry) < 0) {
                  *status = DPM_FAILED | serrno;
                  (void) dpm_abort_tr (&thip->dbfd);
                  return (-1);
            }
            break;
      case 'B':
      case 'G':
            if (dpm_get_gfr_by_surl (&thip->dbfd, r_token, surl, &gfr_entry,
                1, &rec_addr) < 0) {
                  *status = DPM_FAILED | serrno;
                  (void) dpm_abort_tr (&thip->dbfd);
                  return (-1);
            }
            if ((gfr_entry.status & 0xF000) == DPM_TO_BE_RECALLED &&
                dpm_abort_backend_filereq (&thip->dbfd, gfr_entry.status, r_token, surl)) {
                  *status = DPM_FAILED | serrno;
                  (void) dpm_abort_tr (&thip->dbfd);
                  return (-1);
            }
            gfr_entry.lifetime = 0;
            gfr_entry.status = DPM_ABORTED;
            if (dpm_update_gfr_entry (&thip->dbfd, &rec_addr, &gfr_entry) < 0) {
                  *status = DPM_FAILED | serrno;
                  (void) dpm_abort_tr (&thip->dbfd);
                  return (-1);
            }
            pfn = gfr_entry.pfn;
            break;
      case 'P':
            if (dpm_get_pfr_by_surl (&thip->dbfd, r_token, surl, &pfr_entry,
                1, &rec_addr) < 0) {
                  *status = DPM_FAILED | serrno;
                  (void) dpm_abort_tr (&thip->dbfd);
                  return (-1);
            }
            pfr_entry.lifetime = 0;
            if (pfr_entry.status == DPM_READY || pfr_entry.status == DPM_RUNNING) {
                  reqsize = pfr_entry.requested_size;
                  file_created = pfr_entry.actual_size ? 1 : 0;
            } else {
                  reqsize = 0;
                  file_created = 1;
            }
            old_status = pfr_entry.status;
            pfr_entry.status = DPM_ABORTED;
            if (dpm_update_pfr_entry (&thip->dbfd, &rec_addr, &pfr_entry) < 0) {
                  *status = DPM_FAILED | serrno;
                  (void) dpm_abort_tr (&thip->dbfd);
                  return (-1);
            }
            pfn = pfr_entry.pfn;
            break;
      }
      (void) dpm_end_tr (&thip->dbfd);

      if (r_type == 'P' && old_status != DPM_DONE) {
            *status = 0;
            return (dpm_rm_onereplica (NULL, pfn, reqsize, status,
                &thip->dbfd, pfr_entry.s_token, file_created, -1));
      }
      if (r_type == 'G' && *pfn) {
            if (dpm_get_max_get_lifetime (&thip->dbfd, pfn, &t1) < 0)
                  t1 = 0;
            if (Cns_setptime (pfn, t1) < 0) {
                  *status = DPM_FAILED | serrno;
                  return (-1);
            }
      }
      *status = DPM_SUCCESS;
      return (0);
}

dpm_srv_abortfiles(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      struct dpm_req dpm_req;
      char func[19];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[CA_MAXSFNLEN+23];
      int n;
      int nb_file_err = 0;
      int nbgids;
      int nbsurls;
      char r_token[CA_MAXDPMTOKENLEN+1];
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp = repbuf;
      int status;
      char surl[CA_MAXSFNLEN+1];
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_abortfiles");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "abortfiles", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, r_token, CA_MAXDPMTOKENLEN+1)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid request token");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_LONG (rbp, nbsurls);
      if (nbsurls <= 0) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Number of surls <= 0");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      sprintf (logbuf, "abortfiles %s %d", r_token, nbsurls);
      dpm_logreq (func, logbuf);

      if (dpm_get_pending_req_by_token (&thip->dbfd, r_token, &dpm_req, 0, NULL) < 0 &&
          dpm_get_req_by_token (&thip->dbfd, r_token, &dpm_req, 0, NULL) < 0) {
            if (serrno == ENOENT) {
                  status = DPM_FAILED | EINVAL;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "Unknown request token");
            } else {
                  status = DPM_FAILED | serrno;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "");
            }
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, status);
      }
      marshall_LONG (sbp, nbsurls);
      for (i = 0; i < nbsurls; i++) {
            if (unmarshall_STRINGN (rbp, surl, CA_MAXSFNLEN+1)) {
                  status = DPM_FAILED | SENAMETOOLONG;
                  nb_file_err++;
            } else {
                  sprintf (logbuf, "abortfiles %d %s", i, surl);
                  dpm_logreq (func, logbuf);
                  if (dpm_abort_onefile (thip, r_token, dpm_req.r_type,
                      surl, &status) < 0)
                        nb_file_err++;
            }
            n = strlen (surl) + 1;
            n += LONGSIZE;
            n++;
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_SURLST, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_STRING (sbp, surl);
            marshall_LONG (sbp, status);
            marshall_STRING (sbp, "");
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_SURLST, sbp - repbuf, repbuf);

      /* Send global status/errmsg */

      sbp = repbuf;
      if (nb_file_err != nbsurls)
            status = DPM_SUCCESS;
      else if (nbsurls != 1)
            status = DPM_FAILED | EINVAL;
      marshall_LONG (sbp, status);
      marshall_STRING (sbp, "");
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, status);
}

/*    dpm_srv_abortreq - abort a given request */

dpm_abort_backend_request(dbfd, backend_type, r_token)
struct dpm_dbfd *dbfd;
int backend_type;
char *r_token;
{
      struct dpm_backend_req dpm_req;
      dpm_dbrec_addr rec_addr;

#ifdef DICOM
      if (backend_type == DPM_DICOM_RECALL) {
            if (dpm_get_dicomreq_by_token (dbfd, r_token, &dpm_req,
                1, &rec_addr) < 0)
                  return (-1);
            dpm_req.status = DPM_ABORTED;
            if (dpm_update_dicomreq_entry (dbfd, &rec_addr, &dpm_req) < 0)
                  return (-1);
      } else
#endif
      {
            serrno = SEPROTONOTSUP;
            return (-1);
      }
      return (0);
}

dpm_srv_abortreq(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      struct dpm_copy_filereq cpr_entry;
      struct dpm_req dpm_req;
      int file_created = 0;
      char func[17];
      struct dpm_get_filereq gfr_entry;
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[CA_MAXDPMTOKENLEN+10];
      int nb_file_err = 0;
      int nbgids;
      int old_status;
      char *pfn;
      struct dpm_put_filereq pfr_entry;
      char r_token[CA_MAXDPMTOKENLEN+1];
      char *rbp;
      dpm_dbrec_addr rec_addr;
      dpm_dbrec_addr rec_addrf;
      char repbuf[REPBUFSZ];
      u_signed64 reqsize;
      char *sbp = repbuf;
      int status;
      time_t t1;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_abortreq");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "abortreq", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, r_token, CA_MAXDPMTOKENLEN+1)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid request token");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      sprintf (logbuf, "abortreq %s", r_token);
      dpm_logreq (func, logbuf);

      /* start transaction */

      (void) dpm_start_tr (thip->s, &thip->dbfd);

      if (dpm_get_pending_req_by_token (&thip->dbfd, r_token, &dpm_req, 1, &rec_addr) < 0 &&
          dpm_get_req_by_token (&thip->dbfd, r_token, &dpm_req, 1, &rec_addr) < 0) {
            if (serrno == ENOENT) {
                  status = DPM_FAILED | EINVAL;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "Unknown request token");
            } else {
                  status = DPM_FAILED | serrno;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "");
            }
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, status);
      }

      if (dpm_req.status == DPM_QUEUED || dpm_req.status == DPM_ACTIVE) {
            /* Move the request to the non-pending queue */

            if (dpm_delete_pending_entry (&thip->dbfd, &rec_addr) < 0)
                  RETURN (serrno);
            old_status = dpm_req.status;
            dpm_req.status = DPM_ABORTED;
            if (dpm_insert_xferreq_entry (&thip->dbfd, &dpm_req) < 0)
                  RETURN (serrno);
            if (old_status == DPM_QUEUED)
                  dec_reqctr ();
      } else {
            /* Update the request entry */

            dpm_req.status = DPM_ABORTED;
            if (dpm_update_xferreq_entry (&thip->dbfd, &rec_addr, &dpm_req) < 0)
                  RETURN (serrno);
      }
      (void) dpm_end_tr (&thip->dbfd);

      for (i = 0; i < dpm_req.nbreqfiles; i++) {
            (void) dpm_start_tr (thip->s, &thip->dbfd);
            switch (dpm_req.r_type) {
            case 'C':
                  if (dpm_get_cpr_by_fullid (&thip->dbfd, dpm_req.r_token,
                      i, &cpr_entry, 1, &rec_addrf) < 0) {
                        nb_file_err++;
                        (void) dpm_abort_tr (&thip->dbfd);
                        continue;
                  }
                  cpr_entry.status = DPM_ABORTED;
                  if (dpm_update_cpr_entry (&thip->dbfd, &rec_addrf, &cpr_entry) < 0) {
                        nb_file_err++;
                        (void) dpm_abort_tr (&thip->dbfd);
                        continue;
                  }
                  break;
            case 'B':
            case 'G':
                  if (dpm_get_gfr_by_fullid (&thip->dbfd, dpm_req.r_token,
                      i, &gfr_entry, 1, &rec_addrf) < 0) {
                        nb_file_err++;
                        (void) dpm_abort_tr (&thip->dbfd);
                        continue;
                  }
                  if ((gfr_entry.status & 0xF000) == DPM_TO_BE_RECALLED &&
                      dpm_abort_backend_filereq (&thip->dbfd, gfr_entry.status,
                      r_token, gfr_entry.from_surl)) {
                        nb_file_err++;
                        (void) dpm_abort_tr (&thip->dbfd);
                        continue;
                  }
                  gfr_entry.lifetime = 0;
                  gfr_entry.status = DPM_ABORTED;
                  if (dpm_update_gfr_entry (&thip->dbfd, &rec_addrf, &gfr_entry) < 0) {
                        nb_file_err++;
                        (void) dpm_abort_tr (&thip->dbfd);
                        continue;
                  }
                  pfn = gfr_entry.pfn;
                  break;
            case 'P':
                  if (dpm_get_pfr_by_fullid (&thip->dbfd, dpm_req.r_token,
                      i, &pfr_entry, 1, &rec_addrf) < 0) {
                        nb_file_err++;
                        (void) dpm_abort_tr (&thip->dbfd);
                        continue;
                  }
                  pfr_entry.lifetime = 0;
                  if (pfr_entry.status == DPM_READY || pfr_entry.status == DPM_RUNNING) {
                        reqsize = pfr_entry.requested_size;
                        file_created = pfr_entry.actual_size ? 1 : 0;
                  } else {
                        reqsize = 0;
                        file_created = 1;
                  }
                  old_status = pfr_entry.status;
                  pfr_entry.status = DPM_ABORTED;
                  if (dpm_update_pfr_entry (&thip->dbfd, &rec_addrf, &pfr_entry) < 0) {
                        nb_file_err++;
                        (void) dpm_abort_tr (&thip->dbfd);
                        continue;
                  }
                  pfn = pfr_entry.pfn;
                  break;
            }
            (void) dpm_end_tr (&thip->dbfd);

            if (dpm_req.r_type == 'P' && old_status != DPM_DONE) {
                  if (dpm_rm_onereplica (NULL, pfn, reqsize, &status,
                      &thip->dbfd, pfr_entry.s_token, file_created, -1) < 0)
                        nb_file_err++;
                  continue;
            }
            if (dpm_req.r_type == 'G' && *pfn) {
                  if (dpm_get_max_get_lifetime (&thip->dbfd, pfn, &t1) < 0)
                        t1 = 0;
                  if (Cns_setptime (pfn, t1) < 0)
                        nb_file_err++;
            }
      }

      /* Send global status/errmsg */

      status = nb_file_err ? DPM_FAILED|SEINTERNAL : DPM_SUCCESS;
      marshall_LONG (sbp, status);
      marshall_STRING (sbp, "");
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, status);
}

/*    dpm_srv_addfs - add a filesystem to a disk pool */

dpm_srv_addfs(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      struct dpm_fs fs_entry;
      char func[16];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      char logbuf[CA_MAXPOOLNAMELEN+CA_MAXHOSTNAMELEN+88];
      int nbgids;
      char *rbp;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_addfs");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "addfs", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      memset ((char *) &fs_entry, 0, sizeof(fs_entry));
      if (unmarshall_STRINGN (rbp, fs_entry.poolname, CA_MAXPOOLNAMELEN+1))
            RETURN (EINVAL);
      if (unmarshall_STRINGN (rbp, fs_entry.server, CA_MAXHOSTNAMELEN+1))
            RETURN (EINVAL);
      if (unmarshall_STRINGN (rbp, fs_entry.fs, 80))
            RETURN (EINVAL);
      unmarshall_LONG (rbp, fs_entry.status);
      sprintf (logbuf, "addfs %s %s %s", fs_entry.poolname, fs_entry.server,
          fs_entry.fs);
      dpm_logreq (func, logbuf);

      if (uid)
            RETURN (EACCES);

      if (strchr (fs_entry.server, ':') != NULL) {
            RETURN (EINVAL);
      }

      if (strchr (fs_entry.server, '.') == NULL) {
            if (strlen (fs_entry.server) + strlen (localdomain) + 1 > CA_MAXHOSTNAMELEN)
                  RETURN (EINVAL);
            strcat (fs_entry.server, ".");
            strcat (fs_entry.server, localdomain);
      }

      /* Update configuration in memory */

      if (dpm_addfs2poolconf (&fs_entry) < 0)
            RETURN (serrno);

      /* Update configuration in DB */

      (void) dpm_start_tr (thip->s, &thip->dbfd);
      if (dpm_insert_fs_entry (&thip->dbfd, &fs_entry))
            RETURN (serrno);
      RETURN (0);
}

/*    dpm_srv_addpool - add a disk pool */

dpm_srv_addpool(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      char func[16];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[CA_MAXPOOLNAMELEN+30];
      int nbgids;
      struct dpm_pool pool_entry;
      gid_t pool_gid;
      int put_retenp;
      char *rbp;
      char tmpbuf[21];
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_addpool");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "addpool", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      memset ((char *) &pool_entry, 0, sizeof(pool_entry));
      if (unmarshall_STRINGN (rbp, pool_entry.poolname, CA_MAXPOOLNAMELEN+1))
            RETURN (EINVAL);
      unmarshall_HYPER (rbp, pool_entry.defsize);
      unmarshall_LONG (rbp, pool_entry.gc_start_thresh);
      if (pool_entry.gc_start_thresh < 0 || pool_entry.gc_start_thresh > 100)
            RETURN (EINVAL);
      unmarshall_LONG (rbp, pool_entry.gc_stop_thresh);
      if (pool_entry.gc_stop_thresh < 0 || pool_entry.gc_stop_thresh > 100)
            RETURN (EINVAL);
      if (pool_entry.gc_start_thresh > pool_entry.gc_stop_thresh)
            RETURN (EINVAL);
      unmarshall_LONG (rbp, pool_entry.defpintime);
      if (magic < DPM_MAGIC2)
            unmarshall_LONG (rbp, put_retenp);
      if (unmarshall_STRINGN (rbp, pool_entry.fss_policy, CA_MAXPOLICYLEN+1))
            RETURN (EINVAL);
      if (unmarshall_STRINGN (rbp, pool_entry.gc_policy, CA_MAXPOLICYLEN+1))
            RETURN (EINVAL);
      if (unmarshall_STRINGN (rbp, pool_entry.rs_policy, CA_MAXPOLICYLEN+1))
            RETURN (EINVAL);
      unmarshall_LONG (rbp, pool_gid);
      unmarshall_BYTE (rbp, pool_entry.s_type);
      if (magic >= DPM_MAGIC2) {
            if (unmarshall_STRINGN (rbp, pool_entry.mig_policy, CA_MAXPOLICYLEN+1))
                  RETURN (EINVAL);
            unmarshall_BYTE (rbp, pool_entry.ret_policy);
            unmarshall_LONG (rbp, pool_entry.def_lifetime);
            unmarshall_LONG (rbp, pool_entry.max_lifetime);
            unmarshall_LONG (rbp, pool_entry.maxpintime);
      }
      if (magic >= DPM_MAGIC3) {
            unmarshall_LONG (rbp, pool_entry.nbgids);
            if (! pool_entry.nbgids) {
                  pool_entry.nbgids = 1;
                  if ((pool_entry.gids = malloc (sizeof(gid_t))) == NULL)
                        RETURN (ENOMEM);
                  pool_entry.gids[0] = pool_gid;
            } else {
                  if ((pool_entry.gids = malloc (pool_entry.nbgids * sizeof(gid_t))) == NULL)
                        RETURN (ENOMEM);
                  for (i = 0; i < pool_entry.nbgids; i++)
                        unmarshall_LONG (rbp, pool_entry.gids[i]);
                  if (pool_entry.nbgids > 1) {
                        for (i = 0; i < pool_entry.nbgids; i++)
                              if (pool_entry.gids[i] == 0) {
                                    sendrep (thip->s, MSG_ERR,
                                        "Pool must be either generic or dedicated\n");
                                    free (pool_entry.gids);
                                    RETURN (EINVAL);
                              }
                  }
            }
      } else {
            pool_entry.nbgids = 1;
            if ((pool_entry.gids = malloc (sizeof(gid_t))) == NULL)
                  RETURN (ENOMEM);
            pool_entry.gids[0] = pool_gid;
      }
      sprintf (logbuf, "addpool %s %s", pool_entry.poolname,
          u64tostr(pool_entry.defsize, tmpbuf, 0));
      dpm_logreq (func, logbuf);

      if (uid) {
            free (pool_entry.gids);
            RETURN (EACCES);
      }

      if (! pool_entry.def_lifetime)
            pool_entry.def_lifetime = DEFAULT_LIFETIME;
      if (! pool_entry.defpintime)
            pool_entry.defpintime = DEFAULT_PINTIME;
      if (! pool_entry.max_lifetime)
            pool_entry.max_lifetime = MAX_LIFETIME;
      if (! pool_entry.maxpintime)
            pool_entry.maxpintime = MAX_PINTIME;
      if (! *pool_entry.fss_policy)
            strcpy (pool_entry.fss_policy, DEFAULT_FSS_POLICY);
      if (! *pool_entry.gc_policy)
            strcpy (pool_entry.gc_policy, DEFAULT_GC_POLICY);
      if (! *pool_entry.mig_policy)
            strcpy (pool_entry.mig_policy, DEFAULT_MIG_POLICY);
      if (! pool_entry.ret_policy)
            pool_entry.ret_policy = 'R';
      if (! *pool_entry.rs_policy)
            strcpy (pool_entry.rs_policy, DEFAULT_RS_POLICY);
      if (! pool_entry.s_type)
            pool_entry.s_type = '-';
      else if (pool_entry.s_type != 'V' && pool_entry.s_type != 'D' &&
          pool_entry.s_type != 'P' && pool_entry.s_type != '-') {
            sendrep (thip->s, MSG_ERR, "Invalid type of space\n");
            free (pool_entry.gids);
            RETURN (EINVAL);
      }

      /* Update configuration in memory */

      if (dpm_addpool2poolconf (&pool_entry) < 0) {
            free (pool_entry.gids);
            RETURN (serrno);
      }

      /* Update configuration in DB */

      (void) dpm_start_tr (thip->s, &thip->dbfd);
      if (dpm_insert_pool_entry (&thip->dbfd, &pool_entry))
            RETURN (serrno);
      RETURN (0);
}

/*    dpm_srv_copy - copy a set of existing files */

dpm_srv_copy(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      char *deleg_cred;
      size_t deleg_cred_len;
      struct dpm_req dpm_req;
      char func[16];
      struct dpm_copy_filereq cpr_entry;
      int fd;
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[2*CA_MAXSFNLEN+18];
      int n;
      int nb_file_err = 0;
      int nbgids;
      int nbreqfiles;
      char proxy_filename[sizeof(P_tmpdir)+CA_MAXDPMTOKENLEN+4];
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp;
      uid_t uid;
      u_signed64 unique_id;
      char *user;
      uuid_t uuid;

      strcpy (func, "dpm_srv_copy");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "copy", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
#if 0
      RETURN (SEOPNOTSUP);
#else
      memset ((char *) &dpm_req, 0, sizeof(dpm_req));
      dpm_req.r_uid = uid;
      dpm_req.r_gid = gid;
      strcpy (dpm_req.client_dn, user);
      strcpy (dpm_req.groups, groups);
      strcpy (dpm_req.clienthost, clienthost);
      dpm_req.r_type = 'C';

      if (unmarshall_STRINGN (rbp, dpm_req.u_token, 256)) {
            dpm_req.status = DPM_FAILED | EINVAL;
            strcpy (dpm_req.errstring, "Invalid user request description");
      }
      unmarshall_LONG (rbp, dpm_req.flags);     /* overwrite/remove src options */
      unmarshall_TIME_T (rbp, dpm_req.retrytime);

      /* start transaction */

      (void) dpm_start_tr (thip->s, &thip->dbfd);

      if (dpm_unique_id (&thip->dbfd, &unique_id) < 0)
            RETURN (SEINTERNAL);
      dpm_req.r_ordinal = unique_id & 0xFFFFFFFF;

      uuid_generate (uuid);
      uuid_unparse (uuid, dpm_req.r_token);
      sprintf (logbuf, "copy %d %s", dpm_req.r_ordinal, dpm_req.r_token);
      dpm_logreq (func, logbuf);

      dpm_req.ctime = time (0);
      unmarshall_LONG (rbp, nbreqfiles);
      if (nbreqfiles <= 0) {
            nbreqfiles = 0;
            dpm_req.status = DPM_FAILED | EINVAL;
            strcpy (dpm_req.errstring, "Number of surls <= 0");
      } else if (! dpm_req.status)
            dpm_req.status = DPM_QUEUED;

      sbp = repbuf;
      marshall_LONG (sbp, nbreqfiles);
      dpm_req.nbreqfiles = nbreqfiles;

      /* Get and check the individual file requests */

      for (i = 0; i < nbreqfiles; i++) {
            memset (&cpr_entry, 0, sizeof(cpr_entry));
            strcpy (cpr_entry.r_token, dpm_req.r_token);
            cpr_entry.f_ordinal = i;
            cpr_entry.status = DPM_QUEUED;
            if (unmarshall_STRINGN (rbp, cpr_entry.from_surl, CA_MAXSFNLEN+1)) {
                  cpr_entry.status = DPM_FAILED | SENAMETOOLONG;
            }
            if (unmarshall_STRINGN (rbp, cpr_entry.to_surl, CA_MAXSFNLEN+1)) {
                  cpr_entry.status = DPM_FAILED | SENAMETOOLONG;
            }
            unmarshall_TIME_T (rbp, cpr_entry.f_lifetime);
            if (cpr_entry.f_lifetime < 0) {
                  cpr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (cpr_entry.errstring, "Negative value for f_lifetime");
            }
            unmarshall_BYTE (rbp, cpr_entry.f_type);
            if (cpr_entry.f_type == '\0')
                  cpr_entry.f_type = '_';
            else if (cpr_entry.f_type != 'V' && cpr_entry.f_type != 'D' &&
                cpr_entry.f_type != 'P') {
                  cpr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (cpr_entry.errstring, "Invalid file storage type");
            }
            if (unmarshall_STRINGN (rbp, cpr_entry.s_token, CA_MAXDPMTOKENLEN+1)) {
                  cpr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (cpr_entry.errstring, "Invalid space token");
            }
            unmarshall_LONG (rbp, cpr_entry.flags);
            if (magic >= DPM_MAGIC2) {
                  unmarshall_BYTE (rbp, cpr_entry.ret_policy);
                  unmarshall_BYTE (rbp, cpr_entry.ac_latency);
            }
            if (cpr_entry.ret_policy == '\0')
                  cpr_entry.ret_policy = '_';
            else if (cpr_entry.ret_policy != 'R' && cpr_entry.ret_policy != 'O' &&
                cpr_entry.ret_policy != 'C') {
                  cpr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (cpr_entry.errstring, "Invalid retention policy");
            }
            if (cpr_entry.ac_latency == '\0')
                  cpr_entry.ac_latency = '_';
            else if (cpr_entry.ac_latency != 'O' && cpr_entry.ac_latency != 'N') {
                  cpr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (cpr_entry.errstring, "Invalid access latency");
            }
            sprintf (logbuf, "copy %d %s %s", i, cpr_entry.from_surl,
                cpr_entry.to_surl);
            dpm_logreq (func, logbuf);
            if (cpr_entry.status != DPM_QUEUED) {
                  nb_file_err++;
                  if (*cpr_entry.errstring)
                        dpmlogit (func, "file %d: %s\n", i, cpr_entry.errstring);
            }

            if (dpm_insert_cpr_entry (&thip->dbfd, &cpr_entry) < 0)
                  RETURN (SEINTERNAL);

            n = marshall_CPR (NULL, &cpr_entry);      /* get length of marshalled entry */
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_COPY, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_CPR (&sbp, &cpr_entry);
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_COPY, sbp - repbuf, repbuf);

      if (dpm_req.status == DPM_QUEUED && nb_file_err == nbreqfiles) {
            dpm_req.status = DPM_FAILED | EINVAL;
            strcpy (dpm_req.errstring, "Failed for all SURLs");
      }

#ifdef CSEC
      if (dpm_req.status == DPM_QUEUED) {
            if (Csec_server_getDelegatedCredentials (&thip->sec_ctx, NULL,
                (void **) &deleg_cred, &deleg_cred_len) < 0) {
                  dpm_req.status = DPM_FAILED | EINVAL;
                  strcpy (dpm_req.errstring, "No delegated credential available");
            } else {
                  (void) build_proxy_filename (proxy_filename, dpm_req.r_token);
                  if ((fd = open (proxy_filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0 || 
                      write (fd, deleg_cred, deleg_cred_len) != deleg_cred_len ||
                      close (fd) < 0) {
                        dpm_req.status = DPM_FAILED | EINVAL;
                        strcpy (dpm_req.errstring, "Could not export credentials");
                  }
            }
      }
#endif
      if (dpm_req.status == DPM_QUEUED) {
            dpm_req.status = DPM_QUEUED4COPY;
            if (dpm_insert_pending_entry (&thip->dbfd, &dpm_req) < 0)
                  RETURN (SEINTERNAL);
            dpm_end_tr (&thip->dbfd);
            dpmcopy_inc_reqctr ();
      } else {
            if (dpm_insert_xferreq_entry (&thip->dbfd, &dpm_req) < 0)
                  RETURN (SEINTERNAL);
      }

      /* Send global status/errmsg/token */

      sbp = repbuf;
      marshall_LONG (sbp, dpm_req.status);
      marshall_STRING (sbp, dpm_req.errstring);
      marshall_STRING (sbp, dpm_req.r_token);
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, dpm_req.status);
#endif
}

/*    dpm_srv_delreplica - delete a given replica */

dpm_srv_delreplica(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      int c;
      int check_ns = 1;
      char func[19];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[CA_MAXSFNLEN+12];
      int nbgids;
      int nbreplicas = 0;
      char pfn[CA_MAXSFNLEN+1];
      struct dpm_put_filereq pfr_entry;
      char *rbp;
      dpm_dbrec_addr rec_addr;
      struct Cns_filereplicax *rep_entries = NULL;
      u_signed64 reqsize;
      char sfn[CA_MAXSFNLEN+1];
      struct Cns_filestatg statbuf;
      int status = 0;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_delreplica");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "delreplica", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, pfn, CA_MAXSFNLEN+1) < 0)
            RETURN (SENAMETOOLONG);
      sprintf (logbuf, "delreplica %s", pfn);
      dpm_logreq (func, logbuf);

      if (Cns_setrstatus (pfn, 'D') < 0)
            RETURN (serrno);
      reqsize = 0;
      (void) dpm_start_tr (thip->s, &thip->dbfd);
      if ((c = dpm_get_pfr_by_pfn (&thip->dbfd, pfn, &pfr_entry,
          1, &rec_addr)) == 0 &&
          (pfr_entry.status == DPM_READY || pfr_entry.status == DPM_RUNNING)) {
            pfr_entry.status = DPM_ABORTED;
            if (pfr_entry.actual_size == 0)
                  check_ns = 0;
            dpm_update_pfr_entry (&thip->dbfd, &rec_addr, &pfr_entry);
            reqsize = pfr_entry.requested_size;
      }
      dpm_end_tr (&thip->dbfd);
      if (c < 0) {
            if (Cns_statr (pfn, &statbuf) < 0)
                  RETURN (serrno);
            if (Cns_getpath (NULL, statbuf.fileid, sfn) < 0)
                  RETURN (serrno);
            if (Cns_getreplicax (sfn, NULL, NULL, &nbreplicas, &rep_entries) < 0)
                  RETURN (serrno);
            for (i = 0; i < nbreplicas; i++) {
                  if (strcmp ((rep_entries + i)->sfn, pfn) == 0) break;
            }
            if (i >= nbreplicas) {
                  free (rep_entries);
                  RETURN (ENOENT);
            }
            dpm_rm_onereplica (NULL, pfn, reqsize, &status, &thip->dbfd,
                (rep_entries + i)->setname, check_ns, statbuf.filesize);
            free (rep_entries);
      } else
            dpm_rm_onereplica (NULL, pfn, reqsize, &status, &thip->dbfd,
                pfr_entry.s_token, check_ns, -1);
      RETURN (status & 0xFFF);
}

/*    dpm_srv_extendfilelife - extend file lifetime */

dpm_srv_extendfilelife(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      struct dpm_copy_filereq cpr_entry;
      time_t current_time;
      struct dpm_req dpm_req;
      struct dpm_space_reserv dpm_spcmd;
      char func[23];
      struct dpm_get_filereq gfr_entry;
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      time_t lifetime;
      char logbuf[CA_MAXDPMTOKENLEN+CA_MAXSFNLEN+17];
      int max_lifetime;
      int maxpintime;
      int nbgids;
      int nbreplicas = 0;
      struct dpm_put_filereq pfr_entry;
      char r_token[CA_MAXDPMTOKENLEN+1];
      char *rbp;
      dpm_dbrec_addr rec_addr;
      struct Cns_filereplicax *rep_entries = NULL;
      char repbuf[268];
      char *sbp = repbuf;
      char *sfn;
      int status;
      char surl[CA_MAXSFNLEN+1];
      time_t t1;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_extendfilelife");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "extendfilelife", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, r_token, CA_MAXDPMTOKENLEN+1)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid request token");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      if (unmarshall_STRINGN (rbp, surl, CA_MAXSFNLEN+1)) {
            marshall_LONG (sbp, DPM_FAILED | SENAMETOOLONG);
            marshall_STRING (sbp, "");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | SENAMETOOLONG);
      }
      unmarshall_TIME_T (rbp, lifetime);
      if (lifetime < 0) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Negative value for lifetime");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      sprintf (logbuf, "extendfilelife %s %s", r_token, surl);
      dpm_logreq (func, logbuf);

      if (! *r_token) { /* extend SURL lifetime */
            /* must find primary replica */
            if (strncmp (surl, "srm://", 6) == 0) {
                  if ((sfn = sfnfromsurl (surl)) == NULL) {
                        marshall_LONG (sbp, DPM_FAILED | EINVAL);
                        marshall_STRING (sbp, "Bad SURL syntax");
                        sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                        RETURNS (0, DPM_FAILED | EINVAL);
                  }
            } else
                  sfn = surl;
            if (Cns_getreplicax (sfn, NULL, NULL, &nbreplicas, &rep_entries) < 0) {
                  marshall_LONG (sbp, DPM_FAILED | serrno);
                  marshall_STRING (sbp, "");
                  sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                  free (rep_entries);
                  RETURNS (0, DPM_FAILED | serrno);
            }
            for (i = 0; i < nbreplicas; i++) {
                  if ((rep_entries + i)->r_type == 'P') break;
            }
            if (i >= nbreplicas) {
                  marshall_LONG (sbp, DPM_FAILED | ENOENT);
                  marshall_STRING (sbp, "");
                  sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                  free (rep_entries);
                  RETURNS (0, DPM_FAILED | ENOENT);
            }
            if ((rep_entries + i)->f_type == 'P') {
                  free (rep_entries);
                  sbp = repbuf;
                  marshall_LONG (sbp, DPM_SUCCESS);
                  marshall_STRING (sbp, "");
                  marshall_TIME_T (sbp, 0x7FFFFFFF);
                  sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                  RETURNS (0, DPM_SUCCESS);
            }

            /* must check if primary replica is in a space to compute
               maximum lifetime */

            current_time = time (0);
            if (lifetime == 0)
                  lifetime = dpm_get_def_lifetime ((rep_entries + i)->sfn, NULL);
            if (lifetime != 0x7FFFFFFF)
                  lifetime += current_time;
            if (* (rep_entries + i)->setname &&
                dpm_get_spcmd_by_token (&thip->dbfd, (rep_entries + i)->setname,
                &dpm_spcmd, 0, NULL) == 0)
                  max_lifetime = dpm_spcmd.expire_time;
            else {
                  max_lifetime = dpm_get_max_lifetime ((rep_entries + i)->sfn);
                  if (max_lifetime != 0x7FFFFFFF)
                        max_lifetime += current_time;
            }
            if (lifetime > max_lifetime)
                  lifetime = max_lifetime;
            free (rep_entries);

            if (Cns_setrltime ((rep_entries + i)->sfn, lifetime) < 0)
                  RETURN (serrno);
            if (lifetime != 0x7FFFFFFF)
                  lifetime -= current_time;
            sbp = repbuf;
            marshall_LONG (sbp, DPM_SUCCESS);
            marshall_STRING (sbp, "");
            marshall_TIME_T (sbp, lifetime);
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_SUCCESS);
      }

      /* start transaction */

      (void) dpm_start_tr (thip->s, &thip->dbfd);

      if (dpm_get_pending_req_by_token (&thip->dbfd, r_token, &dpm_req, 0, NULL) < 0 &&
          dpm_get_req_by_token (&thip->dbfd, r_token, &dpm_req, 0, NULL) < 0) {
            if (serrno == ENOENT) {
                  status = DPM_FAILED | EINVAL;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "Unknown request token");
            } else {
                  status = DPM_FAILED | serrno;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "");
            }
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, status);
      }
      switch (dpm_req.r_type) {
      case 'C':
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Cannot extend TURL lifetime for a copy");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      case 'B':
      case 'G':
            if (dpm_get_gfr_by_surl (&thip->dbfd, r_token, surl, &gfr_entry,
                1, &rec_addr) < 0)
                  RETURN (serrno);
            if (gfr_entry.status == DPM_RELEASED || gfr_entry.status == DPM_ABORTED) {
                  marshall_LONG (sbp, gfr_entry.status);
                  marshall_STRING (sbp, "");
                  sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                  RETURNS (0, gfr_entry.status);
            }
            current_time = time (0);
            if ((gfr_entry.status == DPM_READY || gfr_entry.status == DPM_RUNNING) &&
                gfr_entry.lifetime < current_time) {
                  marshall_LONG (sbp, DPM_FAILED | EINVAL);
                  marshall_STRING (sbp, "Cannot extend TURL lifetime if already expired");
                  sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                  RETURNS (0, DPM_FAILED | EINVAL);
            }
            if (lifetime == 0)
                  lifetime = dpm_get_defpintime (gfr_entry.pfn);
            if (lifetime != 0x7FFFFFFF)
                  lifetime += current_time;
            maxpintime = dpm_get_maxpintime (gfr_entry.pfn);
            if (maxpintime != 0x7FFFFFFF)
                  maxpintime += current_time;
            if (lifetime > maxpintime)
                  lifetime = maxpintime;
            gfr_entry.lifetime = lifetime;
            if ((gfr_entry.status != DPM_READY && gfr_entry.status != DPM_RUNNING) &&
                gfr_entry.lifetime != 0x7FFFFFFF)
                  gfr_entry.lifetime -= current_time;
            if (dpm_update_gfr_entry (&thip->dbfd, &rec_addr, &gfr_entry) < 0)
                  RETURN (serrno);
            break;
      case 'P':
            if (dpm_get_pfr_by_surl (&thip->dbfd, r_token, surl, &pfr_entry,
                1, &rec_addr) < 0)
                  RETURN (serrno);
            if (pfr_entry.status == DPM_RELEASED || pfr_entry.status == DPM_ABORTED) {
                  marshall_LONG (sbp, pfr_entry.status);
                  marshall_STRING (sbp, "");
                  sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                  RETURNS (0, pfr_entry.status);
            }
            if (pfr_entry.status == DPM_DONE) {
                  marshall_LONG (sbp, DPM_FAILED | EINVAL);
                  marshall_STRING (sbp, "Cannot extend TURL lifetime after putdone");
                  sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                  RETURNS (0, DPM_FAILED | EINVAL);
            }
            current_time = time (0);
            if ((pfr_entry.status == DPM_READY || pfr_entry.status == DPM_RUNNING) &&
                pfr_entry.lifetime < current_time) {
                  marshall_LONG (sbp, DPM_FAILED | EINVAL);
                  marshall_STRING (sbp, "Cannot extend TURL lifetime if already expired");
                  sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                  RETURNS (0, DPM_FAILED | EINVAL);
            }
            if (lifetime == 0)
                  lifetime = dpm_get_defpintime (pfr_entry.pfn);
            if (lifetime != 0x7FFFFFFF)
                  lifetime += current_time;
            if (* pfr_entry.s_token &&
                dpm_get_spcmd_by_token (&thip->dbfd, pfr_entry.s_token,
                &dpm_spcmd, 0, NULL) == 0)
                  maxpintime = dpm_spcmd.expire_time;
            else {
                  maxpintime = dpm_get_maxpintime (pfr_entry.pfn);
                  if (maxpintime != 0x7FFFFFFF)
                        maxpintime += current_time;
            }
            if (lifetime > maxpintime)
                  lifetime = maxpintime;
            pfr_entry.lifetime = lifetime;
            if ((pfr_entry.status != DPM_READY && pfr_entry.status != DPM_RUNNING) &&
                pfr_entry.lifetime != 0x7FFFFFFF)
                  pfr_entry.lifetime -= current_time;
            if (dpm_update_pfr_entry (&thip->dbfd, &rec_addr, &pfr_entry) < 0)
                  RETURN (serrno);
            break;
      }
      if (dpm_req.r_type == 'G') {
            if (dpm_get_max_get_lifetime (&thip->dbfd, gfr_entry.pfn, &t1) < 0)
                  t1 = 0;
            if (Cns_setptime (gfr_entry.pfn, t1) < 0)
                  RETURN (serrno);
      }
      if (lifetime != 0x7FFFFFFF)
            lifetime -= current_time;
      sbp = repbuf;
      marshall_LONG (sbp, DPM_SUCCESS);
      marshall_STRING (sbp, "");
      marshall_TIME_T (sbp, lifetime);
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, DPM_SUCCESS);
}

/*    dpm_srv_get - make a set of existing files available for I/O */

dpm_srv_get(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      struct dpm_req dpm_req;
      char func[16];
      struct dpm_get_filereq gfr_entry;
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      int j;
      char logbuf[CA_MAXSFNLEN+16];
      int n;
      int nb_file_err = 0;
      int nbgids;
      int nbprotocols;
      int nbreqfiles;
      char protocol[CA_MAXPROTOLEN+1];
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp;
      char selected_protocol[CA_MAXPROTOLEN+1];
      uid_t uid;
      u_signed64 unique_id;
      char *user;
      uuid_t uuid;

      strcpy (func, "dpm_srv_get");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "get", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      memset ((char *) &dpm_req, 0, sizeof(dpm_req));
      dpm_req.r_uid = uid;
      dpm_req.r_gid = gid;
      strcpy (dpm_req.client_dn, user);
      strcpy (dpm_req.groups, groups);
      strcpy (dpm_req.clienthost, clienthost);
      unmarshall_LONG (rbp, nbprotocols);
      dpm_req.r_type = 'G';

      /* Negociate protocol */

      *selected_protocol = '\0';
      for (i = 0; i < nbprotocols; i++) {
            if (unmarshall_STRINGN (rbp, protocol, CA_MAXPROTOLEN+1))
                  continue;
            if (*selected_protocol) continue;
            for (j = 0; j < nb_supported_protocols; j++) {
                  if (strcmp (protocol, supported_protocols[j]) == 0) {
                        strcpy (selected_protocol, protocol);
                        break;
                  }
            }
      }
      if (! *selected_protocol) {
            dpm_req.status = DPM_FAILED | SEPROTONOTSUP;
      }
      if (unmarshall_STRINGN (rbp, dpm_req.u_token, 256)) {
            dpm_req.status = DPM_FAILED | EINVAL;
            strcpy (dpm_req.errstring, "Invalid user request description");
      }
      unmarshall_TIME_T (rbp, dpm_req.retrytime);

      /* start transaction */

      (void) dpm_start_tr (thip->s, &thip->dbfd);

      if (dpm_unique_id (&thip->dbfd, &unique_id) < 0)
            RETURN (SEINTERNAL);
      dpm_req.r_ordinal = unique_id & 0xFFFFFFFF;

      uuid_generate (uuid);
      uuid_unparse (uuid, dpm_req.r_token);
      sprintf (logbuf, "get %d %s", dpm_req.r_ordinal, dpm_req.r_token);
      dpm_logreq (func, logbuf);

      dpm_req.ctime = time (0);
      unmarshall_LONG (rbp, nbreqfiles);
      if (nbreqfiles <= 0) {
            nbreqfiles = 0;
            dpm_req.status = DPM_FAILED | EINVAL;
            strcpy (dpm_req.errstring, "Number of surls <= 0");
      } else if (! dpm_req.status)
            dpm_req.status = DPM_QUEUED;

      sbp = repbuf;
      marshall_LONG (sbp, nbreqfiles);
      dpm_req.nbreqfiles = nbreqfiles;

      /* Get and check the individual file requests */

      for (i = 0; i < nbreqfiles; i++) {
            memset (&gfr_entry, 0, sizeof(gfr_entry));
            strcpy (gfr_entry.r_token, dpm_req.r_token);
            gfr_entry.f_ordinal = i;
            gfr_entry.r_uid = uid;
            gfr_entry.status = DPM_QUEUED;
            if (unmarshall_STRINGN (rbp, gfr_entry.from_surl, CA_MAXSFNLEN+1)) {
                  gfr_entry.status = DPM_FAILED | SENAMETOOLONG;
            }
            unmarshall_TIME_T (rbp, gfr_entry.lifetime);
            if (gfr_entry.lifetime < 0) {
                  gfr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (gfr_entry.errstring, "Negative value for lifetime");
            }
            unmarshall_BYTE (rbp, gfr_entry.f_type);
            if (gfr_entry.f_type == '\0')
                  gfr_entry.f_type = DEFAULT_SPACE_TYPE;
            else if (gfr_entry.f_type != 'V' && gfr_entry.f_type != 'D' &&
                gfr_entry.f_type != 'P') {
                  gfr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (gfr_entry.errstring, "Invalid file storage type");
            }
            if (unmarshall_STRINGN (rbp, gfr_entry.s_token, CA_MAXDPMTOKENLEN+1)) {
                  gfr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (gfr_entry.errstring, "Invalid space token");
            }
            unmarshall_LONG (rbp, gfr_entry.flags);
            if (magic >= DPM_MAGIC2) {
                  unmarshall_BYTE (rbp, gfr_entry.ret_policy);
            }
            if (gfr_entry.ret_policy == '\0')
                  gfr_entry.ret_policy = '_';
            else if (gfr_entry.ret_policy != 'R' && gfr_entry.ret_policy != 'O' &&
                gfr_entry.ret_policy != 'C') {
                  gfr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (gfr_entry.errstring, "Invalid retention policy");
            }
            strcpy (gfr_entry.protocol, selected_protocol);
            sprintf (logbuf, "get %d %s", i, gfr_entry.from_surl);
            dpm_logreq (func, logbuf);
            if (gfr_entry.status != DPM_QUEUED) {
                  nb_file_err++;
                  if (*gfr_entry.errstring)
                        dpmlogit (func, "file %d: %s\n", i, gfr_entry.errstring);
            }

            if (dpm_insert_gfr_entry (&thip->dbfd, &gfr_entry) < 0)
                  RETURN (SEINTERNAL);

            /* get length of marshalled entry */
            n = marshall_GFR (NULL, &gfr_entry);
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_GET, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_GFR (&sbp, &gfr_entry);
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_GET, sbp - repbuf, repbuf);

      if (dpm_req.status == DPM_QUEUED && nb_file_err == nbreqfiles) {
            dpm_req.status = DPM_FAILED | EINVAL;
            strcpy (dpm_req.errstring, "Failed for all SURLs");
      }

      if (dpm_req.status == DPM_QUEUED) {
            if (dpm_insert_pending_entry (&thip->dbfd, &dpm_req) < 0)
                  RETURN (SEINTERNAL);
            dpm_end_tr (&thip->dbfd);
            inc_reqctr ();
      } else {
            if (dpm_insert_xferreq_entry (&thip->dbfd, &dpm_req) < 0)
                  RETURN (SEINTERNAL);
      }

      /* Send global status/errmsg/token */

      sbp = repbuf;
      marshall_LONG (sbp, dpm_req.status);
      marshall_STRING (sbp, dpm_req.errstring);
      marshall_STRING (sbp, dpm_req.r_token);
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, dpm_req.status);
}

/*    dpm_srv_getpoolfs - get list of filesystems for a given pool */

dpm_srv_getpoolfs(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      int c;
      struct dpm_fs *elemp;
      char func[18];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      int n;
      int nbfs;
      int nbgids;
      char poolname[CA_MAXPOOLNAMELEN+1];
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_getpoolfs");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "getpoolfs", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, poolname, CA_MAXPOOLNAMELEN+1))
            RETURN (EINVAL);

      if ((nbfs = dpm_getfsfrompoolconf (poolname, &elemp)) < 0)
            RETURN (serrno);
      sbp = repbuf;
      marshall_LONG (sbp, nbfs);
      for (i = 0 ; i < nbfs; i++ ) {
            n = strlen ((elemp + i)->poolname) + 1;
            n += strlen ((elemp + i)->server) + 1;
            n += strlen ((elemp + i)->fs) + 1;
            n += HYPERSIZE;
            n += HYPERSIZE;
            n += LONGSIZE;
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_FS, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_STRING (sbp, (elemp + i)->poolname);
            marshall_STRING (sbp, (elemp + i)->server);
            marshall_STRING (sbp, (elemp + i)->fs);
            marshall_HYPER (sbp, (elemp + i)->capacity);
            marshall_HYPER (sbp, (elemp + i)->free);
            marshall_LONG (sbp, (elemp + i)->status);
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_FS, sbp - repbuf, repbuf);
      if (nbfs)
            free (elemp);
      RETURN (0);
}

/*    dpm_srv_getpools - get list of pools */

dpm_srv_getpools(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      int c;
      char func[17];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      int j;
      int n;
      int nbgids;
      int nbpools;
      struct dpm_pool *poolp;
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_getpools");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "getpools", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);

      if ((nbpools = dpm_getpoolsfrompoolconf (&poolp)) < 0)
            RETURN (serrno);
      sbp = repbuf;
      marshall_LONG (sbp, nbpools);
      for (i = 0; i < nbpools; i++) {
            n = strlen ((poolp + i)->poolname) + 1;
            n += HYPERSIZE;
            n += LONGSIZE;
            n += LONGSIZE;
            n += LONGSIZE;
            if (magic < DPM_MAGIC2)
                  n += LONGSIZE;
            n += strlen ((poolp + i)->fss_policy) + 1;
            n += strlen ((poolp + i)->gc_policy) + 1;
            n += strlen ((poolp + i)->rs_policy) + 1;
            if (magic < DPM_MAGIC3)
                  n += LONGSIZE;
            n++;
            n += HYPERSIZE;
            n += HYPERSIZE;
            n += LONGSIZE;
            if (magic >= DPM_MAGIC2) {
                  n += strlen ((poolp + i)->mig_policy) + 1;
                  n++;
                  n += LONGSIZE;
                  n += LONGSIZE;
                  n += LONGSIZE;
            }
            if (magic >= DPM_MAGIC3) {
                  n += LONGSIZE;
                  n += (poolp + i)->nbgids * LONGSIZE;
            }
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_POOL, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_STRING (sbp, (poolp + i)->poolname);
            marshall_HYPER (sbp, (poolp + i)->defsize);
            marshall_LONG (sbp, (poolp + i)->gc_start_thresh);
            marshall_LONG (sbp, (poolp + i)->gc_stop_thresh);
            marshall_LONG (sbp, (poolp + i)->defpintime);
            if (magic < DPM_MAGIC2)
                  marshall_LONG (sbp, (poolp + i)->defpintime);
            marshall_STRING (sbp, (poolp + i)->fss_policy);
            marshall_STRING (sbp, (poolp + i)->gc_policy);
            marshall_STRING (sbp, (poolp + i)->rs_policy);
            if (magic < DPM_MAGIC3)
                  marshall_LONG (sbp, (poolp + i)->gids[0]);
            marshall_BYTE (sbp, (poolp + i)->s_type);
            marshall_HYPER (sbp, (poolp + i)->capacity);
            marshall_HYPER (sbp, (poolp + i)->free);
            marshall_LONG (sbp, (poolp + i)->nbelem);
            if (magic >= DPM_MAGIC2) {
                  marshall_STRING (sbp, (poolp + i)->mig_policy);
                  marshall_BYTE (sbp, (poolp + i)->ret_policy);
                  marshall_LONG (sbp, (poolp + i)->def_lifetime);
                  marshall_LONG (sbp, (poolp + i)->max_lifetime);
                  marshall_LONG (sbp, (poolp + i)->maxpintime);
            }
            if (magic >= DPM_MAGIC3) {
                  marshall_LONG (sbp, (poolp + i)->nbgids);
                  for (j = 0; j < (poolp + i)->nbgids; j++)
                        marshall_LONG (sbp, (poolp + i)->gids[j]);
            }
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_POOL, sbp - repbuf, repbuf);
      if (nbpools)
            free (poolp);
      RETURN (0);
}

/*    dpm_srv_getprotocols - get the list of supported protocols */

dpm_srv_getprotocols(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      char func[21];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      int nbgids;
      char *rbp;
      char repbuf[256];
      char *sbp;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_getprotocols");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "getprotocols", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);

      sbp = repbuf;
      marshall_WORD (sbp, nb_supported_protocols);
      for (i = 0; i < nb_supported_protocols; i++) {
            marshall_STRING (sbp, supported_protocols[i]);
      }
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURN (0);
}

/*    dpm_srv_getreqid - get request id for a set of requests */

dpm_srv_getreqid(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      int bol = 1;
      int c;
      DBLISTPTR dblistptr;
      struct dpm_req dpm_req;
      char func[17];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[265];
      int n;
      int nbgids;
      int nbreplies = 0;
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp = repbuf;
      char u_token[256];
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_getreqid");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "getreqid", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);

      if (unmarshall_STRINGN (rbp, u_token, 256)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid user request description");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      sprintf (logbuf, "getreqid %s", u_token);
      dpm_logreq (func, logbuf);

      while ((c = dpm_get_pending_reqs_by_u_desc (&thip->dbfd, bol, u_token,
          uid, &dpm_req, 0, &dblistptr)) == 0) {
            bol = 0;
            n = strlen (dpm_req.r_token) + TIME_TSIZE + 1;
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_REQIDS, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_STRING (sbp, dpm_req.r_token);
            marshall_TIME_T (sbp, dpm_req.ctime);
            nbreplies++;
      }
      (void) dpm_get_pending_reqs_by_u_desc (&thip->dbfd, bol, u_token,
           uid, &dpm_req, 1, &dblistptr); /* free res */
      if (c < 0)
            RETURN (serrno);
      bol = 1;
      while ((c = dpm_get_reqs_by_u_desc (&thip->dbfd, bol, u_token, uid,
          &dpm_req, 0, &dblistptr)) == 0) {
            bol = 0;
            n = strlen (dpm_req.r_token) + TIME_TSIZE + 1;
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_REQIDS, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_STRING (sbp, dpm_req.r_token);
            marshall_TIME_T (sbp, dpm_req.ctime);
            nbreplies++;
      }
      (void) dpm_get_reqs_by_u_desc (&thip->dbfd, bol, u_token, uid,
          &dpm_req, 1, &dblistptr); /* free res */
      if (c < 0)
            RETURN (serrno);
      if (nbreplies == 0) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Unknown user request description");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_REQIDS, sbp - repbuf, repbuf);

      /* Send global status/errmsg */

      sbp = repbuf;
      marshall_LONG (sbp, DPM_SUCCESS);
      marshall_STRING (sbp, "");
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, DPM_SUCCESS);
}

/*    dpm_srv_getreqsummary - get summary for a set of requests */

dpm_srv_getreqsummary(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      char func[22];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      int n;
      int nb_errors = 0;
      int nb_failed;
      int nb_progress;
      int nb_queued;
      int nbgids;
      int nbreqfiles;
      int nbtokens;
      int r_status;
      char r_token[CA_MAXDPMTOKENLEN+1];
      char r_type;
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp = repbuf;
      int status;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_getreqsummary");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "getreqsummary", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      unmarshall_LONG (rbp, nbtokens);
      if (nbtokens <= 0) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Number of tokens <= 0");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }

      marshall_LONG (sbp, nbtokens);
      for (i = 0; i < nbtokens; i++) {
            if (unmarshall_STRINGN (rbp, r_token, CA_MAXDPMTOKENLEN+1)) {
                  nb_errors++;
                  continue;
            }
            if (dpm_getonereqsummary (thip, r_token, &r_type, &r_status,
                &nbreqfiles, &nb_queued, &nb_progress, &nb_failed) < 0) {
                  nb_errors++;
                  continue;
            }
            n = strlen (r_token) + 2 + 3 * LONGSIZE;
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_SUMMARY, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_STRING (sbp, r_token);
            marshall_BYTE (sbp, r_type);
            marshall_LONG (sbp, nbreqfiles);
            marshall_LONG (sbp, nb_queued);
            marshall_LONG (sbp, nb_progress);
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_SUMMARY, sbp - repbuf, repbuf);

      /* Send global status/errmsg */

      sbp = repbuf;
      if (nb_errors == nbtokens) {
            status = DPM_FAILED | EINVAL;
            marshall_LONG (sbp, status);
            marshall_STRING (sbp, "Invalid/unknown request token");
      } else {
            status = DPM_SUCCESS;
            marshall_LONG (sbp, status);
            marshall_STRING (sbp, "");
      }
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, status);
}

/*    dpm_srv_getspacemd - get space metadata */

dpm_srv_getspacemd(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      time_t current_time;
      struct dpm_space_reserv dpm_spcmd;
      char func[19];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      int j;
      int n;
      int nb_errors = 0;
      int nb_s_gids;
      int nbgids;
      int nbtokens;
      char *rbp;
      char repbuf[REPBUFSZ];
      gid_t *s_gids;
      char s_token[CA_MAXDPMTOKENLEN+1];
      char *sbp = repbuf;
      int status;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_getspacemd");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "getspacemd", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      unmarshall_LONG (rbp, nbtokens);
      if (nbtokens <= 0) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Number of tokens <= 0");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }

      marshall_LONG (sbp, nbtokens);
      for (i = 0; i < nbtokens; i++) {
            if (unmarshall_STRINGN (rbp, s_token, CA_MAXDPMTOKENLEN+1)) {
                  nb_errors++;
                  continue;
            }
            if (dpm_get_spcmd_by_token (&thip->dbfd, s_token, &dpm_spcmd,
                0, NULL) < 0) {
                  nb_errors++;
                  continue;
            }
            if ((s_gids = Cdecode_groups (dpm_spcmd.groups, &nb_s_gids)) == NULL) {
                  nb_errors++;
                  continue;
            }
            if (dpm_spcmd.s_gid) {
                  for (j = 0; j < nb_s_gids; j++) {
                        if (Cgroupmatch (s_gids[j], nbgids, gids)) break;
                  }
                  if (j >= nb_s_gids && uid != 0) {
                        free (s_gids);
                        nb_errors++;
                        continue;
                  }
            }
            if (dpm_spcmd.s_uid && uid != dpm_spcmd.s_uid && uid != 0) {
                  free (s_gids);
                  nb_errors++;
                  continue;
            }
            n = strlen (s_token) + 2;
            if (magic >= DPM_MAGIC2) {
                  n += 2 * LONGSIZE;
                  n += 2;
                  n += strlen (dpm_spcmd.u_token) + 1;
            }
            if (magic == DPM_MAGIC || magic >= DPM_MAGIC3)
                  n += strlen (dpm_spcmd.client_dn) + 1;
            n += 3 * HYPERSIZE;
            if (magic >= DPM_MAGIC2)
                  n += strlen (dpm_spcmd.poolname) + 1;
            n += 2 * TIME_TSIZE;
            if (magic >= DPM_MAGIC3) {
                  n += LONGSIZE;
                  n += nb_s_gids * LONGSIZE;
            }
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_SPCMD, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            current_time = time (0);
            marshall_BYTE (sbp, dpm_spcmd.s_type);
            marshall_STRING (sbp, dpm_spcmd.s_token);
            if (magic >= DPM_MAGIC2) {
                  marshall_LONG (sbp, dpm_spcmd.s_uid);
                  marshall_LONG (sbp, dpm_spcmd.s_gid);
                  marshall_BYTE (sbp, dpm_spcmd.ret_policy);
                  marshall_BYTE (sbp, dpm_spcmd.ac_latency);
                  marshall_STRING (sbp, dpm_spcmd.u_token);
            }
            if (magic == DPM_MAGIC || magic >= DPM_MAGIC3)
                  marshall_STRING (sbp, dpm_spcmd.client_dn);
            marshall_HYPER (sbp, dpm_spcmd.t_space);
            marshall_HYPER (sbp, dpm_spcmd.g_space);
            marshall_HYPER (sbp, dpm_spcmd.u_space);
            if (magic >= DPM_MAGIC2)
                  marshall_STRING (sbp, dpm_spcmd.poolname);
            marshall_TIME_T (sbp, current_time - dpm_spcmd.assign_time);
            if (dpm_spcmd.expire_time != 0x7FFFFFFF) {
                  marshall_TIME_T (sbp, dpm_spcmd.expire_time - current_time);
            } else {
                  marshall_TIME_T (sbp, 0x7FFFFFFF);
            }
            if (magic >= DPM_MAGIC3) {
                  marshall_LONG (sbp, nb_s_gids);
                  for (j = 0; j < nb_s_gids; j++)
                        marshall_LONG (sbp, s_gids[j]);
            }
            free (s_gids);
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_SPCMD, sbp - repbuf, repbuf);

      /* Send global status/errmsg */

      sbp = repbuf;
      if (nb_errors == nbtokens) {
            status = DPM_FAILED | EINVAL;
            marshall_LONG (sbp, status);
            marshall_STRING (sbp, "Invalid/unknown space token");
      } else {
            status = DPM_SUCCESS;
            marshall_LONG (sbp, status);
            marshall_STRING (sbp, "");
      }
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, status);
}

/*    dpm_srv_getspacetoken - get space token */

dpm_srv_getspacetoken(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      int bol = 1;
      int c;
      DBLISTPTR dblistptr;
      struct dpm_space_reserv dpm_spcmd;
      char func[22];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int j;
      char logbuf[270];
      int n;
      int nb_s_gids;
      int nbgids;
      int nbreplies = 0;
      char *rbp;
      char repbuf[REPBUFSZ];
      gid_t *s_gids;
      char *sbp = repbuf;
      char u_token[256];
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_getspacetoken");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "getspacetoken", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, u_token, 256)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid user space token description");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      sprintf (logbuf, "getspacetoken %s", u_token);
      dpm_logreq (func, logbuf);

      while ((c = dpm_get_spcmd_by_u_desc (&thip->dbfd, bol, u_token, uid,
          &dpm_spcmd, 0, &dblistptr)) == 0) {
            bol = 0;
            if (dpm_spcmd.s_gid) {
                  if ((s_gids = Cdecode_groups (dpm_spcmd.groups, &nb_s_gids)) == NULL) {
                        c = -1;
                        serrno = ENOMEM;
                        break;
                  }
                  for (j = 0; j < nb_s_gids; j++) {
                        if (Cgroupmatch (s_gids[j], nbgids, gids)) break;
                  }
                  free (s_gids);
                  if (j >= nb_s_gids && uid != 0) continue;
            }
            n = strlen (dpm_spcmd.s_token) + 1;
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_SPCTKN, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_STRING (sbp, dpm_spcmd.s_token);
            nbreplies++;
      }
      (void) dpm_get_spcmd_by_u_desc (&thip->dbfd, bol, u_token, uid,
          &dpm_spcmd, 1, &dblistptr);     /* free res */
      if (c < 0)
            RETURN (serrno);
      if (nbreplies == 0) {
            if (*u_token) {
                  marshall_LONG (sbp, DPM_FAILED | EINVAL);
                  marshall_STRING (sbp, "Unknown user space token description");
                  sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                  RETURNS (0, DPM_FAILED | EINVAL);
            } else {
                  if (magic == DPM_MAGIC) {
                        marshall_LONG (sbp, DPM_FAILED | EINVAL);
                        marshall_STRING (sbp, "No accessible space token");
                        sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                        RETURNS (0, DPM_FAILED | EINVAL);
                  }
                  sendrep (thip->s, MSG_SPCTKN, 0, repbuf);
            }

      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_SPCTKN, sbp - repbuf, repbuf);

      /* Send global status/errmsg */

      sbp = repbuf;
      marshall_LONG (sbp, DPM_SUCCESS);
      marshall_STRING (sbp, "");
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, DPM_SUCCESS);
}

/*    dpm_srv_getstatus_copyreq - get status for a dpm_copy request */

dpm_srv_getstatus_copyreq(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      int bol = 1;
      int c;
      struct dpm_copy_filereq cpr_entry;
      DBLISTPTR dblistptr;
      struct dpm_req dpm_req;
      char from_surl[CA_MAXSFNLEN+1];
      char func[26];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[2*CA_MAXSFNLEN+20];
      int n;
      int nbgids;
      int nbsurls;
      char r_token[CA_MAXDPMTOKENLEN+1];
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp = repbuf;
      int status;
      char to_surl[CA_MAXSFNLEN+1];
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_getstatus_copyreq");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "getstatus_copyreq", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, r_token, CA_MAXDPMTOKENLEN+1)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid request token");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_LONG (rbp, nbsurls);
      if (nbsurls < 0) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Number of surls < 0");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      sprintf (logbuf, "getstatus_copyreq %s %d", r_token, nbsurls);
      dpm_logreq (func, logbuf);

      /* check that the request exists and get status/nbreqfiles */

      if (dpm_get_pending_req_by_token (&thip->dbfd, r_token, &dpm_req, 0, NULL) < 0 &&
          dpm_get_req_by_token (&thip->dbfd, r_token, &dpm_req, 0, NULL) < 0) {
            if (serrno == ENOENT) {
                  status = DPM_FAILED | EINVAL;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "Unknown request token");
            } else {
                  status = DPM_FAILED | serrno;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "");
            }
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, status);
      }

      if (dpm_req.r_type != 'C') {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "request type mismatch");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }

      if (nbsurls == 0) {     /* return all file requests for this token */
            marshall_LONG (sbp, dpm_req.nbreqfiles);
            while ((c = dpm_list_cpr_entry (&thip->dbfd, bol, r_token,
                &cpr_entry, 0, NULL, 0, &dblistptr)) == 0) {
                  bol = 0;
                  n = marshall_CPR (NULL, &cpr_entry);      /* get length of marshalled entry */
                  if (sbp - repbuf + n > REPBUFSZ) {
                        sendrep (thip->s, MSG_COPY, sbp - repbuf, repbuf);
                        sbp = repbuf;
                  }
                  marshall_CPR (&sbp, &cpr_entry);
            }
            (void) dpm_list_cpr_entry (&thip->dbfd, bol, r_token,
                &cpr_entry, 0, NULL, 1, &dblistptr);  /* free res */
            if (c < 0)
                  RETURN (serrno);
      } else {    /* return information about specified file requests */
            marshall_LONG (sbp, nbsurls);
            for (i = 0; i < nbsurls; i++) {
                  n = unmarshall_STRINGN (rbp, from_surl, CA_MAXSFNLEN+1);
                  if (unmarshall_STRINGN (rbp, to_surl, CA_MAXSFNLEN+1) || n) {
                        memset (&cpr_entry, 0, sizeof(cpr_entry));
                        strcpy (cpr_entry.from_surl, from_surl);
                        strcpy (cpr_entry.to_surl, to_surl);
                        cpr_entry.status = DPM_FAILED | SENAMETOOLONG;
                  }
                  if (dpm_get_cpr_by_surls (&thip->dbfd, r_token, from_surl,
                      to_surl, &cpr_entry, 0, NULL) < 0) {
                        memset (&cpr_entry, 0, sizeof(cpr_entry));
                        strcpy (cpr_entry.from_surl, from_surl);
                        strcpy (cpr_entry.to_surl, to_surl);
                        cpr_entry.status = DPM_FAILED | serrno;
                  }
                  sprintf (logbuf, "getstatus_copyreq %s %s",
                      cpr_entry.from_surl, cpr_entry.to_surl);
                  dpm_logreq (func, logbuf);
                  n = marshall_CPR (NULL, &cpr_entry);      /* get length of marshalled entry */
                  if (sbp - repbuf + n > REPBUFSZ) {
                        sendrep (thip->s, MSG_COPY, sbp - repbuf, repbuf);
                        sbp = repbuf;
                  }
                  marshall_CPR (&sbp, &cpr_entry);
            }
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_COPY, sbp - repbuf, repbuf);

      /* Send global status/errmsg */

      sbp = repbuf;
      marshall_LONG (sbp, dpm_req.status);
      marshall_STRING (sbp, dpm_req.errstring);
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, dpm_req.status);
}

/*    dpm_srv_getstatus_getreq - get status for a dpm_get request */

dpm_srv_getstatus_getreq(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      int bol = 1;
      int c;
      DBLISTPTR dblistptr;
      struct dpm_req dpm_req;
      char from_surl[CA_MAXSFNLEN+1];
      char func[25];
      struct dpm_get_filereq gfr_entry;
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[CA_MAXSFNLEN+18];
      int n;
      int nbfromsurls;
      int nbgids;
      char r_token[CA_MAXDPMTOKENLEN+1];
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp = repbuf;
      int status;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_getstatus_getreq");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "getstatus_getreq", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, r_token, CA_MAXDPMTOKENLEN+1)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid request token");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_LONG (rbp, nbfromsurls);
      if (nbfromsurls < 0) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Number of surls < 0");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      sprintf (logbuf, "getstatus_getreq %s %d", r_token, nbfromsurls);
      dpm_logreq (func, logbuf);

      /* check that the request exists and get nbreqfiles */

      if (dpm_get_pending_req_by_token (&thip->dbfd, r_token, &dpm_req, 0, NULL) < 0 &&
          dpm_get_req_by_token (&thip->dbfd, r_token, &dpm_req, 0, NULL) < 0) {
            if (serrno == ENOENT) {
                  status = DPM_FAILED | EINVAL;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "Unknown request token");
            } else {
                  status = DPM_FAILED | serrno;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "");
            }
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, status);
      }

      if (dpm_req.r_type != 'G') {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "request type mismatch");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }

      if (nbfromsurls == 0) { /* return all file requests for this token */
            marshall_LONG (sbp, dpm_req.nbreqfiles);
            while ((c = dpm_list_gfr_entry (&thip->dbfd, bol, r_token,
                &gfr_entry, 0, NULL, 0, &dblistptr)) == 0) {
                  bol = 0;
                  /* get length of marshalled entry */
                  n = marshall_GFR (NULL, &gfr_entry);
                  if (sbp - repbuf + n > REPBUFSZ) {
                        sendrep (thip->s, MSG_GET, sbp - repbuf, repbuf);
                        sbp = repbuf;
                  }
                  marshall_GFR (&sbp, &gfr_entry);
            }
            (void) dpm_list_gfr_entry (&thip->dbfd, bol, r_token,
                &gfr_entry, 0, NULL, 1, &dblistptr);  /* free res */
            if (c < 0)
                  RETURN (serrno);
      } else {    /* return information about specified file requests */
            marshall_LONG (sbp, nbfromsurls);
            for (i = 0; i < nbfromsurls; i++) {
                  if (unmarshall_STRINGN (rbp, from_surl, CA_MAXSFNLEN+1)) {
                        memset (&gfr_entry, 0, sizeof(gfr_entry));
                        strcpy (gfr_entry.from_surl, from_surl);
                        gfr_entry.status = DPM_FAILED | SENAMETOOLONG;
                  } else if (dpm_get_gfr_by_surl (&thip->dbfd, r_token, from_surl,
                      &gfr_entry, 0, NULL) < 0) {
                        memset (&gfr_entry, 0, sizeof(gfr_entry));
                        strcpy (gfr_entry.from_surl, from_surl);
                        gfr_entry.status = DPM_FAILED | serrno;
                  }
                  sprintf (logbuf, "getstatus_getreq %s", gfr_entry.from_surl);
                  dpm_logreq (func, logbuf);
                  /* get length of marshalled entry */
                  n = marshall_GFR (NULL, &gfr_entry);
                  if (sbp - repbuf + n > REPBUFSZ) {
                        sendrep (thip->s, MSG_GET, sbp - repbuf, repbuf);
                        sbp = repbuf;
                  }
                  marshall_GFR (&sbp, &gfr_entry);
            }
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_GET, sbp - repbuf, repbuf);

      /* Send global status/errmsg */

      sbp = repbuf;
      marshall_LONG (sbp, dpm_req.status);
      marshall_STRING (sbp, dpm_req.errstring);
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, dpm_req.status);
}

/*    dpm_srv_getstatus_putreq - get status for a dpm_put request */

dpm_srv_getstatus_putreq(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      int bol = 1;
      int c;
      DBLISTPTR dblistptr;
      struct dpm_req dpm_req;
      char func[25];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[CA_MAXSFNLEN+18];
      int n;
      int nbgids;
      int nbtosurls;
      struct dpm_put_filereq pfr_entry;
      char r_token[CA_MAXDPMTOKENLEN+1];
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp = repbuf;
      int status;
      char to_surl[CA_MAXSFNLEN+1];
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_getstatus_putreq");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "getstatus_putreq", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, r_token, CA_MAXDPMTOKENLEN+1)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid request token");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_LONG (rbp, nbtosurls);
      if (nbtosurls < 0) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Number of surls < 0");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      sprintf (logbuf, "getstatus_putreq %s %d", r_token, nbtosurls);
      dpm_logreq (func, logbuf);

      /* check that the request exists and get nbreqfiles */

      if (dpm_get_pending_req_by_token (&thip->dbfd, r_token, &dpm_req, 0, NULL) < 0 &&
          dpm_get_req_by_token (&thip->dbfd, r_token, &dpm_req, 0, NULL) < 0) {
            if (serrno == ENOENT) {
                  status = DPM_FAILED | EINVAL;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "Unknown request token");
            } else {
                  status = DPM_FAILED | serrno;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "");
            }
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, status);
      }

      if (dpm_req.r_type != 'P') {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "request type mismatch");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }

      if (nbtosurls == 0) {   /* return all file requests for this token */
            marshall_LONG (sbp, dpm_req.nbreqfiles);
            while ((c = dpm_list_pfr_entry (&thip->dbfd, bol, r_token,
                &pfr_entry, 0, NULL, 0, &dblistptr)) == 0) {
                  bol = 0;
                  /* get length of marshalled entry */
                  n = marshall_PFR (NULL, magic, &pfr_entry);
                  if (sbp - repbuf + n > REPBUFSZ) {
                        sendrep (thip->s, MSG_PUT, sbp - repbuf, repbuf);
                        sbp = repbuf;
                  }
                  marshall_PFR (&sbp, magic, &pfr_entry);
            }
            (void) dpm_list_pfr_entry (&thip->dbfd, bol, r_token,
                &pfr_entry, 0, NULL, 1, &dblistptr);  /* free res */
            if (c < 0)
                  RETURN (serrno);
      } else {    /* return information about specified file requests */
            marshall_LONG (sbp, nbtosurls);
            for (i = 0; i < nbtosurls; i++) {
                  if (unmarshall_STRINGN (rbp, to_surl, CA_MAXSFNLEN+1)) {
                        memset (&pfr_entry, 0, sizeof(pfr_entry));
                        strcpy (pfr_entry.to_surl, to_surl);
                        pfr_entry.status = DPM_FAILED | SENAMETOOLONG;
                  } else if (dpm_get_pfr_by_surl (&thip->dbfd, r_token, to_surl,
                      &pfr_entry, 0, NULL) < 0) {
                        memset (&pfr_entry, 0, sizeof(pfr_entry));
                        strcpy (pfr_entry.to_surl, to_surl);
                        pfr_entry.status = DPM_FAILED | serrno;
                  }
                  sprintf (logbuf, "getstatus_putreq %s", pfr_entry.to_surl);
                  dpm_logreq (func, logbuf);
                  /* get length of marshalled entry */
                  n = marshall_PFR (NULL, magic, &pfr_entry);
                  if (sbp - repbuf + n > REPBUFSZ) {
                        sendrep (thip->s, MSG_PUT, sbp - repbuf, repbuf);
                        sbp = repbuf;
                  }
                  marshall_PFR (&sbp, magic, &pfr_entry);
            }
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_PUT, sbp - repbuf, repbuf);

      /* Send global status/errmsg */

      sbp = repbuf;
      marshall_LONG (sbp, dpm_req.status);
      marshall_STRING (sbp, dpm_req.errstring);
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, dpm_req.status);
}

/*    dpm_srv_inc_reqctr - increment get/put/copy request counter */

dpm_srv_inc_reqctr(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      int c;
      char func[19];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int nbgids;
      char *rbp;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_inc_reqctr");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "inc_reqctr", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);

      c = inc_reqctr ();
      RETURN (c);
}

/*    dpm_srv_modifyfs - modify the parameters of a disk filesystem */

dpm_srv_modifyfs(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      struct dpm_fs fs_entry;
      char fs[80];
      char func[17];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      char logbuf[CA_MAXHOSTNAMELEN+101];
      int nbgids;
      char *rbp;
      dpm_dbrec_addr rec_addr;
      char server[CA_MAXHOSTNAMELEN+1];
      int status;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_modifyfs");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "modifyfs", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      memset ((char *) &fs_entry, 0, sizeof(fs_entry));
      if (unmarshall_STRINGN (rbp, server, CA_MAXHOSTNAMELEN+1))
            RETURN (EINVAL);
      if (unmarshall_STRINGN (rbp, fs, 80))
            RETURN (EINVAL);
      unmarshall_LONG (rbp, status);
      sprintf (logbuf, "modifyfs %s %s %d", server, fs, status);
      dpm_logreq (func, logbuf);

      if (uid)
            RETURN (EACCES);

      if (strchr (server, '.') == NULL) {
            if (strlen (server) + strlen (localdomain) + 1 > CA_MAXHOSTNAMELEN)
                  RETURN (EINVAL);
            strcat (server, ".");
            strcat (server, localdomain);
      }

      /* Update configuration in memory */

      if (dpm_modfsinpoolconf (server, fs, status) < 0)
            RETURN (serrno);

      /* Update configuration in DB */

      (void) dpm_start_tr (thip->s, &thip->dbfd);

      /* get and lock entry */

      memset ((void *) &fs_entry, 0, sizeof(struct dpm_fs));
      if (dpm_get_fs_entry (&thip->dbfd, server, fs, &fs_entry,
          1, &rec_addr))
            RETURN (serrno);

      /* update entry */

      if (status >= 0 && status != fs_entry.status) {
            fs_entry.status = status;

            if (dpm_update_fs_entry (&thip->dbfd, &rec_addr, &fs_entry))
                  RETURN (serrno);
      }
      RETURN (0);
}

/*    dpm_srv_modifypool - modify a disk pool definition */

dpm_srv_modifypool(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      int def_lifetime;
      int defpintime;
      u_signed64 defsize;
      char fss_policy[CA_MAXPOLICYLEN+1];
      char func[19];
      char gc_policy[CA_MAXPOLICYLEN+1];
      int gc_start_thresh;
      int gc_stop_thresh;
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[CA_MAXPOOLNAMELEN+33];
      int max_lifetime;
      int maxpintime;
      char mig_policy[CA_MAXPOLICYLEN+1];
      int nbgids;
      int need_update = 0;
      struct dpm_pool pool_entry;
      gid_t pool_gid;
      gid_t *pool_gids = NULL;
      int pool_nbgids;
      char poolname[CA_MAXPOOLNAMELEN+1];
      int put_retenp;
      char *rbp;
      dpm_dbrec_addr rec_addr;
      char ret_policy;
      char rs_policy[CA_MAXPOLICYLEN+1];
      char s_type;
      char tmpbuf[21];
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_modifypool");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "modifypool", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      memset ((char *) &pool_entry, 0, sizeof(pool_entry));
      if (unmarshall_STRINGN (rbp, poolname, CA_MAXPOOLNAMELEN+1))
            RETURN (EINVAL);
      unmarshall_HYPER (rbp, defsize);
      unmarshall_LONG (rbp, gc_start_thresh);
      if (gc_start_thresh > 100)
            RETURN (EINVAL);
      unmarshall_LONG (rbp, gc_stop_thresh);
      if (gc_stop_thresh > 100)
            RETURN (EINVAL);
      unmarshall_LONG (rbp, defpintime);
      if (magic < DPM_MAGIC2)
            unmarshall_LONG (rbp, put_retenp);
      if (unmarshall_STRINGN (rbp, fss_policy, CA_MAXPOLICYLEN+1))
            RETURN (EINVAL);
      if (unmarshall_STRINGN (rbp, gc_policy, CA_MAXPOLICYLEN+1))
            RETURN (EINVAL);
      if (unmarshall_STRINGN (rbp, rs_policy, CA_MAXPOLICYLEN+1))
            RETURN (EINVAL);
      unmarshall_LONG (rbp, pool_gid);
      unmarshall_BYTE (rbp, s_type);
      if (magic >= DPM_MAGIC2) {
            if (unmarshall_STRINGN (rbp, mig_policy, CA_MAXPOLICYLEN+1))
                  RETURN (EINVAL);
            unmarshall_BYTE (rbp, ret_policy);
            unmarshall_LONG (rbp, def_lifetime);
            unmarshall_LONG (rbp, max_lifetime);
            unmarshall_LONG (rbp, maxpintime);
      } else {
            *mig_policy = '\0';
            ret_policy = '\0';
            def_lifetime = -1;
            max_lifetime = -1;
            maxpintime = -1;
      }
      if (magic >= DPM_MAGIC3) {
            unmarshall_LONG (rbp, pool_nbgids);
            if (pool_nbgids == 0) {
                  sendrep (thip->s, MSG_ERR,
                      "There must be at least one gid for a dedicated pool\n");
                  RETURN (EINVAL);
            }
            if (pool_nbgids > 0 &&
                (pool_gids = malloc (pool_nbgids * sizeof(gid_t))) == NULL)
                  RETURN (ENOMEM);
            for (i = 0; i < pool_nbgids; i++)
                  unmarshall_LONG (rbp, pool_gids[i]);
            if (pool_nbgids > 1) {
                  for (i = 0; i < pool_nbgids; i++)
                        if (pool_gids[i] == 0) {
                              sendrep (thip->s, MSG_ERR,
                                  "Pool must be either generic or dedicated\n");
                              free (pool_gids);
                              RETURN (EINVAL);
                        }
            }
      } else {
            if (pool_gid != -1) {
                  pool_nbgids = 1;
                  if ((pool_gids = malloc (sizeof(gid_t))) == NULL)
                        RETURN (ENOMEM);
                  pool_gids[0] = pool_gid;
            } else
                  pool_nbgids = -1;
      }
      sprintf (logbuf, "modifypool %s %s", poolname,
          (defsize == -1) ? "" : u64tostr(defsize, tmpbuf, 0));
      dpm_logreq (func, logbuf);

      if (uid) {
            free (pool_gids);
            RETURN (EACCES);
      }

      if (s_type && s_type != 'V' && s_type != 'D' && s_type != 'P' &&
          s_type != '-') {
            sendrep (thip->s, MSG_ERR, "Invalid type of space\n");
            free (pool_gids);
            RETURN (EINVAL);
      }

      /* Update configuration in memory */

      if (dpm_modpoolinpoolconf (poolname, defsize, gc_start_thresh,
          gc_stop_thresh, def_lifetime, defpintime, max_lifetime, maxpintime,
          fss_policy, gc_policy, mig_policy, rs_policy, pool_nbgids, pool_gids,
          ret_policy, s_type) < 0) {
            free (pool_gids);
            RETURN (serrno);
      }

      /* Update configuration in DB */

      (void) dpm_start_tr (thip->s, &thip->dbfd);

      /* get and lock entry */

      memset ((void *) &pool_entry, 0, sizeof(struct dpm_pool));
      if (dpm_get_pool_entry (&thip->dbfd, poolname, &pool_entry,
          1, &rec_addr))
            RETURN (serrno);

      /* update entry */

      if (defsize != -1 && defsize != pool_entry.defsize) {
            pool_entry.defsize = defsize;
            need_update++;
      }
      if (gc_start_thresh != -1 && gc_start_thresh != pool_entry.gc_start_thresh) {
            pool_entry.gc_start_thresh = gc_start_thresh;
            need_update++;
      }
      if (gc_stop_thresh != -1 && gc_stop_thresh != pool_entry.gc_stop_thresh) {
            pool_entry.gc_stop_thresh = gc_stop_thresh;
            need_update++;
      }
      if (def_lifetime != -1 && def_lifetime != pool_entry.def_lifetime) {
            pool_entry.def_lifetime = def_lifetime;
            need_update++;
      }
      if (defpintime != -1 && defpintime != pool_entry.defpintime) {
            pool_entry.defpintime = defpintime;
            need_update++;
      }
      if (max_lifetime != -1 && max_lifetime != pool_entry.max_lifetime) {
            pool_entry.max_lifetime = max_lifetime;
            need_update++;
      }
      if (maxpintime != -1 && maxpintime != pool_entry.maxpintime) {
            pool_entry.maxpintime = maxpintime;
            need_update++;
      }
      if (*fss_policy && strcmp (fss_policy, pool_entry.fss_policy)) {
            strcpy (pool_entry.fss_policy, fss_policy);
            need_update++;
      }
      if (*gc_policy && strcmp (gc_policy, pool_entry.gc_policy)) {
            strcpy (pool_entry.gc_policy, gc_policy);
            need_update++;
      }
      if (*mig_policy && strcmp (mig_policy, pool_entry.mig_policy)) {
            strcpy (pool_entry.mig_policy, mig_policy);
            need_update++;
      }
      if (*rs_policy && strcmp (rs_policy, pool_entry.rs_policy)) {
            strcpy (pool_entry.rs_policy, rs_policy);
            need_update++;
      }
      if (pool_nbgids != -1) {
            free (pool_entry.gids);
            pool_entry.nbgids = pool_nbgids;
            pool_entry.gids = pool_gids;
            need_update++;
      }
      if (ret_policy) {
            pool_entry.ret_policy = ret_policy;
            need_update++;
      }
      if (s_type) {
            pool_entry.s_type = s_type;
            need_update++;
      }

      if (need_update)
            if (dpm_update_pool_entry (&thip->dbfd, &rec_addr, &pool_entry))
                  RETURN (serrno);
      RETURN (0);
}

/*    dpm_srv_ping - check server alive and return version number */

dpm_srv_ping(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      gid_t gid;
      gid_t *gids;
      char info[256];
      int nbgids;
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp;
      uid_t uid;
      char *user;

      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      sprintf (info, "%s-%d", BASEVERSION, PATCHLEVEL);
      sbp = repbuf;
      marshall_STRING (sbp, info);
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      return (0);
}

/*    dpm_srv_put - make a set of existing files available for I/O */

dpm_srv_put(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      struct dpm_req dpm_req;
      char func[16];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      int j;
      char logbuf[CA_MAXSFNLEN+16];
      int n;
      int nb_file_err = 0;
      int nbgids;
      int nbprotocols;
      int nbreqfiles;
      struct dpm_put_filereq pfr_entry;
      char protocol[CA_MAXPROTOLEN+1];
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp;
      char selected_protocol[CA_MAXPROTOLEN+1];
      uid_t uid;
      u_signed64 unique_id;
      char *user;
      uuid_t uuid;

      strcpy (func, "dpm_srv_put");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "put", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      memset ((char *) &dpm_req, 0, sizeof(dpm_req));
      dpm_req.r_uid = uid;
      dpm_req.r_gid = gid;
      strcpy (dpm_req.client_dn, user);
      strcpy (dpm_req.groups, groups);
      strcpy (dpm_req.clienthost, clienthost);
      unmarshall_LONG (rbp, nbprotocols);
      dpm_req.r_type = 'P';

      /* Negociate protocol */

      *selected_protocol = '\0';
      for (i = 0; i < nbprotocols; i++) {
            if (unmarshall_STRINGN (rbp, protocol, CA_MAXPROTOLEN+1))
                  continue;
            if (*selected_protocol) continue;
            for (j = 0; j < nb_supported_protocols; j++) {
                  if (strcmp (protocol, supported_protocols[j]) == 0) {
                        strcpy (selected_protocol, protocol);
                        break;
                  }
            }
      }
      if (! *selected_protocol) {
            dpm_req.status = DPM_FAILED | SEPROTONOTSUP;
      }
      if (unmarshall_STRINGN (rbp, dpm_req.u_token, 256)) {
            dpm_req.status = DPM_FAILED | EINVAL;
            strcpy (dpm_req.errstring, "Invalid user request description");
      }
      unmarshall_LONG (rbp, dpm_req.flags);     /* overwrite option */
      if (dpm_req.flags != 0 && dpm_req.flags != 1 && dpm_req.flags != 4) {
            dpm_req.status = DPM_FAILED | EINVAL;
            strcpy (dpm_req.errstring, "Invalid overwrite flag value");
      }
      unmarshall_TIME_T (rbp, dpm_req.retrytime);

      /* start transaction */

      (void) dpm_start_tr (thip->s, &thip->dbfd);

      if (dpm_unique_id (&thip->dbfd, &unique_id) < 0)
            RETURN (SEINTERNAL);
      dpm_req.r_ordinal = unique_id & 0xFFFFFFFF;

      uuid_generate (uuid);
      uuid_unparse (uuid, dpm_req.r_token);
      sprintf (logbuf, "put %d %s", dpm_req.r_ordinal, dpm_req.r_token);
      dpm_logreq (func, logbuf);

      dpm_req.ctime = time (0);
      unmarshall_LONG (rbp, nbreqfiles);
      if (nbreqfiles <= 0) {
            nbreqfiles = 0;
            dpm_req.status = DPM_FAILED | EINVAL;
            strcpy (dpm_req.errstring, "Number of surls <= 0");
      } else if (! dpm_req.status)
            dpm_req.status = DPM_QUEUED;

      sbp = repbuf;
      marshall_LONG (sbp, nbreqfiles);
      dpm_req.nbreqfiles = nbreqfiles;

      /* Get and check the individual file requests */

      for (i = 0; i < nbreqfiles; i++) {
            memset (&pfr_entry, 0, sizeof(pfr_entry));
            strcpy (pfr_entry.r_token, dpm_req.r_token);
            pfr_entry.f_ordinal = i;
            pfr_entry.status = DPM_QUEUED;
            if (unmarshall_STRINGN (rbp, pfr_entry.to_surl, CA_MAXSFNLEN+1)) {
                  pfr_entry.status = DPM_FAILED | SENAMETOOLONG;
            }
            unmarshall_TIME_T (rbp, pfr_entry.lifetime);
            if (pfr_entry.lifetime < 0) {
                  pfr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (pfr_entry.errstring, "Negative value for lifetime");
            }
            unmarshall_BYTE (rbp, pfr_entry.f_type);
            if (pfr_entry.f_type == '\0')
                  pfr_entry.f_type = DEFAULT_SPACE_TYPE;
            else if (pfr_entry.f_type != 'V' && pfr_entry.f_type != 'D' &&
                pfr_entry.f_type != 'P') {
                  pfr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (pfr_entry.errstring, "Invalid file storage type");
            }
            if (unmarshall_STRINGN (rbp, pfr_entry.s_token, CA_MAXDPMTOKENLEN+1)) {
                  pfr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (pfr_entry.errstring, "Invalid space token");
            }
            unmarshall_HYPER (rbp, pfr_entry.requested_size);
            if (pfr_entry.requested_size & INT64_NEG) {
                  pfr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (pfr_entry.errstring, "Negative value for requested size");
            }
            if (magic >= DPM_MAGIC2) {
                  unmarshall_TIME_T (rbp, pfr_entry.f_lifetime);
                  if (pfr_entry.f_lifetime < 0) {
                        pfr_entry.status = DPM_FAILED | EINVAL;
                        strcpy (pfr_entry.errstring, "Negative value for f_lifetime");
                  }
                  unmarshall_BYTE (rbp, pfr_entry.ret_policy);
                  unmarshall_BYTE (rbp, pfr_entry.ac_latency);
            }
            if (pfr_entry.ret_policy == '\0')
                  pfr_entry.ret_policy = '_';
            else if (pfr_entry.ret_policy != 'R' && pfr_entry.ret_policy != 'O' &&
                pfr_entry.ret_policy != 'C') {
                  pfr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (pfr_entry.errstring, "Invalid retention policy");
            }
            if (pfr_entry.ac_latency == '\0')
                  pfr_entry.ac_latency = 'O';
            else if (pfr_entry.ac_latency != 'O' && pfr_entry.ac_latency != 'N') {
                  pfr_entry.status = DPM_FAILED | EINVAL;
                  strcpy (pfr_entry.errstring, "Invalid access latency");
            }
            strcpy (pfr_entry.protocol, selected_protocol);
            sprintf (logbuf, "put %d %s", i, pfr_entry.to_surl);
            dpm_logreq (func, logbuf);
            if (pfr_entry.status != DPM_QUEUED) {
                  nb_file_err++;
                  if (*pfr_entry.errstring)
                        dpmlogit (func, "file %d: %s\n", i, pfr_entry.errstring);
            }

            if (dpm_insert_pfr_entry (&thip->dbfd, &pfr_entry) < 0)
                  RETURN (SEINTERNAL);

            /* get length of marshalled entry */
            n = marshall_PFR (NULL, magic, &pfr_entry);
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_PUT, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_PFR (&sbp, magic, &pfr_entry);
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_PUT, sbp - repbuf, repbuf);

      if (dpm_req.status == DPM_QUEUED && nb_file_err == nbreqfiles) {
            dpm_req.status = DPM_FAILED | EINVAL;
            strcpy (dpm_req.errstring, "Failed for all SURLs");
      }

      if (dpm_req.status == DPM_QUEUED) {
            if (dpm_insert_pending_entry (&thip->dbfd, &dpm_req) < 0)
                  RETURN (SEINTERNAL);
            dpm_end_tr (&thip->dbfd);
            inc_reqctr ();
      } else {
            if (dpm_insert_xferreq_entry (&thip->dbfd, &dpm_req) < 0)
                  RETURN (SEINTERNAL);
      }

      /* Send global status/errmsg/token */

      sbp = repbuf;
      marshall_LONG (sbp, dpm_req.status);
      marshall_STRING (sbp, dpm_req.errstring);
      marshall_STRING (sbp, dpm_req.r_token);
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, dpm_req.status);
}

/*    dpm_srv_putdone - to mark a set of files as complete */

dpm_oneputdone (thip, r_token, surl, flags, status, errstring)
struct dpm_srv_thread_info *thip;
char *r_token;
char *surl;
int flags;
int *status;
char *errstring;
{
      struct Cns_fileid Cnsfileid;
      time_t current_time;
      struct dpm_space_reserv dpm_spcmd;
      int max_lifetime;
      struct dpm_put_filereq pfr_entry;
      dpm_dbrec_addr rec_addr;
      struct stat64 st;
      struct Cns_filestatg statbuf;

      /* start transaction */

      (void) dpm_start_tr (thip->s, &thip->dbfd);

      if (dpm_get_pfr_by_surl (&thip->dbfd, r_token, surl, &pfr_entry,
          1, &rec_addr) < 0) {
            *status = DPM_FAILED | serrno;
            (void) dpm_abort_tr (&thip->dbfd);
            return (-1);
      }
      if (pfr_entry.status != DPM_RUNNING && pfr_entry.status != DPM_READY) {
            *status = DPM_FAILED | EINVAL;
            strcpy (errstring, "Incompatible with current file status");
            (void) dpm_abort_tr (&thip->dbfd);
            return (-1);
      }
      if (pfr_entry.lifetime < time (0)) {
            *status = DPM_EXPIRED;
            (void) dpm_abort_tr (&thip->dbfd);
            return (-1);
      }
      if (rfio_stat64 (pfr_entry.pfn, &st) < 0) {
            *status = DPM_FAILED | rfio_serrno();
            (void) dpm_abort_tr (&thip->dbfd);
            return (-1);
      }
      pfr_entry.actual_size = st.st_size;
      if (Cns_statr (pfr_entry.pfn, &statbuf) < 0) {
            *status = DPM_FAILED | serrno;
            (void) dpm_abort_tr (&thip->dbfd);
            return (-1);
      }
      if (flags == 4) { /* replication */
            if (pfr_entry.actual_size != statbuf.filesize) {
                  *status = DPM_FAILED | SEINTERNAL;
                  strcpy (errstring, "File size mismatch");
                  (void) dpm_abort_tr (&thip->dbfd);
                  return (-1);
            }
      } else {
            strcpy (Cnsfileid.server, dpnshost);
            Cnsfileid.fileid = statbuf.fileid;
            if (Cns_setfsize (NULL, &Cnsfileid, pfr_entry.actual_size) < 0) {
                  *status = DPM_FAILED | serrno;
                  (void) dpm_abort_tr (&thip->dbfd);
                  return (-1);
            }
      }
      pfr_entry.lifetime = 0;
      if (pfr_entry.f_type == 'P')
            pfr_entry.f_lifetime = 0x7FFFFFFF;
      else {
            current_time = time (0);
            if (flags != 4) {
                  if (! pfr_entry.f_lifetime)
                        pfr_entry.f_lifetime = dpm_get_def_lifetime (pfr_entry.pfn, NULL);
                  if (pfr_entry.f_lifetime != 0x7FFFFFFF)
                        pfr_entry.f_lifetime += current_time;
            } else {
                  if (! pfr_entry.f_lifetime) {
                        pfr_entry.f_lifetime = dpm_get_def_lifetime (pfr_entry.pfn, NULL);
                        if (pfr_entry.f_lifetime != 0x7FFFFFFF)
                              pfr_entry.f_lifetime += current_time;
                  }
            }
            if (* pfr_entry.s_token && dpm_get_spcmd_by_token (&thip->dbfd,
                pfr_entry.s_token, &dpm_spcmd, 0, NULL) == 0)
                  max_lifetime = dpm_spcmd.expire_time;
            else {
                  max_lifetime = dpm_get_max_lifetime (pfr_entry.pfn);
                  if (max_lifetime != 0x7FFFFFFF)
                        max_lifetime += current_time;
            }
            if (pfr_entry.f_lifetime > max_lifetime)
                  pfr_entry.f_lifetime = max_lifetime;
      }
      if (Cns_setptime (pfr_entry.pfn, pfr_entry.lifetime) < 0) {
            *status = DPM_FAILED | serrno;
            (void) dpm_abort_tr (&thip->dbfd);
            return (-1);
      }
      if (Cns_setrltime (pfr_entry.pfn, pfr_entry.f_lifetime) < 0) {
            *status = DPM_FAILED | serrno;
            (void) dpm_abort_tr (&thip->dbfd);
            return (-1);
      }
      if (Cns_setrstatus (pfr_entry.pfn, '-') < 0) {
            *status = DPM_FAILED | serrno;
            (void) dpm_abort_tr (&thip->dbfd);
            return (-1);
      }
      pfr_entry.status = DPM_DONE;
      if (dpm_update_pfr_entry (&thip->dbfd, &rec_addr, &pfr_entry) < 0) {
            *status = DPM_FAILED | serrno;
            (void) dpm_abort_tr (&thip->dbfd);
            return (-1);
      }
      (void) dpm_end_tr (&thip->dbfd);

      dpm_updfreespace (pfr_entry.pfn, pfr_entry.requested_size - pfr_entry.actual_size,
          pfr_entry.s_token, 0);
      if (*pfr_entry.s_token)
            (void) dpm_upd_u_space (&thip->dbfd, pfr_entry.s_token,
                pfr_entry.requested_size - pfr_entry.actual_size);
      *status = DPM_DONE;
      return (0);
}

dpm_srv_putdone(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      struct dpm_req dpm_req;
      char errstring[256];
      char func[16];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[CA_MAXSFNLEN+20];
      int n;
      int nb_file_err = 0;
      int nbgids;
      int nbsurls;
      char r_token[CA_MAXDPMTOKENLEN+1];
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp = repbuf;
      int status;
      char surl[CA_MAXSFNLEN+1];
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_putdone");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "putdone", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, r_token, CA_MAXDPMTOKENLEN+1)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid request token");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_LONG (rbp, nbsurls);
      if (nbsurls <= 0) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Number of surls <= 0");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      sprintf (logbuf, "putdone %s %d", r_token, nbsurls);
      dpm_logreq (func, logbuf);

      if (dpm_get_req_by_token (&thip->dbfd, r_token, &dpm_req, 0, NULL) < 0) {
            if (serrno == ENOENT) {
                  status = DPM_FAILED | EINVAL;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "Unknown request token");
            } else {
                  status = DPM_FAILED | serrno;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "");
            }
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, status);
      }
      if (dpm_req.r_type != 'P') {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Wrong request type");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }

      marshall_LONG (sbp, nbsurls);
      for (i = 0; i < nbsurls; i++) {
            errstring[0] = '\0';
            if (unmarshall_STRINGN (rbp, surl, CA_MAXSFNLEN+1)) {
                  status = DPM_FAILED | SENAMETOOLONG;
                  nb_file_err++;
            } else {
                  sprintf (logbuf, "putdone %d %s", i, surl);
                  dpm_logreq (func, logbuf);
                  if (dpm_oneputdone (thip, r_token, surl, dpm_req.flags,
                      &status, errstring) < 0)
                        nb_file_err++;
            }
            n = strlen (surl) + 1;
                  n += LONGSIZE;
            n += strlen (errstring) + 1;
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_SURLST, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_STRING (sbp, surl);
            marshall_LONG (sbp, status);
            marshall_STRING (sbp, errstring);
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_SURLST, sbp - repbuf, repbuf);

      /* Send global status/errmsg */

      sbp = repbuf;
      if (nb_file_err == 0)
            status = DPM_SUCCESS;
      else if (nb_file_err != nbsurls)
            status = DPM_DONE;
      else if (nbsurls != 1)
            status = DPM_FAILED | EINVAL;
      marshall_LONG (sbp, status);
      if (nb_file_err == 1 && nbsurls == 1) {
            marshall_STRING (sbp, errstring);
      } else {
            marshall_STRING (sbp, "");
      }
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, status);
}

/*    dpm_srv_releasespace - to release space */

dpm_srv_releasespace(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      struct dpm_space_reserv dpm_spcmd;
      int flags;
      int force;
      char func[21];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      Cns_list list;
      char logbuf[CA_MAXDPMTOKENLEN+25];
      struct Cns_filereplicax *lp;
      int nbgids;
      int nbpinned = 0;
      char *rbp;
      dpm_dbrec_addr rec_addr;
      char repbuf[REPBUFSZ];
      char s_token[CA_MAXDPMTOKENLEN+1];
      char *sbp = repbuf;
      int status;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_releasespace");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "releasespace", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, s_token, CA_MAXDPMTOKENLEN+1)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid space token");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_LONG (rbp, force);
      sprintf (logbuf, "releasespace %s %d", s_token, force);
      dpm_logreq (func, logbuf);

      /* start transaction */

      (void) dpm_start_tr (thip->s, &thip->dbfd);

      if (dpm_get_spcmd_by_token (&thip->dbfd, s_token, &dpm_spcmd,
          1, &rec_addr) < 0) {
            if (serrno == ENOENT) {
                  status = DPM_FAILED | EINVAL;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "Unknown space token");
            } else {
                  status = DPM_FAILED | serrno;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "");
            }
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, status);
      }
      if (((dpm_spcmd.s_gid && ! Cgroupmatch (dpm_spcmd.s_gid, nbgids, gids)) ||
          (dpm_spcmd.s_uid && uid != dpm_spcmd.s_uid)) && uid != 0) {
            marshall_LONG (sbp, DPM_FAILED | EACCES);
            marshall_STRING (sbp, "");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EACCES);
      }

      /* Check if any file left in space */

      flags = CNS_LIST_BEGIN;
      while ((lp = Cns_listrepset (s_token, flags, &list)) != NULL) {
            flags = CNS_LIST_CONTINUE;
            if (lp->ptime > time (0)) nbpinned++;
      }
      (void) Cns_listrepset (s_token, CNS_LIST_END, &list);
      if (nbpinned) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Space still contains pinned files");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }

      if (dpm_delete_spcmd_entry (&thip->dbfd, &rec_addr))
            RETURN (serrno);

      /* Update pool free space */

      dpm_updpoolfreespace (dpm_spcmd.poolname, dpm_spcmd.u_space);

      /* Send global status/errmsg */

      marshall_LONG (sbp, DPM_SUCCESS);
      marshall_STRING (sbp, "");
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, DPM_SUCCESS);
}

/*    dpm_srv_relfiles - to release a set of files */

dpm_srv_relfiles(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      struct dpm_req dpm_req;
      struct dpm_filestatus *filestatuses;
      char func[17];
      struct dpm_get_filereq gfr_entry;
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      int keepspace;
      char logbuf[CA_MAXSFNLEN+21];
      int n;
      int nb_file_err = 0;
      int nbgids;
      int nbsurls;
      char r_token[CA_MAXDPMTOKENLEN+1];
      char *rbp;
      dpm_dbrec_addr rec_addr;
      char repbuf[REPBUFSZ];
      char *sbp = repbuf;
      int status;
      char surl[CA_MAXSFNLEN+1];
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_relfiles");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "relfiles", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, r_token, CA_MAXDPMTOKENLEN+1)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid request token");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_LONG (rbp, nbsurls);
      unmarshall_WORD (rbp, keepspace);
      if (nbsurls <= 0) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Number of surls <= 0");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      sprintf (logbuf, "relfiles %s %d", r_token, nbsurls);
      dpm_logreq (func, logbuf);

      if (dpm_get_req_by_token (&thip->dbfd, r_token, &dpm_req, 0, NULL) < 0) {
            if (serrno == ENOENT) {
                  status = DPM_FAILED | EINVAL;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "Unknown request token");
            } else {
                  status = DPM_FAILED | serrno;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "");
            }
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, status);
      }
      if (dpm_req.r_type != 'G') {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "dpm_relfiles only valid on dpm_get req");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }

      marshall_LONG (sbp, nbsurls);
      for (i = 0; i < nbsurls; i++) {
            if (unmarshall_STRINGN (rbp, surl, CA_MAXSFNLEN+1)) {
                  status = DPM_FAILED | SENAMETOOLONG;
                  nb_file_err++;
            } else {
                  sprintf (logbuf, "relfiles %d %s", i, surl);
                  dpm_logreq (func, logbuf);
                  (void) dpm_start_tr (thip->s, &thip->dbfd);
                  if (dpm_get_gfr_by_surl (&thip->dbfd, r_token, surl,
                      &gfr_entry, 1, &rec_addr) < 0) {
                        status = DPM_FAILED | serrno;
                        (void) dpm_abort_tr (&thip->dbfd);
                        nb_file_err++;
                  } else if (dpm_relonefile (thip, &gfr_entry, &rec_addr,
                      &status) < 0) {
                        (void) dpm_abort_tr (&thip->dbfd);
                        nb_file_err++;
                  } else
                        (void) dpm_end_tr (&thip->dbfd);
            }
            n = strlen (surl) + 1;
            n += LONGSIZE;
            n++;
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_SURLST, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_STRING (sbp, surl);
            marshall_LONG (sbp, status);
            marshall_STRING (sbp, "");
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_SURLST, sbp - repbuf, repbuf);

      /* Send global status/errmsg */

      sbp = repbuf;
      if (nb_file_err != nbsurls)
            status = DPM_SUCCESS;
      else if (nbsurls != 1)
            status = DPM_FAILED | EINVAL;
      marshall_LONG (sbp, status);
      marshall_STRING (sbp, "");
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, status);
}

/*    dpm_srv_reservespace - to reserve space */

dpm_srv_reservespace(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      time_t current_time;
      struct dpm_space_reserv dpm_spcmd;
      char errstring[256];
      char func[21];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[290];
      int nb_s_gids;
      int nbgids;
      char *rbp;
      char repbuf[REPBUFSZ];
      gid_t *s_gids = NULL;
      char *sbp = repbuf;
      char tmpbuf[21];
      uid_t uid;
      char *user;
      uuid_t uuid;

      strcpy (func, "dpm_srv_reservespace");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "reservespace", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      memset (&dpm_spcmd, 0, sizeof(dpm_spcmd));
      strcpy (dpm_spcmd.client_dn, user);
      unmarshall_BYTE (rbp, dpm_spcmd.s_type);
      if (dpm_spcmd.s_type == '\0')
            dpm_spcmd.s_type = '-';
      else if (dpm_spcmd.s_type != 'V' && dpm_spcmd.s_type != 'D' &&
          dpm_spcmd.s_type != 'P' && dpm_spcmd.s_type != '-') {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid type of space");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      if (unmarshall_STRINGN (rbp, dpm_spcmd.u_token, 256)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid user space token description");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_HYPER (rbp, dpm_spcmd.t_space);
      if (dpm_spcmd.t_space & INT64_NEG) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Negative value for total space requested");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_HYPER (rbp, dpm_spcmd.g_space);
      if (dpm_spcmd.g_space & INT64_NEG) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Negative value for guaranteed space requested");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_TIME_T (rbp, dpm_spcmd.expire_time);
      if (dpm_spcmd.expire_time < 0) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Negative value for lifetime");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      if (magic >= DPM_MAGIC2) {
            unmarshall_BYTE (rbp, dpm_spcmd.ret_policy);
            unmarshall_BYTE (rbp, dpm_spcmd.ac_latency);
            unmarshall_LONG (rbp, dpm_spcmd.s_gid);
            if (unmarshall_STRINGN (rbp, dpm_spcmd.poolname, CA_MAXPOOLNAMELEN+1)) {
                  marshall_LONG (sbp, DPM_FAILED | EINVAL);
                  marshall_STRING (sbp, "Invalid pool name");
                  sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                  RETURNS (0, DPM_FAILED | EINVAL);
            }
      }
      if (magic >= DPM_MAGIC3) {
            unmarshall_LONG (rbp, nb_s_gids);
            if (nb_s_gids) {
                  if ((s_gids = malloc (nb_s_gids * sizeof(gid_t))) == NULL) {
                        marshall_LONG (sbp, DPM_FAILED | ENOMEM);
                        marshall_STRING (sbp, "");
                        sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                        RETURNS (0, DPM_FAILED | ENOMEM);
                  }
                  for (i = 0; i < nb_s_gids; i++)
                        unmarshall_LONG (rbp, s_gids[i]);
                  if (nb_s_gids > 1) {
                        for (i = 0; i < nb_s_gids; i++)
                              if (s_gids[i] == 0) {
                                    free (s_gids);
                                    marshall_LONG (sbp, DPM_FAILED | EINVAL);
                                    marshall_STRING (sbp, "Incorrect gid list");
                                    sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                                    RETURNS (0, DPM_FAILED | EINVAL);
                              }
                  }
            }
      } else
            nb_s_gids = 0;
      if (dpm_spcmd.ret_policy == '\0')
            dpm_spcmd.ret_policy = '_';
      else if (dpm_spcmd.ret_policy != 'R' && dpm_spcmd.ret_policy != 'O' &&
          dpm_spcmd.ret_policy != 'C') {
            free (s_gids);
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid retention policy");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      if (dpm_spcmd.ac_latency == '\0')
            dpm_spcmd.ac_latency = 'O';
      else if (dpm_spcmd.ac_latency != 'O' && dpm_spcmd.ac_latency != 'N') {
            free (s_gids);
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid access latency");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      if (dpm_spcmd.s_gid) {
            if (gid != 0 && dpm_spcmd.s_gid != gid) {
                  free (s_gids);
                  marshall_LONG (sbp, DPM_FAILED | EACCES);
                  marshall_STRING (sbp, "");
                  sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                  RETURNS (0, DPM_FAILED | EACCES);
            }
      } else {
#ifdef CSEC
            if (Csec_server_get_client_vo (&thip->sec_ctx))
                  dpm_spcmd.s_gid = gid;
            else
#endif
                  dpm_spcmd.s_uid = uid;
      }
      if (! nb_s_gids) {
            nb_s_gids = 1;
            if ((s_gids = malloc (sizeof(gid_t))) == NULL) {
                  marshall_LONG (sbp, DPM_FAILED | ENOMEM);
                  marshall_STRING (sbp, "");
                  sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                  RETURNS (0, DPM_FAILED | ENOMEM);
            }
            s_gids[0] = dpm_spcmd.s_gid;
      }
      (void) Cencode_groups (nb_s_gids, s_gids, dpm_spcmd.groups);
      free (s_gids);
      if (! dpm_spcmd.expire_time) {
            if (uid == 0)
                  dpm_spcmd.expire_time = 0x7FFFFFFF;
            else
                  dpm_spcmd.expire_time = DEFAULT_LIFETIME;
      }
      sprintf (logbuf, "reservespace %s %s", dpm_spcmd.u_token,
          u64tostr(dpm_spcmd.g_space, tmpbuf, 0));
      dpm_logreq (func, logbuf);

      errstring[0] = '\0';
      if (dpm_selectpool (dpm_spcmd.s_gid ? dpm_spcmd.s_gid : gid,
          dpm_spcmd.s_type, dpm_spcmd.ret_policy, dpm_spcmd.ac_latency,
          dpm_spcmd.g_space, dpm_spcmd.poolname, errstring) < 0) {
            marshall_LONG (sbp, DPM_FAILED | serrno);
            marshall_STRING (sbp, errstring);
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | serrno);
      }

      dpm_spcmd.u_space = dpm_spcmd.g_space;
      uuid_generate (uuid);
      uuid_unparse (uuid, dpm_spcmd.s_token);
      current_time = time (0);
      dpm_spcmd.assign_time = current_time;
      if (dpm_spcmd.expire_time != 0x7FFFFFFF)
            dpm_spcmd.expire_time += current_time;

      (void) dpm_start_tr (thip->s, &thip->dbfd);
      if (dpm_insert_spcmd_entry (&thip->dbfd, &dpm_spcmd) < 0)
            RETURN (serrno);

      if (dpm_spcmd.expire_time != 0x7FFFFFFF)
            dpm_spcmd.expire_time -= current_time;

      /* Send global status/errmsg/token */

      marshall_LONG (sbp, DPM_SUCCESS);
      marshall_STRING (sbp, "");
      marshall_BYTE (sbp, dpm_spcmd.s_type);
      marshall_HYPER (sbp, dpm_spcmd.t_space);
      marshall_HYPER (sbp, dpm_spcmd.g_space);
      marshall_TIME_T (sbp, dpm_spcmd.expire_time);
      marshall_STRING (sbp, dpm_spcmd.s_token);
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, DPM_SUCCESS);
}

/*    dpm_srv_rm - to delete a set of files */

/* dpm_rm_onereplica(): delete replica and associated physical
   file via rfio, and adjust pool, fs and space token sizes
   as necessary.

   check:
     if nonzero then a check for last replica/primary replica
     will be made and an unlink or change of r_type will be
     made as necessary. Must not be in a Cns transaction.

   request:
     request size from a relevent put request
     (for replicas being populated). Zero if file
     is not being populated.

   ns_filesize:
     for files not being populated, any relevant space
     token is adjusted by the ns_filesize. If passed as -1
     it means not specified and a value is taken from the ns.
*/
dpm_rm_onereplica(file_uniqueid, pfn, reqsize, status, dbfd, s_token, check, ns_filesize)
struct Cns_fileid *file_uniqueid;
char *pfn;
u_signed64 reqsize;
int *status;
struct dpm_dbfd *dbfd;
char *s_token;
int check;
u_signed64 ns_filesize;
{
      int c;
      struct Cns_filestatg cns_statbuf;
      struct dpm_space_reserv dpm_spcmd;
      u_signed64 fileid = 0;
      int i;
      int j;
      int no_unlink_access = 0;
      int nbreplicas = 0;
      time_t maxltime;
      int online = 0;
      char path[CA_MAXPATHLEN+1];
      struct Cns_filereplicax *rep_entries = NULL;
      int save_serrno;
      struct stat64 statbuf;
      int stoken_missing;

      if (strncmp (pfn, "dicom://", 8)) { /* file is online */

            online = 1;

            /* if needed fetch the filesize from the nameserver */

            if (reqsize == 0 && ns_filesize == -1) {
                  ns_filesize = 0;
                  if (Cns_statr (pfn, &cns_statbuf) >= 0) {
                        ns_filesize = cns_statbuf.filesize;
                        fileid = cns_statbuf.fileid;
                  }
            }

            /* Check is the space token is available */

            stoken_missing = 0;
            if ( !*s_token || (dpm_get_spcmd_by_token (dbfd,
                s_token, &dpm_spcmd, 0, NULL) < 0 && serrno == ENOENT)) {
                  stoken_missing++;
            }

            /* if using the request size free up corresponding amount in token */

            if (!stoken_missing && reqsize)
                  dpm_upd_u_space (dbfd, s_token, reqsize);
                  
            /* Get physical file size if not using a request size */

            statbuf.st_size = 0;
            if (reqsize == 0 && rfio_stat64 (pfn, &statbuf) < 0) {
                  c = rfio_serrno ();
                  if (c != ENOENT) {
                        *status = DPM_FAILED | c;
                        return (-1);
                  }
            }

            /* Remove the file from disk */

            if (rfio_unlink (pfn) < 0) {
                  c = rfio_serrno ();
                  if (c != ENOENT) {
                        *status = DPM_FAILED | c;
                        return (-1);
                  }
                  statbuf.st_size = 0;
            }

            /* update filesystem and pool space */

            if (stoken_missing)
                  dpm_updfreespace (pfn, reqsize ? reqsize : statbuf.st_size, "", 1);
            else
                  dpm_updfreespace (pfn, reqsize ? reqsize : statbuf.st_size, s_token, 1);

      }
      if (check && fileid == 0) {
            if (file_uniqueid == NULL) {
                  if (Cns_statr (pfn, &cns_statbuf) < 0) {
                        if (serrno == ENOENT)
                              return (0);
                        *status = DPM_FAILED | serrno;
                        return (-1);
                  }
                  fileid = cns_statbuf.fileid;
            } else
                  fileid = file_uniqueid->fileid;
      }

begin_trans:
      if (check && Cns_starttrans (NULL, NULL) < 0) {
            *status = DPM_FAILED | serrno;
            return (-1);
      }

      /* Remove the replica entry from the Name Server DB */
      if (Cns_delreplica (NULL, file_uniqueid, pfn) < 0) {
            save_serrno = serrno;
            if (check)
                  (void) Cns_aborttrans ();
            if (save_serrno != ENOENT) {
                  *status = DPM_FAILED | save_serrno;
                  return (-1);
            }
            return (0);
      }
      if (!check)
            goto upd_u_space;

      /* check if the file entry needs to be removed from the dpns */
      if (Cns_getpath (NULL, fileid, path) < 0) {
            save_serrno = serrno;
            (void) Cns_aborttrans ();
            *status = DPM_FAILED | save_serrno;
            return (-1);
      }
      if (Cns_getreplicax (path, NULL, NULL, &nbreplicas, &rep_entries) < 0) {
            save_serrno = serrno;
            (void) Cns_aborttrans ();
            *status = DPM_FAILED | save_serrno;
            return (-1);
      }
      if (nbreplicas == 0) {
            free (rep_entries);
            rep_entries = NULL;
            nbreplicas = 0;
            if (no_unlink_access || Cns_unlink (path) >= 0) {
                  if (Cns_endtrans () < 0) {
                        *status = DPM_FAILED | serrno;
                        return (-1);
                  }
                  goto upd_u_space;
            }
            save_serrno = serrno;
            (void) Cns_aborttrans ();
            if (save_serrno == EACCES) {
                  no_unlink_access = 1;
                  goto begin_trans;
            }
            *status = DPM_FAILED | save_serrno;
            return (-1);
      }

      /* some replicas remain: ensure one of them is primary */
      j = -1;
      maxltime = 0;
      for (i=0; i< nbreplicas; i++) {
            if (rep_entries[i].r_type == 'P' || rep_entries[i].status == 'N') {
                  free (rep_entries);
                  if (Cns_endtrans () < 0) {
                         *status = DPM_FAILED | serrno;
                        return (-1);
                  }
                  goto upd_u_space;
            }
            if (rep_entries[i].status != '-')
                  continue;
            if (maxltime != 0x7FFFFFFF && (rep_entries[i].ltime > maxltime ||
                rep_entries[i].ltime == 0x7FFFFFFF)) {
                  maxltime = rep_entries[i].ltime;
                  j = i;
            }
      }
      if (j>=0 && Cns_modreplicax (rep_entries[j].sfn, NULL, NULL, NULL, NULL, 'P') < 0) {
            save_serrno = serrno;
            (void) Cns_aborttrans ();
            *status = DPM_FAILED | save_serrno;
            free (rep_entries);
            return (-1);
      }
      free (rep_entries);
      if (Cns_endtrans () < 0) {
            *status = DPM_FAILED | serrno;
            return (-1);
      }

upd_u_space:
      /* If not using a request size update the space token using the
         namespace size, now that the replica has definitly been removed
      */
      if (online && *s_token && reqsize == 0)
            dpm_upd_u_space (dbfd, s_token, ns_filesize);

      return (0);
}

dpm_rm_onefile(surl, thip, status, errstring)
char *surl;
struct dpm_srv_thread_info *thip;
int *status;
char *errstring;
{
      struct Cns_fileid file_uniqueid;
      int i;
      int nbreplicas = 0;
      struct dpm_put_filereq pfr_entry;
      dpm_dbrec_addr rec_addr;
      struct Cns_filereplicax *rep_entries = NULL;
      u_signed64 reqsize;
      char *sfn;
      struct Cns_filestat cns_filestat;

      if (strncmp (surl, "srm://", 6) == 0) {
            if ((sfn = sfnfromsurl (surl)) == NULL) {
                  *status = DPM_FAILED | EINVAL;
                  strcpy (errstring, "Bad SURL syntax");
                  return (-1);
            }
      } else
            sfn = surl;

      /* Mark file and replicas as logically deleted to avoid race conditions */

      if (Cns_delete (sfn) < 0) {
            *status = DPM_FAILED | serrno;
            return (-1);
      }

      /* Try to stat the file entry in the Name Server */

      if (Cns_stat (sfn, &cns_filestat) < 0) {
            *status = DPM_FAILED | serrno;
            return (-1);
      }
      *status = 0;

      /* Must remove first the replicas from disk */

      memset (&file_uniqueid, 0, sizeof(file_uniqueid));
      if (Cns_getreplicax (sfn, NULL, NULL, &nbreplicas, &rep_entries) < 0) {
            *status = DPM_FAILED | serrno;
            return (-1);
      }
      for (i = 0; i < nbreplicas; i++) {
            file_uniqueid.fileid = (rep_entries + i)->fileid;
            reqsize = 0;
            (void) dpm_start_tr (thip->s, &thip->dbfd);
            if (dpm_get_pfr_by_pfn (&thip->dbfd, (rep_entries + i)->sfn,
                &pfr_entry, 1, &rec_addr) == 0 &&
                (pfr_entry.status == DPM_READY || pfr_entry.status == DPM_RUNNING)) {
                  pfr_entry.status = DPM_ABORTED;
                  dpm_update_pfr_entry (&thip->dbfd, &rec_addr, &pfr_entry);
                  reqsize = pfr_entry.requested_size;
            }
            dpm_end_tr (&thip->dbfd);
            dpm_rm_onereplica (&file_uniqueid, (rep_entries + i)->sfn, reqsize, status,
                &thip->dbfd, (rep_entries + i)->setname, 0, cns_filestat.filesize);
      }
      free (rep_entries);
      if (*status)
            return (-1);
      if (Cns_unlink (sfn) < 0) {
            *status = DPM_FAILED | serrno;
            return (-1);
      }
      return (0);
}

dpm_srv_rm(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      char errstring[256];
      struct dpm_filestatus *filestatuses;
      char func[16];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      char logbuf[CA_MAXSFNLEN+15];
      int n;
      int nb_file_err = 0;
      int nbgids;
      int nbsurls;
      char *rbp;
      char repbuf[REPBUFSZ];
      char *sbp = repbuf;
      int status;
      char surl[CA_MAXSFNLEN+1];
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_rm");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "rm", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      unmarshall_LONG (rbp, nbsurls);
      if (nbsurls <= 0) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Number of surls <= 0");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }

      marshall_LONG (sbp, nbsurls);
      for (i = 0; i < nbsurls; i++) {
            errstring[0] = '\0';
            if (unmarshall_STRINGN (rbp, surl, CA_MAXSFNLEN+1)) {
                  status = DPM_FAILED | SENAMETOOLONG;
                  nb_file_err++;
            } else {
                  sprintf (logbuf, "rm %d %s", i, surl);
                  dpm_logreq (func, logbuf);
                  if (dpm_rm_onefile (surl, thip, &status, errstring) < 0)
                        nb_file_err++;
            }

            n = strlen (surl) + 1;
            n += LONGSIZE;
            n += strlen (errstring) + 1;
            if (sbp - repbuf + n > REPBUFSZ) {
                  sendrep (thip->s, MSG_SURLST, sbp - repbuf, repbuf);
                  sbp = repbuf;
            }
            marshall_STRING (sbp, surl);
            marshall_LONG (sbp, status);
            marshall_STRING (sbp, errstring);
      }
      if (sbp > repbuf)
            sendrep (thip->s, MSG_SURLST, sbp - repbuf, repbuf);

      /* Send global status/errmsg */

      sbp = repbuf;
      if (nb_file_err != nbsurls)
            status = DPM_SUCCESS;
      else if (nbsurls != 1)
            status = DPM_FAILED | EINVAL;
      marshall_LONG (sbp, status);
      if (nb_file_err == 1 && nbsurls == 1) {
            marshall_STRING (sbp, errstring);
      } else {
            marshall_STRING (sbp, "");
      }
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, status);
}

/*    dpm_srv_rmfs - remove a filesystem from a disk pool definition */

dpm_srv_rmfs(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      char fs[80];
      struct dpm_fs fs_entry;
      char func[16];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      char logbuf[CA_MAXHOSTNAMELEN+86];
      int nbgids;
      char *rbp;
      dpm_dbrec_addr rec_addr;
      char server[CA_MAXHOSTNAMELEN+1];
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_rmfs");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "rmfs", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, server, CA_MAXHOSTNAMELEN+1) < 0)
            RETURN (EINVAL);
      if (unmarshall_STRINGN (rbp, fs, 80) < 0)
            RETURN (EINVAL);
      sprintf (logbuf, "rmfs %s %s", server, fs);
      dpm_logreq (func, logbuf);

      if (uid)
            RETURN (EACCES);

      if (strchr (server, '.') == NULL) {
            if (strlen (server) + strlen (localdomain) + 1 > CA_MAXHOSTNAMELEN)
                  RETURN (EINVAL);
            strcat (server, ".");
            strcat (server, localdomain);
      }

      /* Update configuration in memory */

      if (dpm_rmfsfrompoolconf (server, fs) < 0)
            RETURN (serrno);

      /* Update configuration in DB */

      (void) dpm_start_tr (thip->s, &thip->dbfd);
      if (dpm_get_fs_entry (&thip->dbfd, server, fs, &fs_entry,
          1, &rec_addr))
            RETURN (serrno);
      if (dpm_delete_fs_entry (&thip->dbfd, &rec_addr))
            RETURN (serrno);
      RETURN (0);
}

/*    dpm_srv_rmpool - remove a disk pool definition */

dpm_srv_rmpool(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      char func[16];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      char logbuf[CA_MAXPOOLNAMELEN+8];
      int nbgids;
      struct dpm_pool pool_entry;
      char poolname[CA_MAXPOOLNAMELEN+1];
      char *rbp;
      dpm_dbrec_addr rec_addr;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_rmpool");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "rmpool", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, poolname, CA_MAXPOOLNAMELEN+1) < 0)
            RETURN (EINVAL);
      sprintf (logbuf, "rmpool %s", poolname);
      dpm_logreq (func, logbuf);

      if (uid)
            RETURN (EACCES);

      /* Update configuration in memory */

      if (dpm_rmpoolfrompoolconf (poolname) < 0)
            RETURN (serrno);
      (void) dpm_stop_gc (poolname);

      /* Update configuration in DB */

      (void) dpm_start_tr (thip->s, &thip->dbfd);
      if (dpm_get_pool_entry (&thip->dbfd, poolname, &pool_entry,
          1, &rec_addr))
            RETURN (serrno);
      free (pool_entry.gids);
      if (dpm_delete_pool_entry (&thip->dbfd, &rec_addr))
            RETURN (serrno);
      RETURN (0);
}

/*    dpm_srv_shutdown - shutdown the Disk Pool Manager server */

dpm_srv_shutdown(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      int force = 0;
      char func[17];
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int nbgids;
      char *rbp;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_shutdown");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "shutdown", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      unmarshall_WORD (rbp, force);

      being_shutdown = force + 1;
      RETURN (0);
}

dpm_upd_u_space(struct dpm_dbfd *dbfd, char *s_token, signed64 incr)
{
      struct dpm_space_reserv dpm_spcmd;
      dpm_dbrec_addr rec_addrs;
      char tmpbuf0[21];
      char tmpbuf1[21];

      (void) dpm_start_tr (0, dbfd);
      if (dpm_get_spcmd_by_token (dbfd, s_token, &dpm_spcmd, 1, &rec_addrs) < 0) {
            dpm_abort_tr (dbfd);
            return (-1);
      }
      dpm_spcmd.u_space += incr;
      if (dpm_update_spcmd_entry (dbfd, &rec_addrs, &dpm_spcmd) < 0) {
            dpm_abort_tr (dbfd);
            return (-1);
      }
      (void) dpm_end_tr (dbfd);
      dpmlogit ("dpm_upd_u_space", "%s: incr=%s, u_space=%s\n", s_token,
          i64tostr (incr, tmpbuf0, 0), i64tostr (dpm_spcmd.u_space, tmpbuf1, 0));
      return (0);
}

/*    dpm_srv_updatefilestatus - update file status from a DPM backend */

dpm_srv_updatefilestatus(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      int bol = 1;
      int c;
      time_t current_time;
      DBLISTPTR dblistptr;
      struct dpm_req dpm_req;
      char errmsg[256];
      struct Cns_fileid file_uniqueid;
      char func[25];
      struct dpm_get_filereq gfr_entry;
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int maxpintime;
      int nb_file_err = 0;
      int nbgids;
      struct dpm_get_filereq old_gfr_entry;
      char pfn[CA_MAXSFNLEN+1];
      struct dpm_put_filereq pfr_entry;
      char r_token[CA_MAXDPMTOKENLEN+1];
      char r_type;
      char *rbp;
      dpm_dbrec_addr rec_addr;
      dpm_dbrec_addr rec_addrf;
      char server[CA_MAXHOSTNAMELEN+1];
      struct Cns_filestatg statbuf;
      int status;
      char surl[CA_MAXSFNLEN+1];
      char tmpbuf[256];
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_updatefilestatus");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "updatefilestatus", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      unmarshall_BYTE (rbp, r_type);
      if (r_type != 'B' && r_type != 'G' && r_type != 'P')
            RETURN (EINVAL);
        if (unmarshall_STRINGN (rbp, r_token, CA_MAXDPMTOKENLEN+1))
            RETURN (EINVAL);
      if (unmarshall_STRINGN (rbp, surl, CA_MAXSFNLEN+1))
            RETURN (SENAMETOOLONG);
      if (unmarshall_STRINGN (rbp, server, CA_MAXHOSTNAMELEN+1))
            RETURN (EINVAL);
      if (unmarshall_STRINGN (rbp, pfn, CA_MAXSFNLEN+1))
            RETURN (SENAMETOOLONG);
      unmarshall_LONG (rbp, status);
        if (unmarshall_STRINGN (rbp, errmsg, 256))
            RETURN (EINVAL);

      dpmlogit (func, "r_token = %s\n", r_token);
      dpmlogit (func, "surl = %s\n", surl);
      dpmlogit (func, "status = %s\n", status2str (status, tmpbuf));
      if (r_type == 'B' || r_type == 'G') {
            if (dpm_get_gfr_by_surl (&thip->dbfd, r_token, surl, &gfr_entry,
                0, NULL) < 0)
                  RETURN (serrno);
            if ((gfr_entry.status & 0xF000) != DPM_TO_BE_RECALLED)
                  RETURN (0);
            gfr_entry.status = status;
            if (status == DPM_READY) {

                  /* Get fileid and filesize */

                  if (Cns_statr (pfn, &statbuf) < 0) {
                        gfr_entry.status = DPM_FAILED | serrno;
                        goto upd_gfr;
                  }
                  if (r_type == 'G') {
                        strcpy (file_uniqueid.server, dpnshost);
                        file_uniqueid.fileid = statbuf.fileid;

                        /* Update last access date in DPNS master table */

                        (void) Cns_setatime (NULL, &file_uniqueid);

                        /* Get pintime */

                        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 (Cns_setptime (pfn, gfr_entry.lifetime) < 0) {
                              gfr_entry.status = DPM_FAILED | serrno;
                              goto upd_gfr;
                        }
                        strcpy (gfr_entry.server, server);
                        strcpy (gfr_entry.pfn, pfn);
                        gfr_entry.status = DPM_READY;
                  } else
                        gfr_entry.status = DPM_SUCCESS;
                  gfr_entry.actual_size = statbuf.filesize;
            }
upd_gfr:
            if (! *gfr_entry.errstring)
                  strcpy (gfr_entry.errstring, errmsg);
            (void) dpm_start_tr (thip->s, &thip->dbfd);
            if (dpm_get_gfr_by_fullid (&thip->dbfd, r_token, gfr_entry.f_ordinal,
                &old_gfr_entry, 1, &rec_addrf) < 0)
                  RETURN (serrno);
            if ((old_gfr_entry.status & 0xF000) == DPM_TO_BE_RECALLED)
                  (void) dpm_update_gfr_entry (&thip->dbfd, &rec_addrf,
                      &gfr_entry);
            (void) dpm_end_tr (&thip->dbfd);

            /* Check if it was the last file to be processed in this request */

            while ((c = dpm_list_gfr_entry (&thip->dbfd, bol, r_token,
                &gfr_entry, 0, NULL, 0, &dblistptr)) == 0) {
                  bol = 0;
                  if ((gfr_entry.status & 0xF000) == DPM_TO_BE_RECALLED) break;
                  if ((gfr_entry.status & 0xF000) == DPM_FAILED)
                        nb_file_err++;
            }
            (void) dpm_list_gfr_entry (&thip->dbfd, bol, r_token,
                &gfr_entry, 0, NULL, 1, &dblistptr);  /* free res */

            if (c > 0) {      /* 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,
                      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);
            }
      } else {
            if (dpm_get_pfr_by_surl (&thip->dbfd, r_token, surl, &pfr_entry,
                0, NULL) < 0)
                  RETURN (serrno);
            if (pfr_entry.status != DPM_TO_BE_MIGRATED)
                  RETURN (0);
            if (status == DPM_SUCCESS) {

                  /* Get fileid */

                  if (Cns_statr (pfn, &statbuf) < 0) {
                  }
                  strcpy (file_uniqueid.server, dpnshost);
                  file_uniqueid.fileid = statbuf.fileid;

                  /* Add replica entry */

                  if (Cns_addreplicax (NULL, &file_uniqueid, server, pfn,
                      'N', 'P', NULL, NULL, 'S', NULL) < 0) {
                  }
            }
      }
      RETURN (0);
}

/*    dpm_srv_updatespace - to update space */

dpm_srv_updatespace(magic, req_data, clienthost, thip)
int magic;
char *req_data;
char *clienthost;
struct dpm_srv_thread_info *thip;
{
      time_t current_time;
      struct dpm_space_reserv dpm_spcmd;
      char errstring[256];
      char func[20];
      u_signed64 g_space;
      gid_t gid;
      gid_t *gids;
      char groups[256];
      int i;
      signed64 incr;
      time_t lifetime;
      char logbuf[CA_MAXDPMTOKENLEN+13];
      int nb_s_gids;
      int nbgids;
      char *rbp;
      dpm_dbrec_addr rec_addr;
      char repbuf[REPBUFSZ];
      gid_t *s_gids = NULL;
      char s_token[CA_MAXDPMTOKENLEN+1];
      char *sbp = repbuf;
      int status;
      u_signed64 t_space;
      uid_t uid;
      char *user;

      strcpy (func, "dpm_srv_updatespace");
      rbp = req_data;
      unmarshall_LONG (rbp, uid);
      unmarshall_LONG (rbp, gid);
      get_client_actual_id (thip, &uid, &gid, &nbgids, &gids, &user);
      dpmlogit (func, DP092, "updatespace", user, uid, Cencode_groups (nbgids, gids, groups), clienthost);
      if (unmarshall_STRINGN (rbp, s_token, CA_MAXDPMTOKENLEN+1)) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Invalid space token");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_HYPER (rbp, t_space);
      if ((t_space & INT64_NEG) && t_space != -1) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Negative value for total space requested");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_HYPER (rbp, g_space);
      if ((g_space & INT64_NEG) && g_space != -1) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Negative value for guaranteed space requested");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      unmarshall_TIME_T (rbp, lifetime);
      if (lifetime < 0 && lifetime != -1) {
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Negative value for lifetime");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      if (magic >= DPM_MAGIC2) {
            unmarshall_LONG (rbp, nb_s_gids);
            if (nb_s_gids > 0) {
                  if ((s_gids = malloc (nb_s_gids * sizeof(gid_t))) == NULL) {
                        marshall_LONG (sbp, DPM_FAILED | ENOMEM);
                        marshall_STRING (sbp, "");
                        sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                        RETURNS (0, DPM_FAILED | ENOMEM);
                  }
                  for (i = 0; i < nb_s_gids; i++)
                        unmarshall_LONG (rbp, s_gids[i]);
                  if (nb_s_gids > 1) {
                        for (i = 0; i < nb_s_gids; i++)
                              if (s_gids[i] == 0) {
                                    free (s_gids);
                                    marshall_LONG (sbp, DPM_FAILED | EINVAL);
                                    marshall_STRING (sbp, "Incorrect gid list");
                                    sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                                    RETURNS (0, DPM_FAILED | EINVAL);
                              }
                  }
            }
      } else
            nb_s_gids = -1;
      sprintf (logbuf, "updatespace %s", s_token);
      dpm_logreq (func, logbuf);

      /* start transaction */

      (void) dpm_start_tr (thip->s, &thip->dbfd);

      if (dpm_get_spcmd_by_token (&thip->dbfd, s_token, &dpm_spcmd,
          1, &rec_addr) < 0) {
            free (s_gids);
            if (serrno == ENOENT) {
                  status = DPM_FAILED | EINVAL;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "Unknown space token");
            } else {
                  status = DPM_FAILED | serrno;
                  marshall_LONG (sbp, status);
                  marshall_STRING (sbp, "");
            }
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, status);
      }
      if (((dpm_spcmd.s_gid && ! Cgroupmatch (dpm_spcmd.s_gid, nbgids, gids)) ||
          (dpm_spcmd.s_uid && uid != dpm_spcmd.s_uid)) && uid != 0) {
            free (s_gids);
            marshall_LONG (sbp, DPM_FAILED | EACCES);
            marshall_STRING (sbp, "");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EACCES);
      }

      if (dpm_spcmd.expire_time < time (0)) {
            free (s_gids);
            marshall_LONG (sbp, DPM_FAILED | EINVAL);
            marshall_STRING (sbp, "Space lifetime expired");
            sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
            RETURNS (0, DPM_FAILED | EINVAL);
      }
      if (! lifetime) {
            if (uid == 0)
                  lifetime = 0x7FFFFFFF;
            else
                  lifetime = DEFAULT_LIFETIME;
      }
      if (t_space != -1)
            dpm_spcmd.t_space = t_space;
      if (g_space != -1) {
            incr = g_space - dpm_spcmd.g_space;
            if (incr < 0) {
                  if (dpm_spcmd.u_space < 0 || -incr > dpm_spcmd.u_space) {
                        free (s_gids);
                        marshall_LONG (sbp, DPM_FAILED | EINVAL);
                        marshall_STRING (sbp, "requested size < currently used space");
                        sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                        RETURNS (0, DPM_FAILED | EINVAL);
                  }
                  dpm_updpoolfreespace (dpm_spcmd.poolname, -incr);
            } else if (incr > 0) {  /* need to allocate more space in same pool */
                  errstring[0] = '\0';
                  if (dpm_selectpool (gid, dpm_spcmd.s_type, dpm_spcmd.ret_policy,
                      dpm_spcmd.ac_latency, incr, dpm_spcmd.poolname, errstring) < 0) {
                        free (s_gids);
                        marshall_LONG (sbp, DPM_FAILED | serrno);
                        marshall_STRING (sbp, errstring);
                        sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
                        RETURNS (0, DPM_FAILED | serrno);
                  }
            }
            dpm_spcmd.g_space = g_space;
            dpm_spcmd.u_space += incr;
      }

      current_time = time (0);
      if (lifetime != -1) {
            if (lifetime != 0x7FFFFFFF)
                  lifetime += current_time;
            dpm_spcmd.expire_time = lifetime;
      } else
            lifetime = dpm_spcmd.expire_time;
      if (nb_s_gids != -1) {
            dpm_spcmd.s_gid = s_gids[0];
            (void) Cencode_groups (nb_s_gids, s_gids, dpm_spcmd.groups);
            free (s_gids);
      }

      if (dpm_update_spcmd_entry (&thip->dbfd, &rec_addr, &dpm_spcmd))
            RETURN (serrno);

      if (lifetime != 0x7FFFFFFF)
            lifetime -= current_time;

      /* Send global status/errmsg */

      marshall_LONG (sbp, DPM_SUCCESS);
      marshall_STRING (sbp, "");
      marshall_HYPER (sbp, dpm_spcmd.t_space);
      marshall_HYPER (sbp, dpm_spcmd.g_space);
      marshall_TIME_T (sbp, lifetime);
      sendrep (thip->s, MSG_DATA, sbp - repbuf, repbuf);
      RETURNS (0, DPM_SUCCESS);
}

Generated by  Doxygen 1.6.0   Back to index