跳转到内容

Aros/开发者/文档/库/DOS

来自维基教科书,开放世界中的开放书籍
用于 Aros 维基教科书的导航栏
Aros 用户
Aros 用户文档
Aros 用户常见问题解答
Aros 用户应用程序
Aros 用户 DOS Shell
Aros/用户/AmigaLegacy
Aros 开发者文档
Aros 开发者文档
从 AmigaOS/SDL 移植软件
适用于 Zune 初学者
Zune .MUI 类
适用于 SDL 初学者
Aros 开发者构建系统
特定平台
Aros x86 完整系统 HCL
Aros x86 音频/视频支持
Aros x86 网络支持
Aros Intel AMD x86 安装
Aros 存储支持 IDE SATA 等
Aros Poseidon USB 支持
x86-64 支持
摩托罗拉 68k Amiga 支持
Linux 和 FreeBSD 支持
Windows Mingw 和 MacOSX 支持
Android 支持
Arm Raspberry Pi 支持
PPC Power Architecture
其他
Aros 公共许可证

文件系统控制文件和文件夹在磁盘上的布局方式,并处理创建、读取、写入和删除这些文件的所有细节。如果没有文件系统,您的磁盘(或软盘、CD-ROM、USB 密钥或 SD 卡)只是一堆未结构化的原始数据。

当您访问文件时,每次都会创建一个文件句柄。

  • dos.h 包含 Open、Close、Seek、Read、Write 等。
  • stdio.h 包含 fopen、fclose、fseek、fread、fwrite 等。

所有文件例程都通过 dos.library,即使您使用 fopen(),这些“非原生”库函数只是用 C 标准化文件访问的一些实现,如果您跟踪代码,它们最终会使用 Aros 操作系统调用。

malloc 等也是如此,它们最终会进入 exec.library 的 AllocMem/AllocVec/AllocPooled 或其他。

需要注意的是,当您调用某个操作系统函数时,您的代码实际上是在运行 OS 代码,没有幕后超级代码为您执行此操作。您的应用程序 PC 计数器会通过这些调用。

如果您使用标准 C 库调用,则必须将其链接到二进制文件,或者二进制文件必须在运行时打开 clib。您不希望在编写操作系统部分时拥有 clib(用户应用程序可以随意操作)。如果使用了一个,C 库调用了操作系统调用,那么就会变得很乱(clib 代码会将 C 标准转换为原生调用等)。

当您从编译器的标准 C 库或 POSIX 类型函数库中使用通用例程时,在处理 AROS(或 Amiga)系统内容时通常会看到特定的限制。它们对文件权限位可能有不兼容的想法,对如何处理多个根卷或查找实际上是“多路径分配”的东西或使用文件注释(Amiga 原生应用程序编写人员利用了这些注释)可能有不兼容的想法。标准库不理解 Amiga 工作台环境中程序和图标之间的关系。

标准库编程可能意识不到用户在遇到大量“插入卷 foo:请求者”弹出窗口或更糟的是,在应用程序在其自身屏幕上运行时在工作台屏幕上弹出窗口,阻塞对这些请求者的查看,因为它们是用 Unix shell 语义编写的,其中错误处理的方式不同。

坚持使用 AROS 原生函数名称可能是安全的,即使标准调用在内部被重新映射。

分配一大块内存(使用 AvailMem 和标志 MEMF_LARGEST 获取大小,并使用 AllocDosObject(以前是 AllocMem)分配,文件大小使用 Lock 和 Examine(ExAll)获取),使用 Open 打开文件,并使用 Read 读取数据,使用 Open 打开源文件,并使用 Write 保存数据。对于总 RAM,使用 MEMF_TOTAL。

检查现有文件的一种简单方法是:使用 Examine/ExNext/ExAll 获取一个目录的数据,并尝试对目标目录中的每个文件名进行 Lock()。要更改目录/创建目录,CurrentDir 和 CreateDir 很有用。Rename 和 DeleteFile 函数将很有用。

struct FileHandle
{
    /* The next three are used with packet-based filesystems */
    struct Message * fh_Link;   /* exec message containing packet */
    struct MsgPort * fh_Port;   /* packet reply port */
    struct MsgPort * fh_Type;   /* port to send packets to */

    UBYTE * fh_Buf;
    UBYTE * fh_Pos;
    UBYTE * fh_End;

#ifdef AROS_DOS_PACKETS

    LONG fh_Funcs;
#define fh_Func1 fh_Funcs
    LONG fh_Func2;
    LONG fh_Func3;
    LONG fh_Args;
#define fh_Arg1 fh_Args
    LONG fh_Arg2;

    /* kept here until things stabilize */
    ULONG        fh_Size;
    ULONG        fh_Flags;

#else

    /* The following four fields have different names and a different function than their AmigaOS equivalents. 
       The original names were:      fh_Funcs/fh_Func1, fh_Func2, fh_Func3, fh_Args/fh_Arg1 and fh_Arg2 */
    ULONG        fh_Size;
    ULONG        fh_Flags;   /* see below */
    /* This is a pointer to a filesystem handler. See <dos/filesystems.h> for more information. */
    struct Device * fh_Device;

    /* SDuvan: Added this and removed the #if below. This field allows us to emulate packets -- 
               specifically it makes it possible to implement the ***Pkt() functions */
    SIPTR fh_CompatibilityHack;

    /* A private pointer to a device specific filehandle structure. See <dos/filesystems.h> for more information. */
    struct Unit   * fh_Unit;

#endif
};

外部代码引用的唯一字段是 fh_Device 和 fh_Unit。它们用于发送直接 IOFS 请求。实际上,fh_Size 和 fh_Flags 也可以别名为 fh_Funcs 和 fh_Func2,但这会影响 m68k 端口,如果它们决定出于某种原因实现这些回调。如果可能会保存指针的字段升级为 SIPR 而不是 APTR,可能会更好。这将与 AmigaOS 代码提供更好的源代码级别兼容性,例如避免编译器警告。

以前的实现(对于非 AROS_DOS_PACKET 情况,字段 fh_Size 在偏移量 24,字段 fh_Flags 在偏移量 28)。更改后,字段 fh_Size 在偏移量 44,字段 fh_Flags 在偏移量 48。上面是更改前后的 FH 结构,供参考。

Info() 函数获取系统中卷的信息。

  • lock—对卷上任何应提供信息的锁定文件
  • parameterBlock—指向 InfoData 结构的指针

结果为 != 0(如果操作成功)或 == 0(如果操作不成功)。如果成功(!= 0),则“parameterBlock”将填充有关卷的信息。

/* 由 Info() 返回,必须位于 4 字节边界上 */ struct InfoData {

  LONG	  id_NumSoftErrors;	/* number of soft errors on disk */
  LONG	  id_UnitNumber;	/* Which unit disk is (was) mounted on (os1.3 only) */
  LONG	  id_DiskState;		/* ID_WRITE_PROTECTED, ID_VALIDATING, ID_VALIDATED */
  LONG	  id_NumBlocks;		/* Number of blocks on disk */
  LONG	  id_NumBlocksUsed;	/* Number of block in use */
  LONG	  id_BytesPerBlock;
  LONG	  id_DiskType;		/* (ID_NO_DISK_PRESENT, ID_UNREADABLE_DISK, ID_NOT_REALLY_DOS, ID_BUSY)
                                   Filesystem ID_DOS_DISK, ID_FFS_DISK, ID_INTER_DOS_DISK, ID_INTER_FFS_DISK, 
                                              ID_FASTDIR_DOS_DISK, ID_FASTDIR_FFS_DISK, 
                                              ID_LONGNAME_DOS_DISK, ID_LONGNAME_FFS_DISK, ID_MSDOS_DISK 
                                   Console    ID_CON, ID_RAWCON, ID_KICKSTART_DISK */
  BPTR	  id_VolumeNode;	/* BCPL pointer to volume node */
  LONG	  id_InUse;		/* Flag, zero if not in use */

}; /* InfoData */

要查找 Shell 运行的 CON:/RAW: 窗口的地址;AmigaDOS 手册中对这一点的记录很少,但事实是,如果将 DiskInfo 数据包发送到控制台处理程序,InfoData 结构中的 id_VolumeNode 字段将保存所需的窗口地址。

#include	
#include	
#include	
extern struct Library	*OpenLibrary();
struct Library	*IntuitionBase;
struct Window	*wb_window;

   wb_window = NULL;
#if	RAW_CONSOLE
   if ((IntuitionBase = OpenLibrary("intuition.library", 0L)) != NULL) {
	BPTR			iLock;
	struct FileHandle	*conF;
	struct InfoData		*infTemp;
	extern long		dos_packet();

	iLock = (BPTR) Input();
	conF = (struct FileHandle *) BADDR(iLock);
	infTemp = (struct InfoData *) malloc(sizeof(struct InfoData));
	if (infTemp == 0)
		return;
	/*
	 * Send the packet.
	*/
	if (!dos_packet(conF->fh_Type, ACTION_DISK_INFO, 
			((ULONG) infTemp) >> 2)) {
		free((void *) infTemp);
		return;
	}
	wb_window = (struct Window *) infTemp->id_VolumeNode;
   }
