Exemplo n.º 1
0
static void skipbytes(struct context *ctx, int cur __attribute__ ((unused)))
{
    off_t ro = ctx->io_offset, off = 0;

    DebugIn(DEBUG_BUFFER);

    sigbus_cur = ctx->cfn;

    if (chunk_get(ctx, NULL)) {
	io_sched_pop(ctx->io, ctx);
	ctx->dbufi = buffer_free_all(ctx->dbufi);
	ctx->remaining = 0, ctx->offset = 0;
	cleanup_file(ctx, ctx->ffn);
	cleanup_data(ctx, ctx->ffn);
	reply(ctx, MSG_451_Internal_error);
    } else {
	if (chunk_remaining(ctx)) {
	    char *u = ctx->chunk_start;
	    char lastchar = ctx->lastchar;
	    size_t len = MIN(ctx->chunk_length, (size_t) bufsize);
	    char *ul = u + len;

	    for (off = 0; ro && u < ul; ro--, off++, lastchar = *u++)
		if (*u == '\n' && lastchar != '\r')
		    ro--;

	    ctx->lastchar = lastchar;
	    chunk_release(ctx, len);
	}

	if (!chunk_remaining(ctx))
	    ro = 0;

	if (!ro) {
	    ctx->dbufi = buffer_free_all(ctx->dbufi);
	    lseek(ctx->ffn, ctx->offset + off, SEEK_SET);
	    ctx->remaining = 0, ctx->offset = 0;

	    if (io_get_cb_i(ctx->io, ctx->dfn) == (void *) socket2buffer) {
		/* already connected */
		io_clr_o(ctx->io, ctx->dfn);
		io_set_i(ctx->io, ctx->dfn);
	    }
	    io_sched_pop(ctx->io, ctx);
	} else
	    io_sched_renew_proc(ctx->io, ctx, (void *) skipbytes);

	ctx->io_offset = ro;
    }

    DebugOut(DEBUG_BUFFER);
}
Exemplo n.º 2
0
static void catchbus(int sig __attribute__ ((unused)))
{
    struct context *ctx;
    if (sigbus_cur > -1 && (ctx = io_get_ctx(ctx_spawnd->io, sigbus_cur))) {
	logmsg("catched SIGBUS (%s)", ctx->filename);
	ctx->dbuf = buffer_free_all(ctx->dbuf);
	ctx->dbufi = buffer_free_all(ctx->dbufi);
	ctx->chunk_start = NULL;
	ctx->chunk_length = 0;
	ctx->remaining = 0;
	cleanup_file(ctx, sigbus_cur);
	if (ctx->dfn > -1) {
	    reply(ctx, MSG_451_Transfer_incomplete);
	    cleanup_data(ctx, ctx->dfn);
	}
    }
    signal(SIGBUS, catchbus);
    longjmp(sigbus_jmpbuf, 1);
}
Exemplo n.º 3
0
iface_t *init_file (iface_t *ifa)
{
    struct if_file *ifc;
    struct kopts *opt;
    struct stat statbuf;
    int append=0;

    if ((ifc = (struct if_file *)malloc(sizeof(struct if_file))) == NULL) {
        logerr(errno,"Could not allocate memory");
        return(NULL);
    }

    memset ((void *)ifc,0,sizeof(struct if_file));

    ifc->qsize=DEFFILEQSIZE;
    ifa->info = (void *) ifc;

    for(opt=ifa->options;opt;opt=opt->next) {
        if (!strcasecmp(opt->var,"filename")) {
            if (strcmp(opt->val,"-"))
                if ((ifc->filename=strdup(opt->val)) == NULL) {
                    logerr(errno,"Failed to duplicate argument string");
                    return(NULL);
                }
        } else if (!strcasecmp(opt->var,"qsize")) {
            if (!(ifc->qsize=atoi(opt->val))) {
                logerr(0,"Invalid queue size specified: %s",opt->val);
                return(NULL);
            }
        } else if (!strcasecmp(opt->var,"append")) {
            if (!strcasecmp(opt->val,"yes")) {
                append++;
            } else if (!strcasecmp(opt->val,"no")) {
                append = 0;
            } else {
                logerr(0,"Invalid option \"append=%s\"",opt->val);
                return(NULL);
            }
        } else if (!strcasecmp(opt->var,"eol")) {
            if (!strcasecmp(opt->val,"rn"))
                ifc->usereturn=1;
            else if (!strcasecmp(opt->val,"n")) {
                ifc->usereturn=0;
            } else {
                logerr(0,"Invalid option \"eol=%s\": Must be \"n\" or \"rn\"",
                        opt->val);
                return(NULL);
            }
        } else {
            logerr(0,"Unknown interface option %s\n",opt->var);
            return(NULL);
        }
    }

    /* We do allow use of stdin and stdout, but not if they're connected to
     * a terminal. This allows re-direction in background mode
     */
    if (ifc->filename == NULL) {
        if (ifa->persist) {
            logerr(0,"Can't use persist mode with stdin/stdout");
            return(NULL);
        }

        if (((ifa->direction != IN) &&
                (((struct if_engine *)ifa->lists->engine->info)->flags &
                K_NOSTDOUT)) ||
                ((ifa->direction != OUT) &&
                (((struct if_engine *)ifa->lists->engine->info)->flags &
                K_NOSTDIN))) {
            logerr(0,"Can't use terminal stdin/stdout in background mode");
            return(NULL);
        }
        ifc->fp = (ifa->direction == IN)?stdin:stdout;
    } else {
        if (ifa->direction == BOTH) {
            logerr(0,"Bi-directional file I/O only supported for stdin/stdout");
            return(NULL);
        }

        if (stat(ifc->filename,&statbuf) < 0) {
            if (ifa->direction != OUT) {
                logerr(errno,"stat %s",ifc->filename);
                return(NULL);
            }
        }

        if (S_ISFIFO(statbuf.st_mode)) {
            /* Special rules for FIFOs. Opening here would hang for a reading
             * interface with no writer. Given that we're single threaded here,
             * that would be bad
             */
            if (access(ifc->filename,(ifa->direction==IN)?R_OK:W_OK) != 0) {
                logerr(errno,"Could not access %s",ifc->filename);
                return(NULL);
            }
        }
        else {
            if (ifa->persist) {
                logerr(0,"Can't use persist mode on %s: Not a FIFO",
                        ifc->filename);
                return(NULL);
            }
            if ((ifc->fp=fopen(ifc->filename,(ifa->direction==IN)?"r":
                    (append)?"a":"w")) == NULL) {
                logerr(errno,"Failed to open %s",ifc->filename);
                return(NULL);
            }
            if (ifa->direction == OUT)
                /* Make output line buffered */
                setlinebuf(ifc->fp);
        }
    }

    free_options(ifa->options);

    ifa->write=write_file;
    ifa->read=read_file;
    ifa->cleanup=cleanup_file;

    if (ifa->direction != IN && ifc->fp != NULL)
        if ((ifa->q =init_q(ifc->qsize)) == NULL) {
            logerr(0,"Could not create queue");
            cleanup_file(ifa);
            return(NULL);
        }

    if (ifa->direction == BOTH) {
        if ((ifa->next=ifdup(ifa)) == NULL) {
            logerr(0,"Interface duplication failed");
            cleanup_file(ifa);
            return(NULL);
        }
        ifa->direction=OUT;
        ifa->pair->direction=IN;
        ifc = (struct if_file *) ifa->pair->info;
        ifc->fp=stdin;
    }
    return(ifa);
}
Exemplo n.º 4
0
iface_t *init_file (iface_t *ifa)
{
    struct if_file *ifc;
    struct kopts *opt;
    struct stat statbuf;
    int ret;
    int append=0;
    uid_t uid=-1;
    gid_t gid=-1;
    struct passwd *owner;
    struct group *group;
    mode_t tperm,perm=0;
    char *cp;

    if ((ifc = (struct if_file *)malloc(sizeof(struct if_file))) == NULL) {
        logerr(errno,"Could not allocate memory");
        return(NULL);
    }

    memset ((void *)ifc,0,sizeof(struct if_file));

    ifc->qsize=DEFFILEQSIZE;
    ifc->fd=-1;
    ifa->info = (void *) ifc;

    for(opt=ifa->options;opt;opt=opt->next) {
        if (!strcasecmp(opt->var,"filename")) {
            if (strcmp(opt->val,"-"))
                if ((ifc->filename=strdup(opt->val)) == NULL) {
                    logerr(errno,"Failed to duplicate argument string");
                    return(NULL);
                }
        } else if (!strcasecmp(opt->var,"qsize")) {
            if (!(ifc->qsize=atoi(opt->val))) {
                logerr(0,"Invalid queue size specified: %s",opt->val);
                return(NULL);
            }
        } else if (!strcasecmp(opt->var,"append")) {
            if (!strcasecmp(opt->val,"yes")) {
                append++;
            } else if (!strcasecmp(opt->val,"no")) {
                append = 0;
            } else {
                logerr(0,"Invalid option \"append=%s\"",opt->val);
                return(NULL);
            }
        } else if (!strcasecmp(opt->var,"owner")) {
            if ((owner=getpwnam(opt->val)) == NULL) {
                logerr(0,"No such user '%s'",opt->val);
                return(NULL);
            }
            uid=owner->pw_uid;
        } else if (!strcasecmp(opt->var,"group")) {
            if ((group=getgrnam(opt->val)) == NULL) {
                logerr(0,"No such group '%s'",opt->val);
                return(NULL);
            }
            gid=group->gr_gid;
        }
        else if (!strcasecmp(opt->var,"perm")) {
            for (cp=opt->val;*cp;cp++) {
                if (*cp >= '0' && *cp < '8') {
                    perm <<=3;
                    perm += (*cp-'0');
                } else {
                    perm = 0;
                    break;
                }
            }
            perm &= ACCESSPERMS;
            if (perm == 0) {
                logerr(0,"Invalid permissions for tty device \'%s\'",opt->val);
                return 0;
            }
        } else {
            logerr(0,"Unknown interface option %s\n",opt->var);
            return(NULL);
        }
    }

    /* We do allow use of stdin and stdout, but not if they're connected to
     * a terminal. This allows re-direction in background mode
     */
    if (ifc->filename == NULL) {
        if (flag_test(ifa,F_PERSIST)) {
            logerr(0,"Can't use persist mode with stdin/stdout");
            return(NULL);
        }

        if (((ifa->direction != IN) &&
                (((struct if_engine *)ifa->lists->engine->info)->flags &
                K_NOSTDOUT)) ||
                ((ifa->direction != OUT) &&
                (((struct if_engine *)ifa->lists->engine->info)->flags &
                K_NOSTDIN))) {
            logerr(0,"Can't use terminal stdin/stdout in background mode");
            return(NULL);
        }
        ifc->fd = (ifa->direction == IN)?STDIN_FILENO:STDOUT_FILENO;
    } else {
        if (ifa->direction == BOTH) {
            logerr(0,"Bi-directional file I/O only supported for stdin/stdout");
            return(NULL);
        }

        if ((ret=stat(ifc->filename,&statbuf)) < 0) {
            if (ifa->direction != OUT) {
                logerr(errno,"stat %s",ifc->filename);
                return(NULL);
            }
        }
        if ((ret == 0) && S_ISFIFO(statbuf.st_mode)) {
            /* Special rules for FIFOs. Opening here would hang for a reading
             * interface with no writer. Given that we're single threaded here,
             * that would be bad
             */
            if (access(ifc->filename,(ifa->direction==IN)?R_OK:W_OK) != 0) {
                logerr(errno,"Could not access %s",ifc->filename);
                return(NULL);
            }
        }
        else {
            if (flag_test(ifa,F_PERSIST)) {
                logerr(0,"Can't use persist mode on %s: Not a FIFO",
                        ifc->filename);
                return(NULL);
            }
            if (perm)
                tperm=umask(0);

            errno=0;
            if (ifa->direction != IN && (ifc->fd=open(ifc->filename,
                        O_WRONLY|O_CREAT|O_EXCL|((append)?O_APPEND:0),
                        (perm)?perm:0664)) >= 0) {
                if (gid != 0 || uid != -1) {
                    if (chown(ifc->filename,uid,gid) < 0) {
                        logerr(errno, "Failed to set ownership or group on output file %s",ifc->filename);
                        return(NULL);
                    }
                }
            } else {
                if (errno && errno != EEXIST) {
                    logerr(errno,"Failed to create file %s",ifc->filename);
                    return(NULL);
                }
                if ((ifc->fd=open(ifc->filename,(ifa->direction==IN)?O_RDONLY:
                        (O_WRONLY|((append)?O_APPEND:O_TRUNC)))) < 0) {
                    logerr(errno,"Failed to open file %s",ifc->filename);
                    return(NULL);
                }
            }
            /* reset umask: not really necessary */
            if (perm)
                (void) umask(tperm);
        }
    }

    free_options(ifa->options);

    ifa->write=write_file;
    ifa->read=file_read_wrapper;
    ifa->readbuf=read_file;
    ifa->cleanup=cleanup_file;

    if (ifa->direction != IN && ifc->fd >= 0)
        if ((ifa->q =init_q(ifc->qsize)) == NULL) {
            logerr(0,"Could not create queue");
            cleanup_file(ifa);
            return(NULL);
        }

    if (ifa->direction == BOTH) {
        if ((ifa->next=ifdup(ifa)) == NULL) {
            logerr(0,"Interface duplication failed");
            cleanup_file(ifa);
            return(NULL);
        }
        ifa->direction=OUT;
        ifa->pair->direction=IN;
        ifc = (struct if_file *) ifa->pair->info;
        ifc->fd=STDIN_FILENO;
    }
    return(ifa);
}
Exemplo n.º 5
0
/*
 * Helper function for unionfs_file_revalidate/locked.
 * Expects dentry/parent to be locked already, and revalidated.
 */
