Пример #1
0
int
_gst_set_file_access_times (const char *name, long new_atime, long new_mtime)
{
  int result;
#if defined HAVE_UTIMES
  struct timeval times[2];
  times[0].tv_sec = new_atime + 86400 * 10957;
  times[1].tv_sec = new_mtime + 86400 * 10957;
  times[0].tv_usec = times[1].tv_usec = 0;
  result = utimes (name, times);
#elif defined HAVE_UTIME
  struct utimbuf utb;
  utb.actime = new_atime + 86400 * 10957;
  utb.modtime = new_mtime + 86400 * 10957;
  result = utime (name, &utb);
#else
#warning neither utime nor utimes are available.
  errno = ENOSYS;
  result = -1;
#endif
  if (!result)
    errno = 0;
  return (result);
}
Пример #2
0
int c_utimes(const char *uri, const struct timeval *times) {
    mbchar_t *wuri = c_utf8_path_to_locale(uri);
    int ret = utimes(wuri, times);
    c_free_locale_string(wuri);
    return ret;
}
Пример #3
0
int
extractfile(char *name)
{
	int flags;
	uid_t uid;
	gid_t gid;
	mode_t mode;
	int extsize;
	struct timeval mtimep[2], ctimep[2];
	struct entry *ep;
	char *buf;

	curfile.name = name;
	curfile.action = USING;
	mtimep[0].tv_sec = curfile.atime_sec;
	mtimep[0].tv_usec = curfile.atime_nsec / 1000;
	mtimep[1].tv_sec = curfile.mtime_sec;
	mtimep[1].tv_usec = curfile.mtime_nsec / 1000;
	ctimep[0].tv_sec = curfile.atime_sec;
	ctimep[0].tv_usec = curfile.atime_nsec / 1000;
	ctimep[1].tv_sec = curfile.birthtime_sec;
	ctimep[1].tv_usec = curfile.birthtime_nsec / 1000;
	extsize = curfile.extsize;
	uid = getuid();
	if (uid == 0)
		uid = curfile.uid;
	gid = curfile.gid;
	mode = curfile.mode;
	flags = curfile.file_flags;
	switch (mode & IFMT) {

	default:
		fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
		skipfile();
		return (FAIL);

	case IFSOCK:
		vprintf(stdout, "skipped socket %s\n", name);
		skipfile();
		return (GOOD);

	case IFDIR:
		if (mflag) {
			ep = lookupname(name);
			if (ep == NULL || ep->e_flags & EXTRACT)
				panic("unextracted directory %s\n", name);
			skipfile();
			return (GOOD);
		}
		vprintf(stdout, "extract file %s\n", name);
		return (genliteraldir(name, curfile.ino));

	case IFLNK:
		lnkbuf[0] = '\0';
		pathlen = 0;
		buf = setupextattr(extsize);
		getfile(xtrlnkfile, xtrattr, xtrlnkskip);
		if (pathlen == 0) {
			vprintf(stdout,
			    "%s: zero length symbolic link (ignored)\n", name);
			return (GOOD);
		}
		if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
			if (extsize > 0)
				set_extattr_link(name, buf, extsize);
			(void) lchown(name, uid, gid);
			(void) lchmod(name, mode);
			(void) lutimes(name, ctimep);
			(void) lutimes(name, mtimep);
			(void) lchflags(name, flags);
			return (GOOD);
		}
		return (FAIL);

	case IFIFO:
		vprintf(stdout, "extract fifo %s\n", name);
		if (Nflag) {
			skipfile();
			return (GOOD);
		}
		if (uflag)
			(void) unlink(name);
		if (mkfifo(name, 0600) < 0) {
			fprintf(stderr, "%s: cannot create fifo: %s\n",
			    name, strerror(errno));
			skipfile();
			return (FAIL);
		}
		if (extsize == 0) {
			skipfile();
		} else {
			buf = setupextattr(extsize);
			getfile(xtrnull, xtrattr, xtrnull);
			set_extattr_file(name, buf, extsize);
		}
		(void) chown(name, uid, gid);
		(void) chmod(name, mode);
		(void) utimes(name, ctimep);
		(void) utimes(name, mtimep);
		(void) chflags(name, flags);
		return (GOOD);

	case IFCHR:
	case IFBLK:
		vprintf(stdout, "extract special file %s\n", name);
		if (Nflag) {
			skipfile();
			return (GOOD);
		}
		if (uflag)
			(void) unlink(name);
		if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600,
		    (int)curfile.rdev) < 0) {
			fprintf(stderr, "%s: cannot create special file: %s\n",
			    name, strerror(errno));
			skipfile();
			return (FAIL);
		}
		if (extsize == 0) {
			skipfile();
		} else {
			buf = setupextattr(extsize);
			getfile(xtrnull, xtrattr, xtrnull);
			set_extattr_file(name, buf, extsize);
		}
		(void) chown(name, uid, gid);
		(void) chmod(name, mode);
		(void) utimes(name, ctimep);
		(void) utimes(name, mtimep);
		(void) chflags(name, flags);
		return (GOOD);

	case IFREG:
		vprintf(stdout, "extract file %s\n", name);
		if (Nflag) {
			skipfile();
			return (GOOD);
		}
		if (uflag)
			(void) unlink(name);
		if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
		    0600)) < 0) {
			fprintf(stderr, "%s: cannot create file: %s\n",
			    name, strerror(errno));
			skipfile();
			return (FAIL);
		}
		buf = setupextattr(extsize);
		getfile(xtrfile, xtrattr, xtrskip);
		if (extsize > 0)
			set_extattr_fd(ofile, name, buf, extsize);
		(void) fchown(ofile, uid, gid);
		(void) fchmod(ofile, mode);
		(void) futimes(ofile, ctimep);
		(void) futimes(ofile, mtimep);
		(void) fchflags(ofile, flags);
		(void) close(ofile);
		return (GOOD);
	}
	/* NOTREACHED */
}
Пример #4
0
static void
process_fsetstat(u_int32_t id)
{
	Attrib a;
	int handle, fd, r;
	int status = SSH2_FX_OK;

	if ((r = get_handle(iqueue, &handle)) != 0 ||
	    (r = decode_attrib(iqueue, &a)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));

	debug("request %u: fsetstat handle %d", id, handle);
	fd = handle_to_fd(handle);
	if (fd < 0)
		status = SSH2_FX_FAILURE;
	else {
		char *name = handle_to_name(handle);

		if (a.flags & SSH2_FILEXFER_ATTR_SIZE) {
			logit("set \"%s\" size %llu",
			    name, (unsigned long long)a.size);
			r = ftruncate(fd, a.size);
			if (r == -1)
				status = errno_to_portable(errno);
		}
		if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
			logit("set \"%s\" mode %04o", name, a.perm);
#ifdef HAVE_FCHMOD
			r = fchmod(fd, a.perm & 07777);
#else
			r = chmod(name, a.perm & 07777);
#endif
			if (r == -1)
				status = errno_to_portable(errno);
		}
		if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
			char buf[64];
			time_t t = a.mtime;

			strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
			    localtime(&t));
			logit("set \"%s\" modtime %s", name, buf);
#ifdef HAVE_FUTIMES
			r = futimes(fd, attrib_to_tv(&a));
#else
			r = utimes(name, attrib_to_tv(&a));
#endif
			if (r == -1)
				status = errno_to_portable(errno);
		}
		if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
			logit("set \"%s\" owner %lu group %lu", name,
			    (u_long)a.uid, (u_long)a.gid);
#ifdef HAVE_FCHOWN
			r = fchown(fd, a.uid, a.gid);
#else
			r = chown(name, a.uid, a.gid);