#endif

打开关闭文件

[编辑 | 编辑源代码]

在您可以对文件执行任何操作之前,您必须要求操作系统“打开它”。这是因为 AROS 需要知道您要对文件做什么。您是要创建一个新文件(MODE_NEWFILE),还是要使用已打开的文件(MODE_OLDFILE)。您可以通过调用 Open() 函数打开文件。

例如,如果您要创建一个名为“Highscore.dat”的新文件,则可以编写以下代码:

/* Try to open the file: */
file_handle = Open("Highscore.dat", MODE_NEWFILE );

/* Check if we have opened the file: */
if( file_handle == NULL )
  /* Could NOT open file! */

完成读取/写入文件后,您需要关闭它。您可以通过调用 Close() 函数来完成。

Close(file_handle);

关闭所有已打开的文件!

/*
    Copyright © 1995-2010, The AROS Development Team. All rights reserved.
    $Id: filetest.c 37364 2011-03-04 22:40:55Z jmcmullan $
*/

#include <dos/dos.h>
#include <stdio.h>

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/dos.h>

static void hexdump(UBYTE *data, LONG len)
{
    LONG i;

    for (i = 0; i < len; i++)
        printf("%02X ", data[i]);

    printf("\n");
}

int main(int argc, char **argv)
{
    BPTR file;
    UBYTE buffer[20];
    LONG r1=0,r2=0,r3=0,r4=0;
    char *name = "testfile";
    
    if (argc > 1)
	name = argv[1];

    file=Open(name, MODE_NEWFILE);
    if(file)
    {
	r1=Write(file,"hello, world\n",13);
	r2=Seek(file,0,OFFSET_BEGINNING);
	r3=Read(file,buffer,19);
	r4=Close(file);
    }
    if(r3>=0)
	buffer[r3]=0;

    printf("Results: %d %d %d %d \'%s\'\n",(int)r1,(int)r2,(int)r3,(int)r4,buffer);
    hexdump(buffer, r3);
    
    return 0;
}

使用任何全局 FILE 指针都会带来麻烦,因此最好不要使用它们。只需在每个函数解析时声明其用法(如果需要)。全局变量是一个糟糕的主意,如果您养成不加思考就使用它们的习惯,将来可能会遇到麻烦。在继续之前,请确保您了解变量作用域及其后果。

读取、写入和查找文件

[编辑 | 编辑源代码]

成功打开文件后,就可以开始读取或写入。AmigaDOS(TM) 和 AROS 将文件视为字节流,当您读取或写入内容时,您需要指定要读取或写入的字节数。

要写入文件,可以使用 Write() 函数

要查找

#include <stdio.h>
#include <dos/dos.h>
#include <stdlib.h>

#include <proto/dos.h>

int main()
{
FILE *fd;
char buffer[32];
int i;
BPTR file;

  fd = fopen( "seek.txt", "wb" );
  if ( !fd )
  {
    fprintf( stderr, "Could not write test file seek.txt\n" );
    exit(-1);
  }
  fprintf( fd, "() does not work!\n" );
  fclose(fd);

/* fseek() */
  fd = fopen( "seek.txt", "rb" );
  if ( !fd )
  {
    fprintf( stderr, "Could not open test file seek.txt\n" );
    exit(-1);
  }
  i = fread( buffer, 1, 1, fd );
//printf("pos=%ld\n",ftell(fd));
  i += fread( &buffer[1], 1, 6, fd );
  if( i != 7 )
  {
    fprintf( stderr, "Wanted to fread() %d chars, but could only get %d!\n", 6, i-1 );
    exit(-1);
  }
  fseek( fd, 4, SEEK_CUR );
  i = fread( &buffer[7], 1, 11, fd );
  buffer[7+i]=0;
  printf( "fseek%s", buffer );
  fclose(fd);

/* Seek() */
  file = Open( "seek.txt", MODE_OLDFILE );
  i = Read( file, buffer, 7 );
  Seek( file, 4, OFFSET_CURRENT );
  i += Read( file, &buffer[7], 11 );
  buffer[i] = 0;
  printf( "\nSeek%s", buffer );
  
  return 0;
}

另请参阅 此处

#include "dos/dosextens.h"
extern struct FileHandle *Open()

main()
{
    struct FileHandle *file_handle;
    file_handle = Open("CON:10/10/500/150/New Window", MODE_NEWFILE);

    Write (file_handle,"Hello World\n",13);
    Delay(400);
    Close(file_handle);
}
currentposition=Seek(file_handle,0, OFFSET_END); 
currentposition=Seek(file_handle,0, OFFSET_CURRENT); 
currentposition=Seek(file_handle,20, OFFSET_CURRENT); 
currentposition=Seek(file_handle,0, OFFSET_BEGINNING);
boolean_status=WaitForChar(file_handle,waiting_time);

flock 使用以 MODE_NEWFILE 模式打开的文件句柄调用 DupLockFromFH()。不允许重复它。可以通过用以下内容替换 O_CREAT = NEWFILE 来解决:首先使用 MODE_NEWFILE 创建文件,关闭它,然后使用 MODE_OLDFILE 重新打开它。ChangeMode() 也是一种可能,但它可能不受所有文件系统支持,或者它可能已损坏(直到大约两年前,UAE fs 实现的 CHANGE_FH 变体一直存在错误。它在 AOS 程序中确实很少使用)。

实际上,flock() 调用 NameFromFH(),而 NameFromFH() 本身又调用 DupLockFromFH()。所以第一个问题是,如果使用 MODE_NEWFILE 打开的句柄,NameFromFH() 是否应该失败?在 OS3.x 上是否会失败?NameFromFH() 必须能够处理使用 MODE_NEWFILE 打开的文件句柄。Guru Book 中也提到了,AOS 的 NameFromFH() 在内部使用 ExamineFH() 和 ParentOfFH() 来获取名称字符串,因为如果句柄是 MODE_NEWFILE,DupLockFromFH() 无法工作。

看起来它做了类似这样的事情

  • parentlock = ParentOfFH(fh);
  • 路径字符串 = NameFromLock(parentlock);
  • Unlock(parentlock)
  • 从 ExamineFH(fh) 中获取文件名并追加到路径字符串

为什么 DupLockFromFH() 不能在 MODE_NEWFILE 文件上工作?据我所知,这是因为 MODE_NEWFILE 使用了排它锁(在所有文件系统上,不仅仅是在 AmberRAM 上)。

如果我们让它工作,会有什么问题吗?UAE 的文件系统需要重新编写,但这只是其中的一部分,对吧?这不会破坏与 AOS m68k 文件系统的兼容性吗?是的。排它锁复制(包括具有内部排它锁的 MODE_NEWFILE 文件句柄)尝试必须失败。这是已记录的行为。NameFromFH() 现在已重写,可以处理排它文件句柄。

SameLock()

dol_Name 是指向 BCPL 字符串的 BCPL 指针,因此你不能直接使用 printf() 打印它。请注意,即使如此,你也应该避免这样做,尤其是在你持有 dos 列表锁的时候。最好将你需要的的信息复制到自己的缓冲区中,然后在解锁 dos 列表后打印它。

char buffer[256];
const uint8 *bstr = BADDR(dlPtr->dol_Name);
memcpy(buffer, bstr+1, *bstr);
buffer[*bstr] = 0;

你永远不应该在 dos 列表被锁定的情况下执行任何 DOS I/O 操作。创建一个包含你想要的操作的执行列表,释放 dos 列表,然后打印出列表节点......

在 DOS 列表中遍历,并显示列表中的所有设备。如果你想只过滤那些已经被激活的设备,你需要编写一个新程序来遍历列表(LockDosList / NextDosEntry),并检查 dol_Task 是否已填充(OS4 将其重命名为 dol_Port)。名称是 dol_Task(请参阅 dos/dosextens.h)。它包含指向 MsgPort 的指针。但请注意,这随时可能发生变化。一个设备可以被挂载,但可能不会立即被激活。当用户首次访问它时,它会自动被激活。例如,这适用于 RAM、SER、PAR 和 PRT

卷标

#include <exec/types.h> 
#include <exec/memory.h> 
#include <dos/dos.h> 
#include <clib/exec_protos.h> 
#include <clib/dos_protos.h>

#include <stdio.h> 
#include <stdlib.h> 
#include <ctype.h>

