home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #9 / Amiga Plus CD - 2004 - No. 09.iso / amigaplus / tools / amigaos4_only / smbfs / source / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-08-03  |  148.8 KB  |  6,386 lines

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