int makeflow_archive_copy_preserved_files(struct archive_instance *a, struct batch_task *t, char *task_path ) {
	struct batch_file *f;
	struct stat buf;
	struct list_cursor *cur = list_cursor_create(t->output_files);
	// Iterate through output files
	for(list_seek(cur, 0); list_get(cur, (void**)&f); list_next(cur)) {
		char *file_name = xxstrdup(f->outer_name);
		debug(D_MAKEFLOW_HOOK,"Trying to copy file to %s",file_name);
		char *file_to_check = xxstrdup(file_name);
		//Check to see if the directory was copied as an empty file/incorrectly
		stat(dirname(file_to_check),&buf);
		if(S_ISREG(buf.st_mode)){
			debug(D_MAKEFLOW,"Removing empty file in the place of directory name %s",file_to_check);
			char *dirEmpty = string_format("rm -rf %s",file_to_check);
			system(dirEmpty);
			free(dirEmpty);
		}
		free(file_to_check);
		// Gets path of output file
		char *output_file_path = string_format("%s/output_files/%s",task_path,basename(file_name));
		char *directory_name = xxstrdup(file_name);
		debug(D_MAKEFLOW_HOOK,"Creating directory %s",dirname(directory_name));
		if(strcmp(directory_name,file_name) != 0){
			//Create the upper level directory to copy the output files into if necessary
			if (!create_dir(directory_name, 0777) && errno != EEXIST){
				debug(D_ERROR|D_MAKEFLOW_HOOK,"Failed to create directory %s",directory_name);
				free(directory_name);
				free(output_file_path);
				free(file_name);
				return 1;
			}
		}
		free(directory_name);
		// Copy output file or directory over to specified location
		if(path_is_dir(output_file_path) != 1){
			int success = copy_file_to_file(output_file_path, file_name);
			free(output_file_path);
			free(file_name);
			if (!success) {
				list_cursor_destroy(cur);
				debug(D_ERROR|D_MAKEFLOW_HOOK,"Failed to copy output file %s to %s\n", output_file_path, file_name);
				return 1;
			}
		}
		else{
			if(copy_dir(output_file_path, file_name) != 0){
				list_cursor_destroy(cur);
								debug(D_ERROR|D_MAKEFLOW_HOOK,"Failed to copy output file %s to %s\n", output_file_path, file_name);
				free(output_file_path);
							free(file_name);
								return 1;
						}
			free(output_file_path);
			free(file_name);
		}
		}


	list_cursor_destroy(cur);

	return 0;
}
Example #2
0
static int lookup_umount_fs(struct libmnt_context *cxt)
{
	int rc, loopdev = 0;
	const char *tgt;
	struct libmnt_table *mtab = NULL;
	struct libmnt_fs *fs;

	assert(cxt);
	assert(cxt->fs);

	DBG(CXT, mnt_debug_h(cxt, "umount: lookup FS"));

	tgt = mnt_fs_get_target(cxt->fs);
	if (!tgt) {
		DBG(CXT, mnt_debug_h(cxt, "umount: undefined target"));
		return -EINVAL;
	}
	rc = mnt_context_get_mtab(cxt, &mtab);
	if (rc) {
		DBG(CXT, mnt_debug_h(cxt, "umount: failed to read mtab"));
		return rc;
	}

try_loopdev:
	fs = mnt_table_find_target(mtab, tgt, MNT_ITER_BACKWARD);
	if (!fs && mnt_context_is_swapmatch(cxt)) {
		/* maybe the option is source rather than target (mountpoint) */
		fs = mnt_table_find_source(mtab, tgt, MNT_ITER_BACKWARD);

		if (fs) {
			struct libmnt_fs *fs1 = mnt_table_find_target(mtab,
							mnt_fs_get_target(fs),
							MNT_ITER_BACKWARD);
			if (!fs1) {
				DBG(CXT, mnt_debug_h(cxt, "mtab is broken?!?!"));
				return -EINVAL;
			}
			if (fs != fs1) {
				/* Something was stacked over `file' on the
				 * same mount point. */
				DBG(CXT, mnt_debug_h(cxt,
						"umount: %s: %s is mounted "
						"over it on the same point",
						tgt, mnt_fs_get_source(fs1)));
				return -EINVAL;
			}
		}
	}

	if (!fs && !loopdev) {
		/*
		 * Maybe target is /path/file.img, try to convert to /dev/loopN
		 */
		struct stat st;

		if (stat(tgt, &st) == 0 && S_ISREG(st.st_mode)) {
			char *dev = NULL;
			int count = loopdev_count_by_backing_file(tgt, &dev);

			if (count == 1) {
				DBG(CXT, mnt_debug_h(cxt,
					"umount: %s --> %s (retry)", tgt, dev));
				mnt_fs_set_source(cxt->fs, tgt);
				mnt_fs_set_target(cxt->fs, dev);
				free(dev);
				tgt = mnt_fs_get_target(cxt->fs);

				loopdev = 1;		/* to avoid endless loop */
				goto try_loopdev;

			} else if (count > 1)
				DBG(CXT, mnt_debug_h(cxt,
					"umount: warning: %s is associated "
					"with more than one loodev", tgt));
		}
	}

	if (!fs) {
		DBG(CXT, mnt_debug_h(cxt, "umount: cannot find %s in mtab", tgt));
		return 0;
	}

	if (fs != cxt->fs) {
		/* copy from mtab to our FS description
		 */
		mnt_fs_set_source(cxt->fs, NULL);
		mnt_fs_set_target(cxt->fs, NULL);

		if (!mnt_copy_fs(cxt->fs, fs)) {
			DBG(CXT, mnt_debug_h(cxt, "umount: failed to copy FS"));
			return -errno;
		}
		DBG(CXT, mnt_debug_h(cxt, "umount: mtab applied"));
	}

	cxt->flags |= MNT_FL_TAB_APPLIED;
	return rc;
}
Example #3
0
int is_regular_file(const char *path)
{
    struct stat path_stat;
    stat(path, &path_stat);
    return S_ISREG(path_stat.st_mode);
}
Example #4
0
static void
filegen_open(
	FILEGEN *	gen,
	uint32_t		stamp,
	const time_t *	pivot
	)
{
	char *savename;	/* temp store for name collision handling */
	char *fullname;	/* name with any designation extension */
	char *filename;	/* name without designation extension */
	char *suffix;	/* where to print suffix extension */
	u_int len, suflen;
	FILE *fp;
	struct calendar cal;
	struct isodate	iso;

	/* get basic filename in buffer, leave room for extensions */
	len = strlen(gen->dir) + strlen(gen->fname) + 65;
	filename = emalloc(len);
	fullname = emalloc(len);
	savename = NULL;
	snprintf(filename, len, "%s%s", gen->dir, gen->fname);

	/* where to place suffix */
	suflen = strlcpy(fullname, filename, len);
	suffix = fullname + suflen;
	suflen = len - suflen;

	/* last octet of fullname set to '\0' for truncation check */
	fullname[len - 1] = '\0';

	switch (gen->type) {

	default:
		msyslog(LOG_ERR, 
			"unsupported file generations type %d for "
			"\"%s\" - reverting to FILEGEN_NONE",
			gen->type, filename);
		gen->type = FILEGEN_NONE;
		break;

	case FILEGEN_NONE:
		/* no suffix, all set */
		break;

	case FILEGEN_PID:
		gen->id_lo = getpid();
		gen->id_hi = 0;
		snprintf(suffix, suflen, "%c#%ld",
			 SUFFIX_SEP, gen->id_lo);
		break;

	case FILEGEN_DAY:
		/*
		 * You can argue here in favor of using MJD, but I
		 * would assume it to be easier for humans to interpret
		 * dates in a format they are used to in everyday life.
		 */
		ntpcal_ntp_to_date(&cal, stamp, pivot);
		snprintf(suffix, suflen, "%c%04d%02d%02d",
			 SUFFIX_SEP, cal.year, cal.month, cal.monthday);
		cal.hour = cal.minute = cal.second = 0;
		gen->id_lo = ntpcal_date_to_ntp(&cal); 
		gen->id_hi = (uint32_t)(gen->id_lo + SECSPERDAY);
		break;

	case FILEGEN_WEEK:
		isocal_ntp_to_date(&iso, stamp, pivot);
		snprintf(suffix, suflen, "%c%04dw%02d",
			 SUFFIX_SEP, iso.year, iso.week);
		iso.hour = iso.minute = iso.second = 0;
		iso.weekday = 1;
		gen->id_lo = isocal_date_to_ntp(&iso);
		gen->id_hi = (uint32_t)(gen->id_lo + 7 * SECSPERDAY);
		break;

	case FILEGEN_MONTH:
		ntpcal_ntp_to_date(&cal, stamp, pivot);
		snprintf(suffix, suflen, "%c%04d%02d",
			 SUFFIX_SEP, cal.year, cal.month);
		cal.hour = cal.minute = cal.second = 0;
		cal.monthday = 1;
		gen->id_lo = ntpcal_date_to_ntp(&cal); 
		cal.month++;
		gen->id_hi = ntpcal_date_to_ntp(&cal); 
		break;

	case FILEGEN_YEAR:
		ntpcal_ntp_to_date(&cal, stamp, pivot);
		snprintf(suffix, suflen, "%c%04d",
			 SUFFIX_SEP, cal.year);
		cal.hour = cal.minute = cal.second = 0;
		cal.month = cal.monthday = 1;
		gen->id_lo = ntpcal_date_to_ntp(&cal); 
		cal.year++;
		gen->id_hi = ntpcal_date_to_ntp(&cal); 
		break;

	case FILEGEN_AGE:
		gen->id_lo = current_time - (current_time % SECSPERDAY);
		gen->id_hi = gen->id_lo + SECSPERDAY;
		snprintf(suffix, suflen, "%ca%08ld",
			 SUFFIX_SEP, gen->id_lo);
	}
  
	/* check possible truncation */
	if ('\0' != fullname[len - 1]) {
		fullname[len - 1] = '\0';
		msyslog(LOG_ERR, "logfile name truncated: \"%s\"",
			fullname);
	}

	if (FILEGEN_NONE != gen->type) {
		/*
		 * check for existence of a file with name 'basename'
		 * as we disallow such a file
		 * if FGEN_FLAG_LINK is set create a link
		 */
		struct stat stats;
		/*
		 * try to resolve name collisions
		 */
		static u_long conflicts = 0;

#ifndef	S_ISREG
#define	S_ISREG(mode)	(((mode) & S_IFREG) == S_IFREG)
#endif
		if (stat(filename, &stats) == 0) {
			/* Hm, file exists... */
			if (S_ISREG(stats.st_mode)) {
				if (stats.st_nlink <= 1)	{
					/*
					 * Oh, it is not linked - try to save it
					 */
					savename = emalloc(len);
					snprintf(savename, len,
						"%s%c%dC%lu",
						filename, SUFFIX_SEP,
						(int)getpid(), conflicts++);

					if (rename(filename, savename) != 0)
						msyslog(LOG_ERR,
							"couldn't save %s: %m",
							filename);
					free(savename);
				} else {
					/*
					 * there is at least a second link to
					 * this file.
					 * just remove the conflicting one
					 */
					/* coverity[toctou] */
					if (unlink(filename) != 0)
						msyslog(LOG_ERR, 
							"couldn't unlink %s: %m",
							filename);
				}
			} else {
				/*
				 * Ehh? Not a regular file ?? strange !!!!
				 */
				msyslog(LOG_ERR, 
					"expected regular file for %s "
					"(found mode 0%lo)",
					filename,
					(unsigned long)stats.st_mode);
			}
		} else {
			/*
			 * stat(..) failed, but it is absolutely correct for
			 * 'basename' not to exist
			 */
			if (ENOENT != errno)
				msyslog(LOG_ERR, "stat(%s) failed: %m",
						 filename);
		}
	}

	/*
	 * now, try to open new file generation...
	 */
	DPRINTF(4, ("opening filegen (type=%d/stamp=%u) \"%s\"\n",
		    gen->type, stamp, fullname));

	fp = fopen(fullname, "a");
  
	if (NULL == fp)	{
		/* open failed -- keep previous state
		 *
		 * If the file was open before keep the previous generation.
		 * This will cause output to end up in the 'wrong' file,
		 * but I think this is still better than losing output
		 *
		 * ignore errors due to missing directories
		 */

		if (ENOENT != errno)
			msyslog(LOG_ERR, "can't open %s: %m", fullname);
	} else {
		if (NULL != gen->fp) {
			fclose(gen->fp);
			gen->fp = NULL;
		}
		gen->fp = fp;

		if (gen->flag & FGEN_FLAG_LINK) {
			/*
			 * need to link file to basename
			 * have to use hardlink for now as I want to allow
			 * gen->basename spanning directory levels
			 * this would make it more complex to get the correct
			 * fullname for symlink
			 *
			 * Ok, it would just mean taking the part following
			 * the last '/' in the name.... Should add it later....
			 */

			/* Windows NT does not support file links -Greg Schueman 1/18/97 */

#if defined(SYS_WINNT)
			SetLastError(0); /* On WinNT, don't support FGEN_FLAG_LINK */
#else  /* not WINNT ; DO THE LINK) */
			if (link(fullname, filename) != 0)
				if (EEXIST != errno)
					msyslog(LOG_ERR, 
						"can't link(%s, %s): %m",
						fullname, filename);
#endif /* SYS_WINNT */
		}		/* flags & FGEN_FLAG_LINK */
	}			/* else fp == NULL */
	
	free(filename);
	free(fullname);
	return;
}
Example #5
0
uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
{
	uint32_t result = 0;
	bool offline;

	DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));

	if (!VALID_STAT(smb_fname->st)) {
		return 0;
	}

	/* First do any modifications that depend on the path name. */
	/* hide files with a name starting with a . */
	if (lp_hide_dot_files(SNUM(conn))) {
		const char *p = strrchr_m(smb_fname->base_name,'/');
		if (p) {
			p++;
		} else {
			p = smb_fname->base_name;
		}

		/* Only . and .. are not hidden. */
		if (p[0] == '.' && !((p[1] == '\0') ||
				(p[1] == '.' && p[2] == '\0'))) {
			result |= FILE_ATTRIBUTE_HIDDEN;
		}
	}

	/* Get the DOS attributes from an EA by preference. */
	if (!get_ea_dos_attribute(conn, smb_fname, &result)) {
		result |= dos_mode_from_sbuf(conn, smb_fname);
	}

	offline = SMB_VFS_IS_OFFLINE(conn, smb_fname, &smb_fname->st);
	if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
		result |= FILE_ATTRIBUTE_OFFLINE;
	}

	if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
		bool compressed = false;
		NTSTATUS status = dos_mode_check_compressed(conn, smb_fname,
							    &compressed);
		if (NT_STATUS_IS_OK(status) && compressed) {
			result |= FILE_ATTRIBUTE_COMPRESSED;
		}
	}

	/* Optimization : Only call is_hidden_path if it's not already
	   hidden. */
	if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
	    IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
		result |= FILE_ATTRIBUTE_HIDDEN;
	}

	if (result == 0) {
		result = FILE_ATTRIBUTE_NORMAL;
	}

	result = filter_mode_by_protocol(result);

	dos_mode_debug_print(__func__, result);

	return result;
}
Example #6
0
File: rm.c Project: 0mp/freebsd
/*
 * rm_overwrite --
 *	Overwrite the file 3 times with varying bit patterns.
 *
 * XXX
 * This is a cheap way to *really* delete files.  Note that only regular
 * files are deleted, directories (and therefore names) will remain.
 * Also, this assumes a fixed-block file system (like FFS, or a V7 or a
 * System V file system).  In a logging or COW file system, you'll have to
 * have kernel support.
 */