#endif
			if (r == -1)
				status = errno_to_portable(errno);
		}
	}
	send_status(id, status);
}
Пример #5
0
int
setfile(struct stat *fs, int fd)
{
    static struct timeval tv[2];
    struct stat ts;
    int rval, gotstat, islink, fdval;

    rval = 0;
    fdval = fd != -1;
    islink = !fdval && S_ISLNK(fs->st_mode);
    fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX |
                   S_IRWXU | S_IRWXG | S_IRWXO;

    TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
    TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
    if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) {
        warn("%sutimes: %s", islink ? "l" : "", to.p_path);
        rval = 1;
    }
    if (fdval ? fstat(fd, &ts) :
            (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts)))
        gotstat = 0;
    else {
        gotstat = 1;
        ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX |
                      S_IRWXU | S_IRWXG | S_IRWXO;
    }
    /*
     * Changing the ownership probably won't succeed, unless we're root
     * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
     * the mode; current BSD behavior is to remove all setuid bits on
     * chown.  If chown fails, lose setuid/setgid bits.
     */
    if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid)
        if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) :
                (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) :
                 chown(to.p_path, fs->st_uid, fs->st_gid))) {
            if (errno != EPERM) {
                warn("chown: %s", to.p_path);
                rval = 1;
            }
            fs->st_mode &= ~(S_ISUID | S_ISGID);
        }

    if (!gotstat || fs->st_mode != ts.st_mode)
        if (fdval ? fchmod(fd, fs->st_mode) :
                (islink ? lchmod(to.p_path, fs->st_mode) :
                 chmod(to.p_path, fs->st_mode))) {
            warn("chmod: %s", to.p_path);
            rval = 1;
        }

    if (!gotstat || fs->st_flags != ts.st_flags)
        if (fdval ?
                fchflags(fd, fs->st_flags) :
                (islink ? lchflags(to.p_path, fs->st_flags) :
                 chflags(to.p_path, fs->st_flags))) {
            warn("chflags: %s", to.p_path);
            rval = 1;
        }

    return (rval);
}
Пример #6
0
static void copy_file_attributes(int infd, int outfd, const char *outfile)
{
#ifdef WIN32
    BY_HANDLE_FILE_INFORMATION fi;
    BOOL bOk;

    bOk = GetFileInformationByHandle((HANDLE)_get_osfhandle(infd), &fi);
    trace("GetFileInformationByHandle(...) => %s\n", bOk ? "TRUE" : "FALSE");
    if (bOk) {
        bOk = SetFileTime((HANDLE)_get_osfhandle(outfd), NULL, &fi.ftLastAccessTime, &fi.ftLastWriteTime);
        trace("SetFileTime(...) => %s\n", bOk ? "TRUE" : "FALSE");
        bOk = SetFileAttributesA(outfile, fi.dwFileAttributes);
        trace("SetFileAttributesA(...) => %s\n", bOk ? "TRUE" : "FALSE");
    }
#else
    struct stat sbuf;
#ifdef HAVE_FUTIMENS
    struct timespec times[2];
#else
    struct timeval times[2];
#endif
    int rv;

    if ((rv = fstat(infd, &sbuf)) != 0) {
        trace("fstat(%d, &sbuf) => %d (errno = %d)\n",
              infd, rv, errno);
        return;
    }

    /* copy file times. */
#ifdef HAVE_FUTIMENS
    times[0].tv_sec = sbuf.st_atime;
    times[0].tv_nsec = SNZ_ST_TIME_NSEC(sbuf, a);
    times[1].tv_sec = sbuf.st_mtime;
    times[1].tv_nsec = SNZ_ST_TIME_NSEC(sbuf, m);
    rv = futimens(outfd, times);
    trace("futimens(%d, [{%ld, %ld}, {%ld, %ld}]) => %d\n",
          outfd, times[0].tv_sec, times[0].tv_nsec,
          times[1].tv_sec, times[1].tv_nsec, rv);
#else /* HAVE_FUTIMENS */
    times[0].tv_sec = sbuf.st_atime;
    times[0].tv_usec = SNZ_ST_TIME_NSEC(sbuf, a) / 1000;
    times[1].tv_sec = sbuf.st_mtime;
    times[1].tv_usec = SNZ_ST_TIME_NSEC(sbuf, m) / 1000;
#ifdef HAVE_FUTIMES
    rv = futimes(outfd, times);
    trace("futimes(%d, [{%ld, %ld}, {%ld, %ld}]) => %d\n",
          outfd, times[0].tv_sec, times[0].tv_usec,
          times[1].tv_sec, times[1].tv_usec, rv);
#else /* HAVE_FUTIMES */
    rv = utimes(outfile, times);
    trace("utimes(\"%s\", [{%ld, %ld}, {%ld, %ld}]) => %d\n",
          outfile, times[0].tv_sec, times[0].tv_usec,
          times[1].tv_sec, times[1].tv_usec, rv);
#endif /* HAVE_FUTIMES */
#endif /* HAVE_FUTIMENS */

    /* copy other attributes */
    rv = fchown(outfd, sbuf.st_uid, sbuf.st_gid);
    trace("fchown(%d, %d, %d) => %d\n",
          outfd, sbuf.st_uid, sbuf.st_gid, rv);
    rv = fchmod(outfd, sbuf.st_mode);
    trace("fchmod(%d, 0%o) => %d\n",
          outfd, sbuf.st_mode, rv);
#endif
}
Пример #7
0
int Sg_Utimes(SgString *path, SgObject atime, SgObject mtime)
{
  SgObject absolutePath;
  char *c_path;

  if (!Sg_AbsolutePathP(path)) {
    absolutePath = Sg_AbsolutePath(path);
    if (SG_FALSEP(absolutePath)) {
      return FALSE;		/* file not exists? */
    }
  } else {
    absolutePath = SG_OBJ(path);
  }
  if (!Sg_FileExistP(absolutePath)) return FALSE; /* okay file not exists */

  c_path = Sg_Utf32sToUtf8s(absolutePath);
#if defined(HAVE_UTIMENSAT)
  {
#define set_time(ts, time)			\
    do {					\
      if (SG_TIMEP(time) || SG_REALP(time)) {	\
	Sg_GetTimeSpec(time, ts);		\
      } else if (SG_FALSEP(time)) {		\
	(ts)->tv_sec = 0;			\
	(ts)->tv_nsec = UTIME_OMIT;		\
      } else {					\
	(ts)->tv_sec = 0;			\
	(ts)->tv_nsec = UTIME_NOW;		\
      }						\
    } while (0)
    
    struct timespec times[2];

    set_time(&times[0], atime);
    set_time(&times[1], mtime);
    return utimensat(0, c_path, times, AT_SYMLINK_NOFOLLOW) == 0;
#undef set_time
  }
#elif defined(HAVE_UTIMES)
  {
#define set_time(tv, time, m)			\
    do {					\
      if (SG_TIMEP(time) || SG_REALP(time)) {	\
	struct timespec ts;			\
	Sg_GetTimeSpec(time, &ts);		\
	(tv)->tv_sec = ts.tv_sec;		\
	(tv)->tv_usec = ts.tv_nsec / 1000;	\
      } else if (SG_FALSEP(time)) {		\
	/* emulate UTIME_OMIT */		\
	struct stat st;				\
	if (stat(c_path, &st) == 0) {		\
	  (tv)->tv_sec = st. m;			\
	  (tv)->tv_usec = 0;			\
	} else {				\
	  /* sorry */				\
	  return FALSE;				\
	}					\
      }	else {					\
	/* emulate UTIME_NOW */			\
	unsigned long sec, usec;		\
	Sg_GetTimeOfDay(&sec, &usec);		\
	(tv)->tv_sec = sec;			\
	(tv)->tv_usec = usec;			\
      }						\
    } while (0)
    
    struct timeval times[2];
    set_time(&times[0], atime, st_atime);
    set_time(&times[1], mtime, st_mtime);
    return utimes(c_path, times) == 0;
#undef set_time
  }
#else
  /* just indicate failed to change */
  return FALSE;
#endif
}
Пример #8
0
int
run_attr_tests (char *testfile)
{
        int             ret = -1;
        char            *res = NULL;
        struct stat     buf;
        struct statfs   sbuf;
        struct statvfs  svbuf;

        assert (testfile);

        fprintf (stdout, "Testing chmod");
        ret = chmod (testfile, 0);
        check_err (ret, "chmod", 2);

        fprintf (stdout, "Testing chown");
        ret = chown (testfile, 0, 0);
        check_err (ret, "chown", 2);

        fprintf (stdout, "Testing link");
        ret = link (testfile, testfile);
        check_err (ret, "link", 2);

        fprintf (stdout, "Testing rename");
        ret = rename (testfile, testfile);
        check_err (ret, "rename", 2);

        fprintf (stdout, "Testing utimes");
        ret = utimes (testfile, NULL);
        check_err (ret, "utimes", 2);

        fprintf (stdout, "Testing utime");
        ret = utime (testfile, NULL);
        check_err (ret, "utime", 2);

        fprintf (stdout, "Testing unlink");
        ret = unlink (testfile);
        check_err (ret, "unlink", 2);

        fprintf (stdout, "Testing symlink");
        ret = symlink (testfile, testfile);
        check_err (ret, "symlink", 2);

        fprintf (stdout, "Testing readlink");
        ret = readlink (testfile, testfile, 0);
        check_err (ret, "readlink", 2);

        fprintf (stdout, "Testing realpath");
        ret = 0;
        res = realpath ((const char *)testfile, testfile);
        if (!res)
                ret = -1;
        check_err (ret, "realpath", 2);

        fprintf (stdout, "Testing stat");
        ret = stat (testfile, &buf);
        check_err (ret, "stat", 1);

        fprintf (stdout, "Testing lstat");
        ret = lstat (testfile, &buf);
        check_err (ret, "lstat", 1);

        fprintf (stdout, "Testing statfs");
        ret = statfs (testfile, &sbuf);
        check_err (ret, "statfs", 2);

        fprintf (stdout, "Testing statvfs");
        ret = statvfs (testfile, &svbuf);
        check_err (ret, "statvfs", 1);

        fprintf (stdout, "Testing getxattr");
        ret = getxattr (testfile, NULL, NULL, 0);
        check_err (ret, "getxattr", 2);

        fprintf (stdout, "Testing lgetxattr");
        ret = lgetxattr (testfile, NULL, NULL, 0);
        check_err (ret, "lgetxattr", 1);

        fprintf (stdout, "Testing lchown");
        ret = lchown (testfile, 0, 0);
        check_err (ret, "lchown", 2);
        return 0;
}
Пример #9
0
void SFTP::process_setstat(void)
{
	Attrib a;
	u_int32_t id;
	char *utf8_name;
	int status = SSH2_FX_OK;
  WIN32_FILE_ATTRIBUTE_DATA st;

  try
  {
	  id = get_int();
	  utf8_name = (char*) get_string(NULL);
    a = get_attrib(this->iqueue);
	  debug("request %u: setstat name \"%s\"", id, utf8_name);

    const SFTPFilePath path = pathFact.create_path (utf8_name);
    attrib_to_stat (&a, &st);

	  if (a.flags & SSH2_FILEXFER_ATTR_SIZE) 
    {
#if 0
		  logit("set \"%s\" size %llu",
		      utf8_name, (unsigned long long)a->size);

      LARGE_INTEGER largeOffset;
      largeOffset.QuadPart = a->size;
      if (!::SetFilePointerEx (fh, largeOffset, NULL, FILE_BEGIN)
          || !::SetEndOfFile (fh)
          )
      {
			  status = errno_to_portable(::GetLastError ());
      }
#endif
      status = SSH2_FX_OP_UNSUPPORTED;
	  }

	  if (status == SSH2_FX_OK
        && a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) 
    {
#if 0
		  char buf[64];
		  time_t t = a->mtime;

		  strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
		      localtime(&t));
		  logit("set \"%s\" modtime %s", name, buf);
		  ret = utimes(name, attrib_to_tv(a));
		  if (ret == -1)
			  status = errno_to_portable(::GetLastError ());
#endif
      status = SSH2_FX_OP_UNSUPPORTED;
	  }

	  if (status == SSH2_FX_OK
        && a.flags & SSH2_FILEXFER_ATTR_UIDGID) 
    {
#if 0
		  logit("set \"%s\" owner %lu group %lu", name,
		      (u_long)a->uid, (u_long)a->gid);
		  ret = chown(name, a->uid, a->gid);
		  if (ret == -1)
			  status = errno_to_portable(::GetLastError ());
#endif
      status = SSH2_FX_OP_UNSUPPORTED;
	  }

    // access premissions
	  if (status == SSH2_FX_OK
        && a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 
    {
		  logit("set \"%s\" mode %04o", utf8_name, a.perm);
      if (!::SetFileAttributesW
        (path.get_for_call ().c_str (),
             st.dwFileAttributes)
          )
      {
			  status = errno_to_portable(::GetLastError ());
      }
	  }
  }
  catch (Path::InvalidPath&)
  {
    //logit 
    status = SSH2_FX_FAILURE; 
    // TODO return the reason
  }
  catch (...)
  {
    status = SSH2_FX_FAILURE; 
    error ("unhandled exception in %s", __FUNCTION__);
  }

	send_status(id, status);
	if (utf8_name) xfree(utf8_name);
}
Пример #10
0
int
extractfile(char *name)
{
	u_int flags;
	uid_t uid;
	gid_t gid;
	mode_t mode;
	struct timeval mtimep[2], ctimep[2];
	struct entry *ep;
	int setbirth;

	curfile.name = name;
	curfile.action = USING;
	mtimep[0].tv_sec = curfile.atime_sec;
	mtimep[0].tv_usec = curfile.atime_nsec / 1000;
	mtimep[1].tv_sec = curfile.mtime_sec;
	mtimep[1].tv_usec = curfile.mtime_nsec / 1000;

	setbirth = curfile.birthtime_sec != 0;
	if (setbirth) {
		ctimep[0].tv_sec = curfile.atime_sec;
		ctimep[0].tv_usec = curfile.atime_nsec / 1000;
		ctimep[1].tv_sec = curfile.birthtime_sec;
		ctimep[1].tv_usec = curfile.birthtime_nsec / 1000;
	}
	uid = curfile.uid;
	gid = curfile.gid;
	mode = curfile.mode;
	flags = curfile.file_flags;
	switch (mode & IFMT) {

	default:
		fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
		skipfile();
		return (FAIL);

	case IFSOCK:
		Vprintf(stdout, "skipped socket %s\n", name);
		skipfile();
		return (GOOD);

	case IFDIR:
		if (mflag) {
			ep = lookupname(name);
			if (ep == NULL || ep->e_flags & EXTRACT)
				panic("unextracted directory %s\n", name);
			skipfile();
			return (GOOD);
		}
		Vprintf(stdout, "extract file %s\n", name);
		return (genliteraldir(name, curfile.ino));

	case IFLNK: {
			lnkbuf[0] = '\0';
			pathlen = 0;
			getfile(xtrlnkfile, xtrlnkskip);
			if (pathlen == 0) {
				Vprintf(stdout,
				    "%s: zero length symbolic link (ignored)\n",
				     name);
				return (GOOD);
			}
			if (linkit(lnkbuf, name, SYMLINK) == FAIL)
				return (FAIL);
			(void)lchown(name, uid, gid);
			return (GOOD);
		}

	case IFCHR:
	case IFBLK:
		Vprintf(stdout, "extract special file %s\n", name);
		if (Nflag) {
			skipfile();
			return (GOOD);
		}
		if (mknod(name, mode, (int)curfile.rdev) < 0) {
			warn("%s: cannot create special file", name);
			skipfile();
			return (FAIL);
		}
		(void)chown(name, uid, gid);
		(void)chmod(name, mode);
		(void)chflags(name, flags);
		skipfile();
		if (setbirth)
			(void)utimes(name, ctimep);
		(void)utimes(name, mtimep);
		return (GOOD);

	case IFIFO:
		Vprintf(stdout, "extract fifo %s\n", name);
		if (Nflag) {
			skipfile();
			return (GOOD);
		}
		if (mkfifo(name, mode) < 0) {
			warn("%s: cannot create fifo", name);
			skipfile();
			return (FAIL);
		}
		(void)chown(name, uid, gid);
		(void)chmod(name, mode);
		(void)chflags(name, flags);
		skipfile();
		if (setbirth)
			(void)utimes(name, ctimep);
		(void)utimes(name, mtimep);
		return (GOOD);

	case IFREG:
		Vprintf(stdout, "extract file %s\n", name);
		if (Nflag) {
			skipfile();
			return (GOOD);
		}
		if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
		    0666)) < 0) {
			warn("%s: cannot create file", name);
			skipfile();
			return (FAIL);
		}
		(void)fchown(ofile, curfile.uid, curfile.gid);
		(void)fchmod(ofile, mode);
		(void)fchflags(ofile, flags);
		getfile(xtrfile, xtrskip);
		(void)close(ofile);
		if (setbirth)
			(void)utimes(name, ctimep);
		(void)utimes(name, mtimep);
		return (GOOD);
	}
	/* NOTREACHED */
}
Пример #11
0
static int
rcsdiff_rev(RCSFILE *file, RCSNUM *rev1, RCSNUM *rev2, int dflags)
{
	struct timeval tv[2], tv2[2];
	BUF *b1, *b2;
	int ret;
	char *path1, *path2, rbuf1[RCS_REV_BUFSZ], rbuf2[RCS_REV_BUFSZ];

	ret = D_ERROR;
	b1 = b2 = NULL;
	memset(&tv, 0, sizeof(tv));
	memset(&tv2, 0, sizeof(tv2));

	diff_rev1 = rev1;
	diff_rev2 = rev2;
	path1 = path2 = NULL;

	rcsnum_tostr(rev1, rbuf1, sizeof(rbuf1));
	if (!quiet)
		fprintf(stderr, "retrieving revision %s\n", rbuf1);

	if ((b1 = rcs_getrev(file, rev1)) == NULL) {
		warnx("failed to retrieve revision %s", rbuf1);
		goto out;
	}

	b1 = rcs_kwexp_buf(b1, file, rev1);
	tv[0].tv_sec = (long)rcs_rev_getdate(file, rev1);
	tv[1].tv_sec = tv[0].tv_sec;

	rcsnum_tostr(rev2, rbuf2, sizeof(rbuf2));
	if (!quiet)
		fprintf(stderr, "retrieving revision %s\n", rbuf2);

	if ((b2 = rcs_getrev(file, rev2)) == NULL) {
		warnx("failed to retrieve revision %s", rbuf2);
		goto out;
	}

	b2 = rcs_kwexp_buf(b2, file, rev2);
	tv2[0].tv_sec = (long)rcs_rev_getdate(file, rev2);
	tv2[1].tv_sec = tv2[0].tv_sec;

	if (!quiet)
		fprintf(stderr, "%s -r%s -r%s\n", diffargs, rbuf1, rbuf2);

	(void)xasprintf(&path1, "%s/diff1.XXXXXXXXXX", rcs_tmpdir);
	buf_write_stmp(b1, path1);

	buf_free(b1);
	b1 = NULL;

	if (utimes(path1, (const struct timeval *)&tv) < 0)
		warn("utimes");

	(void)xasprintf(&path2, "%s/diff2.XXXXXXXXXX", rcs_tmpdir);
	buf_write_stmp(b2, path2);

	buf_free(b2);
	b2 = NULL;

	if (utimes(path2, (const struct timeval *)&tv2) < 0)
		warn("utimes");

	ret = diffreg(path1, path2, NULL, dflags);

out:
	if (b1 != NULL)
		buf_free(b1);
	if (b2 != NULL)
		buf_free(b2);
	if (path1 != NULL)
		xfree(path1);
	if (path2 != NULL)
		xfree(path2);

	return (ret);
}
Пример #12
0
static int
rcsdiff_file(RCSFILE *file, RCSNUM *rev, const char *filename, int dflags)
{
	int ret, fd;
	time_t t;
	struct stat st;
	char *path1, *path2;
	BUF *b1, *b2;
	char rbuf[RCS_REV_BUFSZ];
	struct tm *tb;
	struct timeval tv[2], tv2[2];

	memset(&tv, 0, sizeof(tv));
	memset(&tv2, 0, sizeof(tv2));

	ret = D_ERROR;
	b1 = b2 = NULL;

	diff_rev1 = rev;
	diff_rev2 = NULL;
	path1 = path2 = NULL;

	if ((fd = open(filename, O_RDONLY)) == -1) {
		warn("%s", filename);
		goto out;
	}

	rcsnum_tostr(rev, rbuf, sizeof(rbuf));
	if (!quiet) {
		fprintf(stderr, "retrieving revision %s\n", rbuf);
		fprintf(stderr, "%s -r%s %s\n", diffargs, rbuf, filename);
	}

	if ((b1 = rcs_getrev(file, rev)) == NULL) {
		warnx("failed to retrieve revision %s", rbuf);
		goto out;
	}

	b1 = rcs_kwexp_buf(b1, file, rev);
	tv[0].tv_sec = (long)rcs_rev_getdate(file, rev);
	tv[1].tv_sec = tv[0].tv_sec;

	if ((b2 = buf_load(filename)) == NULL) {
		warnx("failed to load file: `%s'", filename);
		goto out;
	}

	/* XXX - GNU uses GMT */
	if (fstat(fd, &st) == -1)
		err(D_ERROR, "%s", filename);

	tb = gmtime(&st.st_mtime);
	t = mktime(tb);

	tv2[0].tv_sec = t;
	tv2[1].tv_sec = t;

	(void)xasprintf(&path1, "%s/diff1.XXXXXXXXXX", rcs_tmpdir);
	buf_write_stmp(b1, path1);

	buf_free(b1);
	b1 = NULL;

	if (utimes(path1, (const struct timeval *)&tv) < 0)
		warn("utimes");

	(void)xasprintf(&path2, "%s/diff2.XXXXXXXXXX", rcs_tmpdir);
	buf_write_stmp(b2, path2);

	buf_free(b2);
	b2 = NULL;

	if (utimes(path2, (const struct timeval *)&tv2) < 0)
		warn("utimes");

	ret = diffreg(path1, path2, NULL, dflags);

out:
	if (fd != -1)
		(void)close(fd);
	if (b1 != NULL)
		buf_free(b1);
	if (b2 != NULL)
		buf_free(b2);
	if (path1 != NULL)
		xfree(path1);
	if (path2 != NULL)
		xfree(path2);

	return (ret);
}
Пример #13
0
/* For regular file, we're going to:
 * Find file with latest modified time
 * copy it to work directory on target
 * move it to proper raid location
 * update file times to match original
 */
