Example #1
0
int do_restore_client_burp1(struct asfd *asfd,
                            struct conf *conf, enum action act, int vss_restore)
{
    int ars=0;
    int ret=-1;
    char msg[512]="";
    struct sbuf *sb=NULL;
// Windows needs to have the VSS data written first, and the actual data
// written immediately afterwards. The server is transferring them in two
// chunks. So, leave bfd open after a Windows metadata transfer.
    BFILE bfd;
#ifdef HAVE_WIN32
    binit(&bfd, 0, conf);
#endif

    logp("doing %s\n", act_str(act));

    snprintf(msg, sizeof(msg), "%s %s:%s", act_str(act),
             conf->backup?conf->backup:"", conf->regex?conf->regex:"");
    if(asfd->write_str(asfd, CMD_GEN, msg)
            || asfd->read_expect(asfd, CMD_GEN, "ok"))
        return -1;
    logp("doing %s confirmed\n", act_str(act));

    if(conf->send_client_cntr)
    {
// FIX THIS
//		if(cntr_recv(conf)) goto end;
    }

#if defined(HAVE_WIN32)
    if(act==ACTION_RESTORE) win32_enable_backup_privileges();
#endif

    if(!(sb=sbuf_alloc(conf))) goto end;
    while(1)
    {
        char *fullpath=NULL;

        sbuf_free_content(sb);
        if((ars=sbufl_fill(sb, asfd, NULL, NULL, conf->cntr)))
        {
            if(ars<0) goto end;
            else
            {
                // ars==1 means it ended ok.
                //logp("got %s end\n", act_str(act));
                if(asfd->write_str(asfd,
                                   CMD_GEN, "restoreend ok")) goto end;
            }
            break;
        }

        switch(sb->path.cmd)
        {
        case CMD_DIRECTORY:
        case CMD_FILE:
        case CMD_ENC_FILE:
        case CMD_SOFT_LINK:
        case CMD_HARD_LINK:
        case CMD_SPECIAL:
        case CMD_METADATA:
        case CMD_ENC_METADATA:
        case CMD_VSS:
        case CMD_ENC_VSS:
        case CMD_VSS_T:
        case CMD_ENC_VSS_T:
        case CMD_EFS_FILE:
            if(conf->strip)
            {
                int s;
                s=strip_path_components(asfd, sb,
                                        &(sb->path.buf), conf);
                if(s<0) goto end; // error
                else if(s==0)
                {
                    // Too many components stripped
                    // - carry on.
                    continue;
                }
                // It is OK, sb->path is now stripped.
            }
            if(!(fullpath=prepend_s(conf->restoreprefix,
                                    sb->path.buf)))
            {
                log_and_send_oom(asfd, __func__);
                goto end;
            }
            if(act==ACTION_RESTORE)
            {
                strip_invalid_characters(&fullpath);
                if(!overwrite_ok(sb, conf, &bfd, fullpath))
                {
                    char msg[512]="";
                    // Something exists at that path.
                    snprintf(msg, sizeof(msg),
                             "Path exists: %s", fullpath);
                    if(restore_interrupt(asfd, sb, msg, conf))
                        goto end;
                    else
                    {
                        if(fullpath) free(fullpath);
                        continue;
                    }
                }
            }
            break;
        default:
            break;
        }

        switch(sb->path.cmd)
        {
        case CMD_WARNING:
            cntr_add(conf->cntr, sb->path.cmd, 1);
            printf("\n");
            logp("%s", sb->path);
            break;
        case CMD_DIRECTORY:
            if(restore_dir(asfd, sb, fullpath, act, conf))
                goto end;
            break;
        case CMD_FILE:
        case CMD_VSS_T:
            // Have it a separate statement to the
            // encrypted version so that encrypted and not
            // encrypted files can be restored at the
            // same time.
            if(restore_file_or_get_meta(asfd, &bfd, sb,
                                        fullpath, act,
                                        NULL, NULL, NULL,
                                        vss_restore, conf))
            {
                logp("restore_file error\n");
                goto end;
            }
            break;
        case CMD_ENC_FILE:
        case CMD_ENC_VSS_T:
            if(restore_file_or_get_meta(asfd, &bfd, sb,
                                        fullpath, act,
                                        conf->encryption_password,
                                        NULL, NULL, vss_restore, conf))
            {
                logp("restore_file error\n");
                goto end;
            }
            break;
        case CMD_SOFT_LINK:
        case CMD_HARD_LINK:
            if(restore_link(asfd, sb, fullpath,
                            conf->restoreprefix, act, conf))
                goto end;
            break;
        case CMD_SPECIAL:
            if(restore_special(asfd, sb, fullpath, act, conf))
                goto end;
            break;
        case CMD_METADATA:
        case CMD_VSS:
            if(restore_metadata(asfd, &bfd, sb, fullpath,
                                act, NULL, vss_restore, conf))
                goto end;
            break;
        case CMD_ENC_METADATA:
        case CMD_ENC_VSS:
            if(restore_metadata(asfd, &bfd, sb, fullpath,
                                act, conf->encryption_password,
                                vss_restore, conf))
                goto end;
            break;
        case CMD_EFS_FILE:
            if(restore_file_or_get_meta(asfd, &bfd, sb,
                                        fullpath, act,
                                        NULL, NULL, NULL, vss_restore, conf))
            {
                logp("restore_file error\n");
                goto end;
            }
            break;
        default:
            logp("unknown cmd: %c\n", sb->path.cmd);
            goto end;
            break;
        }

        if(fullpath) free(fullpath);
    }

    ret=0;
end:
    sbuf_free(sb);

#ifdef HAVE_WIN32
    // It is possible for a bfd to still be open.
    bclose(&bfd, asfd);
#endif

    cntr_print_end(conf->cntr);
    cntr_print(conf->cntr, act);

    if(!ret) logp("%s finished\n", act_str(act));
    else logp("ret: %d\n", ret);