struct InfoData *info; 
struct DosList *doslist; 
char *name; 
void main(void) 
{ 
 BPTR lock, mydoslist;
 BOOL success;
 lock=Lock("File",ACCESS_READ);

 if(!lock) exit(20);
 info=(struct InfoData*)AllocVec(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
 success=Info(lock,info);

 if(!success) exit(30);
 doslist=(struct DosList*)((info->id_VolumeNode)<<2);
 name=((struct Node*)(((struct MsgPort*)(doslist->dol_Task))->mp_SigTask))->ln_Name;
 printf("%s:\n",name);
 FreeVec(info);
}
#include <dos/dosextens.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <stdio.h>

#define MAXV 40
struct DE {
   char name[256];
   APTR task;
};
struct DE vols[MAXV], devs[MAXV];

void ReadDosList(struct DE *list, int *max, int type) {
   struct DosList *dl;
   int i = 0;
   UBYTE *x;
   if (!(dl = LockDosList(type))) {*max = 0; return;}
   while ((dl = NextDosEntry(dl, type))) {
     if (i >= MAXV) continue;
     x = BADDR(dl->dol_Name);
     CopyMem(&x[1], &list[i].name, x[0]);
     list[i].name[x[0]] = 0;
     list[i].task = dl->dol_Task;
     i++;
   }
   UnLockDosList(type);
   *max = i;
}

int main() {
   int i, j, voln, devn;
   STRPTR x;
   SysBase = *((struct ExecBase **)4UL);
   if ((DOSBase = OpenLibrary("dos.library", 37))) {
     ReadDosList(&devs[0], &devn, LDF_DEVICES | LDF_READ);
     ReadDosList(&vols[0], &voln, LDF_VOLUMES | LDF_READ);
     CloseLibrary(DOSBase);
   }
   for (i = 0; i < voln; i++) {
//     x = "o device?;
     for (j = 0; j < devn; j++)
       if (vols[i].task == devs[j].task) x = devs[j].name;
     printf("%s -> %s\n", vols[i].name, x);
   }
   return 0;
}

要将 WBArg 转换为完整路径,你可以执行以下操作

TEXT fullpath[1024];

NameFromLock(WBArg->wa_Lock, fullpath, sizeof(fullpath));
AddPart(fullpath, WBArg->wa_Name, sizeof(fullpath));

但是,通常更有效的方法是

BPTR oldcd, file;

oldcd = CurrentDir(WBArg->wa_Lock);
file = Open(WBArg->wa_Name, MODE_OLDFILE);
CurrentDir(oldcd);

if (file != 0) {
    /* ... */
    Close(file);
}

检查文件或目录

[编辑 | 编辑源代码]

最新的方法需要 ExAll,它取代了 Examine() 和 ExNext()。当 ExAll() 扫描一个目录(之前已经锁定)时,它会将一个 ExAllData 结构写入缓冲区,用于每个条目。

示例 - 查找

旧的方法需要 Examine()。你向函数传递一个指向你要检查的文件或目录的“锁”的指针,它将为你设置一个 FileInfoBlock 结构。

/*
    Copyright © 1995-2002, The AROS Development Team. All rights reserved.
    $Id: ExNext.c 33409 2010-05-31 13:45:26Z mazze $

    Test ExNext() function
*/

#include <proto/dos.h>
#include <proto/exec.h>

#include <dos/dos.h>
#include <dos/exall.h>
#include <dos/rdargs.h>
#include <dos/var.h>
#include <exec/memory.h>
#include <exec/types.h>

#include <utility/tagitem.h>
#include <stdio.h>

#include <aros/debug.h>

#define ARG_TEMPLATE    "DIRECTORY"
#define TOTAL_ARGS      1

static const char version[] = "$VER: ExNext 41.1 (30.01.2000)\n";

int main(int argc, char *argv[])
{
    struct RDArgs	* rda;
    IPTR		* args[TOTAL_ARGS] = { NULL };
    int			  Return_Value;
    BPTR		  lock;

    Return_Value = RETURN_OK;

    rda = ReadArgs(ARG_TEMPLATE, (IPTR *)args, NULL);
    if (rda)
    {
	if (!args[0])
	    lock = Lock("", ACCESS_READ);
	else
	    lock = Lock((STRPTR)args[0], ACCESS_READ);

	if (lock)
	{
	    struct FileInfoBlock * FIB;
	    BOOL success;
	    FIB = AllocVec(sizeof(struct FileInfoBlock), MEMF_CLEAR);
	    if (FIB)
	    {
	      success = Examine(lock, FIB);
	      kprintf("calling ExNext()...\n");
	      success = ExNext(lock, FIB);
	      kprintf("called ExNext()\n");
	      while (success != DOSFALSE)
	      {
		/* don't show dirs */
		if (FIB->fib_DirEntryType < 0)
		    printf("%s\n",FIB->fib_FileName);
		else
		    printf("%s (not a file)\n", FIB->fib_FileName);
		kprintf("calling ExNext()...\n");
		success = ExNext(lock, FIB);
		kprintf("called ExNext()\n");
	      }
	      FreeVec(FIB);
	    }
	    UnLock(lock);
	}
	else
	{
	    PrintFault(IoErr(), "ExNext");
	    Return_Value = RETURN_FAIL;
	}
    }
    else
    {
        PrintFault(IoErr(), "ExNext");
        Return_Value = RETURN_ERROR;
    }

    if (rda)
        FreeArgs(rda);

    return (Return_Value);
} /* main */

使用 AllocMem 分配的内存与 dos 函数 Examine 一起使用,并将 fib_SIZEOF 作为大小是否安全?或者使用 AllocDosObject 是否更好?AllocMem 对所有当前存在的 AmigaOS 版本都是安全的,但 AllocDosObject 对于未来的兼容性更好。请注意,AllocDosObject 在 Kickstart 1.3 及以下版本中不存在,因此对于这些 OS 版本,你需要使用 AllocMem。

struct FileInfoBlock fib;
BPTR lock = Lock(filename, ACCESS_READ);

if (lock)
{
   Examine(lock, &fib);
   UnLock(lock);
}

在 PowerPC 上,堆栈始终是长字对齐的,你不必使用 AllocDosObject() 或 AllocMem()。如果你针对 AmigaOS/68k 编码,你必须分配长字对齐的 FIB。

   TEXT buf[500];
   struct FileInfoBlock *fib = (APTR)&buf;

   stccpy(buf, "PROGDIR:", sizeof(buf));
   AddPart(buf, "Image.png", sizeof(buf));  // Buf is passed to dos.library
   fh = Open(buf, MODE_OLDFILE);            // Again buf is passed to dos.library
   ExamineFH(fh, &fib);                                 // Yet again same buf is passed to dos.library
   Close(fh);

FileInfoBlock 不是系统结构。它只是一个指向用于检索数据的缓冲区的指针。如果你仍然坚持 FIB 必须使用 AllocDosObject() 分配(为什么?),你也应该使用系统例程为传递给 Lock()、Open() 等的名称分配空间。

正如你所看到的,这个使用 AllocDosObject() 分配 FIB 的想法不是一个好主意。对于其他结构,例如 ExAllControl,它确实是必要的,因为结构在传递给 dos.library 之前必须正确初始化。使用 AllocDosObject() 的唯一真正原因是在 AmigaOS 中的长字对齐要求(但在 MorphOS 或 AROS 中不是)。在过去,它曾经是许多错误的来源,因为开发人员不知道长字对齐限制,导致随机行为/内存损坏。

void CreateQPort(struct MsgPort *port)
{
	port->mp_Node.ln_Type = NT_MSGPORT;
	port->mp_Flags        = PA_SIGNAL;
	if ((BYTE) (port->mp_SigBit = AllocSignal(-1)) == -1)
	{
		port->mp_SigBit = SIGB_SINGLE;
		SetSignal(0, SIGF_SINGLE);
	}
	port->mp_SigTask      = FindTask(NULL);  // SysBase->ThisTask would be faster here
	NEWLIST(&port->mp_MsgList);
}

void DeleteQPort(struct MsgPort *port)
{
	if (port->mp_SigBit == SIGB_SINGLE)
	{
		SetSignal(0, SIGF_SINGLE);
	}
	else
	{
		FreeSignal(port->mp_SigBit);
	}
}

如何使用 dos.library/DateToStr() 以字符串格式返回格式为 DDMMYYYY 的日期?

#include <dos/dos.h>
#include <proto/dos.h>
#include <dos/datetime.h>

int main(void)
{
    struct DateTime curr;
    char day[LEN_DATSTRING];
    char time[LEN_DATSTRING];
    char date[LEN_DATSTRING];
    struct DateStamp stamp;

    curr.dat_Format  = FORMAT_DOS;
    curr.dat_Flags   = 0;
    curr.dat_StrDay  = day;
    curr.dat_StrDate = date;
    curr.dat_StrTime = time;

    DateStamp(&curr.dat_Stamp);
    DateToStr(&curr);
    Printf("Current time: %s, %s, %s\n", day, date, time);
    
    BPTR fh = Open("__TEST__", MODE_NEWFILE);
    
    if (fh != NULL)
    {
        struct FileInfoBlock *fib = AllocDosObject(DOS_FIB, NULL);
        
        if (fib != NULL)
        {
            if (ExamineFH(fh, fib))
            { 
        	curr.dat_Stamp = fib->fib_Date;
        	DateToStr(&curr);
                Printf("File modification time: %s, %s, %s\n", day, date, time);
            }
            else
        	PrintFault(IoErr(), "Examine failed");

            Printf("Waiting 5 seconds\n");
            Delay(5*50);
            
            DateStamp(&stamp);
            
            Printf("Calling SetFileDate\n");
            if(SetFileDate("__TEST__", &stamp)) {
                if (ExamineFH(fh, fib))
                { 
                    curr.dat_Stamp = fib->fib_Date;
                    DateToStr(&curr);
                    Printf("New file modification time: %s, %s, %s\n", day, date, time);
                }
                else
                    PrintFault(IoErr(), "Examine failed");        	
            }
            else
        	PrintFault(IoErr(), "SetFileDate");
            
            FreeDosObject(DOS_FIB, fib);
        }
        else 
            PrintFault(IoErr(), "Couldn't alloc FileInfoBlock");
            
        Close(fh);
        DeleteFile("__TEST__");
    }
    else
	PrintFault(IoErr(), "Couldn't create file");
    
    return 0;
}

保护文件和目录

[编辑 | 编辑源代码]

你可以保护文件和目录免受意外删除或更改。你可以通过调用 SetProtection() 函数来实现,该函数会根据 FIB FileInfoBlock 结构中所需的保护位来更改保护位。

#include <proto/dos.h>
#include <stdio.h>

int main(void)
{
    TEXT buffer[512];
    BPTR fh = Open("__TEST__", MODE_NEWFILE);
    
    if (fh != NULL)
    {
        if (NameFromFH(fh, buffer, 512))
        {
            printf("got name: %s\n", buffer);
        }
        else
        {
            printf("namefromlock failed. ioerr = %ld\n", IoErr());
        }
        
        Close(fh);
        DeleteFile("__TEST__");
    }
    else
    {
        printf("couldn't create file\n");
    }

    return 0;
}
#include <proto/dos.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char c;
    if (argc < 2)
    {
        fprintf(stderr, "usage: %s <varname>\n", argv[0]);
        return 20;
    }
	
    if (GetVar(argv[1], &c, 1, GVF_BINARY_VAR) == 0)
    {
        LONG len = IoErr();
	char *buf = malloc(len + 1);
	if (!buf)
	{
	    PrintFault(ERROR_NO_FREE_STORE, argv[0]);
	    return 20;
	}
	
	printf("IoErr() says the len of the value of the var '%s' is: %ld\n", argv[1], len);
	
	
	len = GetVar(argv[1], buf, len+1, GVF_BINARY_VAR);
	
	printf("GetVar() says the len of the value of the var '%s' is: %ld - its value is '%s'\n",
	       argv[1], len, buf);
	
	free(buf);
	
	return 0;
    }

    PrintFault(IoErr(), argv[1]);    
    
    return 20;
}