static int
rm_overwrite(const char *file, struct stat *sbp)
{
	struct stat sb, sb2;
	struct statfs fsb;
	off_t len;
	int bsize, fd, wlen;
	char *buf = NULL;

	fd = -1;
	if (sbp == NULL) {
		if (lstat(file, &sb))
			goto err;
		sbp = &sb;
	}
	if (!S_ISREG(sbp->st_mode))
		return (1);
	if (sbp->st_nlink > 1 && !fflag) {
		warnx("%s (inode %ju): not overwritten due to multiple links",
		    file, (uintmax_t)sbp->st_ino);
		return (0);
	}
	if ((fd = open(file, O_WRONLY|O_NONBLOCK|O_NOFOLLOW, 0)) == -1)
		goto err;
	if (fstat(fd, &sb2))
		goto err;
	if (sb2.st_dev != sbp->st_dev || sb2.st_ino != sbp->st_ino ||
	    !S_ISREG(sb2.st_mode)) {
		errno = EPERM;
		goto err;
	}
	if (fstatfs(fd, &fsb) == -1)
		goto err;
	bsize = MAX(fsb.f_iosize, 1024);
	if ((buf = malloc(bsize)) == NULL)
		err(1, "%s: malloc", file);

#define	PASS(byte) {							\
	memset(buf, byte, bsize);					\
	for (len = sbp->st_size; len > 0; len -= wlen) {		\
		wlen = len < bsize ? len : bsize;			\
		if (write(fd, buf, wlen) != wlen)			\
			goto err;					\
	}								\
}
	PASS(0xff);
	if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
		goto err;
	PASS(0x00);
	if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
		goto err;
	PASS(0xff);
	if (!fsync(fd) && !close(fd)) {
		free(buf);
		return (1);
	}

err:	eval = 1;
	if (buf)
		free(buf);
	if (fd != -1)
		close(fd);
	warn("%s", file);
	return (0);
}
Example #7
0
void zro_load (mstr *str)
{
	unsigned		toktyp, status;
	mstr			tok;
	char			*lp, *top;
	zro_ent			array[ZRO_MAX_ENTS], *op;
	int			oi, si, total_ents;
	struct  stat		outbuf;
	int			stat_res;
	char			tranbuf[MAX_FBUFF + 1];
	parse_blk		pblk;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	memset(array, 0, SIZEOF(array));
	lp = str->addr;
	top = lp + str->len;
	while (lp < top && *lp == ZRO_DEL)	/* Bypass leading blanks */
		lp++;

	array[0].type = ZRO_TYPE_COUNT;
	array[0].count = 0;
	memset(&pblk, 0, SIZEOF(pblk));
	pblk.buffer = tranbuf;

	GETTOK;
	if (toktyp == ZRO_EOL)
	{	/* Null string - set default */
		array[0].count = 1;
		array[1].type = ZRO_TYPE_OBJECT;
		array[1].str.len = 0;
		array[2].type = ZRO_TYPE_COUNT;
		array[2].count = 1;
		array[3].type = ZRO_TYPE_SOURCE;
		array[3].str.len = 0;
		si = 4;
	} else
	{	/* String supplied - parse it */
		for (oi = 1;;)
		{
			if (toktyp != ZRO_IDN)
				rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FSEXP);
			if (oi + 1 >= ZRO_MAX_ENTS)
				rts_error(VARLSTCNT(7) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_MAXARGCNT, 1, ZRO_MAX_ENTS);
			if (tok.len >= SIZEOF(tranbuf))
				rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr);
			pblk.buff_size = MAX_FBUFF;
			pblk.fnb = 0;
			status = parse_file(&tok, &pblk);
			if (!(status & 1))
				rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr,
					ERR_FILEPARSE, 2, tok.len, tok.addr, status);

			tranbuf[pblk.b_esl] = 0;
			STAT_FILE(tranbuf, &outbuf, stat_res);
			if (-1 == stat_res)
				rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr,
					  errno);
			if (S_ISREG(outbuf.st_mode))
			{	/* regular file - a shared library file */
				array[oi].shrlib = zro_shlibs_find(tranbuf);
				array[oi].type = ZRO_TYPE_OBJLIB;
				si = oi + 1;
			} else
			{
				if (!S_ISDIR(outbuf.st_mode))
					rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_INVZROENT, 2,
							tok.len, tok.addr);
				array[oi].type = ZRO_TYPE_OBJECT;
				array[oi + 1].type = ZRO_TYPE_COUNT;
				si = oi + 2;
			}
			array[0].count++;
			array[oi].str = tok;
			GETTOK;
			if (toktyp == ZRO_LBR)
			{
				if (array[oi].type == ZRO_TYPE_OBJLIB)
					rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_NOLBRSRC);

				GETTOK;
				if (toktyp == ZRO_DEL)
					GETTOK;
				if (toktyp != ZRO_IDN && toktyp != ZRO_RBR)
					rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_QUALEXP);

				array[oi + 1].count = 0;
				for (;;)
				{
					if (toktyp == ZRO_RBR)
						break;
					if (toktyp != ZRO_IDN)
						rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FSEXP);
					if (si >= ZRO_MAX_ENTS)
						rts_error(VARLSTCNT(7) ERR_ZROSYNTAX, 2, str->len, str->addr,
								ERR_MAXARGCNT, 1, ZRO_MAX_ENTS);
					if (tok.len >= SIZEOF(tranbuf))
						rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr,
							ERR_FILEPARSE, 2, tok.len, tok.addr);
					pblk.buff_size = MAX_FBUFF;
					pblk.fnb = 0;
					status = parse_file(&tok, &pblk);
					if (!(status & 1))
						rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr,
							ERR_FILEPARSE, 2, tok.len, tok.addr, status);
					tranbuf[pblk.b_esl] = 0;
					STAT_FILE(tranbuf, &outbuf, stat_res);
					if (-1 == stat_res)
						rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr,
							ERR_FILEPARSE, 2, tok.len, tok.addr, errno);
					if (!S_ISDIR(outbuf.st_mode))
						rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr,
							ERR_DIRONLY, 2, tok.len, tok.addr);
					array[oi + 1].count++;
					array[si].type = ZRO_TYPE_SOURCE;
					array[si].str = tok;
					si++;
					GETTOK;
					if (toktyp == ZRO_DEL)
						GETTOK;
				}
				GETTOK;
			} else
			{
				if ((array[oi].type != ZRO_TYPE_OBJLIB) && (toktyp == ZRO_DEL || toktyp == ZRO_EOL))
				{
					if (si >= ZRO_MAX_ENTS)
						rts_error(VARLSTCNT(7) ERR_ZROSYNTAX, 2, str->len, str->addr,
							  ERR_MAXARGCNT, 1, ZRO_MAX_ENTS);
					array[oi + 1].count = 1;
					array[si] = array[oi];
					array[si].type = ZRO_TYPE_SOURCE;
					si++;
				}
			}
			if (toktyp == ZRO_EOL)
				break;

			if (toktyp == ZRO_DEL)
				GETTOK;
			else
				rts_error(VARLSTCNT(4) ERR_ZROSYNTAX, 2, str->len, str->addr);
			oi = si;
		}
	}
	total_ents = si;
	if (TREF(zro_root))
	{
		assert((TREF(zro_root))->type == ZRO_TYPE_COUNT);
		oi = (TREF(zro_root))->count;
		assert(oi);
		for (op = TREF(zro_root) + 1; oi-- > 0; )
		{	/* release space held by translated entries */
			assert(op->type == ZRO_TYPE_OBJECT || op->type == ZRO_TYPE_OBJLIB);
			if (op->str.len)
				free(op->str.addr);
			if ((op++)->type == ZRO_TYPE_OBJLIB)
				continue;	/* i.e. no sources for shared library */
			assert(op->type == ZRO_TYPE_COUNT);
			si = (op++)->count;
			for ( ; si-- > 0; op++)
			{
				assert(op->type == ZRO_TYPE_SOURCE);
				if (op->str.len)
					free(op->str.addr);
			}
		}
		free(TREF(zro_root));
	}
	TREF(zro_root) = (zro_ent *)malloc(total_ents * SIZEOF(zro_ent));
	memcpy((uchar_ptr_t)TREF(zro_root), (uchar_ptr_t)array, total_ents * SIZEOF(zro_ent));
	assert((TREF(zro_root))->type == ZRO_TYPE_COUNT);
	oi = (TREF(zro_root))->count;
	assert(oi);
	for (op = TREF(zro_root) + 1; oi-- > 0; )
	{
		assert(op->type == ZRO_TYPE_OBJECT || op->type == ZRO_TYPE_OBJLIB);
		if (op->str.len)
		{
			pblk.buff_size = MAX_FBUFF;
			pblk.fnb = 0;
			status = parse_file(&op->str, &pblk);
			if (!(status & 1))
				rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr,
					ERR_FILEPARSE, 2, op->str.len, op->str.addr, status);

			op->str.addr = (char *)malloc(pblk.b_esl);
			op->str.len = pblk.b_esl;
			memcpy(op->str.addr, pblk.buffer, pblk.b_esl);
		}
		if ((op++)->type == ZRO_TYPE_OBJLIB)
			continue;
		assert(op->type == ZRO_TYPE_COUNT);
		si = (op++)->count;
		for ( ; si-- > 0; op++)
		{
			assert(op->type == ZRO_TYPE_SOURCE);
			if (op->str.len)
			{
				pblk.buff_size = MAX_FBUFF;
				pblk.fnb = 0;
				status = parse_file(&op->str, &pblk);
				if (!(status & 1))
					rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr,
						ERR_FILEPARSE, 2, op->str.len, op->str.addr, status);

				op->str.addr = (char *)malloc(pblk.b_esl);
				op->str.len = pblk.b_esl;
				memcpy(op->str.addr, pblk.buffer, pblk.b_esl);
			}
		}
	}
}
Example #8
0
File: cmd_tar.c Project: ptal/sash2
/*
 * Save one file into the tar file.
 * If the file is a directory, then this will recursively save all of
 * the files and directories within the directory.  The seeLinks
 * flag indicates whether or not we want to see symbolic links as
 * they really are, instead of blindly following them.
 */