    return ret;
}
Example #2
0
AROS_UFH3(void, packet_reply,
          AROS_UFHA(struct ph_mount *, mount,     A1),
          AROS_UFHA(APTR,              dummy,   A5),
          AROS_UFHA(struct ExecBase *, SysBase, A6)) {   

    AROS_USERFUNC_INIT

    struct DosPacket *dp;
    struct ph_packet *pkt;
    struct IOFileSys *iofs;
    struct ph_handle *handle;

    /* retrieve the message and fish the packet out */
    dp = (struct DosPacket *) GetMsg(&(mount->reply_port))->mn_Node.ln_Name;
    pkt = (struct ph_packet *) dp->dp_Link;

    D(bug("[packet] got reply packet %d (%s)\n", dp->dp_Type, act_str(dp->dp_Type)));

    /* get the iofs back */
    iofs = (struct IOFileSys *) dp->dp_Arg7;

    /* dos error code comes back in Res2 */
    if (dp->dp_Res1 == DOSFALSE) {
        iofs->io_DosError = dp->dp_Res2;

        /* do any cleanup from the request (eg freeing memory) */
        switch (dp->dp_Type) {
            case ACTION_FINDINPUT:
            case ACTION_FINDOUTPUT:
            case ACTION_FINDUPDATE:
                FreeMem((APTR) BADDR(dp->dp_Arg1), sizeof(struct ph_handle));
                break;

            case ACTION_SAME_LOCK:
                /* DOSFALSE & no error means the locks are different */
                if (iofs->io_DosError == 0)
                    iofs->io_Union.io_SAME_LOCK.io_Same = LOCK_DIFFERENT;
                break;

            case ACTION_PARENT:
                /* no error means they tried to go up past the root. The
                 * packet system allows this, IOFS does not */
                if (iofs->io_DosError == 0)
                    iofs->io_DosError = ERROR_OBJECT_NOT_FOUND;
                break;

            /* a zero result is not an error for the following three packet
             * types. We shouldn't really be here */
            case ACTION_SEEK:
                iofs->io_Union.io_SEEK.io_Offset = dp->dp_Res1;
                iofs->io_DosError = 0;
                break;
            case ACTION_READ:
        	iofs->io_Union.io_READ.io_Length = dp->dp_Res1; 
        	iofs->io_DosError = 0;
        	break;
            case ACTION_SET_FILE_SIZE:
                iofs->io_DosError = 0;
                break;
        }

        /* kill the packet */
        DeletePool(pkt->pool);

        D(bug("[packet] returning error %ld\n", iofs->io_DosError));

        /* and tell them */
        ReplyMsg((APTR) iofs);

        return;
    }

    /* no error */
    iofs->io_DosError = 0;
    
    /* populate the iofs with the results. note that for packets that only
     * return success/failure we have nothing to do, so they're not listed
     * here */
    switch (dp->dp_Type) {

        case ACTION_COPY_DIR:
        case ACTION_COPY_DIR_FH:
        case ACTION_LOCATE_OBJECT:
        case ACTION_PARENT:
        case ACTION_PARENT_FH:
            handle = (struct ph_handle *) AllocMem(sizeof(struct ph_handle), MEMF_PUBLIC | MEMF_CLEAR);
            if (handle == NULL) {
                iofs->io_DosError = ERROR_NO_FREE_STORE;
                break;
            }

            /* we'll need the lock they gave us for future operations */
            handle->actual = (void *) dp->dp_Res1;
            handle->is_lock = TRUE;
            handle->mount = mount;

            iofs->IOFS.io_Unit = (struct Unit *) handle;

            break;

        case ACTION_FINDINPUT:
        case ACTION_FINDOUTPUT:
        case ACTION_FINDUPDATE: {
            /* handlers return "internal data" (typically a lock, though we
             * can't assume that) in fh_Arg1. we need to keep it for later
             * filehandle operations.
             * the calls that need this data (e.g. ACTION_READ/WRITE/SEEK)
             * take it directly in dp_Arg1 */
            handle = (struct ph_handle *) BADDR(dp->dp_Arg1);
            handle->actual = (void *) handle->fh.fh_Arg1;
            handle->is_lock = FALSE;
            handle->mount = mount;

            iofs->IOFS.io_Unit = (struct Unit *) handle;

            break;
        }

        case ACTION_FREE_LOCK:
        case ACTION_END:
            /* free up our data */
            handle = (struct ph_handle *) iofs->IOFS.io_Unit;
            FreeMem((APTR) handle, sizeof(struct ph_handle));
            iofs->IOFS.io_Unit = NULL;
            break;

        case ACTION_READ:
            if (dp->dp_Res1 == -1)
        	iofs->io_DosError = dp->dp_Res2;
            iofs->io_Union.io_READ.io_Length = dp->dp_Res1;
            break;

        case ACTION_WRITE:
            iofs->io_Union.io_WRITE.io_Length = dp->dp_Res1;
            break;

        case ACTION_SEEK:
            if (dp->dp_Res1 == -1)
                iofs->io_DosError = dp->dp_Res2;
            else
                iofs->io_Union.io_SEEK.io_Offset = dp->dp_Res1;
            break;

        case ACTION_SET_FILE_SIZE:
            if (dp->dp_Res1 == -1)
                iofs->io_DosError = dp->dp_Res2;
            break;

        case ACTION_SAME_LOCK:
            iofs->io_Union.io_SAME_LOCK.io_Same = LOCK_SAME;
            break;

        case ACTION_EXAMINE_OBJECT:
        case ACTION_EXAMINE_FH: {
            struct FileInfoBlock *fib = (struct FileInfoBlock *) BADDR(dp->dp_Arg2);
            struct ExAllData *ead = iofs->io_Union.io_EXAMINE.io_ead;
            ULONG size = iofs->io_Union.io_EXAMINE.io_Size;
            ULONG mode = iofs->io_Union.io_EXAMINE.io_Mode;
            ULONG comment_len = 0, filename_len = 0;

            iofs->io_DirPos = fib->fib_DiskKey;

            /* make sure we have enough room for everything that came back */
            if (size < sizeof(struct ExAllData) +
                       (mode >= ED_COMMENT ? (comment_len = fib->fib_Comment[0]) : 0) +
                       (mode >= ED_NAME    ? (filename_len = fib->fib_FileName[0]) : 0)) {
                iofs->io_DosError = ERROR_BUFFER_OVERFLOW;
                FreeMem(fib, sizeof(struct FileInfoBlock));
                break;
            }

            /* copy stuff from the fib to the ead */
            switch (mode) {
                case ED_OWNER:
                    ead->ed_OwnerUID = fib->fib_OwnerUID;
                    ead->ed_OwnerGID = fib->fib_OwnerGID;

                case ED_COMMENT:
                    /* store the comment in the spare space after the ead and
                     * the filename */
                    ead->ed_Comment = (UBYTE *) ead + sizeof(struct ExAllData) + filename_len + 1;
                    strcpy(ead->ed_Comment,
                        mkcstr(pkt->pool, fib->fib_Comment));

                case ED_DATE:
                    ead->ed_Days = fib->fib_Date.ds_Days;
                    ead->ed_Mins = fib->fib_Date.ds_Minute;
                    ead->ed_Ticks = fib->fib_Date.ds_Tick;

                case ED_PROTECTION:
                    ead->ed_Prot = fib->fib_Protection;
                    
                case ED_SIZE:
                    ead->ed_Size = fib->fib_Size;

                case ED_TYPE:
                    ead->ed_Type = fib->fib_EntryType;

                case ED_NAME:
                    /* store the name in the spare space after the ead */
                    ead->ed_Name = (UBYTE *) ead + sizeof(struct ExAllData);
                    strcpy(ead->ed_Name, mkcstr(pkt->pool, fib->fib_FileName));
               
                case 0:
                    ead->ed_Next = NULL;
                    break;

                default:
                    iofs->io_DosError = ERROR_BAD_NUMBER;
                    break;
            }

            FreeMem(fib, sizeof(struct FileInfoBlock));

            break;
        }

        case ACTION_EXAMINE_NEXT: {
            struct FileInfoBlock *fib = iofs->io_Union.io_EXAMINE_NEXT.io_fib;
            strcpy(fib->fib_FileName, mkcstr(pkt->pool, fib->fib_FileName));
            strcpy(fib->fib_Comment, mkcstr(pkt->pool, fib->fib_Comment));
            break;
        }

        case ACTION_IS_FILESYSTEM:
            iofs->io_Union.io_IS_FILESYSTEM.io_IsFilesystem = TRUE;
            break;

        case ACTION_CREATE_DIR:
            handle = (struct ph_handle *) AllocMem(sizeof(struct ph_handle), MEMF_PUBLIC | MEMF_CLEAR);
            if (handle == NULL) {
                iofs->io_DosError = ERROR_NO_FREE_STORE;
                break;
            }

            /* we'll need the lock they gave us for future operations */
            handle->actual = (void *) dp->dp_Res1;
            handle->is_lock = TRUE;
            handle->mount = mount;

            iofs->IOFS.io_Unit = (struct Unit *) handle;

            break;

        case ACTION_READ_LINK:
            iofs->io_Union.io_READ_SOFTLINK.io_Size = dp->dp_Res1;
            iofs->io_DosError = dp->dp_Res1 < 0 ? dp->dp_Res2 : 0;
            break;

        case ACTION_MORE_CACHE:
            iofs->io_Union.io_MORE_CACHE.io_NumBuffers = dp->dp_Res1;
    }

    /* done with the packet */
    DeletePool(pkt->pool);

    /* send it back */
    ReplyMsg((APTR) iofs);

    AROS_USERFUNC_EXIT
}
Example #3
0
int do_restore_client(struct asfd *asfd,
	struct conf **confs, enum action act, int vss_restore)
{
	int ret=-1;
	char msg[512]="";
	struct sbuf *sb=NULL;
	struct blk *blk=NULL;
	BFILE *bfd=NULL;
	char *fullpath=NULL;
	char *style=NULL;
	char *datpath=NULL;
	struct cntr *cntr=get_cntr(confs);
	enum protocol protocol=get_protocol(confs);
	int strip=get_int(confs[OPT_STRIP]);
	int overwrite=get_int(confs[OPT_OVERWRITE]);
	const char *backup=get_string(confs[OPT_BACKUP]);
	const char *regex=get_string(confs[OPT_REGEX]);
	const char *restore_prefix=get_string(confs[OPT_RESTOREPREFIX]);
	const char *encryption_password=get_string(confs[OPT_ENCRYPTION_PASSWORD]);

