Exemple #1
0
char *
parse_name (char const *s, int strip_leading, char const **endp)
{
  char *ret;

  while (ISSPACE ((unsigned char) *s))
    s++;
  if (*s == '"')
    ret = parse_c_string (s, endp);
  else
    {
      char const *t;

      for (t = s; *t && ! ISSPACE ((unsigned char) *t); t++)
	/* do nothing*/ ;
      ret = savebuf (s, t - s + 1);
      ret[t - s] = 0;
      if (endp)
	*endp = t;
    }
  if (! strip_leading_slashes (ret, strip_leading))
    {
      free (ret);
      ret = NULL;
    }
  return ret;
}
/*---------------------------------------------------------------*/
int main(int argc, char **argv) {
  SDCMFILEINFO **sdfi_list;
  SDCMFILEINFO  *sdfi=NULL;
  int nlist;
  int NRuns;
  int nthfile;
  char *fname, *psname, *protoname;
  int PrevRunNo;

  Progname = argv[0] ;
  argc --;
  argv++;
  ErrorInit(NULL, NULL, NULL) ;
  DiagInit(NULL, NULL, NULL) ;

  if (argc == 0) usage_exit();

  cmdline = argv2cmdline(argc,argv);

  parse_commandline(argc, argv);
  check_options();

  uname(&uts);
  getcwd(cwd,2000);
  fprintf(stdout,"%s\n",vcid);
  fprintf(stdout,"cwd %s\n",cwd);
  fprintf(stdout,"cmdline %s\n",cmdline);
  fprintf(stdout,"sysname  %s\n",uts.sysname);
  fprintf(stdout,"hostname %s\n",uts.nodename);
  fprintf(stdout,"machine  %s\n",uts.machine);
  fprintf(stdout,"user     %s\n",VERuser());

  strip_leading_slashes(sdicomdir);

  /* open the output file, or set output stream to stdout */
  if (outfile != NULL) {
    outstream = fopen(outfile,"w");
    if (outstream == NULL) {
      fprintf(stderr,"ERROR: could not open %s for writing\n",outfile);
      exit(1);
    }
  } else outstream = stdout;

  /* Get all the Siemens DICOM files from this directory */
  fprintf(stderr,"INFO: scanning path to Siemens DICOM DIR:\n   %s\n",
          sdicomdir);
  sdfi_list = ScanSiemensDCMDir(sdicomdir, &nlist);
  if (sdfi_list == NULL) {
    fprintf(stderr,"ERROR: scanning directory %s\n",sdicomdir);
    exit(1);
  }
  printf("INFO: found %d Siemens files\n",nlist);
  printf("%s\n",sdfi_list[0]->NumarisVer);
  tmpstring = sdcmExtractNumarisVer(sdfi_list[0]->NumarisVer, &Maj, &Min, &MinMin);
  if (tmpstring == NULL) free(tmpstring);
  else {
    if ((Min == 1 && MinMin <= 6) && Maj < 4) {
      // This should only be run for pretty old data. I've lost
      // track as to which versions should do this. With Maj<4,
      // I'm pretty sure that this section of code will never
      // be run.  It might need to be run with version 4VA16
      // and earlier. Note: this same code is in DICOMRead.c
      printf("Computing TR with number of slices\n");
      TRSlice = 1;
    }
  }

  /* Sort the files by Series, Slice Position, and Image Number */
  printf("Sorting\n");
  fflush(stdout);
  fflush(stderr);
  SortSDCMFileInfo(sdfi_list,nlist);

  /* Assign run numbers to each file (count number of runs)*/
  if (sortbyrun) {
    fprintf(stderr,"Assigning Run Numbers\n");
    fflush(stderr);
    NRuns = sdfiAssignRunNo2(sdfi_list, nlist);
    if (NRuns == 0) {
      fprintf(stderr,"ERROR: sorting runs\n");
      fflush(stderr);
      exit(1);
    }
  }

  PrevRunNo = -1;
  for (nthfile = 0; nthfile < nlist; nthfile++) {

    sdfi = sdfi_list[nthfile];

    if (summarize && PrevRunNo == sdfi->RunNo) continue;
    PrevRunNo = sdfi->RunNo;

    sdfi->RepetitionTime /= 1000.0;

    // Old version of Siemens software had reptime as time between
    // slices. New has reptime as time between volumes.
    // Code (above) looks at version and does the right thing.
    if (sdfi->IsMosaic && TRSlice) sdfi->RepetitionTime *= sdfi->VolDim[2];

    fname     = fio_basename(sdfi->FileName,NULL);
    psname    = strip_white_space(sdfi->PulseSequence);
    protoname = strip_white_space(sdfi->ProtocolName);

    fprintf(outstream,
            "%4d %s  %3d %d  %4d %d  %3d %3d %3d %3d  %8.4f %8.4f %s\n",
            nthfile+1, fname,
            sdfi->SeriesNo, sdfi->ErrorFlag,
            sdfi->ImageNo, sdfi->IsMosaic,
            sdfi->VolDim[0], sdfi->VolDim[1], sdfi->VolDim[2], sdfi->NFrames,
            sdfi->RepetitionTime, sdfi->EchoTime,
            protoname);
    fflush(outstream);
    free(fname);
    free(psname);
    free(protoname);
  }

  while (nlist--) {
    // free strings
    free(sdfi_list[nlist]->FileName);
    free(sdfi_list[nlist]->StudyDate);
    free(sdfi_list[nlist]->StudyTime);
    free(sdfi_list[nlist]->PatientName);
    free(sdfi_list[nlist]->SeriesTime);
    free(sdfi_list[nlist]->AcquisitionTime);
    free(sdfi_list[nlist]->ScannerModel);
    free(sdfi_list[nlist]->NumarisVer);
    free(sdfi_list[nlist]->PulseSequence);
    free(sdfi_list[nlist]->ProtocolName);
    free(sdfi_list[nlist]->PhEncDir);
    //
    free(sdfi_list[nlist]);
  }
  free(sdfi_list);

  if (outfile != NULL) fclose(outstream);

  fflush(stdout);
  fflush(stderr);
  exit(0);
  return(0);
}
Exemple #3
0
void
fetchname (char const *at, int strip_leading, char **pname,
	   char **ptimestr, struct timespec *pstamp)
{
    char *name;
    const char *t;
    char *timestr = NULL;
    struct timespec stamp;

    stamp.tv_sec = -1;
    stamp.tv_nsec = 0;

    while (ISSPACE ((unsigned char) *at))
	at++;
    if (debug & 128)
	say ("fetchname %s %d\n", at, strip_leading);

    if (*at == '"')
      {
	name = parse_c_string (at, &t);
	if (! name)
	  {
	    if (debug & 128)
	      say ("ignoring malformed filename %s\n", quotearg (at));
	    return;
	  }
      }
    else
      {
	for (t = at;  *t;  t++)
	  {
	    if (ISSPACE ((unsigned char) *t))
	      {
		/* Allow file names with internal spaces,
		   but only if a tab separates the file name from the date.  */
		char const *u = t;
		while (*u != '\t' && ISSPACE ((unsigned char) u[1]))
		  u++;
		if (*u != '\t' && (strchr (u + 1, pstamp ? '\t' : '\n')))
		  continue;
		break;
	      }
	  }
	name = savebuf (at, t - at + 1);
	name[t - at] = 0;
      }

    /* If the name is "/dev/null", ignore the name and mark the file
       as being nonexistent.  The name "/dev/null" appears in patches
       regardless of how NULL_DEVICE is spelled.  */
    if (strcmp (name, "/dev/null") == 0)
      {
	free (name);
	if (pstamp)
	  {
	    pstamp->tv_sec = 0;
	    pstamp->tv_nsec = 0;
	  }
	return;
      }

    /* Ignore the name if it doesn't have enough slashes to strip off.  */
    if (! strip_leading_slashes (name, strip_leading))
      {
	free (name);
	return;
      }

    if (ptimestr)
      {
	char const *u = t + strlen (t);

	if (u != t && *(u-1) == '\n')
	  u--;
	if (u != t && *(u-1) == '\r')
	  u--;
	timestr = savebuf (t, u - t + 1);
	timestr[u - t] = 0;
      }

      if (*t != '\n')
	{
	  if (! pstamp)
	    {
	      free (name);
	      free (timestr);
	      return;
	    }

	  if (set_time | set_utc)
	    get_date (&stamp, t, &initial_time);
	  else
	    {
	      /* The head says the file is nonexistent if the
		 timestamp is the epoch; but the listed time is
		 local time, not UTC, and POSIX.1 allows local
		 time offset anywhere in the range -25:00 <
		 offset < +26:00.  Match any time in that range.  */
	      const struct timespec lower = { -25L * 60 * 60 },
				    upper = {  26L * 60 * 60 };
	      if (get_date (&stamp, t, &initial_time)
		  && timespec_cmp (stamp, lower) > 0
		  && timespec_cmp (stamp, upper) < 0) {
		      stamp.tv_sec = 0;
		      stamp.tv_nsec = 0;
	      }
	    }
	}

    free (*pname);
    *pname = name;
    if (ptimestr)
      {
	free (*ptimestr);
	*ptimestr = timestr;
      }
    if (pstamp)
      *pstamp = stamp;
}
Exemple #4
0
/*-
 * The logic here for -C <dir> attempts to avoid
 * chdir() as long as possible.  For example:
 * "-C /foo -C /bar file"          needs chdir("/bar") but not chdir("/foo")
 * "-C /foo -C bar file"           needs chdir("/foo/bar")
 * "-C /foo -C bar /file1"         does not need chdir()
 * "-C /foo -C bar /file1 file2"   needs chdir("/foo/bar") before file2
 *
 * The only correct way to handle this is to record a "pending" chdir
 * request and combine multiple requests intelligently until we
 * need to process a non-absolute file.  set_chdir() adds the new dir
 * to the pending list; do_chdir() actually executes any pending chdir.
 *
 * This way, programs that build tar command lines don't have to worry
 * about -C with non-existent directories; such requests will only
 * fail if the directory must be accessed.
 *
 */