static int __replication_copy_regular_file(const char *relative_path, RaidVolume_t *to_vol) {

    EXLog(REPL, DBG, " > __replication_copy_regular_file [%s > %s]", relative_path, to_vol->basepath);

    RaidVolume_t *from_vol;
    char fullpath_from[PATH_MAX];
    struct stat stbuf;

    /* Find volume w/ latest modified time */
    int not_found = volume_most_recently_modified_instance(relative_path, &from_vol, fullpath_from, &stbuf);
    if (not_found || ((stbuf.st_mode & S_IFMT) != S_IFREG)) {
        EXLog(REPL, DBG, "   > Path is not a regular file");
        return 0;
    }

    /* Get target work path */
    char workpath[PATH_MAX];
    if (!volume_avaialble_work_path(to_vol, workpath)) {
        EXLog(REPL, DBG, "   > Volume does not have an available work path");
        __replication_queue_volume_check(to_vol);
        return 0;
    }

    /* Copy source -> dest */
#define REGFILE_COPY_CHUNK_SIZE 32768
    char copy_buffer[REGFILE_COPY_CHUNK_SIZE];

    int from_fd = open(fullpath_from, O_RDONLY);
    if (from_fd < 0) {
        EXLog(REPL, DBG, "   > Could not open path for reading [%s]", fullpath_from);
        __replication_queue_volume_check(from_vol);
        return 0;
    }

    int to_fd = open(workpath, O_CREAT | O_WRONLY | O_APPEND, stbuf.st_mode);
    if (to_fd < 0) {
        close(from_fd);
        EXLog(REPL, DBG, "   > Could not open path for writing [%s]", workpath);
        __replication_queue_volume_check(to_vol);
        return 0;
    }

    VOLUME_UPDATE_REPLICATION_STATUS_STRING(from_vol, "Reading %s", relative_path);
    VOLUME_UPDATE_REPLICATION_STATUS_STRING(to_vol,   "Writing %s", relative_path);

    /* Both files are open */
    while (1) {
        ssize_t bytes_read = read(from_fd, copy_buffer, (size_t)REGFILE_COPY_CHUNK_SIZE);
        if (bytes_read < 0) {
            /* Shit, there was an error.  Shut it all down */
            close(from_fd);
            close(to_fd);
            unlink(workpath);
            EXLog(REPL, DBG, "   > Read error on path [%s]", fullpath_from);
            __replication_queue_volume_check(from_vol);
            VOLUME_UPDATE_REPLICATION_STATUS_STRING(from_vol, "Idle");
            VOLUME_UPDATE_REPLICATION_STATUS_STRING(to_vol,   "Idle");
            return 0;
        }

        if (bytes_read == 0) {
            /* We hit the end of the file, wrap it up! */
            close(from_fd);
            close(to_fd);
            char topath[PATH_MAX];
            volume_full_path_for_raid_path(to_vol, relative_path, topath);
            rename(workpath, topath);

            struct timeval _times[2];
#ifdef __APPLE__
            _times[0].tv_sec = stbuf.st_atimespec.tv_sec;
            _times[0].tv_usec = 0;
            _times[1].tv_sec = stbuf.st_mtimespec.tv_sec;
            _times[1].tv_usec = 0;
#else
            _times[0].tv_sec = stbuf.st_atime;
            _times[0].tv_usec = 0;
            _times[1].tv_sec = stbuf.st_mtime;
            _times[1].tv_usec = 0;
#endif

            utimes(topath, _times);
            VOLUME_UPDATE_REPLICATION_STATUS_STRING(from_vol, "Idle");
            VOLUME_UPDATE_REPLICATION_STATUS_STRING(to_vol,   "Idle");
            return 1;
        }

        /* Otherwise write to workpath */
        ssize_t bytes_left = bytes_read;
        char *bufptr = copy_buffer;
        while (bytes_left) {
            /* Check for halting */
            if (s_replication_halt_replication_of_file) {
                s_replication_halt_replication_of_file = 0;
                pthread_mutex_lock(&s_replication_halt_replication_mutex);
                if (s_replication_halt_replication_of_file_emergency || !strncmp(s_replication_halt_replication_of_file_path, relative_path, PATH_MAX)) {
                    /* Shut it down! */
                    close(from_fd);
                    close(to_fd);
                    unlink(workpath);
                    EXLog(REPL, DBG, "   > Shutting down because path [%s] was opened by the OS", s_replication_halt_replication_of_file_path);
                    /* On emergency, delay by 1 second for other threads to activate */
                    if (s_replication_halt_replication_of_file_emergency) {
                        s_replication_halt_replication_of_file_emergency = 0;
                        usleep(1000);
                    }
                    pthread_mutex_unlock(&s_replication_halt_replication_mutex);
                    VOLUME_UPDATE_REPLICATION_STATUS_STRING(from_vol, "Idle");
                    VOLUME_UPDATE_REPLICATION_STATUS_STRING(to_vol,   "Idle");
                    return 0;
                }
                pthread_mutex_unlock(&s_replication_halt_replication_mutex);
            }

            ssize_t bytes_written = write(to_fd, bufptr, (size_t)bytes_left);
            if (bytes_written < 0) {
                /* Shut it all down! */
                close(from_fd);
                close(to_fd);
                unlink(workpath);
                EXLog(REPL, DBG, "   > Write error on path [%s]", workpath);
                __replication_queue_volume_check(to_vol);
                VOLUME_UPDATE_REPLICATION_STATUS_STRING(from_vol, "Idle");
                VOLUME_UPDATE_REPLICATION_STATUS_STRING(to_vol,   "Idle");
                return 0;
            }

            /* Otherwise ok */
            bytes_left -= bytes_written;
            bufptr += bytes_written;
        }
    }

    VOLUME_UPDATE_REPLICATION_STATUS_STRING(from_vol, "Idle");
    VOLUME_UPDATE_REPLICATION_STATUS_STRING(to_vol,   "Idle");
    return 0;
}
Пример #14
0
/*
 * copy_file - copy a file
 *
 *	Copy a file from src to dst.
 *
 *	statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
 *	the access and modification and the access rights.
 *
 *	Return 0 on success, -1 on error.
 */
static int copy_file (const char *src, const char *dst,
                      bool reset_selinux,
                      const struct stat *statp, const struct timeval mt[],
                      uid_t old_uid, uid_t new_uid,
                      gid_t old_gid, gid_t new_gid)
{
    int err = 0;
    int ifd;
    int ofd;
    char buf[1024];
    ssize_t cnt;

    ifd = open (src, O_RDONLY);
    if (ifd < 0) {
        return -1;
    }
#ifdef WITH_SELINUX
    if (set_selinux_file_context (dst) != 0) {
        return -1;
    }
#endif				/* WITH_SELINUX */
    ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
    if (   (ofd < 0)
            || (fchown_if_needed (ofd, statp,
                                  old_uid, new_uid, old_gid, new_gid) != 0)
#ifdef WITH_ACL
            || (   (perm_copy_fd (src, ifd, dst, ofd, &ctx) != 0)
                   && (errno != 0))
#else				/* !WITH_ACL */
            || (fchmod (ofd, statp->st_mode & 07777) != 0)
#endif				/* !WITH_ACL */
#ifdef WITH_ATTR
            /*
             * If the third parameter is NULL, all extended attributes
             * except those that define Access Control Lists are copied.
             * ACLs are excluded by default because copying them between
             * file systems with and without ACL support needs some
             * additional logic so that no unexpected permissions result.
             */
            || (   !reset_selinux
                   && (attr_copy_fd (src, ifd, dst, ofd, NULL, &ctx) != 0)
                   && (errno != 0))
#endif				/* WITH_ATTR */
       ) {
        (void) close (ifd);
        return -1;
    }

    while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
        if (write (ofd, buf, (size_t)cnt) != cnt) {
            (void) close (ifd);
            return -1;
        }
    }

    (void) close (ifd);

#ifdef HAVE_FUTIMES
    if (futimes (ofd, mt) != 0) {
        return -1;
    }
#endif				/* HAVE_FUTIMES */

    if (close (ofd) != 0) {
        return -1;
    }

#ifndef HAVE_FUTIMES
    if (utimes(dst, mt) != 0) {
        return -1;
    }
#endif				/* !HAVE_FUTIMES */

    return err;
}
Пример #15
0
static ssize_t uv__fs_futime(uv_fs_t* req) {
#if defined(__linux__)
  /* utimesat() has nanosecond resolution but we stick to microseconds
   * for the sake of consistency with other platforms.
   */
  static int no_utimesat;
  struct timespec ts[2];
  struct timeval tv[2];
  char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)];
  int r;

  if (no_utimesat)
    goto skip;

  ts[0].tv_sec  = req->atime;
  ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000;
  ts[1].tv_sec  = req->mtime;
  ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000;

  r = uv__utimesat(req->file, NULL, ts, 0);
  if (r == 0)
    return r;

  if (errno != ENOSYS)
    return r;

  no_utimesat = 1;

skip:

  tv[0].tv_sec  = req->atime;
  tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
  tv[1].tv_sec  = req->mtime;
  tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
  snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file);

  r = utimes(path, tv);
  if (r == 0)
    return r;

  switch (errno) {
  case ENOENT:
    if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF)
      break;
    /* Fall through. */

  case EACCES:
  case ENOTDIR:
    errno = ENOSYS;
    break;
  }

  return r;