	if(!(bfd=bfile_alloc())) goto end;

	bfile_init(bfd, 0, cntr);

	snprintf(msg, sizeof(msg), "%s %s:%s", act_str(act),
		backup?backup:"", regex?regex:"");
	logp("doing %s\n", msg);
	if(asfd->write_str(asfd, CMD_GEN, msg)
	  || asfd_read_expect(asfd, CMD_GEN, "ok"))
		goto error;
	logp("doing %s confirmed\n", act_str(act));

#if defined(HAVE_WIN32)
	if(act==ACTION_RESTORE) win32_enable_backup_privileges();
#endif

	if(!(style=get_restore_style(asfd, confs)))
		goto error;
	if(!strcmp(style, RESTORE_SPOOL))
	{
		if(restore_spool(asfd, confs, &datpath))
			goto error;
	}
	else
		logp("Streaming restore direct\n");

	logf("\n");

	if(get_int(confs[OPT_SEND_CLIENT_CNTR]) && cntr_recv(asfd, confs))
		goto error;

	if(!(sb=sbuf_alloc(protocol))
	  || (protocol==PROTO_2 && !(blk=blk_alloc())))
	{
		log_and_send_oom(asfd, __func__);
		goto error;
	}

	while(1)
	{
		sbuf_free_content(sb);
		if(protocol==PROTO_1)
			sb->flags |= SBUF_CLIENT_RESTORE_HACK;

		switch(sbuf_fill_from_net(sb, asfd, blk, datpath, cntr))
		{
			case 0: break;
			case 1: if(asfd->write_str(asfd, CMD_GEN,
				"restoreend ok")) goto error;
				goto end; // It was OK.
			default:
			case -1: goto error;
		}

		if(protocol==PROTO_2)
		{
			if(blk->data)
			{
				int wret=0;
				if(act==ACTION_VERIFY)
					cntr_add(cntr, CMD_DATA, 1);
				else
					wret=write_data(asfd, bfd, blk);
				if(!datpath) blk_free_content(blk);
				blk->data=NULL;
				if(wret) goto error;
				continue;
			}
			else if(sb->endfile.buf)
			{
				continue;
			}
		}

		switch(sb->path.cmd)
		{
			case CMD_DIRECTORY:
			case CMD_FILE:
			case CMD_ENC_FILE:
			case CMD_SOFT_LINK:
			case CMD_HARD_LINK:
			case CMD_SPECIAL:
			case CMD_METADATA:
			case CMD_ENC_METADATA:
			case CMD_VSS:
			case CMD_ENC_VSS:
			case CMD_VSS_T:
			case CMD_ENC_VSS_T:
			case CMD_EFS_FILE:
				if(strip)
				{
					int s;
					s=strip_path_components(asfd,
						sb, strip, cntr, protocol);
					if(s<0) goto error;
					if(s==0)
					{
						// Too many components stripped
						// - carry on.
						continue;
					}
					// It is OK, sb.path is now stripped.
				}
				free_w(&fullpath);
				if(!(fullpath=prepend_s(restore_prefix,
					sb->path.buf)))
				{
					log_and_send_oom(asfd, __func__);
					goto error;
				}
				if(act==ACTION_RESTORE)
				{
				  strip_invalid_characters(&fullpath);
				  if(!overwrite_ok(sb, overwrite,
#ifdef HAVE_WIN32
					bfd,
#endif
					fullpath))
				  {
					char msg[512]="";
					// Something exists at that path.
					snprintf(msg, sizeof(msg),
						"Path exists: %s\n", fullpath);
					if(restore_interrupt(asfd,
						sb, msg, cntr, protocol))
							goto error;
					continue;
				  }
				}
				break;
			case CMD_MESSAGE:
			case CMD_WARNING:
				log_recvd(&sb->path, cntr, 1);
				logf("\n");
				continue;
			default:
				break;
		}

		switch(sb->path.cmd)
		{
			// These are the same in both protocol1 and protocol2.
			case CMD_DIRECTORY:
				if(restore_dir(asfd, sb, fullpath, act, cntr,
					protocol))
						goto error;
				continue;
			case CMD_SOFT_LINK:
			case CMD_HARD_LINK:
				if(restore_link(asfd, sb, fullpath, act, cntr,
					protocol, restore_prefix))
						goto error;
				continue;
			case CMD_SPECIAL:
				if(restore_special(asfd, sb,
					fullpath, act, cntr, protocol))
						goto error;
				continue;
			default:
				break;
		}

		if(protocol==PROTO_2)
		{
			if(restore_switch_protocol2(asfd, sb, fullpath, act,
				bfd, vss_restore, cntr))
					goto error;
		}
		else
		{
			if(restore_switch_protocol1(asfd, sb, fullpath, act,
				bfd, vss_restore, cntr, encryption_password))
					goto error;
		}
	}

end:
	ret=0;
error:
	// It is possible for a fd to still be open.
	bfd->close(bfd, asfd);
	bfile_free(&bfd);