void
set_chdir(struct bsdtar *bsdtar, const char *newdir)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
	if (newdir[0] == '/' || newdir[0] == '\\' ||
	    /* Detect this type, for example, "C:\" or "C:/" */
	    (((newdir[0] >= 'a' && newdir[0] <= 'z') ||
	      (newdir[0] >= 'A' && newdir[0] <= 'Z')) &&
	    newdir[1] == ':' && (newdir[2] == '/' || newdir[2] == '\\'))) {
#else
	if (newdir[0] == '/') {
#endif
		/* The -C /foo -C /bar case; dump first one. */
		free(bsdtar->pending_chdir);
		bsdtar->pending_chdir = NULL;
	}
	if (bsdtar->pending_chdir == NULL)
		/* Easy case: no previously-saved dir. */
		bsdtar->pending_chdir = strdup(newdir);
	else {
		/* The -C /foo -C bar case; concatenate */
		char *old_pending = bsdtar->pending_chdir;
		size_t old_len = strlen(old_pending);
		bsdtar->pending_chdir = malloc(old_len + strlen(newdir) + 2);
		if (old_pending[old_len - 1] == '/')
			old_pending[old_len - 1] = '\0';
		if (bsdtar->pending_chdir != NULL)
			sprintf(bsdtar->pending_chdir, "%s/%s",
			    old_pending, newdir);
		free(old_pending);
	}
	if (bsdtar->pending_chdir == NULL)
		lafe_errc(1, errno, "No memory");
}