static void
saveFile(const char * fileName, BOOL seeLinks)
{
	int		status;
	int		mode;
	struct stat	statbuf;

	if (verboseFlag)
		printf("a %s\n", fileName);

	/*
	 * Check that the file name will fit in the header.
	 */
	if (strlen(fileName) >= TAR_NAME_SIZE)
	{
		fprintf(stderr, "%s: File name is too long\n", fileName);

		return;
	}

	/*
	 * Find out about the file.
	 */
#ifdef	S_ISLNK
	if (seeLinks)
		status = lstat(fileName, &statbuf);
	else
#endif
		status = stat(fileName, &statbuf);

	if (status < 0)
	{
		perror(fileName);

		return;
	}

	/*
	 * Make sure we aren't trying to save our file into itself.
	 */
	if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode))
	{
		fprintf(stderr, "Skipping saving of archive file itself\n");

		return;
	}

	/*
	 * Check the type of file.
	 */
	mode = statbuf.st_mode;

	if (S_ISDIR(mode))
	{
		saveDirectory(fileName, &statbuf);

		return;
	}

	if (S_ISREG(mode))
	{
		saveRegularFile(fileName, &statbuf);

		return;
	}

	/*
	 * The file is a strange type of file, ignore it.
	 */
	fprintf(stderr, "%s: not a directory or regular file\n", fileName);
}
Example #9
0
int
ELFNAME(nlist)(int fd, struct nlist *list)
{
    struct nlist *p;
    caddr_t strtab;
    Elf_Off symoff = 0, symstroff = 0;
    Elf_Word symsize = 0;
    long symstrsize = 0;
    Elf_Sword nent, cc, i;
    Elf_Sym sbuf[1024];
    Elf_Sym *s;
    Elf_Ehdr ehdr;
    Elf_Shdr *shdr = NULL;
    size_t shdr_size;
    struct stat st;
    int usemalloc = 0;
    size_t left, len;

    /* Make sure obj is OK */
    if (pread(fd, &ehdr, sizeof(Elf_Ehdr), (off_t)0) != sizeof(Elf_Ehdr) ||
            !ELFNAME(__elf_is_okay__)(&ehdr) || fstat(fd, &st) < 0)
        return (-1);

    /* calculate section header table size */
    shdr_size = ehdr.e_shentsize * ehdr.e_shnum;

    /* Make sure it's not too big to mmap */
    if (SIZE_MAX - ehdr.e_shoff < shdr_size ||
            S_ISREG(st.st_mode) && ehdr.e_shoff + shdr_size > st.st_size) {
        errno = EFBIG;
        return (-1);
    }

    /* mmap section header table */
    shdr = (Elf_Shdr *)mmap(NULL, (size_t)shdr_size, PROT_READ,
                            MAP_SHARED|MAP_FILE, fd, (off_t) ehdr.e_shoff);
    if (shdr == MAP_FAILED) {
        usemalloc = 1;
        if ((shdr = malloc(shdr_size)) == NULL)
            return (-1);

        if (pread(fd, shdr, shdr_size, (off_t)ehdr.e_shoff) !=
                shdr_size) {
            free(shdr);
            return (-1);
        }
    }

    /*
     * Find the symbol table entry and its corresponding
     * string table entry.	Version 1.1 of the ABI states
     * that there is only one symbol table but that this
     * could change in the future.
     */
    for (i = 0; i < ehdr.e_shnum; i++) {
        if (shdr[i].sh_type == SHT_SYMTAB) {
            if (shdr[i].sh_link >= ehdr.e_shnum)
                continue;
            symoff = shdr[i].sh_offset;
            symsize = shdr[i].sh_size;
            symstroff = shdr[shdr[i].sh_link].sh_offset;
            symstrsize = shdr[shdr[i].sh_link].sh_size;
            break;
        }
    }

    /* Flush the section header table */
    if (usemalloc)
        free(shdr);
    else
        munmap((caddr_t)shdr, shdr_size);

    /*
     * clean out any left-over information for all valid entries.
     * Type and value defined to be 0 if not found; historical
     * versions cleared other and desc as well.  Also figure out
     * the largest string length so don't read any more of the
     * string table than we have to.
     *
     * XXX clearing anything other than n_type and n_value violates
     * the semantics given in the man page.
     */
    nent = 0;
    for (p = list; !ISLAST(p); ++p) {
        p->n_type = 0;
        p->n_other = 0;
        p->n_desc = 0;
        p->n_value = 0;
        ++nent;
    }

    /* Don't process any further if object is stripped. */
    /* ELFism - dunno if stripped by looking at header */
    if (symoff == 0)
        return nent;

    /* Check for files too large to mmap. */
    if (SIZE_MAX - symstrsize < symstroff ||
            S_ISREG(st.st_mode) && symstrsize + symstroff > st.st_size) {
        errno = EFBIG;
        return (-1);
    }

    /*
     * Map string table into our address space.  This gives us
     * an easy way to randomly access all the strings, without
     * making the memory allocation permanent as with malloc/free
     * (i.e., munmap will return it to the system).
     */
    if (usemalloc) {
        if ((strtab = malloc(symstrsize)) == NULL)
            return (-1);
        if (pread(fd, strtab, symstrsize, (off_t)symstroff) !=
                symstrsize) {
            free(strtab);
            return (-1);
        }
    } else {
        strtab = mmap(NULL, (size_t)symstrsize, PROT_READ,
                      MAP_SHARED|MAP_FILE, fd, (off_t) symstroff);
        if (strtab == MAP_FAILED)
            return (-1);
    }

    while (symsize >= sizeof(Elf_Sym)) {
        cc = MIN(symsize, sizeof(sbuf));
        if (pread(fd, sbuf, cc, (off_t)symoff) != cc)
            break;
        symsize -= cc;
        symoff += cc;
        for (s = sbuf; cc > 0; ++s, cc -= sizeof(*s)) {
            Elf_Word soff = s->st_name;

            if (soff == 0 || soff >= symstrsize)
                continue;
            left = symstrsize - soff;

            for (p = list; !ISLAST(p); p++) {
                char *sym;

                /*
                 * First we check for the symbol as it was
                 * provided by the user. If that fails
                 * and the first char is an '_', skip over
                 * the '_' and try again.
                 * XXX - What do we do when the user really
                 *       wants '_foo' and there are symbols
                 *       for both 'foo' and '_foo' in the
                 *	 table and 'foo' is first?
                 */
                sym = p->n_name;
                len = strlen(sym);

                if ((len >= left ||
                        strcmp(&strtab[soff], sym) != 0) &&
                        (sym[0] != '_' || len - 1 >= left ||
                         strcmp(&strtab[soff], sym + 1) != 0))
                    continue;

                p->n_value = s->st_value;

                /* XXX - type conversion */
                /*	 is pretty rude. */
                switch(ELF_ST_TYPE(s->st_info)) {
                case STT_NOTYPE:
                    switch (s->st_shndx) {
                    case SHN_UNDEF:
                        p->n_type = N_UNDF;
                        break;
                    case SHN_ABS:
                        p->n_type = N_ABS;
                        break;
                    case SHN_COMMON:
                        p->n_type = N_COMM;
                        break;
                    default:
                        p->n_type = N_COMM | N_EXT;
                        break;
                    }
                    break;
                case STT_OBJECT:
                    p->n_type = N_DATA;
                    break;
                case STT_FUNC:
                    p->n_type = N_TEXT;
                    break;
                case STT_FILE:
                    p->n_type = N_FN;
                    break;
                }
                if (ELF_ST_BIND(s->st_info) == STB_LOCAL)
                    p->n_type = N_EXT;
                p->n_desc = 0;
                p->n_other = 0;
                if (--nent <= 0)
                    break;
            }
        }
    }
elf_done:
    if (usemalloc)
        free(strtab);
    else
        munmap(strtab, symstrsize);
    return (nent);
}
Example #10
0
int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
{
	struct file_dedupe_range_info *info;
	struct inode *src = file_inode(file);
	u64 off;
	u64 len;
	int i;
	int ret;
	bool is_admin = capable(CAP_SYS_ADMIN);
	u16 count = same->dest_count;
	struct file *dst_file;
	loff_t dst_off;
	ssize_t deduped;

	if (!(file->f_mode & FMODE_READ))
		return -EINVAL;

	if (same->reserved1 || same->reserved2)
		return -EINVAL;

	off = same->src_offset;
	len = same->src_length;

	ret = -EISDIR;
	if (S_ISDIR(src->i_mode))
		goto out;

	ret = -EINVAL;
	if (!S_ISREG(src->i_mode))
		goto out;

	ret = clone_verify_area(file, off, len, false);
	if (ret < 0)
		goto out;
	ret = 0;

	/* pre-format output fields to sane values */
	for (i = 0; i < count; i++) {
		same->info[i].bytes_deduped = 0ULL;
		same->info[i].status = FILE_DEDUPE_RANGE_SAME;
	}

	for (i = 0, info = same->info; i < count; i++, info++) {
		struct inode *dst;
		struct fd dst_fd = fdget(info->dest_fd);

		dst_file = dst_fd.file;
		if (!dst_file) {
			info->status = -EBADF;
			goto next_loop;
		}
		dst = file_inode(dst_file);

		ret = mnt_want_write_file(dst_file);
		if (ret) {
			info->status = ret;
			goto next_loop;
		}

		dst_off = info->dest_offset;
		ret = clone_verify_area(dst_file, dst_off, len, true);
		if (ret < 0) {
			info->status = ret;
			goto next_file;
		}
		ret = 0;

		if (info->reserved) {
			info->status = -EINVAL;
		} else if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) {
			info->status = -EINVAL;
		} else if (file->f_path.mnt != dst_file->f_path.mnt) {
			info->status = -EXDEV;
		} else if (S_ISDIR(dst->i_mode)) {
			info->status = -EISDIR;
		} else if (dst_file->f_op->dedupe_file_range == NULL) {
			info->status = -EINVAL;
		} else {
			deduped = dst_file->f_op->dedupe_file_range(file, off,
							len, dst_file,
							info->dest_offset);
			if (deduped == -EBADE)
				info->status = FILE_DEDUPE_RANGE_DIFFERS;
			else if (deduped < 0)
				info->status = deduped;
			else
				info->bytes_deduped += deduped;
		}

next_file:
		mnt_drop_write_file(dst_file);
next_loop:
		fdput(dst_fd);

		if (fatal_signal_pending(current))
			goto out;
	}

out:
	return ret;
}
Example #11
0
File: cmd_tar.c Project: ptal/sash2
/*
 * Examine the header block that was just read.
 * This can specify the information for another file, or it can mark
 * the end of the tar file.
 */
static void
readHeader(const TarHeader * hp, int fileCount, const char ** fileTable)
{
	int		mode;
	int		uid;
	int		gid;
	long		size;
	time_t		mtime;
	const char *	name;
	int		cc;
	BOOL		hardLink;
	BOOL		softLink;

	/*
	 * If the block is completely empty, then this is the end of the
	 * archive file.  If the name is null, then just skip this header.
	 */
	name = hp->name;

	if (*name == '\0')
	{
		for (cc = TAR_BLOCK_SIZE; cc > 0; cc--)
		{
			if (*name++)
				return;
		}

		eofFlag = TRUE;

		return;
	}

	/*
	 * There is another file in the archive to examine.
	 * Extract the encoded information and check it.
	 */
	mode = getOctal(hp->mode, sizeof(hp->mode));
	uid = getOctal(hp->uid, sizeof(hp->uid));
	gid = getOctal(hp->gid, sizeof(hp->gid));
	size = getOctal(hp->size, sizeof(hp->size));
	mtime = getOctal(hp->mtime, sizeof(hp->mtime));

	if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0))
	{
		if (!badHeader)
			fprintf(stderr, "Bad tar header, skipping\n");

		badHeader = TRUE;

		return;
	}

	badHeader = FALSE;
	skipFileFlag = FALSE;

	/*
	 * Check for the file modes.
	 */
	hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
		(hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));

	softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
		(hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));

	/*
	 * Check for a directory or a regular file.
	 */
	if (name[strlen(name) - 1] == '/')
		mode |= S_IFDIR;
	else if ((mode & S_IFMT) == 0)
		mode |= S_IFREG;

	/*
	 * Check for absolute paths in the file.
	 * If we find any, then warn the user and make them relative.
	 */
	if (*name == '/')
	{
		while (*name == '/')
			name++;

		if (!warnedRoot)
		{
			fprintf(stderr,
			"Absolute path detected, removing leading slashes\n");
		}

		warnedRoot = TRUE;
	}

	/*
	 * See if we want this file to be restored.
	 * If not, then set up to skip it.
	 */
	if (!wantFileName(name, fileCount, fileTable))
	{
		if (!hardLink && !softLink && S_ISREG(mode))
		{
			inHeader = (size == 0);
			dataCc = size;
		}

		skipFileFlag = TRUE;

		return;
	}

	/*
	 * This file is to be handled.
	 * If we aren't extracting then just list information about the file.
	 */
	if (!extractFlag)
	{
		if (verboseFlag)
		{
			printf("%s %3d/%-d %9ld %s %s", modeString(mode),
				uid, gid, size, timeString(mtime), name);
		}
		else
			printf("%s", name);

		if (hardLink)
			printf(" (link to \"%s\")", hp->linkName);
		else if (softLink)
			printf(" (symlink to \"%s\")", hp->linkName);
		else if (S_ISREG(mode))
		{
			inHeader = (size == 0);
			dataCc = size;
		}

		printf("\n");

		return;
	}

	/*
	 * We really want to extract the file.
	 */
	if (verboseFlag)
		printf("x %s\n", name);

	if (hardLink)
	{
		if (link(hp->linkName, name) < 0)
			perror(name);

		return;
	}

	if (softLink)
	{
#ifdef	S_ISLNK
		if (symlink(hp->linkName, name) < 0)
			perror(name);
#else
		fprintf(stderr, "Cannot create symbolic links\n");
#endif
		return;
	}

	/*
	 * If the file is a directory, then just create the path.
	 */
	if (S_ISDIR(mode))
	{
		createPath(name, mode);

		return;
	}

	/*
	 * There is a file to write.
	 * First create the path to it if necessary with a default permission.
	 */
	createPath(name, 0777);

	inHeader = (size == 0);
	dataCc = size;

	/*
	 * Start the output file.
	 */
	outFd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);

	if (outFd < 0)
	{
		perror(name);
		skipFileFlag = TRUE;

		return;
	}

	/*
	 * If the file is empty, then that's all we need to do.
	 */
	if (size == 0)
	{
		(void) close(outFd);
		outFd = -1;
	}
}
Example #12
0
int web_main(void * _ed, struct MHD_Connection * con, const char * url,
		      const char * method, const char * version,
		      const char *upload_data, size_t * upload_data_size,
		     void ** con_cls){
  UNUSED(url); UNUSED(version); UNUSED(upload_data); UNUSED(upload_data_size);
  UNUSED(method); UNUSED(con_cls); UNUSED(_ed);
  const char * file = "page.html";

  bool style_loc = strcmp((char *) url + 1, "style.css") == 0;
  if(style_loc)
    file = "style.css";
  else if(0 == strcmp((char *) url + 1, (char *) "favicon.png"))
    file = "favicon.png";
  
  char fnamebuffer[100];
  logd("'%s' %s %s %i\n", url, method, version, upload_data_size);
  logd("File: %s\n", file);
  if(url == strstr(url, "/sharesinfo")){
    // Send back json code describing all the available shares.

    file = "shareinfo_data";
    
    dirscan dir = scan_directories("shareinfo");
    
    FILE * outfile = fopen(file, "w");
    fprintf(outfile, "[");
    for(size_t i = 0; i < dir.cnt; i++){
      logd("looking in: %s\n", dir.files[i]);
      char fnamebuffer2[100];
      sprintf(fnamebuffer2, "shareinfo/%s", dir.files[i]);
      void * rdbuffer = read_file_to_string(fnamebuffer2);
      ASSERT(rdbuffer != NULL);
      void *ptr = rdbuffer;
      char * dirname = udpc_unpack_string(&ptr);
      char * name = udpc_unpack_string(&ptr);
      char * user = udpc_unpack_string(&ptr);
      fprintf(outfile, "{\"path\": \"%s\", \"name\":\"%s\", \"user\":\"%s\"}%s\n",dirname, name, user, (i == dir.cnt -1) ? "" : ",");
      dealloc(rdbuffer);
    }
    fprintf(outfile, "]");
    fclose(outfile);
    dirscan_clean(&dir);
  }else if(url == strstr(url,"/shares/")){
    // fetch the active shares item inside the shares folder
    
    char * shareid = (char *) url + strlen("/shares/");
    logd("Shareid: %s\n", shareid);
    char * shareinfo_filename = fmtstr("shareinfo/%s", shareid);
    void * buffer = read_file_to_string(shareinfo_filename);
    if(buffer == NULL)
      goto error;
    void * bufptr = buffer;
    char * dir = udpc_unpack_string(&bufptr);
    char * name = udpc_unpack_string(&bufptr);
    char * user = udpc_unpack_string(&bufptr);
    service_descriptor sd;
    if(!udpc_get_service_descriptor(user, &sd)){
      logd("Unable to parse service name: '%s'\n", user);
      dealloc(buffer);
      goto error;
    }

    logd("path: %s, name: %s, user: %s\n", dir, name, user);
    update_dirfile(dir, name, user);
    sprintf(fnamebuffer, "shares/%s.json", name);
    dealloc(buffer);
    logd("Sending: %s\n", fnamebuffer);
    file = fnamebuffer;
  }
  if(strcmp(url, "/add_share") == 0){ 
    const char * path = MHD_lookup_connection_value(con, MHD_GET_ARGUMENT_KIND, "path");
    const char * name = MHD_lookup_connection_value(con, MHD_GET_ARGUMENT_KIND, "name");
    const char * user = MHD_lookup_connection_value(con, MHD_GET_ARGUMENT_KIND, "user");
    logd("path: %s, name: %s, user: %s\n", path, name, user);
    if(path == NULL || name == NULL || user == NULL){
      goto error;
    }
    service_descriptor sd;
    if(!udpc_get_service_descriptor(user, &sd)){
      logd("Unable to parse service name: '%s'\n", user);
      goto error;
    }
    logd("Service descriptor seems ok \n");
    ensure_directory("shareinfo/");
    char * sharepath = fmtstr("shareinfo/%s", name);
    struct stat filest;
    stat(sharepath, &filest);
    dealloc(sharepath);
    
    if(S_ISREG(filest.st_mode)){
      logd("File exists!\n");
    }else{
      struct stat dirst;
      stat(path, &dirst);
      if(!S_ISDIR(dirst.st_mode)){
	logd("Dir does not exist.. creating a new one..\n");
	int path_len = strlen(path);
	if(path[path_len] !='/'){
	  char * npath = fmtstr("%s/", path);
	  ensure_directory(npath);
	  dealloc(npath);
	}else{
	  ensure_directory(path);
	}
      }
      logd("Updating dirfile!\n");
      update_dirfile(path, name, user);
      logd("Done..\n");
    }
    const char * r = "\"OK\"";
    struct MHD_Response * response = MHD_create_response_from_data(strlen(r),
								   (void *) r,
								   0,
								   MHD_NO);
    int ret = MHD_queue_response(con, MHD_HTTP_OK, response);
    MHD_destroy_response(response);
    return ret;
  }

  size_t filesize = 0;
  void * pg = read_file_to_buffer(file, &filesize);
  struct MHD_Response * response = MHD_create_response_from_data(filesize,
					   pg,
					   1,
					   MHD_NO);
  int ret = MHD_queue_response(con, MHD_HTTP_OK, response);
  MHD_destroy_response(response);
  return ret;

 error:;
  const char * error_str = "<html><body>400</body></html>";
  response = MHD_create_response_from_data(strlen(error_str) + 1,
					   (void *) error_str,
					   0,
					   MHD_NO);
  ret = MHD_queue_response(con, MHD_HTTP_BAD_REQUEST, response);
  MHD_destroy_response(response);
  return ret;
}
Example #13
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;
	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++;
			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) 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(*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);
}
Example #14
0
/* Consider adding a remove_leftovers() that runs in verify/fix in order to
 * allow this function to mkdtemp create folders for parallel build */