#elif defined(__APPLE__)                                                      \
    || defined(__DragonFly__)                                                 \
    || defined(__FreeBSD__)                                                   \
    || defined(__NetBSD__)                                                    \
    || defined(__OpenBSD__)                                                   \
    || defined(__sun)
  struct timeval tv[2];
  tv[0].tv_sec  = req->atime;
  tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
  tv[1].tv_sec  = req->mtime;
  tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
# if defined(__sun)
  return futimesat(req->file, NULL, tv);
# else
  return futimes(req->file, tv);
# endif
#else
  errno = ENOSYS;
  return -1;
#endif
}
Пример #16
0
int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
{
	struct hostfs_stat st;
	struct timeval times[2];
	int err, ma;

	if (attrs->ia_valid & HOSTFS_ATTR_MODE) {
		if (fd >= 0) {
			if (fchmod(fd, attrs->ia_mode) != 0)
				return -errno;
		} else if (chmod(file, attrs->ia_mode) != 0) {
			return -errno;
		}
	}
	if (attrs->ia_valid & HOSTFS_ATTR_UID) {
		if (fd >= 0) {
			if (fchown(fd, attrs->ia_uid, -1))
				return -errno;
		} else if (chown(file, attrs->ia_uid, -1)) {
			return -errno;
		}
	}
	if (attrs->ia_valid & HOSTFS_ATTR_GID) {
		if (fd >= 0) {
			if (fchown(fd, -1, attrs->ia_gid))
				return -errno;
		} else if (chown(file, -1, attrs->ia_gid)) {
			return -errno;
		}
	}
	if (attrs->ia_valid & HOSTFS_ATTR_SIZE) {
		if (fd >= 0) {
			if (ftruncate(fd, attrs->ia_size))
				return -errno;
		} else if (truncate(file, attrs->ia_size)) {
			return -errno;
		}
	}

	/*
	 * Update accessed and/or modified time, in two parts: first set
	 * times according to the changes to perform, and then call futimes()
	 * or utimes() to apply them.
	 */
	ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET);
	if (attrs->ia_valid & ma) {
		err = stat_file(file, &st, fd);
		if (err != 0)
			return err;

		times[0].tv_sec = st.atime.tv_sec;
		times[0].tv_usec = st.atime.tv_nsec / 1000;
		times[1].tv_sec = st.mtime.tv_sec;
		times[1].tv_usec = st.mtime.tv_nsec / 1000;

		if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) {
			times[0].tv_sec = attrs->ia_atime.tv_sec;
			times[0].tv_usec = attrs->ia_atime.tv_nsec / 1000;
		}
		if (attrs->ia_valid & HOSTFS_ATTR_MTIME_SET) {
			times[1].tv_sec = attrs->ia_mtime.tv_sec;
			times[1].tv_usec = attrs->ia_mtime.tv_nsec / 1000;
		}

		if (fd >= 0) {
			if (futimes(fd, times) != 0)
				return -errno;
		} else if (utimes(file, times) != 0) {
			return -errno;
		}
	}

	/* Note: ctime is not handled */
	if (attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)) {
		err = stat_file(file, &st, fd);
		attrs->ia_atime = st.atime;
		attrs->ia_mtime = st.mtime;
		if (err != 0)
			return err;
	}
	return 0;
}
Пример #17
0
static void
process_fsetstat(u_int32_t id)
{
	Attrib *a;
	int handle, fd, ret;
	int status = SSH2_FX_OK;

	handle = get_handle();
	a = get_attrib();
	debug("request %u: fsetstat handle %d", id, handle);
	fd = handle_to_fd(handle);
	if (fd < 0)
		status = SSH2_FX_FAILURE;
	else {
		char *name = handle_to_name(handle);

		if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
			logit("set \"%s\" size %llu",
			    name, (unsigned long long)a->size);
			ret = ftruncate(fd, a->size);
			if (ret == -1)
				status = errno_to_portable(errno);
		}
		if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
			logit("set \"%s\" mode %04o", name, a->perm);
#ifdef HAVE_FCHMOD
			ret = fchmod(fd, a->perm & 07777);
#else
			ret = chmod(name, a->perm & 07777);
#endif
			if (ret == -1)
				status = errno_to_portable(errno);
		}
		if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
			char buf[64];
			time_t t = a->mtime;

			strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
			    localtime(&t));
			logit("set \"%s\" modtime %s", name, buf);
#ifdef HAVE_FUTIMES
			ret = futimes(fd, attrib_to_tv(a));
#else
			ret = utimes(name, attrib_to_tv(a));
#endif
			if (ret == -1)
				status = errno_to_portable(errno);
		}
		if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
			logit("set \"%s\" owner %lu group %lu", name,
			    (u_long)a->uid, (u_long)a->gid);
#ifdef HAVE_FCHOWN
			ret = fchown(fd, a->uid, a->gid);
#else
			ret = chown(name, a->uid, a->gid);
#endif
			if (ret == -1)
				status = errno_to_portable(errno);
		}
	}
	send_status(id, status);
}
Пример #18
0
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input)
{
	char* s = NULL;
        mode_t m;
	UINT64 size;
	int status;
	char* fullpath;
	struct STAT st;
	struct timeval tv[2];
	UINT64 LastWriteTime;
	UINT32 FileAttributes;
	UINT32 FileNameLength;

	m = 0;

	switch (FsInformationClass)
	{
		case FileBasicInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
			Stream_Seek_UINT64(input); /* CreationTime */
			Stream_Seek_UINT64(input); /* LastAccessTime */
			Stream_Read_UINT64(input, LastWriteTime);
			Stream_Seek_UINT64(input); /* ChangeTime */
			Stream_Read_UINT32(input, FileAttributes);

			if (FSTAT(file->fd, &st) != 0)
				return FALSE;

			tv[0].tv_sec = st.st_atime;
			tv[0].tv_usec = 0;
			tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime);
			tv[1].tv_usec = 0;
#ifndef WIN32
/* TODO on win32 */                        
#ifdef ANDROID
			utimes(file->fullpath, tv);
#else
			futimes(file->fd, tv);
#endif

			if (FileAttributes > 0)
			{
				m = st.st_mode;
				if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
					m |= S_IWUSR;
				else
					m &= ~S_IWUSR;
				if (m != st.st_mode)
					fchmod(file->fd, m);
			}
#endif
                        break;

		case FileEndOfFileInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
		case FileAllocationInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
			Stream_Read_UINT64(input, size);
			if (ftruncate(file->fd, size) != 0)
				return FALSE;
			break;

		case FileDispositionInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232098.aspx */
			/* http://msdn.microsoft.com/en-us/library/cc241371.aspx */
			if (Length)
				Stream_Read_UINT8(input, file->delete_pending);
			else
				file->delete_pending = 1;
			if (file->delete_pending && file->is_dir)
			{
				/* mstsc causes this to FAIL if the directory is not empty,
				 * and that's what the server is expecting.  If we wait for
				 * the close to flag a failure, cut and paste of a folder
				 * will lose the folder's contents.
				 */
				int status;
				status = rmdir(file->fullpath);
				if (status == 0)
				{
					/* Put it back so the normal pending delete will work. */
					mkdir(file->fullpath, 0755);
				}
				else
				{
					return FALSE;
				}
			}
			break;

		case FileRenameInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232085.aspx */
			Stream_Seek_UINT8(input); /* ReplaceIfExists */
			Stream_Seek_UINT8(input); /* RootDirectory */
			Stream_Read_UINT32(input, FileNameLength);

			status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(input),
					FileNameLength / 2, &s, 0, NULL, NULL);

			if (status < 1)
				s = (char*) calloc(1, 1);

			fullpath = drive_file_combine_fullpath(file->basepath, s);
			free(s);

			/* TODO rename does not work on win32 */
                        if (rename(file->fullpath, fullpath) == 0)
			{
				DEBUG_SVC("renamed %s to %s", file->fullpath, fullpath);
				drive_file_set_fullpath(file, fullpath);
			}
			else
			{
				DEBUG_WARN("rename %s to %s failed, errno = %d", file->fullpath, fullpath, errno);
				free(fullpath);
				return FALSE;
			}

			break;

		default:
			DEBUG_WARN("invalid FsInformationClass %d", FsInformationClass);
			return FALSE;
	}

	return TRUE;
}
Пример #19
0
/*
 * Periodically test network connection. On signals, determine what
 * happened or what to do with child. Return as necessary for exit 
 * or restart of child.
 */
int
ssh_watch(int sock)
{
	int	r;
	int	val;
	static	int	secs_left;
	int	my_poll_time = first_poll_time;
	time_t	now;
	double	secs_to_shutdown;

#if defined(HAVE_SETPROCTITLE)
	setproctitle("parent of %d (%d)", 
	    (int)cchild, start_count);
#endif

	for (;;) {
		if (restart_ssh) {
			errlog(LOG_INFO, "signalled to kill and restart ssh");
			ssh_kill();
			return P_RESTART;
		}
		if ((val = sigsetjmp(jumpbuf, 1)) == 0) {

			errlog(LOG_DEBUG, "check on child %d", cchild);

			/* poll for expired child */
			r = ssh_wait(WNOHANG);
			if (r != P_CONTINUE) {
				errlog(LOG_DEBUG, 
				    "expired child, returning %d", r);
				return r;
			}

			secs_left = alarm(0);
			if (secs_left == 0)
				secs_left = my_poll_time;

			my_poll_time = poll_time;

			if (max_lifetime != 0) {
				time(&now);
				secs_to_shutdown = max_lifetime - difftime(now,pid_start_time);
				if (secs_to_shutdown < poll_time)
					secs_left = secs_to_shutdown;
			}

			errlog(LOG_DEBUG, 
			    "set alarm for %d secs", secs_left);

			alarm(secs_left);
			dolongjmp = 1;
			pause();

		} else {

			switch(val) {
			case SIGINT:
			case SIGTERM:
			case SIGQUIT:
			case SIGABRT:
				errlog(LOG_INFO, 
				    "received signal to exit (%d)", val);
				ssh_kill();
				return P_EXIT;
				break;
			case SIGALRM:
				if (exceeded_lifetime()) {
					ssh_kill();
					return P_EXIT;
				}

				if (writep && sock != -1 &&
				    !conn_test(sock, mhost, writep)) {
					errlog(LOG_INFO, 
					    "port down, restarting ssh");
					ssh_kill();
					return P_RESTART;
				}
#ifdef TOUCH_PIDFILE
				/*
				 * utimes() with a NULL time argument sets
				 * file access and modification times to
				 * the current time
				 */
				if (pid_file_name && 
				    utimes(pid_file_name, NULL) != 0) {
					errlog(LOG_ERR,
					    "could not touch pid file: %s",
					    strerror(errno));
				}
#endif
				break;
			default:
				break;
			}
		}
	}
}
Пример #20
0
int copy_file_recursive(const char *source, const char *dest)
{
	/* This is a recursive function, try to minimize stack usage */
	/* NB: each struct stat is ~100 bytes */
	struct stat source_stat;
	struct stat dest_stat;
	int retval = 0;
	int dest_exists = 0;

	if (strcmp(source, ".lock") == 0)
		goto skip;

	if (stat(source, &source_stat) < 0) {
		perror_msg("Can't stat '%s'", source);
		return -1;
	}

	if (lstat(dest, &dest_stat) < 0) {
		if (errno != ENOENT) {
			perror_msg("Can't stat '%s'", dest);
			return -1;
		}
	} else {
		if (source_stat.st_dev == dest_stat.st_dev
		 && source_stat.st_ino == dest_stat.st_ino
		) {
			error_msg("'%s' and '%s' are the same file", source, dest);
			return -1;
		}
		dest_exists = 1;
	}

	if (S_ISDIR(source_stat.st_mode)) {
		DIR *dp;
		struct dirent *d;

		if (dest_exists) {
			if (!S_ISDIR(dest_stat.st_mode)) {
				error_msg("Target '%s' is not a directory", dest);
				return -1;
			}
			/* race here: user can substitute a symlink between
			 * this check and actual creation of files inside dest */
		} else {
			/* Create DEST */
			mode_t mode = source_stat.st_mode;
			/* Allow owner to access new dir (at least for now) */
			mode |= S_IRWXU;
			if (mkdir(dest, mode) < 0) {
				perror_msg("Can't create directory '%s'", dest);
				return -1;
			}
		}
		/* Recursively copy files in SOURCE */
		dp = opendir(source);
		if (dp == NULL) {
			retval = -1;
			goto ret;
		}

		while (retval == 0 && (d = readdir(dp)) != NULL) {
			char *new_source, *new_dest;

			if (dot_or_dotdot(d->d_name))
				continue;
			new_source = concat_path_file(source, d->d_name);
			new_dest = concat_path_file(dest, d->d_name);
			if (copy_file_recursive(new_source, new_dest) < 0)
				retval = -1;
			free(new_source);
			free(new_dest);
		}
		closedir(dp);

		goto ret;
	}

	if (S_ISREG(source_stat.st_mode)) {
		int src_fd;
		int dst_fd;
		mode_t new_mode;

		src_fd = open(source, O_RDONLY);
		if (src_fd < 0) {
			perror_msg("Can't open '%s'", source);
			return -1;
		}

		/* Do not try to open with weird mode fields */
		new_mode = source_stat.st_mode;

		// security problem versus (sym)link attacks
		// dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode);
		/* safe way: */
		dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
		if (dst_fd < 0) {
			close(src_fd);
			return -1;
		}

		if (copyfd_eof(src_fd, dst_fd, COPYFD_SPARSE) == -1)
			retval = -1;
		close(src_fd);
		/* Careful: do check that buffered writes succeeded... */
		if (close(dst_fd) < 0) {
			perror_msg("Error writing to '%s'", dest);
			retval = -1;
		} else {
			/* (Try to) copy atime and mtime */
			struct timeval atime_mtime[2];
			atime_mtime[0].tv_sec = source_stat.st_atime;
			// note: if "st_atim.tv_nsec" doesn't compile, try "st_atimensec":
			atime_mtime[0].tv_usec = source_stat.st_atim.tv_nsec / 1000;
			atime_mtime[1].tv_sec = source_stat.st_mtime;
			atime_mtime[1].tv_usec = source_stat.st_mtim.tv_nsec / 1000;
			// note: can use utimensat when it is more widely supported:
			utimes(dest, atime_mtime);
		}
		goto ret;
	}

	/* Neither dir not regular file: skip */

 skip:
	log_warning("Skipping '%s'", source);
 ret:
	return retval;
}
Пример #21
0
int
fastcopy(char *from, char *to, struct stat *sbp)
{
	struct timeval tval[2];
	static u_int32_t blen;
	static char *bp;
	int nread, from_fd, to_fd;
	int badchown = 0, serrno = 0;

	if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
		warn("%s", from);
		return (1);
	}
	if ((to_fd = open(to, O_CREAT | O_TRUNC | O_WRONLY, 0600)) < 0) {
		warn("%s", to);
		(void)close(from_fd);
		return (1);
	}

	if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
		serrno = errno;
		badchown = 1;
	}
	(void) fchmod(to_fd, sbp->st_mode & ~(S_ISUID|S_ISGID));

	if (!blen) {
		blen = sbp->st_blksize;
		if ((bp = malloc(blen)) == NULL) {
			warn(NULL);
			blen = 0;
			return (1);
		}
	}
	while ((nread = read(from_fd, bp, blen)) > 0)
		if (write(to_fd, bp, nread) != nread) {
			warn("%s", to);
			goto err;
		}
	if (nread < 0) {
		warn("%s", from);
err:		if (unlink(to))
			warn("%s: remove", to);
		(void)close(from_fd);
		(void)close(to_fd);
		return (1);
	}
	(void)close(from_fd);

	if (badchown) {
		errno = serrno;
		if ((sbp->st_mode & (S_ISUID|S_ISGID)))  {
			warn("%s: set owner/group; not setting setuid/setgid",
			    to);
			sbp->st_mode &= ~(S_ISUID|S_ISGID);
		} else if (!fflg)
			warn("%s: set owner/group", to);
	}
	if (fchmod(to_fd, sbp->st_mode))
		warn("%s: set mode", to);

	/*
	 * XXX
	 * NFS doesn't support chflags; ignore errors unless there's reason
	 * to believe we're losing bits.  (Note, this still won't be right
	 * if the server supports flags and we were trying to *remove* flags
	 * on a file that we copied, i.e., that we didn't create.)
	 */
	errno = 0;
	if (fchflags(to_fd, sbp->st_flags))
		if (errno != EOPNOTSUPP || sbp->st_flags != 0)
			warn("%s: set flags", to);

	TIMESPEC_TO_TIMEVAL(&tval[0], &sbp->st_atimespec);
	TIMESPEC_TO_TIMEVAL(&tval[1], &sbp->st_mtimespec);
	if (utimes(to, tval))
		warn("%s: set times", to);

	if (close(to_fd)) {
		warn("%s", to);
		return (1);
	}

	if (unlink(from)) {
		warn("%s: remove", from);
		return (1);
	}
	return (0);
}
Пример #22
0
/* Save a control message received from an agent
 * read_contromsg (other thread) is going to deal with it
 * (only if message changed)
 */