FileInfoBlock 看起来像这样

struct FileInfoBlock {
  LONG fib_DiskKey;
  LONG fib_DirEntryType;
  char fib_FileName[108];
  LONG fib_Protection;
  LONG fib_EntryType;
  LONG fib_Size;
  LONG fib_NumBlocks;
  struct DateStamp fib_Date;
  char fib_Comment[80];
  char fib_Reserved[36];
};
*fib_DiskKey:      Key number for the disk. Usually of no interest for us.
*fib_DirEntryType: If the number is smaller than zero it is a file. On the other hand, if the number is larger than zero it is a directory.
*fib_FileName:     Null terminated string containing the filename. (Do not use longer filenames than 30 characters.) FileInfoBlock fib_Comment and fib_FileName should be BCPL strings would make porting of ftp-handler easier and Staf wrote that BCPL strings will become BCPL strings on all platforms. 
*fib_Protection:   Field containing the protection flags:
                  FIBF_DELETE  : the file/directory can not be deleted.
                  FIBF_EXECUTE : the file can not be executed.
                  FIBF_WRITE   : you can not write to the file.
                  FIBF_READ    : you can not read the file.
                  FIBF_ARCHIVE : Archive bit.
                  FIBF_PURE    : Pure bit.
                  FIBF_SCRIPT  : Script bit.
                  (Note! All of the flags are for the moment not working!)

*fib_EntryType:   File/Directory entry type number. Usually of no interest for us.
*fib_Size:        Size of the file (in bytes).
*fib_NumBlocks:   Number of blocks in the file.
*fib_Date:        Structure containing the date when the file was latest updated/created.
*fib_Comment:     Null terminated string containing the file comment. (Max 80 characters including the NULL sign.) 
The Amiga Dos/Examine() docs say that the buffers are ASCIIZ when Dos/Examine() returns. The only confusion was what the *handler* fills in the FIB on an ACTION_EXAMINE_OBJECT. On m68k it was always BCPL-style. There was some idea that on non-m68k handlers should use ASCIIZ, to save the BCPL2ASCIIZ step in Dos/Examine(). The *handler* always fills in as BCPL style, and Dos/Examine() always runs a BCPL2ASCIIZ conversion on fib_Comment and fib_FileName *regardless* of architecture. Especially since a length-terminated string is quicker to convert to a null-terminated string than the other way around. Only handler writers need to be aware of these details. 
*fib_Reserved:    This field is for the moment reserved, and may therefore not be used.
#include <dos/dos.h>
#include <proto/dos.h>
#include <stdio.h>

int main(void)
{
    BPTR fh = Open("__TEST__", MODE_NEWFILE);
    
    if (fh != NULL)
    {
        struct FileInfoBlock *fib = AllocDosObject(DOS_FIB, NULL);
        
        if (fib != NULL)
        {
            if (ExamineFH(fh, fib))
            {
                printf("got fib.filename = %s\n", fib->fib_FileName);
            }
            else
            {
                printf("examinefh failed, ioerr = %ld\n", IoErr());
            }
            FreeDosObject(DOS_FIB, fib);
        }
        else
        {
            printf("couldn't allocate fileinfoblock\n");
        }
            
        Close(fh);
        DeleteFile("__TEST__");
    }
    else
    {
        printf("couldn't create file\n");
    }

    return 0;
}

目前可以使用一些代码获取“双击”文件的名称

if (argc == 0)   
{   
    struct WBStartup *startup = (struct WBStartup *) argv;   
    if (startup->sm_NumArgs > 1)   
    {   
        BPTR  parentlock = startup->sm_ArgList[1].wa_Lock;   
        char *filename   = startup->sm_ArgList[1].wa_Name;   
    }   
}

但无法使用“GetCurrentDirName”获取我的文件所在的目录。如果将 CLI 设置为 ToolType,GetCurrentDirName 会起作用,但随后会获取错误的名称。由于你的程序是由 Workbench 启动的,因此它实际上没有 CLI 结构,因此 GetCurrentDirName() 无法在没有 CLI 工具类型的情况下工作。但你应该能够使用 NameFromLock() 并从那里找到你需要的東西。

BPTR GetCurrentDir (void) {
    BPTR dir;
    dir = CurrentDir(0);
    CurrentDir(dir);
    return dir;
}

GetCurrentDirName() 从程序的 CLI 结构中获取当前路径字符串,如果不存在 CLI 结构,则返回错误(IoErr() == ERROR_OBJECT_WRONG_TYPE)。

#include <proto/exec.h>
#include <proto/dos.h>
#include <dos/dostags.h>

/*
BOOL myGetCurrentDirName (STRPTR buffer,LONG length)

{
BPTR lock;
BOOL success = FALSE;

if (lock = Lock ("",SHARED_LOCK))
    {
    success = NameFromLock (lock,buffer,length);
    UnLock (lock);
    }

return (success);
}
*/

{
struct Process *pr = (struct Process *) FindTask (NULL);
struct Message *msg;
BPTR win;

WaitPort (&pr->pr_MsgPort);
msg = GetMsg (&pr->pr_MsgPort);

win = Open ("con:////DirName/CLOSE/WAIT",MODE_NEWFILE);
if (win)
    {
    char buffer[256];

    if (GetCurrentDirName (buffer,256))
        {
        FPrintf (win,"Dir Name = <%s>n",buffer);
        }
    else
        {
        Fault (IoErr(),NULL,buffer,256);
        FPrintf (win,"Error: %sn",buffer);
        }

    Close (win);
    }

Forbid();
ReplyMsg (msg);
}

int main (void)

{
struct Message *msg = AllocVec (sizeof(struct Message),MEMF_CLEAR|MEMF_PUBLIC);

if (msg)
    {
    struct MsgPort *port = CreateMsgPort();
    if (port)
        {
        struct Process *pr = CreateNewProcTags (NP_Entry,proc,TAG_END);
        if (pr)
            {
            msg->mn_ReplyPort = port;
            PutMsg (&pr->pr_MsgPort,msg);
            WaitPort (port);
            GetMsg (port);
            }
        DeleteMsgPort (port);
        }
    FreeVec (msg);
    }

return (0);
}

MatchFirst() 并传递给 MatchNext() 和 MatchEnd()

ParsePattern() 函数创建一个区分大小写的通配符字符串,而 ParsePatternNoCase() 函数创建一个不区分大小写的通配符字符串。区分大小写的 MatchPattern() 或不区分大小写的 MatchPatternNoCase()