enum swupd_code do_staging(struct file *file, struct manifest *MoM)
{
	char *statfile = NULL, *tmp = NULL, *tmp2 = NULL;
	char *dir, *base, *rel_dir;
	char *tarcommand = NULL;
	char *original = NULL;
	char *target = NULL;
	char *targetpath = NULL;
	char *rename_target = NULL;
	char *rename_tmpdir = NULL;
	char real_path[4096] = { 0 };
	int ret;
	struct stat s;

	tmp = strdup_or_die(file->filename);
	tmp2 = strdup_or_die(file->filename);

	dir = dirname(tmp);
	base = basename(tmp2);

	rel_dir = dir;
	if (*dir == '/') {
		rel_dir = dir + 1;
	}

	string_or_die(&original, "%s/staged/%s", state_dir, file->hash);

	string_or_die(&targetpath, "%s%s", path_prefix, rel_dir);
	ret = stat(targetpath, &s);

	if ((ret == -1) && (errno == ENOENT)) {
		if (MoM) {
			warn("Update target directory does not exist: %s. Trying to fix it\n", targetpath);
			verify_fix_path(dir, MoM);
		} else {
			warn("Update target directory does not exist: %s. Auto-fix disabled\n", targetpath);
		}

	} else if (!S_ISDIR(s.st_mode)) {
		error("Update target exists but is NOT a directory: %s\n", targetpath);
	}
	if (!realpath(targetpath, real_path)) {
		ret = -1;
		goto out;
	} else if (strcmp(path_prefix, targetpath) != 0 &&
		   strcmp(targetpath, real_path) != 0) {
		/*
		 * targetpath and real_path should always be equal but
		 * in the case of the targetpath being the path_prefix
		 * there is a trailing '/' in path_prefix but realpath
		 * doesn't keep the trailing '/' so check for that case
		 * specifically.
		 */
		ret = -1;
		goto out;
	}

	string_or_die(&target, "%s%s/.update.%s", path_prefix, rel_dir, base);
	ret = swupd_rm(target);
	if (ret < 0 && ret != -ENOENT) {
		error("Failed to remove %s\n", target);
	}

	string_or_die(&statfile, "%s%s", path_prefix, file->filename);

	memset(&s, 0, sizeof(struct stat));
	ret = lstat(statfile, &s);
	if (ret == 0) {
		if ((file->is_dir && !S_ISDIR(s.st_mode)) ||
		    (file->is_link && !S_ISLNK(s.st_mode)) ||
		    (file->is_file && !S_ISREG(s.st_mode))) {
			//file type changed, move old out of the way for new
			ret = swupd_rm(statfile);
			if (ret < 0) {
				ret = SWUPD_COULDNT_REMOVE_FILE;
				goto out;
			}
		}
	}
	free_string(&statfile);

	if (file->is_dir || S_ISDIR(s.st_mode)) {
		/* In the btrfs only scenario there was an implicit
		 * "create_or_update_dir()" via un-tar-ing a directory.tar after
		 * download and the untar happens in the staging subvolume which
		 * then gets promoted to a "real" usable subvolume.  But for
		 * a live rootfs the directory needs copied out of staged
		 * and into the rootfs.  Tar is a way to copy with
		 * attributes and it includes internal logic that does the
		 * right thing to overlay a directory onto something
		 * pre-existing: */
		/* In order to avoid tar transforms with directories, rename
		 * the directory before and after the tar command */
		string_or_die(&rename_tmpdir, "%s/tmprenamedir", state_dir);
		ret = create_staging_renamedir(rename_tmpdir);
		if (ret) {
			ret = SWUPD_COULDNT_CREATE_DIR;
			goto out;
		}
		string_or_die(&rename_target, "%s/%s", rename_tmpdir, base);
		if (rename(original, rename_target)) {
			ret = SWUPD_COULDNT_RENAME_DIR;
			goto out;
		}
		string_or_die(&tarcommand, TAR_COMMAND " -C '%s' " TAR_PERM_ATTR_ARGS " -cf - './%s' 2> /dev/null | " TAR_COMMAND " -C '%s%s' " TAR_PERM_ATTR_ARGS " -xf - 2> /dev/null",
			      rename_tmpdir, base, path_prefix, rel_dir);
		ret = system(tarcommand);
		if (ret == -1) {
			ret = SWUPD_SUBPROCESS_ERROR;
		}
		if (WIFEXITED(ret)) {
			ret = WEXITSTATUS(ret);
		}
		free_string(&tarcommand);
		if (rename(rename_target, original)) {
			ret = SWUPD_COULDNT_RENAME_DIR;
			goto out;
		}
		if (ret) {
			ret = SWUPD_COULDNT_RENAME_DIR;
			goto out;
		}
	} else { /* (!file->is_dir && !S_ISDIR(stat.st_mode)) */
		/* can't naively hard link(): Non-read-only files with same hash must remain
		 * separate copies otherwise modifications to one instance of the file
		 * propagate to all instances of the file perhaps causing subtle data corruption from
		 * a user's perspective.  In practice the rootfs is stateless and owned by us.
		 * Additionally cross-mount hardlinks fail and it's hard to know what an admin
		 * might have for overlaid mounts.  The use of tar is a simple way to copy, but
		 * inefficient.  So prefer hardlink and fall back if needed: */
		ret = -1;
		if (!file->is_config && !file->is_state && !file->use_xattrs) {
			ret = link(original, target);
		}
		if (ret < 0) {
			/* either the hardlink failed, or it was undesirable (config), do a tar-tar dance */
			/* In order to avoid tar transforms, rename the file
			 * before and after the tar command */
			string_or_die(&rename_target, "%s/staged/.update.%s", state_dir, base);
			ret = rename(original, rename_target);
			if (ret) {
				ret = SWUPD_COULDNT_RENAME_FILE;
				goto out;
			}
			string_or_die(&tarcommand, TAR_COMMAND " -C '%s/staged' " TAR_PERM_ATTR_ARGS " -cf - '.update.%s' 2> /dev/null | " TAR_COMMAND " -C '%s%s' " TAR_PERM_ATTR_ARGS " -xf - 2> /dev/null",
				      state_dir, base, path_prefix, rel_dir);
			ret = system(tarcommand);
			if (ret == -1) {
				ret = SWUPD_SUBPROCESS_ERROR;
			}
			if (WIFEXITED(ret)) {
				ret = WEXITSTATUS(ret);
			}
			free_string(&tarcommand);
			ret = rename(rename_target, original);
			if (ret) {
				ret = SWUPD_COULDNT_RENAME_FILE;
				goto out;
			}
		}

		struct stat buf;
		int err;

		free_string(&file->staging);
		string_or_die(&file->staging, "%s%s/.update.%s", path_prefix, rel_dir, base);

		err = lstat(file->staging, &buf);
		if (err != 0) {
			free_string(&file->staging);
			ret = SWUPD_COULDNT_CREATE_FILE;
			goto out;
		}
	}

out:
	free_string(&target);
	free_string(&targetpath);
	free_string(&original);
	free_string(&rename_target);
	free_string(&rename_tmpdir);
	free_string(&tmp);
	free_string(&tmp2);