void save_controlmsg(unsigned int agentid, char *r_msg)
{
    char msg_ack[OS_FLSIZE + 1];

    /* Reply to the agent */
    snprintf(msg_ack, OS_FLSIZE, "%s%s", CONTROL_HEADER, HC_ACK);
    send_msg(agentid, msg_ack);

    /* Check if there is a keep alive already for this agent */
    if (_keep_alive[agentid] && _msg[agentid] &&
            (strcmp(_msg[agentid], r_msg) == 0)) {
        utimes(_keep_alive[agentid], NULL);
    }

    else if (strcmp(r_msg, HC_STARTUP) == 0) {
        return;
    }

    else {
        FILE *fp;
        char *uname = r_msg;
        char *random_leftovers;

        /* Lock mutex */
        if (pthread_mutex_lock(&lastmsg_mutex) != 0) {
            merror(MUTEX_ERROR, ARGV0);
            return;
        }

        /* Update rmsg */
        if (_msg[agentid]) {
            free(_msg[agentid]);
        }
        os_strdup(r_msg, _msg[agentid]);

        /* Unlock mutex */
        if (pthread_mutex_unlock(&lastmsg_mutex) != 0) {
            merror(MUTEX_ERROR, ARGV0);
            return;
        }

        r_msg = strchr(r_msg, '\n');
        if (!r_msg) {
            merror("%s: WARN: Invalid message from agent id: '%d'(uname)",
                   ARGV0,
                   agentid);
            return;
        }

        *r_msg = '\0';
        random_leftovers = strchr(r_msg, '\n');
        if (random_leftovers) {
            *random_leftovers = '\0';
        }

        /* Update the keep alive */
        if (!_keep_alive[agentid]) {
            char agent_file[OS_SIZE_1024 + 1];
            agent_file[OS_SIZE_1024] = '\0';

            /* Write to the agent file */
            snprintf(agent_file, OS_SIZE_1024, "%s/%s-%s",
                     AGENTINFO_DIR,
                     keys.keyentries[agentid]->name,
                     keys.keyentries[agentid]->ip->ip);
            os_strdup(agent_file, _keep_alive[agentid]);
        }

        /* Write to the file */
        fp = fopen(_keep_alive[agentid], "w");
        if (fp) {
            fprintf(fp, "%s\n", uname);
            fclose(fp);
        }
    }

    /* Lock now to notify of change */
    if (pthread_mutex_lock(&lastmsg_mutex) != 0) {
        merror(MUTEX_ERROR, ARGV0);
        return;
    }

    /* Assign new values */
    _changed[agentid] = 1;
    modified_agentid = (int) agentid;

    /* Signal that new data is available */
    pthread_cond_signal(&awake_mutex);

    /* Unlock mutex */
    if (pthread_mutex_unlock(&lastmsg_mutex) != 0) {
        merror(MUTEX_ERROR, ARGV0);
        return;
    }

    return;
}
Пример #23
0
/* Build supermin appliance from supermin_path to $TMPDIR/.guestfs-$UID.
 *
 * Returns:
 * 0 = built
 * -1 = error (aborts launch)
 */