void
do_chdir(struct bsdtar *bsdtar)
{
	if (bsdtar->pending_chdir == NULL)
		return;

	if (chdir(bsdtar->pending_chdir) != 0) {
		lafe_errc(1, 0, "could not chdir to '%s'\n",
		    bsdtar->pending_chdir);
	}
	free(bsdtar->pending_chdir);
	bsdtar->pending_chdir = NULL;
}

static const char *
strip_components(const char *p, int elements)
{
	/* Skip as many elements as necessary. */
	while (elements > 0) {
		switch (*p++) {
		case '/':
#if defined(_WIN32) && !defined(__CYGWIN__)
		case '\\': /* Support \ path sep on Windows ONLY. */
#endif
			elements--;
			break;
		case '\0':
			/* Path is too short, skip it. */
			return (NULL);
		}
	}

	/* Skip any / characters.  This handles short paths that have
	 * additional / termination.  This also handles the case where
	 * the logic above stops in the middle of a duplicate //
	 * sequence (which would otherwise get converted to an
	 * absolute path). */
	for (;;) {
		switch (*p) {
		case '/':
#if defined(_WIN32) && !defined(__CYGWIN__)
		case '\\': /* Support \ path sep on Windows ONLY. */
#endif
			++p;
			break;
		case '\0':
			return (NULL);
		default:
			return (p);
		}
	}
}