	cntr_print_end(cntr);
	cntr_print(cntr, act);

	if(!ret) logp("%s finished\n", act_str(act));
	else logp("ret: %d\n", ret);

	sbuf_free(&sb);
	free_w(&style);
	if(datpath)
	{
		recursive_delete(datpath);
		free_w(&datpath);
	}
	free_w(&fullpath);
	blk_free(&blk);

	return ret;
}
Example #4
0
void packet_handle_request(struct IOFileSys *iofs, struct PacketBase *PacketBase) {
    struct ph_handle *handle;
    struct ph_packet *pkt;
    struct DosPacket *dp;

    D(bug("[packet] got io request %d (%s)\n", iofs->IOFS.io_Command, fsa_str(iofs->IOFS.io_Command)));

    /* get our data back */
    handle = (struct ph_handle *) iofs->IOFS.io_Unit;

    /* make a fresh new packet */
    pkt = packet_alloc();
    dp = &(pkt->dp);

    /* hook the iofs up to the packet so we can find it on return
     * dp_Arg7 should be unused; DoPkt() doesn't touch it */
    dp->dp_Arg7 = (IPTR) iofs;

    /* our reply port will cause packet_reply() to be called when they reply */
    dp->dp_Port = &(handle->mount->reply_port);

    /* convert the command */
    switch (iofs->IOFS.io_Command) {

        case FSA_OPEN:
            D(bug("[packet] OPEN: lock 0x%08x (%s) name '%s' type %s\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_OPEN.io_Filename,
                (iofs->io_Union.io_OPEN.io_FileMode & FMF_LOCK) ? "EXCLUSIVE" : "SHARED"));

            if (!handle->is_lock) {
                /* If passed a filehandle, we can only deal with locking the
                 * filehandle itself or its parent (unless we were to resort
                 * to sending multiple packets)
                 */
                if (iofs->io_Union.io_OPEN.io_Filename[0] == '\0') {
                    dp->dp_Type = ACTION_COPY_DIR_FH;
                    dp->dp_Arg1 = (IPTR) handle->actual;
                }
                else if (iofs->io_Union.io_OPEN.io_Filename[0] == '/' &&
                    iofs->io_Union.io_OPEN.io_Filename[1] == '\0') {
                    dp->dp_Type = ACTION_PARENT_FH;
                    dp->dp_Arg1 = (IPTR) handle->actual;
                }
                else {
                    iofs->io_DosError = ERROR_NOT_IMPLEMENTED;
                    goto reply;
                }
            }
            else {
                dp->dp_Type = ACTION_LOCATE_OBJECT;
                dp->dp_Arg1 = (IPTR) handle->actual;
                dp->dp_Arg2 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_OPEN.io_Filename);
                dp->dp_Arg3 = (iofs->io_Union.io_OPEN.io_FileMode & FMF_LOCK) ? EXCLUSIVE_LOCK : SHARED_LOCK;
            }

            break;

        case FSA_OPEN_FILE: {
            ULONG mode = iofs->io_Union.io_OPEN_FILE.io_FileMode;
            struct ph_handle *new_handle;

            D(bug("[packet] OPEN_FILE: lock 0x%08x (%s) name '%s' mode 0x%x prot 0x%x\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_OPEN_FILE.io_Filename,
                mode,
                iofs->io_Union.io_OPEN_FILE.io_Protection));

            /* convert modes to the proper packet type (as best we can) */
            if ((mode & FMF_CLEAR) != 0)
                dp->dp_Type = ACTION_FINDOUTPUT;
            else if ((mode & FMF_CREATE) != 0)
                dp->dp_Type = ACTION_FINDUPDATE;
            else
                dp->dp_Type = ACTION_FINDINPUT;
            if ((mode & FMF_APPEND) != 0) {
                iofs->io_DosError = ERROR_BAD_NUMBER;
                goto reply;
            }

            /* make a new handle */
            new_handle =
                (struct ph_handle *) AllocMem(sizeof(struct ph_handle),
                MEMF_PUBLIC | MEMF_CLEAR);
            if (new_handle == NULL) {
                iofs->io_DosError = ERROR_NO_FREE_STORE;
                goto reply;
            }

            /* dos.lib buffer stuff, must be initialised this way */
            new_handle->fh.fh_Pos = new_handle->fh.fh_End = (UBYTE *) -1;

            dp->dp_Arg1 = (IPTR) MKBADDR(&new_handle->fh);
            dp->dp_Arg2 = (IPTR) (handle->is_lock ? handle->actual : NULL);
            dp->dp_Arg3 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_OPEN.io_Filename);

            break;
        }

        case FSA_CLOSE:
            D(bug("[packet] CLOSE: lock 0x%08x (%s)\n",
                handle->actual, handle_desc(handle)));

            /* if this is the root handle, then we previously intercepted a
             * call and returned it (e.g. FSA_OPEN/ACTION_PARENT), so we don't
             * want the handler to do anything */
            if (handle == &(handle->mount->root_handle)) {
                iofs->IOFS.io_Unit = NULL;
                goto reply;
            }

            dp->dp_Type = (handle->is_lock) ? ACTION_FREE_LOCK : ACTION_END;
            dp->dp_Arg1 = (IPTR) handle->actual;
            break;

        case FSA_READ:
            D(bug("[packet] READ: handle 0x%08x buf 0x%08x len %ld\n",
                handle->actual,
                iofs->io_Union.io_READ.io_Buffer,
                iofs->io_Union.io_READ.io_Length));

            dp->dp_Type = ACTION_READ;
            dp->dp_Arg1 = (IPTR) handle->actual;
            dp->dp_Arg2 = (IPTR) iofs->io_Union.io_READ.io_Buffer;
            dp->dp_Arg3 = (IPTR) iofs->io_Union.io_READ.io_Length;

            /* DOSFALSE == 0, so we can't distinguish between a zero-length
             * read and an actual error. So, we reset the length here. If the
             * returned packet is DOSFALSE, but no error, this will make sure
             * DOS gets the right length back */
            iofs->io_Union.io_READ.io_Length = 0;
            break;

        case FSA_WRITE:
            D(bug("[packet] WRITE: handle 0x%08x buf 0x%08x len %ld\n",
                handle->actual,
                iofs->io_Union.io_WRITE.io_Buffer,
                iofs->io_Union.io_WRITE.io_Length));

            dp->dp_Type = ACTION_WRITE;
            dp->dp_Arg1 = (IPTR) handle->actual;
            dp->dp_Arg2 = (IPTR) iofs->io_Union.io_WRITE.io_Buffer;
            dp->dp_Arg3 = (IPTR) iofs->io_Union.io_WRITE.io_Length;

            iofs->io_Union.io_WRITE.io_Length = 0;
            break;

        case FSA_SEEK:
#if defined(DEBUG) && DEBUG != 0
        {
            ULONG mode = iofs->io_Union.io_SEEK.io_SeekMode;

            bug("[packet] SEEK: handle 0x%08x offset %ld mode %ld (%s)\n",
                handle->actual,
                (LONG) iofs->io_Union.io_SEEK.io_Offset,
                mode,
                mode == OFFSET_BEGINNING ? "OFFSET_BEGINNING" :
                mode == OFFSET_CURRENT   ? "OFFSET_CURRENT"   :
                mode == OFFSET_END       ? "OFFSET_END"       :
                                           "[unknown]");
        }
#endif

            dp->dp_Type = ACTION_SEEK;
            dp->dp_Arg1 = (IPTR) handle->actual;
            dp->dp_Arg2 = (IPTR) iofs->io_Union.io_SEEK.io_Offset;
            dp->dp_Arg3 = (IPTR) iofs->io_Union.io_SEEK.io_SeekMode;
            break;

        case FSA_SET_FILE_SIZE:
#if defined(DEBUG) && DEBUG != 0
        {
            ULONG mode = iofs->io_Union.io_SET_FILE_SIZE.io_SeekMode;

            bug("[packet] SET_FILE_SIZE: handle 0x%08x offset %ld mode %ld (%s)\n",
                handle->actual,
                (LONG) iofs->io_Union.io_SET_FILE_SIZE.io_Offset,
                mode,
                mode == OFFSET_BEGINNING ? "OFFSET_BEGINNING" :
                mode == OFFSET_CURRENT   ? "OFFSET_CURRENT"   :
                mode == OFFSET_END       ? "OFFSET_END"       :
                                           "[unknown]");
        }