通过 ReadArgs() 使用 RDArgs 结构解析命令行

CompareDates()

AmigaDos wild card are ? # % | * [] ` ~
#include <stdlib.h>

/* Write some numbers to a file */
void WriteNumbers(void) {
  BPTR fh;
  int n;
  UBYTE numstr[5];

  printf("Writing numbers to numbers.dat\n\n");
  /* Open file for writing */
  fh = Open("numbers.dat", MODE_NEWFILE);
  if (fh) {
    for (n=1; n<=20; n++) {
      /* Convert number to a string with new line
          & write string to file */
      sprintf(numstr, "%d\n", n);
      FPuts(fh, numstr);
     }
     Close(fh);
  }
}

/* Read numbers from a file */
void ReadNumbers(void) {
  BPTR fh;
  int i;
  UBYTE numstr[5];
  UBYTE *buffer;

  printf("Reading file numbers.dat.\n");
  /* Open existing file for reading */
  fh = Open("numbers.dat", MODE_OLDFILE);
  if (fh) {
     /* Read a string and check for End of File */
     while (buffer = FGets(fh, numstr, 5L)) {
         /* Convert string to number and print it */
         i = atoi(numstr);
         printf("Number %d\n", i);
     }
     Close(fh);
  }
  printf("EOF found\n");
}

int main(void)
{
  WriteNumbers();

  ReadNumbers();

  return 0;
}
#include <stdlib.h>
#include <dos/dos.h>
#include <defines/dos.h>

extern struct SYSBase *SysBase;
extern struct DOSBase *DOSBase;

int main(int argc, char *argv[])
{
int ioerr, fsize, res;
BPTR fhandle;

if (argc != 2) {
printf("Wrong number of arguments\n");
return 1;
}

fhandle = Open(argv[1], MODE_OLDFILE);
if (!fhandle) {
ioerr = IoErr();
printf("Cannot open '%s'\n", argv[1]);
PrintFault(ioerr, "IoErr() says: ");
return 1;
}

res = Seek(fhandle, 0, OFFSET_END);
if (res == -1) {
ioerr = IoErr();
printf("Cannot seek to the end of file\n");
PrintFault(ioerr, "IoErr() says: ");
Close(fhandle);
return 1;
}

fsize = Seek(fhandle, 0, OFFSET_BEGINNING);
printf("File size = %d\n", fsize);

Close(fhandle);
return 0;
}

文件系统

[编辑 | 编辑源代码]

设备、处理程序和文件系统必须是可重入的。

处理程序和文件系统的区别在于,文件系统需要公开目录结构和文件。隐含地,这意味着大约 60% 的 dos 包。

一般的经验法则是,将“虚拟”设备(没有底层硬件)实现为处理程序,而不是像 ram-handler 那样实现为完整的文件系统。显然,这不是铁律,但它是 OS 中的既定模式。

模拟外来文件系统属于完整文件系统的类别,但是,由于虚拟设备没有底层硬件,因此对设备的需求可能是一种浪费,最好将其实现为 fat-handler。

在“Assign DISMOUNT”之后?我不知道,但是 AROS 的 Assign 命令没有调用 ACTION_END,而 ACTION_END 是完全关闭处理程序所必需的?

文件系统可以使用 LDF_READ|LDF_DEVICES 锁定,但可以使用 LDF_READ|LDF_VOLUMES 解锁。

不应从 dl_DosList 中删除设备条目,也不应该卸载代码,直到所有关联的锁(直接或间接)都被释放。具体来说,如果一个设备挂载了介质(又名卷),任何尝试删除设备的尝试,无论是硬件设备还是虚拟设备,都必须被拒绝。检测设备是否挂载的最佳方法是在不触发提示用户“请插入卷 BLAH:”的请求的情况下,使用 LockDosList \ AttemptLockDosList,然后使用 FindDOSEntry。

struct Process * this_process; 
APTR old_window_ptr; 
BPTR lock;

this_process = (struct Process *)FindTask(NULL);

old_window_ptr = this_process->pr_WindowPtr; 
this_process->pr_WindowPtr = (APTR)-1;

UnLock(lock = Lock("device_name:",SHARED_LOCK));

this_process->pr_WindowPtr = old_window_ptr;

如果获得的锁不是 (BPTR)NULL,则你尝试的设备/卷/分配可用,否则不可用。请注意,此方法不专门检查设备,你必须扫描 DOSList 以进行检查。

鉴于 dl_Volume 和 dl_Device 是“配对”的,任何尝试删除设备的尝试都应验证设备的卷及其关联的锁,并返回一个失败,并带有一个适当的错误代码。

fm2000 源代码文档

文件系统决定最大大小,只要你正确地与文件系统通信,>4GB 是可能的。

它们仅受以下因素限制 -

  1. 在 64 位 DOS 扩展出现之前编写的软件,
  2. 没有使用这些扩展的软件,因为没有实际的“API”调用替换,它们需要直接与文件系统通信。

第一步是添加 64 位支持,以便它可以处理大于 4GB 的分区。在缓存中添加了新的代码来探测底层设备,以查看它是否支持 64 位扩展,然后如果收到对超过 4GB 边界的数据的请求,则使用 64 位读或写操作而不是标准操作(或者出错,如果探测没有找到任何 64 位扩展)。在 Amiga 世界中,有三种常用的 64 位扩展 - TD64(即 TrackDisk64)、新型 TD64 和 DirectSCSI。前两个是支持的,但 DirectSCSI 应该不难添加。

实现写回缓存,其中处理程序要求缓存写入一些数据,缓存立即报告成功,但仅将数据标记为“待写入”。然后,以固定间隔(例如五秒钟)将所有这些“脏”块一次性写入磁盘。这使得用户感觉速度更快,并且有可能减少磁盘活动(== 减少磨损和降低功耗),但存在在发生电源故障或设备丢失(例如拔出磁盘)的情况下丢失数据的风险。通常,可移动介质使用直写缓存(即立即写入),而固定磁盘使用写回缓存。

由于这需要一个单独的任务来坐等并在被调用时刷新脏块,这意味着缓存需要锁定。如果文件系统想要多线程(而缓存实际上是在 cache.library 中,对所有程序都可用),将来也需要锁定。到目前为止,在缓存操作周围有锁定,但在块操作周围没有锁定。

将读锁升级为写锁。通常在获取写锁之前需要先释放原始锁,这意味着有一段时间内不会持有任何锁,其他进程可能会在这个时间窗口内抢占锁。POSIX 线程的解决方法需要使用条件变量,而 AROS 信号量目前还没有条件变量。

参考文献

[编辑 | 编辑源代码]

数据包

[编辑 | 编辑源代码]

数据包(封装在 Dos 调用中的小消息)被发送到文件系统或处理程序,可以按如下分类:

* Basic Input/Output (handlers and file systems) - Open, Read (ACTION_READ), Write (ACTION_WRITE), Seek, Close, LockRecord, UnLockRecord, SetFileSize,
* File/Directory Manipulation/Information (handlers) - Lock, DupLock, UnLock, Examine, ExNext, ExAll, CreateDir, Rename, DeleteFile, 
* Volume Manipulation/Information - Info (ACTION_DISK_INFO), Relabel (ACTION_RENAME_DISK), Format (ACTION_FORMAT), 
* Handler Maintenance and Control - AddBuffers (ACTION_MORE_CACHE), Inhibit (ACTION_INHIBIT), 
* Handler Internal - ACTION_NIL, ACTION_READ_RETURN, ACTION_WRITE_RETURN, ACTION_TIMER 
* Console Only Packets (handler only - ignored by file system) - WaitForChar (ACTION_WAIT_CHAR), 
struct DosPacket {
   struct Message *dp_Link;	 /* EXEC message	      */
   struct MsgPort *dp_Port;	 /* Reply port for the packet */
				 /* Must be filled in each send. */
   LONG dp_Type;                 /* See ACTION_... 'R' means Read, 'W' means Write to the file system */
   LONG dp_Res1;                 /* result that would have been returned by the function, 
                                    e.g. Write ('W') returns actual
				  * length written */
   LONG dp_Res2;                 /* For file system calls - returned by IoErr() */
/*  Device packets common equivalents */
#define dp_Action  dp_Type
#define dp_Status  dp_Res1
#define dp_Status2 dp_Res2
#define dp_BufAddr dp_Arg1
   LONG dp_Arg1;
   LONG dp_Arg2;
   LONG dp_Arg3;
   LONG dp_Arg4;
   LONG dp_Arg5;
   LONG dp_Arg6;
   LONG dp_Arg7;
}; 
struct StandardPacket {
   struct Message   sp_Msg;
   struct DosPacket sp_Pkt;
}; /* StandardPacket */