static const char*
strip_leading_slashes(const char *p)
{

	/* Remove leading "/../", "//", etc. */
	while (p[0] == '/' || p[0] == '\\') {
		if (p[1] == '.' && p[2] == '.' && (
		    p[3] == '/' || p[3] == '\\')) {
			p += 3; /* Remove "/..", leave "/" for next pass. */
		} else
			p += 1; /* Remove "/". */
	}
	return (p);
}

/*
 * Handle --strip-components and any future path-rewriting options.
 * Returns non-zero if the pathname should not be extracted.
 *
 * TODO: Support pax-style regex path rewrites.
 */
int
edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
{
	const char *name = archive_entry_pathname(entry);
#if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H)
	char *subst_name;
	int r;

	r = apply_substitution(bsdtar, name, &subst_name, 0, 0);
	if (r == -1) {
		lafe_warnc(0, "Invalid substitution, skipping entry");
		return 1;
	}
	if (r == 1) {
		archive_entry_copy_pathname(entry, subst_name);
		if (*subst_name == '\0') {
			free(subst_name);
			return -1;
		} else
			free(subst_name);
		name = archive_entry_pathname(entry);
	}

	if (archive_entry_hardlink(entry)) {
		r = apply_substitution(bsdtar, archive_entry_hardlink(entry), &subst_name, 0, 1);
		if (r == -1) {
			lafe_warnc(0, "Invalid substitution, skipping entry");
			return 1;
		}
		if (r == 1) {
			archive_entry_copy_hardlink(entry, subst_name);
			free(subst_name);
		}
	}
	if (archive_entry_symlink(entry) != NULL) {
		r = apply_substitution(bsdtar, archive_entry_symlink(entry), &subst_name, 1, 0);
		if (r == -1) {
			lafe_warnc(0, "Invalid substitution, skipping entry");
			return 1;
		}
		if (r == 1) {
			archive_entry_copy_symlink(entry, subst_name);
			free(subst_name);
		}
	}
#endif

	/* Strip leading dir names as per --strip-components option. */
	if (bsdtar->strip_components > 0) {
		const char *linkname = archive_entry_hardlink(entry);

		name = strip_components(name, bsdtar->strip_components);
		if (name == NULL)
			return (1);

		if (linkname != NULL) {
			linkname = strip_components(linkname,
			    bsdtar->strip_components);
			if (linkname == NULL)
				return (1);
			archive_entry_copy_hardlink(entry, linkname);
		}
	}

	/* By default, don't write or restore absolute pathnames. */
	if (!bsdtar->option_absolute_paths) {
		const char *rp, *p = name;
		int slashonly = 1;

		/* Remove leading "//./" or "//?/" or "//?/UNC/"
		 * (absolute path prefixes used by Windows API) */
		if ((p[0] == '/' || p[0] == '\\') &&
		    (p[1] == '/' || p[1] == '\\') &&
		    (p[2] == '.' || p[2] == '?') &&
		    (p[3] == '/' || p[3] == '\\'))
		{
			if (p[2] == '?' &&
			    (p[4] == 'U' || p[4] == 'u') &&
			    (p[5] == 'N' || p[5] == 'n') &&
			    (p[6] == 'C' || p[6] == 'c') &&
			    (p[7] == '/' || p[7] == '\\'))
				p += 8;
			else
				p += 4;
			slashonly = 0;
		}
		do {
			rp = p;
			/* Remove leading drive letter from archives created
			 * on Windows. */
			if (((p[0] >= 'a' && p[0] <= 'z') ||
			     (p[0] >= 'A' && p[0] <= 'Z')) &&
				 p[1] == ':') {
				p += 2;
				slashonly = 0;
			}
			p = strip_leading_slashes(p);
		} while (rp != p);

		if (p != name && !bsdtar->warned_lead_slash) {
			/* Generate a warning the first time this happens. */
			if (slashonly)
				lafe_warnc(0,
				    "Removing leading '%c' from member names",
				    name[0]);
			else
				lafe_warnc(0,
				    "Removing leading drive letter from "
				    "member names");
			bsdtar->warned_lead_slash = 1;
		}

		/* Special case: Stripping everything yields ".". */
		if (*p == '\0')
			name = ".";
		else
			name = p;

		p = archive_entry_hardlink(entry);
		if (p != NULL) {
			rp = strip_leading_slashes(p);
			if (rp == '\0')
				return (1);
			if (rp != p) {
				char *linkname = strdup(rp);

				archive_entry_copy_hardlink(entry, linkname);
				free(linkname);
			}
		}
	} else {
		/* Strip redundant leading '/' characters. */
		while (name[0] == '/' && name[1] == '/')
			name++;
	}

	/* Safely replace name in archive_entry. */
	if (name != archive_entry_pathname(entry)) {
		char *q = strdup(name);
		archive_entry_copy_pathname(entry, q);
		free(q);
	}
	return (0);
}