#endif

            dp->dp_Type = ACTION_SET_FILE_SIZE;
            dp->dp_Arg1 = (IPTR) handle->actual;
            dp->dp_Arg2 = (IPTR) iofs->io_Union.io_SET_FILE_SIZE.io_Offset;
            dp->dp_Arg3 = (IPTR) iofs->io_Union.io_SET_FILE_SIZE.io_SeekMode;
            break;

        case FSA_FILE_MODE: {

            D(bug("[packet] FILE_MODE: object 0x%08x (%s) mode 0x%x\b\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_FILE_MODE.io_FileMode));

            dp->dp_Type = ACTION_CHANGE_MODE;

            /* We can only change access mode */
            if ((iofs->io_Union.io_FILE_MODE.io_Mask & FMF_LOCK) == 0) {
                iofs->io_DosError = 0;
                goto reply;
            }
            if (handle->is_lock) {
                dp->dp_Arg1 = CHANGE_LOCK;
                dp->dp_Arg2 = (IPTR) handle->actual;
            }
            else {
                dp->dp_Arg1 = CHANGE_FH;
                handle->fh.fh_Arg1 = (IPTR) handle->actual;
                dp->dp_Arg2 = (IPTR) MKBADDR(&handle->fh);
            }
            dp->dp_Arg3 = (iofs->io_Union.io_FILE_MODE.io_FileMode & FMF_LOCK) ?
                EXCLUSIVE_LOCK : SHARED_LOCK;

            break;
        }

        case FSA_IS_INTERACTIVE:
            /* XXX is there some other way to query this? how does (eg) aos
             * console handler do it? */
            iofs->io_Union.io_IS_INTERACTIVE.io_IsInteractive = FALSE;
            iofs->io_DosError = 0;
            goto reply;

        case FSA_SAME_LOCK: {
            struct ph_handle *h1, *h2;
            h1 = (struct ph_handle *) iofs->io_Union.io_SAME_LOCK.io_Lock[0];
            h2 = (struct ph_handle *) iofs->io_Union.io_SAME_LOCK.io_Lock[1];

            D(bug("[packet] SAME_LOCK: lock1 0x%08x (%s) lock2 0x%08x (%s)\n",
                h1->actual, handle_desc(h1), h2->actual, handle_desc(h2)));

            dp->dp_Type = ACTION_SAME_LOCK;
            dp->dp_Arg1 = (IPTR) h1->actual;
            dp->dp_Arg2 = (IPTR) h2->actual;
            break;
        }

        case FSA_EXAMINE: {
            struct FileInfoBlock *fib;

            D(bug("[packet] EXAMINE: lock 0x%08x (%s)\n",
                handle->actual, handle_desc(handle)));

            fib = (struct FileInfoBlock *) AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC | MEMF_CLEAR);

            dp->dp_Type = (handle->is_lock) ? ACTION_EXAMINE_OBJECT : ACTION_EXAMINE_FH;
            dp->dp_Arg1 = (IPTR) handle->actual;
            dp->dp_Arg2 = (IPTR) MKBADDR(fib);
            break;
        }

        case FSA_EXAMINE_NEXT:
            D(bug("[packet] EXAMINE_NEXT: lock 0x%08x (%s) fib 0x%08x\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_EXAMINE_NEXT.io_fib));

            dp->dp_Type = ACTION_EXAMINE_NEXT;
            dp->dp_Arg1 = (IPTR) handle->actual;
            dp->dp_Arg2 = (IPTR) MKBADDR(iofs->io_Union.io_EXAMINE_NEXT.io_fib);
            break;

        case FSA_CREATE_DIR:
            D(bug("[packet] CREATE_DIR: lock 0x%08x (%s) name '%s'\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_CREATE_DIR.io_Filename));

            dp->dp_Type = ACTION_CREATE_DIR;
            dp->dp_Arg1 = (IPTR) (handle->is_lock ? handle->actual : NULL);
            dp->dp_Arg2 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_CREATE_DIR.io_Filename);
            break;

        case FSA_IS_FILESYSTEM:
            dp->dp_Type = ACTION_IS_FILESYSTEM;
            break;

        case FSA_DISK_INFO:
            dp->dp_Type = ACTION_DISK_INFO;
            dp->dp_Arg1 = (IPTR) MKBADDR(iofs->io_Union.io_INFO.io_Info);
            break;

        case FSA_CREATE_HARDLINK:
            {
                struct ph_handle *target = (struct ph_handle *)
                    iofs->io_Union.io_CREATE_HARDLINK.io_OldFile;

                D(bug("[packet] CREATE_HARDLINK: lock 0x%08x (%s) name '%s' "
                    "target 0x%08x (%s)\n",
                    handle->actual, handle_desc(handle),
                    iofs->io_Union.io_CREATE_HARDLINK.io_Filename,
                    target->actual, handle_desc(target)));

                dp->dp_Type = ACTION_MAKE_LINK;
                dp->dp_Arg1 = (IPTR) handle->actual;
                dp->dp_Arg2 = (IPTR) mkbstr(pkt->pool,
                    iofs->io_Union.io_CREATE_HARDLINK.io_Filename);
                dp->dp_Arg3 = (IPTR) target->actual;
                dp->dp_Arg4 = LINK_HARD;
                break;
            }

        case FSA_CREATE_SOFTLINK:
            D(bug("[packet] CREATE_SOFTLINK: lock 0x%08x (%s) name '%s' target '%s'\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_CREATE_SOFTLINK.io_Filename,
                iofs->io_Union.io_CREATE_SOFTLINK.io_Reference));

            dp->dp_Type = ACTION_MAKE_LINK;
            dp->dp_Arg1 = (IPTR) handle->actual;
            dp->dp_Arg2 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_CREATE_SOFTLINK.io_Filename);
            dp->dp_Arg3 = (IPTR) iofs->io_Union.io_CREATE_SOFTLINK.io_Reference;
            dp->dp_Arg4 = LINK_SOFT;
            break;

        case FSA_RENAME:
            D(bug("[packet] RENAME: lock 0x%08x (%s) name '%s' target '%s'\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_RENAME.io_Filename,
                iofs->io_Union.io_RENAME.io_NewName));

            /* XXX the two paths from FSA_RENAME are copied directly from the
             * arguments to rename with no changes, so they may contain volume
             * specifiers, path seperators, etc. both can be calculated
             * relative to the handle. here we just pass them through to the
             * handler as-is, but I'm not sure if that's right. fat.handler at
             * least will do the right thing. this probably needs to be
             * revisited if another packet-based handler is ported */

            dp->dp_Type = ACTION_RENAME_OBJECT;
            dp->dp_Arg1 = (IPTR) handle->actual;
            dp->dp_Arg2 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_RENAME.io_Filename);
            dp->dp_Arg3 = (IPTR) handle->actual;
            dp->dp_Arg4 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_RENAME.io_NewName);
            break;

        case FSA_READ_SOFTLINK:
            D(bug("[packet] READ_SOFTLINK: lock 0x%08x (%s) name '%s'\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_READ_SOFTLINK.io_Filename));

            dp->dp_Type = ACTION_READ_LINK;
            dp->dp_Arg1 = (IPTR) handle->actual;
            dp->dp_Arg2 = (IPTR) iofs->io_Union.io_READ_SOFTLINK.io_Filename;
            dp->dp_Arg3 = (IPTR) iofs->io_Union.io_READ_SOFTLINK.io_Buffer;
            dp->dp_Arg4 = (IPTR) iofs->io_Union.io_READ_SOFTLINK.io_Size;
            break;

        case FSA_DELETE_OBJECT:
            D(bug("[packet] DELETE: lock 0x%08x (%s) name '%s'\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_DELETE_OBJECT.io_Filename));

            dp->dp_Type = ACTION_DELETE_OBJECT;
            dp->dp_Arg1 = (IPTR) handle->actual;
            dp->dp_Arg2 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_DELETE_OBJECT.io_Filename);
            break;

        case FSA_SET_COMMENT:
            D(bug("[packet] SET_COMMENT: lock 0x%08x (%s) name '%s' comment '%s'\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_SET_COMMENT.io_Filename,
                iofs->io_Union.io_SET_COMMENT.io_Comment));

            dp->dp_Type = ACTION_SET_COMMENT;
            dp->dp_Arg1 = 0;
            dp->dp_Arg2 = (IPTR) handle->actual;
            dp->dp_Arg3 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_SET_COMMENT.io_Filename);
            dp->dp_Arg4 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_SET_COMMENT.io_Comment);
            break;
            
        case FSA_SET_PROTECT:
            D(bug("[packet] SET_PROTECT: lock 0x%08x (%s) name '%s' attrs 0x%x\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_SET_PROTECT.io_Filename,
                iofs->io_Union.io_SET_PROTECT.io_Protection));

            dp->dp_Type = ACTION_SET_PROTECT;
            dp->dp_Arg1 = 0;
            dp->dp_Arg2 = (IPTR) handle->actual;
            dp->dp_Arg3 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_SET_PROTECT.io_Filename);
            dp->dp_Arg4 = (IPTR) iofs->io_Union.io_SET_PROTECT.io_Protection;
            break;

        case FSA_SET_OWNER: /* XXX untested */
            D(bug("[packet] SET_OWNER: lock 0x%08x (%s) name '%s' uid 0x%x gid 0x%x\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_SET_OWNER.io_Filename,
                iofs->io_Union.io_SET_OWNER.io_UID,
                iofs->io_Union.io_SET_OWNER.io_GID));

            dp->dp_Type = ACTION_SET_OWNER;
            dp->dp_Arg1 = 0;
            dp->dp_Arg2 = (IPTR) handle->actual;
            dp->dp_Arg3 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_SET_OWNER.io_Filename);
            dp->dp_Arg4 = (IPTR) iofs->io_Union.io_SET_OWNER.io_GID << 16 |
                                 iofs->io_Union.io_SET_OWNER.io_UID;
            break;

        case FSA_SET_DATE: /* XXX untested */