static int
build_supermin_appliance (guestfs_h *g,
                          const char *supermin_path,
                          uid_t uid,
                          char **kernel, char **dtb,
			  char **initrd, char **appliance)
{
  CLEANUP_FREE char *tmpdir = guestfs_get_cachedir (g);
  struct stat statbuf;
  size_t len;

  /* len must be longer than the length of any pathname we can
   * generate in this function.
   */
  len = strlen (tmpdir) + 128;
  char cachedir[len];
  snprintf (cachedir, len, "%s/.guestfs-%ju", tmpdir, (uintmax_t) uid);
  char lockfile[len];
  snprintf (lockfile, len, "%s/lock", cachedir);
  char appliancedir[len];
  snprintf (appliancedir, len, "%s/appliance.d", cachedir);

  ignore_value (mkdir (cachedir, 0755));
  ignore_value (chmod (cachedir, 0755)); /* RHBZ#921292 */

  /* See if the cache directory exists and passes some simple checks
   * to make sure it has not been tampered with.
   */
  if (lstat (cachedir, &statbuf) == -1)
    return 0;
  if (statbuf.st_uid != uid) {
    error (g, _("security: cached appliance %s is not owned by UID %ju"),
           cachedir, (uintmax_t) uid);
    return -1;
  }
  if (!S_ISDIR (statbuf.st_mode)) {
    error (g, _("security: cached appliance %s is not a directory (mode %o)"),
           cachedir, statbuf.st_mode);
    return -1;
  }
  if ((statbuf.st_mode & 0022) != 0) {
    error (g, _("security: cached appliance %s is writable by group or other (mode %o)"),
           cachedir, statbuf.st_mode);
    return -1;
  }

  (void) utimes (cachedir, NULL);
  if (g->verbose)
    guestfs_int_print_timestamped_message (g, "begin building supermin appliance");

  /* Build the appliance if it needs to be built. */
  if (g->verbose)
    guestfs_int_print_timestamped_message (g, "run supermin");

  if (run_supermin_build (g, lockfile, appliancedir, supermin_path) == -1)
    return -1;

  if (g->verbose)
    guestfs_int_print_timestamped_message (g, "finished building supermin appliance");

  /* Return the appliance filenames. */
  *kernel = safe_malloc (g, len);
#ifdef DTB_WILDCARD
  *dtb = safe_malloc (g, len);
#else
  *dtb = NULL;
#endif
  *initrd = safe_malloc (g, len);
  *appliance = safe_malloc (g, len);
  snprintf (*kernel, len, "%s/kernel", appliancedir);
#ifdef DTB_WILDCARD
  snprintf (*dtb, len, "%s/dtb", appliancedir);
#endif
  snprintf (*initrd, len, "%s/initrd", appliancedir);
  snprintf (*appliance, len, "%s/root", appliancedir);

  /* Touch the files so they don't get deleted (as they are in /var/tmp). */
  (void) utimes (*kernel, NULL);
#ifdef DTB_WILDCARD
  (void) utimes (*dtb, NULL);
#endif
  (void) utimes (*initrd, NULL);

  /* Checking backend != "uml" is a big hack.  UML encodes the mtime
   * of the original backing file (in this case, the appliance) in the
   * COW file, and checks it when adding it to the VM.  If there are
   * multiple threads running and one touches the appliance here, it
   * will disturb the mtime and UML will give an error.
   *
   * We can get rid of this hack as soon as UML fixes the
   * ubdN=cow,original parsing bug, since we won't need to run
   * uml_mkcow separately, so there is no possible race.
   *
   * XXX
   */
  if (STRNEQ (g->backend, "uml"))
    (void) utimes (*appliance, NULL);

  return 0;
}
Пример #24
0
void
sink(int argc, char **argv)
{
	static BUF buffer;
	struct stat stb;
	enum {
		YES, NO, DISPLAYED
	} wrerr;
	BUF *bp;
	off_t i;
	size_t j, count;
	int amt, exists, first, ofd;
	mode_t mode, omode, mask;
	off_t size, statbytes;
	unsigned long long ull;
	int setimes, targisdir, wrerrno = 0;
	char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
	struct timeval tv[2];

#define	atime	tv[0]
#define	mtime	tv[1]
#define	SCREWUP(str)	{ why = str; goto screwup; }

	setimes = targisdir = 0;
	mask = umask(0);
	if (!pflag)
		(void) umask(mask);
	if (argc != 1) {
		run_err("ambiguous target");
		exit(1);
	}
	targ = *argv;
	if (targetshouldbedirectory)
		verifydir(targ);

	(void) atomicio(vwrite, remout, "", 1);
	if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
		targisdir = 1;
	for (first = 1;; first = 0) {
		cp = buf;
		if (atomicio(read, remin, cp, 1) != 1)
			return;
		if (*cp++ == '\n')
			SCREWUP("unexpected <newline>");
		do {
			if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
				SCREWUP("lost connection");
			*cp++ = ch;
		} while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
		*cp = 0;
		if (verbose_mode)
			fprintf(stderr, "Sink: %s", buf);

		if (buf[0] == '\01' || buf[0] == '\02') {
			if (iamremote == 0)
				(void) atomicio(vwrite, STDERR_FILENO,
				    buf + 1, strlen(buf + 1));
			if (buf[0] == '\02')
				exit(1);
			++errs;
			continue;
		}
		if (buf[0] == 'E') {
			(void) atomicio(vwrite, remout, "", 1);
			return;
		}
		if (ch == '\n')
			*--cp = 0;

		cp = buf;
		if (*cp == 'T') {
			setimes++;
			cp++;
			if (!isdigit((unsigned char)*cp))
				SCREWUP("mtime.sec not present");
			ull = strtoull(cp, &cp, 10);
			if (!cp || *cp++ != ' ')
				SCREWUP("mtime.sec not delimited");
			if ((time_t)ull < 0 ||
			    (unsigned long long)(time_t)ull != ull)
				setimes = 0;	/* out of range */
			mtime.tv_sec = ull;
			mtime.tv_usec = strtol(cp, &cp, 10);
			if (!cp || *cp++ != ' ' || mtime.tv_usec < 0 ||
			    mtime.tv_usec > 999999)
				SCREWUP("mtime.usec not delimited");
			if (!isdigit((unsigned char)*cp))
				SCREWUP("atime.sec not present");
			ull = strtoull(cp, &cp, 10);
			if (!cp || *cp++ != ' ')
				SCREWUP("atime.sec not delimited");
			if ((time_t)ull < 0 ||
			    (unsigned long long)(time_t)ull != ull)
				setimes = 0;	/* out of range */
			atime.tv_sec = ull;
			atime.tv_usec = strtol(cp, &cp, 10);
			if (!cp || *cp++ != '\0' || atime.tv_usec < 0 ||
			    atime.tv_usec > 999999)
				SCREWUP("atime.usec not delimited");
			(void) atomicio(vwrite, remout, "", 1);
			continue;
		}
		if (*cp != 'C' && *cp != 'D') {
			/*
			 * Check for the case "rcp remote:foo\* local:bar".
			 * In this case, the line "No match." can be returned
			 * by the shell before the rcp command on the remote is
			 * executed so the ^Aerror_message convention isn't
			 * followed.
			 */
			if (first) {
				run_err("%s", cp);
				exit(1);
			}
			SCREWUP("expected control record");
		}
		mode = 0;
		for (++cp; cp < buf + 5; cp++) {
			if (*cp < '0' || *cp > '7')
				SCREWUP("bad mode");
			mode = (mode << 3) | (*cp - '0');
		}
		if (*cp++ != ' ')
			SCREWUP("mode not delimited");

		for (size = 0; isdigit((unsigned char)*cp);)
			size = size * 10 + (*cp++ - '0');
		if (*cp++ != ' ')
			SCREWUP("size not delimited");
		if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) {
			run_err("error: unexpected filename: %s", cp);
			exit(1);
		}
		if (targisdir) {
			static char *namebuf;
			static size_t cursize;
			size_t need;

			need = strlen(targ) + strlen(cp) + 250;
			if (need > cursize) {
				free(namebuf);
				namebuf = xmalloc(need);
				cursize = need;
			}
			(void) snprintf(namebuf, need, "%s%s%s", targ,
			    strcmp(targ, "/") ? "/" : "", cp);
			np = namebuf;
		} else
			np = targ;
		curfile = cp;
		exists = stat(np, &stb) == 0;
		if (buf[0] == 'D') {
			int mod_flag = pflag;
			if (!iamrecursive)
				SCREWUP("received directory without -r");
			if (exists) {
				if (!S_ISDIR(stb.st_mode)) {
					errno = ENOTDIR;
					goto bad;
				}
				if (pflag)
					(void) chmod(np, mode);
			} else {
				/* Handle copying from a read-only
				   directory */
				mod_flag = 1;
				if (mkdir(np, mode | S_IRWXU) < 0)
					goto bad;
			}
			vect[0] = xstrdup(np);
			sink(1, vect);
			if (setimes) {
				setimes = 0;
				if (utimes(vect[0], tv) < 0)
					run_err("%s: set times: %s",
					    vect[0], strerror(errno));
			}
			if (mod_flag)
				(void) chmod(vect[0], mode);
			free(vect[0]);
			continue;
		}
		omode = mode;
		mode |= S_IWUSR;
		if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
bad:			run_err("%s: %s", np, strerror(errno));
			continue;
		}
		(void) atomicio(vwrite, remout, "", 1);
		if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) {
			(void) close(ofd);
			continue;
		}
		cp = bp->buf;
		wrerr = NO;

		statbytes = 0;
		if (showprogress)
			start_progress_meter(curfile, size, &statbytes);
		set_nonblock(remin);
		for (count = i = 0; i < size; i += bp->cnt) {
			amt = bp->cnt;
			if (i + amt > size)
				amt = size - i;
			count += amt;
			do {
				j = atomicio6(read, remin, cp, amt,
				    scpio, &statbytes);
				if (j == 0) {
					run_err("%s", j != EPIPE ?
					    strerror(errno) :
					    "dropped connection");
					exit(1);
				}
				amt -= j;
				cp += j;
			} while (amt > 0);

			if (count == bp->cnt) {
				/* Keep reading so we stay sync'd up. */
				if (wrerr == NO) {
					if (atomicio(vwrite, ofd, bp->buf,
					    count) != count) {
						wrerr = YES;
						wrerrno = errno;
					}
				}
				count = 0;
				cp = bp->buf;
			}
		}
		unset_nonblock(remin);
		if (showprogress)
			stop_progress_meter();
		if (count != 0 && wrerr == NO &&
		    atomicio(vwrite, ofd, bp->buf, count) != count) {
			wrerr = YES;
			wrerrno = errno;
		}
		if (wrerr == NO && (!exists || S_ISREG(stb.st_mode)) &&
		    ftruncate(ofd, size) != 0) {
			run_err("%s: truncate: %s", np, strerror(errno));
			wrerr = DISPLAYED;
		}
		if (pflag) {
			if (exists || omode != mode)
#ifdef HAVE_FCHMOD
				if (fchmod(ofd, omode)) {
#else /* HAVE_FCHMOD */
				if (chmod(np, omode)) {
#endif /* HAVE_FCHMOD */
					run_err("%s: set mode: %s",
					    np, strerror(errno));
					wrerr = DISPLAYED;
				}
		} else {
			if (!exists && omode != mode)
#ifdef HAVE_FCHMOD
				if (fchmod(ofd, omode & ~mask)) {
#else /* HAVE_FCHMOD */
				if (chmod(np, omode & ~mask)) {
#endif /* HAVE_FCHMOD */
					run_err("%s: set mode: %s",
					    np, strerror(errno));
					wrerr = DISPLAYED;
				}
		}
		if (close(ofd) == -1) {
			wrerr = YES;
			wrerrno = errno;
		}
		(void) response();
		if (setimes && wrerr == NO) {
			setimes = 0;
			if (utimes(np, tv) < 0) {
				run_err("%s: set times: %s",
				    np, strerror(errno));
				wrerr = DISPLAYED;
			}
		}
		switch (wrerr) {
		case YES:
			run_err("%s: %s", np, strerror(wrerrno));
			break;
		case NO:
			(void) atomicio(vwrite, remout, "", 1);
			break;
		case DISPLAYED:
			break;
		}
	}
screwup:
	run_err("protocol error: %s", why);
	exit(1);
}

int
response(void)
{
	char ch, *cp, resp, rbuf[2048];

	if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp))
		lostconn(0);

	cp = rbuf;
	switch (resp) {
	case 0:		/* ok */
		return (0);
	default:
		*cp++ = resp;
		/* FALLTHROUGH */
	case 1:		/* error, followed by error msg */
	case 2:		/* fatal error, "" */
		do {
			if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
				lostconn(0);
			*cp++ = ch;
		} while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');

		if (!iamremote)
			(void) atomicio(vwrite, STDERR_FILENO, rbuf, cp - rbuf);
		++errs;
		if (resp == 1)
			return (-1);
		exit(1);
	}
	/* NOTREACHED */
}

void
usage(void)
{
	(void) fprintf(stderr,
	    "usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
	    "           [-l limit] [-o ssh_option] [-P port] [-S program]\n"
	    "           [[user@]host1:]file1 ... [[user@]host2:]file2\n");
	exit(1);
}
Пример #25
0
static int
fastcopy(char *from, char *to, struct stat *sbp)
{
#if defined(__NetBSD__)
	struct timespec ts[2];
#else
	struct timeval tval[2];
#endif
	static blksize_t blen;
	static char *bp;
	int nread, from_fd, to_fd;

	if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
		warn("%s", from);
		return (1);
	}
	if ((to_fd =
	    open(to, O_CREAT | O_TRUNC | O_WRONLY, sbp->st_mode)) < 0) {
		warn("%s", to);
		(void)close(from_fd);
		return (1);
	}
	if (!blen && !(bp = malloc(blen = sbp->st_blksize))) {
		warn(NULL);
		blen = 0;
		(void)close(from_fd);
		(void)close(to_fd);
		return (1);
	}
	while ((nread = read(from_fd, bp, blen)) > 0)
		if (write(to_fd, bp, nread) != nread) {
			warn("%s", to);
			goto err;
		}
	if (nread < 0) {
		warn("%s", from);
err:		if (unlink(to))
			warn("%s: remove", to);
		(void)close(from_fd);
		(void)close(to_fd);
		return (1);
	}

	if (fcpxattr(from_fd, to_fd) == -1)
		warn("%s: error copying extended attributes", to);

	(void)close(from_fd);
#ifdef BSD4_4
#if defined(__NetBSD__)
	ts[0] = sbp->st_atimespec;
	ts[1] = sbp->st_mtimespec;
#else
	TIMESPEC_TO_TIMEVAL(&tval[0], &sbp->st_atimespec);
	TIMESPEC_TO_TIMEVAL(&tval[1], &sbp->st_mtimespec);
#endif
#else
	tval[0].tv_sec = sbp->st_atime;
	tval[1].tv_sec = sbp->st_mtime;
	tval[0].tv_usec = 0;
	tval[1].tv_usec = 0;
#endif
#ifdef __SVR4
	if (utimes(to, tval))
#else
#if defined(__NetBSD__)
	if (futimens(to_fd, ts))
#else
	if (futimes(to_fd, tval))
#endif
#endif
		warn("%s: set times", to);
	if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
		if (errno != EPERM)
			warn("%s: set owner/group", to);
		sbp->st_mode &= ~(S_ISUID | S_ISGID);
	}
	if (fchmod(to_fd, sbp->st_mode))
		warn("%s: set mode", to);
	if (fchflags(to_fd, sbp->st_flags) && (errno != EOPNOTSUPP))
		warn("%s: set flags (was: 0%07o)", to, sbp->st_flags);

	if (close(to_fd)) {
		warn("%s", to);
		return (1);
	}

	if (unlink(from)) {
		warn("%s: remove", from);
		return (1);
	}

	if (vflg)
		printf("%s -> %s\n", from, to);

	return (0);
}
Пример #26
0
RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
                               PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags)
{
    /*
     * Validate input.
     */
    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
    AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
    AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
    AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
    AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
    AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
    AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);

    /*
     * Convert the paths.
     */
    char const *pszNativePath;
    int rc = rtPathToNative(&pszNativePath, pszPath, NULL);
    if (RT_SUCCESS(rc))
    {
        RTFSOBJINFO ObjInfo;

        /*
         * If it's a no-op, we'll only verify the existance of the file.
         */
        if (!pAccessTime && !pModificationTime)
            rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, fFlags);
        else
        {
            /*
             * Convert the input to timeval, getting the missing one if necessary,
             * and call the API which does the change.
             */
            struct timeval aTimevals[2];
            if (pAccessTime && pModificationTime)
            {
                RTTimeSpecGetTimeval(pAccessTime,       &aTimevals[0]);
                RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]);
            }
            else
            {
                rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags);
                if (RT_SUCCESS(rc))
                {
                    RTTimeSpecGetTimeval(pAccessTime        ? pAccessTime       : &ObjInfo.AccessTime,       &aTimevals[0]);
                    RTTimeSpecGetTimeval(pModificationTime  ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]);
                }
                else
                    Log(("RTPathSetTimes('%s',%p,%p,,): RTPathQueryInfo failed with %Rrc\n",
                         pszPath, pAccessTime, pModificationTime, rc));
            }
            if (RT_SUCCESS(rc))
            {
                if (fFlags & RTPATH_F_FOLLOW_LINK)
                {
                    if (utimes(pszNativePath, aTimevals))
                        rc = RTErrConvertFromErrno(errno);
                }
#if (defined(RT_OS_DARWIN) && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) \
 || defined(RT_OS_FREEBSD) \
 || defined(RT_OS_LINUX) \
 || defined(RT_OS_OS2) /** @todo who really has lutimes? */
                else
                {
                    if (lutimes(pszNativePath, aTimevals))
                        rc = RTErrConvertFromErrno(errno);
                }
#else
                else
                {
                    if (pAccessTime && pModificationTime)
                        rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags);
                    if (RT_SUCCESS(rc) && RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
                        rc = VERR_NS_SYMLINK_SET_TIME;
                    else if (RT_SUCCESS(rc))
                    {
                        if (utimes(pszNativePath, aTimevals))
                            rc = RTErrConvertFromErrno(errno);
                    }
                }
#endif
                if (RT_FAILURE(rc))
                    Log(("RTPathSetTimes('%s',%p,%p,,): failed with %Rrc and errno=%d\n",
                         pszPath, pAccessTime, pModificationTime, rc, errno));
            }
        }
        rtPathFreeNative(pszNativePath, pszPath);
    }