	return ret;
}
Example #15
0
void server_process_native_file(
                Server *s,
                int fd,
                const struct ucred *ucred,
                const struct timeval *tv,
                const char *label, size_t label_len) {

        struct stat st;
        bool sealed;
        int r;

        /* Data is in the passed fd, since it didn't fit in a
         * datagram. */

        assert(s);
        assert(fd >= 0);

        /* If it's a memfd, check if it is sealed. If so, we can just
         * use map it and use it, and do not need to copy the data
         * out. */
        sealed = memfd_get_sealed(fd) > 0;

        if (!sealed && (!ucred || ucred->uid != 0)) {
                _cleanup_free_ char *sl = NULL, *k = NULL;
                const char *e;

                /* If this is not a sealed memfd, and the peer is unknown or
                 * unprivileged, then verify the path. */

                if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
                        log_oom();
                        return;
                }

                r = readlink_malloc(sl, &k);
                if (r < 0) {
                        log_error_errno(r, "readlink(%s) failed: %m", sl);
                        return;
                }

                e = path_startswith(k, "/dev/shm/");
                if (!e)
                        e = path_startswith(k, "/tmp/");
                if (!e)
                        e = path_startswith(k, "/var/tmp/");
                if (!e) {
                        log_error("Received file outside of allowed directories. Refusing.");
                        return;
                }

                if (!filename_is_valid(e)) {
                        log_error("Received file in subdirectory of allowed directories. Refusing.");
                        return;
                }
        }

        if (fstat(fd, &st) < 0) {
                log_error_errno(errno, "Failed to stat passed file, ignoring: %m");
                return;
        }

        if (!S_ISREG(st.st_mode)) {
                log_error("File passed is not regular. Ignoring.");
                return;
        }

        if (st.st_size <= 0)
                return;

        if (st.st_size > ENTRY_SIZE_MAX) {
                log_error("File passed too large. Ignoring.");
                return;
        }

        if (sealed) {
                void *p;
                size_t ps;

                /* The file is sealed, we can just map it and use it. */

                ps = PAGE_ALIGN(st.st_size);
                p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0);
                if (p == MAP_FAILED) {
                        log_error_errno(errno, "Failed to map memfd, ignoring: %m");
                        return;
                }

                server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len);
                assert_se(munmap(p, ps) >= 0);
        } else {
                _cleanup_free_ void *p = NULL;
                struct statvfs vfs;
                ssize_t n;

                if (fstatvfs(fd, &vfs) < 0) {
                        log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m");
                        return;
                }

                /* Refuse operating on file systems that have
                 * mandatory locking enabled, see:
                 *
                 * https://github.com/systemd/systemd/issues/1822
                 */
                if (vfs.f_flag & ST_MANDLOCK) {
                        log_error("Received file descriptor from file system with mandatory locking enable, refusing.");
                        return;
                }

                /* Make the fd non-blocking. On regular files this has
                 * the effect of bypassing mandatory locking. Of
                 * course, this should normally not be necessary given
                 * the check above, but let's better be safe than
                 * sorry, after all NFS is pretty confusing regarding
                 * file system flags, and we better don't trust it,
                 * and so is SMB. */
                r = fd_nonblock(fd, true);
                if (r < 0) {
                        log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m");
                        return;
                }

                /* The file is not sealed, we can't map the file here, since
                 * clients might then truncate it and trigger a SIGBUS for
                 * us. So let's stupidly read it */

                p = malloc(st.st_size);
                if (!p) {
                        log_oom();
                        return;
                }

                n = pread(fd, p, st.st_size, 0);
                if (n < 0)
                        log_error_errno(errno, "Failed to read file, ignoring: %m");
                else if (n > 0)
                        server_process_native_message(s, p, n, ucred, tv, label, label_len);
        }
}
static int
file_open(struct archive *a, void *client_data)
{
	struct stat st;
	struct read_file_data *mine = (struct read_file_data *)client_data;
	void *buffer;
	const char *filename = NULL;
	const wchar_t *wfilename = NULL;
	int fd;
	int is_disk_like = 0;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
	off_t mediasize = 0; /* FreeBSD-specific, so off_t okay here. */
#elif defined(__NetBSD__) || defined(__OpenBSD__)
	struct disklabel dl;
#elif defined(__DragonFly__)
	struct partinfo pi;
#endif

	archive_clear_error(a);
	if (mine->filename_type == FNT_STDIN) {
		/* We used to delegate stdin support by
		 * directly calling archive_read_open_fd(a,0,block_size)
		 * here, but that doesn't (and shouldn't) handle the
		 * end-of-file flush when reading stdout from a pipe.
		 * Basically, read_open_fd() is intended for folks who
		 * are willing to handle such details themselves.  This
		 * API is intended to be a little smarter for folks who
		 * want easy handling of the common case.
		 */
		fd = 0;
#if defined(__CYGWIN__) || defined(_WIN32)
		setmode(0, O_BINARY);
#endif
		filename = "";
	} else if (mine->filename_type == FNT_MBS) {
		filename = mine->filename.m;
		fd = open(filename, O_RDONLY | O_BINARY | O_CLOEXEC);
		__archive_ensure_cloexec_flag(fd);
		if (fd < 0) {
			archive_set_error(a, errno,
			    "Failed to open '%s'", filename);
			return (ARCHIVE_FATAL);
		}
	} else {
#if defined(_WIN32) && !defined(__CYGWIN__)
		wfilename = mine->filename.w;
		fd = _wopen(wfilename, O_RDONLY | O_BINARY);
		if (fd < 0 && errno == ENOENT) {
			wchar_t *fullpath;
			fullpath = __la_win_permissive_name_w(wfilename);
			if (fullpath != NULL) {
				fd = _wopen(fullpath, O_RDONLY | O_BINARY);
				free(fullpath);
			}
		}
		if (fd < 0) {
			archive_set_error(a, errno,
			    "Failed to open '%S'", wfilename);
			return (ARCHIVE_FATAL);
		}
#else
		archive_set_error(a, ARCHIVE_ERRNO_MISC,
		    "Unexpedted operation in archive_read_open_filename");
		return (ARCHIVE_FATAL);
#endif
	}
	if (fstat(fd, &st) != 0) {
		if (mine->filename_type == FNT_WCS)
			archive_set_error(a, errno, "Can't stat '%S'",
			    wfilename);
		else
			archive_set_error(a, errno, "Can't stat '%s'",
			    filename);
		return (ARCHIVE_FATAL);
	}

	/*
	 * Determine whether the input looks like a disk device or a
	 * tape device.  The results are used below to select an I/O
	 * strategy:
	 *  = "disk-like" devices support arbitrary lseek() and will
	 *    support I/O requests of any size.  So we get easy skipping
	 *    and can cheat on block sizes to get better performance.
	 *  = "tape-like" devices require strict blocking and use
	 *    specialized ioctls for seeking.
	 *  = "socket-like" devices cannot seek at all but can improve
	 *    performance by using nonblocking I/O to read "whatever is
	 *    available right now".
	 *
	 * Right now, we only specially recognize disk-like devices,
	 * but it should be straightforward to add probes and strategy
	 * here for tape-like and socket-like devices.
	 */
	if (S_ISREG(st.st_mode)) {
		/* Safety:  Tell the extractor not to overwrite the input. */
		archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
		/* Regular files act like disks. */
		is_disk_like = 1;
	}
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
	/* FreeBSD: if it supports DIOCGMEDIASIZE ioctl, it's disk-like. */
	else if (S_ISCHR(st.st_mode) &&
	    ioctl(fd, DIOCGMEDIASIZE, &mediasize) == 0 &&
	    mediasize > 0) {
		is_disk_like = 1;
	}
#elif defined(__NetBSD__) || defined(__OpenBSD__)
	/* Net/OpenBSD: if it supports DIOCGDINFO ioctl, it's disk-like. */
	else if ((S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) &&
	    ioctl(fd, DIOCGDINFO, &dl) == 0 &&
	    dl.d_partitions[DISKPART(st.st_rdev)].p_size > 0) {
		is_disk_like = 1;
	}
#elif defined(__DragonFly__)
	/* DragonFly BSD:  if it supports DIOCGPART ioctl, it's disk-like. */
	else if (S_ISCHR(st.st_mode) &&
	    ioctl(fd, DIOCGPART, &pi) == 0 &&
	    pi.media_size > 0) {
		is_disk_like = 1;
	}
#elif defined(__linux__)
	/* Linux:  All block devices are disk-like. */
	else if (S_ISBLK(st.st_mode) &&
	    lseek(fd, 0, SEEK_CUR) == 0 &&
	    lseek(fd, 0, SEEK_SET) == 0 &&
	    lseek(fd, 0, SEEK_END) > 0 &&
	    lseek(fd, 0, SEEK_SET) == 0) {
		is_disk_like = 1;
	}
#endif
	/* TODO: Add an "is_tape_like" variable and appropriate tests. */

	/* Disk-like devices prefer power-of-two block sizes.  */
	/* Use provided block_size as a guide so users have some control. */
	if (is_disk_like) {
		size_t new_block_size = 64 * 1024;
		while (new_block_size < mine->block_size
		    && new_block_size < 64 * 1024 * 1024)
			new_block_size *= 2;
		mine->block_size = new_block_size;
	}
	buffer = malloc(mine->block_size);
	if (mine == NULL || buffer == NULL) {
		archive_set_error(a, ENOMEM, "No memory");
		free(mine);
		free(buffer);
		return (ARCHIVE_FATAL);
	}
	mine->buffer = buffer;
	mine->fd = fd;
	/* Remember mode so close can decide whether to flush. */
	mine->st_mode = st.st_mode;

	/* Disk-like inputs can use lseek(). */
	if (is_disk_like)
		mine->use_lseek = 1;

	return (ARCHIVE_OK);
}
Example #17
0
bool cgfs_list_keys(const char *controller, const char *cgroup, struct cgfs_files ***keys)
{
	size_t len;
	char *dirname, *tmpc = find_mounted_controller(controller);
	char pathname[MAXPATHLEN];
	size_t sz = 0, asz = 0;
	struct dirent dirent, *direntp;
	DIR *dir;
	int ret;

	*keys = NULL;
	if (!tmpc)
		return NULL;

	/* basedir / tmpc / cgroup \0 */
	len = strlen(basedir) + strlen(tmpc) + strlen(cgroup) + 3;
	dirname = alloca(len);
	snprintf(dirname, len, "%s/%s/%s", basedir, tmpc, cgroup);

	dir = opendir(dirname);
	if (!dir)
		return false;

	while (!readdir_r(dir, &dirent, &direntp)) {
		struct stat mystat;
		int rc;

		if (!direntp)
			break;

		if (!strcmp(direntp->d_name, ".") ||
		    !strcmp(direntp->d_name, ".."))
			continue;

		rc = snprintf(pathname, MAXPATHLEN, "%s/%s", dirname, direntp->d_name);
		if (rc < 0 || rc >= MAXPATHLEN) {
			fprintf(stderr, "%s: pathname too long under %s\n", __func__, dirname);
			continue;
		}

		ret = lstat(pathname, &mystat);
		if (ret) {
			fprintf(stderr, "%s: failed to stat %s: %s\n", __func__, pathname, strerror(errno));
			continue;
		}
		if (!S_ISREG(mystat.st_mode))
			continue;

		if (sz+2 >= asz) {
			struct cgfs_files **tmp;
			asz += BATCH_SIZE;
			do {
				tmp = realloc(*keys, asz * sizeof(struct cgfs_files *));
			} while  (!tmp);
			*keys = tmp;
		}
		(*keys)[sz] = cgfs_get_key(controller, cgroup, direntp->d_name);
		(*keys)[sz+1] = NULL;
		if (!(*keys)[sz]) {
			fprintf(stderr, "%s: Error getting files under %s:%s\n",
				__func__, controller, cgroup);
			continue;
		}
		sz++;
	}
	if (closedir(dir) < 0) {
		fprintf(stderr, "%s: failed closedir for %s: %s\n", __func__, dirname, strerror(errno));
		return false;
	}
	return true;
}
Example #18
0
EDIT_FILE *edit_file_open(const char *path, int flags, mode_t mode)
{
    struct stat before_lock;
    struct stat after_lock;
    int     saved_errno;
    EDIT_FILE *ep;

    /*
     * Initialize. Do not bother to optimize for the error case.
     */
    EDIT_FILE_ALLOC(ep, path, mode);

    /*
     * As long as the output file can be opened under the temporary pathname,
     * this code can loop or block forever.
     * 
     * Applications that are concerned about deadlock should protect the
     * edit_file_open() call with a watchdog timer.
     */
    for ( /* void */ ; /* void */ ; (void) vstream_fclose(ep->tmp_fp)) {

	/*
	 * Try to open the output file under the temporary pathname. This
	 * succeeds or fails immediately. To avoid creating a shared-lock DOS
	 * opportunity after we crash, we create the output file with no
	 * group or other permissions, and set the final permissions at the
	 * end (this is one reason why we try to get exclusive control over
	 * the output file instead of the original file). We postpone file
	 * truncation until we have obtained exclusive control over the file
	 * content and temporary pathname. If the open operation fails, we
	 * give up immediately. The caller can retry the call if desirable.
	 * 
	 * XXX If we replace the vstream_fopen() call by safe_open(), then we
	 * should replace the stat() call below by lstat().
	 */
	if ((ep->tmp_fp = vstream_fopen(ep->tmp_path, flags & ~(O_TRUNC),
				    EDIT_FILE_MODE)) == 0) {
	    saved_errno = errno;
	    EDIT_FILE_FREE(ep);
	    errno = saved_errno;
	    return (0);
	}

	/*
	 * At this point we may have opened an existing output file that was
	 * already locked. Try to lock the open file exclusively. This may
	 * take some time.
	 */
	if (myflock(vstream_fileno(ep->tmp_fp), INTERNAL_LOCK,
		    MYFLOCK_OP_EXCLUSIVE) < 0)
	    msg_fatal("lock %s: %m", ep->tmp_path);

	/*
	 * At this point we have an exclusive lock, but some other process
	 * may have renamed or removed the output file while we were waiting
	 * for the lock. If that is the case, back out and try again.
	 */
	if (fstat(vstream_fileno(ep->tmp_fp), &before_lock) < 0)
	    msg_fatal("open %s: %m", ep->tmp_path);
	if (stat(ep->tmp_path, &after_lock) < 0
	    || before_lock.st_dev != after_lock.st_dev
	    || before_lock.st_ino != after_lock.st_ino
#ifdef HAS_ST_GEN
	    || before_lock.st_gen != after_lock.st_gen
#endif
	/* No need to compare st_rdev or st_nlink here. */
	    ) {
	    continue;
	}

	/*
	 * At this point we have exclusive control over the output file
	 * content and its temporary pathname (within the rules of the
	 * cooperative protocol). But wait, there is more.
	 * 
	 * There are many opportunies for trouble when opening a pre-existing
	 * output file. Here are just a few.
	 * 
	 * - Victor observes that a system crash in the middle of the
	 * final-phase rename() operation may result in the output file
	 * having both the temporary pathname and the final pathname. In that
	 * case we must not write to the output file.
	 * 
	 * - Wietse observes that crashes may also leave the output file in
	 * other inconsistent states. To avoid permission-related trouble, we
	 * simply refuse to work with an output file that has the wrong
	 * temporary permissions. This won't stop the shared-lock DOS if we
	 * crash after changing the file permissions, though.
	 * 
	 * To work around these crash-related problems, remove the temporary
	 * pathname, back out, and try again.
	 */
	if (!S_ISREG(after_lock.st_mode)
#ifndef EDIT_FILE_REUSE_AFTER_CRASH
	    || after_lock.st_size > 0
#endif
	    || after_lock.st_nlink > 1
	    || (after_lock.st_mode & FILE_PERM_MASK) != EDIT_FILE_MODE) {
	    if (unlink(ep->tmp_path) < 0 && errno != ENOENT)
		msg_fatal("unlink %s: %m", ep->tmp_path);
	    continue;
	}

	/*
	 * Settle the final details.
	 */
#ifdef EDIT_FILE_REUSE_AFTER_CRASH
	if (ftruncate(vstream_fileno(ep->tmp_fp), 0) < 0)
	    msg_fatal("truncate %s: %m", ep->tmp_path);
#endif
	return (ep);
    }
}
Example #19
0
int read_full_stream(FILE *f, char **contents, size_t *size) {
        size_t n, l;
        _cleanup_free_ char *buf = NULL;
        struct stat st;

        assert(f);
        assert(contents);

        if (fstat(fileno(f), &st) < 0)
                return -errno;

        n = LINE_MAX;

        if (S_ISREG(st.st_mode)) {

                /* Safety check */
                if (st.st_size > 4*1024*1024)
                        return -E2BIG;

                /* Start with the right file size, but be prepared for
                 * files from /proc which generally report a file size
                 * of 0 */
                if (st.st_size > 0)
                        n = st.st_size;
        }

        l = 0;
        for (;;) {
                char *t;
                size_t k;

                t = realloc(buf, n+1);
                if (!t)
                        return -ENOMEM;

                buf = t;
                k = fread(buf + l, 1, n - l, f);

                if (k <= 0) {
                        if (ferror(f))
                                return -errno;

                        break;
                }

                l += k;
                n *= 2;

                /* Safety check */
                if (n > 4*1024*1024)
                        return -E2BIG;
        }

        buf[l] = 0;
        *contents = buf;
        buf = NULL; /* do not free */

        if (size)
                *size = l;

        return 0;
}
Example #20
0
/*
 * ar_close()
 *	closes archive device, increments volume number, and prints i/o summary
 */
void
ar_close(void)
{
	int status;

	if (arfd < 0) {
		did_io = io_ok = flcnt = 0;
		return;
	}

	/*
	 * Close archive file. This may take a LONG while on tapes (we may be
	 * forced to wait for the rewind to complete) so tell the user what is
	 * going on (this avoids the user hitting control-c thinking pax is
	 * broken).
	 */
	if (vflag && (artyp == ISTAPE)) {
		if (vfpart)
			(void)putc('\n', listf);
		(void)fprintf(listf,
			"%s: Waiting for tape drive close to complete...",
			argv0);
		(void)fflush(listf);
	}

	/*
	 * if nothing was written to the archive (and we created it), we remove
	 * it
	 */
	if (can_unlnk && (fstat(arfd, &arsb) == 0) && (S_ISREG(arsb.st_mode)) &&
	    (arsb.st_size == 0)) {
		(void)unlink(arcname);
		can_unlnk = 0;
	}

	/*
	 * for a quick extract/list, pax frequently exits before the child
	 * process is done
	 */
	if ((act == LIST || act == EXTRACT) && nflag && zpid > 0)
		kill(zpid, SIGINT);

	(void)close(arfd);

	/* Do not exit before child to ensure data integrity */
	if (zpid > 0)
		waitpid(zpid, &status, 0);

	if (vflag && (artyp == ISTAPE)) {
		(void)fputs("done.\n", listf);
		vfpart = 0;
		(void)fflush(listf);
	}
	arfd = -1;

	if (!io_ok && !did_io) {
		flcnt = 0;
		return;
	}
	did_io = io_ok = 0;

	/*
	 * The volume number is only increased when the last device has data
	 * and we have already determined the archive format.
	 */
	if (frmt != NULL)
		++arvol;

	if (!vflag) {
		flcnt = 0;
		return;
	}

	/*
	 * Print out a summary of I/O for this archive volume.
	 */
	if (vfpart) {
		(void)putc('\n', listf);
		vfpart = 0;
	}

	/*
	 * If we have not determined the format yet, we just say how many bytes
	 * we have skipped over looking for a header to id. there is no way we
	 * could have written anything yet.
	 */
	if (frmt == NULL) {
#	ifdef NET2_STAT
		(void)fprintf(listf, "%s: unknown format, %lu bytes skipped.\n",
		    argv0, rdcnt);
#	else
		(void)fprintf(listf, "%s: unknown format, %ju bytes skipped.\n",
		    argv0, (uintmax_t)rdcnt);
#	endif
		(void)fflush(listf);
		flcnt = 0;
		return;
	}

	if (strcmp(NM_CPIO, argv0) == 0)
		(void)fprintf(listf, "%llu blocks\n",
		    (unsigned long)((rdcnt ? rdcnt : wrcnt) / 5120));
	else if (strcmp(NM_TAR, argv0) != 0)
		(void)fprintf(listf,
#	ifdef NET2_STAT
		    "%s: %s vol %d, %lu files, %lu bytes read, %lu bytes written.\n",
		    argv0, frmt->name, arvol-1, flcnt, rdcnt, wrcnt);
#	else
		    "%s: %s vol %d, %ju files, %ju bytes read, %ju bytes written.\n",
		    argv0, frmt->name, arvol-1, (uintmax_t)flcnt,
		    (uintmax_t)rdcnt, (uintmax_t)wrcnt);