#if defined(DEBUG) && DEBUG != 0
        {
            struct DateTime dt;
            char datestr[LEN_DATSTRING];

            dt.dat_Stamp = iofs->io_Union.io_SET_DATE.io_Date;
            dt.dat_Format = FORMAT_DOS;
            dt.dat_Flags = 0;
            dt.dat_StrDay = NULL;
            dt.dat_StrDate = datestr;
            dt.dat_StrTime = NULL;
            DateToStr(&dt);

            bug("[packet] SET_DATE: lock 0x%08x (%s) name '%s' date '%s'\n",
                handle->actual, handle_desc(handle),
                iofs->io_Union.io_SET_DATE.io_Filename,
                datestr);
        }
#endif

            dp->dp_Type = ACTION_SET_DATE;
            dp->dp_Arg1 = 0;
            dp->dp_Arg2 = (IPTR) handle->actual;
            dp->dp_Arg3 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_SET_DATE.io_Filename);
            dp->dp_Arg4 = (IPTR) &iofs->io_Union.io_SET_DATE.io_Date;
            break;

        case FSA_MORE_CACHE: /* XXX untested */
            D(bug("[packet] MORE_CACHE: buffers '0x%x'\n", iofs->io_Union.io_MORE_CACHE.io_NumBuffers));

            dp->dp_Type = ACTION_MORE_CACHE;
            dp->dp_Arg1 = (IPTR) iofs->io_Union.io_MORE_CACHE.io_NumBuffers;
            break;

        case FSA_FORMAT: /* XXX untested */
            D(bug("[packet] FSA_FORMAT: name '%s' type 0x%x\n",
                  iofs->io_Union.io_FORMAT.io_VolumeName,
                  iofs->io_Union.io_FORMAT.io_DosType));

            dp->dp_Type = ACTION_FORMAT;
            dp->dp_Arg1 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_FORMAT.io_VolumeName);
            dp->dp_Arg2 = (IPTR) iofs->io_Union.io_FORMAT.io_DosType;
            break;

        case FSA_INHIBIT:
            D(bug("[packet] FSA_INHIBIT: %sinhibit\n", iofs->io_Union.io_INHIBIT.io_Inhibit == 0 ? "un" : ""));

            dp->dp_Type = ACTION_INHIBIT;
            dp->dp_Arg1 = iofs->io_Union.io_INHIBIT.io_Inhibit ? DOSTRUE : DOSFALSE;
            break;

        case FSA_RELABEL:
            D(bug("[packet] FSA_RELABEL: name '%s'\n", iofs->io_Union.io_RELABEL.io_NewName));

            dp->dp_Type = ACTION_RENAME_DISK;
            dp->dp_Arg1 = (IPTR) mkbstr(pkt->pool, iofs->io_Union.io_RELABEL.io_NewName);
            break;

        case FSA_LOCK_RECORD: /* XXX untested */