/* Packet types */
#define ACTION_NIL		0
#define ACTION_STARTUP		0
#define ACTION_GET_BLOCK	2	/* OBSOLETE */
#define ACTION_SET_MAP		4
#define ACTION_DIE		5
#define ACTION_EVENT		6
#define ACTION_CURRENT_VOLUME	7
#define ACTION_LOCATE_OBJECT	8
#define ACTION_RENAME_DISK	9
#define ACTION_WRITE		'W'
#define ACTION_READ		'R'
#define ACTION_FREE_LOCK	15
#define ACTION_DELETE_OBJECT	16
#define ACTION_RENAME_OBJECT	17
#define ACTION_MORE_CACHE	18
#define ACTION_COPY_DIR		19
#define ACTION_WAIT_CHAR	20
#define ACTION_SET_PROTECT	21
#define ACTION_CREATE_DIR	22
#define ACTION_EXAMINE_OBJECT	23
#define ACTION_EXAMINE_NEXT	24
#define ACTION_DISK_INFO	25
#define ACTION_INFO		26
#define ACTION_FLUSH		27
#define ACTION_SET_COMMENT	28
#define ACTION_PARENT		29
#define ACTION_TIMER		30
#define ACTION_INHIBIT		31
#define ACTION_DISK_TYPE	32
#define ACTION_DISK_CHANGE	33
#define ACTION_SET_DATE		34
#define ACTION_SCREEN_MODE	994
#define ACTION_READ_RETURN	1001
#define ACTION_WRITE_RETURN	1002
#define ACTION_SEEK		1008
#define ACTION_FINDUPDATE	1004
#define ACTION_FINDINPUT	1005
#define ACTION_FINDOUTPUT	1006
#define ACTION_END		1007
#define ACTION_SET_FILE_SIZE	1022	/* fast file system only in 1.3 */
#define ACTION_WRITE_PROTECT	1023	/* fast file system only in 1.3 */

/* new 2.0 packets */
#define ACTION_SAME_LOCK	40
#define ACTION_CHANGE_SIGNAL	995
#define ACTION_FORMAT		1020
#define ACTION_MAKE_LINK	1021
/**/
/**/
#define ACTION_READ_LINK	1024
#define ACTION_FH_FROM_LOCK	1026
#define ACTION_IS_FILESYSTEM	1027
#define ACTION_CHANGE_MODE	1028
/**/
#define ACTION_COPY_DIR_FH	1030
#define ACTION_PARENT_FH	1031
#define ACTION_EXAMINE_ALL	1033
#define ACTION_EXAMINE_FH	1034
#define ACTION_LOCK_RECORD	2008
#define ACTION_FREE_RECORD	2009
#define ACTION_ADD_NOTIFY	4097
#define ACTION_REMOVE_NOTIFY	4098
#define	ACTION_SERIALIZE_DISK	4200
struct ErrorString {
	LONG  *estr_Nums;
	UBYTE *estr_Strings;
};

例如,AFS 处理程序尚未完全“dos 数据包化”。(“真实”dos 数据包和 FSA 内容不能一起工作)它们可以。我们与 Rob Norris 讨论过这个问题。基本思路是检查文件句柄或锁的 Port(或 Process)成员指向的内容。它既可以是 NT_PROCESS,也可以是 NT_DEVICE 类型的节点。这样就可以区分你正在与谁通信。此外,你的 con.handler 应该能够与 packet.handler 很好地协作。如果不能,则需要修复 packet.handler。

有一些问题,都与 AROS 的硬编码 32 位值等有关(例如,fib_Size)。对此最好的解决方法是什么?MorphOS 使用 DOS 函数和结构的 64 位版本,但我不知道 OS4 是不是这样。

OS4 使用以下 64 位数据包类型,因为我被要求在几年前为 WinUAE 目录文件系统仿真提供支持。

#define ACTION_CHANGE_FILE_POSITION64  8001
#define ACTION_GET_FILE_POSITION64    8002
#define ACTION_CHANGE_FILE_SIZE64      8003
#define ACTION_GET_FILE_SIZE64        8004

旧的数据包在实际大小大于等于 2G 时会返回文件大小为 2GB-1。我想我们需要更改 DoPkt 等函数以返回 QUAD?据我所知,DoPkt 和内部 dopacket 都需要更改以返回 QUAD,并且 DosPacket->dp_Res1 需要是 QUAD(据我所知,这会破坏兼容性)。我认为这比尝试将所有 dos 结构更改为使用 64 位值更可取,是吗?

如果说访问 blocknr/size/etc 的代码应该检查它们是否等于 0x7FFFFFFF,如果等于,则直接使用 64 位数据包调用,这样够了吗?

MorphOS、phase5、Ralph Babel 和一些 CBM 工程师定义了 TD64 标准。MorphOS dosextens.h 描述了他们的 64 位数据包扩展。

TD64 与 64 位 DOS 文件访问无关。是的,我们长期以来一直支持 TD64(以及 NSD)。如果没有它,AROS 就无法访问任何硬盘的第一个 4GB 以上的部分。

普通任务的限制在于它们不能调用 dos.library 的函数,也不能调用可能调用 dos.library 函数的函数。进程没有这个限制。

进程是一种扩展的任务。与任务相反,它可以使用 dos.library 的函数,因为进程结构包含一些特殊字段,涉及文件和目录。

struct Process {
    struct    pr_Task;    
    struct    pr_MsgPort; 
    WORD      pr_pad;
    BPTR      pr_SegList;
    LONG      pr_stackSize;
    APTR      pr_GlobVec;
    LONG      pr_TaskNum;
    BPTR      pr_StackBase;
    LONG      pr_Result2;
    BPTR      pr_CurrentDir;
    BPTR      pr_CIS;
    BPTR      pr_COS;
    APTR      pr_ConsoleTask;
    APTR      pr_FileSystemTask;
    BPTR      pr_CLI;
    APTR      pr_ReturnAddr;
    APTR      pr_PktWait;
    APTR      pr_WindowPtr;
    BPTR      pr_HomeDir;
    LONG      pr_Flags;
    APTR      pr_ExitCode;
    LONG      pr_ExitData;
    APTR      pr_Arguments;
    struct    pr_LocalVrs;
    APTR      pr_ShellPrivate;
    BPTR      pr_CES;
};

pr_Flags 标志

prb_FreeSegList
prb_FreeCurrDir
prb_FreeCli
prb_CloseInput
prb_CloseOutput
prb_FreeArgs

这比把所有东西都塞进全局变量要干净。假设你希望在稍微不同的数据上运行相同的线程代码(除非你有多个 CPU 内核,否则这样做意义不大,但无论如何),NP_UserData 允许你一遍又一遍地使用相同的代码,只需传递不同的起始数据即可。当然,你可以设置一个消息端口,并以这种方式进行操作,但是对于简单任务来说,传递一个指向数据的直接指针并使用信号量更容易。你几乎可以共享进程之间的任何库指针。

每个使用 bsdsocket.library 的进程都必须自行打开该库。不允许共享 bsdsocketbase。

一般来说,任务应该共享相同的地址空间,而进程不应共享,至少出于这个原因,每个进程都应该单独重新打开库。

由于人们不遵守这些规则,因此无法在系统中引入内存保护机制。

最简单的方法是调用 CreateNewProc(),不带 NP_Input、NP_Output、NP_Error 的标记,这样会为子进程打开一个默认的“NIL:”流。

int ProcEntry () { 
struct Process *proc; 
struct Message *msg; 
proc = (struct Process *)FindTask(NULL); 
WaitPort(&proc->pr_MsgPort); 
msg = GetMsg(&proc->pr_MsgPort); 
/* ... */ 
}

正确地(使用信号量)保护任何你打算在线程之间共享的资源,例如 IO 句柄等,所有这些都应该没问题。

CreateNewProc() 不应该创建 BCPL 堆栈帧和寄存器设置(A5=BCPL_jsr 和其他相关的奇怪行为),只有 RunCommand() 需要这样做。可以理解为什么会有混淆,因为 CreateNewProc() 需要调用 BCPL_init(),而 BCPL_init() 实际上只执行 BCPL 设置的一部分(愚蠢的 segarray 和一些 globvec 内容),但它不应该设置 BCPL 堆栈帧(当所有进程条目都期望 SysBase = 崩溃时,它会用 BCPL_rts 替换 A6)。

CreateNewProc()->CallEntry() 应该与以前一样。

 argPtr = A0, argSize = D0, SysBase = A6, no stack swap

RunProcess() 应该包含疯狂的 BCPL 内容。

为什么要进行这种更改?我不明白它对其他架构有什么帮助,它肯定对 m68k 没有帮助。但它仍然应该设置 pr_ReturnAddr,对吧?不,因为 pr_ReturnAddr 仅由 RunProcess()/RunCommand() 的退出使用。

dos/Exit() 适用于使用 Create(New)Proc() 启动的正常进程。它不是 BCPL 特定的。(但也许它在“BCPL 模式”下的工作方式不同,我还没有测试过)AROS/DOS/Exit() 应该是一个空操作。Exit() 的唯一调用者是 BCPL 例程,并且在 arch/m68k-amiga/dos/bcpl.S 中有一个 BCPL 特定的实现来支持这些旧程序。

Dos/Exit() 是 AmigaOS 中的一个错误,我们不应该把它变成一个一等函数。要实现一个 C 风格的退出,它应该在 AROS C 库中,实现内存释放和库关闭等功能。