#	endif
	(void)fflush(listf);
	flcnt = 0;
}
Example #21
0
static int test_config(char *filename)
{
#if 0
	struct stat st;
	char	    *file;
#endif

	if (!(rc_conf_srv("authserver")->max))
	{
		rc_log(LOG_ERR,"%s: no authserver specified", filename);
		return (-1);
	}
	if (!(rc_conf_srv("acctserver")->max))
	{
		rc_log(LOG_ERR,"%s: no acctserver specified", filename);
		return (-1);
	}
	if (!rc_conf_str("servers"))
	{
		rc_log(LOG_ERR,"%s: no servers file specified", filename);
		return (-1);
	}
	if (!rc_conf_str("dictionary"))
	{
		rc_log(LOG_ERR,"%s: no dictionary specified", filename);
		return (-1);
	}

	if (rc_conf_int("radius_timeout") <= 0)
	{
		rc_log(LOG_ERR,"%s: radius_timeout <= 0 is illegal", filename);
		return (-1);
	}
	if (rc_conf_int("radius_retries") <= 0)
	{
		rc_log(LOG_ERR,"%s: radius_retries <= 0 is illegal", filename);
		return (-1);
	}

#if 0
	file = rc_conf_str("login_local");
	if (stat(file, &st) == 0)
	{
		if (!S_ISREG(st.st_mode)) {
			rc_log(LOG_ERR,"%s: not a regular file: %s", filename, file);
			return (-1);
		}
	} else {
		rc_log(LOG_ERR,"%s: file not found: %s", filename, file);
		return (-1);
	}
	file = rc_conf_str("login_radius");
	if (stat(file, &st) == 0)
	{
		if (!S_ISREG(st.st_mode)) {
			rc_log(LOG_ERR,"%s: not a regular file: %s", filename, file);
			return (-1);
		}
	} else {
		rc_log(LOG_ERR,"%s: file not found: %s", filename, file);
		return (-1);
	}
#endif

	if (rc_conf_int("login_tries") <= 0)
	{
		rc_log(LOG_ERR,"%s: login_tries <= 0 is illegal", filename);
		return (-1);
	}
	if (rc_conf_str("seqfile") == NULL)
	{
		rc_log(LOG_ERR,"%s: seqfile not specified", filename);
		return (-1);
	}
	if (rc_conf_int("login_timeout") <= 0)
	{
		rc_log(LOG_ERR,"%s: login_timeout <= 0 is illegal", filename);
		return (-1);
	}
	if (rc_conf_str("mapfile") == NULL)
	{
		rc_log(LOG_ERR,"%s: mapfile not specified", filename);
		return (-1);
	}
	if (rc_conf_str("nologin") == NULL)
	{
		rc_log(LOG_ERR,"%s: nologin not specified", filename);
		return (-1);
	}

	return 0;
}
Example #22
0
File: durable.c Project: hef/samba
NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
					const DATA_BLOB old_cookie,
					TALLOC_CTX *mem_ctx,
					DATA_BLOB *new_cookie)
{
	struct connection_struct *conn = fsp->conn;
	NTSTATUS status;
	enum ndr_err_code ndr_err;
	struct vfs_default_durable_cookie cookie;
	DATA_BLOB new_cookie_blob = data_blob_null;
	struct share_mode_lock *lck;
	bool ok;

	*new_cookie = data_blob_null;

	ZERO_STRUCT(cookie);

	ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
			(ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		status = ndr_map_error2ntstatus(ndr_err);
		return status;
	}

	if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!file_id_equal(&fsp->file_id, &cookie.id)) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!BATCH_OPLOCK_TYPE(fsp->oplock_type)) {
		return NT_STATUS_NOT_SUPPORTED;
	}

	/*
	 * For now let it be simple and do not keep
	 * delete on close files durable open
	 */
	if (fsp->initial_delete_on_close) {
		return NT_STATUS_NOT_SUPPORTED;
	}
	if (fsp->delete_on_close) {
		return NT_STATUS_NOT_SUPPORTED;
	}

	if (!VALID_STAT(fsp->fsp_name->st)) {
		return NT_STATUS_NOT_SUPPORTED;
	}

	if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
		return NT_STATUS_NOT_SUPPORTED;
	}

	/* Ensure any pending write time updates are done. */
	if (fsp->update_write_time_event) {
		update_write_time_handler(fsp->conn->sconn->ev_ctx,
					fsp->update_write_time_event,
					timeval_current(),
					(void *)fsp);
	}

	/*
	 * The above checks are done in mark_share_mode_disconnected() too
	 * but we want to avoid getting the lock if possible
	 */
	lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
	if (lck != NULL) {
		struct smb_file_time ft;

		ZERO_STRUCT(ft);

		if (fsp->write_time_forced) {
			ft.mtime = lck->data->changed_write_time;
		} else if (fsp->update_write_time_on_close) {
			if (null_timespec(fsp->close_write_time)) {
				ft.mtime = timespec_current();
			} else {
				ft.mtime = fsp->close_write_time;
			}
		}

		if (!null_timespec(ft.mtime)) {
			round_timespec(conn->ts_res, &ft.mtime);
			file_ntimes(conn, fsp->fsp_name, &ft);
		}

		ok = mark_share_mode_disconnected(lck, fsp);
		if (!ok) {
			TALLOC_FREE(lck);
		}
	}
	if (lck != NULL) {
		ok = brl_mark_disconnected(fsp);
		if (!ok) {
			TALLOC_FREE(lck);
		}
	}
	if (lck == NULL) {
		return NT_STATUS_NOT_SUPPORTED;
	}
	TALLOC_FREE(lck);

	status = vfs_stat_fsp(fsp);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	ZERO_STRUCT(cookie);
	cookie.allow_reconnect = true;
	cookie.id = fsp->file_id;
	cookie.servicepath = conn->connectpath;
	cookie.base_name = fsp->fsp_name->base_name;
	cookie.initial_allocation_size = fsp->initial_allocation_size;
	cookie.position_information = fsp->fh->position_information;
	cookie.update_write_time_triggered = fsp->update_write_time_triggered;
	cookie.update_write_time_on_close = fsp->update_write_time_on_close;
	cookie.write_time_forced = fsp->write_time_forced;
	cookie.close_write_time = fsp->close_write_time;

	cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
	cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
	cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
	cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
	cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
	cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
	cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
	cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
	cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
	cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
	cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
	cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
	cookie.stat_info.st_ex_calculated_birthtime = fsp->fsp_name->st.st_ex_calculated_birthtime;
	cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
	cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
	cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
	cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;

	ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
			(ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		status = ndr_map_error2ntstatus(ndr_err);
		return status;
	}

	status = fd_close(fsp);
	if (!NT_STATUS_IS_OK(status)) {
		data_blob_free(&new_cookie_blob);
		return status;
	}

	*new_cookie = new_cookie_blob;
	return NT_STATUS_OK;
}
Example #23
0
gt_input_file* gt_input_file_open(char* const file_name,const bool mmap_file) {
    GT_NULL_CHECK(file_name);
    // Allocate handler
    gt_input_file* input_file = gt_alloc(gt_input_file);
    // Input file
    struct stat stat_info;
    unsigned char tbuf[4];
    int i;
    gt_cond_fatal_error(stat(file_name,&stat_info)==-1,FILE_STAT,file_name);
    input_file->file_name = file_name;
    input_file->file_size = stat_info.st_size;
    input_file->eof = (input_file->file_size==0);
    input_file->file_format = FILE_FORMAT_UNKNOWN;
    gt_cond_fatal_error(pthread_mutex_init(&input_file->input_mutex,NULL),SYS_MUTEX_INIT);
    if (mmap_file) {
        input_file->file = NULL;
        input_file->fildes = open(file_name,O_RDONLY,0); // TODO: O_NOATIME condCompl (Thanks Jordi Camps)
        gt_cond_fatal_error(input_file->fildes==-1,FILE_OPEN,file_name);
        input_file->file_buffer =
            (uint8_t*) mmap(0,input_file->file_size,PROT_READ,MAP_PRIVATE,input_file->fildes,0);
        gt_cond_fatal_error(input_file->file_buffer==MAP_FAILED,SYS_MMAP_FILE,file_name);
        input_file->file_type = MAPPED_FILE;
    } else {
        input_file->fildes = -1;
        gt_cond_fatal_error(!(input_file->file=fopen(file_name,"r")),FILE_OPEN,file_name);
        input_file->file_type = REGULAR_FILE;
        if(S_ISREG(stat_info.st_mode)) {
            // Regular file - check if gzip or bzip compressed
            i=(int)fread(tbuf,(size_t)1,(size_t)4,input_file->file);
            if(tbuf[0]==0x1f && tbuf[1]==0x8b && tbuf[2]==0x08) {
                input_file->file_type=GZIPPED_FILE;
                fclose(input_file->file);
#ifdef HAVE_ZLIB
                gt_cond_fatal_error(!(input_file->file=(void *)gzopen(file_name,"r")),FILE_GZIP_OPEN,file_name);
#else
                gt_fatal_error(FILE_GZIP_NO_ZLIB,file_name);
#endif
            } else if(tbuf[0]=='B' && tbuf[1]=='Z' && tbuf[2]=='h' && tbuf[3]>='0' && tbuf[3]<='9') {
                fseek(input_file->file,0L,SEEK_SET);
                input_file->file_type=BZIPPED_FILE;
#ifdef HAVE_BZLIB
                input_file->file=BZ2_bzReadOpen(&i,input_file->file,0,0,NULL,0);
                gt_cond_fatal_error(i!=BZ_OK,FILE_BZIP2_OPEN,file_name);
#else
                gt_fatal_error(FILE_BZIP2_NO_BZLIB,file_name);
#endif
            } else {
                fseek(input_file->file,0L,SEEK_SET);
            }
        } else {
            input_file->eof=0;
        }
        input_file->file_buffer = gt_malloc(GT_INPUT_BUFFER_SIZE);
    }
    // Auxiliary Buffer (for synch purposes)
    input_file->buffer_size = 0;
    input_file->buffer_begin = 0;
    input_file->buffer_pos = 0;
    input_file->global_pos = 0;
    input_file->processed_lines = 0;
    // ID generator
    input_file->processed_id = 0;
    // Detect file format
    gt_input_file_detect_file_format(input_file);
    return input_file;
}
Example #24
0
File: durable.c Project: hef/samba
NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
				       struct smb_request *smb1req,
				       struct smbXsrv_open *op,
				       const DATA_BLOB old_cookie,
				       TALLOC_CTX *mem_ctx,
				       files_struct **result,
				       DATA_BLOB *new_cookie)
{
	struct share_mode_lock *lck;
	struct share_mode_entry *e;
	struct files_struct *fsp = NULL;
	NTSTATUS status;
	bool ok;
	int ret;
	int flags = 0;
	struct file_id file_id;
	struct smb_filename *smb_fname = NULL;
	enum ndr_err_code ndr_err;
	struct vfs_default_durable_cookie cookie;
	DATA_BLOB new_cookie_blob = data_blob_null;

	*result = NULL;
	*new_cookie = data_blob_null;

	if (!lp_durable_handles(SNUM(conn))) {
		return NT_STATUS_NOT_SUPPORTED;
	}

	/*
	 * the checks for kernel oplocks
	 * and similar things are done
	 * in the vfs_default_durable_cookie()
	 * call below.
	 */

	ZERO_STRUCT(cookie);

	ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
			(ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		status = ndr_map_error2ntstatus(ndr_err);
		return status;
	}

	if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!cookie.allow_reconnect) {
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	if (strcmp(cookie.servicepath, conn->connectpath) != 0) {
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	/* Create an smb_filename with stream_name == NULL. */
	smb_fname = synthetic_smb_fname(talloc_tos(), cookie.base_name,
					NULL, NULL);
	if (smb_fname == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	ret = SMB_VFS_LSTAT(conn, smb_fname);
	if (ret == -1) {
		status = map_nt_error_from_unix_common(errno);
		DEBUG(1, ("Unable to lstat stream: %s => %s\n",
			  smb_fname_str_dbg(smb_fname),
			  nt_errstr(status)));
		return status;
	}

	if (!S_ISREG(smb_fname->st.st_ex_mode)) {
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
	if (!file_id_equal(&cookie.id, &file_id)) {
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	/*
	 * 1. check entry in locking.tdb
	 */

	lck = get_existing_share_mode_lock(mem_ctx, file_id);
	if (lck == NULL) {
		DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
			   "not obtained from db\n"));
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	if (lck->data->num_share_modes == 0) {
		DEBUG(1, ("vfs_default_durable_reconnect: Error: no share-mode "
			  "entry in existing share mode lock\n"));
		TALLOC_FREE(lck);
		return NT_STATUS_INTERNAL_DB_ERROR;
	}

	if (lck->data->num_share_modes > 1) {
		/*
		 * It can't be durable if there is more than one handle
		 * on the file.
		 */
		DEBUG(5, ("vfs_default_durable_reconnect: more than one "
			  "share-mode entry - can not be durable\n"));
		TALLOC_FREE(lck);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	e = &lck->data->share_modes[0];

	if (!server_id_is_disconnected(&e->pid)) {
		DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
			  "reconnect for handle that was not marked "
			  "disconnected (e.g. smbd or cluster node died)\n"));
		TALLOC_FREE(lck);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	if (e->share_file_id != op->global->open_persistent_id) {
		DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
			  "share_file_id changed %llu != %llu"
			  "(e.g. another client had opened the file)\n",
			  (unsigned long long)e->share_file_id,
			  (unsigned long long)op->global->open_persistent_id));
		TALLOC_FREE(lck);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	if ((e->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
	    !CAN_WRITE(conn))
	{
		DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
			  "share[%s] is not writeable anymore\n",
			  lp_servicename(talloc_tos(), SNUM(conn))));
		TALLOC_FREE(lck);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	/*
	 * 2. proceed with opening file
	 */

	status = fsp_new(conn, conn, &fsp);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
			  "new fsp: %s\n", nt_errstr(status)));
		TALLOC_FREE(lck);
		return status;
	}

	fsp->fh->private_options = e->private_options;
	fsp->fh->gen_id = smbXsrv_open_hash(op);
	fsp->file_id = file_id;
	fsp->file_pid = smb1req->smbpid;
	fsp->vuid = smb1req->vuid;
	fsp->open_time = e->time;
	fsp->access_mask = e->access_mask;
	fsp->share_access = e->share_access;
	fsp->can_read = ((fsp->access_mask & (FILE_READ_DATA)) != 0);
	fsp->can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
	fsp->fnum = op->local_id;

	/*
	 * TODO:
	 * Do we need to store the modified flag in the DB?
	 */
	fsp->modified = false;
	/*
	 * no durables for directories
	 */
	fsp->is_directory = false;
	/*
	 * For normal files, can_lock == !is_directory
	 */
	fsp->can_lock = true;
	/*
	 * We do not support aio write behind for smb2
	 */
	fsp->aio_write_behind = false;
	fsp->oplock_type = e->op_type;

	fsp->initial_allocation_size = cookie.initial_allocation_size;
	fsp->fh->position_information = cookie.position_information;
	fsp->update_write_time_triggered = cookie.update_write_time_triggered;
	fsp->update_write_time_on_close = cookie.update_write_time_on_close;
	fsp->write_time_forced = cookie.write_time_forced;
	fsp->close_write_time = cookie.close_write_time;

	status = fsp_set_smb_fname(fsp, smb_fname);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(lck);
		fsp_free(fsp);
		DEBUG(0, ("vfs_default_durable_reconnect: "
			  "fsp_set_smb_fname failed: %s\n",
			  nt_errstr(status)));
		return status;
	}

	op->compat = fsp;
	fsp->op = op;

	e->pid = messaging_server_id(conn->sconn->msg_ctx);
	e->op_mid = smb1req->mid;
	e->share_file_id = fsp->fh->gen_id;

	ok = brl_reconnect_disconnected(fsp);
	if (!ok) {
		status = NT_STATUS_INTERNAL_ERROR;
		DEBUG(1, ("vfs_default_durable_reconnect: "
			  "failed to reopen brlocks: %s\n",
			  nt_errstr(status)));
		TALLOC_FREE(lck);
		op->compat = NULL;
		fsp_free(fsp);
		return status;
	}

	/*
	 * TODO: properly calculate open flags
	 */
	if (fsp->can_write && fsp->can_read) {
		flags = O_RDWR;
	} else if (fsp->can_write) {
		flags = O_WRONLY;
	} else if (fsp->can_read) {
		flags = O_RDONLY;
	}

	status = fd_open(conn, fsp, flags, 0 /* mode */);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(lck);
		DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
			  "file: %s\n", nt_errstr(status)));
		op->compat = NULL;
		fsp_free(fsp);
		return status;
	}

	/*
	 * We now check the stat info stored in the cookie against
	 * the current stat data from the file we just opened.
	 * If any detail differs, we deny the durable reconnect,
	 * because in that case it is very likely that someone
	 * opened the file while the handle was disconnected,
	 * which has to be interpreted as an oplock break.
	 */

	ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
	if (ret == -1) {
		status = map_nt_error_from_unix_common(errno);
		DEBUG(1, ("Unable to fstat stream: %s => %s\n",
			  smb_fname_str_dbg(smb_fname),
			  nt_errstr(status)));
		ret = SMB_VFS_CLOSE(fsp);
		if (ret == -1) {
			DEBUG(0, ("vfs_default_durable_reconnect: "
				  "SMB_VFS_CLOSE failed (%s) - leaking file "
				  "descriptor\n", strerror(errno)));
		}
		TALLOC_FREE(lck);
		op->compat = NULL;
		fsp_free(fsp);
		return status;
	}

	if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
		ret = SMB_VFS_CLOSE(fsp);
		if (ret == -1) {
			DEBUG(0, ("vfs_default_durable_reconnect: "
				  "SMB_VFS_CLOSE failed (%s) - leaking file "
				  "descriptor\n", strerror(errno)));
		}
		TALLOC_FREE(lck);
		op->compat = NULL;
		fsp_free(fsp);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
	if (!file_id_equal(&cookie.id, &file_id)) {
		ret = SMB_VFS_CLOSE(fsp);
		if (ret == -1) {
			DEBUG(0, ("vfs_default_durable_reconnect: "
				  "SMB_VFS_CLOSE failed (%s) - leaking file "
				  "descriptor\n", strerror(errno)));
		}
		TALLOC_FREE(lck);
		op->compat = NULL;
		fsp_free(fsp);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info,
						      &fsp->fsp_name->st,
						      fsp_str_dbg(fsp));
	if (!ok) {
		ret = SMB_VFS_CLOSE(fsp);
		if (ret == -1) {
			DEBUG(0, ("vfs_default_durable_reconnect: "
				  "SMB_VFS_CLOSE failed (%s) - leaking file "
				  "descriptor\n", strerror(errno)));
		}
		TALLOC_FREE(lck);
		op->compat = NULL;
		fsp_free(fsp);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	status = set_file_oplock(fsp);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
			  "after opening file: %s\n", nt_errstr(status)));
		ret = SMB_VFS_CLOSE(fsp);
		if (ret == -1) {
			DEBUG(0, ("vfs_default_durable_reconnect: "
				  "SMB_VFS_CLOSE failed (%s) - leaking file "
				  "descriptor\n", strerror(errno)));
		}
		TALLOC_FREE(lck);
		op->compat = NULL;
		fsp_free(fsp);
		return status;
	}

	status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(lck);
		DEBUG(1, ("vfs_default_durable_reconnect: "
			  "vfs_default_durable_cookie - %s\n",
			  nt_errstr(status)));
		op->compat = NULL;
		fsp_free(fsp);
		return status;
	}

	smb1req->chain_fsp = fsp;
	smb1req->smb2req->compat_chain_fsp = fsp;

	DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
		   fsp_str_dbg(fsp)));

	/*
	 * release the sharemode lock: this writes the changes
	 */
	lck->data->modified = true;
	TALLOC_FREE(lck);

	*result = fsp;
	*new_cookie = new_cookie_blob;

	return NT_STATUS_OK;
}
Example #25
0
static int ext4_destroy_inline_data_nolock(handle_t *handle,
					   struct inode *inode)
{
	struct ext4_inode_info *ei = EXT4_I(inode);
	struct ext4_xattr_ibody_find is = {
		.s = { .not_found = 0, },
	};
	struct ext4_xattr_info i = {
		.name_index = EXT4_XATTR_INDEX_SYSTEM,
		.name = EXT4_XATTR_SYSTEM_DATA,
		.value = NULL,
		.value_len = 0,
	};
	int error;