/*
 * It would be nice to just use printf() for formatting large numbers,
 * but the compatibility problems are quite a headache.  Hence the
 * following simple utility function.
 */
const char *
tar_i64toa(int64_t n0)
{
	static char buff[24];
	uint64_t n = n0 < 0 ? -n0 : n0;
	char *p = buff + sizeof(buff);

	*--p = '\0';
	do {
		*--p = '0' + (int)(n % 10);
	} while (n /= 10);
	if (n0 < 0)
		*--p = '-';
	return p;
}

/*
 * Like strcmp(), but try to be a little more aware of the fact that
 * we're comparing two paths.  Right now, it just handles leading
 * "./" and trailing '/' specially, so that "a/b/" == "./a/b"
 *
 * TODO: Make this better, so that "./a//b/./c/" == "a/b/c"
 * TODO: After this works, push it down into libarchive.
 * TODO: Publish the path normalization routines in libarchive so
 * that bsdtar can normalize paths and use fast strcmp() instead
 * of this.
 *
 * Note: This is currently only used within write.c, so should
 * not handle \ path separators.
 */

int
pathcmp(const char *a, const char *b)
{
	/* Skip leading './' */
	if (a[0] == '.' && a[1] == '/' && a[2] != '\0')
		a += 2;
	if (b[0] == '.' && b[1] == '/' && b[2] != '\0')
		b += 2;
	/* Find the first difference, or return (0) if none. */
	while (*a == *b) {
		if (*a == '\0')
			return (0);
		a++;
		b++;
	}
	/*
	 * If one ends in '/' and the other one doesn't,
	 * they're the same.
	 */
	if (a[0] == '/' && a[1] == '\0' && b[0] == '\0')
		return (0);
	if (a[0] == '\0' && b[0] == '/' && b[1] == '\0')
		return (0);
	/* They're really different, return the correct sign. */
	return (*(const unsigned char *)a - *(const unsigned char *)b);
}