Пример #27
0
int
fdutimens (int fd, char const *file, struct timespec const timespec[2])
{
    struct timespec adjusted_timespec[2];
    struct timespec *ts = timespec ? adjusted_timespec : NULL;
    int adjustment_needed = 0;
    struct stat st;

    if (ts)
    {
        adjusted_timespec[0] = timespec[0];
        adjusted_timespec[1] = timespec[1];
        adjustment_needed = validate_timespec (ts);
    }
    if (adjustment_needed < 0)
        return -1;

    /* Require that at least one of FD or FILE are potentially valid, to avoid
       a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
       than failing.  */
    if (fd < 0 && !file)
    {
        errno = EBADF;
        return -1;
    }

    /* Some Linux-based NFS clients are buggy, and mishandle time stamps
       of files in NFS file systems in some cases.  We have no
       configure-time test for this, but please see
       <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
       some of the problems with Linux 2.6.16.  If this affects you,
       compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
       help in some cases, albeit at a cost in performance.  But you
       really should upgrade your kernel to a fixed version, since the
       problem affects many applications.  */

#if HAVE_BUGGY_NFS_TIME_STAMPS
    if (fd < 0)
        sync ();
    else
        fsync (fd);
#endif

    /* POSIX 2008 added two interfaces to set file timestamps with
       nanosecond resolution; newer Linux implements both functions via
       a single syscall.  We provide a fallback for ENOSYS (for example,
       compiling against Linux 2.6.25 kernel headers and glibc 2.7, but
       running on Linux 2.6.18 kernel).  */
#if HAVE_UTIMENSAT || HAVE_FUTIMENS
    if (0 <= utimensat_works_really)
    {
        int result;
# if __linux__
        /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
           systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
           but work if both times are either explicitly specified or
           UTIME_NOW.  Work around it with a preparatory [f]stat prior
           to calling futimens/utimensat; fortunately, there is not much
           timing impact due to the extra syscall even on file systems
           where UTIME_OMIT would have worked.  FIXME: Simplify this in
           2012, when file system bugs are no longer common.  */
        if (adjustment_needed == 2)
        {
            if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
                return -1;
            if (ts[0].tv_nsec == UTIME_OMIT)
                ts[0] = get_stat_atime (&st);
            else if (ts[1].tv_nsec == UTIME_OMIT)
                ts[1] = get_stat_mtime (&st);
            /* Note that st is good, in case utimensat gives ENOSYS.  */
            adjustment_needed++;
        }
# endif /* __linux__ */
# if HAVE_UTIMENSAT
        if (fd < 0)
        {
            result = utimensat (AT_FDCWD, file, ts, 0);
#  ifdef __linux__
            /* Work around a kernel bug:
               http://bugzilla.redhat.com/442352
               http://bugzilla.redhat.com/449910
               It appears that utimensat can mistakenly return 280 rather
               than -1 upon ENOSYS failure.
               FIXME: remove in 2010 or whenever the offending kernels
               are no longer in common use.  */
            if (0 < result)
                errno = ENOSYS;
#  endif /* __linux__ */
            if (result == 0 || errno != ENOSYS)
            {
                utimensat_works_really = 1;
                return result;
            }
        }
# endif /* HAVE_UTIMENSAT */
# if HAVE_FUTIMENS
        if (0 <= fd)
        {
            result = futimens (fd, ts);
#  ifdef __linux__
            /* Work around the same bug as above.  */
            if (0 < result)
                errno = ENOSYS;
#  endif /* __linux__ */
            if (result == 0 || errno != ENOSYS)
            {
                utimensat_works_really = 1;
                return result;
            }
        }
# endif /* HAVE_FUTIMENS */
    }
    utimensat_works_really = -1;
    lutimensat_works_really = -1;
#endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */

    /* The platform lacks an interface to set file timestamps with
       nanosecond resolution, so do the best we can, discarding any
       fractional part of the timestamp.  */

    if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
    {
        if (adjustment_needed != 3
                && (fd < 0 ? stat (file, &st) : fstat (fd, &st)))
            return -1;
        if (ts && update_timespec (&st, &ts))
            return 0;
    }

    {
#if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
        struct timeval timeval[2];
        struct timeval *t;
        if (ts)
        {
            timeval[0].tv_sec = ts[0].tv_sec;
            timeval[0].tv_usec = ts[0].tv_nsec / 1000;
            timeval[1].tv_sec = ts[1].tv_sec;
            timeval[1].tv_usec = ts[1].tv_nsec / 1000;
            t = timeval;
        }
        else
            t = NULL;

        if (fd < 0)
        {
# if HAVE_FUTIMESAT
            return futimesat (AT_FDCWD, file, t);
# endif
        }
        else
        {
            /* If futimesat or futimes fails here, don't try to speed things
               up by returning right away.  glibc can incorrectly fail with
               errno == ENOENT if /proc isn't mounted.  Also, Mandrake 10.0
               in high security mode doesn't allow ordinary users to read
               /proc/self, so glibc incorrectly fails with errno == EACCES.
               If errno == EIO, EPERM, or EROFS, it's probably safe to fail
               right away, but these cases are rare enough that they're not
               worth optimizing, and who knows what other messed-up systems
               are out there?  So play it safe and fall back on the code
               below.  */

# if (HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) || HAVE_FUTIMES
#  if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
#   undef futimes
#   define futimes(fd, t) futimesat (fd, NULL, t)
#  endif
            if (futimes (fd, t) == 0)
            {
#  if __linux__ && __GLIBC__
                /* Work around a longstanding glibc bug, still present as
                   of 2010-12-27.  On older Linux kernels that lack both
                   utimensat and utimes, glibc's futimes rounds instead of
                   truncating when falling back on utime.  The same bug
                   occurs in futimesat with a null 2nd arg.  */
                if (t)
                {
                    bool abig = 500000 <= t[0].tv_usec;
                    bool mbig = 500000 <= t[1].tv_usec;
                    if ((abig | mbig) && fstat (fd, &st) == 0)
                    {
                        /* If these two subtractions overflow, they'll
                           track the overflows inside the buggy glibc.  */
                        time_t adiff = st.st_atime - t[0].tv_sec;
                        time_t mdiff = st.st_mtime - t[1].tv_sec;

                        struct timeval *tt = NULL;
                        struct timeval truncated_timeval[2];
                        truncated_timeval[0] = t[0];
                        truncated_timeval[1] = t[1];
                        if (abig && adiff == 1 && get_stat_atime_ns (&st) == 0)
                        {
                            tt = truncated_timeval;
                            tt[0].tv_usec = 0;
                        }
                        if (mbig && mdiff == 1 && get_stat_mtime_ns (&st) == 0)
                        {
                            tt = truncated_timeval;
                            tt[1].tv_usec = 0;
                        }
                        if (tt)
                            futimes (fd, tt);
                    }
                }
#  endif

                return 0;
            }
# endif
        }
#endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */

        if (!file)
        {
#if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG)          \
        || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
            errno = ENOSYS;
#endif
            return -1;
        }

#if HAVE_WORKING_UTIMES
        return utimes (file, t);
#else
        {
            struct utimbuf utimbuf;
            struct utimbuf *ut;
            if (ts)
            {
                utimbuf.actime = ts[0].tv_sec;
                utimbuf.modtime = ts[1].tv_sec;
                ut = &utimbuf;
            }
            else
                ut = NULL;

            return utime (file, ut);
        }
#endif /* !HAVE_WORKING_UTIMES */
    }
}
Пример #28
0
void
sink(int argc, char *argv[])
{
	static BUF buffer;
	struct stat stb;
	struct timeval tv[2];
	enum { YES, NO, DISPLAYED } wrerr;
	BUF *bp;
	off_t i, j, size;
	int amt, exists, first, mask, mode, ofd, omode;
	size_t count;
	int setimes, targisdir, wrerrno = 0;
	char ch, *cp, *np, *targ, *vect[1], buf[BUFSIZ], path[PATH_MAX];
	const char *why;

#define	atime	tv[0]
#define	mtime	tv[1]
#define	SCREWUP(str)	{ why = str; goto screwup; }

	setimes = targisdir = 0;
	mask = umask(0);
	if (!pflag)
		(void)umask(mask);
	if (argc != 1) {
		run_err("ambiguous target");
		exit(1);
	}
	targ = *argv;
	if (targetshouldbedirectory)
		verifydir(targ);
	(void)write(rem, "", 1);
	if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
		targisdir = 1;
	for (first = 1;; first = 0) {
		cp = buf;
		if (read(rem, cp, 1) <= 0)
			return;
		if (*cp++ == '\n')
			SCREWUP("unexpected <newline>");
		do {
			if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
				SCREWUP("lost connection");
			*cp++ = ch;
		} while (cp < &buf[BUFSIZ - 1] && ch != '\n');
		*cp = 0;

		if (buf[0] == '\01' || buf[0] == '\02') {
			if (iamremote == 0)
				(void)write(STDERR_FILENO,
				    buf + 1, strlen(buf + 1));
			if (buf[0] == '\02')
				exit(1);
			++errs;
			continue;
		}
		if (buf[0] == 'E') {
			(void)write(rem, "", 1);
			return;
		}

		if (ch == '\n')
			*--cp = 0;

		cp = buf;
		if (*cp == 'T') {
			setimes++;
			cp++;
			mtime.tv_sec = strtol(cp, &cp, 10);
			if (!cp || *cp++ != ' ')
				SCREWUP("mtime.sec not delimited");
			mtime.tv_usec = strtol(cp, &cp, 10);
			if (!cp || *cp++ != ' ')
				SCREWUP("mtime.usec not delimited");
			atime.tv_sec = strtol(cp, &cp, 10);
			if (!cp || *cp++ != ' ')
				SCREWUP("atime.sec not delimited");
			atime.tv_usec = strtol(cp, &cp, 10);
			if (!cp || *cp++ != '\0')
				SCREWUP("atime.usec not delimited");
			(void)write(rem, "", 1);
			continue;
		}
		if (*cp != 'C' && *cp != 'D') {
			/*
			 * Check for the case "rcp remote:foo\* local:bar".
			 * In this case, the line "No match." can be returned
			 * by the shell before the rcp command on the remote is
			 * executed so the ^Aerror_message convention isn't
			 * followed.
			 */
			if (first) {
				run_err("%s", cp);
				exit(1);
			}
			SCREWUP("expected control record");
		}
		mode = 0;
		for (++cp; cp < buf + 5; cp++) {
			if (*cp < '0' || *cp > '7')
				SCREWUP("bad mode");
			mode = (mode << 3) | (*cp - '0');
		}
		if (*cp++ != ' ')
			SCREWUP("mode not delimited");

		for (size = 0; isdigit(*cp);)
			size = size * 10 + (*cp++ - '0');
		if (*cp++ != ' ')
			SCREWUP("size not delimited");
		if (targisdir) {
			if (strlen(targ) + (*targ ? 1 : 0) + strlen(cp)
					>= sizeof(path)) {
				run_err("%s%s%s: name too long", targ,
					*targ ? "/" : "", cp);
				exit(1);
			}
			(void)snprintf(path, sizeof(path), "%s%s%s", targ,
			    *targ ? "/" : "", cp);
			np = path;
		} else
			np = targ;
		exists = stat(np, &stb) == 0;
		if (buf[0] == 'D') {
			int mod_flag = pflag;
			if (exists) {
				if (!S_ISDIR(stb.st_mode)) {
					errno = ENOTDIR;
					goto bad;
				}
				if (pflag)
					(void)chmod(np, mode);
			} else {
				/* Handle copying from a read-only directory */
				mod_flag = 1;
				if (mkdir(np, mode | S_IRWXU) < 0)
					goto bad;
			}
			vect[0] = np;
			sink(1, vect);
			if (setimes) {
				setimes = 0;
				if (utimes(np, tv) < 0)
				    run_err("%s: set times: %s",
					np, strerror(errno));
			}
			if (mod_flag)
				(void)chmod(np, mode);
			continue;
		}
		omode = mode;
		mode |= S_IWRITE;
		if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
bad:			run_err("%s: %s", np, strerror(errno));
			continue;
		}
		(void)write(rem, "", 1);
		if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) {
			(void)close(ofd);
			continue;
		}
		cp = bp->buf;
		wrerr = NO;
		for (count = i = 0; i < size; i += BUFSIZ) {
			amt = BUFSIZ;
			if (i + amt > size)
				amt = size - i;
			count += amt;
			do {
				j = read(rem, cp, amt);
				if (j <= 0) {
					run_err("%s", j ? strerror(errno) :
					    "dropped connection");
					exit(1);
				}
				amt -= j;
				cp += j;
			} while (amt > 0);
			if (count == bp->cnt) {
				/* Keep reading so we stay sync'd up. */
				if (wrerr == NO) {
					j = write(ofd, bp->buf, count);
					if (j != (off_t)count) {
						wrerr = YES;
						wrerrno = j >= 0 ? EIO : errno;
					}
				}
				count = 0;
				cp = bp->buf;
			}
		}
		if (count != 0 && wrerr == NO &&
		    (j = write(ofd, bp->buf, count)) != (off_t)count) {
			wrerr = YES;
			wrerrno = j >= 0 ? EIO : errno;
		}
		if (ftruncate(ofd, size)) {
			run_err("%s: truncate: %s", np, strerror(errno));
			wrerr = DISPLAYED;
		}
		if (pflag) {
			if (exists || omode != mode)
				if (fchmod(ofd, omode))
					run_err("%s: set mode: %s",
					    np, strerror(errno));
		} else {
			if (!exists && omode != mode)
				if (fchmod(ofd, omode & ~mask))
					run_err("%s: set mode: %s",
					    np, strerror(errno));
		}
		(void)close(ofd);
		(void)response();
		if (setimes && wrerr == NO) {
			setimes = 0;
			if (utimes(np, tv) < 0) {
				run_err("%s: set times: %s",
				    np, strerror(errno));
				wrerr = DISPLAYED;
			}
		}
		switch(wrerr) {
		case YES:
			run_err("%s: %s", np, strerror(wrerrno));
			break;
		case NO:
			(void)write(rem, "", 1);
			break;
		case DISPLAYED:
			break;
		}
	}