了解更多信息 请点击这里

DateStamp 结构如下所示

struct DateStamp
{
  LONG ds_Days;      /* days since 01-Jan-1978 */
  LONG ds_Minute;    /* minutes past midnight */
  LONG ds_Tick;      /* ticks past the last minute */
};

涉及四个公共结构:DosLibrary (dl_)、RootNode (rn_)、DosInfo (di_) 和 DevInfo (dvi_)。重新审视了 DOSBase,并从中删除了几乎所有 AROS 特定的字段。

dl_DevInfo - 在 struct DosInfo 中用 di_DevInfo 替换。

dl_SegList - 根本没有使用,dos.library 是 ROM 常驻的,没有自己的段列表。

dl_ResList - 已删除,现在它是 DosInfo->di_ResList。

唯一剩下的就是 dl_Flags。DirectoryOpus 在 AROS 上使用了它。现在可以用 rn_Flags 正确替换它吗,或者应该在 ABI v1 中进行此操作?其他私有字段仍然存在,它们确实是私有的。

struct RootNode {
    BPTR rn_TaskArray;
    BPTR rn_ConsoleSegment;
    struct DateStamp rn_time;
    LONG rn_RestartSeg;
    BPTR rn_Info;
    BPTR rn_FileHandlerSegment;
};
struct DosInfo {
    BPTR di_McName;
    BPTR di_DevInfo;
    BPTR di_Devices;
    BPTR di_Handlers;
    BPTR di_NextEntry;
    LONG di_UseCount;
    BPTR di_SegPtr;
    BPTR di_SegName;
};
struct DevInfo {
    BPTR dvi_Next;
    LONG dvi_Type;
    APTR dvi_Task;
    BPTR dvi_Lock;
    BPTR dvi_Handler;
    LONG dvi_StackSize;
    LONG dvi_Priority;
    LONG dvi_Startup;
    BPTR dvi_SegList;
    BPTR dvi_GlobVec;
    BPTR dvi_Name;
};

在 FGetC-s 之后是 Seek-s,然后是 Read。所有这些都是针对同一个 file_handle。我没有检查参数和具体发生了什么,但这与精确内存分配的模式类似:使用 'getc',你以一步一步的方式读取文件缓冲区,并且只计算字符或字节,直到你到达你想要读取的单词、行、文件或任何内容的结尾。然后你 'seek' 回到开始的位置,你 'alloc' 计算出的内存大小,然后你 'read' 整个内容一次。这是一种避免内存相关问题的方法,但它在 i/o 方面可能相当繁重。

与 C 中的 (f)getc 类似,FGetC 是一个旨在被频繁调用的函数。它通常用作传递给解析函数的函数指针。使用 fscanf 等的程序会大量使用 FGetC。由于它是缓冲的,所以我怀疑它是一个性能瓶颈(除非你当然修补它,并在每次调用时在控制台上打印一行)。

#include <proto/dos.h>
#include <proto/utility.h>

UBYTE get_char()
{
    UBYTE buffer;
    BPTR in = Input();

    SetMode (in,1); /* set to RAW mode */
    Read (in,&buffer,1);
    SetMode (in,0); /* set to CON mode */

    if (buffer == '\r')
    buffer = '\n';

    return (ToUpper (buffer));
}

int main (void)

{
    UBYTE key;

    Printf ("Please press a key: ");
    Flush (Output());

    key = get_char();

    Printf ("\nThe key you pressed is %lc\n",key);

    return (0);
}
BPTR Open(CONST_STRPTR name, LONG accessMode) (D1,D2)
BOOL Close(BPTR file) (D1)
LONG Read(BPTR file, APTR buffer, LONG length) (D1, D2, D3)
LONG Write(BPTR file, CONST_APTR buffer, LONG length) (D1, D2, D3)
BPTR Input() ()
BPTR Output() ()
LONG Seek(BPTR file, LONG position, LONG mode) (D1,D2,D3)
BOOL DeleteFile(CONST_STRPTR name) (D1)
LONG Rename(CONST_STRPTR oldName, CONST_STRPTR newName) (D1,D2)
BPTR Lock(CONST_STRPTR name, LONG accessMode) (D1,D2)
BOOL UnLock(BPTR lock) (D1)
BPTR DupLock(BPTR lock) (D1)
LONG Examine(BPTR lock, struct FileInfoBlock* fib) (D1,D2)
LONG ExNext(BPTR lock, struct FileInfoBlock* fileInfoBlock) (D1,D2)
LONG Info(BPTR lock, struct InfoData* parameterBlock) (D1,D2)
BPTR CreateDir(CONST_STRPTR name) (D1)
BPTR CurrentDir(BPTR lock) (D1)
SIPTR IoErr() ()
struct MsgPort* CreateProc(CONST_STRPTR name, LONG pri, BPTR segList, LONG stackSize) (D1,D2,D3,D4)
void Exit(LONG returnCode) (D1)
BPTR LoadSeg(CONST_STRPTR name) (D1)
BOOL UnLoadSeg(BPTR seglist) (D1)
struct MsgPort* RunHandler(struct DeviceNode *devnode, const char *path) (A0,A1)

struct Device *DeviceProc(CONST_STRPTR name) (D1)
LONG SetComment(CONST_STRPTR name, CONST_STRPTR comment) (D1,D2)
LONG SetProtection(CONST_STRPTR name, ULONG protect) (D1,D2)
struct DateStamp *DateStamp(struct DateStamp *date) (D1)
void Delay(ULONG timeout) (D1)
LONG WaitForChar(BPTR file, LONG timeout) (D1,D2)
BPTR ParentDir(BPTR lock) (D1)
LONG IsInteractive(BPTR file) (D1)
LONG Execute(CONST_STRPTR string, BPTR input, BPTR output) (D1,D2,D3)
APTR AllocDosObject(ULONG type, struct TagItem *tags) (D1,D2)
void FreeDosObject(ULONG type, APTR ptr) (D1,D2)

LONG DoPkt(struct MsgPort* port, LONG action, SIPTR arg1, SIPTR arg2, SIPTR arg3, SIPTR arg4, SIPTR arg5) 
void SendPkt(struct DosPacket *dp, struct MsgPort *port, struct MsgPort *replyport) (D1,D2,D3)
struct DosPacket *WaitPkt() ()
void ReplyPkt(struct DosPacket *dp, LONG res1, LONG res2) (D1,D2,D3)
void AbortPkt(struct MsgPort *port, struct DosPacket *pkt) (D1,D2)
BOOL LockRecord(BPTR fh, ULONG offset, ULONG length, ULONG mode, ULONG timeout) (D1,D2,D3,D4,D5)
BOOL LockRecords(struct RecordLock *recArray, ULONG timeout) (D1,D2)
BOOL UnLockRecord(BPTR fh, ULONG offset, ULONG length) (D1,D2,D3)
BOOL UnLockRecords(struct RecordLock * recArray) (D1)
BPTR SelectInput(BPTR fh) (D1)
BPTR SelectOutput(BPTR fh) (D1)

LONG FGetC(BPTR file) (D1)
LONG FPutC(BPTR file, LONG character) (D1,D2)
LONG UnGetC(BPTR file, LONG character) (D1,D2)
LONG FRead(BPTR fh, APTR block, ULONG blocklen, ULONG number) (D1,D2,D3,D4)
LONG FWrite(BPTR fh, CONST_APTR block, ULONG blocklen, ULONG numblocks) (D1,D2,D3,D4)
STRPTR FGets(BPTR fh, STRPTR buf, ULONG buflen) (D1,D2,D3)
LONG FPuts(BPTR file, CONST_STRPTR string) (D1,D2)
LONG VFWritef(BPTR fh, CONST_STRPTR fmt, const IPTR *argarray) (D1,D2,D3)
LONG VFPrintf(BPTR file, CONST_STRPTR format, const IPTR *argarray) (D1,D2,D3)