#if defined(DEBUG) && DEBUG != 0
        {
            ULONG mode = iofs->io_Union.io_RECORD.io_RecordMode;

            bug("[packet] FSA_LOCK_RECORD: handle 0x%08x offset %ld size %ld mode %d (%s) timeout %d\n",
                handle->actual,
                (LONG) iofs->io_Union.io_RECORD.io_Offset,
                iofs->io_Union.io_RECORD.io_Size,
                mode,
                mode == REC_EXCLUSIVE       ? "REC_EXCLUSIVE"       :
                mode == REC_EXCLUSIVE_IMMED ? "REC_EXCLUSIVE_IMMED" :
                mode == REC_SHARED          ? "REC_SHARED"          :
                mode == REC_SHARED_IMMED    ? "REC_SHARED_IMMED"    :
                                              "[unknown]",
                iofs->io_Union.io_RECORD.io_Timeout);
        }
#endif

            dp->dp_Type = ACTION_LOCK_RECORD;
            dp->dp_Arg1 = (IPTR) handle->actual;
            dp->dp_Arg2 = (IPTR) iofs->io_Union.io_RECORD.io_Offset;
            dp->dp_Arg3 = (IPTR) iofs->io_Union.io_RECORD.io_Size;
            dp->dp_Arg4 = (IPTR) iofs->io_Union.io_RECORD.io_RecordMode;
            dp->dp_Arg5 = (IPTR) iofs->io_Union.io_RECORD.io_Timeout;
            break;

        case FSA_UNLOCK_RECORD: /* XXX untested */
            D(bug("[packet] FSA_UNLOCK_RECORD: handle 0x%08x offset %ld size %ld\n",
                  handle->actual,
                  (LONG) iofs->io_Union.io_RECORD.io_Offset,
                  iofs->io_Union.io_RECORD.io_Size));

            dp->dp_Type = ACTION_FREE_RECORD;
            dp->dp_Arg1 = (IPTR) handle->actual;
            dp->dp_Arg2 = (IPTR) iofs->io_Union.io_RECORD.io_Offset;
            dp->dp_Arg3 = (IPTR) iofs->io_Union.io_RECORD.io_Size;
            break;

        case FSA_ADD_NOTIFY:
            D(bug("[packet] FSA_ADD_NOTIFY: nr 0x%08x name '%s'\n", 
                  iofs->io_Union.io_NOTIFY.io_NotificationRequest,
                  iofs->io_Union.io_NOTIFY.io_NotificationRequest->nr_FullName));

            dp->dp_Type = ACTION_ADD_NOTIFY;
            dp->dp_Arg1 =
                (SIPTR) iofs->io_Union.io_NOTIFY.io_NotificationRequest;
            break;

        case FSA_REMOVE_NOTIFY:
            D(bug("[packet] FSA_REMOVE_NOTIFY: nr 0x%08x name '%s'\n", 
                  iofs->io_Union.io_NOTIFY.io_NotificationRequest,
                  iofs->io_Union.io_NOTIFY.io_NotificationRequest->nr_FullName));

            dp->dp_Type = ACTION_REMOVE_NOTIFY;
            dp->dp_Arg1 =
                (SIPTR) iofs->io_Union.io_NOTIFY.io_NotificationRequest;
            break;

        /* XXX implement */
        case FSA_EXAMINE_ALL:
        case FSA_EXAMINE_ALL_END:
        case FSA_MOUNT_MODE:
        case FSA_CHANGE_SIGNAL:
        case FSA_PARENT_DIR:
        case FSA_PARENT_DIR_POST:
        case FSA_CONSOLE_MODE:
            D(bug("[packet] command not implemented\n"));
            iofs->io_DosError = ERROR_NOT_IMPLEMENTED;
            goto reply;

        default:
            D(bug("[packet] unknown command\n"));
            iofs->io_DosError = ERROR_ACTION_NOT_KNOWN;
            goto reply;
    }

    D(bug("[packet] converted to %s packet\n", act_str(dp->dp_Type)));

    /* WaitIO() will look into this */
    iofs->IOFS.io_Message.mn_Node.ln_Type = NT_MESSAGE;

    /* since these all go to the packet handler process, they can't be done now */
    iofs->IOFS.io_Flags &= ~IOF_QUICK;

    /* send the packet */
    PutMsg(&(handle->mount->process->pr_MsgPort), dp->dp_Link);

    return;

    /* jump here to reply to the packet now, handling IOF_QUICK appropriately */
reply:
    D(bug("[packet] replying directly with error %d\n", iofs->io_DosError));
    
    /* kill the packet */
    DeletePool(pkt->pool);

    /* if they can handle quick replies, just bail out */
    if (iofs->IOFS.io_Flags & IOF_QUICK)
        return;

    /* otherwise tell them properly */
    ReplyMsg((APTR) iofs);
}