screwup:
	run_err("protocol error: %s", why);
	exit(1);
}
Пример #29
0
/* Return:
 * -1 error, copy not made
 *  0 copy is made or user answered "no" in interactive mode
 *    (failures to preserve mode/owner/times are not reported in exit code)
 */
int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
{
	/* This is a recursive function, try to minimize stack usage */
	/* NB: each struct stat is ~100 bytes */
	struct stat source_stat;
	struct stat dest_stat;
	smallint retval = 0;
	smallint dest_exists = 0;
	smallint ovr;

/* Inverse of cp -d ("cp without -d") */
#define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0))

	if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) {
		/* This may be a dangling symlink.
		 * Making [sym]links to dangling symlinks works, so... */
		if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK))
			goto make_links;
		bb_perror_msg("can't stat '%s'", source);
		return -1;
	}

	if (lstat(dest, &dest_stat) < 0) {
		if (errno != ENOENT) {
			bb_perror_msg("can't stat '%s'", dest);
			return -1;
		}
	} else {
		if (source_stat.st_dev == dest_stat.st_dev
		 && source_stat.st_ino == dest_stat.st_ino
		) {
			bb_error_msg("'%s' and '%s' are the same file", source, dest);
			return -1;
		}
		dest_exists = 1;
	}

#if ENABLE_SELINUX
	if ((flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) && is_selinux_enabled() > 0) {
		security_context_t con;
		if (lgetfilecon(source, &con) >= 0) {
			if (setfscreatecon(con) < 0) {
				bb_perror_msg("can't set setfscreatecon %s", con);
				freecon(con);
				return -1;
			}
		} else if (errno == ENOTSUP || errno == ENODATA) {
			setfscreatecon_or_die(NULL);
		} else {
			bb_perror_msg("can't lgetfilecon %s", source);
			return -1;
		}
	}
#endif

	if (S_ISDIR(source_stat.st_mode)) {
		DIR *dp;
		const char *tp;
		struct dirent *d;
		mode_t saved_umask = 0;

		if (!(flags & FILEUTILS_RECUR)) {
			bb_error_msg("omitting directory '%s'", source);
			return -1;
		}

		/* Did we ever create source ourself before? */
		tp = is_in_ino_dev_hashtable(&source_stat);
		if (tp) {
			/* We did! it's a recursion! man the lifeboats... */
			bb_error_msg("recursion detected, omitting directory '%s'",
					source);
			return -1;
		}

		if (dest_exists) {
			if (!S_ISDIR(dest_stat.st_mode)) {
				bb_error_msg("target '%s' is not a directory", dest);
				return -1;
			}
			/* race here: user can substitute a symlink between
			 * this check and actual creation of files inside dest */
		} else {
			/* Create DEST */
			mode_t mode;
			saved_umask = umask(0);

			mode = source_stat.st_mode;
			if (!(flags & FILEUTILS_PRESERVE_STATUS))
				mode = source_stat.st_mode & ~saved_umask;
			/* Allow owner to access new dir (at least for now) */
			mode |= S_IRWXU;
			if (mkdir(dest, mode) < 0) {
				umask(saved_umask);
				bb_perror_msg("can't create directory '%s'", dest);
				return -1;
			}
			umask(saved_umask);
			/* need stat info for add_to_ino_dev_hashtable */
			if (lstat(dest, &dest_stat) < 0) {
				bb_perror_msg("can't stat '%s'", dest);
				return -1;
			}
		}
		/* remember (dev,inode) of each created dir.
		 * NULL: name is not remembered */
		add_to_ino_dev_hashtable(&dest_stat, NULL);

		/* Recursively copy files in SOURCE */
		dp = opendir(source);
		if (dp == NULL) {
			retval = -1;
			goto preserve_mode_ugid_time;
		}

		while ((d = readdir(dp)) != NULL) {
			char *new_source, *new_dest;

			new_source = concat_subpath_file(source, d->d_name);
			if (new_source == NULL)
				continue;
			new_dest = concat_path_file(dest, d->d_name);
			if (copy_file(new_source, new_dest, flags & ~FILEUTILS_DEREFERENCE_L0) < 0)
				retval = -1;
			free(new_source);
			free(new_dest);
		}
		closedir(dp);

		if (!dest_exists
		 && chmod(dest, source_stat.st_mode & ~saved_umask) < 0
		) {
			bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
			/* retval = -1; - WRONG! copy *WAS* made */
		}
		goto preserve_mode_ugid_time;
	}

	if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) {
		int (*lf)(const char *oldpath, const char *newpath);
 make_links:
		/* Hmm... maybe
		 * if (DEREF && MAKE_SOFTLINK) source = realpath(source) ?
		 * (but realpath returns NULL on dangling symlinks...) */
		lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link;
		if (lf(source, dest) < 0) {
			ovr = ask_and_unlink(dest, flags);
			if (ovr <= 0)
				return ovr;
			if (lf(source, dest) < 0) {
				bb_perror_msg("can't create link '%s'", dest);
				return -1;
			}
		}
		/* _Not_ jumping to preserve_mode_ugid_time:
		 * (sym)links don't have those */
		return 0;
	}

	if (/* "cp thing1 thing2" without -R: just open and read() from thing1 */
	    !(flags & FILEUTILS_RECUR)
	    /* "cp [-opts] regular_file thing2" */
	 || S_ISREG(source_stat.st_mode)
	 /* DEREF uses stat, which never returns S_ISLNK() == true.
	  * So the below is never true: */
	 /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */
	) {
		int src_fd;
		int dst_fd;
		mode_t new_mode;

		if (!FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) {
			/* "cp -d symlink dst": create a link */
			goto dont_cat;
		}

		if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) {
			const char *link_target;
			link_target = is_in_ino_dev_hashtable(&source_stat);
			if (link_target) {
				if (link(link_target, dest) < 0) {
					ovr = ask_and_unlink(dest, flags);
					if (ovr <= 0)
						return ovr;
					if (link(link_target, dest) < 0) {
						bb_perror_msg("can't create link '%s'", dest);
						return -1;
					}
				}
				return 0;
			}
			add_to_ino_dev_hashtable(&source_stat, dest);
		}

		src_fd = open_or_warn(source, O_RDONLY);
		if (src_fd < 0)
			return -1;

		/* Do not try to open with weird mode fields */
		new_mode = source_stat.st_mode;
		if (!S_ISREG(source_stat.st_mode))
			new_mode = 0666;

		// POSIX way is a security problem versus (sym)link attacks
		if (!ENABLE_FEATURE_NON_POSIX_CP) {
			dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode);
		} else { /* safe way: */
			dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
		}
		if (dst_fd == -1) {
			ovr = ask_and_unlink(dest, flags);
			if (ovr <= 0) {
				close(src_fd);
				return ovr;
			}
			/* It shouldn't exist. If it exists, do not open (symlink attack?) */
			dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
			if (dst_fd < 0) {
				close(src_fd);
				return -1;
			}
		}

#if ENABLE_SELINUX
		if ((flags & (FILEUTILS_PRESERVE_SECURITY_CONTEXT|FILEUTILS_SET_SECURITY_CONTEXT))
		 && is_selinux_enabled() > 0
		) {
			security_context_t con;
			if (getfscreatecon(&con) == -1) {
				bb_perror_msg("getfscreatecon");
				return -1;
			}
			if (con) {
				if (setfilecon(dest, con) == -1) {
					bb_perror_msg("setfilecon:%s,%s", dest, con);
					freecon(con);
					return -1;
				}
				freecon(con);
			}
		}
#endif

		if (bb_copyfd_eof(src_fd, dst_fd) == -1)
			retval = -1;
		/* Careful with writing... */
		if (close(dst_fd) < 0) {
			bb_perror_msg("error writing to '%s'", dest);
			retval = -1;
		}
		/* ...but read size is already checked by bb_copyfd_eof */
		close(src_fd);
		/* "cp /dev/something new_file" should not
		 * copy mode of /dev/something */
		if (!S_ISREG(source_stat.st_mode))
			return retval;
		goto preserve_mode_ugid_time;
	}
 dont_cat:

	/* Source is a symlink or a special file */
	/* We are lazy here, a bit lax with races... */
	if (dest_exists) {
		errno = EEXIST;
		ovr = ask_and_unlink(dest, flags);
		if (ovr <= 0)
			return ovr;
	}
	if (S_ISLNK(source_stat.st_mode)) {
		char *lpath = xmalloc_readlink_or_warn(source);
		if (lpath) {
			int r = symlink(lpath, dest);
			free(lpath);
			if (r < 0) {
				bb_perror_msg("can't create symlink '%s'", dest);
				return -1;
			}
			if (flags & FILEUTILS_PRESERVE_STATUS)
				if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
					bb_perror_msg("can't preserve %s of '%s'", "ownership", dest);
		}
		/* _Not_ jumping to preserve_mode_ugid_time:
		 * symlinks don't have those */
		return 0;
	}
	if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode)
	 || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode)
	) {
		if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
			bb_perror_msg("can't create '%s'", dest);
			return -1;
		}
	} else {
		bb_error_msg("unrecognized file '%s' with mode %x", source, source_stat.st_mode);
		return -1;
	}

 preserve_mode_ugid_time:

	if (flags & FILEUTILS_PRESERVE_STATUS
	/* Cannot happen: */
	/* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */
	) {
		struct timeval times[2];

		times[1].tv_sec = times[0].tv_sec = source_stat.st_mtime;
		times[1].tv_usec = times[0].tv_usec = 0;
		/* BTW, utimes sets usec-precision time - just FYI */
		if (utimes(dest, times) < 0)
			bb_perror_msg("can't preserve %s of '%s'", "times", dest);
		if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
			source_stat.st_mode &= ~(S_ISUID | S_ISGID);
			bb_perror_msg("can't preserve %s of '%s'", "ownership", dest);
		}
#if ENABLE_XATTR
		/* Preserve extended attributes. We must copy it after chown()
		 * because it resets capabilities. */
		if (copy_file_attr(source, dest) == -1)
			bb_perror_msg("can't preserve %s of '%s'",
				      "extended attributes", dest);
#endif
		if (chmod(dest, source_stat.st_mode) < 0)
			bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
	}

	return retval;
}
Пример #30
0
static void
docopy (const char *src, const char *dst)
{
  str tdst = strbuf ("%s#%d~", dst, int (getpid ()));
  tmppath = tdst.cstr ();

  tmofile = src;
  alarm (timeout);
  int sfd = open (src, O_RDONLY);
  struct stat sb;
  if (fstat (sfd, &sb) < 0) {
    close (sfd);
    sfd = -1;
  }
  alarm (0);
  if (sfd < 0)
    fatal ("%s: %m\n", src);

  tmofile = tmppath;
  alarm (timeout);
  unlink (tdst);
  int dfd = open (tdst, O_WRONLY|O_CREAT|O_TRUNC, 0444);
  alarm (0);
  if (dfd < 0)
    fatal ("%s: %m\n", tmppath);

  for (;;) {
    int n;
    char buf[65536];

    tmofile = src;
    alarm (timeout);
    n = read (sfd, buf, sizeof (buf));
    alarm (0);
    if (n == 0)
      break;
    else if (n < 0) {
      warn ("fatal: %s: %m\n", src);
      cleanup ();
    }

    tmofile = tdst;
    alarm (timeout);
    int nw = write (dfd, buf, n);
    alarm (0);
    if (nw != n) {
      warn ("fatal: %s: %m\n", tmppath);
      cleanup ();
    }
  }

  close (sfd);

  int r;

  tmofile = tdst;
  alarm (timeout);
  r = fsync (dfd);
  if (r >= 0)
    r = close (dfd);
  if (r >= 0) {
    struct timeval tvs[2];
    tvs[0].tv_sec = sb.st_atime;
    tvs[1].tv_sec = sb.st_mtime;
#ifdef SFS_HAVE_STAT_ST_MTIMESPEC
    tvs[0].tv_usec = sb.st_atimespec.tv_nsec / 1000;
    tvs[1].tv_usec = sb.st_mtimespec.tv_nsec / 1000;
#else /* !SFS_HAVE_STAT_ST_MTIMESPEC */
    tvs[0].tv_usec = tvs[1].tv_usec = 0;
#endif /* !SFS_HAVE_STAT_ST_MTIMESPEC */
    r = utimes (tmppath, tvs);
  }
  alarm (0);
  if (r < 0) {
    warn ("fatal: %s: %m\n", tmppath);
    cleanup ();
  }

  tmofile = dst;
  alarm (timeout);
  r = rename (tmppath, dst);
  alarm (0);
  if (r < 0) {
    warn ("fatal: %s: %m\n", tmppath);
    cleanup ();
  }
  tmofile = tmppath = NULL;
}