home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 24 / AACD 24.iso / AACD / Online / smbfs / source / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-06-29  |  113.6 KB  |  5,644 lines

  1. /*
  2.  * $Id: main.c,v 1.66 2001/06/29 06:47:06 olsen Exp $
  3.  *
  4.  * :ts=4
  5.  *
  6.  * SMB file system wrapper for AmigaOS, using the AmiTCP V3 API
  7.  *
  8.  * Copyright (C) 2000-2001 by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  *
  24.  * smbfs arbeitsgruppe pcguest debug=2 //sourcery/all
  25.  */
  26.  
  27. #include "system_headers.h"
  28. #include "assert.h"
  29.  
  30. /****************************************************************************/
  31.  
  32. #include "smb_abstraction.h"
  33.  
  34. /****************************************************************************/
  35.  
  36. #include "smbfs_rev.h"
  37. STRPTR Version = VERSTAG;
  38.  
  39. /****************************************************************************/
  40.  
  41. #define SAME (0)
  42. #define OK (0)
  43. #define NOT !
  44. #define ZERO ((BPTR)NULL)
  45.  
  46. /****************************************************************************/
  47.  
  48. #ifdef __SASC
  49. #define FAR __far
  50. #define ASM __asm
  51. #define REG(x) register __ ## x
  52. #define INLINE __inline
  53. #else
  54. #define FAR
  55. #define ASM
  56. #define REG(x)
  57. #define INLINE
  58. #endif /* __SASC */
  59.  
  60. /****************************************************************************/
  61.  
  62. #define UNIX_TIME_OFFSET 252460800
  63. #define MAX_FILENAME_LEN 256
  64.  
  65. /****************************************************************************/
  66.  
  67. #define SMB_ROOT_DIR_NAME    "\\"
  68. #define SMB_PATH_SEPARATOR    '\\'
  69.  
  70. /****************************************************************************/
  71.  
  72. typedef STRPTR    KEY;
  73. typedef LONG *    NUMBER;
  74. typedef LONG    SWITCH;
  75.  
  76. /****************************************************************************/
  77.  
  78. struct FileNode
  79. {
  80.     struct MinNode        fn_MinNode;
  81.     struct FileHandle *    fn_Handle;
  82.     LONG                fn_Offset;
  83.     LONG                fn_Mode;
  84.     smba_file_t *        fn_File;
  85.     STRPTR                fn_FullName;
  86. };
  87.  
  88. struct LockNode
  89. {
  90.     struct MinNode    ln_MinNode;
  91.     struct FileLock    ln_FileLock;
  92.     smba_file_t *    ln_File;
  93.     BOOL            ln_RestartExamine;
  94.     UWORD            ln_Pad;
  95.     STRPTR            ln_FullName;
  96. };
  97.  
  98. /****************************************************************************/
  99.  
  100. /* These are in amiga.lib */
  101. APTR ASM AsmCreatePool(REG(d0) ULONG memFlags,REG(d1) ULONG puddleSize,REG(d2) ULONG threshSize,REG(a6) struct Library * SysBase);
  102. VOID ASM AsmDeletePool(REG(a0) APTR poolHeader,REG(a6) struct Library * SysBase);
  103. APTR ASM AsmAllocPooled(REG(a0) APTR poolHeader,REG(d0) ULONG memSize,REG(a6) struct Library * SysBase);
  104. VOID ASM AsmFreePooled(REG(a0) APTR poolHeader,REG(a1) APTR memory,REG(d0) ULONG memSize,REG(a6) struct Library * SysBase);
  105.  
  106. /****************************************************************************/
  107.  
  108. /* Forward declarations for local routines. */
  109. STATIC VOID DisplayErrorList(VOID);
  110. STATIC VOID AddError(STRPTR fmt, va_list args);
  111. STATIC LONG CVSPrintf(STRPTR format_string, va_list args);
  112. STATIC VOID VSPrintf(STRPTR buffer, STRPTR formatString, va_list args);
  113. STATIC VOID SendDiskChange(ULONG class);
  114. STATIC struct FileNode *FindFileNode(STRPTR name, struct FileNode *skip);
  115. STATIC struct LockNode *FindLockNode(STRPTR name, struct LockNode *skip);
  116. STATIC LONG CheckAccessModeCollision(STRPTR name, LONG mode);
  117. STATIC LONG NameAlreadyInUse(STRPTR name);
  118. STATIC BOOL IsReservedName(STRPTR name);
  119. STATIC LONG MapErrnoToIoErr(int error);
  120. STATIC VOID INLINE TranslateBName(UBYTE *name, UBYTE *map);
  121. STATIC VOID INLINE TranslateCName(UBYTE *name, UBYTE *map);
  122. STATIC BOOL ReallyRemoveDosEntry(struct DosList *entry);
  123. STATIC VOID Cleanup(VOID);
  124. STATIC BOOL Setup(STRPTR program_name, STRPTR service, STRPTR workgroup, STRPTR username, STRPTR opt_password, BOOL opt_changecase, STRPTR opt_clientname, STRPTR opt_servername, int opt_cachesize, LONG * opt_time_zone_offset, STRPTR device_name, STRPTR volume_name, STRPTR translation_file);
  125. STATIC VOID INLINE ConvertBString(LONG max_len, STRPTR cstring, APTR bstring);
  126. STATIC VOID INLINE ConvertCString(LONG max_len, APTR bstring, STRPTR cstring);
  127. STATIC LONG BuildFullName(STRPTR parent_name, STRPTR name, STRPTR *result_ptr);
  128. STATIC BPTR Action_Parent(struct FileLock *parent, LONG *error_ptr);
  129. STATIC LONG Action_DeleteObject(struct FileLock *parent, APTR bcpl_name, LONG *error_ptr);
  130. STATIC BPTR Action_CreateDir(struct FileLock *parent, APTR bcpl_name, LONG *error_ptr);
  131. STATIC BPTR Action_LocateObject(struct FileLock *parent, APTR bcpl_name, LONG mode, LONG *error_ptr);
  132. STATIC BPTR Action_CopyDir(struct FileLock *lock, LONG *error_ptr);
  133. STATIC LONG Action_FreeLock(struct FileLock *lock, LONG *error_ptr);
  134. STATIC LONG Action_SameLock(struct FileLock *lock1, struct FileLock *lock2, LONG *error_ptr);
  135. STATIC LONG Action_SetProtect(struct FileLock *parent, APTR bcpl_name, LONG mask, LONG *error_ptr);
  136. STATIC LONG Action_RenameObject(struct FileLock *source_lock, APTR source_bcpl_name, struct FileLock *destination_lock, APTR destination_bcpl_name, LONG *error_ptr);
  137. STATIC LONG Action_DiskInfo(struct InfoData *id, LONG *error_ptr);
  138. STATIC LONG Action_Info(struct FileLock *lock, struct InfoData *id, LONG *error_ptr);
  139. STATIC LONG Action_ExamineObject(struct FileLock *lock, struct FileInfoBlock *fib, LONG *error_ptr);
  140. STATIC BOOL NameIsAcceptable(STRPTR name, LONG max_len);
  141. STATIC LONG Action_ExamineNext(struct FileLock *lock, struct FileInfoBlock *fib, LONG *error_ptr);
  142. STATIC LONG Action_ExamineAll(struct FileLock *lock, struct ExAllData *ed, ULONG size, ULONG type, struct ExAllControl *eac, LONG *error_ptr);
  143. STATIC LONG Action_Find(LONG action, struct FileHandle *fh, struct FileLock *parent, APTR bcpl_name, LONG *error_ptr);
  144. STATIC LONG Action_Read(struct FileNode *fn, APTR mem, LONG length, LONG *error_ptr);
  145. STATIC LONG Action_Write(struct FileNode *fn, APTR mem, LONG length, LONG *error_ptr);
  146. STATIC LONG Action_End(struct FileNode *fn, LONG *error_ptr);
  147. STATIC LONG Action_Seek(struct FileNode *fn, LONG position, LONG mode, LONG *error_ptr);
  148. STATIC LONG Action_SetFileSize(struct FileNode *fn, LONG position, LONG mode, LONG *error_ptr);
  149. STATIC LONG Action_SetDate(struct FileLock *parent, APTR bcpl_name, struct DateStamp *ds, LONG *error_ptr);
  150. STATIC LONG Action_ExamineFH(struct FileNode *fn, struct FileInfoBlock *fib, LONG *error_ptr);
  151. STATIC BPTR Action_ParentFH(struct FileNode *fn, LONG *error_ptr);
  152. STATIC BPTR Action_CopyDirFH(struct FileNode *fn, LONG *error_ptr);
  153. STATIC LONG Action_FHFromLock(struct FileHandle *fh, struct FileLock *fl, LONG *error_ptr);
  154. STATIC LONG Action_RenameDisk(APTR bcpl_name, LONG *error_ptr);
  155. STATIC LONG Action_ChangeMode(LONG type, APTR object, LONG new_mode, LONG *error_ptr);
  156. STATIC LONG Action_WriteProtect(LONG flag, ULONG key, LONG *error_ptr);
  157. STATIC LONG Action_MoreCache(LONG buffer_delta, LONG *error_ptr);
  158. STATIC LONG Action_SetComment(struct FileLock *parent, APTR bcpl_name, APTR bcpl_comment, LONG *error_ptr);
  159. STATIC VOID HandleFileSystem(STRPTR device_name, STRPTR volume_name, STRPTR service_name);
  160.  
  161. /****************************************************************************/
  162.  
  163. VOID ReportError(STRPTR fmt,...);
  164. VOID SPrintf(STRPTR buffer, STRPTR formatString,...);
  165.  
  166. /****************************************************************************/
  167.  
  168. struct Library *            SysBase;
  169. struct Library *            DOSBase;
  170. struct Library *            UtilityBase;
  171. struct Library *            SocketBase;
  172. struct Library *            LocaleBase;
  173. struct Locale *                Locale;
  174. struct Device *                TimerBase;
  175. struct timerequest            TimerRequest;
  176. struct Library *            IconBase;
  177.  
  178. /****************************************************************************/
  179.  
  180. int                            errno;
  181. int                            h_errno;
  182.  
  183. /****************************************************************************/
  184.  
  185. STATIC struct DosList *        DeviceNode;
  186. STATIC BOOL                    DeviceNodeAdded;
  187. STATIC struct DosList *        VolumeNode;
  188. STATIC BOOL                    VolumeNodeAdded;
  189. STATIC struct MsgPort *        FileSystemPort;
  190.  
  191. STATIC smba_server_t *        ServerData;
  192.  
  193. STATIC BOOL                    Quit;
  194. STATIC BOOL                    Quiet;
  195. STATIC BOOL                    CaseSensitive;
  196. STATIC BOOL                    OmitHidden;
  197.  
  198. STATIC LONG                    TimeZoneOffset;
  199. STATIC BOOL                    OverrideLocaleTimeZone;
  200.  
  201. STATIC BOOL                    WriteProtected;
  202. STATIC ULONG                WriteProtectKey;
  203.  
  204. STATIC struct MinList        FileList;
  205. STATIC struct MinList        LockList;
  206.  
  207. STATIC APTR                    MemoryPool;
  208.  
  209. STATIC struct RDArgs *        Parameters;
  210. STATIC struct DiskObject *    Icon;
  211.  
  212. STATIC struct WBStartup *     WBStartup;
  213.  
  214. STATIC struct MinList        ErrorList;
  215.  
  216. STATIC STRPTR                NewProgramName;
  217.  
  218. STATIC BOOL                    TranslateNames;
  219. STATIC UBYTE                A2M[256];
  220. STATIC UBYTE                M2A[256];
  221.  
  222. /****************************************************************************/
  223.  
  224. extern struct Library * FAR    AbsExecBase;
  225.  
  226. /****************************************************************************/
  227.  
  228. LONG
  229. Main(VOID)
  230. {
  231.     struct
  232.     {
  233.         KEY        Workgroup;
  234.         KEY        UserName;
  235.         KEY        Password;
  236.         SWITCH    ChangeCase;
  237.         SWITCH    CaseSensitive;
  238.         SWITCH    OmitHidden;
  239.         SWITCH    Quiet;
  240.         KEY        ClientName;
  241.         KEY        ServerName;
  242.         KEY        DeviceName;
  243.         KEY        VolumeName;
  244.         NUMBER    CacheSize;
  245.         NUMBER    DebugLevel;
  246.         NUMBER    TimeZoneOffset;
  247.         KEY        TranslationFile;
  248.         KEY        Service;
  249.     } args;
  250.  
  251.     STRPTR cmd_template =
  252.         "DOMAIN=WORKGROUP/K,"
  253.         "USER=USERNAME/K,"
  254.         "PASSWORD/K,"
  255.         "CHANGECASE/S,"
  256.         "CASE=CASESENSITIVE/S,"
  257.         "OMITHIDDEN/S,"
  258.         "QUIET/S,"
  259.         "CLIENT=CLIENTNAME/K,"
  260.         "SERVER=SERVERNAME/K,"
  261.         "DEVICE=DEVICENAME/K,"
  262.         "VOLUME=VOLUMENAME/K,"
  263.         "CACHE=CACHESIZE/N/K,"
  264.         "DEBUGLEVEL=DEBUG/N/K,"
  265.         "TZ=TIMEZONEOFFSET/N/K,"
  266.         "TRANSLATE=TRANSLATIONFILE/K,"
  267.         "SERVICE/A";
  268.  
  269.     struct Process * this_process;
  270.     UBYTE program_name[MAX_FILENAME_LEN];
  271.     LONG result;
  272.     LONG number;
  273.     LONG other_number;
  274.     LONG cache_size = 0;
  275.     char env_workgroup_name[17];
  276.     char env_user_name[64];
  277.     char env_password[64];
  278.  
  279.     geta4();
  280.  
  281.     SysBase = AbsExecBase;
  282.  
  283.     /* Pick up the Workbench startup message, if
  284.      * there is one.
  285.      */
  286.     this_process = (struct Process *)FindTask(NULL);
  287.     if(this_process->pr_CLI == ZERO)
  288.     {
  289.         WaitPort(&this_process->pr_MsgPort);
  290.         WBStartup = (struct WBStartup *)GetMsg(&this_process->pr_MsgPort);
  291.     }
  292.     else
  293.     {
  294.         WBStartup = NULL;
  295.     }
  296.  
  297.     /* Don't emit any debugging output before we are ready. */
  298.     SETDEBUGLEVEL(0);
  299.  
  300.     /* Open the libraries we need and check
  301.      * whether we could get them.
  302.      */
  303.     DOSBase = OpenLibrary("dos.library",0);
  304.     UtilityBase = OpenLibrary("utility.library",37);
  305.  
  306.     if(UtilityBase == NULL || DOSBase == NULL || DOSBase->lib_Version < 37)
  307.     {
  308.         /* Complain loudly if this is not the operating
  309.          * system version we expected.
  310.          */
  311.         if(DOSBase != NULL && this_process->pr_CLI != ZERO)
  312.         {
  313.             STRPTR msg = "AmigaOS 2.04 or higher required.\n";
  314.  
  315.             Write(Output(),msg,strlen(msg));
  316.         }
  317.  
  318.         Cleanup();
  319.  
  320.         return(RETURN_FAIL);
  321.     }
  322.  
  323.     /* This needs to be set up properly for error report
  324.      * to work.
  325.      */
  326.     NewList((struct List *)&ErrorList);
  327.  
  328.     memset(&args,0,sizeof(args));
  329.  
  330.     /* If this program was launched from Workbench,
  331.      * parameter passing will have to be handled
  332.      * differently.
  333.      */
  334.     if(WBStartup != NULL)
  335.     {
  336.         STRPTR str;
  337.         BPTR old_dir;
  338.         LONG n;
  339.  
  340.         if(WBStartup->sm_NumArgs > 1)
  341.             n = 1;
  342.         else
  343.             n = 0;
  344.  
  345.         /* Get the name of the program, as it was launched
  346.          * from Workbench. We actually prefer the name of
  347.          * the first project file, if there is one.
  348.          */
  349.         strncpy(program_name,WBStartup->sm_ArgList[n].wa_Name,sizeof(program_name)-1);
  350.         program_name[sizeof(program_name)-1] = '\0';
  351.  
  352.         /* Now open icon.library and read that icon. */
  353.         IconBase = OpenLibrary("icon.library",0);
  354.         if(IconBase == NULL)
  355.         {
  356.             ReportError("Could not open 'icon.library'.");
  357.  
  358.             Cleanup();
  359.  
  360.             return(RETURN_FAIL);
  361.         }
  362.  
  363.         old_dir = CurrentDir(WBStartup->sm_ArgList[n].wa_Lock);
  364.         Icon = GetDiskObject(WBStartup->sm_ArgList[n].wa_Name);
  365.         CurrentDir(old_dir);
  366.  
  367.         if(Icon == NULL)
  368.         {
  369.             ReportError("Icon not found.");
  370.  
  371.             Cleanup();
  372.  
  373.             return(RETURN_FAIL);
  374.         }
  375.  
  376.         /* Examine the icon's tool types and use the
  377.          * information to fill the startup parameter
  378.          * data structure.
  379.          */
  380.         str = FindToolType(Icon->do_ToolTypes,"DOMAIN");
  381.         if(str == NULL)
  382.             str = FindToolType(Icon->do_ToolTypes,"WORKGROUP");
  383.  
  384.         if(str == NULL)
  385.         {
  386.             if(GetVar("smbfs_domain",env_workgroup_name,sizeof(env_workgroup_name),0) > 0 ||
  387.                GetVar("smbfs_workgroup",env_workgroup_name,sizeof(env_workgroup_name),0) > 0)
  388.             {
  389.                 str = env_workgroup_name;
  390.             }
  391.             else
  392.             {
  393.                 ReportError("Required 'WORKGROUP' parameter was not provided.");
  394.                 Cleanup();
  395.  
  396.                 return(RETURN_ERROR);
  397.             }
  398.         }
  399.  
  400.         args.Workgroup = str;
  401.  
  402.         str = FindToolType(Icon->do_ToolTypes,"USER");
  403.         if(str == NULL)
  404.             str = FindToolType(Icon->do_ToolTypes,"USERNAME");
  405.  
  406.         if(str == NULL)
  407.         {
  408.             if(GetVar("smbfs_user",env_user_name,sizeof(env_user_name),0) > 0 ||
  409.                GetVar("smbfs_username",env_user_name,sizeof(env_user_name),0) > 0)
  410.             {
  411.                 str = env_user_name;
  412.             }
  413.         }
  414.  
  415.         args.UserName = str;
  416.  
  417.         str = FindToolType(Icon->do_ToolTypes,"PASSWORD");
  418.         if(str == NULL)
  419.         {
  420.             if(GetVar("smbfs_password",env_password,sizeof(env_password),0) > 0)
  421.                 str = env_password;
  422.         }
  423.  
  424.         args.Password = str;
  425.  
  426.         if(FindToolType(Icon->do_ToolTypes,"CHANGECASE") != NULL)
  427.             args.ChangeCase = TRUE;
  428.  
  429.         if(FindToolType(Icon->do_ToolTypes,"OMITHIDDEN") != NULL)
  430.             args.OmitHidden = TRUE;
  431.  
  432.         if(FindToolType(Icon->do_ToolTypes,"QUIET") != NULL)
  433.             args.Quiet = TRUE;
  434.  
  435.         if(FindToolType(Icon->do_ToolTypes,"CASE") != NULL ||
  436.            FindToolType(Icon->do_ToolTypes,"CASESENSITIVE") != NULL)
  437.         {
  438.             args.CaseSensitive = TRUE;
  439.         }
  440.  
  441.         str = FindToolType(Icon->do_ToolTypes,"CLIENT");
  442.         if(str == NULL)
  443.             str = FindToolType(Icon->do_ToolTypes,"CLIENTNAME");
  444.  
  445.         args.ClientName = str;
  446.  
  447.         str = FindToolType(Icon->do_ToolTypes,"SERVER");
  448.         if(str == NULL)
  449.             str = FindToolType(Icon->do_ToolTypes,"SERVERNAME");
  450.  
  451.         args.ServerName = str;
  452.  
  453.         str = FindToolType(Icon->do_ToolTypes,"DEVICE");
  454.         if(str == NULL)
  455.             str = FindToolType(Icon->do_ToolTypes,"DEVICENAME");
  456.  
  457.         args.DeviceName = str;
  458.  
  459.         str = FindToolType(Icon->do_ToolTypes,"VOLUME");
  460.         if(str == NULL)
  461.             str = FindToolType(Icon->do_ToolTypes,"VOLUMENAME");
  462.  
  463.         args.VolumeName = str;
  464.  
  465.         str = FindToolType(Icon->do_ToolTypes,"TRANSLATE");
  466.         if(str == NULL)
  467.             str = FindToolType(Icon->do_ToolTypes,"TRANSLATIONFILE");
  468.  
  469.         args.TranslationFile = str;
  470.  
  471.         str = FindToolType(Icon->do_ToolTypes,"SERVICE");
  472.         args.Service = str;
  473.  
  474.         if(str != NULL)
  475.         {
  476.             /* Set up the name of the program, as it will be
  477.              * displayed in error requesters.
  478.              */
  479.             NewProgramName = AllocVec(strlen(WBStartup->sm_ArgList[0].wa_Name) + strlen(" ''") + strlen(str)+1,MEMF_ANY|MEMF_PUBLIC);
  480.             if(NewProgramName != NULL)
  481.                 SPrintf(NewProgramName,"%s '%s'",WBStartup->sm_ArgList[0].wa_Name,str);
  482.         }
  483.  
  484.         str = FindToolType(Icon->do_ToolTypes,"DEBUG");
  485.         if(str == NULL)
  486.             str = FindToolType(Icon->do_ToolTypes,"DEBUGLEVEL");
  487.  
  488.         if(str != NULL)
  489.         {
  490.             if(StrToLong(str,&number) == -1)
  491.             {
  492.                 ReportError("Invalid number '%s' for 'DEBUG' parameter.",str);
  493.                 Cleanup();
  494.  
  495.                 return(RETURN_ERROR);
  496.             }
  497.  
  498.             args.DebugLevel = &number;
  499.         }
  500.  
  501.         str = FindToolType(Icon->do_ToolTypes,"TZ");
  502.         if(str == NULL)
  503.             str = FindToolType(Icon->do_ToolTypes,"TIMEZONEOFFSET");
  504.  
  505.         if(str != NULL)
  506.         {
  507.             if(StrToLong(str,&other_number) == -1)
  508.             {
  509.                 ReportError("Invalid number '%s' for 'TIMEZONEOFFSET' parameter.",str);
  510.                 Cleanup();
  511.  
  512.                 return(RETURN_ERROR);
  513.             }
  514.  
  515.             args.TimeZoneOffset = &other_number;
  516.         }
  517.  
  518.         str = FindToolType(Icon->do_ToolTypes,"CACHE");
  519.         if(str == NULL)
  520.             str = FindToolType(Icon->do_ToolTypes,"CACHESIZE");
  521.  
  522.         if(str != NULL)
  523.         {
  524.             LONG number;
  525.  
  526.             if(StrToLong(str,&number) == -1)
  527.             {
  528.                 ReportError("Invalid number '%s' for 'CACHE' parameter.",str);
  529.                 Cleanup();
  530.  
  531.                 return(RETURN_ERROR);
  532.             }
  533.  
  534.             cache_size = number;
  535.         }
  536.  
  537.         if(args.Workgroup == NULL)
  538.         {
  539.             ReportError("Required 'WORKGROUP' parameter was not provided.");
  540.             Cleanup();
  541.  
  542.             return(RETURN_ERROR);
  543.         }
  544.  
  545.         if(args.Service == NULL)
  546.         {
  547.             ReportError("'SERVICE' parameter needs an argument.");
  548.             Cleanup();
  549.  
  550.             return(RETURN_ERROR);
  551.         }
  552.     }
  553.     else
  554.     {
  555.         GetProgramName(program_name,sizeof(program_name));
  556.  
  557.         Parameters = ReadArgs(cmd_template,(LONG *)&args,NULL);
  558.         if(Parameters == NULL)
  559.         {
  560.             PrintFault(IoErr(),FilePart(program_name));
  561.             Cleanup();
  562.  
  563.             return(RETURN_ERROR);
  564.         }
  565.  
  566.         if(args.Workgroup == NULL)
  567.         {
  568.             if(GetVar("smbfs_domain",env_workgroup_name,sizeof(env_workgroup_name),0) > 0 ||
  569.                GetVar("smbfs_workgroup",env_workgroup_name,sizeof(env_workgroup_name),0) > 0)
  570.             {
  571.                 args.Workgroup = env_workgroup_name;
  572.             }
  573.             else
  574.             {
  575.                 ReportError("Required 'WORKGROUP' parameter was not provided.");
  576.                 Cleanup();
  577.  
  578.                 return(RETURN_ERROR);
  579.             }
  580.         }
  581.  
  582.         if(args.UserName == NULL)
  583.         {
  584.             if(GetVar("smbfs_user",env_user_name,sizeof(env_user_name),0) > 0 ||
  585.                GetVar("smbfs_username",env_user_name,sizeof(env_user_name),0) > 0)
  586.             {
  587.                 args.UserName = env_user_name;
  588.             }
  589.         }
  590.  
  591.         if(args.Password == NULL)
  592.         {
  593.             if(GetVar("smbfs_password",env_password,sizeof(env_password),0) > 0)
  594.                 args.Password = env_password;
  595.         }
  596.  
  597.         if(args.Service != NULL)
  598.         {
  599.             STRPTR name = FilePart(program_name);
  600.  
  601.             /* Set up the name of the program, as it will be
  602.              * displayed in the proces status list.
  603.              */
  604.             NewProgramName = AllocVec(strlen(name) + strlen(" ''") + strlen(args.Service)+1,MEMF_ANY|MEMF_PUBLIC);
  605.             if(NewProgramName != NULL)
  606.                 SPrintf(NewProgramName,"%s '%s'",name,args.Service);
  607.         }
  608.  
  609.         if(args.CacheSize != NULL)
  610.             cache_size = (*args.CacheSize);
  611.     }
  612.  
  613.     /* Use the default if no user name is given. */
  614.     if(args.UserName == NULL)
  615.         args.UserName = "GUEST";
  616.  
  617.     /* Use the default if no device or volume name is given. */
  618.     if(args.DeviceName == NULL && args.VolumeName == NULL)
  619.         args.DeviceName = "SMBFS";
  620.  
  621.     CaseSensitive = (BOOL)args.CaseSensitive;
  622.     OmitHidden = (BOOL)args.OmitHidden;
  623.  
  624.     /* Configure the debugging options. */
  625.     SETPROGRAMNAME(FilePart(program_name));
  626.  
  627.     if(args.DebugLevel != NULL)
  628.         SETDEBUGLEVEL(*args.DebugLevel);
  629.     else
  630.         SETDEBUGLEVEL(0);
  631.  
  632.     D(("%s (%s)",VERS,DATE));
  633.  
  634.     if(Setup(
  635.         FilePart(program_name),
  636.         args.Service,
  637.         args.Workgroup,
  638.         args.UserName,
  639.         args.Password,
  640.         args.ChangeCase,
  641.         args.ClientName,
  642.         args.ServerName,
  643.         cache_size,
  644.         args.TimeZoneOffset,
  645.         args.DeviceName,
  646.         args.VolumeName,
  647.         args.TranslationFile))
  648.     {
  649.         Quiet = args.Quiet;
  650.  
  651.         if(Locale != NULL)
  652.             SHOWVALUE(Locale->loc_GMTOffset);
  653.  
  654.         HandleFileSystem(args.DeviceName,args.VolumeName,args.Service);
  655.  
  656.         result = RETURN_WARN;
  657.     }
  658.     else
  659.     {
  660.         result = RETURN_ERROR;
  661.     }
  662.  
  663.     Cleanup();
  664.     return(result);
  665. }
  666.  
  667. /****************************************************************************/
  668.  
  669. /* Obtain the descriptive text corresponding to an error number
  670.  * that may have been generated by the TCP/IP stack.
  671.  */
  672. STRPTR
  673. amitcp_strerror(int error)
  674. {
  675.     struct TagItem tags[2];
  676.     STRPTR result;
  677.  
  678.     ENTER();
  679.  
  680.     tags[0].ti_Tag    = SBTM_GETVAL(SBTC_ERRNOSTRPTR);
  681.     tags[0].ti_Data    = error;
  682.     tags[1].ti_Tag    = TAG_END;
  683.  
  684.     SocketBaseTagList(tags);
  685.  
  686.     result = (STRPTR)tags[0].ti_Data;
  687.  
  688.     RETURN(result);
  689.     return(result);
  690. }
  691.  
  692. /****************************************************************************/
  693.  
  694. /* Return the descriptive text associated with a host lookup failure code. */
  695. STRPTR
  696. host_strerror(int error)
  697. {
  698.     struct TagItem tags[2];
  699.     STRPTR result;
  700.  
  701.     ENTER();
  702.  
  703.     tags[0].ti_Tag    = SBTM_GETVAL(SBTC_HERRNOSTRPTR);
  704.     tags[0].ti_Data    = error;
  705.     tags[1].ti_Tag    = TAG_END;
  706.  
  707.     SocketBaseTagList(tags);
  708.  
  709.     result = (STRPTR)tags[0].ti_Data;
  710.  
  711.     RETURN(result);
  712.     return(result);
  713. }
  714.  
  715. /****************************************************************************/
  716.  
  717. /* Compare two strings, either case sensitive or not
  718.  * sensitive to the case of the letters. How this is
  719.  * to be done is controlled by a global option. This
  720.  * routine is called whenever two SMB file names are
  721.  * to be compared.
  722.  */
  723. LONG
  724. CompareNames(STRPTR a,STRPTR b)
  725. {
  726.     LONG result;
  727.  
  728.     if(CaseSensitive)
  729.         result = strcmp(a,b);
  730.     else
  731.         result = Stricmp(a,b);
  732.  
  733.     return(result);
  734. }
  735.  
  736. /****************************************************************************/
  737.  
  738. /* Translate a string into all upper case characters. */
  739. VOID
  740. StringToUpper(STRPTR s)
  741. {
  742.     UBYTE c;
  743.  
  744.     while((c = (*s)) != '\0')
  745.         (*s++) = ToUpper(c);
  746. }
  747.  
  748. /****************************************************************************/
  749.  
  750. /* Prepare the accumulated list of error messages for display
  751.  * and purge the contents of that list.
  752.  */
  753. STATIC VOID
  754. DisplayErrorList(VOID)
  755. {
  756.     struct MinNode * last = NULL;
  757.     struct MinNode * mn;
  758.     STRPTR str = NULL;
  759.     STRPTR msg;
  760.     LONG len;
  761.  
  762.     /* Determine how much memory will have to be
  763.      * allocated to hold all the accumulated
  764.      * error messages.
  765.      */
  766.     len = 0;
  767.  
  768.     for(mn = ErrorList.mlh_Head ;
  769.         mn->mln_Succ != NULL ;
  770.         mn = mn->mln_Succ)
  771.     {
  772.         last = mn;
  773.  
  774.         msg = (STRPTR)(mn + 1);
  775.  
  776.         len += strlen(msg)+1;
  777.     }
  778.  
  779.     /* Allocate the memory for the messages, then
  780.      * copy them there.
  781.      */
  782.     if(len > 0)
  783.     {
  784.         str = AllocVec(len,MEMF_ANY);
  785.         if(str != NULL)
  786.         {
  787.             str[0] = '\0';
  788.  
  789.             for(mn = ErrorList.mlh_Head ;
  790.                 mn->mln_Succ != NULL ;
  791.                 mn = mn->mln_Succ)
  792.             {
  793.                 msg = (STRPTR)(mn + 1);
  794.  
  795.                 strcat(str,msg);
  796.                 if(mn != last)
  797.                     strcat(str,"\n");
  798.             }
  799.         }
  800.     }
  801.  
  802.     /* Purge the list. */
  803.     while((mn = (struct MinNode *)RemHead((struct List *)&ErrorList)) != NULL)
  804.         FreeVec(mn);
  805.  
  806.     /* Display the error messages. */
  807.     if(str != NULL)
  808.     {
  809.         struct Library * IntuitionBase;
  810.  
  811.         IntuitionBase = OpenLibrary("intuition.library",37);
  812.         if(IntuitionBase != NULL)
  813.         {
  814.             struct EasyStruct es;
  815.             STRPTR title;
  816.  
  817.             memset(&es,0,sizeof(es));
  818.  
  819.             if(NewProgramName == NULL)
  820.                 title = WBStartup->sm_ArgList[0].wa_Name;
  821.             else
  822.                 title = NewProgramName;
  823.  
  824.             es.es_StructSize    = sizeof(es);
  825.             es.es_Title            = title;
  826.             es.es_TextFormat    = str;
  827.             es.es_GadgetFormat    = "Ok";
  828.  
  829.             EasyRequestArgs(NULL,&es,NULL,NULL);
  830.  
  831.             CloseLibrary(IntuitionBase);
  832.         }
  833.  
  834.         FreeVec(str);
  835.     }
  836. }
  837.  
  838. /* Add another error message to the list; the messages are
  839.  * collected so that they may be displayed together when
  840.  * necessary.
  841.  */
  842. STATIC VOID
  843. AddError(STRPTR fmt,va_list args)
  844. {
  845.     LONG len;
  846.  
  847.     len = CVSPrintf(fmt,args);
  848.     if(len > 0)
  849.     {
  850.         struct MinNode * mn;
  851.  
  852.         mn = AllocVec(sizeof(*mn) + len,MEMF_ANY|MEMF_PUBLIC);
  853.         if(mn != NULL)
  854.         {
  855.             STRPTR msg = (STRPTR)(mn + 1);
  856.  
  857.             VSPrintf(msg,fmt,args);
  858.  
  859.             AddTail((struct List *)&ErrorList,(struct Node *)mn);
  860.         }
  861.     }
  862. }
  863.  
  864. /****************************************************************************/
  865.  
  866. /* Report an error that has occured; if the program was not launched
  867.  * from Shell, error messages will be accumulated for later display.
  868.  */
  869. VOID
  870. ReportError(STRPTR fmt,...)
  871. {
  872.     if(NOT Quiet)
  873.     {
  874.         va_list args;
  875.  
  876.         if(WBStartup != NULL)
  877.         {
  878.             va_start(args,fmt);
  879.             AddError(fmt,args);
  880.             va_end(args);
  881.         }
  882.         else
  883.         {
  884.             UBYTE program_name[MAX_FILENAME_LEN];
  885.  
  886.             GetProgramName(program_name,sizeof(program_name));
  887.  
  888.             Printf("%s: ",FilePart(program_name));
  889.  
  890.             va_start(args,fmt);
  891.             VPrintf(fmt,args);
  892.             va_end(args);
  893.  
  894.             Printf("\n");
  895.         }
  896.     }
  897. }
  898.  
  899. /****************************************************************************/
  900.  
  901. /* Release memory allocated from the global pool. */
  902. VOID
  903. FreeVecPooled(APTR address)
  904. {
  905.     if(address != NULL)
  906.     {
  907.         ULONG * mem = address;
  908.  
  909.         #if DEBUG
  910.         {
  911.             if(GETDEBUGLEVEL() > 0)
  912.                 memset(address,0xA3,mem[-1] - sizeof(*mem));
  913.         }
  914.         #endif /* DEBUG */
  915.  
  916.         AsmFreePooled(MemoryPool,&mem[-1],mem[-1],SysBase);
  917.     }
  918. }
  919.  
  920. /* Allocate memory from the global pool. */
  921. APTR
  922. AllocVecPooled(ULONG size)
  923. {
  924.     APTR result = NULL;
  925.  
  926.     if(size > 0)
  927.     {
  928.         ULONG * mem;
  929.  
  930.         size = (sizeof(*mem) + size + 7) & ~7;
  931.  
  932.         mem = AsmAllocPooled(MemoryPool,size,SysBase);
  933.         if(mem != NULL)
  934.         {
  935.             (*mem++) = size;
  936.  
  937.             #if DEBUG
  938.             {
  939.                 if(GETDEBUGLEVEL() > 0)
  940.                     memset(mem,0xA5,mem[-1] - sizeof(*mem));
  941.             }
  942.             #endif /* DEBUG */
  943.  
  944.             result = mem;
  945.         }
  946.     }
  947.  
  948.     return(result);
  949. }
  950.  
  951. /****************************************************************************/
  952.  
  953. /* Obtain the number of seconds to add to the current time
  954.  * to translate local time into UTC.
  955.  */
  956. LONG
  957. GetTimeZoneDelta(VOID)
  958. {
  959.     LONG seconds;
  960.  
  961.     if(OverrideLocaleTimeZone)
  962.     {
  963.         seconds = 60 * TimeZoneOffset;
  964.     }
  965.     else if (Locale != NULL)
  966.     {
  967.         /* The GMT offset actually is the number of minutes to add to
  968.          * the local time to yield Greenwich Mean Time. It is negative
  969.          * for all time zones east of the Greenwich meridian and
  970.          * positive for all time zones west of it.
  971.          */
  972.         seconds = 60 * Locale->loc_GMTOffset;
  973.     }
  974.     else
  975.     {
  976.         seconds = 0;
  977.     }
  978.  
  979.     return(seconds);
  980. }
  981.  
  982. /****************************************************************************/
  983.  
  984. /* Obtain the current time, in standard Unix format, adjusted for the
  985.  * local time zone.
  986.  */
  987. ULONG
  988. GetCurrentTime(VOID)
  989. {
  990.     struct timeval tv;
  991.     ULONG result;
  992.  
  993.     GetSysTime((APTR)&tv);
  994.  
  995.     result = UNIX_TIME_OFFSET + GetTimeZoneDelta() + tv.tv_secs;
  996.  
  997.     return(result);
  998. }
  999.  
  1000. /****************************************************************************/
  1001.  
  1002. /* Fill in a 'tm' type time specification with time information
  1003.  * corresponding to the number of seconds provided. Input is
  1004.  * in Unix format.
  1005.  */
  1006. VOID
  1007. LocalTime(time_t seconds,struct tm * tm)
  1008. {
  1009.     struct ClockData clock;
  1010.  
  1011.     seconds -= GetTimeZoneDelta();
  1012.  
  1013.     if(seconds < UNIX_TIME_OFFSET)
  1014.         seconds = 0;
  1015.     else
  1016.         seconds -= UNIX_TIME_OFFSET;
  1017.  
  1018.     Amiga2Date(seconds,&clock);
  1019.  
  1020.     memset(tm,0,sizeof(*tm));
  1021.  
  1022.     tm->tm_sec    = clock.sec;
  1023.     tm->tm_min    = clock.min;
  1024.     tm->tm_hour    = clock.hour;
  1025.     tm->tm_mday    = clock.mday;
  1026.     tm->tm_mon    = clock.month - 1;
  1027.     tm->tm_year    = clock.year - 1900;
  1028. }
  1029.  
  1030. /* Calculate the number of seconds that have passed since January 1st 1970
  1031.  * based upon the time specification provided. Output is in Unix format.
  1032.  */
  1033. time_t
  1034. MakeTime(const struct tm * const tm)
  1035. {
  1036.     struct ClockData clock;
  1037.     time_t seconds;
  1038.  
  1039.     clock.sec    = tm->tm_sec;
  1040.     clock.min    = tm->tm_min;
  1041.     clock.hour    = tm->tm_hour;
  1042.     clock.mday    = tm->tm_mday;
  1043.     clock.month    = tm->tm_mon + 1;
  1044.     clock.year    = tm->tm_year + 1900;
  1045.  
  1046.     seconds = Date2Amiga(&clock) + UNIX_TIME_OFFSET + GetTimeZoneDelta();
  1047.  
  1048.     return(seconds);
  1049. }
  1050.  
  1051. /****************************************************************************/
  1052.  
  1053. struct FormatContext
  1054. {
  1055.     LONG fc_Size;
  1056. };
  1057.  
  1058. STATIC VOID ASM
  1059. CountChar(REG(a3) struct FormatContext * fc)
  1060. {
  1061.     fc->fc_Size++;
  1062. }
  1063.  
  1064. /* Count the number of characters SPrintf() would put into a string. */
  1065. STATIC LONG
  1066. CVSPrintf(STRPTR format_string,va_list args)
  1067. {
  1068.     struct FormatContext fc;
  1069.  
  1070.     fc.fc_Size = 0;
  1071.  
  1072.     RawDoFmt((STRPTR)format_string,args,(VOID (*)())CountChar,&fc);
  1073.  
  1074.     return(fc.fc_Size);
  1075. }
  1076.  
  1077. /****************************************************************************/
  1078.  
  1079. STATIC VOID
  1080. VSPrintf(STRPTR buffer, STRPTR formatString, va_list args)
  1081. {
  1082.     RawDoFmt(formatString,args,(VOID (*)())"\x16\xC0\x4E\x75",buffer);
  1083. }
  1084.  
  1085. /* Format a string for output. */
  1086. VOID
  1087. SPrintf(STRPTR buffer, STRPTR formatString,...)
  1088. {
  1089.     va_list varArgs;
  1090.  
  1091.     va_start(varArgs,formatString);
  1092.     VSPrintf(buffer,formatString,varArgs);
  1093.     va_end(varArgs);
  1094. }
  1095.  
  1096. /****************************************************************************/
  1097.  
  1098. /* NetBIOS broadcast name query code courtesy of Christopher R. Hertel.
  1099.  * Thanks much, Chris!
  1100.  */
  1101. struct addr_entry
  1102. {
  1103.     unsigned short flags;
  1104.     unsigned char address[4];
  1105. };
  1106.  
  1107. struct nmb_header
  1108. {
  1109.     unsigned short name_trn_id;
  1110.     unsigned short flags;
  1111.     unsigned short qdcount;
  1112.     unsigned short ancount;
  1113.     unsigned short nscount;
  1114.     unsigned short arcount;
  1115. };
  1116.  
  1117. static UBYTE *
  1118. L1_Encode(UBYTE * dst, const UBYTE * name, const UBYTE pad, const UBYTE sfx)
  1119. {
  1120.     int i = 0;
  1121.     int j = 0;
  1122.     int k;
  1123.  
  1124.     while(('\0' != name[i]) && (i < 15))
  1125.     {
  1126.         k = ToUpper(name[i]);
  1127.         i++;
  1128.         dst[j++] = 'A' + ((k & 0xF0) >> 4);
  1129.         dst[j++] = 'A' + (k & 0x0F);
  1130.     }
  1131.  
  1132.     i = 'A' + ((pad & 0xF0) >> 4);
  1133.     k = 'A' + (pad & 0x0F);
  1134.  
  1135.     while(j < 30)
  1136.     {
  1137.         dst[j++] = i;
  1138.         dst[j++] = k;
  1139.     }
  1140.  
  1141.     dst[30] = 'A' + ((sfx & 0xF0) >> 4);
  1142.     dst[31] = 'A' + (sfx & 0x0F);
  1143.     dst[32] = '\0';
  1144.  
  1145.     return(dst);
  1146. }
  1147.  
  1148. static int
  1149. L2_Encode(UBYTE * dst, const UBYTE * name, const UBYTE pad, const UBYTE sfx, const UBYTE * scope)
  1150. {
  1151.     int lenpos;
  1152.     int i;
  1153.     int j;
  1154.  
  1155.     if(NULL == L1_Encode(&dst[1], name, pad, sfx))
  1156.         return(-1);
  1157.  
  1158.     dst[0] = 0x20;
  1159.     lenpos = 33;
  1160.  
  1161.     if('\0' != (*scope))
  1162.     {
  1163.         do
  1164.         {
  1165.             for(i = 0, j = (lenpos + 1);
  1166.                 ('.' != scope[i]) && ('\0' != scope[i]);
  1167.                 i++, j++)
  1168.             {
  1169.                 dst[j] = ToUpper(scope[i]);
  1170.             }
  1171.  
  1172.             dst[lenpos] = (UBYTE)i;
  1173.             lenpos += i + 1;
  1174.             scope += i;
  1175.         }
  1176.         while('.' == (*scope++));
  1177.  
  1178.         dst[lenpos] = '\0';
  1179.     }
  1180.  
  1181.     return(lenpos + 1);
  1182. }
  1183.  
  1184. int
  1185. BroadcastNameQuery(char *name, char *scope, UBYTE *address)
  1186. {
  1187.     static const UBYTE header[12] =
  1188.     {
  1189.         0x07, 0xB0,    /* 1964 == 0x07B0. */
  1190.         0x01, 0x10,    /* Binary 0 0000 0010001 0000 */
  1191.         0x00, 0x01,    /* One name query. */
  1192.         0x00, 0x00,    /* Zero answers. */
  1193.         0x00, 0x00,    /* Zero authorities. */
  1194.         0x00, 0x00    /* Zero additional. */
  1195.     };
  1196.  
  1197.     static const UBYTE query_tail[4] =
  1198.     {
  1199.         0x00, 0x20,
  1200.         0x00, 0x01
  1201.     };
  1202.  
  1203.     struct timeval tv;
  1204.     fd_set read_fds;
  1205.     int sock_fd;
  1206.     int option_true = 1;
  1207.     struct sockaddr_in sox;
  1208.     struct nmb_header nmb_header;
  1209.     UBYTE buffer[512];
  1210.     int total_len;
  1211.     int i,n;
  1212.     int result;
  1213.  
  1214.     ENTER();
  1215.  
  1216.     sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  1217.     if(sock_fd < 0)
  1218.     {
  1219.         SHOWMSG("couldn't get the socket");
  1220.         result = (-errno);
  1221.         goto out;
  1222.     }
  1223.  
  1224.     if(setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &option_true, sizeof(option_true)) < 0)
  1225.     {
  1226.         SHOWMSG("couldn't enable the broadcast option");
  1227.         result = (-errno);
  1228.         goto out;
  1229.     }
  1230.  
  1231.     sox.sin_family = AF_INET;
  1232.     sox.sin_port = htons(137);
  1233.     sox.sin_addr.s_addr = htonl(0xFFFFFFFF);
  1234.  
  1235.     memcpy(buffer, header, (total_len = sizeof(header)));
  1236.  
  1237.     n = L2_Encode(&buffer[total_len], name, ' ', '\0', scope);
  1238.     if(n < 0)
  1239.     {
  1240.         SHOWMSG("name encoding failed");
  1241.         result = (-EINVAL);
  1242.         goto out;
  1243.     }
  1244.  
  1245.     total_len += n;
  1246.     memcpy(&buffer[total_len], query_tail, sizeof(query_tail));
  1247.     total_len += sizeof(query_tail);
  1248.  
  1249.     result = (-ENOENT);
  1250.     n = 0;
  1251.  
  1252.     /* Send the query packet; retry five times with a one second
  1253.      * delay in between.
  1254.      */
  1255.     for(i = 0 ; i < 5 ; i++)
  1256.     {
  1257.         if(sendto(sock_fd, (void *) buffer, total_len, 0, (struct sockaddr *)&sox, sizeof(struct sockaddr_in)) < 0)
  1258.         {
  1259.             SHOWMSG("could not send the packet");
  1260.             result = (-errno);
  1261.             goto out;
  1262.         }
  1263.  
  1264.         /* Wait for a response to arrive. */
  1265.         tv.tv_secs = 1;
  1266.         tv.tv_micro = 0;
  1267.  
  1268.         FD_ZERO(&read_fds);
  1269.         FD_SET(sock_fd,&read_fds);
  1270.  
  1271.         if(WaitSelect(sock_fd+1, &read_fds, NULL, NULL, &tv, NULL) > 0)
  1272.         {
  1273.             n = recvfrom(sock_fd, buffer, sizeof(buffer), 0, NULL, NULL);
  1274.             if(n < 0)
  1275.             {
  1276.                 SHOWMSG("could not pick up the response packet");
  1277.                 result = (-errno);
  1278.                 goto out;
  1279.             }
  1280.             else if (n > 0)
  1281.             {
  1282.                 break;
  1283.             }
  1284.         }
  1285.     }
  1286.  
  1287.     /* Did we get anything at all? */
  1288.     if(n > sizeof(nmb_header))
  1289.     {
  1290.         /* Check whether the query was successful. */
  1291.         memcpy(&nmb_header, buffer, sizeof(nmb_header));
  1292.         if((nmb_header.flags & 0xF) == OK)
  1293.         {
  1294.             /* Find the NB/IP fields which directly follow
  1295.              * the name.
  1296.              */
  1297.             for(i = sizeof(header) + strlen(&buffer[sizeof(header)])+1 ; i < n - sizeof(query_tail) ; i++)
  1298.             {
  1299.                 if(memcmp(&buffer[i], query_tail, sizeof(query_tail)) == SAME)
  1300.                 {
  1301.                     int start;
  1302.  
  1303.                     /* This should be the start of the interesting bits;
  1304.                      * we skip the NB/IP fields and the TTL field.
  1305.                      */
  1306.                     start = i + sizeof(query_tail) + sizeof(long);
  1307.                     if(start < n)
  1308.                     {
  1309.                         unsigned short read_len;
  1310.                         struct addr_entry addr_entry;
  1311.  
  1312.                         /* This should be the read length. */
  1313.                         memcpy(&read_len, &buffer[start], 2);
  1314.  
  1315.                         /* Is there any useful and readable data attached? */
  1316.                         if(read_len >= sizeof(addr_entry) &&
  1317.                            start + sizeof(read_len) + sizeof(addr_entry) <= n)
  1318.                         {
  1319.                             /* Copy a single address entry; this should be
  1320.                              * just the one we need.
  1321.                              */
  1322.                             memcpy(&addr_entry, &buffer[start + sizeof(read_len)], sizeof(addr_entry));
  1323.  
  1324.                             /* Copy the address field (IPv4 only). */
  1325.                             memcpy(address, addr_entry.address, 4);
  1326.  
  1327.                             result = 0;
  1328.                         }
  1329.                     }
  1330.  
  1331.                     break;
  1332.                 }
  1333.             }
  1334.         }
  1335.     }
  1336.  
  1337. out:
  1338.  
  1339.     if(sock_fd >= 0)
  1340.         CloseSocket(sock_fd);
  1341.  
  1342.     RETURN(result);
  1343.     return(result);
  1344. }
  1345.  
  1346. /****************************************************************************/
  1347.  
  1348. /* Send a disk change notification message which will be picked up
  1349.  * by all applications that listen for this kind of event, e.g.
  1350.  * Workbench.
  1351.  */
  1352. STATIC VOID
  1353. SendDiskChange(ULONG class)
  1354. {
  1355.     struct IOStdReq * input_request = NULL;
  1356.     struct MsgPort * input_port;
  1357.     struct InputEvent ie;
  1358.  
  1359.     ENTER();
  1360.  
  1361.     input_port = CreateMsgPort();
  1362.     if(input_port == NULL)
  1363.         goto out;
  1364.  
  1365.     input_request = CreateIORequest(input_port,sizeof(*input_request));
  1366.     if(input_request == NULL)
  1367.         goto out;
  1368.  
  1369.     if(OpenDevice("input.device",0,(struct IORequest *)input_request,0) != OK)
  1370.         goto out;
  1371.  
  1372.     memset(&ie,0,sizeof(ie));
  1373.  
  1374.     ie.ie_Class        = class;
  1375.     ie.ie_Qualifier    = IEQUALIFIER_MULTIBROADCAST;
  1376.     GetSysTime(&ie.ie_TimeStamp);
  1377.  
  1378.     input_request->io_Command    = IND_WRITEEVENT;
  1379.     input_request->io_Data        = &ie;
  1380.     input_request->io_Length    = sizeof(ie);
  1381.  
  1382.     DoIO((struct IORequest *)input_request);
  1383.  
  1384.  out:
  1385.  
  1386.     if(input_request != NULL)
  1387.     {
  1388.         if(input_request->io_Device != NULL)
  1389.             CloseDevice((struct IORequest *)input_request);
  1390.  
  1391.         DeleteIORequest((struct IORequest *)input_request);
  1392.     }
  1393.  
  1394.     DeleteMsgPort(input_port);
  1395.  
  1396.     LEAVE();
  1397. }
  1398.  
  1399. /****************************************************************************/
  1400.  
  1401. /* Find the file node corresponding to a given name,
  1402.  * skipping a particular entry if necessary.
  1403.  */
  1404. STATIC struct FileNode *
  1405. FindFileNode(STRPTR name,struct FileNode * skip)
  1406. {
  1407.     struct FileNode * result = NULL;
  1408.     struct FileNode * fn;
  1409.  
  1410.     for(fn = (struct FileNode *)FileList.mlh_Head ;
  1411.         fn->fn_MinNode.mln_Succ != NULL ;
  1412.         fn = (struct FileNode *)fn->fn_MinNode.mln_Succ)
  1413.     {
  1414.         if(fn != skip && CompareNames(name,fn->fn_FullName) == SAME)
  1415.         {
  1416.             result = fn;
  1417.             break;
  1418.         }
  1419.     }
  1420.  
  1421.     return(result);
  1422. }
  1423.  
  1424. /* Find the lock node corresponding to a given name,
  1425.  * skipping a particular entry if necessary.
  1426.  */
  1427. STATIC struct LockNode *
  1428. FindLockNode(STRPTR name,struct LockNode * skip)
  1429. {
  1430.     struct LockNode * result = NULL;
  1431.     struct LockNode * ln;
  1432.  
  1433.     for(ln = (struct LockNode *)LockList.mlh_Head ;
  1434.         ln->ln_MinNode.mln_Succ != NULL ;
  1435.         ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
  1436.     {
  1437.         if(ln != skip && CompareNames(name,ln->ln_FullName) == SAME)
  1438.         {
  1439.             result = ln;
  1440.             break;
  1441.         }
  1442.     }
  1443.  
  1444.     return(result);
  1445. }
  1446.  
  1447. /* Check whether a new reference to be made to a named
  1448.  * file will cause a conflict of access modes. No two
  1449.  * files and locks may refer to the same object if
  1450.  * either of these references is made in exclusive
  1451.  * mode. This is the case which this function is
  1452.  * trying to avoid.
  1453.  */
  1454. STATIC LONG
  1455. CheckAccessModeCollision(STRPTR name,LONG mode)
  1456. {
  1457.     struct LockNode * ln;
  1458.     struct FileNode * fn;
  1459.     LONG error = OK;
  1460.  
  1461.     ENTER();
  1462.     SHOWSTRING(name);
  1463.  
  1464.     fn = FindFileNode(name,NULL);
  1465.     if(fn != NULL)
  1466.     {
  1467.         if(mode != SHARED_LOCK || fn->fn_Mode != SHARED_LOCK)
  1468.         {
  1469.             D(("collides with '%s'",fn->fn_FullName));
  1470.             error = ERROR_OBJECT_IN_USE;
  1471.             goto out;
  1472.         }
  1473.     }
  1474.  
  1475.     ln = FindLockNode(name,NULL);
  1476.     if(ln != NULL)
  1477.     {
  1478.         if(mode != SHARED_LOCK || ln->ln_FileLock.fl_Access != SHARED_LOCK)
  1479.         {
  1480.             D(("collides with '%s'",ln->ln_FullName));
  1481.             error = ERROR_OBJECT_IN_USE;
  1482.             goto out;
  1483.         }
  1484.     }
  1485.  
  1486.  out:
  1487.  
  1488.     RETURN(error);
  1489.     return(error);
  1490. }
  1491.  
  1492. /* Find out whether there already exists a reference to a
  1493.  * certain file or directory.
  1494.  */
  1495. STATIC LONG
  1496. NameAlreadyInUse(STRPTR name)
  1497. {
  1498.     LONG error = OK;
  1499.  
  1500.     ENTER();
  1501.  
  1502.     if(FindFileNode(name,NULL) != NULL)
  1503.     {
  1504.         error = ERROR_OBJECT_IN_USE;
  1505.         goto out;
  1506.     }
  1507.  
  1508.     if(FindLockNode(name,NULL) != NULL)
  1509.     {
  1510.         error = ERROR_OBJECT_IN_USE;
  1511.         goto out;
  1512.     }
  1513.  
  1514.  out:
  1515.  
  1516.     RETURN(error);
  1517.     return(error);
  1518. }
  1519.  
  1520. /* Check whether an Amiga file name uses special characters which
  1521.  * should be avoided when used with the SMB file sharing protocol.
  1522.  */
  1523. STATIC BOOL
  1524. IsReservedName(STRPTR name)
  1525. {
  1526.     BOOL result = FALSE;
  1527.  
  1528.     /* Disallow "." and "..". */
  1529.     if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
  1530.     {
  1531.         result = TRUE;
  1532.     }
  1533.     else
  1534.     {
  1535.         UBYTE c;
  1536.  
  1537.         /* Disallow the use of the backslash in file names. */
  1538.         while((c = (*name++)) != '\0')
  1539.         {
  1540.             if(c == SMB_PATH_SEPARATOR)
  1541.             {
  1542.                 result = TRUE;
  1543.                 break;
  1544.             }
  1545.         }
  1546.     }
  1547.  
  1548.     return(result);
  1549. }
  1550.  
  1551. /****************************************************************************/
  1552.  
  1553. /* Convert a POSIX error code into an AmigaDOS error code. */
  1554. STATIC LONG
  1555. MapErrnoToIoErr(int error)
  1556. {
  1557.     /* Not all of these mappings make good sense; bear in mind that
  1558.      * POSIX covers more than a hundred different error codes
  1559.      * whereas with AmigaDOS we're stranded with a measly 48...
  1560.      */
  1561.     STATIC const LONG Map[][2] =
  1562.     {
  1563.         EPERM,                ERROR_OBJECT_NOT_FOUND,        /* Operation not permitted */
  1564.         ENOENT,                ERROR_OBJECT_NOT_FOUND,        /* No such file or directory */
  1565.         ESRCH,                ERROR_OBJECT_NOT_FOUND,        /* No such process */
  1566.         EINTR,                ERROR_BREAK,                /* Interrupted system call */
  1567.         EIO,                ERROR_OBJECT_IN_USE,        /* Input/output error */
  1568.         E2BIG,                ERROR_TOO_MANY_ARGS,        /* Argument list too long */
  1569.         EBADF,                ERROR_INVALID_LOCK,            /* Bad file descriptor */
  1570.         ENOMEM,                ERROR_NO_FREE_STORE,        /* Cannot allocate memory */
  1571.         EACCES,                ERROR_OBJECT_IN_USE,        /* Permission denied */
  1572.         ENOTBLK,            ERROR_OBJECT_WRONG_TYPE,    /* Block device required */
  1573.         EBUSY,                ERROR_OBJECT_IN_USE,        /* Device busy */
  1574.         EEXIST,                ERROR_OBJECT_EXISTS,        /* File exists */
  1575.         EXDEV,                ERROR_NOT_IMPLEMENTED,        /* Cross-device link */
  1576.         ENOTDIR,            ERROR_OBJECT_WRONG_TYPE,    /* Not a directory */
  1577.         EISDIR,                ERROR_OBJECT_WRONG_TYPE,    /* Is a directory */
  1578.         EINVAL,                ERROR_BAD_NUMBER,            /* Invalid argument */
  1579.         EFBIG,                ERROR_DISK_FULL,            /* File too large */
  1580.         ENOSPC,                ERROR_DISK_FULL,            /* No space left on device */
  1581.         ESPIPE,                ERROR_SEEK_ERROR,            /* Illegal seek */
  1582.         EROFS,                ERROR_WRITE_PROTECTED,        /* Read-only file system */
  1583.         EMLINK,                ERROR_TOO_MANY_LEVELS,        /* Too many links */
  1584.         ENOTSOCK,            ERROR_OBJECT_WRONG_TYPE,    /* Socket operation on non-socket */
  1585.         EDESTADDRREQ,        ERROR_REQUIRED_ARG_MISSING,    /* Destination address required */
  1586.         EMSGSIZE,            ERROR_LINE_TOO_LONG,        /* Message too long */
  1587.         EPROTOTYPE,            ERROR_BAD_TEMPLATE,            /* Protocol wrong type for socket */
  1588.         ENOPROTOOPT,        ERROR_NOT_IMPLEMENTED,        /* Protocol not available */
  1589.         EPROTONOSUPPORT,    ERROR_NOT_IMPLEMENTED,        /* Protocol not supported */
  1590.         ESOCKTNOSUPPORT,    ERROR_NOT_IMPLEMENTED,        /* Socket type not supported */
  1591.         EOPNOTSUPP,            ERROR_NOT_IMPLEMENTED,        /* Operation not supported */
  1592.         EPFNOSUPPORT,        ERROR_NOT_IMPLEMENTED,        /* Protocol family not supported */
  1593.         EAFNOSUPPORT,        ERROR_NOT_IMPLEMENTED,        /* Address family not supported by protocol family */
  1594.         EADDRINUSE,            ERROR_OBJECT_IN_USE,        /* Address already in use */
  1595.         EADDRNOTAVAIL,        ERROR_OBJECT_NOT_FOUND,        /* Can't assign requested address */
  1596.         ENETDOWN,            ERROR_OBJECT_NOT_FOUND,        /* Network is down */
  1597.         ENETUNREACH,        ERROR_OBJECT_NOT_FOUND,        /* Network is unreachable */
  1598.         ENETRESET,            ERROR_OBJECT_NOT_FOUND,        /* Network dropped connection on reset */
  1599.         ECONNABORTED,        ERROR_OBJECT_NOT_FOUND,        /* Software caused connection abort */
  1600.         ECONNRESET,            ERROR_OBJECT_NOT_FOUND,        /* Connection reset by peer */
  1601.         ENOBUFS,            ERROR_DISK_FULL,            /* No buffer space available */
  1602.         EISCONN,            ERROR_OBJECT_IN_USE,        /* Socket is already connected */
  1603.         ENOTCONN,            ERROR_OBJECT_WRONG_TYPE,    /* Socket is not connected */
  1604.         ESHUTDOWN,            ERROR_INVALID_LOCK,            /* Can't send after socket shutdown */
  1605.         ECONNREFUSED,        ERROR_OBJECT_IN_USE,        /* Connection refused */
  1606.         ELOOP,                ERROR_TOO_MANY_LEVELS,        /* Too many levels of symbolic links */
  1607.         ENAMETOOLONG,        ERROR_LINE_TOO_LONG,        /* File name too long */
  1608.         EHOSTDOWN,            ERROR_OBJECT_NOT_FOUND,        /* Host is down */
  1609.         EHOSTUNREACH,        ERROR_OBJECT_NOT_FOUND,        /* No route to host */
  1610.         ENOTEMPTY,            ERROR_DIRECTORY_NOT_EMPTY,    /* Directory not empty */
  1611.         EPROCLIM,            ERROR_TASK_TABLE_FULL,        /* Too many processes */
  1612.         EUSERS,                ERROR_TASK_TABLE_FULL,        /* Too many users */
  1613.         EDQUOT,                ERROR_DISK_FULL,            /* Disc quota exceeded */
  1614.         -1
  1615.     };
  1616.  
  1617.     LONG result = ERROR_ACTION_NOT_KNOWN;
  1618.     LONG i;
  1619.  
  1620.     ENTER();
  1621.  
  1622.     if(error < 0)
  1623.         error = (-error);
  1624.  
  1625.     for(i = 0 ; Map[i][0] != -1 ; i++)
  1626.     {
  1627.         if(Map[i][0] == error)
  1628.         {
  1629.             result = Map[i][1];
  1630.             break;
  1631.         }
  1632.     }
  1633.  
  1634.     RETURN(result);
  1635.     return(result);
  1636. }
  1637.  
  1638. /****************************************************************************/
  1639.  
  1640. /* Translate a BCPL style file name (i.e. length is in the first byte)
  1641.  * via a mapping table.
  1642.  */
  1643. STATIC VOID INLINE
  1644. TranslateBName(UBYTE * name,UBYTE * map)
  1645. {
  1646.     if(TranslateNames)
  1647.     {
  1648.         LONG len;
  1649.         UBYTE c;
  1650.  
  1651.         len = (*name++);
  1652.  
  1653.         while(len-- > 0)
  1654.         {
  1655.             c = (*name);
  1656.  
  1657.             (*name++) = map[c];
  1658.         }
  1659.     }
  1660. }
  1661.  
  1662. /* Translate a NUL terminated file name via a mapping table. */
  1663. STATIC VOID INLINE
  1664. TranslateCName(UBYTE * name,UBYTE * map)
  1665. {
  1666.     if(TranslateNames)
  1667.     {
  1668.         UBYTE c;
  1669.  
  1670.         while((c = (*name)) != '\0')
  1671.             (*name++) = map[c];
  1672.     }
  1673. }
  1674.  
  1675. /****************************************************************************/
  1676.  
  1677. /* Remove a DosList entry using the proper protocols. Note that
  1678.  * this function can fail!
  1679.  */
  1680. STATIC BOOL
  1681. ReallyRemoveDosEntry(struct DosList * entry)
  1682. {
  1683.     struct Message * mn;
  1684.     struct MsgPort * port;
  1685.     struct DosList * dl;
  1686.     BOOL result = FALSE;
  1687.     LONG kind,i;
  1688.  
  1689.     if(entry->dol_Type == DLT_DEVICE)
  1690.         kind = LDF_DEVICES;
  1691.     else
  1692.         kind = LDF_VOLUMES;
  1693.  
  1694.     port = entry->dol_Task;
  1695.  
  1696.     for(i = 0 ; i < 100 ; i++)
  1697.     {
  1698.         dl = AttemptLockDosList(LDF_WRITE|kind);
  1699.         if(((ULONG)dl) <= 1)
  1700.             dl = NULL;
  1701.  
  1702.         if(dl != NULL)
  1703.         {
  1704.             RemDosEntry(entry);
  1705.  
  1706.             UnLockDosList(LDF_WRITE|kind);
  1707.  
  1708.             result = TRUE;
  1709.  
  1710.             break;
  1711.         }
  1712.  
  1713.         while((mn = GetMsg(port)) != NULL)
  1714.             ReplyPkt((struct DosPacket *)mn->mn_Node.ln_Name,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  1715.  
  1716.         Delay(TICKS_PER_SECOND / 10);
  1717.     }
  1718.  
  1719.     return(result);
  1720. }
  1721.  
  1722. /****************************************************************************/
  1723.  
  1724. /* Release all resources allocated by the Setup() routine. */
  1725. STATIC VOID
  1726. Cleanup(VOID)
  1727. {
  1728.     BOOL send_disk_change = FALSE;
  1729.  
  1730.     ENTER();
  1731.  
  1732.     /* If any errors have cropped up, display them now before
  1733.      * call it quits.
  1734.      */
  1735.     DisplayErrorList();
  1736.  
  1737.     if(NewProgramName != NULL)
  1738.     {
  1739.         FreeVec(NewProgramName);
  1740.         NewProgramName = NULL;
  1741.     }
  1742.  
  1743.     if(Parameters != NULL)
  1744.     {
  1745.         FreeArgs(Parameters);
  1746.         Parameters = NULL;
  1747.     }
  1748.  
  1749.     if(Icon != NULL)
  1750.     {
  1751.         FreeDiskObject(Icon);
  1752.         Icon = NULL;
  1753.     }
  1754.  
  1755.     if(ServerData != NULL)
  1756.     {
  1757.         smba_disconnect(ServerData);
  1758.         ServerData = NULL;
  1759.     }
  1760.  
  1761.     if(DeviceNode != NULL)
  1762.     {
  1763.         if(DeviceNodeAdded)
  1764.         {
  1765.             if(ReallyRemoveDosEntry(DeviceNode))
  1766.                 FreeDosEntry(DeviceNode);
  1767.         }
  1768.         else
  1769.         {
  1770.             FreeDosEntry(DeviceNode);
  1771.         }
  1772.  
  1773.         DeviceNode = NULL;
  1774.     }
  1775.  
  1776.     if(VolumeNode != NULL)
  1777.     {
  1778.         if(VolumeNodeAdded)
  1779.         {
  1780.             if(ReallyRemoveDosEntry(VolumeNode))
  1781.                 FreeDosEntry(VolumeNode);
  1782.  
  1783.             send_disk_change = TRUE;
  1784.         }
  1785.         else
  1786.         {
  1787.             FreeDosEntry(VolumeNode);
  1788.         }
  1789.  
  1790.         VolumeNode = NULL;
  1791.     }
  1792.  
  1793.     if(FileSystemPort != NULL)
  1794.     {
  1795.         struct Message * mn;
  1796.  
  1797.         /* Return all queued packets; there should be none, though. */
  1798.         while((mn = GetMsg(FileSystemPort)) != NULL)
  1799.             ReplyPkt((struct DosPacket *)mn->mn_Node.ln_Name,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  1800.  
  1801.         DeleteMsgPort(FileSystemPort);
  1802.         FileSystemPort = NULL;
  1803.     }
  1804.  
  1805.     if(WBStartup == NULL && send_disk_change)
  1806.         SendDiskChange(IECLASS_DISKREMOVED);
  1807.  
  1808.     if(TimerBase != NULL)
  1809.     {
  1810.         CloseDevice((struct IORequest *)&TimerRequest);
  1811.         TimerBase = NULL;
  1812.     }
  1813.  
  1814.     if(SocketBase != NULL)
  1815.     {
  1816.         CloseLibrary(SocketBase);
  1817.         SocketBase = NULL;
  1818.     }
  1819.  
  1820.     if(UtilityBase != NULL)
  1821.     {
  1822.         CloseLibrary(UtilityBase);
  1823.         UtilityBase = NULL;
  1824.     }
  1825.  
  1826.     if(IconBase != NULL)
  1827.     {
  1828.         CloseLibrary(IconBase);
  1829.         IconBase = NULL;
  1830.     }
  1831.  
  1832.     if(Locale != NULL)
  1833.     {
  1834.         CloseLocale(Locale);
  1835.         Locale = NULL;
  1836.     }
  1837.  
  1838.     if(LocaleBase != NULL)
  1839.     {
  1840.         CloseLibrary(LocaleBase);
  1841.         LocaleBase = NULL;
  1842.     }
  1843.  
  1844.     if(MemoryPool != NULL)
  1845.     {
  1846.         AsmDeletePool(MemoryPool,SysBase);
  1847.         MemoryPool = NULL;
  1848.     }
  1849.  
  1850.     if(DOSBase != NULL)
  1851.     {
  1852.         CloseLibrary(DOSBase);
  1853.         DOSBase = NULL;
  1854.     }
  1855.  
  1856.     if(WBStartup != NULL)
  1857.     {
  1858.         Forbid();
  1859.         ReplyMsg((struct Message *)WBStartup);
  1860.     }
  1861.  
  1862.     LEAVE();
  1863. }
  1864.  
  1865. /* Allocate all the necessary resources to get going. */
  1866. STATIC BOOL
  1867. Setup(
  1868.     STRPTR    program_name,
  1869.     STRPTR    service,
  1870.     STRPTR    workgroup,
  1871.     STRPTR     username,
  1872.     STRPTR    opt_password,
  1873.     BOOL    opt_changecase,
  1874.     STRPTR    opt_clientname,
  1875.     STRPTR    opt_servername,
  1876.     int        opt_cachesize,
  1877.     LONG *    opt_time_zone_offset,
  1878.     STRPTR    device_name,
  1879.     STRPTR    volume_name,
  1880.     STRPTR    translation_file)
  1881. {
  1882.     BOOL result = FALSE;
  1883.     int error;
  1884.     UBYTE name[MAX_FILENAME_LEN];
  1885.     LONG i;
  1886.  
  1887.     ENTER();
  1888.  
  1889.     NewList((struct List *)&FileList);
  1890.     NewList((struct List *)&LockList);
  1891.  
  1892.     MemoryPool = AsmCreatePool(MEMF_ANY|MEMF_PUBLIC,4096,4096,SysBase);
  1893.     if(MemoryPool == NULL)
  1894.     {
  1895.         ReportError("Could not create memory pool.");
  1896.         goto out;
  1897.     }
  1898.  
  1899.     LocaleBase = OpenLibrary("locale.library",38);
  1900.     if(LocaleBase != NULL)
  1901.         Locale = OpenLocale(NULL);
  1902.  
  1903.     if(opt_time_zone_offset != NULL)
  1904.     {
  1905.         TimeZoneOffset            = (*opt_time_zone_offset);
  1906.         OverrideLocaleTimeZone    = TRUE;
  1907.     }
  1908.  
  1909.     memset(&TimerRequest,0,sizeof(TimerRequest));
  1910.  
  1911.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)&TimerRequest,0) != OK)
  1912.     {
  1913.         ReportError("Could not open 'timer.device'.");
  1914.         goto out;
  1915.     }
  1916.  
  1917.     TimerBase = TimerRequest.tr_node.io_Device;
  1918.  
  1919.     SocketBase = OpenLibrary("bsdsocket.library",3);
  1920.     if(SocketBase == NULL)
  1921.     {
  1922.         ReportError("Could not open 'bsdsocket.library' V3; TCP/IP stack not running?");
  1923.         goto out;
  1924.     }
  1925.  
  1926.     error = SocketBaseTags(
  1927.         SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))),    &errno,
  1928.         SBTM_SETVAL(SBTC_HERRNOLONGPTR),            &h_errno,
  1929.         SBTM_SETVAL(SBTC_LOGTAGPTR),                program_name,
  1930.         SBTM_SETVAL(SBTC_BREAKMASK),                SIGBREAKF_CTRL_C,
  1931.     TAG_END);
  1932.     if(error != OK)
  1933.     {
  1934.         ReportError("Could not initialize 'bsdsocket.library' (%ld, %s).",error,amitcp_strerror(error));
  1935.         goto out;
  1936.     }
  1937.  
  1938.     if(opt_changecase)
  1939.     {
  1940.         for(i = 0 ; i < strlen(opt_password) ; i++)
  1941.             opt_password[i] = ToUpper(opt_password[i]);
  1942.     }
  1943.  
  1944.     TranslateNames = FALSE;
  1945.  
  1946.     /* Read the translation file, if possible. */
  1947.     if(translation_file != NULL)
  1948.     {
  1949.         LONG error = OK;
  1950.         STRPTR msg = NULL;
  1951.         BPTR file;
  1952.  
  1953.         file = Open(translation_file,MODE_OLDFILE);
  1954.         if(file != ZERO)
  1955.         {
  1956.             if(Read(file,A2M,256) != 256 ||
  1957.                Read(file,M2A,256) != 256)
  1958.             {
  1959.                 msg = "Could not read translation file";
  1960.                 error = IoErr();
  1961.             }
  1962.  
  1963.             Close(file);
  1964.         }
  1965.         else
  1966.         {
  1967.             msg = "Could not open translation file";
  1968.             error = IoErr();
  1969.         }
  1970.  
  1971.         if(msg == NULL)
  1972.         {
  1973.             TranslateNames = TRUE;
  1974.         }
  1975.         else
  1976.         {
  1977.             UBYTE description[100];
  1978.  
  1979.             Fault(error,NULL,description,sizeof(description));
  1980.             for(i = ((int)strlen(description)) - 1 ; i >= 0 ; i--)
  1981.             {
  1982.                 if(description[i] == '\n')
  1983.                     description[i] = '\0';
  1984.             }
  1985.  
  1986.             ReportError("%s '%s' (%ld, %s).",msg,translation_file,error,description);
  1987.             goto out;
  1988.         }
  1989.     }
  1990.  
  1991.     error = smba_start(service,workgroup,username,opt_password,opt_clientname,opt_servername,opt_cachesize,&ServerData);
  1992.     if(error < 0)
  1993.         goto out;
  1994.  
  1995.     FileSystemPort = CreateMsgPort();
  1996.     if(FileSystemPort == NULL)
  1997.     {
  1998.         ReportError("Could not create filesystem port.");
  1999.         goto out;
  2000.     }
  2001.  
  2002.     Forbid();
  2003.  
  2004.     /* If a device name was provided, check whether it is
  2005.      * well-formed.
  2006.      */
  2007.     if(device_name != NULL)
  2008.     {
  2009.         struct DosList * dl;
  2010.         BOOL device_exists;
  2011.  
  2012.         for(i = 0 ; i < strlen(device_name) ; i++)
  2013.         {
  2014.             if(device_name[i] == '/')
  2015.             {
  2016.                 Permit();
  2017.  
  2018.                 ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name);
  2019.                 goto out;
  2020.             }
  2021.         }
  2022.  
  2023.         if(device_name[0] == '\0')
  2024.         {
  2025.             Permit();
  2026.  
  2027.             ReportError("Device name '%s' cannot be used with AmigaDOS.",device_name);
  2028.             goto out;
  2029.         }
  2030.  
  2031.         strncpy(name,device_name,255);
  2032.         name[255] = '\0';
  2033.  
  2034.         /* Chop off any trailing colons. */
  2035.         for(i = strlen(name)-1 ; i >= 0 ; i--)
  2036.         {
  2037.             if(name[i] == ':')
  2038.                 name[i] = '\0';
  2039.         }
  2040.  
  2041.         if(device_name[0] == '\0')
  2042.         {
  2043.             Permit();
  2044.  
  2045.             ReportError("Device name '%s:' cannot be used with AmigaDOS.",device_name);
  2046.             goto out;
  2047.         }
  2048.  
  2049.         dl = LockDosList(LDF_READ|LDF_DEVICES);
  2050.         device_exists = (BOOL)(FindDosEntry(dl,device_name,LDF_DEVICES) != NULL);
  2051.         UnLockDosList(LDF_DEVICES);
  2052.  
  2053.         if(device_exists)
  2054.         {
  2055.             Permit();
  2056.  
  2057.             ReportError("Device name '%s:' is already taken.",device_name);
  2058.             goto out;
  2059.         }
  2060.     }
  2061.     else
  2062.     {
  2063.         struct DosList * dl;
  2064.         BOOL device_exists;
  2065.  
  2066.         /* Find a unique device name. */
  2067.         for(i = 0 ; i < 100 ; i++)
  2068.         {
  2069.             SPrintf(name,"SMBFS%ld",i);
  2070.  
  2071.             dl = LockDosList(LDF_READ|LDF_DEVICES);
  2072.             device_exists = (BOOL)(FindDosEntry(dl,name,LDF_DEVICES) != NULL);
  2073.             UnLockDosList(LDF_DEVICES);
  2074.  
  2075.             if(NOT device_exists)
  2076.             {
  2077.                 device_name = name;
  2078.                 break;
  2079.             }
  2080.         }
  2081.     }
  2082.  
  2083.     if(device_name != NULL)
  2084.     {
  2085.         DeviceNode = MakeDosEntry(name,DLT_DEVICE);
  2086.         if(DeviceNode == NULL)
  2087.         {
  2088.             Permit();
  2089.  
  2090.             ReportError("Could not create device node.");
  2091.             goto out;
  2092.         }
  2093.  
  2094.         DeviceNode->dol_Task = FileSystemPort;
  2095.  
  2096.         AddDosEntry(DeviceNode);
  2097.         DeviceNodeAdded = TRUE;
  2098.     }
  2099.  
  2100.     Permit();
  2101.  
  2102.     /* Now take care of the volume name; make sure that it is
  2103.      * well-formed.
  2104.      */
  2105.     if(volume_name == NULL)
  2106.         strncpy(name,device_name,255);
  2107.     else
  2108.         strncpy(name,volume_name,255);
  2109.  
  2110.     name[255] = '\0';
  2111.  
  2112.     for(i = 0 ; i < strlen(name) ; i++)
  2113.     {
  2114.         if(name[i] == '/')
  2115.         {
  2116.             ReportError("Volume name '%s' cannot be used with AmigaDOS.",name);
  2117.             goto out;
  2118.         }
  2119.     }
  2120.  
  2121.     if(name[0] == '\0')
  2122.     {
  2123.         ReportError("Volume name '%s' cannot be used with AmigaDOS.",name);
  2124.         goto out;
  2125.     }
  2126.  
  2127.     /* Chop off any trailing colons. */
  2128.     for(i = strlen(name)-1 ; i >= 0 ; i--)
  2129.     {
  2130.         if(name[i] == ':')
  2131.             name[i] = '\0';
  2132.     }
  2133.  
  2134.     VolumeNode = MakeDosEntry(name,DLT_VOLUME);
  2135.     if(VolumeNode == NULL)
  2136.     {
  2137.         ReportError("Could not create volume node.");
  2138.         goto out;
  2139.     }
  2140.  
  2141.     VolumeNode->dol_Task = FileSystemPort;
  2142.     DateStamp(&VolumeNode->dol_misc.dol_volume.dol_VolumeDate);
  2143.     VolumeNode->dol_misc.dol_volume.dol_DiskType = ID_DOS_DISK;
  2144.  
  2145.     if(volume_name != NULL)
  2146.     {
  2147.          AddDosEntry(VolumeNode);
  2148.         VolumeNodeAdded = TRUE;
  2149.  
  2150.         SendDiskChange(IECLASS_DISKINSERTED);
  2151.     }
  2152.  
  2153.     SetProgramName(NewProgramName);
  2154.  
  2155.     result = TRUE;
  2156.  
  2157.  out:
  2158.  
  2159.     RETURN(result);
  2160.     return(result);
  2161. }
  2162.  
  2163. /****************************************************************************/
  2164.  
  2165. /* Convert a BCPL string into a standard NUL terminated 'C' string. */
  2166. STATIC VOID INLINE
  2167. ConvertBString(LONG max_len,STRPTR cstring,APTR bstring)
  2168. {
  2169.     STRPTR from = bstring;
  2170.     LONG len = from[0];
  2171.  
  2172.     if(len > max_len-1)
  2173.         len = max_len-1;
  2174.  
  2175.     if(len > 0)
  2176.         strncpy(cstring,from+1,len);
  2177.  
  2178.     cstring[len] = '\0';
  2179. }
  2180.  
  2181. /* Convert a NUL terminated 'C' string into a BCPL string. */
  2182. STATIC VOID INLINE
  2183. ConvertCString(LONG max_len,APTR bstring,STRPTR cstring)
  2184. {
  2185.     LONG len = strlen(cstring);
  2186.     STRPTR to = bstring;
  2187.  
  2188.     if(len > max_len-1)
  2189.         len = max_len-1;
  2190.  
  2191.     (*to++) = len;
  2192.     memcpy(to,cstring,len);
  2193. }
  2194.  
  2195. /****************************************************************************/
  2196.  
  2197. /* Build the fully qualified name of a file or directory in reference
  2198.  * to the name of the parent directory. This takes care of all the
  2199.  * special cases, such as the root directory. The result will be converted
  2200.  * to be in a form suitable for use with the SMB file sharing service.
  2201.  */
  2202. STATIC LONG
  2203. BuildFullName(
  2204.     STRPTR        parent_name,
  2205.     STRPTR        name,
  2206.     STRPTR *    result_ptr)
  2207. {
  2208.     LONG error = OK;
  2209.     STRPTR buffer;
  2210.     LONG len;
  2211.     LONG i;
  2212.  
  2213.     ENTER();
  2214.  
  2215.     SHOWSTRING(parent_name);
  2216.     SHOWSTRING(name);
  2217.  
  2218.     (*result_ptr) = NULL;
  2219.  
  2220.     /* Throw everything left of the colon away. */
  2221.     if(name != NULL)
  2222.     {
  2223.         for(i = 0 ; i < strlen(name) ; i++)
  2224.         {
  2225.             if(name[i] == ':')
  2226.             {
  2227.                 name = &name[i+1];
  2228.                 break;
  2229.             }
  2230.         }
  2231.     }
  2232.  
  2233.     /* Now, how much room is needed for the complete
  2234.      * path to fit into a buffer?
  2235.      */
  2236.     len = 2;
  2237.  
  2238.     if(parent_name != NULL)
  2239.         len += strlen(parent_name) + 1;
  2240.  
  2241.     if(name != NULL)
  2242.         len += strlen(name) + 1;
  2243.  
  2244.     buffer = AllocVecPooled(len+3);
  2245.     if(buffer == NULL)
  2246.     {
  2247.         error = ERROR_NO_FREE_STORE;
  2248.         goto out;
  2249.     }
  2250.  
  2251.     /* Start by filling in the path name. */
  2252.     if(parent_name != NULL)
  2253.     {
  2254.         /* Skip any excess separators. */
  2255.         while((*parent_name) == SMB_PATH_SEPARATOR)
  2256.             parent_name++;
  2257.  
  2258.         buffer[0] = SMB_PATH_SEPARATOR;
  2259.         strcpy(&buffer[1],parent_name);
  2260.     }
  2261.     else
  2262.     {
  2263.         strcpy(buffer,SMB_ROOT_DIR_NAME);
  2264.     }
  2265.  
  2266.     /* If there's a name to add, do just that. */
  2267.     if(name != NULL)
  2268.     {
  2269.         LONG segment_start;
  2270.         LONG segment_len;
  2271.         LONG buffer_len;
  2272.         LONG name_len;
  2273.  
  2274.         buffer_len = strlen(buffer);
  2275.         name_len = strlen(name);
  2276.  
  2277.         segment_start = 0;
  2278.  
  2279.         while(TRUE)
  2280.         {
  2281.             segment_len = 0;
  2282.  
  2283.             /* Extract the next path name segment. */
  2284.             for(i = segment_start ; i <= name_len ; i++)
  2285.             {
  2286.                 if(i == name_len)
  2287.                 {
  2288.                     segment_len = i - segment_start;
  2289.                     break;
  2290.                 }
  2291.                 else if (name[i] == '/')
  2292.                 {
  2293.                     segment_len = i - segment_start + 1;
  2294.                     break;
  2295.                 }
  2296.             }
  2297.  
  2298.             /* We're finished if there are no further
  2299.              * path name segments to take care of.
  2300.              */
  2301.             if(segment_len == 0)
  2302.             {
  2303.                 buffer[buffer_len] = '\0';
  2304.                 break;
  2305.             }
  2306.  
  2307.             /* A single slash indicates that we need to move up
  2308.              * to the parent directory, if any.
  2309.              */
  2310.             if(segment_len == 1 && name[segment_start] == '/')
  2311.             {
  2312.                 /* Is this already the root directory name? */
  2313.                 if(buffer_len == 1)
  2314.                 {
  2315.                     FreeVecPooled(buffer);
  2316.                     buffer = NULL;
  2317.  
  2318.                     goto out;
  2319.                 }
  2320.                 else
  2321.                 {
  2322.                     /* Skip the last path component. */
  2323.                     for(i = 1 ; i <= buffer_len ; i++)
  2324.                     {
  2325.                         if(i == buffer_len)
  2326.                         {
  2327.                             /* We just skipped the first path
  2328.                              * component following the root
  2329.                              * directory name. We preserve
  2330.                              * the first character since it
  2331.                              * refers to the root directory.
  2332.                              */
  2333.                             buffer_len = 1;
  2334.                             break;
  2335.                         }
  2336.                         else if (buffer[buffer_len-i] == SMB_PATH_SEPARATOR)
  2337.                         {
  2338.                             /* This removes both the path separator and
  2339.                              * the name following it.
  2340.                              */
  2341.                             buffer_len -= i;
  2342.                             break;
  2343.                         }
  2344.                     }
  2345.                 }
  2346.             }
  2347.             else
  2348.             {
  2349.                 /* Add a proper separator character if
  2350.                  * necessary.
  2351.                  */
  2352.                 if(buffer_len > 0 && buffer[buffer_len-1] != SMB_PATH_SEPARATOR)
  2353.                     buffer[buffer_len++] = SMB_PATH_SEPARATOR;
  2354.  
  2355.                 /* Find out how many characters are in that name; this
  2356.                  * excludes the terminating slash.
  2357.                  */
  2358.                 if(name[segment_start + segment_len - 1] == '/')
  2359.                     len = segment_len - 1;
  2360.                 else
  2361.                     len = segment_len;
  2362.  
  2363.                 memcpy(&buffer[buffer_len],&name[segment_start],len);
  2364.                 buffer_len += len;
  2365.             }
  2366.  
  2367.             segment_start += segment_len;
  2368.         }
  2369.     }
  2370.  
  2371.     (*result_ptr) = buffer;
  2372.  
  2373.     SHOWSTRING(buffer);
  2374.  
  2375.  out:
  2376.  
  2377.     if(error != OK)
  2378.         FreeVecPooled(buffer);
  2379.  
  2380.     RETURN(error);
  2381.     return(error);
  2382. }
  2383.  
  2384. /****************************************************************************/
  2385.  
  2386. STATIC BPTR
  2387. Action_Parent(
  2388.     struct FileLock *    parent,
  2389.     LONG *                error_ptr)
  2390. {
  2391.     BPTR result = ZERO;
  2392.     STRPTR full_name = NULL;
  2393.     STRPTR parent_name;
  2394.     BOOL cleanup = TRUE;
  2395.     struct LockNode * ln = NULL;
  2396.     LONG error;
  2397.  
  2398.     ENTER();
  2399.  
  2400.     SHOWVALUE(parent);
  2401.  
  2402.     if(parent != NULL)
  2403.     {
  2404.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  2405.  
  2406.         parent_name = ln->ln_FullName;
  2407.     }
  2408.     else
  2409.     {
  2410.         parent_name = NULL;
  2411.     }
  2412.  
  2413.     error = BuildFullName(parent_name,"/",&full_name);
  2414.     if(error != OK)
  2415.         goto out;
  2416.  
  2417.     /* Check if we ended up having to return the parent of
  2418.      * the root directory. This is indicated by a NULL
  2419.      * name pointer and a zero error code.
  2420.      */
  2421.     if(full_name == NULL)
  2422.         goto out;
  2423.  
  2424.     ln = AllocVecPooled(sizeof(*ln));
  2425.     if(ln == NULL)
  2426.     {
  2427.         error = ERROR_NO_FREE_STORE;
  2428.         goto out;
  2429.     }
  2430.  
  2431.     memset(ln,0,sizeof(*ln));
  2432.  
  2433.     ln->ln_FileLock.fl_Key        = (LONG)ln;
  2434.     ln->ln_FileLock.fl_Access    = SHARED_LOCK;
  2435.     ln->ln_FileLock.fl_Task        = FileSystemPort;
  2436.     ln->ln_FileLock.fl_Volume    = MKBADDR(VolumeNode);
  2437.     ln->ln_FullName                = full_name;
  2438.  
  2439.     SHOWSTRING(full_name);
  2440.  
  2441.     error = smba_open(ServerData,full_name,&ln->ln_File);
  2442.     if(error < 0)
  2443.     {
  2444.         error = MapErrnoToIoErr(error);
  2445.         goto out;
  2446.     }
  2447.  
  2448.     AddTail((struct List *)&LockList,(struct Node *)ln);
  2449.     result = MKBADDR(&ln->ln_FileLock);
  2450.     cleanup = FALSE;
  2451.     SHOWVALUE(&ln->ln_FileLock);
  2452.  
  2453.  out:
  2454.  
  2455.     if(cleanup)
  2456.     {
  2457.         FreeVecPooled(full_name);
  2458.         FreeVecPooled(ln);
  2459.     }
  2460.  
  2461.     (*error_ptr) = error;
  2462.  
  2463.     RETURN(result);
  2464.     return(result);
  2465. }
  2466.  
  2467. /****************************************************************************/
  2468.  
  2469. STATIC LONG
  2470. Action_DeleteObject(
  2471.     struct FileLock *    parent,
  2472.     APTR                bcpl_name,
  2473.     LONG *                error_ptr)
  2474. {
  2475.     LONG result = DOSFALSE;
  2476.     STRPTR full_name = NULL;
  2477.     smba_file_t * file = NULL;
  2478.     STRPTR parent_name;
  2479.     STRPTR full_parent_name = NULL;
  2480.     UBYTE name[MAX_FILENAME_LEN];
  2481.     struct LockNode * ln;
  2482.     smba_stat_t stat;
  2483.     LONG error;
  2484.  
  2485.     ENTER();
  2486.  
  2487.     if(WriteProtected)
  2488.     {
  2489.         error = ERROR_DISK_WRITE_PROTECTED;
  2490.         goto out;
  2491.     }
  2492.  
  2493.     SHOWVALUE(parent);
  2494.  
  2495.     if(parent != NULL)
  2496.     {
  2497.         ln = (struct LockNode *)parent->fl_Key;
  2498.  
  2499.         parent_name = ln->ln_FullName;
  2500.     }
  2501.     else
  2502.     {
  2503.         parent_name = NULL;
  2504.     }
  2505.  
  2506.     ConvertBString(sizeof(name),name,bcpl_name);
  2507.     TranslateCName(name,A2M);
  2508.  
  2509.     error = BuildFullName(parent_name,name,&full_name);
  2510.     if(error != OK)
  2511.         goto out;
  2512.  
  2513.     /* Trying to delete the root directory, are you kidding? */
  2514.     if(full_name == NULL)
  2515.     {
  2516.         error = ERROR_OBJECT_WRONG_TYPE;
  2517.         goto out;
  2518.     }
  2519.  
  2520.     /* We need to find this file's parent directory, so that
  2521.      * in case the directory contents are currently being
  2522.      * examined, that process is restarted.
  2523.      */
  2524.     full_parent_name = AllocVecPooled(strlen(full_name)+3);
  2525.     if(full_parent_name == NULL)
  2526.     {
  2527.         error = ERROR_NO_FREE_STORE;
  2528.         goto out;
  2529.     }
  2530.  
  2531.     strcpy(full_parent_name,full_name);
  2532.  
  2533.     ln = FindLockNode(full_parent_name,NULL);
  2534.     if(ln != NULL)
  2535.         ln->ln_RestartExamine = TRUE;
  2536.  
  2537.     FreeVecPooled(full_parent_name);
  2538.     full_parent_name = NULL;
  2539.  
  2540.     SHOWSTRING(full_name);
  2541.  
  2542.     error = smba_open(ServerData,full_name,&file);
  2543.     if(error < 0)
  2544.     {
  2545.         error = MapErrnoToIoErr(error);
  2546.         goto out;
  2547.     }
  2548.  
  2549.     error = smba_getattr(file,&stat);
  2550.     if(error < 0)
  2551.     {
  2552.         error = MapErrnoToIoErr(error);
  2553.         goto out;
  2554.     }
  2555.  
  2556.     smba_close(file);
  2557.     file = NULL;
  2558.  
  2559.     if(stat.is_dir)
  2560.     {
  2561.         SHOWMSG("removing a directory");
  2562.  
  2563.         error = smba_rmdir(ServerData,full_name);
  2564.         if(error < 0)
  2565.         {
  2566.             SHOWVALUE(error);
  2567.  
  2568.             /* This is a little bit difficult to justify since
  2569.              * the error code may indicate a different cause,
  2570.              * but in practice 'EACCES' seems to be returned
  2571.              * if the directory to remove is not empty.
  2572.              */
  2573.             if(error == (-EACCES))
  2574.                 error = ERROR_DIRECTORY_NOT_EMPTY;
  2575.             else
  2576.                 error = MapErrnoToIoErr(error);
  2577.  
  2578.             goto out;
  2579.         }
  2580.     }
  2581.     else
  2582.     {
  2583.         SHOWMSG("removing a file");
  2584.  
  2585.         error = smba_remove(ServerData,full_name);
  2586.         if(error < 0)
  2587.         {
  2588.             SHOWVALUE(error);
  2589.  
  2590.             error = MapErrnoToIoErr(error);
  2591.             goto out;
  2592.         }
  2593.     }
  2594.  
  2595.     SHOWMSG("done.");
  2596.  
  2597.     result = DOSTRUE;
  2598.  
  2599.  out:
  2600.  
  2601.     FreeVecPooled(full_name);
  2602.     FreeVecPooled(full_parent_name);
  2603.     if(file != NULL)
  2604.         smba_close(file);
  2605.  
  2606.     (*error_ptr) = error;
  2607.  
  2608.     RETURN(result);
  2609.     return(result);
  2610. }
  2611.  
  2612. /****************************************************************************/
  2613.  
  2614. STATIC BPTR
  2615. Action_CreateDir(
  2616.     struct FileLock *    parent,
  2617.     APTR                bcpl_name,
  2618.     LONG *                error_ptr)
  2619. {
  2620.     BPTR result = ZERO;
  2621.     STRPTR full_name = NULL;
  2622.     struct LockNode * ln = NULL;
  2623.     STRPTR parent_name;
  2624.     STRPTR dir_name = NULL;
  2625.     smba_file_t * dir = NULL;
  2626.     STRPTR base_name;
  2627.     UBYTE name[MAX_FILENAME_LEN];
  2628.     LONG error;
  2629.     LONG i;
  2630.  
  2631.     ENTER();
  2632.  
  2633.     if(WriteProtected)
  2634.     {
  2635.         error = ERROR_DISK_WRITE_PROTECTED;
  2636.         goto out;
  2637.     }
  2638.  
  2639.     SHOWVALUE(parent);
  2640.  
  2641.     if(parent != NULL)
  2642.     {
  2643.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  2644.  
  2645.         parent_name = ln->ln_FullName;
  2646.     }
  2647.     else
  2648.     {
  2649.         parent_name = NULL;
  2650.     }
  2651.  
  2652.     ConvertBString(sizeof(name),name,bcpl_name);
  2653.     TranslateCName(name,A2M);
  2654.  
  2655.     error = BuildFullName(parent_name,name,&full_name);
  2656.     if(error != OK)
  2657.         goto out;
  2658.  
  2659.     /* Trying to overwrite the root directory, are you kidding? */
  2660.     if(full_name == NULL)
  2661.     {
  2662.         error = ERROR_OBJECT_IN_USE;
  2663.         goto out;
  2664.     }
  2665.  
  2666.     dir_name = AllocVecPooled(strlen(full_name)+3);
  2667.     if(dir_name == NULL)
  2668.     {
  2669.         error = ERROR_NO_FREE_STORE;
  2670.         goto out;
  2671.     }
  2672.  
  2673.     strcpy(dir_name,full_name);
  2674.     base_name = NULL;
  2675.     for(i = strlen(dir_name)-1 ; i >= 0 ; i--)
  2676.     {
  2677.         if(dir_name[i] == SMB_PATH_SEPARATOR)
  2678.         {
  2679.             if(i == 0)
  2680.             {
  2681.                 memmove(&dir_name[1],&dir_name[0],strlen(dir_name)+1);
  2682.                 i++;
  2683.             }
  2684.  
  2685.             dir_name[i] = '\0';
  2686.  
  2687.             base_name = &dir_name[i+1];
  2688.             break;
  2689.         }
  2690.     }
  2691.  
  2692.     ln = AllocVecPooled(sizeof(*ln));
  2693.     if(ln == NULL)
  2694.     {
  2695.         error = ERROR_NO_FREE_STORE;
  2696.         goto out;
  2697.     }
  2698.  
  2699.     memset(ln,0,sizeof(*ln));
  2700.  
  2701.     ln->ln_FileLock.fl_Key        = (LONG)ln;
  2702.     ln->ln_FileLock.fl_Access    = EXCLUSIVE_LOCK;
  2703.     ln->ln_FileLock.fl_Task        = FileSystemPort;
  2704.     ln->ln_FileLock.fl_Volume    = MKBADDR(VolumeNode);
  2705.     ln->ln_FullName                = full_name;
  2706.  
  2707.     error = smba_open(ServerData,dir_name,&dir);
  2708.     if(error < 0)
  2709.     {
  2710.         error = MapErrnoToIoErr(error);
  2711.         goto out;
  2712.     }
  2713.  
  2714.     error = smba_mkdir(dir,base_name);
  2715.     if(error < 0)
  2716.     {
  2717.         error = MapErrnoToIoErr(error);
  2718.         goto out;
  2719.     }
  2720.  
  2721.     smba_close(dir);
  2722.     dir = NULL;
  2723.  
  2724.     SHOWSTRING(full_name);
  2725.  
  2726.     error = smba_open(ServerData,full_name,&ln->ln_File);
  2727.     if(error < 0)
  2728.     {
  2729.         error = MapErrnoToIoErr(error);
  2730.         goto out;
  2731.     }
  2732.  
  2733.     AddTail((struct List *)&LockList,(struct Node *)ln);
  2734.     result = MKBADDR(&ln->ln_FileLock);
  2735.     SHOWVALUE(&ln->ln_FileLock);
  2736.  
  2737.  out:
  2738.  
  2739.     if(dir != NULL)
  2740.         smba_close(dir);
  2741.  
  2742.     FreeVecPooled(dir_name);
  2743.  
  2744.     if(result == ZERO)
  2745.     {
  2746.         FreeVecPooled(full_name);
  2747.         FreeVecPooled(ln);
  2748.     }
  2749.  
  2750.     (*error_ptr) = error;
  2751.  
  2752.     RETURN(result);
  2753.     return(result);
  2754. }
  2755.  
  2756. /****************************************************************************/
  2757.  
  2758. STATIC BPTR
  2759. Action_LocateObject(
  2760.     struct FileLock *    parent,
  2761.     APTR                bcpl_name,
  2762.     LONG                mode,
  2763.     LONG *                error_ptr)
  2764. {
  2765.     BPTR result = ZERO;
  2766.     STRPTR full_name = NULL;
  2767.     struct LockNode * ln = NULL;
  2768.     STRPTR parent_name;
  2769.     UBYTE name[MAX_FILENAME_LEN];
  2770.     LONG error;
  2771.  
  2772.     ENTER();
  2773.  
  2774.     SHOWVALUE(parent);
  2775.  
  2776.     if(parent != NULL)
  2777.     {
  2778.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  2779.  
  2780.         parent_name = ln->ln_FullName;
  2781.     }
  2782.     else
  2783.     {
  2784.         parent_name = NULL;
  2785.     }
  2786.  
  2787.     ConvertBString(sizeof(name),name,bcpl_name);
  2788.     TranslateCName(name,A2M);
  2789.  
  2790.     if(IsReservedName(FilePart(name)))
  2791.     {
  2792.         error = ERROR_OBJECT_NOT_FOUND;
  2793.         goto out;
  2794.     }
  2795.  
  2796.     error = BuildFullName(parent_name,name,&full_name);
  2797.     if(error != OK)
  2798.         goto out;
  2799.  
  2800.     /* Trying to get a lock on the root directory's parent?
  2801.      * My pleasure.
  2802.      */
  2803.     if(full_name == NULL)
  2804.         goto out;
  2805.  
  2806.     ln = AllocVecPooled(sizeof(*ln));
  2807.     if(ln == NULL)
  2808.     {
  2809.         error = ERROR_NO_FREE_STORE;
  2810.         goto out;
  2811.     }
  2812.  
  2813.     memset(ln,0,sizeof(*ln));
  2814.  
  2815.     ln->ln_FileLock.fl_Key        = (LONG)ln;
  2816.     ln->ln_FileLock.fl_Access    = (mode != EXCLUSIVE_LOCK) ? SHARED_LOCK : EXCLUSIVE_LOCK;
  2817.     ln->ln_FileLock.fl_Task        = FileSystemPort;
  2818.     ln->ln_FileLock.fl_Volume    = MKBADDR(VolumeNode);
  2819.     ln->ln_FullName                = full_name;
  2820.  
  2821.     error = CheckAccessModeCollision(full_name,ln->ln_FileLock.fl_Access);
  2822.     if(error != OK)
  2823.         goto out;
  2824.  
  2825.     SHOWSTRING(full_name);
  2826.  
  2827.     error = smba_open(ServerData,full_name,&ln->ln_File);
  2828.     if(error < 0)
  2829.     {
  2830.         error = MapErrnoToIoErr(error);
  2831.         goto out;
  2832.     }
  2833.  
  2834.     AddTail((struct List *)&LockList,(struct Node *)ln);
  2835.     result = MKBADDR(&ln->ln_FileLock);
  2836.     SHOWVALUE(&ln->ln_FileLock);
  2837.  
  2838.  out:
  2839.  
  2840.     if(result == ZERO)
  2841.     {
  2842.         FreeVecPooled(full_name);
  2843.         FreeVecPooled(ln);
  2844.     }
  2845.  
  2846.     (*error_ptr) = error;
  2847.  
  2848.     RETURN(result);
  2849.     return(result);
  2850. }
  2851.  
  2852. /****************************************************************************/
  2853.  
  2854. STATIC BPTR
  2855. Action_CopyDir(
  2856.     struct FileLock *    lock,
  2857.     LONG *                error_ptr)
  2858. {
  2859.     BPTR result = ZERO;
  2860.     STRPTR full_name = NULL;
  2861.     struct LockNode * ln = NULL;
  2862.     STRPTR source_name;
  2863.     LONG source_mode;
  2864.     LONG error;
  2865.  
  2866.     ENTER();
  2867.  
  2868.     SHOWVALUE(lock);
  2869.  
  2870.     if(lock != NULL && lock->fl_Access != SHARED_LOCK)
  2871.     {
  2872.         SHOWMSG("cannot duplicate exclusive lock");
  2873.         error = ERROR_OBJECT_IN_USE;
  2874.         goto out;
  2875.     }
  2876.  
  2877.     ln = AllocVecPooled(sizeof(*ln));
  2878.     if(ln == NULL)
  2879.     {
  2880.         error = ERROR_NO_FREE_STORE;
  2881.         goto out;
  2882.     }
  2883.  
  2884.     memset(ln,0,sizeof(*ln));
  2885.  
  2886.     if(lock != NULL)
  2887.     {
  2888.         struct LockNode * source = (struct LockNode *)lock->fl_Key;
  2889.  
  2890.         source_name = source->ln_FullName;
  2891.         source_mode = source->ln_FileLock.fl_Access;
  2892.     }
  2893.     else
  2894.     {
  2895.         source_name = SMB_ROOT_DIR_NAME;
  2896.         source_mode = SHARED_LOCK;
  2897.     }
  2898.  
  2899.     full_name = AllocVecPooled(strlen(source_name)+3);
  2900.     if(full_name == NULL)
  2901.     {
  2902.         error = ERROR_NO_FREE_STORE;
  2903.         goto out;
  2904.     }
  2905.  
  2906.     strcpy(full_name,source_name);
  2907.  
  2908.     ln->ln_FileLock.fl_Key        = (LONG)ln;
  2909.     ln->ln_FileLock.fl_Access    = source_mode;
  2910.     ln->ln_FileLock.fl_Task        = FileSystemPort;
  2911.     ln->ln_FileLock.fl_Volume    = MKBADDR(VolumeNode);
  2912.     ln->ln_FullName                = full_name;
  2913.  
  2914.     SHOWSTRING(full_name);
  2915.  
  2916.     error = smba_open(ServerData,full_name,&ln->ln_File);
  2917.     if(error < 0)
  2918.     {
  2919.         error = MapErrnoToIoErr(error);
  2920.         goto out;
  2921.     }
  2922.  
  2923.     AddTail((struct List *)&LockList,(struct Node *)ln);
  2924.     result = MKBADDR(&ln->ln_FileLock);
  2925.     SHOWVALUE(&ln->ln_FileLock);
  2926.  
  2927.  out:
  2928.  
  2929.     if(result == ZERO)
  2930.     {
  2931.         FreeVecPooled(full_name);
  2932.         FreeVecPooled(ln);
  2933.     }
  2934.  
  2935.     (*error_ptr) = error;
  2936.  
  2937.     RETURN(result);
  2938.     return(result);
  2939. }
  2940.  
  2941. /****************************************************************************/
  2942.  
  2943. STATIC LONG
  2944. Action_FreeLock(
  2945.     struct FileLock *    lock,
  2946.     LONG *                error_ptr)
  2947. {
  2948.     LONG result = DOSTRUE;
  2949.     struct LockNode * ln;
  2950.     LONG error = OK;
  2951.  
  2952.     ENTER();
  2953.  
  2954.     SHOWVALUE(lock);
  2955.  
  2956.     if(lock == NULL)
  2957.         goto out;
  2958.  
  2959.     ln = (struct LockNode *)lock->fl_Key;
  2960.  
  2961.     Remove((struct Node *)ln);
  2962.     smba_close(ln->ln_File);
  2963.     FreeVecPooled(ln->ln_FullName);
  2964.     FreeVecPooled(ln);
  2965.  
  2966.  out:
  2967.  
  2968.     (*error_ptr) = error;
  2969.  
  2970.     RETURN(result);
  2971.     return(result);
  2972. }
  2973.  
  2974. /****************************************************************************/
  2975.  
  2976. STATIC LONG
  2977. Action_SameLock(
  2978.     struct FileLock *    lock1,
  2979.     struct FileLock *    lock2,
  2980.     LONG *                error_ptr)
  2981. {
  2982.     LONG result = DOSFALSE;
  2983.     STRPTR name1;
  2984.     STRPTR name2;
  2985.     LONG error = OK;
  2986.  
  2987.     ENTER();
  2988.  
  2989.     SHOWVALUE(lock1);
  2990.     SHOWVALUE(lock2);
  2991.  
  2992.     if(lock1 != NULL)
  2993.     {
  2994.         struct LockNode * ln = (struct LockNode *)lock1->fl_Key;
  2995.  
  2996.         name1 = ln->ln_FullName;
  2997.     }
  2998.     else
  2999.     {
  3000.         name1 = SMB_ROOT_DIR_NAME;
  3001.     }
  3002.  
  3003.     if(lock2 != NULL)
  3004.     {
  3005.         struct LockNode * ln = (struct LockNode *)lock2->fl_Key;
  3006.  
  3007.         name2 = ln->ln_FullName;
  3008.     }
  3009.     else
  3010.     {
  3011.         name2 = SMB_ROOT_DIR_NAME;
  3012.     }
  3013.  
  3014.     SHOWSTRING(name1);
  3015.     SHOWSTRING(name2);
  3016.  
  3017.     if(Stricmp(name1,name2) == SAME)
  3018.         result = DOSTRUE;
  3019.  
  3020.     (*error_ptr) = error;
  3021.  
  3022.     RETURN(result);
  3023.     return(result);
  3024. }
  3025.  
  3026. /****************************************************************************/
  3027.  
  3028. STATIC LONG
  3029. Action_SetProtect(
  3030.     struct FileLock *    parent,
  3031.     APTR                bcpl_name,
  3032.     LONG                mask,
  3033.     LONG *                error_ptr)
  3034. {
  3035.     LONG result = DOSFALSE;
  3036.     STRPTR full_name = NULL;
  3037.     smba_file_t * file = NULL;
  3038.     STRPTR parent_name;
  3039.     UBYTE name[MAX_FILENAME_LEN];
  3040.     smba_stat_t stat;
  3041.     LONG error;
  3042.  
  3043.     ENTER();
  3044.  
  3045.     if(WriteProtected)
  3046.     {
  3047.         error = ERROR_DISK_WRITE_PROTECTED;
  3048.         goto out;
  3049.     }
  3050.  
  3051.     SHOWVALUE(parent);
  3052.  
  3053.     if(parent != NULL)
  3054.     {
  3055.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  3056.  
  3057.         parent_name = ln->ln_FullName;
  3058.     }
  3059.     else
  3060.     {
  3061.         parent_name = NULL;
  3062.     }
  3063.  
  3064.     ConvertBString(sizeof(name),name,bcpl_name);
  3065.     TranslateCName(name,A2M);
  3066.  
  3067.     error = BuildFullName(parent_name,name,&full_name);
  3068.     if(error != OK)
  3069.         goto out;
  3070.  
  3071.     /* Trying to change the protection bits of the root
  3072.      * directory, are you kidding?
  3073.      */
  3074.     if(full_name == NULL)
  3075.     {
  3076.         error = ERROR_OBJECT_WRONG_TYPE;
  3077.         goto out;
  3078.     }
  3079.  
  3080.     SHOWSTRING(full_name);
  3081.  
  3082.     error = smba_open(ServerData,full_name,&file);
  3083.     if(error < 0)
  3084.     {
  3085.         error = MapErrnoToIoErr(error);
  3086.         goto out;
  3087.     }
  3088.  
  3089.     memset(&stat,0,sizeof(stat));
  3090.  
  3091.     mask ^= FIBF_READ | FIBF_WRITE | FIBF_EXECUTE | FIBF_DELETE;
  3092.  
  3093.     stat.atime = -1;
  3094.     stat.ctime = -1;
  3095.     stat.mtime = -1;
  3096.     stat.size = -1;
  3097.  
  3098.     if((mask & (FIBF_WRITE|FIBF_DELETE)) != (FIBF_WRITE|FIBF_DELETE))
  3099.     {
  3100.         SHOWMSG("write protection enabled");
  3101.         stat.is_wp = TRUE;
  3102.     }
  3103.     else
  3104.     {
  3105.         SHOWMSG("write protection disabled");
  3106.     }
  3107.  
  3108.     error = smba_setattr(file,&stat);
  3109.     if(error < 0)
  3110.     {
  3111.         error = MapErrnoToIoErr(error);
  3112.         goto out;
  3113.     }
  3114.  
  3115.     result = DOSTRUE;
  3116.  
  3117.  out:
  3118.  
  3119.     FreeVecPooled(full_name);
  3120.     if(file != NULL)
  3121.         smba_close(file);
  3122.  
  3123.     (*error_ptr) = error;
  3124.  
  3125.     RETURN(result);
  3126.     return(result);
  3127. }
  3128.  
  3129. /****************************************************************************/
  3130.  
  3131. STATIC LONG
  3132. Action_RenameObject(
  3133.     struct FileLock *    source_lock,
  3134.     APTR                source_bcpl_name,
  3135.     struct FileLock *    destination_lock,
  3136.     APTR                destination_bcpl_name,
  3137.     LONG *                error_ptr)
  3138. {
  3139.     struct LockNode * ln;
  3140.     LONG result = DOSFALSE;
  3141.     STRPTR full_source_name = NULL;
  3142.     STRPTR full_destination_name = NULL;
  3143.     UBYTE name[MAX_FILENAME_LEN];
  3144.     STRPTR parent_name;
  3145.     LONG error;
  3146.  
  3147.     ENTER();
  3148.  
  3149.     if(WriteProtected)
  3150.     {
  3151.         error = ERROR_DISK_WRITE_PROTECTED;
  3152.         goto out;
  3153.     }
  3154.  
  3155.     SHOWVALUE(source_lock);
  3156.     SHOWVALUE(destination_lock);
  3157.  
  3158.     if(source_lock != NULL)
  3159.     {
  3160.         ln = (struct LockNode *)source_lock->fl_Key;
  3161.  
  3162.         parent_name = ln->ln_FullName;
  3163.     }
  3164.     else
  3165.     {
  3166.         parent_name = NULL;
  3167.     }
  3168.  
  3169.     ConvertBString(sizeof(name),name,source_bcpl_name);
  3170.     TranslateCName(name,A2M);
  3171.  
  3172.     error = BuildFullName(parent_name,name,&full_source_name);
  3173.     if(error != OK)
  3174.         goto out;
  3175.  
  3176.     /* Trying to rename the root directory, are you kidding? */
  3177.     if(full_source_name == NULL)
  3178.     {
  3179.         error = ERROR_OBJECT_IN_USE;
  3180.         goto out;
  3181.     }
  3182.  
  3183.     if(destination_lock != NULL)
  3184.     {
  3185.         ln = (struct LockNode *)destination_lock->fl_Key;
  3186.  
  3187.         parent_name = ln->ln_FullName;
  3188.     }
  3189.     else
  3190.     {
  3191.         parent_name = NULL;
  3192.     }
  3193.  
  3194.     ConvertBString(sizeof(name),name,destination_bcpl_name);
  3195.     TranslateCName(name,A2M);
  3196.  
  3197.     error = BuildFullName(parent_name,name,&full_destination_name);
  3198.     if(error != OK)
  3199.         goto out;
  3200.  
  3201.     /* Trying to rename the root directory, are you kidding? */
  3202.     if(full_destination_name == NULL)
  3203.     {
  3204.         error = ERROR_OBJECT_IN_USE;
  3205.         goto out;
  3206.     }
  3207.  
  3208.     error = NameAlreadyInUse(full_source_name);
  3209.     if(error != OK)
  3210.         goto out;
  3211.  
  3212.     error = NameAlreadyInUse(full_destination_name);
  3213.     if(error != OK)
  3214.         goto out;
  3215.  
  3216.     SHOWSTRING(full_source_name);
  3217.     SHOWSTRING(full_destination_name);
  3218.  
  3219.     error = smba_rename(ServerData,full_source_name,full_destination_name);
  3220.     if(error < 0)
  3221.     {
  3222.         error = MapErrnoToIoErr(error);
  3223.         goto out;
  3224.     }
  3225.  
  3226.     result = DOSTRUE;
  3227.  
  3228.  out:
  3229.  
  3230.     FreeVecPooled(full_source_name);
  3231.     FreeVecPooled(full_destination_name);
  3232.  
  3233.     (*error_ptr) = error;
  3234.  
  3235.     RETURN(result);
  3236.     return(result);
  3237. }
  3238.  
  3239. /****************************************************************************/
  3240.  
  3241. STATIC LONG
  3242. Action_DiskInfo(
  3243.     struct InfoData *    id,
  3244.     LONG *                error_ptr)
  3245. {
  3246.     LONG result = DOSTRUE;
  3247.     LONG block_size;
  3248.     LONG num_blocks;
  3249.     LONG num_blocks_free;
  3250.     LONG error;
  3251.  
  3252.     ENTER();
  3253.  
  3254.     memset(id,0,sizeof(*id));
  3255.  
  3256.     if(WriteProtected)
  3257.         id->id_DiskState = ID_WRITE_PROTECTED;
  3258.     else
  3259.         id->id_DiskState = ID_VALIDATED;
  3260.  
  3261.     error = smba_statfs(ServerData,&block_size,&num_blocks,&num_blocks_free);
  3262.     if(error >= 0)
  3263.     {
  3264.         SHOWMSG("got the disk data");
  3265.         SHOWVALUE(block_size);
  3266.         SHOWVALUE(num_blocks);
  3267.         SHOWVALUE(num_blocks_free);
  3268.  
  3269.         if(block_size <= 0)
  3270.             block_size = 512;
  3271.  
  3272.         if(block_size < 512)
  3273.         {
  3274.             num_blocks        /= (512 / block_size);
  3275.             num_blocks_free    /= (512 / block_size);
  3276.         }
  3277.         else if (block_size > 512)
  3278.         {
  3279.             num_blocks        *= (block_size / 512);
  3280.             num_blocks_free    *= (block_size / 512);
  3281.         }
  3282.  
  3283.         id->id_NumBlocks        = num_blocks;
  3284.         id->id_NumBlocksUsed    = num_blocks - num_blocks_free;
  3285.         id->id_BytesPerBlock    = 512;
  3286.         id->id_DiskType            = ID_DOS_DISK;
  3287.         id->id_VolumeNode        = MKBADDR(VolumeNode);
  3288.         id->id_InUse            = NOT (IsListEmpty((struct List *)&FileList) && IsListEmpty((struct List *)&LockList));
  3289.  
  3290.         if(id->id_NumBlocks == 0)
  3291.             id->id_NumBlocks = 1;
  3292.  
  3293.         if(id->id_NumBlocksUsed == 0)
  3294.             id->id_NumBlocksUsed = 1;
  3295.     }
  3296.     else
  3297.     {
  3298.         SHOWMSG("could not get any disk data");
  3299.  
  3300.         id->id_NumBlocks        = 1;
  3301.         id->id_NumBlocksUsed    = 1;
  3302.         id->id_BytesPerBlock    = 512;
  3303.         id->id_DiskType            = ID_NO_DISK_PRESENT;
  3304.  
  3305.         error = MapErrnoToIoErr(error);
  3306.         result = DOSFALSE;
  3307.     }
  3308.  
  3309.     SHOWVALUE(id->id_NumBlocks);
  3310.     SHOWVALUE(id->id_NumBlocksUsed);
  3311.     SHOWVALUE(id->id_BytesPerBlock);
  3312.     SHOWVALUE(id->id_DiskType);
  3313.     SHOWVALUE(id->id_VolumeNode);
  3314.     SHOWVALUE(id->id_InUse);
  3315.  
  3316.     (*error_ptr) = error;
  3317.  
  3318.     RETURN(result);
  3319.     return(result);
  3320. }
  3321.  
  3322. STATIC LONG
  3323. Action_Info(
  3324.     struct FileLock *    lock,
  3325.     struct InfoData *    id,
  3326.     LONG *                error_ptr)
  3327. {
  3328.     LONG result;
  3329.  
  3330.     ENTER();
  3331.  
  3332.     SHOWVALUE(lock);
  3333.  
  3334.     if(lock == NULL || lock->fl_Volume != MKBADDR(VolumeNode))
  3335.     {
  3336.         SHOWMSG("volume node does not match");
  3337.  
  3338.         result = DOSFALSE;
  3339.  
  3340.         (*error_ptr) = ERROR_NO_DISK;
  3341.     }
  3342.     else
  3343.     {
  3344.         result = Action_DiskInfo(id,error_ptr);
  3345.     }
  3346.  
  3347.     RETURN(result);
  3348.     return(result);
  3349. }
  3350.  
  3351. /****************************************************************************/
  3352.  
  3353. STATIC LONG
  3354. Action_ExamineObject(
  3355.     struct FileLock *        lock,
  3356.     struct FileInfoBlock *    fib,
  3357.     LONG *                    error_ptr)
  3358. {
  3359.     LONG result = DOSFALSE;
  3360.     LONG error = OK;
  3361.  
  3362.     ENTER();
  3363.  
  3364.     SHOWVALUE(lock);
  3365.  
  3366.     memset(fib,0,sizeof(*fib));
  3367.  
  3368.     if(lock == NULL)
  3369.     {
  3370.         STRPTR volume_name = BADDR(VolumeNode->dol_Name);
  3371.         LONG len = volume_name[0];
  3372.  
  3373.         SHOWMSG("ZERO root lock");
  3374.  
  3375.         memcpy(fib->fib_FileName+1,volume_name+1,len);
  3376.         fib->fib_FileName[0] = len;
  3377.  
  3378.         fib->fib_DirEntryType    = ST_ROOT;
  3379.         fib->fib_EntryType        = ST_ROOT;
  3380.         fib->fib_NumBlocks        = 1;
  3381.         fib->fib_Date            = VolumeNode->dol_misc.dol_volume.dol_VolumeDate;
  3382.         fib->fib_DiskKey        = -1;
  3383.         fib->fib_Protection        = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
  3384.                                   FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
  3385.     }
  3386.     else
  3387.     {
  3388.         struct LockNode * ln = (struct LockNode *)lock->fl_Key;
  3389.         LONG seconds;
  3390.         smba_stat_t stat;
  3391.  
  3392.         error = smba_getattr(ln->ln_File,&stat);
  3393.         if(error < 0)
  3394.         {
  3395.             SHOWMSG("information not available");
  3396.  
  3397.             error = MapErrnoToIoErr(error);
  3398.             goto out;
  3399.         }
  3400.  
  3401.         seconds = stat.mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
  3402.         if(seconds < 0)
  3403.             seconds = 0;
  3404.  
  3405.         fib->fib_Date.ds_Days    = (seconds / (24 * 60 * 60));
  3406.         fib->fib_Date.ds_Minute    = (seconds % (24 * 60 * 60)) / 60;
  3407.         fib->fib_Date.ds_Tick    = (seconds % 60) * TICKS_PER_SECOND;
  3408.  
  3409.         SHOWSTRING(ln->ln_FullName);
  3410.  
  3411.         if(strcmp(ln->ln_FullName,SMB_ROOT_DIR_NAME) == SAME)
  3412.         {
  3413.             STRPTR volume_name = BADDR(VolumeNode->dol_Name);
  3414.             LONG len = volume_name[0];
  3415.  
  3416.             SHOWMSG("root lock");
  3417.  
  3418.             memcpy(fib->fib_FileName+1,volume_name+1,len);
  3419.             fib->fib_FileName[0] = len;
  3420.  
  3421.             fib->fib_DirEntryType    = ST_ROOT;
  3422.             fib->fib_EntryType        = ST_ROOT;
  3423.             fib->fib_NumBlocks        = 1;
  3424.             fib->fib_Protection        = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
  3425.                                       FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
  3426.         }
  3427.         else
  3428.         {
  3429.             STRPTR name;
  3430.             LONG i;
  3431.  
  3432.             name = ln->ln_FullName;
  3433.             for(i = strlen(name)-1 ; i >= 0 ; i--)
  3434.             {
  3435.                 if(name[i] == SMB_PATH_SEPARATOR)
  3436.                 {
  3437.                     name = &name[i+1];
  3438.                     break;
  3439.                 }
  3440.             }
  3441.  
  3442.             /* Just checking: will the name fit? */
  3443.             if(strlen(name) >= sizeof(fib->fib_FileName))
  3444.             {
  3445.                 error = ERROR_INVALID_COMPONENT_NAME;
  3446.                 goto out;
  3447.             }
  3448.  
  3449.             ConvertCString(sizeof(fib->fib_FileName),fib->fib_FileName,name);
  3450.             TranslateBName(fib->fib_FileName,M2A);
  3451.  
  3452.             fib->fib_DirEntryType    = stat.is_dir ? ST_USERDIR : ST_FILE;
  3453.             fib->fib_EntryType        = fib->fib_DirEntryType;
  3454.             fib->fib_NumBlocks        = (stat.size + 511) / 512;
  3455.             fib->fib_Size            = stat.size;
  3456.             fib->fib_Protection        = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
  3457.                                       FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
  3458.  
  3459.             if(stat.is_wp)
  3460.                 fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
  3461.  
  3462.             if(NOT stat.is_dir)
  3463.                 fib->fib_DiskKey = -1;
  3464.         }
  3465.     }
  3466.  
  3467.     result = DOSTRUE;
  3468.  
  3469.     D(("fib->fib_FileName = \"%b\"",MKBADDR(fib->fib_FileName)));
  3470.     SHOWVALUE(fib->fib_DirEntryType);
  3471.     SHOWVALUE(fib->fib_NumBlocks);
  3472.     SHOWVALUE(fib->fib_Size);
  3473.     SHOWVALUE(fib->fib_Date.ds_Days);
  3474.     SHOWVALUE(fib->fib_Date.ds_Minute);
  3475.     SHOWVALUE(fib->fib_Date.ds_Tick);
  3476.     SHOWVALUE(fib->fib_DiskKey);
  3477.  
  3478.  out:
  3479.  
  3480.     (*error_ptr) = error;
  3481.  
  3482.     RETURN(result);
  3483.     return(result);
  3484. }
  3485.  
  3486. /****************************************************************************/
  3487.  
  3488. STATIC BOOL
  3489. NameIsAcceptable(STRPTR name,LONG max_len)
  3490. {
  3491.     BOOL result = FALSE;
  3492.     UBYTE c;
  3493.  
  3494.     /* This takes care of "." and "..". */
  3495.     if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
  3496.         goto out;
  3497.  
  3498.     /* Now for embedded '/', ':' and '\' characters and
  3499.      * names that just don't want to fit.
  3500.      */
  3501.     while((c = (*name++)) != '\0')
  3502.     {
  3503.         max_len--;
  3504.         if(max_len == 0 || c == '/' || c == ':' || c == SMB_PATH_SEPARATOR)
  3505.             goto out;
  3506.     }
  3507.  
  3508.     result = TRUE;
  3509.  
  3510.  out:
  3511.  
  3512.     return(result);
  3513. }
  3514.  
  3515. /****************************************************************************/
  3516.  
  3517. static int
  3518. dir_scan_callback_func_exnext(
  3519.     struct FileInfoBlock *    fib,
  3520.     int                        fpos,
  3521.     int                        nextpos,
  3522.     char *                    name,
  3523.     int                        eof,
  3524.     smba_stat_t *            stat)
  3525. {
  3526.     int result;
  3527.  
  3528.     ENTER();
  3529.  
  3530.     D((" '%s'",name));
  3531.     D(("   is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
  3532.         stat->is_dir,stat->is_wp,stat->is_hidden,stat->size));
  3533.     D(("   fpos=%ld nextpos=%ld eof=%ld",fpos,nextpos,eof));
  3534.  
  3535.     /* Skip file and drawer names that we wouldn't be
  3536.      * able to handle in the first place.
  3537.      */
  3538.     if(NameIsAcceptable((STRPTR)name,sizeof(fib->fib_FileName)) && NOT (stat->is_hidden && OmitHidden))
  3539.     {
  3540.         LONG seconds;
  3541.  
  3542.         ConvertCString(sizeof(fib->fib_FileName),fib->fib_FileName,name);
  3543.         TranslateBName(fib->fib_FileName,M2A);
  3544.  
  3545.         fib->fib_DirEntryType    = stat->is_dir ? ST_USERDIR : ST_FILE;
  3546.         fib->fib_EntryType        = fib->fib_DirEntryType;
  3547.         fib->fib_NumBlocks        = (stat->size + 511) / 512;
  3548.         fib->fib_Size            = stat->size;
  3549.         fib->fib_Protection        = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
  3550.                                   FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
  3551.  
  3552.         if(stat->is_wp)
  3553.             fib->fib_Protection ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
  3554.  
  3555.         seconds = stat->mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
  3556.         if(seconds < 0)
  3557.             seconds = 0;
  3558.  
  3559.         fib->fib_Date.ds_Days    = (seconds / (24 * 60 * 60));
  3560.         fib->fib_Date.ds_Minute    = (seconds % (24 * 60 * 60)) / 60;
  3561.         fib->fib_Date.ds_Tick    = (seconds % 60) * TICKS_PER_SECOND;
  3562.  
  3563.         result = 1;
  3564.     }
  3565.     else
  3566.     {
  3567.         result = 0;
  3568.     }
  3569.  
  3570.     fib->fib_DiskKey = eof ? -1 : nextpos;
  3571.  
  3572.     RETURN(result);
  3573.     return(result);
  3574. }
  3575.  
  3576. STATIC LONG
  3577. Action_ExamineNext(
  3578.     struct FileLock *        lock,
  3579.     struct FileInfoBlock *    fib,
  3580.     LONG *                    error_ptr)
  3581. {
  3582.     struct LockNode * ln;
  3583.     LONG result = DOSFALSE;
  3584.     LONG error = OK;
  3585.     long offset;
  3586.     int count;
  3587.  
  3588.     ENTER();
  3589.  
  3590.     SHOWVALUE(lock);
  3591.  
  3592.     if(fib->fib_DiskKey == -1)
  3593.     {
  3594.         SHOWMSG("scanning finished.");
  3595.         error = ERROR_NO_MORE_ENTRIES;
  3596.         goto out;
  3597.     }
  3598.  
  3599.     if(lock == NULL)
  3600.     {
  3601.         SHOWMSG("invalid lock");
  3602.         error = ERROR_INVALID_LOCK;
  3603.         goto out;
  3604.     }
  3605.  
  3606.     offset = fib->fib_DiskKey;
  3607.  
  3608.     ln = (struct LockNode *)lock->fl_Key;
  3609.  
  3610.     /* Check if we should restart scanning the directory
  3611.      * contents. This is tricky at best and may produce
  3612.      * irritating results :(
  3613.      */
  3614.     if(ln->ln_RestartExamine)
  3615.     {
  3616.         offset = 0;
  3617.         ln->ln_RestartExamine = FALSE;
  3618.     }
  3619.  
  3620.     memset(fib,0,sizeof(*fib));
  3621.  
  3622.     SHOWMSG("calling 'smba_readdir'");
  3623.     SHOWVALUE(offset);
  3624.  
  3625.     count = smba_readdir(ln->ln_File,offset,fib,(smba_callback_t)dir_scan_callback_func_exnext);
  3626.  
  3627.     SHOWVALUE(count);
  3628.  
  3629.     if(count == 0 || fib->fib_FileName[0] == '\0')
  3630.     {
  3631.         SHOWMSG("nothing to be read");
  3632.         fib->fib_DiskKey = -1;
  3633.  
  3634.         error = ERROR_NO_MORE_ENTRIES;
  3635.         goto out;
  3636.     }
  3637.     else if (count == (-EIO))
  3638.     {
  3639.         SHOWMSG("ouch! directory read error");
  3640.         fib->fib_DiskKey = -1;
  3641.  
  3642.         error = ERROR_NO_DEFAULT_DIR;
  3643.         goto out;
  3644.     }
  3645.     else if (count < 0)
  3646.     {
  3647.         SHOWMSG("error whilst scanning");
  3648.         SHOWVALUE(count);
  3649.         fib->fib_DiskKey = -1;
  3650.  
  3651.         error = MapErrnoToIoErr(count);
  3652.         goto out;
  3653.     }
  3654.  
  3655.     result = DOSTRUE;
  3656.  
  3657.  out:
  3658.  
  3659.     (*error_ptr) = error;
  3660.  
  3661.     RETURN(result);
  3662.     return(result);
  3663. }
  3664.  
  3665. /****************************************************************************/
  3666.  
  3667. struct ExAllContext
  3668. {
  3669.     struct ExAllData *        ec_Last;
  3670.     struct ExAllData *        ec_Next;
  3671.     ULONG                    ec_BytesLeft;
  3672.     ULONG                    ec_MinSize;
  3673.     struct ExAllControl *     ec_Control;
  3674.     ULONG                    ec_Type;
  3675.     LONG                    ec_Error;
  3676.     BOOL                    ec_FirstAttempt;
  3677. };
  3678.  
  3679. static int
  3680. dir_scan_callback_func_exall(
  3681.     struct ExAllContext *    ec,
  3682.     int                        fpos,
  3683.     int                        nextpos,
  3684.     char *                    name,
  3685.     int                        eof,
  3686.     smba_stat_t *            stat)
  3687. {
  3688.     int result = 0;
  3689.  
  3690.     ENTER();
  3691.  
  3692.     D((" '%s'",name));
  3693.     D(("   is_dir=%ld is_wp=%ld is_hidden=%ld size=%ld",
  3694.         stat->is_dir,stat->is_wp,stat->is_hidden,stat->size));
  3695.     D(("   fpos=%ld nextpos=%ld eof=%ld",fpos,nextpos,eof));
  3696.  
  3697.     /* Skip file and drawer names that we wouldn't be
  3698.      * able to handle in the first place.
  3699.      */
  3700.     if(NameIsAcceptable((STRPTR)name,MAX_FILENAME_LEN) && NOT (stat->is_hidden && OmitHidden))
  3701.     {
  3702.         struct ExAllData * ed;
  3703.         ULONG size;
  3704.         ULONG type = ec->ec_Type;
  3705.         BOOL take_it;
  3706.  
  3707.         size = (ec->ec_MinSize + strlen(name)+1 + 3) & ~3;
  3708.         SHOWVALUE(size);
  3709.         if(size > ec->ec_BytesLeft)
  3710.         {
  3711.             D(("size %ld > ec->ec_BytesLeft %ld",size,ec->ec_BytesLeft));
  3712.  
  3713.             /* If this is the first directory entry,
  3714.              * stop the entire process before it has
  3715.              * really begun.
  3716.              */
  3717.             if(ec->ec_FirstAttempt)
  3718.             {
  3719.                 SHOWMSG("this was the first read attempt.");
  3720.                 ec->ec_Control->eac_Entries = 0;
  3721.                 ec->ec_Error = ERROR_NO_FREE_STORE;
  3722.             }
  3723.             else
  3724.             {
  3725.                 SHOWMSG("try again");
  3726.                 ec->ec_Error = 0;
  3727.             }
  3728.  
  3729.             result = 1;
  3730.             goto out;
  3731.         }
  3732.  
  3733.         ed = ec->ec_Next;
  3734.  
  3735.         ed->ed_Next = NULL;
  3736.         ed->ed_Name = (STRPTR)(((ULONG)ed) + ec->ec_MinSize);
  3737.         strcpy(ed->ed_Name,name);
  3738.  
  3739.         TranslateCName(ed->ed_Name,M2A);
  3740.  
  3741.         if(type >= ED_TYPE)
  3742.             ed->ed_Type = stat->is_dir ? ST_USERDIR : ST_FILE;
  3743.  
  3744.         if(type >= ED_SIZE)
  3745.             ed->ed_Size = stat->size;
  3746.  
  3747.         if(type >= ED_PROTECTION)
  3748.         {
  3749.             ed->ed_Prot = FIBF_OTR_READ|FIBF_OTR_EXECUTE|FIBF_OTR_WRITE|FIBF_OTR_DELETE|
  3750.                           FIBF_GRP_READ|FIBF_GRP_EXECUTE|FIBF_GRP_WRITE|FIBF_GRP_DELETE;
  3751.  
  3752.             if(stat->is_wp)
  3753.                 ed->ed_Prot ^= (FIBF_OTR_WRITE|FIBF_OTR_DELETE|FIBF_GRP_WRITE|FIBF_GRP_DELETE|FIBF_WRITE|FIBF_DELETE);
  3754.         }
  3755.  
  3756.         if(type >= ED_DATE)
  3757.         {
  3758.             LONG seconds;
  3759.  
  3760.             seconds = stat->mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
  3761.             if(seconds < 0)
  3762.                 seconds = 0;
  3763.  
  3764.             ed->ed_Days        = (seconds / (24 * 60 * 60));
  3765.             ed->ed_Mins     = (seconds % (24 * 60 * 60)) / 60;
  3766.             ed->ed_Ticks    = (seconds % 60) * TICKS_PER_SECOND;
  3767.         }
  3768.  
  3769.         if(type >= ED_COMMENT)
  3770.             ed->ed_Comment = "";
  3771.  
  3772.         if(type >= ED_OWNER)
  3773.             ed->ed_OwnerUID = ed->ed_OwnerGID = 0;
  3774.  
  3775.         take_it = TRUE;
  3776.  
  3777.         if(ec->ec_Control->eac_MatchString != NULL)
  3778.         {
  3779.             SHOWMSG("checking against match string");
  3780.             if(NOT MatchPatternNoCase(ec->ec_Control->eac_MatchString,ed->ed_Name))
  3781.             {
  3782.                 SHOWMSG("does not match");
  3783.                 take_it = FALSE;
  3784.             }
  3785.         }
  3786.  
  3787.         if(take_it && ec->ec_Control->eac_MatchFunc != NULL)
  3788.         {
  3789.             SHOWMSG("calling match func");
  3790.  
  3791.             /* NOTE: the order of the parameters passed to the match hook
  3792.              *       function can be somewhat confusing. For standard
  3793.              *       hook functions, the order of the parameters and the
  3794.              *       registers they go into is hook=A0, object=A2,
  3795.              *       message=A1. However, the documentation for the 'ExAll()'
  3796.              *       function always lists them in ascending order, that is
  3797.              *       hook=A0, message=A1, object=A2, which can lead to
  3798.              *       quite some confusion and strange errors.
  3799.              */
  3800.             if(NOT CallHookPkt(ec->ec_Control->eac_MatchFunc,&type,ed))
  3801.             {
  3802.                 SHOWMSG("does not match");
  3803.                 take_it = FALSE;
  3804.             }
  3805.         }
  3806.  
  3807.         if(take_it)
  3808.         {
  3809.             SHOWMSG("registering new entry");
  3810.  
  3811.             if(ec->ec_Last != NULL)
  3812.                 ec->ec_Last->ed_Next = ed;
  3813.  
  3814.             ec->ec_Last = ed;
  3815.             ec->ec_Next = (struct ExAllData *)(((ULONG)ed) + size);
  3816.             ec->ec_BytesLeft -= size;
  3817.             ec->ec_Control->eac_Entries++;
  3818.  
  3819.             SHOWVALUE(ec->ec_Last->ed_Next);
  3820.             SHOWVALUE(ed->ed_Name);
  3821.             SHOWVALUE(ed->ed_Comment);
  3822.         }
  3823.     }
  3824.  
  3825.     ec->ec_Control->eac_LastKey = (ULONG)(eof ? -1 : nextpos);
  3826.  
  3827.  out:
  3828.  
  3829.     ec->ec_FirstAttempt = FALSE;
  3830.  
  3831.     RETURN(result);
  3832.     return(result);
  3833. }
  3834.  
  3835. STATIC LONG
  3836. Action_ExamineAll(
  3837.     struct FileLock *        lock,
  3838.     struct ExAllData *        ed,
  3839.     ULONG                    size,
  3840.     ULONG                    type,
  3841.     struct ExAllControl *    eac,
  3842.     LONG *                    error_ptr)
  3843. {
  3844.     struct ExAllContext ec;
  3845.     struct LockNode * ln;
  3846.     LONG result = DOSFALSE;
  3847.     LONG error = OK;
  3848.     LONG offset;
  3849.     int count;
  3850.  
  3851.     ENTER();
  3852.  
  3853.     SHOWVALUE(lock);
  3854.  
  3855.     SHOWVALUE(eac->eac_LastKey);
  3856.  
  3857.     eac->eac_Entries = 0;
  3858.     ed->ed_Next = NULL;
  3859.  
  3860.     if(eac->eac_LastKey == (ULONG)-1)
  3861.     {
  3862.         SHOWMSG("scanning finished.");
  3863.         error = ERROR_NO_MORE_ENTRIES;
  3864.         goto out;
  3865.     }
  3866.  
  3867.     if(lock == NULL)
  3868.     {
  3869.         SHOWMSG("invalid lock");
  3870.         error = ERROR_INVALID_LOCK;
  3871.         goto out;
  3872.     }
  3873.  
  3874.     if(type < ED_NAME || type > ED_OWNER)
  3875.     {
  3876.         D(("type %ld not supported",type));
  3877.         error = ERROR_BAD_NUMBER;
  3878.         goto out;
  3879.     }
  3880.  
  3881.     SHOWVALUE(type);
  3882.  
  3883.     memset(&ec,0,sizeof(ec));
  3884.  
  3885.     ec.ec_Next            = ed;
  3886.     ec.ec_BytesLeft        = size;
  3887.     ec.ec_Control        = eac;
  3888.     ec.ec_Type            = type;
  3889.     ec.ec_Error            = ERROR_NO_MORE_ENTRIES;
  3890.     ec.ec_FirstAttempt    = TRUE;
  3891.  
  3892.     switch(type)
  3893.     {
  3894.         case ED_NAME:
  3895.  
  3896.             ec.ec_MinSize = offsetof(struct ExAllData,ed_Type);
  3897.             break;
  3898.  
  3899.         case ED_TYPE:
  3900.  
  3901.             ec.ec_MinSize = offsetof(struct ExAllData,ed_Size);
  3902.             break;
  3903.  
  3904.         case ED_SIZE:
  3905.  
  3906.             ec.ec_MinSize = offsetof(struct ExAllData,ed_Prot);
  3907.             break;
  3908.  
  3909.         case ED_PROTECTION:
  3910.  
  3911.             ec.ec_MinSize = offsetof(struct ExAllData,ed_Days);
  3912.             break;
  3913.  
  3914.         case ED_DATE:
  3915.  
  3916.             ec.ec_MinSize = offsetof(struct ExAllData,ed_Comment);
  3917.             break;
  3918.  
  3919.         case ED_COMMENT:
  3920.  
  3921.             ec.ec_MinSize = offsetof(struct ExAllData,ed_OwnerUID);
  3922.             break;
  3923.  
  3924.         case ED_OWNER:
  3925.  
  3926.             ec.ec_MinSize = sizeof(struct ExAllData);
  3927.             break;
  3928.     }
  3929.  
  3930.     SHOWVALUE(ec.ec_MinSize);
  3931.  
  3932.     offset = eac->eac_LastKey;
  3933.  
  3934.     ln = (struct LockNode *)lock->fl_Key;
  3935.  
  3936.     /* Check if we should restart scanning the directory
  3937.      * contents. This is tricky at best and may produce
  3938.      * irritating results :(
  3939.      */
  3940.     if(ln->ln_RestartExamine)
  3941.     {
  3942.         offset = 0;
  3943.  
  3944.         ln->ln_RestartExamine = FALSE;
  3945.     }
  3946.  
  3947.     if(offset == 0)
  3948.     {
  3949.         smba_stat_t stat;
  3950.  
  3951.         SHOWMSG("first invocation");
  3952.  
  3953.         SHOWMSG("getting file attributes");
  3954.         error = smba_getattr(ln->ln_File,&stat);
  3955.         if(error < 0)
  3956.         {
  3957.             SHOWMSG("didn't work");
  3958.             error = MapErrnoToIoErr(error);
  3959.             eac->eac_LastKey = (ULONG)-1;
  3960.             goto out;
  3961.         }
  3962.  
  3963.         if(NOT stat.is_dir)
  3964.         {
  3965.             SHOWMSG("lock does not refer to a directory");
  3966.             error = ERROR_OBJECT_WRONG_TYPE;
  3967.             eac->eac_LastKey = (ULONG)-1;
  3968.             goto out;
  3969.         }
  3970.     }
  3971.  
  3972.     SHOWMSG("calling 'smba_readdir'");
  3973.     SHOWVALUE(offset);
  3974.  
  3975.     count = smba_readdir(ln->ln_File,offset,&ec,(smba_callback_t)dir_scan_callback_func_exall);
  3976.  
  3977.     SHOWVALUE(count);
  3978.  
  3979.     if(count == 0 || eac->eac_Entries == 0)
  3980.     {
  3981.         SHOWMSG("nothing to be read");
  3982.         if(ec.ec_Error != OK)
  3983.         {
  3984.             SHOWMSG("flagging an error");
  3985.             SHOWVALUE(ec.ec_Error);
  3986.             eac->eac_LastKey = (ULONG)-1;
  3987.             error = ec.ec_Error;
  3988.         }
  3989.  
  3990.         goto out;
  3991.     }
  3992.     else if (count == (-EIO))
  3993.     {
  3994.         SHOWMSG("ouch! directory read error");
  3995.         eac->eac_LastKey = (ULONG)-1;
  3996.  
  3997.         error = ERROR_NO_DEFAULT_DIR;
  3998.         goto out;
  3999.     }
  4000.     else if (count < 0)
  4001.     {
  4002.         SHOWMSG("error whilst scanning");
  4003.         eac->eac_LastKey = (ULONG)-1;
  4004.  
  4005.         error = MapErrnoToIoErr(count);
  4006.         goto out;
  4007.     }
  4008.  
  4009.     SHOWMSG("ok");
  4010.     result = DOSTRUE;
  4011.  
  4012.  out:
  4013.  
  4014.     #if DEBUG
  4015.     {
  4016.         SHOWVALUE(eac->eac_Entries);
  4017.  
  4018.         while(ed != NULL)
  4019.         {
  4020.             SHOWSTRING(ed->ed_Name);
  4021.  
  4022.             ed = ed->ed_Next;
  4023.         }
  4024.     }
  4025.     #endif /* DEBUG */
  4026.  
  4027.     (*error_ptr) = error;
  4028.  
  4029.     RETURN(result);
  4030.     return(result);
  4031. }
  4032.  
  4033. /****************************************************************************/
  4034.  
  4035. STATIC LONG
  4036. Action_Find(
  4037.     LONG                    action,
  4038.     struct FileHandle *        fh,
  4039.     struct FileLock *        parent,
  4040.     APTR                    bcpl_name,
  4041.     LONG *                    error_ptr)
  4042. {
  4043.     LONG result = DOSFALSE;
  4044.     STRPTR parent_path = NULL;
  4045.     STRPTR full_name = NULL;
  4046.     struct FileNode * fn = NULL;
  4047.     STRPTR parent_name;
  4048.     UBYTE name[MAX_FILENAME_LEN];
  4049.     BOOL create_new_file;
  4050.     LONG error;
  4051.  
  4052.     ENTER();
  4053.  
  4054.     switch(action)
  4055.     {
  4056.         case ACTION_FINDINPUT:
  4057.             D(("ACTION_FINDINPUT [Open(\"%b\",MODE_OLDFILE)]",MKBADDR(bcpl_name)));
  4058.             break;
  4059.  
  4060.         case ACTION_FINDOUTPUT:
  4061.             D(("ACTION_FINDOUTPUT [Open(\"%b\",MODE_NEWFILE)]",MKBADDR(bcpl_name)));
  4062.             break;
  4063.  
  4064.         case ACTION_FINDUPDATE:
  4065.             D(("ACTION_FINDUPDATE [Open(\"%b\",MODE_READWRITE)]",MKBADDR(bcpl_name)));
  4066.             break;
  4067.     }
  4068.  
  4069.     SHOWVALUE(parent);
  4070.  
  4071.     if(parent != NULL)
  4072.     {
  4073.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  4074.  
  4075.         parent_name = ln->ln_FullName;
  4076.     }
  4077.     else
  4078.     {
  4079.         parent_name = NULL;
  4080.     }
  4081.  
  4082.     ConvertBString(sizeof(name),name,bcpl_name);
  4083.     TranslateCName(name,A2M);
  4084.  
  4085.     if(IsReservedName(FilePart(name)))
  4086.     {
  4087.         error = ERROR_OBJECT_NOT_FOUND;
  4088.         goto out;
  4089.     }
  4090.  
  4091.     error = BuildFullName(parent_name,name,&full_name);
  4092.     if(error != OK)
  4093.         goto out;
  4094.  
  4095.     /* Trying to open the root directory? */
  4096.     if(full_name == NULL)
  4097.     {
  4098.         error = ERROR_OBJECT_WRONG_TYPE;
  4099.         goto out;
  4100.     }
  4101.  
  4102.     fn = AllocVecPooled(sizeof(*fn));
  4103.     if(fn == NULL)
  4104.     {
  4105.         error = ERROR_NO_FREE_STORE;
  4106.         goto out;
  4107.     }
  4108.  
  4109.     memset(fn,0,sizeof(*fn));
  4110.  
  4111.     fn->fn_Handle    = fh;
  4112.     fn->fn_FullName    = full_name;
  4113.     fn->fn_Mode        = (action == ACTION_FINDOUTPUT) ? EXCLUSIVE_LOCK : SHARED_LOCK;
  4114.  
  4115.     error = CheckAccessModeCollision(full_name,fn->fn_Mode);
  4116.     if(error != OK)
  4117.         goto out;
  4118.  
  4119.     SHOWSTRING(full_name);
  4120.  
  4121.     if(action == ACTION_FINDOUTPUT)
  4122.     {
  4123.         /* Definitely create a new file. */
  4124.         create_new_file = TRUE;
  4125.     }
  4126.     else if (action == ACTION_FINDINPUT)
  4127.     {
  4128.         /* Open an existing file for reading. */
  4129.         create_new_file = FALSE;
  4130.     }
  4131.     else if (action == ACTION_FINDUPDATE)
  4132.     {
  4133.         smba_file_t * file = NULL;
  4134.         smba_stat_t stat;
  4135.  
  4136.         if(smba_open(ServerData,full_name,&file) == OK &&
  4137.            smba_getattr(file,&stat) == OK)
  4138.         {
  4139.             /* File apparently opens Ok and information on it
  4140.              * is available, don't try to replace it.
  4141.              */
  4142.             create_new_file = FALSE;
  4143.         }
  4144.         else
  4145.         {
  4146.             /* We try to ignore the error here and assume
  4147.              * that the remainder of the file opening
  4148.              * procedure will produce a useful error
  4149.              * report. In the mean time, assume that the
  4150.              * file needs to be created.
  4151.              */
  4152.             create_new_file = TRUE;
  4153.         }
  4154.  
  4155.         if(file != NULL)
  4156.             smba_close(file);
  4157.     }
  4158.     else
  4159.     {
  4160.         /* What's that? */
  4161.         error = ERROR_ACTION_NOT_KNOWN;
  4162.         goto out;
  4163.     }
  4164.  
  4165.     /* Create a new file? */
  4166.     if(create_new_file)
  4167.     {
  4168.         smba_stat_t stat;
  4169.         smba_file_t * dir;
  4170.         STRPTR base_name;
  4171.         LONG i;
  4172.  
  4173.         if(WriteProtected)
  4174.         {
  4175.             error = ERROR_DISK_WRITE_PROTECTED;
  4176.             goto out;
  4177.         }
  4178.  
  4179.         parent_path = AllocVecPooled(strlen(full_name)+3);
  4180.         if(parent_path == NULL)
  4181.         {
  4182.             error = ERROR_NO_FREE_STORE;
  4183.             goto out;
  4184.         }
  4185.  
  4186.         strcpy(parent_path,full_name);
  4187.         base_name = NULL;
  4188.         for(i = strlen(parent_path)-1 ; i >= 0 ; i--)
  4189.         {
  4190.             if(parent_path[i] == SMB_PATH_SEPARATOR)
  4191.             {
  4192.                 if(i == 0)
  4193.                 {
  4194.                     memmove(&parent_path[1],&parent_path[0],strlen(parent_path)+1);
  4195.                     i++;
  4196.                 }
  4197.  
  4198.                 parent_path[i] = '\0';
  4199.  
  4200.                 base_name = &parent_path[i+1];
  4201.                 break;
  4202.             }
  4203.         }
  4204.  
  4205.         SHOWMSG("creating a file; finding parent path first");
  4206.         SHOWSTRING(parent_path);
  4207.  
  4208.         error = smba_open(ServerData,parent_path,&dir);
  4209.         if(error < 0)
  4210.         {
  4211.             error = MapErrnoToIoErr(error);
  4212.             goto out;
  4213.         }
  4214.  
  4215.         /* Only one attribute counts: the file should not be write protected. */
  4216.         memset(&stat,0,sizeof(stat));
  4217.  
  4218.         SHOWMSG("now trying to create the file");
  4219.         SHOWSTRING(base_name);
  4220.  
  4221.         error = smba_create(dir,base_name,&stat);
  4222.         if(error < 0)
  4223.         {
  4224.             SHOWMSG("didn't work.");
  4225.             SHOWVALUE(error);
  4226.  
  4227.             smba_close(dir);
  4228.             error = MapErrnoToIoErr(error);
  4229.  
  4230.             SHOWVALUE(error);
  4231.  
  4232.             goto out;
  4233.         }
  4234.  
  4235.         SHOWMSG("good.");
  4236.  
  4237.         smba_close(dir);
  4238.     }
  4239.  
  4240.     /* Now for the remainder... */
  4241.     error = smba_open(ServerData,full_name,&fn->fn_File);
  4242.     if(error < 0)
  4243.     {
  4244.         error = MapErrnoToIoErr(error);
  4245.         goto out;
  4246.     }
  4247.  
  4248.     fh->fh_Arg1 = (LONG)fn;
  4249.  
  4250.     AddTail((struct List *)&FileList,(struct Node *)fn);
  4251.     result = DOSTRUE;
  4252.  
  4253.  out:
  4254.  
  4255.     if(result == DOSFALSE)
  4256.     {
  4257.         FreeVecPooled(full_name);
  4258.         FreeVecPooled(fn);
  4259.     }
  4260.  
  4261.     FreeVecPooled(parent_path);
  4262.  
  4263.     (*error_ptr) = error;
  4264.  
  4265.     RETURN(result);
  4266.     return(result);
  4267. }
  4268.  
  4269. /****************************************************************************/
  4270.  
  4271. STATIC LONG
  4272. Action_Read(
  4273.     struct FileNode *    fn,
  4274.     APTR                mem,
  4275.     LONG                length,
  4276.     LONG *                error_ptr)
  4277. {
  4278.     LONG result = 0;
  4279.     LONG error = OK;
  4280.  
  4281.     ENTER();
  4282.  
  4283.     if(length > 0)
  4284.     {
  4285.         result = smba_read(fn->fn_File,mem,length,fn->fn_Offset);
  4286.         if(result < 0)
  4287.         {
  4288.             error = MapErrnoToIoErr(result);
  4289.             result = -1;
  4290.             goto out;
  4291.         }
  4292.  
  4293.         fn->fn_Offset += result;
  4294.     }
  4295.  
  4296.  out:
  4297.  
  4298.     (*error_ptr) = error;
  4299.  
  4300.     RETURN(result);
  4301.     return(result);
  4302. }
  4303.  
  4304. /****************************************************************************/
  4305.  
  4306. STATIC LONG
  4307. Action_Write(
  4308.     struct FileNode *    fn,
  4309.     APTR                mem,
  4310.     LONG                length,
  4311.     LONG *                error_ptr)
  4312. {
  4313.     LONG result = DOSFALSE;
  4314.     LONG error = OK;
  4315.  
  4316.     ENTER();
  4317.  
  4318.     if(WriteProtected)
  4319.     {
  4320.         error = ERROR_DISK_WRITE_PROTECTED;
  4321.         goto out;
  4322.     }
  4323.  
  4324.     if(length > 0)
  4325.     {
  4326.         result = smba_write(fn->fn_File,mem,length,fn->fn_Offset);
  4327.         if(result < 0)
  4328.         {
  4329.             error = MapErrnoToIoErr(result);
  4330.             result = -1;
  4331.             goto out;
  4332.         }
  4333.  
  4334.         fn->fn_Offset += result;
  4335.     }
  4336.  
  4337.  out:
  4338.  
  4339.     (*error_ptr) = error;
  4340.  
  4341.     RETURN(result);
  4342.     return(result);
  4343. }
  4344.  
  4345. /****************************************************************************/
  4346.  
  4347. STATIC LONG
  4348. Action_End(
  4349.     struct FileNode *    fn,
  4350.     LONG *                error_ptr)
  4351. {
  4352.     Remove((struct Node *)fn);
  4353.  
  4354.     smba_close(fn->fn_File);
  4355.     FreeVecPooled(fn->fn_FullName);
  4356.     FreeVecPooled(fn);
  4357.  
  4358.     (*error_ptr) = OK;
  4359.     return(DOSTRUE);
  4360. }
  4361.  
  4362. /****************************************************************************/
  4363.  
  4364. STATIC LONG
  4365. Action_Seek(
  4366.     struct FileNode *    fn,
  4367.     LONG                position,
  4368.     LONG                mode,
  4369.     LONG *                error_ptr)
  4370. {
  4371.     smba_stat_t stat;
  4372.     LONG result;
  4373.     LONG error;
  4374.     LONG offset;
  4375.  
  4376.     ENTER();
  4377.  
  4378.     error = smba_getattr(fn->fn_File,&stat);
  4379.     if(error < 0)
  4380.     {
  4381.         error = MapErrnoToIoErr(error);
  4382.         result = -1;
  4383.         goto out;
  4384.     }
  4385.  
  4386.     result = offset = fn->fn_Offset;
  4387.  
  4388.     switch(mode)
  4389.     {
  4390.         case OFFSET_BEGINNING:
  4391.  
  4392.             offset = position;
  4393.             break;
  4394.  
  4395.         case OFFSET_CURRENT:
  4396.  
  4397.             offset += position;
  4398.             break;
  4399.  
  4400.         case OFFSET_END:
  4401.  
  4402.             offset = stat.size + position;
  4403.             break;
  4404.  
  4405.         default:
  4406.  
  4407.             error = ERROR_ACTION_NOT_KNOWN;
  4408.  
  4409.             result = -1;
  4410.             goto out;
  4411.     }
  4412.  
  4413.     if(offset < 0 || offset > stat.size)
  4414.     {
  4415.         error = ERROR_SEEK_ERROR;
  4416.  
  4417.         result = -1;
  4418.         goto out;
  4419.     }
  4420.  
  4421.     fn->fn_Offset = offset;
  4422.  
  4423.  out:
  4424.  
  4425.     (*error_ptr) = error;
  4426.  
  4427.     RETURN(result);
  4428.     return(result);
  4429. }
  4430.  
  4431. /****************************************************************************/
  4432.  
  4433. STATIC LONG
  4434. Action_SetFileSize(
  4435.     struct FileNode *    fn,
  4436.     LONG                position,
  4437.     LONG                mode,
  4438.     LONG *                error_ptr)
  4439. {
  4440.     smba_stat_t stat;
  4441.     LONG result = -1;
  4442.     LONG error;
  4443.     long offset;
  4444.  
  4445.     ENTER();
  4446.  
  4447.     if(WriteProtected)
  4448.     {
  4449.         error = ERROR_DISK_WRITE_PROTECTED;
  4450.         goto out;
  4451.     }
  4452.  
  4453.     error = smba_getattr(fn->fn_File,&stat);
  4454.     if(error < 0)
  4455.     {
  4456.         error = MapErrnoToIoErr(error);
  4457.         goto out;
  4458.     }
  4459.  
  4460.     offset = fn->fn_Offset;
  4461.  
  4462.     switch(mode)
  4463.     {
  4464.         case OFFSET_BEGINNING:
  4465.  
  4466.             offset = position;
  4467.             break;
  4468.  
  4469.         case OFFSET_CURRENT:
  4470.  
  4471.             offset += position;
  4472.             break;
  4473.  
  4474.         case OFFSET_END:
  4475.  
  4476.             offset = stat.size + position;
  4477.             break;
  4478.  
  4479.         default:
  4480.  
  4481.             error = ERROR_ACTION_NOT_KNOWN;
  4482.             goto out;
  4483.     }
  4484.  
  4485.     if(offset < 0)
  4486.     {
  4487.         error = ERROR_SEEK_ERROR;
  4488.         goto out;
  4489.     }
  4490.  
  4491.     stat.atime    = -1;
  4492.     stat.ctime    = -1;
  4493.     stat.mtime    = -1;
  4494.     stat.size    = offset;
  4495.  
  4496.     error = smba_setattr(fn->fn_File,&stat);
  4497.     if(error < 0)
  4498.     {
  4499.         error = MapErrnoToIoErr(error);
  4500.         goto out;
  4501.     }
  4502.  
  4503.     if(fn->fn_Offset > offset)
  4504.         fn->fn_Offset = offset;
  4505.  
  4506.     result = offset;
  4507.  
  4508.  out:
  4509.  
  4510.     (*error_ptr) = error;
  4511.  
  4512.     RETURN(result);
  4513.     return(result);
  4514. }
  4515.  
  4516. /****************************************************************************/
  4517.  
  4518. STATIC LONG
  4519. Action_SetDate(
  4520.     struct FileLock *    parent,
  4521.     APTR                bcpl_name,
  4522.     struct DateStamp *    ds,
  4523.     LONG *                error_ptr)
  4524. {
  4525.     LONG result = DOSFALSE;
  4526.     STRPTR full_name = NULL;
  4527.     smba_file_t * file = NULL;
  4528.     STRPTR parent_name;
  4529.     UBYTE name[MAX_FILENAME_LEN];
  4530.     smba_stat_t stat;
  4531.     LONG seconds;
  4532.     LONG error;
  4533.  
  4534.     ENTER();
  4535.  
  4536.     if(WriteProtected)
  4537.     {
  4538.         error = ERROR_DISK_WRITE_PROTECTED;
  4539.         goto out;
  4540.     }
  4541.  
  4542.     SHOWVALUE(parent);
  4543.  
  4544.     if(parent != NULL)
  4545.     {
  4546.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  4547.  
  4548.         parent_name = ln->ln_FullName;
  4549.     }
  4550.     else
  4551.     {
  4552.         parent_name = NULL;
  4553.     }
  4554.  
  4555.     ConvertBString(sizeof(name),name,bcpl_name);
  4556.     TranslateCName(name,A2M);
  4557.  
  4558.     error = BuildFullName(parent_name,name,&full_name);
  4559.     if(error != OK)
  4560.         goto out;
  4561.  
  4562.     /* Trying to change the date of the root directory? */
  4563.     if(full_name == NULL)
  4564.     {
  4565.         error = ERROR_OBJECT_IN_USE;
  4566.         goto out;
  4567.     }
  4568.  
  4569.     SHOWSTRING(full_name);
  4570.  
  4571.     error = smba_open(ServerData,full_name,&file);
  4572.     if(error < 0)
  4573.     {
  4574.         error = MapErrnoToIoErr(error);
  4575.         goto out;
  4576.     }
  4577.  
  4578.     error = smba_getattr(file,&stat);
  4579.     if(error < 0)
  4580.     {
  4581.         error = MapErrnoToIoErr(error);
  4582.         goto out;
  4583.     }
  4584.  
  4585.     seconds = (ds->ds_Days * 24 * 60 + ds->ds_Minute) * 60 + (ds->ds_Tick / TICKS_PER_SECOND);
  4586.  
  4587.     stat.atime = -1;
  4588.     stat.ctime = -1;
  4589.     stat.mtime = UNIX_TIME_OFFSET + seconds + GetTimeZoneDelta();
  4590.     stat.size = -1;
  4591.  
  4592.     error = smba_setattr(file,&stat);
  4593.     if(error < 0)
  4594.     {
  4595.         error = MapErrnoToIoErr(error);
  4596.         goto out;
  4597.     }
  4598.  
  4599.     result = DOSTRUE;
  4600.  
  4601.  out:
  4602.  
  4603.     FreeVecPooled(full_name);
  4604.     if(file != NULL)
  4605.         smba_close(file);
  4606.  
  4607.     (*error_ptr) = error;
  4608.  
  4609.     RETURN(result);
  4610.     return(result);
  4611. }
  4612.  
  4613. /****************************************************************************/
  4614.  
  4615. STATIC LONG
  4616. Action_ExamineFH(
  4617.     struct FileNode *        fn,
  4618.     struct FileInfoBlock *    fib,
  4619.     LONG *                    error_ptr)
  4620. {
  4621.     LONG result = DOSFALSE;
  4622.     smba_stat_t stat;
  4623.     LONG error;
  4624.     LONG seconds;
  4625.     STRPTR name;
  4626.     LONG i;
  4627.  
  4628.     ENTER();
  4629.  
  4630.     error = smba_getattr(fn->fn_File,&stat);
  4631.     if(error < 0)
  4632.     {
  4633.         error = MapErrnoToIoErr(error);
  4634.         goto out;
  4635.     }
  4636.  
  4637.     name = fn->fn_FullName;
  4638.     for(i = strlen(name)-1 ; i >= 0 ; i--)
  4639.     {
  4640.         if(name[i] == SMB_PATH_SEPARATOR)
  4641.         {
  4642.             name = &name[i+1];
  4643.             break;
  4644.         }
  4645.     }
  4646.  
  4647.     /* Just checking: will the name fit? */
  4648.     if(strlen(name) >= sizeof(fib->fib_FileName))
  4649.     {
  4650.         error = ERROR_INVALID_COMPONENT_NAME;
  4651.         goto out;
  4652.     }
  4653.  
  4654.     memset(fib,0,sizeof(*fib));
  4655.  
  4656.     ConvertCString(sizeof(fib->fib_FileName),fib->fib_FileName,name);
  4657.     TranslateBName(fib->fib_FileName,M2A);
  4658.  
  4659.     fib->fib_DirEntryType    = ST_FILE;
  4660.     fib->fib_EntryType        = ST_FILE;
  4661.     fib->fib_NumBlocks        = (stat.size + 511) / 512;
  4662.     fib->fib_Size            = stat.size;
  4663.     fib->fib_DiskKey        = -1;
  4664.  
  4665.     seconds = stat.mtime - UNIX_TIME_OFFSET - GetTimeZoneDelta();
  4666.     if(seconds < 0)
  4667.         seconds = 0;
  4668.  
  4669.     fib->fib_Date.ds_Days    = (seconds / (24 * 60 * 60));
  4670.     fib->fib_Date.ds_Minute    = (seconds % (24 * 60 * 60)) / 60;
  4671.     fib->fib_Date.ds_Tick    = (seconds % 60) * TICKS_PER_SECOND;
  4672.  
  4673.     result = DOSTRUE;
  4674.  
  4675.  out:
  4676.  
  4677.     (*error_ptr) = error;
  4678.  
  4679.     RETURN(result);
  4680.     return(result);
  4681. }
  4682.  
  4683. /****************************************************************************/
  4684.  
  4685. STATIC BPTR
  4686. Action_ParentFH(
  4687.     struct FileNode *    fn,
  4688.     LONG *                error_ptr)
  4689. {
  4690.     BPTR result = ZERO;
  4691.     struct LockNode * ln = NULL;
  4692.     LONG error;
  4693.     STRPTR full_name;
  4694.     LONG i;
  4695.  
  4696.     ENTER();
  4697.  
  4698.     full_name = AllocVecPooled(strlen(fn->fn_FullName)+3);
  4699.     if(full_name == NULL)
  4700.     {
  4701.         error = ERROR_NO_FREE_STORE;
  4702.         goto out;
  4703.     }
  4704.  
  4705.     strcpy(full_name,fn->fn_FullName);
  4706.  
  4707.     for(i = strlen(full_name)-1 ; i >= 0 ; i--)
  4708.     {
  4709.         if(i == 0)
  4710.         {
  4711.             strcpy(full_name,SMB_ROOT_DIR_NAME);
  4712.             break;
  4713.         }
  4714.         else if (full_name[i] == SMB_PATH_SEPARATOR)
  4715.         {
  4716.             full_name[i] = '\0';
  4717.             break;
  4718.         }
  4719.     }
  4720.  
  4721.     ln = AllocVecPooled(sizeof(*ln));
  4722.     if(ln == NULL)
  4723.     {
  4724.         error = ERROR_NO_FREE_STORE;
  4725.         goto out;
  4726.     }
  4727.  
  4728.     memset(ln,0,sizeof(*ln));
  4729.  
  4730.     ln->ln_FileLock.fl_Key        = (LONG)ln;
  4731.     ln->ln_FileLock.fl_Access    = SHARED_LOCK;
  4732.     ln->ln_FileLock.fl_Task        = FileSystemPort;
  4733.     ln->ln_FileLock.fl_Volume    = MKBADDR(VolumeNode);
  4734.     ln->ln_FullName                = full_name;
  4735.  
  4736.     SHOWSTRING(full_name);
  4737.  
  4738.     error = smba_open(ServerData,full_name,&ln->ln_File);
  4739.     if(error < 0)
  4740.     {
  4741.         error = MapErrnoToIoErr(error);
  4742.         goto out;
  4743.     }
  4744.  
  4745.     AddTail((struct List *)&LockList,(struct Node *)ln);
  4746.     result = MKBADDR(&ln->ln_FileLock);
  4747.     SHOWVALUE(&ln->ln_FileLock);
  4748.  
  4749.  out:
  4750.  
  4751.     if(result == ZERO)
  4752.     {
  4753.         FreeVecPooled(ln);
  4754.         FreeVecPooled(full_name);
  4755.     }
  4756.  
  4757.     (*error_ptr) = error;
  4758.  
  4759.     RETURN(result);
  4760.     return(result);
  4761. }
  4762.  
  4763. /****************************************************************************/
  4764.  
  4765. STATIC BPTR
  4766. Action_CopyDirFH(
  4767.     struct FileNode *    fn,
  4768.     LONG *                error_ptr)
  4769. {
  4770.     BPTR result = ZERO;
  4771.     struct LockNode * ln = NULL;
  4772.     STRPTR full_name = NULL;
  4773.     LONG error;
  4774.  
  4775.     ENTER();
  4776.  
  4777.     if(fn->fn_Mode != SHARED_LOCK)
  4778.     {
  4779.         error = ERROR_OBJECT_IN_USE;
  4780.         goto out;
  4781.     }
  4782.  
  4783.     full_name = AllocVecPooled(strlen(fn->fn_FullName)+3);
  4784.     if(full_name == NULL)
  4785.     {
  4786.         error = ERROR_NO_FREE_STORE;
  4787.         goto out;
  4788.     }
  4789.  
  4790.     strcpy(full_name,fn->fn_FullName);
  4791.  
  4792.     ln = AllocVecPooled(sizeof(*ln));
  4793.     if(ln == NULL)
  4794.     {
  4795.         error = ERROR_NO_FREE_STORE;
  4796.         goto out;
  4797.     }
  4798.  
  4799.     memset(ln,0,sizeof(*ln));
  4800.  
  4801.     ln->ln_FileLock.fl_Key        = (LONG)ln;
  4802.     ln->ln_FileLock.fl_Access    = SHARED_LOCK;
  4803.     ln->ln_FileLock.fl_Task        = FileSystemPort;
  4804.     ln->ln_FileLock.fl_Volume    = MKBADDR(VolumeNode);
  4805.     ln->ln_FullName                = full_name;
  4806.  
  4807.     SHOWSTRING(full_name);
  4808.  
  4809.     error = smba_open(ServerData,full_name,&ln->ln_File);
  4810.     if(error < 0)
  4811.     {
  4812.         error = MapErrnoToIoErr(error);
  4813.         goto out;
  4814.     }
  4815.  
  4816.     AddTail((struct List *)&LockList,(struct Node *)ln);
  4817.     result = MKBADDR(&ln->ln_FileLock);
  4818.     SHOWVALUE(&ln->ln_FileLock);
  4819.  
  4820.  out:
  4821.  
  4822.     if(result == ZERO)
  4823.     {
  4824.         FreeVecPooled(ln);
  4825.         FreeVecPooled(full_name);
  4826.     }
  4827.  
  4828.     (*error_ptr) = error;
  4829.  
  4830.     RETURN(result);
  4831.     return(result);
  4832. }
  4833.  
  4834. /****************************************************************************/
  4835.  
  4836. STATIC LONG
  4837. Action_FHFromLock(
  4838.     struct FileHandle *    fh,
  4839.     struct FileLock *    fl,
  4840.     LONG *                error_ptr)
  4841. {
  4842.     LONG result = DOSFALSE;
  4843.     struct FileNode * fn;
  4844.     struct LockNode * ln;
  4845.     LONG error = OK;
  4846.  
  4847.     ENTER();
  4848.  
  4849.     SHOWVALUE(fl);
  4850.  
  4851.     fn = AllocVecPooled(sizeof(*fn));
  4852.     if(fn == NULL)
  4853.     {
  4854.         error = ERROR_NO_FREE_STORE;
  4855.         goto out;
  4856.     }
  4857.  
  4858.     memset(fn,0,sizeof(*fn));
  4859.  
  4860.     ln = (struct LockNode *)fl->fl_Key;
  4861.  
  4862.     fn->fn_Handle    = fh;
  4863.     fn->fn_FullName    = ln->ln_FullName;
  4864.     fn->fn_File        = ln->ln_File;
  4865.     fn->fn_Mode        = fl->fl_Access;
  4866.  
  4867.     Remove((struct Node *)ln);
  4868.     FreeVecPooled(ln);
  4869.  
  4870.     fh->fh_Arg1 = (LONG)fn;
  4871.  
  4872.     AddTail((struct List *)&FileList,(struct Node *)fn);
  4873.     result = DOSTRUE;
  4874.  
  4875.  out:
  4876.  
  4877.     (*error_ptr) = error;
  4878.  
  4879.     RETURN(result);
  4880.     return(result);
  4881. }
  4882.  
  4883. /****************************************************************************/
  4884.  
  4885. STATIC LONG
  4886. Action_RenameDisk(
  4887.     APTR    bcpl_name,
  4888.     LONG *    error_ptr)
  4889. {
  4890.     LONG result = DOSFALSE;
  4891.     LONG error = OK;
  4892.     STRPTR old_name;
  4893.     STRPTR new_name;
  4894.     UBYTE * name;
  4895.     LONG len;
  4896.  
  4897.     ENTER();
  4898.  
  4899.     if(NOT VolumeNodeAdded)
  4900.     {
  4901.         error = ERROR_OBJECT_IN_USE;
  4902.         goto out;
  4903.     }
  4904.  
  4905.     if(WriteProtected)
  4906.     {
  4907.         error = ERROR_DISK_WRITE_PROTECTED;
  4908.         goto out;
  4909.     }
  4910.  
  4911.     /* Now for the really interesting part; the new name
  4912.      * is to be a NUL-terminated BCPL string, and as such
  4913.      * must be allocated via AllocVec().
  4914.      */
  4915.  
  4916.     name = bcpl_name;
  4917.  
  4918.     len = name[0];
  4919.  
  4920.     new_name = AllocVec(1 + len + 1,MEMF_ANY|MEMF_PUBLIC);
  4921.     if(new_name == NULL)
  4922.     {
  4923.         error = ERROR_NO_FREE_STORE;
  4924.         goto out;
  4925.     }
  4926.  
  4927.     new_name[0] = len;
  4928.     memcpy(&new_name[1],&name[1],len);
  4929.     new_name[len+1] = '\0';
  4930.  
  4931.     Forbid();
  4932.  
  4933.     old_name = BADDR(VolumeNode->dol_Name);
  4934.     FreeVec(old_name);
  4935.     VolumeNode->dol_Name = MKBADDR(new_name);
  4936.  
  4937.     Permit();
  4938.  
  4939.     SendDiskChange(IECLASS_DISKINSERTED);
  4940.  
  4941.     result = DOSTRUE;
  4942.  
  4943.  out:
  4944.  
  4945.     (*error_ptr) = error;
  4946.  
  4947.     RETURN(result);
  4948.     return(result);
  4949. }
  4950.  
  4951. /****************************************************************************/
  4952.  
  4953. STATIC LONG
  4954. Action_ChangeMode(
  4955.     LONG                type,
  4956.     APTR                object,
  4957.     LONG                new_mode,
  4958.     LONG *                error_ptr)
  4959. {
  4960.     LONG result = DOSFALSE;
  4961.     struct FileLock * fl = NULL;
  4962.     struct FileNode * fn = NULL;
  4963.     struct LockNode * ln = NULL;
  4964.     STRPTR name;
  4965.     LONG old_mode;
  4966.     LONG error = OK;
  4967.  
  4968.     ENTER();
  4969.  
  4970.     /* Sanity check; verify parameters */
  4971.     if((type != CHANGE_LOCK && type != CHANGE_FH) ||
  4972.        (new_mode != EXCLUSIVE_LOCK && new_mode != SHARED_LOCK))
  4973.     {
  4974.         error = ERROR_ACTION_NOT_KNOWN;
  4975.         goto out;
  4976.     }
  4977.  
  4978.     /* Now obtain the data structures, name and mode
  4979.      * associated with the object in question.
  4980.      */
  4981.     if(type == CHANGE_LOCK)
  4982.     {
  4983.         fl = object;
  4984.         ln = (struct LockNode *)fl->fl_Key;
  4985.         name = ln->ln_FullName;
  4986.         old_mode = fl->fl_Access;
  4987.     }
  4988.     else
  4989.     {
  4990.         struct FileHandle * fh = object;
  4991.  
  4992.         fn = (struct FileNode *)fh->fh_Arg1;
  4993.         name = fn->fn_FullName;
  4994.         old_mode = fn->fn_Mode;
  4995.     }
  4996.  
  4997.     /* Do we need to change anything at all? */
  4998.     if(new_mode == old_mode)
  4999.     {
  5000.         result = DOSTRUE;
  5001.         goto out;
  5002.     }
  5003.  
  5004.     /* This is the easiest case; change an
  5005.      * exclusive access mode to a shared
  5006.      * access mode. Since the original mode
  5007.      * can be used by one object only,
  5008.      * we get away by updating the mode
  5009.      * value.
  5010.      */
  5011.     if(new_mode == SHARED_LOCK)
  5012.     {
  5013.         if(type == CHANGE_LOCK)
  5014.             fl->fl_Access = new_mode;
  5015.         else
  5016.             fn->fn_Mode = new_mode;
  5017.  
  5018.         result = DOSTRUE;
  5019.         goto out;
  5020.     }
  5021.  
  5022.     /* Is there another shared access lock
  5023.      * which refers to the same object?
  5024.      */
  5025.     if(FindLockNode(name,ln) != NULL)
  5026.     {
  5027.         error = ERROR_OBJECT_IN_USE;
  5028.         goto out;
  5029.     }
  5030.  
  5031.     /* Is there another shared access file
  5032.      * which refers to the same object?
  5033.      */
  5034.     if(FindFileNode(name,fn) != NULL)
  5035.     {
  5036.         error = ERROR_OBJECT_IN_USE;
  5037.         goto out;
  5038.     }
  5039.  
  5040.     /* There is just one single reference
  5041.      * to this object; change the mode
  5042.      * and quit.
  5043.      */
  5044.     if(type == CHANGE_LOCK)
  5045.         fl->fl_Access = new_mode;
  5046.     else
  5047.         fn->fn_Mode = new_mode;
  5048.  
  5049.     result = DOSTRUE;
  5050.  
  5051.  out:
  5052.  
  5053.     (*error_ptr) = error;
  5054.  
  5055.     RETURN(result);
  5056.     return(result);
  5057. }
  5058.  
  5059. /****************************************************************************/
  5060.  
  5061. STATIC LONG
  5062. Action_WriteProtect(
  5063.     LONG    flag,
  5064.     ULONG    key,
  5065.     LONG *    error_ptr)
  5066. {
  5067.     LONG result = DOSFALSE;
  5068.     LONG error = OK;
  5069.  
  5070.     ENTER();
  5071.  
  5072.     if(flag == DOSFALSE)
  5073.     {
  5074.         if(WriteProtected)
  5075.         {
  5076.             if(key != WriteProtectKey)
  5077.             {
  5078.                 error = ERROR_INVALID_LOCK;
  5079.                 goto out;
  5080.             }
  5081.  
  5082.             WriteProtected = FALSE;
  5083.  
  5084.             if(VolumeNodeAdded)
  5085.             {
  5086.                 SendDiskChange(IECLASS_DISKREMOVED);
  5087.                 SendDiskChange(IECLASS_DISKINSERTED);
  5088.             }
  5089.         }
  5090.     }
  5091.     else
  5092.     {
  5093.         if(NOT WriteProtected)
  5094.         {
  5095.             WriteProtected = TRUE;
  5096.             WriteProtectKey = key;
  5097.  
  5098.             if(VolumeNodeAdded)
  5099.             {
  5100.                 SendDiskChange(IECLASS_DISKREMOVED);
  5101.                 SendDiskChange(IECLASS_DISKINSERTED);
  5102.             }
  5103.         }
  5104.         else
  5105.         {
  5106.             error = ERROR_INVALID_LOCK;
  5107.             goto out;
  5108.         }
  5109.     }
  5110.  
  5111.     result = DOSTRUE;
  5112.  
  5113.  out:
  5114.  
  5115.     (*error_ptr) = error;
  5116.  
  5117.     RETURN(result);
  5118.     return(result);
  5119. }
  5120.  
  5121. /****************************************************************************/
  5122.  
  5123. STATIC LONG
  5124. Action_MoreCache(
  5125.     LONG    buffer_delta,
  5126.     LONG *    error_ptr)
  5127. {
  5128.     LONG result;
  5129.     int old_size;
  5130.  
  5131.     ENTER();
  5132.  
  5133.     old_size = smba_get_dircache_size(ServerData);
  5134.  
  5135.     result = smba_change_dircache_size(ServerData,old_size + buffer_delta);
  5136.  
  5137.     if(result == old_size && buffer_delta != 0)
  5138.     {
  5139.         result = DOSFALSE;
  5140.         (*error_ptr) = ERROR_NO_FREE_STORE;
  5141.     }
  5142.  
  5143.     RETURN(result);
  5144.     return(result);
  5145. }
  5146.  
  5147. /****************************************************************************/
  5148.  
  5149. STATIC LONG
  5150. Action_SetComment(
  5151.     struct FileLock *    parent,
  5152.     APTR                bcpl_name,
  5153.     APTR                bcpl_comment,
  5154.     LONG *                error_ptr)
  5155. {
  5156.     LONG result = DOSFALSE;
  5157.     STRPTR full_name = NULL;
  5158.     smba_file_t * file = NULL;
  5159.     STRPTR parent_name;
  5160.     UBYTE name[MAX_FILENAME_LEN];
  5161.     UBYTE comment[80];
  5162.     LONG error;
  5163.  
  5164.     ENTER();
  5165.  
  5166.     if(WriteProtected)
  5167.     {
  5168.         error = ERROR_DISK_WRITE_PROTECTED;
  5169.         goto out;
  5170.     }
  5171.  
  5172.     SHOWVALUE(parent);
  5173.  
  5174.     if(parent != NULL)
  5175.     {
  5176.         struct LockNode * ln = (struct LockNode *)parent->fl_Key;
  5177.  
  5178.         parent_name = ln->ln_FullName;
  5179.     }
  5180.     else
  5181.     {
  5182.         parent_name = NULL;
  5183.     }
  5184.  
  5185.     ConvertBString(sizeof(name),name,bcpl_name);
  5186.     TranslateCName(name,A2M);
  5187.  
  5188.     error = BuildFullName(parent_name,name,&full_name);
  5189.     if(error != OK)
  5190.         goto out;
  5191.  
  5192.     /* Trying to change the comment of the root directory? */
  5193.     if(full_name == NULL)
  5194.     {
  5195.         error = ERROR_OBJECT_IN_USE;
  5196.         goto out;
  5197.     }
  5198.  
  5199.     SHOWSTRING(full_name);
  5200.  
  5201.     error = smba_open(ServerData,full_name,&file);
  5202.     if(error < 0)
  5203.     {
  5204.         error = MapErrnoToIoErr(error);
  5205.         goto out;
  5206.     }
  5207.  
  5208.     ConvertBString(sizeof(comment),comment,bcpl_comment);
  5209.  
  5210.     SHOWSTRING(comment);
  5211.  
  5212.     /* All this work and we're only doing something very silly... */
  5213.     if(strlen(comment) > 0)
  5214.     {
  5215.         error = ERROR_COMMENT_TOO_BIG;
  5216.         goto out;
  5217.     }
  5218.  
  5219.     result = DOSTRUE;
  5220.  
  5221.  out:
  5222.  
  5223.     FreeVecPooled(full_name);
  5224.     if(file != NULL)
  5225.         smba_close(file);
  5226.  
  5227.     (*error_ptr) = error;
  5228.  
  5229.     RETURN(result);
  5230.     return(result);
  5231. }
  5232.  
  5233. /****************************************************************************/
  5234.  
  5235. STATIC VOID
  5236. HandleFileSystem(STRPTR device_name,STRPTR volume_name,STRPTR service_name)
  5237. {
  5238.     BOOL sign_off = FALSE;
  5239.     ULONG signals;
  5240.     BOOL done;
  5241.  
  5242.     ENTER();
  5243.  
  5244.     DisplayErrorList();
  5245.  
  5246.     if(NOT Quiet && WBStartup == NULL)
  5247.     {
  5248.         struct CommandLineInterface * cli;
  5249.  
  5250.         cli = Cli();
  5251.         if(NOT cli->cli_Background)
  5252.         {
  5253.             struct Process * this_process;
  5254.             UBYTE name[MAX_FILENAME_LEN];
  5255.             LONG max_cli;
  5256.             LONG which;
  5257.             LONG i;
  5258.  
  5259.             this_process = (struct Process *)FindTask(NULL);
  5260.  
  5261.             Forbid();
  5262.  
  5263.             which = max_cli = MaxCli();
  5264.  
  5265.             for(i = 1 ; i <= max_cli ; i++)
  5266.             {
  5267.                 if(FindCliProc(i) == this_process)
  5268.                 {
  5269.                     which = i;
  5270.                     break;
  5271.                 }
  5272.             }
  5273.  
  5274.             Permit();
  5275.  
  5276.             if(volume_name == NULL)
  5277.                 strncpy(name,device_name,sizeof(name)-1);
  5278.             else
  5279.                 strncpy(name,volume_name,sizeof(name)-1);
  5280.  
  5281.             name[sizeof(name)-1] = '\0';
  5282.  
  5283.             for(i = strlen(name)-1 ; i >= 0 ; i--)
  5284.             {
  5285.                 if(name[i] == ':')
  5286.                     name[i] = '\0';
  5287.                 else
  5288.                     break;
  5289.             }
  5290.  
  5291.             Printf("Connected '%s' to '%s:'; \"Break %ld\" or [Ctrl-C] to stop... ",
  5292.             service_name,name,which);
  5293.  
  5294.             Flush(Output());
  5295.  
  5296.             sign_off = TRUE;
  5297.         }
  5298.     }
  5299.  
  5300.     Quiet = TRUE;
  5301.  
  5302.     done = FALSE;
  5303.  
  5304.     do
  5305.     {
  5306.         signals = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F | (1UL << FileSystemPort->mp_SigBit));
  5307.  
  5308.         if(signals & (1UL << FileSystemPort->mp_SigBit))
  5309.         {
  5310.             struct DosPacket * dp;
  5311.             struct Message * mn;
  5312.             LONG res1,res2;
  5313.  
  5314.             while((mn = GetMsg(FileSystemPort)) != NULL)
  5315.             {
  5316.                 dp = (struct DosPacket *)mn->mn_Node.ln_Name;
  5317.  
  5318.                 D(("got packet; sender '%s'",((struct Node *)dp->dp_Port->mp_SigTask)->ln_Name));
  5319.  
  5320.                 res2 = 0;
  5321.  
  5322.                 switch(dp->dp_Action)
  5323.                 {
  5324.                     case ACTION_DIE:
  5325.  
  5326.                         SHOWMSG("ACTION_DIE");
  5327.                         if(IsListEmpty((struct List *)&FileList) && IsListEmpty((struct List *)&LockList))
  5328.                         {
  5329.                             SHOWMSG("no locks or files pending; quitting");
  5330.  
  5331.                             res1 = DOSTRUE;
  5332.                         }
  5333.                         else
  5334.                         {
  5335.                             SHOWMSG("locks or files still pending; cannot quit yet");
  5336.  
  5337.                             res1 = DOSFALSE;
  5338.                             res2 = ERROR_OBJECT_IN_USE;
  5339.                         }
  5340.  
  5341.                         Quit = TRUE;
  5342.                         break;
  5343.  
  5344.                     case ACTION_CURRENT_VOLUME:
  5345.                         /* (Ignore) -> VolumeNode */
  5346.  
  5347.                         res1 = MKBADDR(VolumeNode);
  5348.                         break;
  5349.  
  5350.                     case ACTION_LOCATE_OBJECT:
  5351.                         /* Lock,Name,Mode -> Lock */
  5352.  
  5353.                         res1 = Action_LocateObject((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),dp->dp_Arg3,&res2);
  5354.                         break;
  5355.  
  5356.                     case ACTION_RENAME_DISK:
  5357.                         /* Name -> Bool */
  5358.  
  5359.                         res1 = Action_RenameDisk((UBYTE *)BADDR(dp->dp_Arg1),&res2);
  5360.                         break;
  5361.  
  5362.                     case ACTION_FREE_LOCK:
  5363.                         /* Lock -> Bool */
  5364.  
  5365.                         res1 = Action_FreeLock((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
  5366.                         break;
  5367.  
  5368.                     case ACTION_DELETE_OBJECT:
  5369.                         /* Lock,Name -> Bool */
  5370.  
  5371.                         res1 = Action_DeleteObject((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),&res2);
  5372.                         break;
  5373.  
  5374.                     case ACTION_RENAME_OBJECT:
  5375.                         /* Source lock,source name,destination lock,destination name -> Bool */
  5376.  
  5377.                         res1 = Action_RenameObject((struct FileLock *)BADDR(dp->dp_Arg1),BADDR(dp->dp_Arg2),
  5378.                             (struct FileLock *)BADDR(dp->dp_Arg3),BADDR(dp->dp_Arg4),&res2);
  5379.  
  5380.                         break;
  5381.  
  5382.                     case ACTION_MORE_CACHE:
  5383.                         /* Buffer delta -> Total number of buffers */
  5384.  
  5385.                         /* NOTE: documentation for this packet type is inconsistent;
  5386.                          *       in the 'good old' 1.x days 'res1' was documented as
  5387.                          *       the total number of buffers to be returned. In the
  5388.                          *       2.x documentation it is said that 'res1' should
  5389.                          *       return the success code, with 'res2' to hold the
  5390.                          *       total number of buffers. However, the 'AddBuffers'
  5391.                          *       shell command doesn't work that way, and the
  5392.                          *       dos.library implementation of 'AddBuffers()' doesn't
  5393.                          *       work that way either. The 1.3 'AddBuffers' command
  5394.                          *       appears to treat a zero result as failure and a
  5395.                          *       non-zero result as success, which suggests that this
  5396.                          *       is how the packet is supposed to work, contrary to
  5397.                          *       what the official documentation says.
  5398.                          */
  5399.                         res1 = Action_MoreCache(dp->dp_Arg1,&res2);
  5400.                         break;
  5401.  
  5402.                     case ACTION_COPY_DIR:
  5403.                         /* Lock -> Lock */
  5404.  
  5405.                         res1 = Action_CopyDir((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
  5406.                         break;
  5407.  
  5408.                     case ACTION_SET_PROTECT:
  5409.                         /* (Ignore),Lock,Name,Mask -> Bool */
  5410.  
  5411.                         res1 = Action_SetProtect((struct FileLock *)BADDR(dp->dp_Arg2),BADDR(dp->dp_Arg3),dp->dp_Arg4,&res2);
  5412.                         break;
  5413.  
  5414.                     case ACTION_CREATE_DIR:
  5415.                         /* Lock,Name -> Lock */
  5416.  
  5417.                         res1 = Action_CreateDir((struct FileLock *)BADDR(dp->dp_Arg1),(APTR)BADDR(dp->dp_Arg2),&res2);
  5418.                         break;
  5419.  
  5420.                     case ACTION_EXAMINE_OBJECT:
  5421.                         /* FileLock,FileInfoBlock -> Bool */
  5422.  
  5423.                         res1 = Action_ExamineObject((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
  5424.                         break;
  5425.  
  5426.                     case ACTION_EXAMINE_NEXT:
  5427.                         /* FileLock,FileInfoBlock -> Bool */
  5428.  
  5429.                         res1 = Action_ExamineNext((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
  5430.                         break;
  5431.  
  5432.                     case ACTION_DISK_INFO:
  5433.                         /* InfoData -> Bool */
  5434.  
  5435.                         Action_DiskInfo((struct InfoData *)BADDR(dp->dp_Arg1),&res2);
  5436.                         res1 = DOSTRUE;
  5437.                         res2 = 0;
  5438.                         break;
  5439.  
  5440.                     case ACTION_INFO:
  5441.                         /* FileLock,InfoData -> Bool */
  5442.  
  5443.                         res1 = Action_Info((struct FileLock *)BADDR(dp->dp_Arg1),(struct InfoData *)BADDR(dp->dp_Arg2),&res2);
  5444.                         break;
  5445.  
  5446.                     case ACTION_SET_COMMENT:
  5447.                         /* (Ignore),FileLock,Name,Comment -> Bool */
  5448.  
  5449.                         res1 = Action_SetComment((struct FileLock *)BADDR(dp->dp_Arg2),BADDR(dp->dp_Arg3),BADDR(dp->dp_Arg4),&res2);
  5450.                         break;
  5451.  
  5452.                     case ACTION_PARENT:
  5453.                         /* Lock -> Lock */
  5454.  
  5455.                         res1 = Action_Parent((struct FileLock *)BADDR(dp->dp_Arg1),&res2);
  5456.                         break;
  5457.  
  5458.                     case ACTION_INHIBIT:
  5459.  
  5460.                         SHOWMSG("ACTION_INHIBIT");
  5461.                         res1 = DOSTRUE;
  5462.                         break;
  5463.  
  5464.                     case ACTION_SET_DATE:
  5465.                         /* (Ignore),FileLock,Name,DateStamp(APTR) -> Bool */
  5466.  
  5467.                         res1 = Action_SetDate((struct FileLock *)BADDR(dp->dp_Arg2),(APTR)BADDR(dp->dp_Arg3),(struct DateStamp *)dp->dp_Arg4,&res2);
  5468.                         break;
  5469.  
  5470.                     case ACTION_SAME_LOCK:
  5471.                         /* Lock,Lock -> Bool */
  5472.  
  5473.                         res1 = Action_SameLock((struct FileLock *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),&res2);
  5474.                         break;
  5475.  
  5476.                     case ACTION_READ:
  5477.                         /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
  5478.  
  5479.                         res1 = Action_Read((struct FileNode *)dp->dp_Arg1,(APTR)dp->dp_Arg2,dp->dp_Arg3,&res2);
  5480.                         break;
  5481.  
  5482.                     case ACTION_WRITE:
  5483.                         /* FileHandle->fh_Arg1,Buffer(APTR),Length -> Length */
  5484.  
  5485.                         res1 = Action_Write((struct FileNode *)dp->dp_Arg1,(APTR)dp->dp_Arg2,dp->dp_Arg3,&res2);
  5486.                         break;
  5487.  
  5488.                     case ACTION_FINDUPDATE:
  5489.                     case ACTION_FINDINPUT:
  5490.                     case ACTION_FINDOUTPUT:
  5491.                         /* FileHandle,FileLock,Name -> Bool */
  5492.  
  5493.                         res1 = Action_Find(dp->dp_Action,(struct FileHandle *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),(APTR)BADDR(dp->dp_Arg3),&res2);
  5494.                         break;
  5495.  
  5496.                     case ACTION_END:
  5497.                         /* FileHandle->fh_Arg1 -> Bool */
  5498.  
  5499.                         res1 = Action_End((struct FileNode *)dp->dp_Arg1,&res2);
  5500.                         break;
  5501.  
  5502.                     case ACTION_SEEK:
  5503.                         /* FileHandle->fh_Arg1,Position,Mode -> Position */
  5504.  
  5505.                         res1 = Action_Seek((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
  5506.                         break;
  5507.  
  5508.                     case ACTION_SET_FILE_SIZE:
  5509.                         /* FileHandle->fh_Arg1,Offset,Mode -> New file size */
  5510.  
  5511.                         res1 = Action_SetFileSize((struct FileNode *)dp->dp_Arg1,dp->dp_Arg2,dp->dp_Arg3,&res2);
  5512.                         break;
  5513.  
  5514.                     case ACTION_WRITE_PROTECT:
  5515.                         /* Flag,Key -> Bool */
  5516.  
  5517.                         res1 = Action_WriteProtect(dp->dp_Arg1,dp->dp_Arg2,&res2);
  5518.                         break;
  5519.  
  5520.                     case ACTION_FH_FROM_LOCK:
  5521.                         /* FileHandle(BPTR),FileLock -> Bool */
  5522.  
  5523.                         res1 = Action_FHFromLock((struct FileHandle *)BADDR(dp->dp_Arg1),(struct FileLock *)BADDR(dp->dp_Arg2),&res2);
  5524.                         break;
  5525.  
  5526.                     case ACTION_IS_FILESYSTEM:
  5527.  
  5528.                         SHOWMSG("ACTION_IS_FILESYSTEM");
  5529.                         res1 = DOSTRUE;
  5530.                         break;
  5531.  
  5532.                     case ACTION_CHANGE_MODE:
  5533.                         /* Type,Object,Mode -> Bool */
  5534.  
  5535.                         res1 = Action_ChangeMode(dp->dp_Arg1,(APTR)BADDR(dp->dp_Arg2),dp->dp_Arg3,&res2);
  5536.                         break;
  5537.  
  5538.                     case ACTION_COPY_DIR_FH:
  5539.                         /* FileHandle->fh_Arg1 -> Bool */
  5540.  
  5541.                         res1 = Action_CopyDirFH((struct FileNode *)dp->dp_Arg1,&res2);
  5542.                         break;
  5543.  
  5544.                     case ACTION_PARENT_FH:
  5545.                         /* FileHandle->fh_Arg1 -> Bool */
  5546.  
  5547.                         res1 = Action_ParentFH((struct FileNode *)dp->dp_Arg1,&res2);
  5548.                         break;
  5549.  
  5550.                     case ACTION_EXAMINE_ALL:
  5551.                         /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
  5552.  
  5553.                         res1 = Action_ExamineAll((struct FileLock *)BADDR(dp->dp_Arg1),(struct ExAllData *)dp->dp_Arg2,
  5554.                             dp->dp_Arg3,dp->dp_Arg4,(struct ExAllControl *)dp->dp_Arg5,&res2);
  5555.  
  5556.                         break;
  5557.  
  5558.                     case ACTION_EXAMINE_FH:
  5559.                         /* FileHandle->fh_Arg1,FileInfoBlock -> Bool */
  5560.  
  5561.                         res1 = Action_ExamineFH((struct FileNode *)dp->dp_Arg1,(struct FileInfoBlock *)BADDR(dp->dp_Arg2),&res2);
  5562.                         break;
  5563.  
  5564.                     case ACTION_EXAMINE_ALL_END:
  5565.                         /* FileLock,ExAllData(APTR),Size,Type,ExAllControl(APTR) -> Bool */
  5566.  
  5567.                         res1 = DOSTRUE;
  5568.                         break;
  5569.  
  5570.                     default:
  5571.  
  5572.                         D(("Anything goes: dp->dp_Action=%ld (0x%lx)",dp->dp_Action,dp->dp_Action));
  5573.  
  5574.                         res1 = DOSFALSE;
  5575.                         res2 = ERROR_ACTION_NOT_KNOWN;
  5576.  
  5577.                         break;
  5578.                 }
  5579.  
  5580.                 SHOWVALUE(res1);
  5581.                 SHOWVALUE(res2);
  5582.  
  5583.                 ReplyPkt(dp,res1,res2);
  5584.  
  5585.                 D(("\n"));
  5586.             }
  5587.         }
  5588.  
  5589.         #if DEBUG
  5590.         {
  5591.             if(signals & SIGBREAKF_CTRL_F)
  5592.             {
  5593.                 struct FileNode * fn;
  5594.                 struct LockNode * ln;
  5595.  
  5596.                 D(("list of open files:"));
  5597.  
  5598.                 for(fn = (struct FileNode *)FileList.mlh_Head ;
  5599.                     fn->fn_MinNode.mln_Succ != NULL ;
  5600.                     fn = (struct FileNode *)fn->fn_MinNode.mln_Succ)
  5601.                 {
  5602.                     D(("  name='%s'",fn->fn_FullName));
  5603.                     D(("  mode=%ld, offset=%ld",fn->fn_Mode,fn->fn_Offset));
  5604.                     D((""));
  5605.                 }
  5606.  
  5607.                 D(("list of allocated locks:"));
  5608.  
  5609.                 for(ln = (struct LockNode *)LockList.mlh_Head ;
  5610.                     ln->ln_MinNode.mln_Succ != NULL ;
  5611.                     ln = (struct LockNode *)ln->ln_MinNode.mln_Succ)
  5612.                 {
  5613.                     D(("  name='%s'",ln->ln_FullName));
  5614.                     D(("  mode=%ld",ln->ln_FileLock.fl_Access));
  5615.                     D((""));
  5616.                 }
  5617.             }
  5618.         }
  5619.         #endif /* DEBUG */
  5620.  
  5621.         if(signals & SIGBREAKF_CTRL_C)
  5622.             Quit = TRUE;
  5623.  
  5624.         if(Quit)
  5625.         {
  5626.             if(IsListEmpty((struct List *)&FileList) && IsListEmpty((struct List *)&LockList))
  5627.             {
  5628.                 SHOWMSG("no locks or files pending; quitting");
  5629.                 done = TRUE;
  5630.             }
  5631.             else
  5632.             {
  5633.                 SHOWMSG("locks or files still pending; cannot quit yet");
  5634.             }
  5635.         }
  5636.     }
  5637.     while(NOT done);
  5638.  
  5639.     if(sign_off)
  5640.         Printf("stopped.\n");
  5641.  
  5642.     LEAVE();
  5643. }
  5644.