	if (!ei->i_inline_off)
		return 0;

	error = ext4_get_inode_loc(inode, &is.iloc);
	if (error)
		return error;

	error = ext4_xattr_ibody_find(inode, &i, &is);
	if (error)
		goto out;

	error = ext4_journal_get_write_access(handle, is.iloc.bh);
	if (error)
		goto out;

	error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is);
	if (error)
		goto out;

	memset((void *)ext4_raw_inode(&is.iloc)->i_block,
		0, EXT4_MIN_INLINE_DATA_SIZE);

	if (EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb,
				      EXT4_FEATURE_INCOMPAT_EXTENTS)) {
		if (S_ISDIR(inode->i_mode) ||
		    S_ISREG(inode->i_mode) || S_ISLNK(inode->i_mode)) {
			ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
			ext4_ext_tree_init(handle, inode);
		}
	}
	ext4_clear_inode_flag(inode, EXT4_INODE_INLINE_DATA);

	get_bh(is.iloc.bh);
	error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);

	EXT4_I(inode)->i_inline_off = 0;
	EXT4_I(inode)->i_inline_size = 0;
	ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
out:
	brelse(is.iloc.bh);
	if (error == -ENODATA)
		error = 0;
	return error;
}

static int ext4_read_inline_page(struct inode *inode, struct page *page)
{
	void *kaddr;
	int ret = 0;
	size_t len;
	struct ext4_iloc iloc;

	BUG_ON(!PageLocked(page));
	BUG_ON(!ext4_has_inline_data(inode));
	BUG_ON(page->index);

	if (!EXT4_I(inode)->i_inline_off) {
		ext4_warning(inode->i_sb, "inode %lu doesn't have inline data.",
			     inode->i_ino);
		goto out;
	}

	ret = ext4_get_inode_loc(inode, &iloc);
	if (ret)
		goto out;

	len = min_t(size_t, ext4_get_inline_size(inode), i_size_read(inode));
	kaddr = kmap_atomic(page);
	ret = ext4_read_inline_data(inode, kaddr, len, &iloc);
	flush_dcache_page(page);
	kunmap_atomic(kaddr);
	zero_user_segment(page, len, PAGE_CACHE_SIZE);
	SetPageUptodate(page);
	brelse(iloc.bh);

out:
	return ret;
}
Example #26
0
handler_t http_response_prepare(server *srv, connection *con) {
	handler_t r;

	/* looks like someone has already done a decision */
	if (con->mode == DIRECT &&
	    (con->http_status != 0 && con->http_status != 200)) {
		/* remove a packets in the queue */
		if (con->file_finished == 0) {
			chunkqueue_reset(con->write_queue);
		}

		return HANDLER_FINISHED;
	}

	/* no decision yet, build conf->filename */
	if (con->mode == DIRECT && buffer_is_empty(con->physical.path)) {
		char *qstr;

		/* we only come here when we have the parse the full request again
		 *
		 * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
		 * problem here as mod_setenv might get called multiple times
		 *
		 * fastcgi-auth might lead to a COMEBACK too
		 * fastcgi again dead server too
		 *
		 * mod_compress might add headers twice too
		 *
		 *  */

		config_cond_cache_reset(srv, con);
		config_setup_connection(srv, con); /* Perhaps this could be removed at other places. */

		if (con->conf.log_condition_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "run condition");
		}

		/**
		 * prepare strings
		 *
		 * - uri.path_raw
		 * - uri.path (secure)
		 * - uri.query
		 *
		 */

		/**
		 * Name according to RFC 2396
		 *
		 * - scheme
		 * - authority
		 * - path
		 * - query
		 *
		 * (scheme)://(authority)(path)?(query)#fragment
		 *
		 *
		 */

		/* initial scheme value. can be overwritten for example by mod_extforward later */
		if (con->srv_socket->is_ssl) {
			buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("https"));
		} else {
			buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http"));
		}
		buffer_copy_buffer(con->uri.authority, con->request.http_host);
		buffer_to_lower(con->uri.authority);

		/** their might be a fragment which has to be cut away */
		if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) {
			buffer_string_set_length(con->request.uri, qstr - con->request.uri->ptr);
		}

		/** extract query string from request.uri */
		if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
			buffer_copy_string    (con->uri.query, qstr + 1);
			buffer_copy_string_len(con->uri.path_raw, con->request.uri->ptr, qstr - con->request.uri->ptr);
		} else {
			buffer_reset     (con->uri.query);
			buffer_copy_buffer(con->uri.path_raw, con->request.uri);
		}

		/* decode url to path
		 *
		 * - decode url-encodings  (e.g. %20 -> ' ')
		 * - remove path-modifiers (e.g. /../)
		 */

		if (con->request.http_method == HTTP_METHOD_OPTIONS &&
		    con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
			/* OPTIONS * ... */
			buffer_copy_buffer(con->uri.path, con->uri.path_raw);
		} else {
			buffer_copy_buffer(srv->tmp_buf, con->uri.path_raw);
			buffer_urldecode_path(srv->tmp_buf);
			buffer_path_simplify(con->uri.path, srv->tmp_buf);
		}

		con->conditional_is_valid[COMP_SERVER_SOCKET] = 1;       /* SERVERsocket */
		con->conditional_is_valid[COMP_HTTP_SCHEME] = 1;         /* Scheme:      */
		con->conditional_is_valid[COMP_HTTP_HOST] = 1;           /* Host:        */
		con->conditional_is_valid[COMP_HTTP_REMOTE_IP] = 1;      /* Client-IP */
		con->conditional_is_valid[COMP_HTTP_REFERER] = 1;        /* Referer:     */
		con->conditional_is_valid[COMP_HTTP_USER_AGENT] =        /* User-Agent:  */
		con->conditional_is_valid[COMP_HTTP_LANGUAGE] = 1;       /* Accept-Language:  */
		con->conditional_is_valid[COMP_HTTP_COOKIE] = 1;         /* Cookie:  */
		con->conditional_is_valid[COMP_HTTP_REQUEST_METHOD] = 1; /* REQUEST_METHOD */
		con->conditional_is_valid[COMP_HTTP_URL] = 1;            /* HTTPurl */
		con->conditional_is_valid[COMP_HTTP_QUERY_STRING] = 1;   /* HTTPqs */
		config_patch_connection(srv, con);

#ifdef USE_OPENSSL
		if (con->srv_socket->is_ssl && con->conf.ssl_verifyclient) {
			https_add_ssl_entries(con);
		}
#endif

		/* do we have to downgrade to 1.0 ? */
		if (!con->conf.allow_http11) {
			con->request.http_version = HTTP_VERSION_1_0;
		}

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- splitting Request-URI");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Request-URI     : ", con->request.uri);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-scheme      : ", con->uri.scheme);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-authority   : ", con->uri.authority);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path (raw)  : ", con->uri.path_raw);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path (clean): ", con->uri.path);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-query       : ", con->uri.query);
		}


		/**
		 *
		 * call plugins
		 *
		 * - based on the raw URL
		 *
		 */

		switch(r = plugins_call_handle_uri_raw(srv, con)) {
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
			return r;
		default:
			log_error_write(srv, __FILE__, __LINE__, "sd", "handle_uri_raw: unknown return value", r);
			break;
		}

		/**
		 *
		 * call plugins
		 *
		 * - based on the clean URL
		 *
		 */

		switch(r = plugins_call_handle_uri_clean(srv, con)) {
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
			return r;
		default:
			log_error_write(srv, __FILE__, __LINE__, "");
			break;
		}

		if (con->request.http_method == HTTP_METHOD_OPTIONS &&
		    con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
			/* option requests are handled directly without checking of the path */

			response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));

			con->http_status = 200;
			con->file_finished = 1;

			return HANDLER_FINISHED;
		}

		/***
		 *
		 * border
		 *
		 * logical filename (URI) becomes a physical filename here
		 *
		 *
		 *
		 */




		/* 1. stat()
		 * ... ISREG() -> ok, go on
		 * ... ISDIR() -> index-file -> redirect
		 *
		 * 2. pathinfo()
		 * ... ISREG()
		 *
		 * 3. -> 404
		 *
		 */

		/*
		 * SEARCH DOCUMENT ROOT
		 */

		/* set a default */

		buffer_copy_buffer(con->physical.doc_root, con->conf.document_root);
		buffer_copy_buffer(con->physical.rel_path, con->uri.path);

#if defined(__WIN32) || defined(__CYGWIN__)
		/* strip dots from the end and spaces
		 *
		 * windows/dos handle those filenames as the same file
		 *
		 * foo == foo. == foo..... == "foo...   " == "foo..  ./"
		 *
		 * This will affect in some cases PATHINFO
		 *
		 * on native windows we could prepend the filename with \\?\ to circumvent
		 * this behaviour. I have no idea how to push this through cygwin
		 *
		 * */

		if (con->physical.rel_path->used > 1) {
			buffer *b = con->physical.rel_path;
			size_t len = buffer_string_length(b);

			/* strip trailing " /" or "./" once */
			if (len > 1 &&
			    b->ptr[len - 1] == '/' &&
			    (b->ptr[len - 2] == ' ' || b->ptr[len - 2] == '.')) {
				len -= 2;
			}
			/* strip all trailing " " and "." */
			while (len > 0 &&  ( ' ' == b->ptr[len-1] || '.' == b->ptr[len-1] ) ) --len;
			buffer_string_set_length(b, len);
		}
#endif

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- before doc_root");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}
		/* the docroot plugin should set the doc_root and might also set the physical.path
		 * for us (all vhost-plugins are supposed to set the doc_root)
		 * */
		switch(r = plugins_call_handle_docroot(srv, con)) {
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
			return r;
		default:
			log_error_write(srv, __FILE__, __LINE__, "");
			break;
		}

		/* MacOS X and Windows can't distiguish between upper and lower-case
		 *
		 * convert to lower-case
		 */
		if (con->conf.force_lowercase_filenames) {
			buffer_to_lower(con->physical.rel_path);
		}

		/* the docroot plugins might set the servername, if they don't we take http-host */
		if (buffer_string_is_empty(con->server_name)) {
			buffer_copy_buffer(con->server_name, con->uri.authority);
		}

		/**
		 * create physical filename
		 * -> physical.path = docroot + rel_path
		 *
		 */

		buffer_copy_buffer(con->physical.basedir, con->physical.doc_root);
		buffer_copy_buffer(con->physical.path, con->physical.doc_root);
		buffer_append_slash(con->physical.path);
		if (!buffer_string_is_empty(con->physical.rel_path) &&
		    con->physical.rel_path->ptr[0] == '/') {
			buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, buffer_string_length(con->physical.rel_path) - 1);
		} else {
			buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
		}

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after doc_root");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}

		switch(r = plugins_call_handle_physical(srv, con)) {
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
			return r;
		default:
			log_error_write(srv, __FILE__, __LINE__, "");
			break;
		}

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- logical -> physical");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Basedir      :", con->physical.basedir);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}
	}

	/*
	 * Noone catched away the file from normal path of execution yet (like mod_access)
	 *
	 * Go on and check of the file exists at all
	 */

	if (con->mode == DIRECT) {
		char *slash = NULL;
		char *pathinfo = NULL;
		int found = 0;
		stat_cache_entry *sce = NULL;

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling physical path");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}

		if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
			/* file exists */

			if (con->conf.log_request_handling) {
				log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file found");
				log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
			}
#ifdef HAVE_LSTAT
			if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
				con->http_status = 403;

				if (con->conf.log_request_handling) {
					log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
					log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				}

				buffer_reset(con->physical.path);
				return HANDLER_FINISHED;
			};
#endif
			if (S_ISDIR(sce->st.st_mode)) {
				if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') {
					/* redirect to .../ */

					http_response_redirect_to_directory(srv, con);

					return HANDLER_FINISHED;
				}