LONG Flush(BPTR file) (D1)
LONG SetVBuf(BPTR file, STRPTR buff, LONG type, LONG size) (D1,D2,D3,D4)
BPTR DupLockFromFH(BPTR lock) (D1)
BPTR OpenFromLock(BPTR lock) (D1)
BPTR ParentOfFH(BPTR fh) (D1)
BOOL ExamineFH(BPTR fh, struct FileInfoBlock* fib) (D1,D2)
BOOL SetFileDate(CONST_STRPTR name, const struct DateStamp *date) (D1,D2)
BOOL NameFromLock(BPTR lock, STRPTR buffer, LONG length) (D1,D2,D3)
BOOL NameFromFH(BPTR fh, STRPTR buffer, LONG length) (D1,D2,D3)
LONG SplitName(CONST_STRPTR name, ULONG separator, STRPTR buf, LONG oldpos, LONG size) (D1,D2,D3,D4,D5)
LONG SameLock(BPTR lock1, BPTR lock2) (D1,D2)
LONG SetMode(BPTR fh, LONG mode) (D1,D2)
BOOL ExAll(BPTR lock, struct ExAllData *buffer, LONG size, LONG data, struct ExAllControl *control) (D1,D2,D3,D4,D5)
LONG ReadLink(struct MsgPort *port, BPTR lock, CONST_STRPTR path, STRPTR buffer, ULONG size) (D1,D2,D3,D4,D5)
LONG MakeLink(CONST_STRPTR name, APTR dest, LONG soft) (D1,D2,D3)
BOOL ChangeMode(ULONG type, BPTR object, ULONG newmode) (D1,D2,D3)
LONG SetFileSize(BPTR file, LONG offset, LONG mode) (D1,D2,D3)
SIPTR SetIoErr(SIPTR result) (D1)
BOOL Fault(LONG code, CONST_STRPTR header, STRPTR buffer, LONG len) (D1,D2,D3,D4)
BOOL PrintFault(LONG code, CONST_STRPTR header) (D1,D2)
BOOL ErrorReport(LONG code, LONG type, IPTR arg1, struct MsgPort *device) (D1,D2,D3,D4)
LONG DisplayError(CONST_STRPTR formatStr, ULONG flags, APTR args) (A0,D0,A1)
struct CommandLineInterface *Cli() ()
struct Process *CreateNewProc(const struct TagItem *tags) (D1)
   NP_Seglist, NP_FreeSeglist, NP_Entry, NP_Input, NP_Output, NP_Error, NP_CloseInput, NP_CloseOutput, NP_CloseError
   NP_CurrentDir, NP_StackSize, NP_Name, NP_Priority, NP_CopyVars, NP_Path, NP_Arguments, NP_ConsoleTask
   NP_WindowPtr, NP_HomeDir, NP_Cli, NP_CommandName, NP_NotifyOnDeath, NP_Synchronous, NP_ExitCode, NP_ExitData
   NP_UserData
   TAG_DONE
LONG RunCommand(BPTR segList, ULONG stacksize, STRPTR argptr, ULONG argsize) (D1,D2,D3,D4)

struct MsgPort *GetConsoleTask() ()
struct MsgPort *SetConsoleTask(struct MsgPort *handler) (D1)
struct MsgPort *GetFileSysTask() ()
struct MsgPort *SetFileSysTask(struct MsgPort *task) (D1)
STRPTR GetArgStr() ()
STRPTR SetArgStr(CONST_STRPTR string) (D1)
struct Process *FindCliProc(ULONG num) (D1)
ULONG MaxCli() ()
BOOL SetCurrentDirName(CONST_STRPTR name) (D1)
BOOL GetCurrentDirName(STRPTR buf, LONG len) (D1,D2)
BOOL SetProgramName(CONST_STRPTR name) (D1)
BOOL GetProgramName(STRPTR buf, LONG len) (D1,D2)
BOOL SetPrompt(CONST_STRPTR name) (D1)
BOOL GetPrompt(STRPTR buf, LONG len) (D1,D2)
BPTR SetProgramDir(BPTR lock) (D1)
BPTR GetProgramDir() ()
LONG SystemTagList(CONST_STRPTR command, const struct TagItem *tags) (D1,D2)
LONG AssignLock(CONST_STRPTR name, BPTR lock) (D1,D2)
BOOL AssignLate(CONST_STRPTR name, CONST_STRPTR path) (D1,D2)
BOOL AssignPath(CONST_STRPTR name, CONST_STRPTR path) (D1,D2)
BOOL AssignAdd(CONST_STRPTR name, BPTR lock) (D1,D2)
LONG RemAssignList(CONST_STRPTR name, BPTR lock) (D1,D2)
struct DevProc *GetDeviceProc(CONST_STRPTR name, struct DevProc *dp) (D1,D2)
void FreeDeviceProc(struct DevProc *dp) (D1)
struct DosList *LockDosList(ULONG flags) (D1)
void UnLockDosList(ULONG flags) (D1)
struct DosList *AttemptLockDosList(ULONG flags) (D1)

LONG RemDosEntry(struct DosList *dlist) (D1)
LONG AddDosEntry(struct DosList *dlist) (D1)
struct DosList *FindDosEntry(struct DosList *dlist, CONST_STRPTR name, ULONG flags) (D1,D2,D3)
struct DosList *NextDosEntry(struct DosList *dlist, ULONG flags) (D1,D2)
struct DosList * MakeDosEntry(CONST_STRPTR name, LONG type) (D1,D2)
void FreeDosEntry(struct DosList *dlist) (D1)
BOOL IsFileSystem(CONST_STRPTR devicename) (D1)
BOOL Format(CONST_STRPTR devicename, CONST_STRPTR volumename, ULONG dostype) (D1,D2,D3)
LONG Relabel(CONST_STRPTR drive, CONST_STRPTR newname) (D1,D2)
LONG Inhibit(CONST_STRPTR name, LONG onoff) (D1,D2)
BOOL AddBuffers(CONST_STRPTR devicename, LONG numbuffers) (D1,D2)
LONG CompareDates(const struct DateStamp *date1, const struct DateStamp *date2) (D1,D2)
BOOL DateToStr(struct DateTime *datetime) (D1)
BOOL StrToDate(struct DateTime *datetime) (D1)
BPTR InternalLoadSeg(BPTR fh, BPTR table, LONG_FUNC *functionarray, LONG *stack) (D0,A0,A1,A2)
BOOL InternalUnLoadSeg(BPTR seglist, VOID_FUNC freefunc) (D1,A1)
BPTR NewLoadSeg(CONST_STRPTR file, const struct TagItem *tags) (D1,D2)
BOOL AddSegment(CONST_STRPTR name, BPTR seg, LONG type) (D1,D2,D3)
struct Segment *FindSegment(CONST_STRPTR name, struct Segment *seg, BOOL system) (D1,D2,D3)
LONG RemSegment(struct Segment *seg) (D1)
LONG CheckSignal(LONG mask) (D1)

struct RDArgs *ReadArgs(CONST_STRPTR template, IPTR *array, struct RDArgs *rdargs) (D1,D2,D3)
LONG FindArg(CONST_STRPTR template, CONST_STRPTR keyword) (D1,D2)
LONG ReadItem(STRPTR buffer, LONG maxchars, struct CSource *input) (D1,D2,D3)
LONG StrToLong(CONST_STRPTR string, LONG *value) (D1,D2)
LONG MatchFirst(CONST_STRPTR pat, struct AnchorPath *AP) (D1,D2)
LONG MatchNext(struct AnchorPath *AP) (D1)
void MatchEnd(struct AnchorPath *AP) (D1)
LONG ParsePattern(CONST_STRPTR Source, STRPTR Dest, LONG DestLength) (D1,D2,D3)
BOOL MatchPattern(CONST_STRPTR pat, CONST_STRPTR str) (D1,D2)
BPTR Error() ()
void FreeArgs(struct RDArgs *args) (D1)

BPTR SelectError(BPTR fh) (D1)
STRPTR FilePart(CONST_STRPTR path) (D1)
STRPTR PathPart(CONST_STRPTR path) (D1)
BOOL AddPart(STRPTR dirname, CONST_STRPTR filename, ULONG size) (D1,D2,D3)
BOOL StartNotify(struct NotifyRequest *notify) (D1)
void EndNotify(struct NotifyRequest *notify) (D1)
BOOL SetVar(CONST_STRPTR name, CONST_STRPTR buffer, LONG size, LONG flags) (D1,D2,D3,D4)
LONG GetVar(CONST_STRPTR name, STRPTR buffer, LONG size, LONG flags) (D1,D2,D3,D4)
LONG DeleteVar(CONST_STRPTR name, ULONG flags) (D1,D2)
struct LocalVar *FindVar(CONST_STRPTR name, ULONG type) (D1,D2)
STRPTR DosGetLocalizedString(LONG stringNum) (D1)
IPTR CliInitNewcli(struct DosPacket *dp) (A0)
IPTR CliInitRun(struct DosPacket *dp) (A0)
LONG WriteChars(CONST_STRPTR buf, ULONG buflen) (D1,D2)
LONG PutStr(CONST_STRPTR string) (D1)
LONG VPrintf(CONST_STRPTR format, IPTR *argarray) (D1,D2)
LONG Pipe(CONST_STRPTR name, BPTR *reader, BPTR *writer) (D1,D2,D3)
LONG ParsePatternNoCase(CONST_STRPTR Source, STRPTR Dest, LONG DestLength) (D1,D2,D3)
BOOL MatchPatternNoCase(CONST_STRPTR pat, CONST_STRPTR str) (D1,D2)
STRPTR DosGetString(LONG stringNum) (D0)
BOOL SameDevice(BPTR lock1, BPTR lock2) (D1,D2)
void ExAllEnd(BPTR lock, struct ExAllData *buffer, LONG size, LONG data, struct ExAllControl *control)  
BOOL SetOwner(CONST_STRPTR name, ULONG owner_info) (D1,D2)
LONG ScanVars(struct Hook * hook, ULONG flags, APTR userdata) (D1,D2,D3)
华夏公益教科书