static int __unionfs_file_revalidate(struct file *file, struct dentry *dentry,
				     struct dentry *parent,
				     struct super_block *sb, int sbgen,
				     int dgen, bool willwrite)
{
	int fgen;
	int bstart, bend, orig_brid;
	int size;
	int err = 0;

	fgen = atomic_read(&UNIONFS_F(file)->generation);

	/*
	 * There are two cases we are interested in.  The first is if the
	 * generation is lower than the super-block.  The second is if
	 * someone has copied up this file from underneath us, we also need
	 * to refresh things.
	 */
	if (d_deleted(dentry) ||
	    (sbgen <= fgen &&
	     dbstart(dentry) == fbstart(file) &&
	     unionfs_lower_file(file)))
		goto out_may_copyup;

	/* save orig branch ID */
	orig_brid = UNIONFS_F(file)->saved_branch_ids[fbstart(file)];

	/* First we throw out the existing files. */
	cleanup_file(file);

	/* Now we reopen the file(s) as in unionfs_open. */
	bstart = fbstart(file) = dbstart(dentry);
	bend = fbend(file) = dbend(dentry);

	size = sizeof(struct file *) * sbmax(sb);
	UNIONFS_F(file)->lower_files = kzalloc(size, GFP_KERNEL);
	if (unlikely(!UNIONFS_F(file)->lower_files)) {
		err = -ENOMEM;
		goto out;
	}
	size = sizeof(int) * sbmax(sb);
	UNIONFS_F(file)->saved_branch_ids = kzalloc(size, GFP_KERNEL);
	if (unlikely(!UNIONFS_F(file)->saved_branch_ids)) {
		err = -ENOMEM;
		goto out;
	}

	if (S_ISDIR(dentry->d_inode->i_mode)) {
		/* We need to open all the files. */
		err = open_all_files(file);
		if (err)
			goto out;
	} else {
		int new_brid;
		/* We only open the highest priority branch. */
		err = open_highest_file(file, willwrite);
		if (err)
			goto out;
		new_brid = UNIONFS_F(file)->saved_branch_ids[fbstart(file)];
		if (unlikely(new_brid != orig_brid && sbgen > fgen)) {
			/*
			 * If we re-opened the file on a different branch
			 * than the original one, and this was due to a new
			 * branch inserted, then update the mnt counts of
			 * the old and new branches accordingly.
			 */
			unionfs_mntget(dentry, bstart);
			unionfs_mntput(sb->s_root,
				       branch_id_to_idx(sb, orig_brid));
		}
		/* regular files have only one open lower file */
		fbend(file) = fbstart(file);
	}
	atomic_set(&UNIONFS_F(file)->generation,
		   atomic_read(&UNIONFS_I(dentry->d_inode)->generation));

out_may_copyup:
	/* Copyup on the first write to a file on a readonly branch. */
	if (willwrite && IS_WRITE_FLAG(file->f_flags) &&
	    !IS_WRITE_FLAG(unionfs_lower_file(file)->f_flags) &&
	    is_robranch(dentry)) {
		pr_debug("unionfs: do delay copyup of \"%s\"\n",
			 dentry->d_name.name);
		err = do_delayed_copyup(file, parent);
		/* regular files have only one open lower file */
		if (!err && !S_ISDIR(dentry->d_inode->i_mode))
			fbend(file) = fbstart(file);
	}

out:
	if (err) {
		kfree(UNIONFS_F(file)->lower_files);
		kfree(UNIONFS_F(file)->saved_branch_ids);
	}
	return err;
}