#ifdef HAVE_LSTAT
			} else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) {
#else
			} else if (!S_ISREG(sce->st.st_mode)) {
#endif
				/* any special handling of non-reg files ?*/


			}
		} else {
			switch (errno) {
			case EACCES:
				con->http_status = 403;

				if (con->conf.log_request_handling) {
					log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied");
					log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				}

				buffer_reset(con->physical.path);
				return HANDLER_FINISHED;
			case ENAMETOOLONG:
				/* file name to be read was too long. return 404 */
			case ENOENT:
				con->http_status = 404;

				if (con->conf.log_request_handling) {
					log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file not found");
					log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				}

				buffer_reset(con->physical.path);
				return HANDLER_FINISHED;
			case ENOTDIR:
				/* PATH_INFO ! :) */
				break;
			default:
				/* we have no idea what happend. let's tell the user so. */
				con->http_status = 500;
				buffer_reset(con->physical.path);

				log_error_write(srv, __FILE__, __LINE__, "ssbsb",
						"file not found ... or so: ", strerror(errno),
						con->uri.path,
						"->", con->physical.path);

				return HANDLER_FINISHED;
			}

			/* not found, perhaps PATHINFO */

			buffer_copy_buffer(srv->tmp_buf, con->physical.path);

			do {
				if (slash) {
					buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
				} else {
					buffer_copy_buffer(con->physical.path, srv->tmp_buf);
				}

				if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
					found = S_ISREG(sce->st.st_mode);
					break;
				}

				if (pathinfo != NULL) {
					*pathinfo = '\0';
				}
				slash = strrchr(srv->tmp_buf->ptr, '/');

				if (pathinfo != NULL) {
					/* restore '/' */
					*pathinfo = '/';
				}

				if (slash) pathinfo = slash;
			} while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (buffer_string_length(con->physical.basedir) - 1)));

			if (found == 0) {
				/* no it really doesn't exists */
				con->http_status = 404;

				if (con->conf.log_file_not_found) {
					log_error_write(srv, __FILE__, __LINE__, "sbsb",
							"file not found:", con->uri.path,
							"->", con->physical.path);
				}

				buffer_reset(con->physical.path);

				return HANDLER_FINISHED;
			}

#ifdef HAVE_LSTAT
			if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
				con->http_status = 403;

				if (con->conf.log_request_handling) {
					log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
					log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				}

				buffer_reset(con->physical.path);
				return HANDLER_FINISHED;
			};
#endif

			/* we have a PATHINFO */
			if (pathinfo) {
				size_t len = strlen(pathinfo), reqlen;
				if (con->conf.force_lowercase_filenames
				    && len <= (reqlen = buffer_string_length(con->request.uri))
				    && 0 == strncasecmp(con->request.uri->ptr + reqlen - len, pathinfo, len)) {
					/* attempt to preserve case-insensitive PATH_INFO
					 * (works in common case where mod_alias, mod_magnet, and other modules
					 *  have not modified the PATH_INFO portion of request URI, or did so
					 *  with exactly the PATH_INFO desired) */
					buffer_copy_string_len(con->request.pathinfo, con->request.uri->ptr + reqlen - len, len);
				} else {
					buffer_copy_string_len(con->request.pathinfo, pathinfo, len);
				}

				/*
				 * shorten uri.path
				 */

				buffer_string_set_length(con->uri.path, buffer_string_length(con->uri.path) - len);
			}

			if (con->conf.log_request_handling) {
				log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after pathinfo check");
				log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
				log_error_write(srv, __FILE__, __LINE__,  "sb", "Pathinfo     :", con->request.pathinfo);
			}
		}

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling subrequest");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}

		/* call the handlers */
		switch(r = plugins_call_handle_subrequest_start(srv, con)) {
		case HANDLER_GO_ON:
			/* request was not handled */
			break;
		case HANDLER_FINISHED:
		default:
			if (con->conf.log_request_handling) {
				log_error_write(srv, __FILE__, __LINE__,  "s",  "-- subrequest finished");
			}

			/* something strange happend */
			return r;
		}

		/* if we are still here, no one wanted the file, status 403 is ok I think */

		if (con->mode == DIRECT && con->http_status == 0) {
			switch (con->request.http_method) {
			case HTTP_METHOD_OPTIONS:
				con->http_status = 200;
				break;
			default:
				con->http_status = 403;
			}

			return HANDLER_FINISHED;
		}

	}

	switch(r = plugins_call_handle_subrequest(srv, con)) {
	case HANDLER_GO_ON:
		/* request was not handled, looks like we are done */
		return HANDLER_FINISHED;
	case HANDLER_FINISHED:
		/* request is finished */
	default:
		/* something strange happend */
		return r;
	}

	/* can't happen */
	return HANDLER_COMEBACK;
}
Example #27
0
static long do_sys_truncate(const char __user *pathname, loff_t length)
{
	struct path path;
	struct inode *inode;
	int error;

	error = -EINVAL;
	if (length < 0)	/* sorry, but loff_t says... */
		goto out;

	error = user_path(pathname, &path);
	if (error)
		goto out;
	inode = path.dentry->d_inode;

	/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
	error = -EISDIR;
	if (S_ISDIR(inode->i_mode))
		goto dput_and_out;

	error = -EINVAL;
	if (!S_ISREG(inode->i_mode))
		goto dput_and_out;

	error = mnt_want_write(path.mnt);
	if (error)
		goto dput_and_out;

	error = inode_permission(inode, MAY_WRITE);
	if (error)
		goto mnt_drop_write_and_out;

	error = -EPERM;
	if (IS_APPEND(inode))
		goto mnt_drop_write_and_out;

	error = get_write_access(inode);
	if (error)
		goto mnt_drop_write_and_out;

	/*
	 * Make sure that there are no leases.  get_write_access() protects
	 * against the truncate racing with a lease-granting setlease().
	 */
	error = break_lease(inode, O_WRONLY);
	if (error)
		goto put_write_and_out;

	error = locks_verify_truncate(inode, NULL, length);
	if (!error)
		error = security_path_truncate(&path);
	if (!error)
		error = do_truncate(path.dentry, length, 0, NULL);

put_write_and_out:
	put_write_access(inode);
mnt_drop_write_and_out:
	mnt_drop_write(path.mnt);
dput_and_out:
	path_put(&path);
out:
	return error;
}
Example #28
0
static int au_cmoo(struct dentry *dentry)
{
	int err, cmoo;
	unsigned int udba;
	struct path h_path;
	struct au_pin pin;
	struct au_cp_generic cpg = {
		.dentry	= dentry,
		.bdst	= -1,
		.bsrc	= -1,
		.len	= -1,
		.pin	= &pin,
		.flags	= AuCpup_DTIME | AuCpup_HOPEN
	};
	struct inode *inode, *delegated;
	struct super_block *sb;
	struct au_sbinfo *sbinfo;
	struct au_fhsm *fhsm;
	pid_t pid;
	struct au_branch *br;
	struct dentry *parent;
	struct au_hinode *hdir;

	DiMustWriteLock(dentry);
	inode = dentry->d_inode;
	IiMustWriteLock(inode);

	err = 0;
	if (IS_ROOT(dentry))
		goto out;
	cpg.bsrc = au_dbstart(dentry);
	if (!cpg.bsrc)
		goto out;

	sb = dentry->d_sb;
	sbinfo = au_sbi(sb);
	fhsm = &sbinfo->si_fhsm;
	pid = au_fhsm_pid(fhsm);
	if (pid
	    && (current->pid == pid
		|| current->real_parent->pid == pid))
		goto out;

	br = au_sbr(sb, cpg.bsrc);
	cmoo = au_br_cmoo(br->br_perm);
	if (!cmoo)
		goto out;
	if (!S_ISREG(inode->i_mode))
		cmoo &= AuBrAttr_COO_ALL;
	if (!cmoo)
		goto out;

	parent = dget_parent(dentry);
	di_write_lock_parent(parent);
	err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1);
	cpg.bdst = err;
	if (unlikely(err < 0)) {
		err = 0;	/* there is no upper writable branch */
		goto out_dgrade;
	}
	AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst);

	/* do not respect the coo attrib for the target branch */
	err = au_cpup_dirs(dentry, cpg.bdst);
	if (unlikely(err))
		goto out_dgrade;

	di_downgrade_lock(parent, AuLock_IR);
	udba = au_opt_udba(sb);
	err = au_pin(&pin, dentry, cpg.bdst, udba,
		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
	if (unlikely(err))
		goto out_parent;

	err = au_sio_cpup_simple(&cpg);
	au_unpin(&pin);
	if (unlikely(err))
		goto out_parent;
	if (!(cmoo & AuBrWAttr_MOO))
		goto out_parent; /* success */

	err = au_pin(&pin, dentry, cpg.bsrc, udba,
		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
	if (unlikely(err))
		goto out_parent;

	h_path.mnt = au_br_mnt(br);
	h_path.dentry = au_h_dptr(dentry, cpg.bsrc);
	hdir = au_hi(parent->d_inode, cpg.bsrc);
	delegated = NULL;
	err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1);
	au_unpin(&pin);
	/* todo: keep h_dentry or not? */
	if (unlikely(err == -EWOULDBLOCK)) {
		pr_warn("cannot retry for NFSv4 delegation"
			" for an internal unlink\n");
		iput(delegated);
	}
	if (unlikely(err)) {
		pr_err("unlink %pd after coo failed (%d), ignored\n",
		       dentry, err);
		err = 0;
	}
	goto out_parent; /* success */

out_dgrade:
	di_downgrade_lock(parent, AuLock_IR);
out_parent:
	di_read_unlock(parent, AuLock_IR);
	dput(parent);
out:
	AuTraceErr(err);
	return err;
}

int au_do_open(struct file *file, struct au_do_open_args *args)
{
	int err, no_lock = args->no_lock;
	struct dentry *dentry;
	struct au_finfo *finfo;

	if (!no_lock)
		err = au_finfo_init(file, args->fidir);
	else {
		lockdep_off();
		err = au_finfo_init(file, args->fidir);
		lockdep_on();
	}
	if (unlikely(err))
		goto out;

	dentry = file->f_dentry;
	AuDebugOn(IS_ERR_OR_NULL(dentry));
	if (!no_lock) {
		di_write_lock_child(dentry);
		err = au_cmoo(dentry);
		di_downgrade_lock(dentry, AuLock_IR);
		if (!err)
			err = args->open(file, vfsub_file_flags(file), NULL);
		di_read_unlock(dentry, AuLock_IR);
	} else {
		err = au_cmoo(dentry);
		if (!err)
			err = args->open(file, vfsub_file_flags(file),
					 args->h_file);
		if (!err && au_fbstart(file) != au_dbstart(dentry))
			/*
			 * cmoo happens after h_file was opened.
			 * need to refresh file later.
			 */
			atomic_dec(&au_fi(file)->fi_generation);
	}

	finfo = au_fi(file);
	if (!err) {
		finfo->fi_file = file;
		au_sphl_add(&finfo->fi_hlist,
			    &au_sbi(file->f_dentry->d_sb)->si_files);
	}
	if (!no_lock)
		fi_write_unlock(file);
	else {
		lockdep_off();
		fi_write_unlock(file);
		lockdep_on();
	}
	if (unlikely(err)) {
		finfo->fi_hdir = NULL;
		au_finfo_fin(file);
	}

out:
	return err;
}
Example #29
0
/*
 * access() needs to use the real uid/gid, not the effective uid/gid.
 * We do this by temporarily clearing all FS-related capabilities and
 * switching the fsuid/fsgid around to the real ones.
 */
SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
{
	const struct cred *old_cred;
	struct cred *override_cred;
	struct path path;
	struct inode *inode;
	int res;
	unsigned int lookup_flags = LOOKUP_FOLLOW;

	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */
		return -EINVAL;

	override_cred = prepare_creds();
	if (!override_cred)
		return -ENOMEM;

	override_cred->fsuid = override_cred->uid;
	override_cred->fsgid = override_cred->gid;

	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
		/* Clear the capabilities if we switch to a non-root user */
		kuid_t root_uid = make_kuid(override_cred->user_ns, 0);
		if (!uid_eq(override_cred->uid, root_uid))
			cap_clear(override_cred->cap_effective);
		else
			override_cred->cap_effective =
				override_cred->cap_permitted;
	}

	old_cred = override_creds(override_cred);
retry:
	res = user_path_at(dfd, filename, lookup_flags, &path);
	if (res)
		goto out;

	inode = path.dentry->d_inode;

	if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
		/*
		 * MAY_EXEC on regular files is denied if the fs is mounted
		 * with the "noexec" flag.
		 */
		res = -EACCES;
		if (path.mnt->mnt_flags & MNT_NOEXEC)
			goto out_path_release;
	}

	res = inode_permission(inode, mode | MAY_ACCESS);
	/* SuS v2 requires we report a read only fs too */
	if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
		goto out_path_release;
	/*
	 * This is a rare case where using __mnt_is_readonly()
	 * is OK without a mnt_want/drop_write() pair.  Since
	 * no actual write to the fs is performed here, we do
	 * not need to telegraph to that to anyone.
	 *
	 * By doing this, we accept that this access is
	 * inherently racy and know that the fs may change
	 * state before we even see this result.
	 */
	if (__mnt_is_readonly(path.mnt))
		res = -EROFS;

out_path_release:
	path_put(&path);
	if (retry_estale(res, lookup_flags)) {
		lookup_flags |= LOOKUP_REVAL;
		goto retry;
	}
out:
	revert_creds(old_cred);
	put_cred(override_cred);
	return res;
}
bool sieve_binary_file_open
(struct sieve_binary_file *file,
	struct sieve_instance *svinst, const char *path, enum sieve_error *error_r)
{
	int fd;
	bool result = TRUE;
	struct stat st;

	if ( error_r != NULL )
		*error_r = SIEVE_ERROR_NONE;

	if ( (fd=open(path, O_RDONLY)) < 0 ) {
		switch ( errno ) {
		case ENOENT:
			if ( error_r != NULL )
				*error_r = SIEVE_ERROR_NOT_FOUND;
			break;
		case EACCES:
			sieve_sys_error(svinst, "binary open: failed to open: %s",
				eacces_error_get("open", path));
			if ( error_r != NULL )
				*error_r = SIEVE_ERROR_NO_PERMISSION;
			break;
		default:
			sieve_sys_error(svinst, "binary open: failed to open: "
				"open(%s) failed: %m", path);
			if ( error_r != NULL )
				*error_r = SIEVE_ERROR_TEMP_FAILURE;
			break;
		}
		return FALSE;
	}

	if ( fstat(fd, &st) < 0 ) {
		if ( errno != ENOENT ) {
			sieve_sys_error(svinst,
				"binary open: fstat(fd=%s) failed: %m", path);
		}
		result = FALSE;
	}

	if ( result && !S_ISREG(st.st_mode) ) {
		sieve_sys_error(svinst,
			"binary open: %s is not a regular file", path);
		result = FALSE;
	}

	if ( !result )	{
		if ( close(fd) < 0 ) {
			sieve_sys_error(svinst,
				"binary open: close(fd=%s) failed after error: %m", path);
		}
		return FALSE;
	}

	file->svinst = svinst;
	file->fd = fd;
	file->st = st;

	return TRUE;
}